Merge tag 'zonefs-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 12 Mar 2024 19:24:40 +0000 (12:24 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 12 Mar 2024 19:24:40 +0000 (12:24 -0700)
Pull zonefs update from Damien Le Moal:

 - A single change for this cycle to convert zonefs to use the new
   mount API

* tag 'zonefs-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs:
  zonefs: convert zonefs to use the new mount api

3175 files changed:
.mailmap
CREDITS
Documentation/ABI/testing/sysfs-class-net-statistics
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/ABI/testing/sysfs-nvmem-cells
Documentation/RCU/checklist.rst
Documentation/RCU/rcu_dereference.rst
Documentation/RCU/whatisRCU.rst
Documentation/admin-guide/RAS/address-translation.rst [new file with mode: 0644]
Documentation/admin-guide/RAS/error-decoding.rst [moved from Documentation/RAS/ras.rst with 73% similarity]
Documentation/admin-guide/RAS/index.rst [new file with mode: 0644]
Documentation/admin-guide/RAS/main.rst [moved from Documentation/admin-guide/ras.rst with 99% similarity]
Documentation/admin-guide/cgroup-v1/cpusets.rst
Documentation/admin-guide/cgroup-v1/hugetlb.rst
Documentation/admin-guide/hw-vuln/index.rst
Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst [new file with mode: 0644]
Documentation/admin-guide/hw-vuln/spectre.rst
Documentation/admin-guide/index.rst
Documentation/admin-guide/kdump/kdump.rst
Documentation/admin-guide/kernel-parameters.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/arch/arm64/silicon-errata.rst
Documentation/arch/x86/amd-memory-encryption.rst
Documentation/arch/x86/boot.rst
Documentation/arch/x86/mds.rst
Documentation/arch/x86/pti.rst
Documentation/arch/x86/topology.rst
Documentation/arch/x86/x86_64/fred.rst [new file with mode: 0644]
Documentation/arch/x86/x86_64/index.rst
Documentation/conf.py
Documentation/core-api/workqueue.rst
Documentation/dev-tools/kselftest.rst
Documentation/devicetree/bindings/Makefile
Documentation/devicetree/bindings/arm/amlogic.yaml
Documentation/devicetree/bindings/arm/arm,realview.yaml
Documentation/devicetree/bindings/arm/atmel-at91.yaml
Documentation/devicetree/bindings/arm/fsl.yaml
Documentation/devicetree/bindings/arm/marvell/armada-38x.txt [deleted file]
Documentation/devicetree/bindings/arm/marvell/armada-38x.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/mediatek.yaml
Documentation/devicetree/bindings/arm/msm/qcom,saw2.txt [deleted file]
Documentation/devicetree/bindings/arm/qcom.yaml
Documentation/devicetree/bindings/arm/rockchip.yaml
Documentation/devicetree/bindings/arm/sunxi.yaml
Documentation/devicetree/bindings/arm/tegra.yaml
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra186-pmc.yaml
Documentation/devicetree/bindings/arm/ti/k3.yaml
Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml
Documentation/devicetree/bindings/bus/imx-weim.txt [deleted file]
Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
Documentation/devicetree/bindings/clock/qcom,gcc-sc8180x.yaml
Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml
Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml
Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml
Documentation/devicetree/bindings/clock/qcom,sm8650-dispcc.yaml [deleted file]
Documentation/devicetree/bindings/clock/renesas,cpg-mssr.yaml
Documentation/devicetree/bindings/display/bridge/nxp,tda998x.yaml
Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml
Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
Documentation/devicetree/bindings/fpga/xlnx,versal-fpga.yaml
Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml
Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml [moved from Documentation/devicetree/bindings/gpu/img,powervr.yaml with 91% similarity]
Documentation/devicetree/bindings/gpu/img,powervr-sgx.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml
Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.yaml
Documentation/devicetree/bindings/interrupt-controller/starfive,jh8100-intc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml
Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim-peripherals.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/mc-peripheral-props.yaml
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.yaml
Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml
Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml
Documentation/devicetree/bindings/net/marvell,prestera.yaml
Documentation/devicetree/bindings/net/renesas,ethertsn.yaml
Documentation/devicetree/bindings/power/renesas,rcar-sysc.yaml
Documentation/devicetree/bindings/reset/renesas,rst.yaml
Documentation/devicetree/bindings/reset/xlnx,zynqmp-reset.yaml
Documentation/devicetree/bindings/soc/qcom/qcom,pbs.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
Documentation/devicetree/bindings/soc/qcom/qcom,rpm-master-stats.yaml
Documentation/devicetree/bindings/soc/qcom/qcom,saw2.yaml [moved from Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml with 53% similarity]
Documentation/devicetree/bindings/soc/renesas/renesas-soc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/soc/renesas/renesas.yaml
Documentation/devicetree/bindings/soc/rockchip/grf.yaml
Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml
Documentation/devicetree/bindings/soc/xilinx/xilinx.yaml
Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max9808x.yaml
Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml
Documentation/devicetree/bindings/tpm/tpm-common.yaml
Documentation/devicetree/bindings/ufs/samsung,exynos-ufs.yaml
Documentation/devicetree/bindings/usb/dwc3-xilinx.yaml
Documentation/devicetree/bindings/usb/microchip,usb5744.yaml
Documentation/devicetree/bindings/usb/xlnx,usb2.yaml
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/driver-api/dpll.rst
Documentation/filesystems/files.rst
Documentation/filesystems/index.rst
Documentation/filesystems/locking.rst
Documentation/filesystems/ntfs.rst [deleted file]
Documentation/filesystems/vfs.rst
Documentation/index.rst
Documentation/kbuild/Kconfig.recursion-issue-01
Documentation/netlink/specs/dpll.yaml
Documentation/networking/devlink/devlink-port.rst
Documentation/networking/net_cachelines/inet_sock.rst
Documentation/networking/net_cachelines/net_device.rst
Documentation/networking/net_cachelines/tcp_sock.rst
Documentation/process/changes.rst
Documentation/process/cve.rst [new file with mode: 0644]
Documentation/process/index.rst
Documentation/process/maintainer-netdev.rst
Documentation/process/maintainer-tip.rst
Documentation/process/security-bugs.rst
Documentation/rust/general-information.rst
Documentation/rust/index.rst
Documentation/rust/testing.rst [new file with mode: 0644]
Documentation/sphinx/kernel_feat.py
Documentation/sphinx/translations.py
Documentation/userspace-api/ioctl/ioctl-number.rst
Documentation/virt/coco/sev-guest.rst
Documentation/virt/hyperv/index.rst
Documentation/virt/hyperv/vpci.rst [new file with mode: 0644]
Documentation/virt/kvm/api.rst
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/Kconfig
arch/alpha/include/asm/page.h
arch/alpha/kernel/smp.c
arch/arc/Kconfig
arch/arc/include/uapi/asm/page.h
arch/arc/kernel/smp.c
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/dts/allwinner/sun8i-r40-feta40i.dtsi
arch/arm/boot/dts/amazon/alpine.dtsi
arch/arm/boot/dts/amlogic/meson.dtsi
arch/arm/boot/dts/amlogic/meson8.dtsi
arch/arm/boot/dts/amlogic/meson8b.dtsi
arch/arm/boot/dts/arm/arm-realview-pb1176.dts
arch/arm/boot/dts/arm/integratorap-im-pd1.dts
arch/arm/boot/dts/arm/versatile-ab.dts
arch/arm/boot/dts/arm/vexpress-v2p-ca9.dts
arch/arm/boot/dts/aspeed/aspeed-g4.dtsi
arch/arm/boot/dts/aspeed/aspeed-g5.dtsi
arch/arm/boot/dts/aspeed/aspeed-g6.dtsi
arch/arm/boot/dts/broadcom/bcm-cygnus.dtsi
arch/arm/boot/dts/broadcom/bcm-hr2.dtsi
arch/arm/boot/dts/broadcom/bcm-nsp.dtsi
arch/arm/boot/dts/gemini/gemini-dlink-dir-685.dts
arch/arm/boot/dts/gemini/gemini-dlink-dns-313.dts
arch/arm/boot/dts/gemini/gemini-sl93512r.dts
arch/arm/boot/dts/gemini/gemini-sq201.dts
arch/arm/boot/dts/gemini/gemini-wbd111.dts
arch/arm/boot/dts/gemini/gemini-wbd222.dts
arch/arm/boot/dts/intel/ixp/intel-ixp42x-gateway-7001.dts
arch/arm/boot/dts/intel/ixp/intel-ixp42x-goramo-multilink.dts
arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-l8.dts
arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-s4.dts
arch/arm/boot/dts/marvell/armada-385-clearfog-gtr.dtsi
arch/arm/boot/dts/marvell/armada-388-clearfog.dts
arch/arm/boot/dts/marvell/dove-cubox.dts
arch/arm/boot/dts/marvell/kirkwood-l-50.dts
arch/arm/boot/dts/marvell/mmp2-brownstone.dts
arch/arm/boot/dts/microchip/Makefile
arch/arm/boot/dts/microchip/at91-sama7g54_curiosity.dts [new file with mode: 0644]
arch/arm/boot/dts/microchip/at91sam9g25-gardena-smart-gateway.dts
arch/arm/boot/dts/microchip/at91sam9x5ek.dtsi
arch/arm/boot/dts/microchip/sam9x60.dtsi
arch/arm/boot/dts/microchip/sama7g5.dtsi
arch/arm/boot/dts/nuvoton/nuvoton-wpcm450.dtsi
arch/arm/boot/dts/nvidia/Makefile
arch/arm/boot/dts/nvidia/tegra124-nyan.dtsi
arch/arm/boot/dts/nvidia/tegra124-venice2.dts
arch/arm/boot/dts/nvidia/tegra30-apalis-v1.1.dtsi
arch/arm/boot/dts/nvidia/tegra30-apalis.dtsi
arch/arm/boot/dts/nvidia/tegra30-asus-nexus7-grouper-common.dtsi
arch/arm/boot/dts/nvidia/tegra30-colibri.dtsi
arch/arm/boot/dts/nvidia/tegra30-lg-p880.dts [new file with mode: 0644]
arch/arm/boot/dts/nvidia/tegra30-lg-p895.dts [new file with mode: 0644]
arch/arm/boot/dts/nvidia/tegra30-lg-x3.dtsi [new file with mode: 0644]
arch/arm/boot/dts/nxp/imx/Makefile
arch/arm/boot/dts/nxp/imx/imx1-apf9328.dts
arch/arm/boot/dts/nxp/imx/imx1.dtsi
arch/arm/boot/dts/nxp/imx/imx27.dtsi
arch/arm/boot/dts/nxp/imx/imx31.dtsi
arch/arm/boot/dts/nxp/imx/imx35.dtsi
arch/arm/boot/dts/nxp/imx/imx51.dtsi
arch/arm/boot/dts/nxp/imx/imx53-qsb-hdmi.dtso [new file with mode: 0644]
arch/arm/boot/dts/nxp/imx/imx6dl-sielaff.dts [new file with mode: 0644]
arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi
arch/arm/boot/dts/nxp/imx/imx6q-apalis-eval-v1.2.dts [new file with mode: 0644]
arch/arm/boot/dts/nxp/imx/imx6q-apalis-eval.dts
arch/arm/boot/dts/nxp/imx/imx6q-apalis-eval.dtsi [new file with mode: 0644]
arch/arm/boot/dts/nxp/imx/imx6q-b850v3.dts
arch/arm/boot/dts/nxp/imx/imx6q-bx50v3.dtsi
arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi
arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi
arch/arm/boot/dts/nxp/imx/imx6qdl-emcon.dtsi
arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard.dtsi
arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard2.dtsi
arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-pfla02.dtsi
arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-phycore-som.dtsi
arch/arm/boot/dts/nxp/imx/imx6qdl-skov-cpu.dtsi
arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi
arch/arm/boot/dts/nxp/imx/imx6sl-tolino-shine2hd.dts
arch/arm/boot/dts/nxp/imx/imx6sl.dtsi
arch/arm/boot/dts/nxp/imx/imx6sx.dtsi
arch/arm/boot/dts/nxp/imx/imx6ul-14x14-evk.dtsi
arch/arm/boot/dts/nxp/imx/imx6ul-geam.dts
arch/arm/boot/dts/nxp/imx/imx6ul-imx6ull-opos6uldev.dtsi
arch/arm/boot/dts/nxp/imx/imx6ul.dtsi
arch/arm/boot/dts/nxp/imx/imx6ull-dhcom-som-cfg-sdcard.dtsi
arch/arm/boot/dts/nxp/imx/imx6ull-dhcom-som.dtsi
arch/arm/boot/dts/nxp/imx/imx6ull-dhcor-som.dtsi
arch/arm/boot/dts/nxp/imx/imx6ull.dtsi
arch/arm/boot/dts/nxp/imx/imx7-mba7.dtsi
arch/arm/boot/dts/nxp/imx/imx7-tqma7.dtsi
arch/arm/boot/dts/nxp/imx/imx7d-mba7.dts
arch/arm/boot/dts/nxp/imx/imx7d-pico-dwarf.dts
arch/arm/boot/dts/nxp/imx/imx7s.dtsi
arch/arm/boot/dts/nxp/ls/ls1021a.dtsi
arch/arm/boot/dts/nxp/mxs/imx28-evk.dts
arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts
arch/arm/boot/dts/qcom/Makefile
arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts
arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts
arch/arm/boot/dts/qcom/qcom-apq8064.dtsi
arch/arm/boot/dts/qcom/qcom-apq8084.dtsi
arch/arm/boot/dts/qcom/qcom-ipq4019-ap.dk01.1.dtsi
arch/arm/boot/dts/qcom/qcom-ipq4019.dtsi
arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi
arch/arm/boot/dts/qcom/qcom-msm8226-samsung-matisse-common.dtsi [new file with mode: 0644]
arch/arm/boot/dts/qcom/qcom-msm8226.dtsi
arch/arm/boot/dts/qcom/qcom-msm8660.dtsi
arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts
arch/arm/boot/dts/qcom/qcom-msm8926-samsung-matisselte.dts [new file with mode: 0644]
arch/arm/boot/dts/qcom/qcom-msm8960-pins.dtsi [new file with mode: 0644]
arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts
arch/arm/boot/dts/qcom/qcom-msm8960.dtsi
arch/arm/boot/dts/qcom/qcom-msm8974.dtsi
arch/arm/boot/dts/qcom/qcom-sdx55.dtsi
arch/arm/boot/dts/qcom/qcom-sdx65.dtsi
arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts
arch/arm/boot/dts/renesas/r8a73a4.dtsi
arch/arm/boot/dts/renesas/r8a7740.dtsi
arch/arm/boot/dts/renesas/r8a7778.dtsi
arch/arm/boot/dts/renesas/r8a7779.dtsi
arch/arm/boot/dts/renesas/r8a7790-lager.dts
arch/arm/boot/dts/renesas/r8a7790-stout.dts
arch/arm/boot/dts/renesas/r8a7791-koelsch.dts
arch/arm/boot/dts/renesas/r8a7791-porter.dts
arch/arm/boot/dts/renesas/r8a7792-blanche.dts
arch/arm/boot/dts/renesas/r8a7793-gose.dts
arch/arm/boot/dts/renesas/r8a7794-alt.dts
arch/arm/boot/dts/renesas/r8a7794-silk.dts
arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts
arch/arm/boot/dts/rockchip/rk3128.dtsi
arch/arm/boot/dts/rockchip/rk322x.dtsi
arch/arm/boot/dts/rockchip/rk3288.dtsi
arch/arm/boot/dts/rockchip/rv1108.dtsi
arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dtsi
arch/arm/boot/dts/samsung/exynos4412-i9300.dts
arch/arm/boot/dts/samsung/exynos4412-i9305.dts
arch/arm/boot/dts/samsung/exynos4412-n710x.dts
arch/arm/boot/dts/samsung/exynos4412-p4note.dtsi
arch/arm/boot/dts/samsung/exynos5420-galaxy-tab-common.dtsi
arch/arm/boot/dts/samsung/exynos5420-peach-pit.dts
arch/arm/boot/dts/samsung/exynos5422-odroidxu3-common.dtsi
arch/arm/boot/dts/samsung/exynos5800-peach-pi.dts
arch/arm/boot/dts/st/Makefile
arch/arm/boot/dts/st/stih407-pinctrl.dtsi
arch/arm/boot/dts/st/stm32429i-eval.dts
arch/arm/boot/dts/st/stm32f769-disco-mb1166-reva09.dts [new file with mode: 0644]
arch/arm/boot/dts/st/stm32f769-disco.dts
arch/arm/boot/dts/st/stm32f769.dtsi [new file with mode: 0644]
arch/arm/boot/dts/st/stm32mp131.dtsi
arch/arm/boot/dts/st/stm32mp135f-dk.dts
arch/arm/boot/dts/st/stm32mp157.dtsi
arch/arm/boot/dts/st/stm32mp157a-dk1-scmi.dts
arch/arm/boot/dts/st/stm32mp157c-dk2-scmi.dts
arch/arm/boot/dts/st/stm32mp157c-dk2.dts
arch/arm/boot/dts/st/stm32mp157c-ed1-scmi.dts
arch/arm/boot/dts/st/stm32mp157c-ev1-scmi.dts
arch/arm/boot/dts/st/stm32mp157c-lxa-tac-gen2.dts
arch/arm/boot/dts/st/stm32mp15xc-lxa-tac.dtsi
arch/arm/boot/dts/ti/davinci/da850.dtsi
arch/arm/boot/dts/ti/keystone/keystone-clocks.dtsi
arch/arm/boot/dts/ti/keystone/keystone-k2e-clocks.dtsi
arch/arm/boot/dts/ti/keystone/keystone-k2e-evm.dts
arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi
arch/arm/boot/dts/ti/keystone/keystone-k2e.dtsi
arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts
arch/arm/boot/dts/ti/keystone/keystone-k2g-ice.dts
arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi
arch/arm/boot/dts/ti/keystone/keystone-k2g.dtsi
arch/arm/boot/dts/ti/keystone/keystone-k2hk-clocks.dtsi
arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts
arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi
arch/arm/boot/dts/ti/keystone/keystone-k2hk.dtsi
arch/arm/boot/dts/ti/keystone/keystone-k2l-clocks.dtsi
arch/arm/boot/dts/ti/keystone/keystone-k2l-evm.dts
arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi
arch/arm/boot/dts/ti/keystone/keystone-k2l.dtsi
arch/arm/boot/dts/ti/keystone/keystone.dtsi
arch/arm/boot/dts/ti/omap/am335x-baltos-ir2110.dts
arch/arm/boot/dts/ti/omap/am335x-baltos-ir3220.dts
arch/arm/boot/dts/ti/omap/am335x-baltos-ir5221.dts
arch/arm/boot/dts/ti/omap/am335x-baltos-leds.dtsi
arch/arm/boot/dts/ti/omap/am335x-baltos.dtsi
arch/arm/boot/dts/ti/omap/am335x-base0033.dts
arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi
arch/arm/boot/dts/ti/omap/am335x-cm-t335.dts
arch/arm/boot/dts/ti/omap/am335x-evmsk.dts
arch/arm/boot/dts/ti/omap/am335x-guardian.dts
arch/arm/boot/dts/ti/omap/am335x-icev2.dts
arch/arm/boot/dts/ti/omap/am335x-igep0033.dtsi
arch/arm/boot/dts/ti/omap/am335x-myirtech-myc.dtsi
arch/arm/boot/dts/ti/omap/am335x-myirtech-myd.dts
arch/arm/boot/dts/ti/omap/am335x-nano.dts
arch/arm/boot/dts/ti/omap/am335x-netcan-plus-1xx.dts
arch/arm/boot/dts/ti/omap/am335x-netcom-plus-2xx.dts
arch/arm/boot/dts/ti/omap/am335x-netcom-plus-8xx.dts
arch/arm/boot/dts/ti/omap/am335x-pdu001.dts
arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe-extended-wifi.dts
arch/arm/boot/dts/ti/omap/am335x-sancloud-bbe-lite.dts
arch/arm/boot/dts/ti/omap/am335x-sbc-t335.dts
arch/arm/boot/dts/ti/omap/am335x-sl50.dts
arch/arm/boot/dts/ti/omap/am33xx.dtsi
arch/arm/boot/dts/ti/omap/am3517.dtsi
arch/arm/boot/dts/ti/omap/am4372.dtsi
arch/arm/boot/dts/ti/omap/am437x-cm-t43.dts
arch/arm/boot/dts/ti/omap/am437x-sbc-t43.dts
arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts
arch/arm/boot/dts/ti/omap/am57xx-cl-som-am57x.dts
arch/arm/boot/dts/ti/omap/am57xx-sbc-am57x.dts
arch/arm/boot/dts/ti/omap/compulab-sb-som.dtsi
arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
arch/arm/boot/dts/ti/omap/dra7.dtsi
arch/arm/boot/dts/ti/omap/dra74x-p.dtsi
arch/arm/boot/dts/ti/omap/dra7xx-clocks.dtsi
arch/arm/boot/dts/ti/omap/omap34xx.dtsi
arch/arm/boot/dts/ti/omap/omap36xx.dtsi
arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts
arch/arm/boot/dts/ti/omap/omap4-panda-common.dtsi
arch/arm/boot/dts/ti/omap/omap4-sdp.dts
arch/arm/boot/dts/ti/omap/omap4.dtsi
arch/arm/boot/dts/ti/omap/omap5-igep0050.dts
arch/arm/boot/dts/ti/omap/omap5.dtsi
arch/arm/boot/dts/ti/omap/twl4030.dtsi
arch/arm/boot/dts/ti/omap/twl6030.dtsi
arch/arm/configs/exynos_defconfig
arch/arm/configs/imx_v6_v7_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/shmobile_defconfig
arch/arm/include/asm/elf.h
arch/arm/include/asm/page.h
arch/arm/include/asm/vdso_datapage.h [deleted file]
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/vdso.c
arch/arm/mach-ep93xx/core.c
arch/arm/mach-imx/mmdc.c
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap2/am33xx-restart.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c
arch/arm/mach-omap2/clockdomain.c
arch/arm/mach-omap2/cm33xx.c
arch/arm/mach-omap2/cminst44xx.c
arch/arm/mach-omap2/omap-secure.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_common_data.c
arch/arm/mach-omap2/pmic-cpcap.c
arch/arm/mach-omap2/powerdomain.c
arch/arm/mach-omap2/prm-regbits-33xx.h
arch/arm/mach-omap2/prm.h
arch/arm/mach-omap2/prm33xx.c
arch/arm/mach-omap2/prm44xx.c
arch/arm/mach-omap2/prm_common.c
arch/arm/mach-omap2/wd_timer.c
arch/arm/mach-qcom/Kconfig
arch/arm/mach-s3c/cpu.h
arch/arm/mach-s3c/s3c6410.c
arch/arm/mach-s3c/s3c64xx.c
arch/arm/mach-s5pv210/pm.c
arch/arm/mach-zynq/slcr.c
arch/arm64/Kconfig
arch/arm64/boot/dts/allwinner/Makefile
arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts
arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-cb1-manta.dts
arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-cb1.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h616-bigtreetech-pi.dts
arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h618-longan-module-3h.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/allwinner/sun50i-h618-longanpi-3h.dts [new file with mode: 0644]
arch/arm64/boot/dts/allwinner/sun50i-h618-transpeed-8k618-t.dts
arch/arm64/boot/dts/allwinner/sun50i-h64-remix-mini-pc.dts [new file with mode: 0644]
arch/arm64/boot/dts/amazon/alpine-v2.dtsi
arch/arm64/boot/dts/amazon/alpine-v3.dtsi
arch/arm64/boot/dts/amlogic/Makefile
arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
arch/arm64/boot/dts/amlogic/meson-a1-ad402.dts
arch/arm64/boot/dts/amlogic/meson-a1.dtsi
arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j1xx.dtsi
arch/arm64/boot/dts/amlogic/meson-axg-s400.dts
arch/arm64/boot/dts/amlogic/meson-axg.dtsi
arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
arch/arm64/boot/dts/amlogic/meson-g12a-fbx8am-brcm.dtso [new file with mode: 0644]
arch/arm64/boot/dts/amlogic/meson-g12a-fbx8am-realtek.dtso [new file with mode: 0644]
arch/arm64/boot/dts/amlogic/meson-g12a-fbx8am.dts [new file with mode: 0644]
arch/arm64/boot/dts/amlogic/meson-g12a-radxa-zero.dts
arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts
arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts
arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi
arch/arm64/boot/dts/amlogic/meson-g12b-odroid.dtsi
arch/arm64/boot/dts/amlogic/meson-g12b-w400.dtsi
arch/arm64/boot/dts/amlogic/meson-gx-libretech-pc.dtsi
arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts
arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s805x-p241.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905w-jethome-jethub-j80.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc-v2.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
arch/arm64/boot/dts/amlogic/meson-gxm-s912-libretech-pc.dts
arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi
arch/arm64/boot/dts/amlogic/meson-libretech-cottonwood.dtsi
arch/arm64/boot/dts/amlogic/meson-sm1-ac2xx.dtsi
arch/arm64/boot/dts/amlogic/meson-sm1-bananapi.dtsi
arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts
arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi
arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi
arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi
arch/arm64/boot/dts/exynos/exynos850.dtsi
arch/arm64/boot/dts/exynos/google/gs101-oriole.dts
arch/arm64/boot/dts/exynos/google/gs101-pinctrl.dtsi
arch/arm64/boot/dts/exynos/google/gs101.dtsi
arch/arm64/boot/dts/freescale/Makefile
arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
arch/arm64/boot/dts/freescale/imx8-apalis-eval-v1.1.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8-apalis-eval-v1.2.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8-apalis-eval.dtsi
arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi
arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi
arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
arch/arm64/boot/dts/freescale/imx8-ss-gpu0.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi
arch/arm64/boot/dts/freescale/imx8dxl.dtsi
arch/arm64/boot/dts/freescale/imx8dxp-tqma8xdp-mba8xx.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8dxp-tqma8xdp.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8dxp.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi
arch/arm64/boot/dts/freescale/imx8mm-kontron-bl-osm-s.dts
arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts
arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi
arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi
arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts
arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi
arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
arch/arm64/boot/dts/freescale/imx8mn-beacon-kit.dts
arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
arch/arm64/boot/dts/freescale/imx8mn-rve-gateway.dts
arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx-usbotg.dtso [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts
arch/arm64/boot/dts/freescale/imx8mn-var-som-symphony.dts
arch/arm64/boot/dts/freescale/imx8mn.dtsi
arch/arm64/boot/dts/freescale/imx8mp-beacon-som.dtsi
arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts
arch/arm64/boot/dts/freescale/imx8mp-dhcom-pdk3.dts
arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
arch/arm64/boot/dts/freescale/imx8mp-evk.dts
arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi
arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
arch/arm64/boot/dts/freescale/imx8mp-venice-gw71xx.dtsi
arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi
arch/arm64/boot/dts/freescale/imx8mp.dtsi
arch/arm64/boot/dts/freescale/imx8mq-tqma8mq-mba8mx.dts
arch/arm64/boot/dts/freescale/imx8qm-apalis-eval-v1.2.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8qm-apalis-eval.dts
arch/arm64/boot/dts/freescale/imx8qm-apalis-v1.1-eval-v1.2.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8qm-apalis-v1.1-eval.dts
arch/arm64/boot/dts/freescale/imx8qm-mek.dts
arch/arm64/boot/dts/freescale/imx8qm-ss-conn.dtsi
arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi
arch/arm64/boot/dts/freescale/imx8qm.dtsi
arch/arm64/boot/dts/freescale/imx8qxp-tqma8xqp-mba8xx.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8qxp-tqma8xqp.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8qxp.dtsi
arch/arm64/boot/dts/freescale/imx8ulp-evk.dts
arch/arm64/boot/dts/freescale/imx93-phyboard-segin.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi
arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx93-var-som.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx93.dtsi
arch/arm64/boot/dts/freescale/mba8mx.dtsi
arch/arm64/boot/dts/freescale/mba8xx.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/tqma8xx.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi
arch/arm64/boot/dts/lg/lg1312.dtsi
arch/arm64/boot/dts/lg/lg1313.dtsi
arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi
arch/arm64/boot/dts/marvell/ac5-98dx35xx-rd.dts
arch/arm64/boot/dts/marvell/armada-37xx.dtsi
arch/arm64/boot/dts/marvell/armada-ap807.dtsi
arch/arm64/boot/dts/marvell/armada-ap80x.dtsi
arch/arm64/boot/dts/marvell/armada-cp11x.dtsi
arch/arm64/boot/dts/mediatek/Makefile
arch/arm64/boot/dts/mediatek/mt2712-evb.dts
arch/arm64/boot/dts/mediatek/mt2712e.dtsi
arch/arm64/boot/dts/mediatek/mt6797.dtsi
arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
arch/arm64/boot/dts/mediatek/mt7981b-xiaomi-ax3000t.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt7981b.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt7986a-acelink-ew-7886cax.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso
arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts
arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts
arch/arm64/boot/dts/mediatek/mt7986a.dtsi
arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts
arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt7988a.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8173-elm-hana-rev7.dts
arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi
arch/arm64/boot/dts/mediatek/mt8173-evb.dts
arch/arm64/boot/dts/mediatek/mt8173.dtsi
arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi
arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi
arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi
arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi
arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts
arch/arm64/boot/dts/mediatek/mt8183.dtsi
arch/arm64/boot/dts/mediatek/mt8186-corsola-krabby.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186-corsola-magneton-sku393216.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186-corsola-magneton-sku393217.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186-corsola-magneton-sku393218.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186-corsola-rusty-sku196608.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186-corsola-steelix-sku131072.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186-corsola-steelix-sku131073.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186-corsola-steelix.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186-corsola-tentacool-sku327681.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186-corsola-tentacool-sku327683.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186-corsola-tentacruel-sku262144.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186-corsola-tentacruel-sku262148.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186-corsola.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8186.dtsi
arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi
arch/arm64/boot/dts/mediatek/mt8192.dtsi
arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dts
arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dts
arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dts
arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
arch/arm64/boot/dts/mediatek/mt8195-demo.dts
arch/arm64/boot/dts/mediatek/mt8195-evb.dts
arch/arm64/boot/dts/mediatek/mt8195.dtsi
arch/arm64/boot/dts/mediatek/mt8395-genio-1200-evk.dts
arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts [new file with mode: 0644]
arch/arm64/boot/dts/nvidia/tegra132-norrin.dts
arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
arch/arm64/boot/dts/nvidia/tegra194-p3668.dtsi
arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi
arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
arch/arm64/boot/dts/nvidia/tegra234-p3767-0000.dtsi [deleted file]
arch/arm64/boot/dts/nvidia/tegra234-p3767-0005.dtsi [deleted file]
arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi
arch/arm64/boot/dts/nvidia/tegra234-p3768-0000+p3767-0000.dts
arch/arm64/boot/dts/nvidia/tegra234-p3768-0000+p3767-0005.dts
arch/arm64/boot/dts/nvidia/tegra234-sim-vdk.dts
arch/arm64/boot/dts/nvidia/tegra234.dtsi
arch/arm64/boot/dts/qcom/Makefile
arch/arm64/boot/dts/qcom/apq8016-sbc-d3-camera-mezzanine.dts
arch/arm64/boot/dts/qcom/ipq5332.dtsi
arch/arm64/boot/dts/qcom/ipq6018.dtsi
arch/arm64/boot/dts/qcom/ipq8074.dtsi
arch/arm64/boot/dts/qcom/ipq9574.dtsi
arch/arm64/boot/dts/qcom/msm8216-samsung-fortuna3g.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/msm8916-samsung-fortuna-common.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/msm8916-samsung-gprimeltecan.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/msm8916-samsung-grandprimelte.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/msm8916-samsung-rossa-common.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/msm8916-samsung-rossa.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/msm8916.dtsi
arch/arm64/boot/dts/qcom/msm8939.dtsi
arch/arm64/boot/dts/qcom/msm8953.dtsi
arch/arm64/boot/dts/qcom/msm8994-msft-lumia-octagon.dtsi
arch/arm64/boot/dts/qcom/msm8994-sony-xperia-kitakami.dtsi
arch/arm64/boot/dts/qcom/msm8994.dtsi
arch/arm64/boot/dts/qcom/msm8996.dtsi
arch/arm64/boot/dts/qcom/msm8998.dtsi
arch/arm64/boot/dts/qcom/pm4125.dtsi [moved from arch/arm64/boot/dts/qcom/pm2250.dtsi with 56% similarity]
arch/arm64/boot/dts/qcom/pmi632.dtsi
arch/arm64/boot/dts/qcom/qcm2290.dtsi
arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts
arch/arm64/boot/dts/qcom/qcm6490-idp.dts
arch/arm64/boot/dts/qcom/qcs404.dtsi
arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
arch/arm64/boot/dts/qcom/qrb2210-rb1.dts
arch/arm64/boot/dts/qcom/qrb4210-rb2.dts
arch/arm64/boot/dts/qcom/sa8295p-adp.dts
arch/arm64/boot/dts/qcom/sa8540p-ride.dts
arch/arm64/boot/dts/qcom/sa8540p.dtsi
arch/arm64/boot/dts/qcom/sa8775p.dtsi
arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
arch/arm64/boot/dts/qcom/sc7180.dtsi
arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi
arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi
arch/arm64/boot/dts/qcom/sc7280-idp-ec-h1.dtsi
arch/arm64/boot/dts/qcom/sc7280.dtsi
arch/arm64/boot/dts/qcom/sc8180x.dtsi
arch/arm64/boot/dts/qcom/sc8280xp-crd.dts
arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts
arch/arm64/boot/dts/qcom/sc8280xp-pmics.dtsi
arch/arm64/boot/dts/qcom/sc8280xp.dtsi
arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts
arch/arm64/boot/dts/qcom/sdm450-motorola-ali.dts
arch/arm64/boot/dts/qcom/sdm450.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sdm630-sony-xperia-nile.dtsi
arch/arm64/boot/dts/qcom/sdm630.dtsi
arch/arm64/boot/dts/qcom/sdm632.dtsi
arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts
arch/arm64/boot/dts/qcom/sdm670.dtsi
arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
arch/arm64/boot/dts/qcom/sdm845-db845c.dts
arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi
arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts
arch/arm64/boot/dts/qcom/sdm845.dtsi
arch/arm64/boot/dts/qcom/sm4450.dtsi
arch/arm64/boot/dts/qcom/sm6115.dtsi
arch/arm64/boot/dts/qcom/sm6125.dtsi
arch/arm64/boot/dts/qcom/sm6350.dtsi
arch/arm64/boot/dts/qcom/sm6375.dtsi
arch/arm64/boot/dts/qcom/sm7125-xiaomi-common.dtsi
arch/arm64/boot/dts/qcom/sm7125-xiaomi-curtana.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
arch/arm64/boot/dts/qcom/sm8150.dtsi
arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi
arch/arm64/boot/dts/qcom/sm8250.dtsi
arch/arm64/boot/dts/qcom/sm8350.dtsi
arch/arm64/boot/dts/qcom/sm8450-hdk.dts
arch/arm64/boot/dts/qcom/sm8450.dtsi
arch/arm64/boot/dts/qcom/sm8550-hdk.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sm8550-mtp.dts
arch/arm64/boot/dts/qcom/sm8550-qrd.dts
arch/arm64/boot/dts/qcom/sm8550.dtsi
arch/arm64/boot/dts/qcom/sm8650-mtp.dts
arch/arm64/boot/dts/qcom/sm8650-qrd.dts
arch/arm64/boot/dts/qcom/sm8650.dtsi
arch/arm64/boot/dts/qcom/x1e80100-crd.dts
arch/arm64/boot/dts/qcom/x1e80100-qcp.dts
arch/arm64/boot/dts/qcom/x1e80100.dtsi
arch/arm64/boot/dts/renesas/Makefile
arch/arm64/boot/dts/renesas/r8a774a1.dtsi
arch/arm64/boot/dts/renesas/r8a774b1.dtsi
arch/arm64/boot/dts/renesas/r8a774c0.dtsi
arch/arm64/boot/dts/renesas/r8a774e1.dtsi
arch/arm64/boot/dts/renesas/r8a77951.dtsi
arch/arm64/boot/dts/renesas/r8a77960.dtsi
arch/arm64/boot/dts/renesas/r8a77961.dtsi
arch/arm64/boot/dts/renesas/r8a77965.dtsi
arch/arm64/boot/dts/renesas/r8a77970.dtsi
arch/arm64/boot/dts/renesas/r8a77980.dtsi
arch/arm64/boot/dts/renesas/r8a77990.dtsi
arch/arm64/boot/dts/renesas/r8a77995.dtsi
arch/arm64/boot/dts/renesas/r8a779a0.dtsi
arch/arm64/boot/dts/renesas/r8a779f0.dtsi
arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dts [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi
arch/arm64/boot/dts/renesas/r8a779g0-white-hawk.dts
arch/arm64/boot/dts/renesas/r8a779g0.dtsi
arch/arm64/boot/dts/renesas/r8a779g2-white-hawk-single.dts [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a779g2.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a779h0-gray-hawk-single.dts [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a779h0.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r9a07g043u.dtsi
arch/arm64/boot/dts/renesas/r9a07g043u11-smarc-cru-csi-ov5645.dtso [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r9a07g044.dtsi
arch/arm64/boot/dts/renesas/r9a07g054.dtsi
arch/arm64/boot/dts/renesas/r9a08g045.dtsi
arch/arm64/boot/dts/renesas/rzg2l-smarc.dtsi
arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi
arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi
arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi
arch/arm64/boot/dts/renesas/ulcb-kf.dtsi
arch/arm64/boot/dts/renesas/white-hawk-common.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/renesas/white-hawk-cpu-common.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/renesas/white-hawk-csi-dsi.dtsi [moved from arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-csi-dsi.dtsi with 97% similarity]
arch/arm64/boot/dts/renesas/white-hawk-ethernet.dtsi [moved from arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-ethernet.dtsi with 76% similarity]
arch/arm64/boot/dts/rockchip/Makefile
arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts
arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi
arch/arm64/boot/dts/rockchip/px30.dtsi
arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts
arch/arm64/boot/dts/rockchip/rk3328.dtsi
arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts
arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts
arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts
arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4a.dts
arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b.dts
arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4c.dts
arch/arm64/boot/dts/rockchip/rk3399.dtsi
arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc-d.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc-s.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353x.dtsi
arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg503.dts
arch/arm64/boot/dts/rockchip/rk3566-anbernic-rgxx3.dtsi
arch/arm64/boot/dts/rockchip/rk3566-pinetab2-v0.1.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3566-pinetab2-v2.0.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3566-pinetab2.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb10max3.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts
arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dts
arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dtsi
arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts
arch/arm64/boot/dts/rockchip/rk3568-qnap-ts433.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk356x.dtsi
arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts
arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5.dtsi
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-common.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dts
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-wifi.dtso [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a.dtsi
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dts
arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b.dtsi
arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts
arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts
arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts
arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts
arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts
arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3588-tiger.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts
arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts
arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6c.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6s.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts
arch/arm64/boot/dts/rockchip/rk3588s.dtsi
arch/arm64/boot/dts/st/stm32mp251.dtsi
arch/arm64/boot/dts/st/stm32mp255.dtsi
arch/arm64/boot/dts/tesla/fsd.dtsi
arch/arm64/boot/dts/ti/Makefile
arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts
arch/arm64/boot/dts/ti/k3-am62-main.dtsi
arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi
arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi
arch/arm64/boot/dts/ti/k3-am62-thermal.dtsi
arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi
arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi
arch/arm64/boot/dts/ti/k3-am62-verdin-mallow.dtsi
arch/arm64/boot/dts/ti/k3-am62-verdin-wifi.dtsi
arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi
arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-am62.dtsi
arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-ov5640.dtso
arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-tevi-ov5640.dtso
arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts
arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts
arch/arm64/boot/dts/ti/k3-am625-sk.dts
arch/arm64/boot/dts/ti/k3-am625.dtsi
arch/arm64/boot/dts/ti/k3-am62a-main.dtsi
arch/arm64/boot/dts/ti/k3-am62a-mcu.dtsi
arch/arm64/boot/dts/ti/k3-am62a-thermal.dtsi
arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-am62a.dtsi
arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
arch/arm64/boot/dts/ti/k3-am62a7.dtsi
arch/arm64/boot/dts/ti/k3-am62p-main.dtsi
arch/arm64/boot/dts/ti/k3-am62p-mcu.dtsi
arch/arm64/boot/dts/ti/k3-am62p-thermal.dtsi
arch/arm64/boot/dts/ti/k3-am62p-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-am62p.dtsi
arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
arch/arm64/boot/dts/ti/k3-am62p5.dtsi
arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra-gpio-fan.dtso [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi
arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso
arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso
arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso
arch/arm64/boot/dts/ti/k3-am62x-sk-hdmi-audio.dtso
arch/arm64/boot/dts/ti/k3-am64-main.dtsi
arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi
arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi
arch/arm64/boot/dts/ti/k3-am64-thermal.dtsi
arch/arm64/boot/dts/ti/k3-am64.dtsi
arch/arm64/boot/dts/ti/k3-am642-evm-icssg1-dualemac.dtso [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-am642-evm.dts
arch/arm64/boot/dts/ti/k3-am642-hummingboard-t-pcie.dtso [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-am642-hummingboard-t-usb3.dtso [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-am642-hummingboard-t.dts [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts
arch/arm64/boot/dts/ti/k3-am642-sk.dts
arch/arm64/boot/dts/ti/k3-am642-sr-som.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts
arch/arm64/boot/dts/ti/k3-am642.dtsi
arch/arm64/boot/dts/ti/k3-am65-iot2050-arduino-connector.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi
arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi
arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi
arch/arm64/boot/dts/ti/k3-am65-iot2050-dp.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-am65-iot2050-usb3.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-am65-main.dtsi
arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi
arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-am65.dtsi
arch/arm64/boot/dts/ti/k3-am652.dtsi
arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi
arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-pg2.dts
arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic.dts
arch/arm64/boot/dts/ti/k3-am654-base-board-rocktech-rk101-panel.dtso
arch/arm64/boot/dts/ti/k3-am654-base-board.dts
arch/arm64/boot/dts/ti/k3-am654-icssg2.dtso
arch/arm64/boot/dts/ti/k3-am654-idk.dtso
arch/arm64/boot/dts/ti/k3-am654-industrial-thermal.dtsi
arch/arm64/boot/dts/ti/k3-am654-pcie-usb2.dtso [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-am654-pcie-usb3.dtso [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-am654.dtsi
arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi
arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts
arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-pg2.dts
arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-sm.dts [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced.dts
arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts
arch/arm64/boot/dts/ti/k3-am68-sk-som.dtsi
arch/arm64/boot/dts/ti/k3-am69-sk.dts
arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts
arch/arm64/boot/dts/ti/k3-j7200-evm-quad-port-eth-exp.dtso
arch/arm64/boot/dts/ti/k3-j7200-main.dtsi
arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi
arch/arm64/boot/dts/ti/k3-j7200-thermal.dtsi
arch/arm64/boot/dts/ti/k3-j7200.dtsi
arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts
arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
arch/arm64/boot/dts/ti/k3-j721e-evm-gesi-exp-board.dtso
arch/arm64/boot/dts/ti/k3-j721e-evm-pcie0-ep.dtso
arch/arm64/boot/dts/ti/k3-j721e-evm-quad-port-eth-exp.dtso
arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-j721e-sk-csi2-dual-imx219.dtso [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-j721e-sk.dts
arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi
arch/arm64/boot/dts/ti/k3-j721e-thermal.dtsi
arch/arm64/boot/dts/ti/k3-j721e.dtsi
arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts
arch/arm64/boot/dts/ti/k3-j721s2-evm-gesi-exp-board.dtso
arch/arm64/boot/dts/ti/k3-j721s2-evm-pcie1-ep.dtso
arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi
arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi
arch/arm64/boot/dts/ti/k3-j721s2-thermal.dtsi
arch/arm64/boot/dts/ti/k3-j721s2.dtsi
arch/arm64/boot/dts/ti/k3-j722s-evm.dts [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-j722s.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/ti/k3-j784s4-evm.dts
arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi
arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-j784s4-thermal.dtsi
arch/arm64/boot/dts/ti/k3-j784s4.dtsi
arch/arm64/boot/dts/ti/k3-pinctrl.h
arch/arm64/boot/dts/ti/k3-serdes.h
arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi
arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso
arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso
arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm015-dc1.dts
arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm016-dc2.dts
arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm019-dc5.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revA.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revC.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu111-revA.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu1275-revA.dts
arch/arm64/boot/dts/xilinx/zynqmp.dtsi
arch/arm64/configs/defconfig
arch/arm64/configs/virt.config
arch/arm64/crypto/aes-neonbs-glue.c
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/cputype.h
arch/arm64/include/asm/fpsimd.h
arch/arm64/include/asm/page-def.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/signal.c
arch/arm64/kernel/stacktrace.c
arch/arm64/kernel/suspend.c
arch/arm64/kernel/vdso.c
arch/arm64/kvm/Kconfig
arch/arm64/kvm/hyp/pgtable.c
arch/arm64/kvm/pkvm.c
arch/arm64/kvm/vgic/vgic-its.c
arch/csky/Kconfig
arch/csky/include/asm/page.h
arch/csky/include/asm/vdso.h
arch/csky/kernel/smp.c
arch/csky/kernel/vdso.c
arch/hexagon/Kconfig
arch/hexagon/include/asm/page.h
arch/hexagon/kernel/smp.c
arch/loongarch/Kconfig
arch/loongarch/boot/dts/loongson-2k0500-ref.dts
arch/loongarch/boot/dts/loongson-2k1000-ref.dts
arch/loongarch/include/asm/page.h
arch/loongarch/kernel/setup.c
arch/loongarch/kernel/smp.c
arch/loongarch/kernel/vdso.c
arch/loongarch/kvm/vcpu.c
arch/m68k/Kconfig
arch/m68k/Kconfig.cpu
arch/m68k/Makefile
arch/m68k/configs/amiga_defconfig
arch/m68k/configs/apollo_defconfig
arch/m68k/configs/atari_defconfig
arch/m68k/configs/bvme6000_defconfig
arch/m68k/configs/hp300_defconfig
arch/m68k/configs/mac_defconfig
arch/m68k/configs/multi_defconfig
arch/m68k/configs/mvme147_defconfig
arch/m68k/configs/mvme16x_defconfig
arch/m68k/configs/q40_defconfig
arch/m68k/configs/sun3_defconfig
arch/m68k/configs/sun3x_defconfig
arch/m68k/emu/nfblock.c
arch/m68k/include/asm/page.h
arch/microblaze/Kconfig
arch/microblaze/include/asm/page.h
arch/mips/Kconfig
arch/mips/include/asm/checksum.h
arch/mips/include/asm/page.h
arch/mips/include/asm/ptrace.h
arch/mips/include/asm/vdso.h
arch/mips/kernel/ptrace.c
arch/mips/kernel/vdso.c
arch/nios2/Kconfig
arch/nios2/include/asm/page.h
arch/openrisc/Kconfig
arch/openrisc/include/asm/page.h
arch/openrisc/kernel/smp.c
arch/parisc/Kconfig
arch/parisc/Makefile
arch/parisc/include/asm/kprobes.h
arch/parisc/include/asm/page.h
arch/parisc/kernel/ftrace.c
arch/parisc/kernel/processor.c
arch/parisc/kernel/unwind.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/ftrace.h
arch/powerpc/include/asm/page.h
arch/powerpc/include/asm/papr-sysparm.h
arch/powerpc/include/asm/ppc-pci.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/rtas.h
arch/powerpc/include/asm/sections.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/include/uapi/asm/papr-sysparm.h
arch/powerpc/kernel/cpu_setup_6xx.S
arch/powerpc/kernel/cpu_specs_e500mc.h
arch/powerpc/kernel/interrupt_64.S
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/trace/ftrace.c
arch/powerpc/kernel/trace/ftrace_64_pg.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_nestedv2.c
arch/powerpc/mm/kasan/init_32.c
arch/powerpc/platforms/85xx/mpc8536_ds.c
arch/powerpc/platforms/85xx/mvme2500.c
arch/powerpc/platforms/85xx/p1010rdb.c
arch/powerpc/platforms/85xx/p1022_ds.c
arch/powerpc/platforms/85xx/p1022_rdk.c
arch/powerpc/platforms/85xx/socrates_fpga_pic.c
arch/powerpc/platforms/85xx/xes_mpc85xx.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/pci_dlpar.c
arch/powerpc/sysdev/udbg_memcons.c
arch/riscv/Kconfig
arch/riscv/Kconfig.socs
arch/riscv/boot/dts/Makefile
arch/riscv/boot/dts/canaan/Makefile
arch/riscv/boot/dts/microchip/Makefile
arch/riscv/boot/dts/sifive/Makefile
arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
arch/riscv/boot/dts/sophgo/sg2042.dtsi
arch/riscv/boot/dts/starfive/jh7100.dtsi
arch/riscv/boot/dts/starfive/jh7110.dtsi
arch/riscv/configs/nommu_k210_defconfig
arch/riscv/configs/nommu_k210_sdcard_defconfig
arch/riscv/include/asm/csr.h
arch/riscv/include/asm/ftrace.h
arch/riscv/include/asm/hugetlb.h
arch/riscv/include/asm/hwcap.h
arch/riscv/include/asm/page.h
arch/riscv/include/asm/pgalloc.h
arch/riscv/include/asm/pgtable-64.h
arch/riscv/include/asm/pgtable.h
arch/riscv/include/asm/suspend.h
arch/riscv/include/asm/vmalloc.h
arch/riscv/kernel/Makefile
arch/riscv/kernel/cpufeature.c
arch/riscv/kernel/paravirt.c
arch/riscv/kernel/return_address.c [new file with mode: 0644]
arch/riscv/kernel/smpboot.c
arch/riscv/kernel/suspend.c
arch/riscv/kernel/vdso.c
arch/riscv/kvm/vcpu_sbi_sta.c
arch/riscv/mm/hugetlbpage.c
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/boot/.gitignore
arch/s390/boot/Makefile
arch/s390/boot/boot.h
arch/s390/boot/startup.c
arch/s390/boot/vmlinux.lds.S
arch/s390/configs/compat.config [new file with mode: 0644]
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/configs/zfcpdump_defconfig
arch/s390/crypto/chacha-glue.c
arch/s390/crypto/chacha-s390.S
arch/s390/crypto/crc32-vx.c
arch/s390/crypto/crc32-vx.h [new file with mode: 0644]
arch/s390/crypto/crc32be-vx.c [moved from arch/s390/crypto/crc32be-vx.S with 56% similarity]
arch/s390/crypto/crc32le-vx.c [moved from arch/s390/crypto/crc32le-vx.S with 52% similarity]
arch/s390/crypto/paes_s390.c
arch/s390/hypfs/hypfs_diag0c.c
arch/s390/hypfs/hypfs_sprp.c
arch/s390/include/asm/access-regs.h [new file with mode: 0644]
arch/s390/include/asm/appldata.h
arch/s390/include/asm/asm-prototypes.h
arch/s390/include/asm/bug.h
arch/s390/include/asm/checksum.h
arch/s390/include/asm/diag.h
arch/s390/include/asm/entry-common.h
arch/s390/include/asm/fpu-insn-asm.h [moved from arch/s390/include/asm/vx-insn-asm.h with 86% similarity]
arch/s390/include/asm/fpu-insn.h [new file with mode: 0644]
arch/s390/include/asm/fpu-types.h [new file with mode: 0644]
arch/s390/include/asm/fpu.h [new file with mode: 0644]
arch/s390/include/asm/fpu/api.h [deleted file]
arch/s390/include/asm/fpu/internal.h [deleted file]
arch/s390/include/asm/fpu/types.h [deleted file]
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/lowcore.h
arch/s390/include/asm/page.h
arch/s390/include/asm/pai.h
arch/s390/include/asm/pci.h
arch/s390/include/asm/physmem_info.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/ptrace.h
arch/s390/include/asm/stacktrace.h
arch/s390/include/asm/switch_to.h [deleted file]
arch/s390/include/asm/vdso/data.h
arch/s390/include/asm/vx-insn.h [deleted file]
arch/s390/kernel/cache.c
arch/s390/kernel/compat_signal.c
arch/s390/kernel/crash_dump.c
arch/s390/kernel/diag.c
arch/s390/kernel/early.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry.h
arch/s390/kernel/fpu.c
arch/s390/kernel/ipl.c
arch/s390/kernel/machine_kexec.c
arch/s390/kernel/nmi.c
arch/s390/kernel/os_info.c
arch/s390/kernel/perf_pai_crypto.c
arch/s390/kernel/perf_pai_ext.c
arch/s390/kernel/perf_regs.c
arch/s390/kernel/process.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/setup.c
arch/s390/kernel/signal.c
arch/s390/kernel/smp.c
arch/s390/kernel/sysinfo.c
arch/s390/kernel/text_amode31.S
arch/s390/kernel/time.c
arch/s390/kernel/traps.c
arch/s390/kernel/uprobes.c
arch/s390/kernel/vdso.c
arch/s390/kernel/vdso32/Makefile
arch/s390/kernel/vdso32/vdso32.lds.S
arch/s390/kernel/vdso64/Makefile
arch/s390/kernel/vdso64/vdso64.lds.S
arch/s390/kernel/vmlinux.lds.S
arch/s390/kvm/gaccess.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/vsie.c
arch/s390/lib/Makefile
arch/s390/lib/csum-partial.c [new file with mode: 0644]
arch/s390/mm/extmem.c
arch/s390/mm/mmap.c
arch/s390/pci/pci.c
arch/s390/pci/pci_debug.c
arch/s390/pci/pci_event.c
arch/s390/pci/pci_sysfs.c
arch/s390/tools/.gitignore
arch/s390/tools/Makefile
arch/s390/tools/relocs.c [new file with mode: 0644]
arch/sh/include/asm/page.h
arch/sh/mm/Kconfig
arch/sparc/Kconfig
arch/sparc/Makefile
arch/sparc/include/asm/page_32.h
arch/sparc/include/asm/page_64.h
arch/sparc/kernel/smp_64.c
arch/sparc/video/Makefile
arch/um/Kconfig
arch/um/drivers/ubd_kern.c
arch/um/include/asm/page.h
arch/x86/Kbuild
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/boot/compressed/acpi.c
arch/x86/boot/compressed/cmdline.c
arch/x86/boot/compressed/efi.c
arch/x86/boot/compressed/efi.h
arch/x86/boot/compressed/ident_map_64.c
arch/x86/boot/compressed/misc.c
arch/x86/boot/compressed/misc.h
arch/x86/boot/compressed/pgtable_64.c
arch/x86/boot/compressed/sev.c
arch/x86/boot/header.S
arch/x86/coco/core.c
arch/x86/configs/i386_defconfig
arch/x86/entry/Makefile
arch/x86/entry/calling.h
arch/x86/entry/entry.S
arch/x86/entry/entry_32.S
arch/x86/entry/entry_64.S
arch/x86/entry/entry_64_compat.S
arch/x86/entry/entry_64_fred.S [new file with mode: 0644]
arch/x86/entry/entry_fred.c [new file with mode: 0644]
arch/x86/entry/thunk_32.S
arch/x86/entry/thunk_64.S
arch/x86/entry/vdso/Makefile
arch/x86/entry/vdso/vma.c
arch/x86/entry/vsyscall/vsyscall_64.c
arch/x86/events/amd/core.c
arch/x86/events/amd/uncore.c
arch/x86/events/intel/core.c
arch/x86/events/intel/cstate.c
arch/x86/events/intel/ds.c
arch/x86/events/intel/uncore.c
arch/x86/events/intel/uncore_nhmex.c
arch/x86/events/intel/uncore_snb.c
arch/x86/events/intel/uncore_snbep.c
arch/x86/events/rapl.c
arch/x86/hyperv/hv_vtl.c
arch/x86/hyperv/ivm.c
arch/x86/include/asm/apic.h
arch/x86/include/asm/asm-prototypes.h
arch/x86/include/asm/asm.h
arch/x86/include/asm/barrier.h
arch/x86/include/asm/coco.h
arch/x86/include/asm/cpu.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/cpuid.h
arch/x86/include/asm/current.h
arch/x86/include/asm/debugreg.h
arch/x86/include/asm/desc.h
arch/x86/include/asm/disabled-features.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/elf.h
arch/x86/include/asm/entry-common.h
arch/x86/include/asm/extable_fixup_types.h
arch/x86/include/asm/fpu/sched.h
arch/x86/include/asm/fred.h [new file with mode: 0644]
arch/x86/include/asm/fsgsbase.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/ia32.h
arch/x86/include/asm/idtentry.h
arch/x86/include/asm/io.h
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/iommu.h
arch/x86/include/asm/kexec.h
arch/x86/include/asm/kvm-x86-ops.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/kvmclock.h
arch/x86/include/asm/linkage.h
arch/x86/include/asm/local.h
arch/x86/include/asm/mem_encrypt.h
arch/x86/include/asm/mpspec.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/msr.h
arch/x86/include/asm/nmi.h
arch/x86/include/asm/nospec-branch.h
arch/x86/include/asm/page.h
arch/x86/include/asm/page_types.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/percpu.h
arch/x86/include/asm/perf_event_p4.h
arch/x86/include/asm/pgalloc.h
arch/x86/include/asm/pgtable-3level.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_64.h
arch/x86/include/asm/pgtable_64_types.h
arch/x86/include/asm/preempt.h
arch/x86/include/asm/processor-flags.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/prom.h
arch/x86/include/asm/pti.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/resctrl.h
arch/x86/include/asm/set_memory.h
arch/x86/include/asm/setup.h
arch/x86/include/asm/setup_data.h [new file with mode: 0644]
arch/x86/include/asm/sev.h
arch/x86/include/asm/smp.h
arch/x86/include/asm/spec-ctrl.h
arch/x86/include/asm/special_insns.h
arch/x86/include/asm/static_call.h
arch/x86/include/asm/switch_to.h
arch/x86/include/asm/text-patching.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/topology.h
arch/x86/include/asm/trap_pf.h
arch/x86/include/asm/trapnr.h
arch/x86/include/asm/tsc.h
arch/x86/include/asm/uaccess_64.h
arch/x86/include/asm/vmx.h
arch/x86/include/asm/vsyscall.h
arch/x86/include/asm/x86_init.h
arch/x86/include/uapi/asm/bootparam.h
arch/x86/include/uapi/asm/processor-flags.h
arch/x86/include/uapi/asm/setup_data.h [new file with mode: 0644]
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/wakeup_64.S
arch/x86/kernel/alternative.c
arch/x86/kernel/amd_nb.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/apic_common.c
arch/x86/kernel/apic/apic_flat_64.c
arch/x86/kernel/apic/apic_noop.c
arch/x86/kernel/apic/apic_numachip.c
arch/x86/kernel/apic/bigsmp_32.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/local.h
arch/x86/kernel/apic/probe_32.c
arch/x86/kernel/apic/x2apic_cluster.c
arch/x86/kernel/apic/x2apic_phys.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/asm-offsets.c
arch/x86/kernel/callthunks.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/acrn.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/cacheinfo.c
arch/x86/kernel/cpu/centaur.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpu.h
arch/x86/kernel/cpu/cpuid-deps.c
arch/x86/kernel/cpu/debugfs.c
arch/x86/kernel/cpu/hygon.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/intel_pconfig.c
arch/x86/kernel/cpu/mce/amd.c
arch/x86/kernel/cpu/mce/core.c
arch/x86/kernel/cpu/mce/inject.c
arch/x86/kernel/cpu/microcode/intel.c
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/cpu/mtrr/generic.c
arch/x86/kernel/cpu/rdrand.c
arch/x86/kernel/cpu/resctrl/core.c
arch/x86/kernel/cpu/resctrl/ctrlmondata.c
arch/x86/kernel/cpu/resctrl/internal.h
arch/x86/kernel/cpu/resctrl/monitor.c
arch/x86/kernel/cpu/resctrl/pseudo_lock.c
arch/x86/kernel/cpu/resctrl/rdtgroup.c
arch/x86/kernel/cpu/topology.c
arch/x86/kernel/cpu/topology.h [new file with mode: 0644]
arch/x86/kernel/cpu/topology_amd.c [new file with mode: 0644]
arch/x86/kernel/cpu/topology_common.c [new file with mode: 0644]
arch/x86/kernel/cpu/topology_ext.c [new file with mode: 0644]
arch/x86/kernel/cpu/zhaoxin.c
arch/x86/kernel/crash.c
arch/x86/kernel/devicetree.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/e820.c
arch/x86/kernel/espfix_64.c
arch/x86/kernel/fpu/bugs.c
arch/x86/kernel/fred.c [new file with mode: 0644]
arch/x86/kernel/ftrace.c
arch/x86/kernel/head64.c
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/hpet.c
arch/x86/kernel/idt.c
arch/x86/kernel/irqinit.c
arch/x86/kernel/jailhouse.c
arch/x86/kernel/kexec-bzimage64.c
arch/x86/kernel/kprobes/opt.c
arch/x86/kernel/kvm.c
arch/x86/kernel/kvmclock.c
arch/x86/kernel/ldt.c
arch/x86/kernel/mpparse.c
arch/x86/kernel/nmi.c
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/setup.c
arch/x86/kernel/sev-shared.c
arch/x86/kernel/sev.c
arch/x86/kernel/sev_verify_cbit.S
arch/x86/kernel/smp.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/static_call.c
arch/x86/kernel/step.c
arch/x86/kernel/sys_x86_64.c
arch/x86/kernel/traps.c
arch/x86/kernel/tsc.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kernel/vsmp_64.c
arch/x86/kernel/x86_init.c
arch/x86/kvm/Kconfig
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/mmu/mmu_internal.h
arch/x86/kvm/svm/nested.c
arch/x86/kvm/svm/sev.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/svm/svm.h
arch/x86/kvm/svm/vmenter.S
arch/x86/kvm/vmx/pmu_intel.c
arch/x86/kvm/vmx/run_flags.h
arch/x86/kvm/vmx/vmenter.S
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/lib/Makefile
arch/x86/lib/cmpxchg16b_emu.S
arch/x86/lib/cmpxchg8b_emu.S
arch/x86/lib/insn-eval.c
arch/x86/lib/insn.c
arch/x86/lib/msr-smp.c
arch/x86/lib/msr.c
arch/x86/lib/retpoline.S
arch/x86/lib/x86-opcode-map.txt
arch/x86/mm/Makefile
arch/x86/mm/amdtopology.c
arch/x86/mm/debug_pagetables.c
arch/x86/mm/dump_pagetables.c
arch/x86/mm/extable.c
arch/x86/mm/fault.c
arch/x86/mm/ident_map.c
arch/x86/mm/maccess.c
arch/x86/mm/mem_encrypt.c
arch/x86/mm/mem_encrypt_identity.c
arch/x86/mm/numa.c
arch/x86/mm/pat/memtype.c
arch/x86/mm/pat/set_memory.c
arch/x86/mm/pgtable.c
arch/x86/mm/tlb.c
arch/x86/net/bpf_jit_comp.c
arch/x86/net/bpf_jit_comp32.c
arch/x86/platform/ce4100/ce4100.c
arch/x86/platform/efi/efi.c
arch/x86/platform/intel-mid/intel-mid.c
arch/x86/platform/pvh/enlighten.c
arch/x86/purgatory/Makefile
arch/x86/realmode/rm/trampoline_64.S
arch/x86/virt/svm/Makefile [new file with mode: 0644]
arch/x86/virt/svm/sev.c [new file with mode: 0644]
arch/x86/xen/apic.c
arch/x86/xen/enlighten_hvm.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/enlighten_pvh.c
arch/x86/xen/smp.c
arch/x86/xen/smp.h
arch/x86/xen/smp_pv.c
arch/x86/xen/vga.c
arch/x86/xen/xen-asm.S
arch/x86/xen/xen-head.S
arch/xtensa/Kconfig
arch/xtensa/include/asm/page.h
arch/xtensa/platforms/iss/simdisk.c
block/bdev.c
block/bfq-cgroup.c
block/bfq-iosched.c
block/bio-integrity.c
block/bio.c
block/blk-cgroup.c
block/blk-cgroup.h
block/blk-core.c
block/blk-crypto-fallback.c
block/blk-flush.c
block/blk-integrity.c
block/blk-iocost.c
block/blk-iolatency.c
block/blk-lib.c
block/blk-merge.c
block/blk-mq.c
block/blk-settings.c
block/blk-stat.c
block/blk-sysfs.c
block/blk-throttle.c
block/blk-wbt.c
block/blk-zoned.c
block/blk.h
block/bounce.c
block/bsg-lib.c
block/fops.c
block/genhd.c
block/holder.c
block/ioctl.c
block/opal_proto.h
block/partitions/core.c
block/partitions/mac.c
block/sed-opal.c
block/t10-pi.c
crypto/lskcipher.c
drivers/accel/ivpu/ivpu_hw_37xx.c
drivers/accel/ivpu/ivpu_hw_40xx.c
drivers/accel/ivpu/ivpu_pm.c
drivers/acpi/apei/ghes.c
drivers/acpi/ec.c
drivers/ata/ahci.c
drivers/ata/ahci_ceva.c
drivers/ata/libata-core.c
drivers/base/arch_topology.c
drivers/base/base.h
drivers/base/core.c
drivers/base/cpu.c
drivers/base/platform-msi.c
drivers/base/regmap/regmap-kunit.c
drivers/block/amiflop.c
drivers/block/aoe/aoeblk.c
drivers/block/aoe/aoecmd.c
drivers/block/aoe/aoenet.c
drivers/block/ataflop.c
drivers/block/brd.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_state.c
drivers/block/drbd/drbd_state_change.h
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/n64cart.c
drivers/block/nbd.c
drivers/block/null_blk/main.c
drivers/block/null_blk/null_blk.h
drivers/block/null_blk/trace.h
drivers/block/null_blk/zoned.c
drivers/block/pktcdvd.c
drivers/block/ps3disk.c
drivers/block/ps3vram.c
drivers/block/rbd.c
drivers/block/rnbd/rnbd-clt.c
drivers/block/rnbd/rnbd-srv.c
drivers/block/rnbd/rnbd-srv.h
drivers/block/sunvdc.c
drivers/block/swim.c
drivers/block/swim3.c
drivers/block/ublk_drv.c
drivers/block/virtio_blk.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkback/common.h
drivers/block/xen-blkback/xenbus.c
drivers/block/xen-blkfront.c
drivers/block/z2ram.c
drivers/block/zram/zram_drv.c
drivers/block/zram/zram_drv.h
drivers/bluetooth/btqca.c
drivers/bluetooth/hci_bcm4377.c
drivers/bluetooth/hci_qca.c
drivers/bus/Kconfig
drivers/bus/imx-weim.c
drivers/bus/sunxi-rsb.c
drivers/bus/ti-sysc.c
drivers/cache/ax45mp_cache.c
drivers/cdrom/gdrom.c
drivers/clk/rockchip/clk-rk3588.c
drivers/clk/rockchip/clk.c
drivers/clk/rockchip/clk.h
drivers/clk/samsung/clk-gs101.c
drivers/clocksource/arm_arch_timer.c
drivers/comedi/drivers/comedi_8255.c
drivers/comedi/drivers/comedi_test.c
drivers/connector/cn_proc.c
drivers/counter/counter-core.c
drivers/cpufreq/intel_pstate.c
drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c
drivers/crypto/ccp/Kconfig
drivers/crypto/ccp/sev-dev.c
drivers/crypto/ccp/sev-dev.h
drivers/crypto/rockchip/rk3288_crypto_ahash.c
drivers/crypto/virtio/virtio_crypto_akcipher_algs.c
drivers/cxl/acpi.c
drivers/cxl/core/cdat.c
drivers/cxl/core/mbox.c
drivers/cxl/core/memdev.c
drivers/cxl/core/pci.c
drivers/cxl/core/region.c
drivers/cxl/cxl.h
drivers/cxl/cxlmem.h
drivers/cxl/mem.c
drivers/cxl/pci.c
drivers/dma/dw-edma/dw-edma-v0-core.c
drivers/dma/dw-edma/dw-hdma-v0-core.c
drivers/dma/dw-edma/dw-hdma-v0-regs.h
drivers/dma/fsl-edma-common.c
drivers/dma/fsl-edma-common.h
drivers/dma/fsl-edma-main.c
drivers/dma/fsl-qdma.c
drivers/dma/idxd/cdev.c
drivers/dma/idxd/debugfs.c
drivers/dma/idxd/idxd.h
drivers/dma/idxd/init.c
drivers/dma/idxd/irq.c
drivers/dma/mv_xor_v2.c
drivers/dma/ptdma/ptdma-dmaengine.c
drivers/dma/qcom/hidma.c
drivers/dpll/dpll_core.c
drivers/dpll/dpll_core.h
drivers/dpll/dpll_netlink.c
drivers/dpll/dpll_nl.c
drivers/dpll/dpll_nl.h
drivers/edac/Kconfig
drivers/edac/amd64_edac.c
drivers/edac/i10nm_base.c
drivers/edac/igen6_edac.c
drivers/edac/mce_amd.c
drivers/edac/synopsys_edac.c
drivers/edac/versal_edac.c
drivers/firewire/core-card.c
drivers/firewire/ohci.c
drivers/firmware/arm_ffa/bus.c
drivers/firmware/arm_scmi/bus.c
drivers/firmware/arm_scmi/clock.c
drivers/firmware/arm_scmi/common.h
drivers/firmware/arm_scmi/driver.c
drivers/firmware/arm_scmi/notify.c
drivers/firmware/arm_scmi/notify.h
drivers/firmware/arm_scmi/optee.c
drivers/firmware/arm_scmi/perf.c
drivers/firmware/arm_scmi/power.c
drivers/firmware/arm_scmi/powercap.c
drivers/firmware/arm_scmi/protocols.h
drivers/firmware/arm_scmi/reset.c
drivers/firmware/arm_scmi/sensors.c
drivers/firmware/arm_scmi/smc.c
drivers/firmware/arm_scmi/system.c
drivers/firmware/efi/capsule-loader.c
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/x86-stub.c
drivers/firmware/microchip/mpfs-auto-update.c
drivers/firmware/tegra/bpmp-debugfs.c
drivers/gpio/gpio-74x164.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/amdgpu/soc21.c
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_topology.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
drivers/gpu/drm/amd/display/dc/dce/dce_panel_cntl.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c
drivers/gpu/drm/amd/display/dc/dcn301/dcn301_panel_cntl.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c
drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c
drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c
drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c
drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h
drivers/gpu/drm/amd/display/dc/link/link_factory.c
drivers/gpu/drm/amd/display/dc/link/link_validation.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c
drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
drivers/gpu/drm/amd/pm/amdgpu_pm.c
drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
drivers/gpu/drm/bridge/aux-hpd-bridge.c
drivers/gpu/drm/drm_buddy.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/drm_syncobj.c
drivers/gpu/drm/i915/display/intel_display_power_well.c
drivers/gpu/drm/i915/display/intel_display_types.h
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_dp.h
drivers/gpu/drm/i915/display/intel_dp_hdcp.c
drivers/gpu/drm/i915/display/intel_dp_mst.c
drivers/gpu/drm/i915/display/intel_modeset_setup.c
drivers/gpu/drm/i915/display/intel_psr.c
drivers/gpu/drm/i915/display/intel_sdvo.c
drivers/gpu/drm/i915/display/intel_tv.c
drivers/gpu/drm/i915/display/intel_vdsc_regs.h
drivers/gpu/drm/i915/gem/i915_gem_userptr.c
drivers/gpu/drm/i915/selftests/intel_scheduler_helpers.c
drivers/gpu/drm/meson/meson_encoder_cvbs.c
drivers/gpu/drm/meson/meson_encoder_dsi.c
drivers/gpu/drm/meson/meson_encoder_hdmi.c
drivers/gpu/drm/msm/adreno/a6xx_gpu.c
drivers/gpu/drm/msm/dp/dp_display.c
drivers/gpu/drm/msm/msm_gem_prime.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_iommu.c
drivers/gpu/drm/msm/msm_ringbuffer.c
drivers/gpu/drm/nouveau/Kconfig
drivers/gpu/drm/nouveau/include/nvkm/core/client.h
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_abi16.h
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_exec.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_sched.c
drivers/gpu/drm/nouveau/nouveau_sched.h
drivers/gpu/drm/nouveau/nouveau_svm.c
drivers/gpu/drm/nouveau/nouveau_uvmm.c
drivers/gpu/drm/nouveau/nvkm/core/client.c
drivers/gpu/drm/nouveau/nvkm/core/object.c
drivers/gpu/drm/nouveau/nvkm/subdev/bar/r535.c
drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tests/drm_buddy_test.c
drivers/gpu/drm/tests/drm_mm_test.c
drivers/gpu/drm/ttm/ttm_pool.c
drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h
drivers/gpu/drm/xe/tests/xe_migrate.c
drivers/gpu/drm/xe/tests/xe_mocs_test.c
drivers/gpu/drm/xe/xe_bo.c
drivers/gpu/drm/xe/xe_bo.h
drivers/gpu/drm/xe/xe_device.c
drivers/gpu/drm/xe/xe_device.h
drivers/gpu/drm/xe/xe_device_types.h
drivers/gpu/drm/xe/xe_drm_client.c
drivers/gpu/drm/xe/xe_exec_queue.c
drivers/gpu/drm/xe/xe_exec_queue_types.h
drivers/gpu/drm/xe/xe_execlist.c
drivers/gpu/drm/xe/xe_gt_idle.c
drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c
drivers/gpu/drm/xe/xe_guc_submit.c
drivers/gpu/drm/xe/xe_lrc.c
drivers/gpu/drm/xe/xe_mmio.c
drivers/gpu/drm/xe/xe_pt.c
drivers/gpu/drm/xe/xe_pt_walk.c
drivers/gpu/drm/xe/xe_pt_walk.h
drivers/gpu/drm/xe/xe_range_fence.c
drivers/gpu/drm/xe/xe_sync.c
drivers/gpu/drm/xe/xe_sync.h
drivers/gpu/drm/xe/xe_sync_types.h
drivers/gpu/drm/xe/xe_tile.c
drivers/gpu/drm/xe/xe_trace.h
drivers/gpu/drm/xe/xe_vm.c
drivers/gpu/drm/xe/xe_vm_types.h
drivers/gpu/host1x/dev.c
drivers/gpu/host1x/dev.h
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-multitouch.c
drivers/hid/intel-ish-hid/ishtp/bus.c
drivers/hid/intel-ish-hid/ishtp/client.c
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c
drivers/hv/channel.c
drivers/hv/hv_util.c
drivers/hv/vmbus_drv.c
drivers/hwmon/coretemp.c
drivers/hwmon/fam15h_power.c
drivers/hwmon/nct6775-core.c
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-aspeed.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-pasemi-core.c
drivers/i2c/busses/i2c-qcom-geni.c
drivers/i2c/busses/i2c-wmt.c
drivers/iio/accel/Kconfig
drivers/iio/accel/adxl367.c
drivers/iio/accel/adxl367_i2c.c
drivers/iio/adc/ad4130.c
drivers/iio/adc/ad7091r8.c
drivers/iio/humidity/Kconfig
drivers/iio/humidity/Makefile
drivers/iio/humidity/hdc3020.c
drivers/iio/imu/bno055/Kconfig
drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
drivers/iio/industrialio-core.c
drivers/iio/light/hid-sensor-als.c
drivers/iio/magnetometer/rm3100-core.c
drivers/iio/pressure/bmp280-spi.c
drivers/iio/pressure/dlhl60d.c
drivers/infiniband/hw/bnxt_re/ib_verbs.c
drivers/infiniband/hw/bnxt_re/main.c
drivers/infiniband/hw/bnxt_re/qplib_fp.c
drivers/infiniband/hw/hfi1/pio.c
drivers/infiniband/hw/hfi1/sdma.c
drivers/infiniband/hw/irdma/defs.h
drivers/infiniband/hw/irdma/hw.c
drivers/infiniband/hw/irdma/verbs.c
drivers/infiniband/hw/mlx5/cong.c
drivers/infiniband/hw/mlx5/devx.c
drivers/infiniband/hw/mlx5/wr.c
drivers/infiniband/hw/qedr/verbs.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/mouse/bcm5974.c
drivers/input/rmi4/rmi_driver.c
drivers/interconnect/qcom/sc8180x.c
drivers/interconnect/qcom/sm8550.c
drivers/interconnect/qcom/sm8650.c
drivers/interconnect/qcom/x1e80100.c
drivers/iommu/Kconfig
drivers/iommu/amd/amd_iommu.h
drivers/iommu/amd/init.c
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
drivers/iommu/arm/arm-smmu/arm-smmu.c
drivers/iommu/intel/iommu.c
drivers/iommu/intel/iommu.h
drivers/iommu/intel/nested.c
drivers/iommu/intel/pasid.c
drivers/iommu/intel/pasid.h
drivers/iommu/iommu-sva.c
drivers/iommu/iommufd/hw_pagetable.c
drivers/iommu/iommufd/io_pagetable.c
drivers/iommu/iommufd/iommufd_test.h
drivers/iommu/iommufd/iova_bitmap.c
drivers/iommu/iommufd/selftest.c
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-bcm6345-l1.c
drivers/irqchip/irq-bcm7038-l1.c
drivers/irqchip/irq-brcmstb-l2.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-imgpdc.c
drivers/irqchip/irq-imx-intmux.c
drivers/irqchip/irq-imx-irqsteer.c
drivers/irqchip/irq-keystone.c
drivers/irqchip/irq-loongson-eiointc.c
drivers/irqchip/irq-ls-scfg-msi.c
drivers/irqchip/irq-madera.c
drivers/irqchip/irq-mbigen.c
drivers/irqchip/irq-meson-gpio.c
drivers/irqchip/irq-mvebu-pic.c
drivers/irqchip/irq-pruss-intc.c
drivers/irqchip/irq-qcom-mpm.c
drivers/irqchip/irq-renesas-intc-irqpin.c
drivers/irqchip/irq-renesas-irqc.c
drivers/irqchip/irq-renesas-rza1.c
drivers/irqchip/irq-riscv-intc.c
drivers/irqchip/irq-sifive-plic.c
drivers/irqchip/irq-starfive-jh8100-intc.c [new file with mode: 0644]
drivers/irqchip/irq-stm32-exti.c
drivers/irqchip/irq-ts4800.c
drivers/irqchip/irq-vic.c
drivers/mailbox/bcm-flexrm-mailbox.c
drivers/md/bcache/bcache.h
drivers/md/bcache/super.c
drivers/md/dm-crypt.c
drivers/md/dm-integrity.c
drivers/md/dm-raid.c
drivers/md/dm-verity-target.c
drivers/md/dm-verity.h
drivers/md/dm-zoned-metadata.c
drivers/md/dm.c
drivers/md/md-bitmap.c
drivers/md/md-linear.h [deleted file]
drivers/md/md-multipath.h [deleted file]
drivers/md/md.c
drivers/md/md.h
drivers/md/raid0.c
drivers/md/raid1-10.c
drivers/md/raid1.c
drivers/md/raid1.h
drivers/md/raid10.c
drivers/md/raid5-ppl.c
drivers/md/raid5.c
drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c
drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
drivers/media/rc/Kconfig
drivers/media/rc/bpf-lirc.c
drivers/media/rc/ir_toy.c
drivers/media/rc/lirc_dev.c
drivers/media/rc/rc-core-priv.h
drivers/memory/emif.c
drivers/memory/stm32-fmc2-ebi.c
drivers/memory/tegra/tegra234.c
drivers/memstick/core/ms_block.c
drivers/memstick/core/mspro_block.c
drivers/misc/fastrpc.c
drivers/misc/lis3lv02d/lis3lv02d_i2c.c
drivers/misc/mei/gsc_proxy/mei_gsc_proxy.c
drivers/misc/mei/hw-me-regs.h
drivers/misc/mei/pci-me.c
drivers/misc/mei/vsc-tp.c
drivers/mmc/core/mmc.c
drivers/mmc/core/queue.c
drivers/mmc/host/mmci_stm32_sdmmc.c
drivers/mmc/host/sdhci-xenon-phy.c
drivers/mtd/devices/block2mtd.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdcore.c
drivers/mtd/nand/raw/marvell_nand.c
drivers/mtd/nand/spi/gigadevice.c
drivers/mtd/ubi/block.c
drivers/net/arcnet/arc-rawmode.c
drivers/net/arcnet/arc-rimi.c
drivers/net/arcnet/capmode.c
drivers/net/arcnet/com20020-pci.c
drivers/net/arcnet/com20020.c
drivers/net/arcnet/com20020_cs.c
drivers/net/arcnet/com90io.c
drivers/net/arcnet/com90xx.c
drivers/net/arcnet/rfc1051.c
drivers/net/arcnet/rfc1201.c
drivers/net/bonding/bond_main.c
drivers/net/can/dev/netlink.c
drivers/net/dsa/dsa_loop_bdinfo.c
drivers/net/dsa/microchip/ksz8795.c
drivers/net/ethernet/adi/Kconfig
drivers/net/ethernet/amd/pds_core/auxbus.c
drivers/net/ethernet/amd/pds_core/main.c
drivers/net/ethernet/broadcom/asp2/bcmasp.c
drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c
drivers/net/ethernet/brocade/bna/bnad.c
drivers/net/ethernet/cisco/enic/vnic_vic.c
drivers/net/ethernet/freescale/fman/fman_memac.c
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/i40e/i40e_dcb.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_prototype.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/ice/ice_base.c
drivers/net/ethernet/intel/ice/ice_dpll.c
drivers/net/ethernet/intel/ice/ice_lag.c
drivers/net/ethernet/intel/ice/ice_lag.h
drivers/net/ethernet/intel/ice/ice_lib.c
drivers/net/ethernet/intel/ice/ice_lib.h
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ice/ice_sriov.c
drivers/net/ethernet/intel/ice/ice_virtchnl.c
drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c
drivers/net/ethernet/intel/ice/ice_xsk.c
drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
drivers/net/ethernet/intel/igb/igb.h
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igb/igb_ptp.c
drivers/net/ethernet/intel/igc/igc_main.c
drivers/net/ethernet/intel/igc/igc_phy.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
drivers/net/ethernet/mellanox/mlx5/core/devlink.c
drivers/net/ethernet/mellanox/mlx5/core/dpll.c
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
drivers/net/ethernet/mellanox/mlx5/core/health.c
drivers/net/ethernet/microchip/lan966x/lan966x_lag.c
drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c
drivers/net/ethernet/microchip/sparx5/sparx5_main.c
drivers/net/ethernet/microchip/sparx5/sparx5_main.h
drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
drivers/net/ethernet/pensando/ionic/ionic_dev.c
drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
drivers/net/ethernet/pensando/ionic/ionic_fw.c
drivers/net/ethernet/pensando/ionic/ionic_lif.c
drivers/net/ethernet/pensando/ionic/ionic_main.c
drivers/net/ethernet/pensando/ionic/ionic_txrx.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
drivers/net/ethernet/stmicro/stmmac/hwif.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/ti/Kconfig
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/ethernet/ti/cpts.c
drivers/net/ethernet/toshiba/ps3_gelic_net.c
drivers/net/fddi/skfp/skfddi.c
drivers/net/geneve.c
drivers/net/gtp.c
drivers/net/ieee802154/fakelb.c
drivers/net/ipa/ipa_interrupt.c
drivers/net/ipvlan/ipvtap.c
drivers/net/phy/mdio_devres.c
drivers/net/phy/realtek.c
drivers/net/plip/plip.c
drivers/net/ppp/bsd_comp.c
drivers/net/ppp/ppp_async.c
drivers/net/ppp/ppp_deflate.c
drivers/net/ppp/ppp_generic.c
drivers/net/ppp/ppp_synctty.c
drivers/net/ppp/pppoe.c
drivers/net/tun.c
drivers/net/usb/dm9601.c
drivers/net/usb/lan78xx.c
drivers/net/usb/smsc95xx.c
drivers/net/veth.c
drivers/net/wireless/intel/iwlwifi/fw/acpi.c
drivers/net/wireless/intel/iwlwifi/fw/api/txq.h
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.h
drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/xen-netback/netback.c
drivers/nvdimm/btt.c
drivers/nvdimm/pmem.c
drivers/nvme/host/apple.c
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.c
drivers/nvme/host/multipath.c
drivers/nvme/host/nvme.h
drivers/nvme/host/rdma.c
drivers/nvme/host/sysfs.c
drivers/nvme/host/zns.c
drivers/nvme/target/admin-cmd.c
drivers/nvme/target/configfs.c
drivers/nvme/target/core.c
drivers/nvme/target/discovery.c
drivers/nvme/target/fabrics-cmd.c
drivers/nvme/target/fcloop.c
drivers/nvme/target/io-cmd-bdev.c
drivers/nvme/target/nvmet.h
drivers/nvme/target/passthru.c
drivers/nvme/target/rdma.c
drivers/nvme/target/zns.c
drivers/nvmem/core.c
drivers/of/property.c
drivers/of/unittest.c
drivers/pci/hotplug/s390_pci_hpc.c
drivers/pci/msi/irqdomain.c
drivers/pci/pci.c
drivers/perf/arm-cmn.c
drivers/perf/arm_smmuv3_pmu.c
drivers/perf/cxl_pmu.c
drivers/perf/riscv_pmu.c
drivers/perf/riscv_pmu_legacy.c
drivers/perf/riscv_pmu_sbi.c
drivers/phy/freescale/phy-fsl-imx8-mipi-dphy.c
drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
drivers/phy/qualcomm/phy-qcom-m31.c
drivers/phy/qualcomm/phy-qcom-qmp-combo.c
drivers/phy/qualcomm/phy-qcom-qmp-usb.c
drivers/pinctrl/core.c
drivers/pinctrl/stm32/pinctrl-stm32mp257.c
drivers/platform/x86/amd/pmf/core.c
drivers/platform/x86/amd/pmf/pmf.h
drivers/platform/x86/amd/pmf/tee-if.c
drivers/platform/x86/intel/int0002_vgpio.c
drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c
drivers/platform/x86/intel/vbtn.c
drivers/platform/x86/p2sb.c
drivers/platform/x86/serdev_helpers.h [new file with mode: 0644]
drivers/platform/x86/think-lmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/touchscreen_dmi.c
drivers/platform/x86/x86-android-tablets/core.c
drivers/platform/x86/x86-android-tablets/lenovo.c
drivers/platform/x86/x86-android-tablets/other.c
drivers/platform/x86/x86-android-tablets/x86-android-tablets.h
drivers/pmdomain/arm/scmi_perf_domain.c
drivers/pmdomain/qcom/rpmhpd.c
drivers/power/supply/Kconfig
drivers/power/supply/bq27xxx_battery_i2c.c
drivers/powercap/intel_rapl_common.c
drivers/ptp/ptp_kvm_common.c
drivers/ptp/ptp_kvm_x86.c
drivers/ras/Kconfig
drivers/ras/Makefile
drivers/ras/amd/atl/Kconfig [new file with mode: 0644]
drivers/ras/amd/atl/Makefile [new file with mode: 0644]
drivers/ras/amd/atl/access.c [new file with mode: 0644]
drivers/ras/amd/atl/core.c [new file with mode: 0644]
drivers/ras/amd/atl/dehash.c [new file with mode: 0644]
drivers/ras/amd/atl/denormalize.c [new file with mode: 0644]
drivers/ras/amd/atl/internal.h [new file with mode: 0644]
drivers/ras/amd/atl/map.c [new file with mode: 0644]
drivers/ras/amd/atl/reg_fields.h [new file with mode: 0644]
drivers/ras/amd/atl/system.c [new file with mode: 0644]
drivers/ras/amd/atl/umc.c [new file with mode: 0644]
drivers/ras/amd/fmpm.c [new file with mode: 0644]
drivers/ras/cec.c
drivers/ras/debugfs.c
drivers/ras/debugfs.h
drivers/ras/ras.c
drivers/regulator/max5970-regulator.c
drivers/regulator/rk808-regulator.c
drivers/rtc/lib_test.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_alias.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eer.c
drivers/s390/block/dasd_erp.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_genhd.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/block/dasd_proc.c
drivers/s390/block/dcssblk.c
drivers/s390/block/scm_blk.c
drivers/s390/char/vmur.c
drivers/s390/char/zcore.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc_sch.c
drivers/s390/cio/cmf.c
drivers/s390/cio/css.c
drivers/s390/cio/device.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/scm.c
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/ap_debug.h
drivers/s390/crypto/ap_queue.c
drivers/s390/crypto/pkey_api.c
drivers/s390/crypto/vfio_ap_drv.c
drivers/s390/crypto/vfio_ap_ops.c
drivers/s390/crypto/zcrypt_api.c
drivers/s390/crypto/zcrypt_api.h
drivers/s390/crypto/zcrypt_ccamisc.c
drivers/s390/crypto/zcrypt_debug.h
drivers/s390/crypto/zcrypt_ep11misc.c
drivers/s390/crypto/zcrypt_error.h
drivers/s390/crypto/zcrypt_msgtype50.c
drivers/s390/crypto/zcrypt_msgtype6.c
drivers/scsi/Kconfig
drivers/scsi/fcoe/fcoe_ctlr.c
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_fcs.c
drivers/scsi/fnic/fnic_main.c
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/mpi3mr/mpi3mr_transport.c
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/scsi.c
drivers/scsi/scsi_scan.c
drivers/scsi/sd.c
drivers/scsi/smartpqi/smartpqi_init.c
drivers/soc/mediatek/Kconfig
drivers/soc/mediatek/Makefile
drivers/soc/mediatek/mtk-socinfo.c [new file with mode: 0644]
drivers/soc/microchip/Kconfig
drivers/soc/qcom/Kconfig
drivers/soc/qcom/Makefile
drivers/soc/qcom/apr.c
drivers/soc/qcom/llcc-qcom.c
drivers/soc/qcom/pmic_glink.c
drivers/soc/qcom/pmic_glink_altmode.c
drivers/soc/qcom/qcom-geni-se.c
drivers/soc/qcom/qcom-pbs.c [new file with mode: 0644]
drivers/soc/qcom/qcom_aoss.c
drivers/soc/qcom/smem.c
drivers/soc/qcom/smp2p.c
drivers/soc/qcom/socinfo.c
drivers/soc/qcom/spm.c
drivers/soc/qcom/trace-aoss.h [new file with mode: 0644]
drivers/soc/renesas/Kconfig
drivers/soc/renesas/rcar-rst.c
drivers/soc/renesas/renesas-soc.c
drivers/soc/samsung/Kconfig
drivers/soc/samsung/exynos-pmu.c
drivers/soc/samsung/exynos-pmu.h
drivers/soc/tegra/Kconfig
drivers/soc/tegra/fuse/fuse-tegra.c
drivers/soc/tegra/fuse/fuse-tegra30.c
drivers/soc/tegra/fuse/fuse.h
drivers/soc/tegra/fuse/tegra-apbmisc.c
drivers/soc/tegra/pmc.c
drivers/spi/spi-cadence-quadspi.c
drivers/spi/spi-cs42l43.c
drivers/spi/spi-imx.c
drivers/spi/spi-intel-pci.c
drivers/spi/spi-mxs.c
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-ppc4xx.c
drivers/staging/fieldbus/Documentation/devicetree/bindings/fieldbus/arcx,anybus-controller.txt
drivers/staging/iio/impedance-analyzer/ad5933.c
drivers/staging/media/atomisp/pci/atomisp_cmd.c
drivers/staging/media/atomisp/pci/atomisp_internal.h
drivers/staging/media/atomisp/pci/atomisp_ioctl.c
drivers/staging/media/atomisp/pci/atomisp_v4l2.c
drivers/target/target_core_configfs.c
drivers/target/target_core_iblock.c
drivers/target/target_core_iblock.h
drivers/target/target_core_pscsi.c
drivers/target/target_core_pscsi.h
drivers/tee/optee/device.c
drivers/tee/tee_core.c
drivers/thermal/intel/intel_hfi.c
drivers/thermal/intel/intel_powerclamp.c
drivers/thermal/intel/x86_pkg_temp_thermal.c
drivers/thunderbolt/switch.c
drivers/thunderbolt/tb_regs.h
drivers/thunderbolt/usb4.c
drivers/tty/hvc/Kconfig
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_pci1xxxx.c
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/imx.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/qcom_geni_serial.c
drivers/tty/serial/serial_port.c
drivers/tty/serial/stm32-usart.c
drivers/tty/vt/vt.c
drivers/ufs/core/ufshcd.c
drivers/ufs/host/ufs-qcom.c
drivers/usb/cdns3/cdns3-gadget.c
drivers/usb/cdns3/core.c
drivers/usb/cdns3/drd.c
drivers/usb/cdns3/drd.h
drivers/usb/cdns3/host.c
drivers/usb/core/hcd.c
drivers/usb/core/port.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/gadget.h
drivers/usb/gadget/function/f_ncm.c
drivers/usb/gadget/udc/omap_udc.c
drivers/usb/host/uhci-grlib.c
drivers/usb/host/xhci-ring.c
drivers/usb/roles/class.c
drivers/usb/storage/isd200.c
drivers/usb/storage/scsiglue.c
drivers/usb/storage/uas.c
drivers/usb/typec/altmodes/displayport.c
drivers/usb/typec/tcpm/tcpm.c
drivers/usb/typec/ucsi/ucsi_glink.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/hyperv_fb.c
drivers/watchdog/Kconfig
drivers/watchdog/s3c2410_wdt.c
drivers/xen/events/events_base.c
drivers/xen/gntalloc.c
drivers/xen/pcpu.c
drivers/xen/privcmd.c
drivers/xen/xen-balloon.c
drivers/xen/xenbus/xenbus_client.c
drivers/zorro/zorro-driver.c
drivers/zorro/zorro.h
fs/9p/vfs_file.c
fs/Kconfig
fs/Makefile
fs/affs/affs.h
fs/affs/super.c
fs/afs/dir.c
fs/afs/file.c
fs/afs/flock.c
fs/afs/internal.h
fs/afs/main.c
fs/afs/server.c
fs/afs/volume.c
fs/aio.c
fs/attr.c
fs/backing-file.c
fs/bcachefs/backpointers.c
fs/bcachefs/bcachefs.h
fs/bcachefs/btree_iter.c
fs/bcachefs/btree_update_interior.c
fs/bcachefs/fs-io-buffered.c
fs/bcachefs/fs-io-direct.c
fs/bcachefs/fs.c
fs/bcachefs/io_write.c
fs/bcachefs/journal_io.c
fs/bcachefs/journal_reclaim.c
fs/bcachefs/printbuf.c
fs/bcachefs/recovery.c
fs/bcachefs/sb-members.c
fs/bcachefs/snapshot.c
fs/bcachefs/super-io.c
fs/bcachefs/super.c
fs/bcachefs/super_types.h
fs/bcachefs/util.c
fs/btrfs/block-group.c
fs/btrfs/block-group.h
fs/btrfs/block-rsv.c
fs/btrfs/block-rsv.h
fs/btrfs/defrag.c
fs/btrfs/delalloc-space.c
fs/btrfs/dev-replace.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/send.c
fs/btrfs/space-info.c
fs/btrfs/transaction.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/btrfs/zoned.c
fs/buffer.c
fs/cachefiles/cache.c
fs/cachefiles/daemon.c
fs/ceph/caps.c
fs/ceph/locks.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/mdsmap.c
fs/ceph/mdsmap.h
fs/coda/inode.c
fs/coredump.c
fs/cramfs/inode.c
fs/crypto/fname.c
fs/crypto/hooks.c
fs/dcache.c
fs/direct-io.c
fs/dlm/plock.c
fs/ecryptfs/crypto.c
fs/efivarfs/internal.h
fs/efivarfs/super.c
fs/efivarfs/vars.c
fs/efs/super.c
fs/erofs/data.c
fs/erofs/decompressor.c
fs/erofs/fscache.c
fs/erofs/internal.h
fs/erofs/namei.c
fs/erofs/super.c
fs/eventfd.c
fs/eventpoll.c
fs/exec.c
fs/exfat/exfat_fs.h
fs/exfat/file.c
fs/exfat/nls.c
fs/exfat/super.c
fs/exportfs/expfs.c
fs/ext4/ext4.h
fs/ext4/fsmap.c
fs/ext4/namei.c
fs/ext4/super.c
fs/ext4/symlink.c
fs/f2fs/f2fs.h
fs/f2fs/namei.c
fs/f2fs/segment.c
fs/f2fs/super.c
fs/fat/inode.c
fs/fcntl.c
fs/fhandle.c
fs/file_table.c
fs/fs-writeback.c
fs/fs_parser.c
fs/fuse/cuse.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/bmap.c
fs/gfs2/file.c
fs/gfs2/ops_fstype.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/super.c
fs/hfsplus/wrapper.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/internal.h
fs/ioctl.c
fs/iomap/buffered-io.c
fs/iomap/direct-io.c
fs/iomap/trace.h
fs/jfs/jfs_logmgr.c
fs/jfs/jfs_logmgr.h
fs/jfs/jfs_mount.c
fs/jfs/super.c
fs/kernfs/mount.c
fs/libfs.c
fs/lockd/clnt4xdr.c
fs/lockd/clntlock.c
fs/lockd/clntproc.c
fs/lockd/clntxdr.c
fs/lockd/svc4proc.c
fs/lockd/svclock.c
fs/lockd/svcproc.c
fs/lockd/svcsubs.c
fs/lockd/xdr.c
fs/lockd/xdr4.c
fs/locks.c
fs/mbcache.c
fs/minix/inode.c
fs/mnt_idmapping.c
fs/mpage.c
fs/namei.c
fs/namespace.c
fs/netfs/buffered_write.c
fs/netfs/direct_write.c
fs/netfs/io.c
fs/nfs/blocklayout/blocklayout.h
fs/nfs/blocklayout/dev.c
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4file.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4trace.h
fs/nfs/nfs4xdr.c
fs/nfs/write.c
fs/nfsd/filecache.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4state.c
fs/nsfs.c
fs/ntfs/Kconfig [deleted file]
fs/ntfs/Makefile [deleted file]
fs/ntfs/aops.c [deleted file]
fs/ntfs/aops.h [deleted file]
fs/ntfs/attrib.c [deleted file]
fs/ntfs/attrib.h [deleted file]
fs/ntfs/bitmap.c [deleted file]
fs/ntfs/bitmap.h [deleted file]
fs/ntfs/collate.c [deleted file]
fs/ntfs/collate.h [deleted file]
fs/ntfs/compress.c [deleted file]
fs/ntfs/debug.c [deleted file]
fs/ntfs/debug.h [deleted file]
fs/ntfs/dir.c [deleted file]
fs/ntfs/dir.h [deleted file]
fs/ntfs/endian.h [deleted file]
fs/ntfs/file.c [deleted file]
fs/ntfs/index.c [deleted file]
fs/ntfs/index.h [deleted file]
fs/ntfs/inode.c [deleted file]
fs/ntfs/inode.h [deleted file]
fs/ntfs/layout.h [deleted file]
fs/ntfs/lcnalloc.c [deleted file]
fs/ntfs/lcnalloc.h [deleted file]
fs/ntfs/logfile.c [deleted file]
fs/ntfs/logfile.h [deleted file]
fs/ntfs/malloc.h [deleted file]
fs/ntfs/mft.c [deleted file]
fs/ntfs/mft.h [deleted file]
fs/ntfs/mst.c [deleted file]
fs/ntfs/namei.c [deleted file]
fs/ntfs/ntfs.h [deleted file]
fs/ntfs/quota.c [deleted file]
fs/ntfs/quota.h [deleted file]
fs/ntfs/runlist.c [deleted file]
fs/ntfs/runlist.h [deleted file]
fs/ntfs/super.c [deleted file]
fs/ntfs/sysctl.c [deleted file]
fs/ntfs/sysctl.h [deleted file]
fs/ntfs/time.h [deleted file]
fs/ntfs/types.h [deleted file]
fs/ntfs/unistr.c [deleted file]
fs/ntfs/upcase.c [deleted file]
fs/ntfs/usnjrnl.c [deleted file]
fs/ntfs/usnjrnl.h [deleted file]
fs/ntfs/volume.h [deleted file]
fs/ntfs3/frecord.c
fs/ntfs3/namei.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/locks.c
fs/ocfs2/stack_user.c
fs/ocfs2/super.c
fs/open.c
fs/openpromfs/inode.c
fs/overlayfs/copy_up.c
fs/overlayfs/params.c
fs/overlayfs/super.c
fs/overlayfs/util.c
fs/pidfs.c [new file with mode: 0644]
fs/pipe.c
fs/posix_acl.c
fs/proc/base.c
fs/proc/inode.c
fs/proc/root.c
fs/qnx4/inode.c
fs/qnx6/inode.c
fs/reiserfs/journal.c
fs/reiserfs/procfs.c
fs/reiserfs/reiserfs.h
fs/reiserfs/super.c
fs/remap_range.c
fs/romfs/super.c
fs/select.c
fs/smb/client/cached_dir.c
fs/smb/client/cifsfs.c
fs/smb/client/cifsglob.h
fs/smb/client/cifssmb.c
fs/smb/client/connect.c
fs/smb/client/file.c
fs/smb/client/fs_context.c
fs/smb/client/namespace.c
fs/smb/client/smb2file.c
fs/smb/client/smb2ops.c
fs/smb/client/smb2pdu.c
fs/smb/server/smb2pdu.c
fs/smb/server/vfs.c
fs/super.c
fs/sysv/inode.c
fs/sysv/itree.c
fs/ubifs/dir.c
fs/ubifs/super.c
fs/xfs/xfs_aops.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_mount.c
fs/xfs/xfs_super.c
fs/zonefs/file.c
fs/zonefs/super.c
include/asm-generic/barrier.h
include/drm/bridge/aux-bridge.h
include/dt-bindings/arm/qcom,ids.h
include/dt-bindings/clock/exynos850.h
include/dt-bindings/clock/google,gs101.h
include/dt-bindings/clock/qcom,gcc-msm8953.h
include/dt-bindings/clock/qcom,gcc-sc8180x.h
include/dt-bindings/clock/qcom,x1e80100-camcc.h [new file with mode: 0644]
include/dt-bindings/clock/qcom,x1e80100-dispcc.h [new file with mode: 0644]
include/dt-bindings/clock/qcom,x1e80100-gpucc.h [new file with mode: 0644]
include/dt-bindings/clock/qcom,x1e80100-tcsr.h [new file with mode: 0644]
include/dt-bindings/clock/renesas,r8a779h0-cpg-mssr.h [new file with mode: 0644]
include/dt-bindings/clock/rockchip,rk3588-cru.h
include/dt-bindings/mfd/stm32f7-rcc.h
include/dt-bindings/power/renesas,r8a779h0-sysc.h [new file with mode: 0644]
include/dt-bindings/reset/qcom,x1e80100-gpucc.h [new file with mode: 0644]
include/kunit/test.h
include/linux/amd-iommu.h
include/linux/arm_ffa.h
include/linux/async.h
include/linux/atomic/atomic-arch-fallback.h
include/linux/atomic/atomic-instrumented.h
include/linux/atomic/atomic-long.h
include/linux/backing-dev.h
include/linux/bitmap.h
include/linux/blk-integrity.h
include/linux/blk-mq.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/bvec.h
include/linux/clocksource.h
include/linux/clocksource_ids.h
include/linux/compiler-gcc.h
include/linux/compiler.h
include/linux/compiler_attributes.h
include/linux/compiler_types.h
include/linux/cpu.h
include/linux/cpuhotplug.h
include/linux/cpuset.h
include/linux/cxl-event.h
include/linux/dcache.h
include/linux/device-mapper.h
include/linux/dpll.h
include/linux/file.h
include/linux/filelock.h
include/linux/fs.h
include/linux/fscrypt.h
include/linux/gfp.h
include/linux/gpio/driver.h
include/linux/hrtimer.h
include/linux/hrtimer_defs.h
include/linux/hyperv.h
include/linux/iio/adc/ad_sigma_delta.h
include/linux/iio/common/st_sensors.h
include/linux/iio/imu/adis.h
include/linux/indirect_call_wrapper.h
include/linux/io_uring_types.h
include/linux/iomap.h
include/linux/iommu.h
include/linux/irq.h
include/linux/irqdomain.h
include/linux/irqdomain_defs.h
include/linux/irqhandler.h
include/linux/jiffies.h
include/linux/kvm_host.h
include/linux/lockd/lockd.h
include/linux/lockd/xdr.h
include/linux/maple_tree.h
include/linux/memblock.h
include/linux/mlx5/mlx5_ifc.h
include/linux/mlx5/qp.h
include/linux/module.h
include/linux/msi.h
include/linux/mutex.h
include/linux/netdevice.h
include/linux/netfilter.h
include/linux/nfs_fs_sb.h
include/linux/ns_common.h
include/linux/nvme-rdma.h
include/linux/nvme.h
include/linux/objtool.h
include/linux/pid.h
include/linux/pidfs.h [new file with mode: 0644]
include/linux/pktcdvd.h
include/linux/poison.h
include/linux/poll.h
include/linux/proc_fs.h
include/linux/proc_ns.h
include/linux/psp-sev.h
include/linux/pti.h
include/linux/ptp_kvm.h
include/linux/ptrace.h
include/linux/ras.h
include/linux/rcu_sync.h
include/linux/rcupdate.h
include/linux/resctrl.h
include/linux/rw_hint.h [new file with mode: 0644]
include/linux/sched.h
include/linux/sched/sd_flags.h
include/linux/sched/signal.h
include/linux/sched/topology.h
include/linux/scmi_protocol.h
include/linux/seq_buf.h
include/linux/serial_core.h
include/linux/smp.h
include/linux/soc/andes/irq.h [new file with mode: 0644]
include/linux/soc/qcom/apr.h
include/linux/soc/qcom/qcom-pbs.h [new file with mode: 0644]
include/linux/soc/samsung/exynos-pmu.h
include/linux/string.h
include/linux/swap.h
include/linux/tcp.h
include/linux/tee_drv.h
include/linux/tick.h
include/linux/timekeeping.h
include/linux/timer.h
include/linux/trace_seq.h
include/linux/uio.h
include/linux/usb/gadget.h
include/linux/usb/hcd.h
include/linux/workqueue.h
include/net/busy_poll.h
include/net/mctp.h
include/net/netfilter/nf_flow_table.h
include/net/netfilter/nf_tables_core.h
include/net/sch_generic.h
include/net/switchdev.h
include/net/tc_wrapper.h
include/net/tcp.h
include/net/tls.h
include/scsi/scsi_device.h
include/soc/qcom/qcom-spmi-pmic.h
include/soc/qcom/spm.h
include/soc/tegra/fuse.h
include/soc/tegra/pmc.h
include/sound/soc-card.h
include/sound/tas2781.h
include/trace/events/afs.h
include/trace/events/filelock.h
include/trace/events/io_uring.h
include/trace/events/qdisc.h
include/trace/events/timer_migration.h [new file with mode: 0644]
include/uapi/drm/nouveau_drm.h
include/uapi/drm/xe_drm.h
include/uapi/linux/fs.h
include/uapi/linux/iio/types.h
include/uapi/linux/in6.h
include/uapi/linux/io_uring.h
include/uapi/linux/magic.h
include/uapi/linux/pidfd.h
include/uapi/linux/psp-sev.h
include/uapi/linux/ublk_cmd.h
include/uapi/sound/asound.h
include/uapi/xen/gntalloc.h
include/vdso/datapage.h
include/vdso/helpers.h
init/Kconfig
init/do_mounts.c
init/do_mounts.h
init/init_task.c
init/initramfs.c
init/main.c
io_uring/Makefile
io_uring/cancel.c
io_uring/cancel.h
io_uring/fdinfo.c
io_uring/filetable.h
io_uring/io_uring.c
io_uring/io_uring.h
io_uring/kbuf.c
io_uring/kbuf.h
io_uring/napi.c [new file with mode: 0644]
io_uring/napi.h [new file with mode: 0644]
io_uring/net.c
io_uring/opdef.c
io_uring/poll.c
io_uring/register.c
io_uring/rsrc.h
io_uring/rw.c
io_uring/sqpoll.c
io_uring/sqpoll.h
io_uring/truncate.c [new file with mode: 0644]
io_uring/truncate.h [new file with mode: 0644]
io_uring/uring_cmd.c
io_uring/xattr.c
kernel/async.c
kernel/backtracetest.c
kernel/bpf/cpumap.c
kernel/bpf/helpers.c
kernel/bpf/task_iter.c
kernel/bpf/verifier.c
kernel/cgroup/cpuset.c
kernel/context_tracking.c
kernel/cpu.c
kernel/exit.c
kernel/fork.c
kernel/irq/irq_sim.c
kernel/irq/irqdesc.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/irq/matrix.c
kernel/irq/msi.c
kernel/locking/percpu-rwsem.c
kernel/locking/qspinlock_paravirt.h
kernel/locking/rtmutex.c
kernel/locking/rwsem.c
kernel/nsproxy.c
kernel/pid.c
kernel/power/swap.c
kernel/rcu/Kconfig
kernel/rcu/rcu.h
kernel/rcu/rcuscale.c
kernel/rcu/rcutorture.c
kernel/rcu/srcutree.c
kernel/rcu/sync.c
kernel/rcu/tasks.h
kernel/rcu/tiny.c
kernel/rcu/tree.c
kernel/rcu/tree.h
kernel/rcu/tree_exp.h
kernel/rcu/tree_nocb.h
kernel/rcu/tree_plugin.h
kernel/sched/core.c
kernel/sched/fair.c
kernel/sched/idle.c
kernel/sched/membarrier.c
kernel/sched/sched.h
kernel/sched/topology.c
kernel/signal.c
kernel/softirq.c
kernel/time/Kconfig
kernel/time/Makefile
kernel/time/clockevents.c
kernel/time/clocksource-wdtest.c
kernel/time/clocksource.c
kernel/time/hrtimer.c
kernel/time/tick-common.c
kernel/time/tick-internal.h
kernel/time/tick-sched.c
kernel/time/tick-sched.h
kernel/time/time_test.c
kernel/time/timekeeping.c
kernel/time/timer.c
kernel/time/timer_list.c
kernel/time/timer_migration.c [new file with mode: 0644]
kernel/time/timer_migration.h [new file with mode: 0644]
kernel/trace/fprobe.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace_btf.c
kernel/trace/trace_events_synth.c
kernel/trace/trace_output.c
kernel/workqueue.c
lib/Kconfig.debug
lib/Makefile
lib/checksum_kunit.c
lib/cmdline_kunit.c
lib/iov_iter.c
lib/kobject.c
lib/kunit/device-impl.h
lib/kunit/device.c
lib/kunit/executor.c
lib/kunit/executor_test.c
lib/kunit/test.c
lib/livepatch/Makefile [deleted file]
lib/maple_tree.c
lib/memcpy_kunit.c
lib/nlattr.c
lib/raid6/s390vx.uc
lib/seq_buf.c
lib/stackdepot.c
lib/test_maple_tree.c
mm/backing-dev.c
mm/compaction.c
mm/damon/core.c
mm/damon/lru_sort.c
mm/damon/reclaim.c
mm/damon/sysfs-schemes.c
mm/debug_vm_pgtable.c
mm/filemap.c
mm/kasan/common.c
mm/kasan/generic.c
mm/kasan/kasan.h
mm/kasan/quarantine.c
mm/memblock.c
mm/memcontrol.c
mm/memory.c
mm/migrate.c
mm/mmap.c
mm/page_alloc.c
mm/shmem.c
mm/swap.h
mm/swap_state.c
mm/swapfile.c
mm/userfaultfd.c
mm/util.c
mm/vmscan.c
mm/zswap.c
net/6lowpan/core.c
net/atm/mpc.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sync.c
net/bluetooth/l2cap_core.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/core.c
net/bridge/br_netfilter_hooks.c
net/bridge/br_switchdev.c
net/bridge/netfilter/nf_conntrack_bridge.c
net/can/j1939/j1939-priv.h
net/can/j1939/main.c
net/can/j1939/socket.c
net/ceph/messenger_v2.c
net/core/dev.c
net/core/gso_test.c
net/core/page_pool_user.c
net/core/rtnetlink.c
net/core/skmsg.c
net/core/sock.c
net/devlink/core.c
net/devlink/port.c
net/handshake/handshake-test.c
net/hsr/hsr_forward.c
net/ipv4/ah4.c
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/esp4.c
net/ipv4/inet_hashtables.c
net/ipv4/ip_gre.c
net/ipv4/ip_output.c
net/ipv4/ip_tunnel.c
net/ipv4/ip_vti.c
net/ipv4/ipip.c
net/ipv4/tcp.c
net/ipv4/tunnel4.c
net/ipv4/udp.c
net/ipv4/udp_tunnel_core.c
net/ipv4/xfrm4_tunnel.c
net/ipv6/addrconf.c
net/ipv6/ah6.c
net/ipv6/esp6.c
net/ipv6/exthdrs.c
net/ipv6/ip6_output.c
net/ipv6/ip6_udp_tunnel.c
net/ipv6/mip6.c
net/ipv6/route.c
net/ipv6/seg6.c
net/ipv6/sit.c
net/ipv6/tunnel6.c
net/ipv6/xfrm6_tunnel.c
net/iucv/iucv.c
net/key/af_key.c
net/l2tp/l2tp_ip6.c
net/mac80211/rate.c
net/mac80211/tx.c
net/mctp/route.c
net/mptcp/diag.c
net/mptcp/fastopen.c
net/mptcp/options.c
net/mptcp/pm_netlink.c
net/mptcp/pm_userspace.c
net/mptcp/protocol.c
net/mptcp/protocol.h
net/mptcp/subflow.c
net/netfilter/Makefile
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_h323_asn1.c
net/netfilter/nf_flow_table_core.c
net/netfilter/nf_nat_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_core.c
net/netfilter/nft_compat.c
net/netfilter/nft_ct.c
net/netfilter/nft_flow_offload.c
net/netfilter/nft_lookup.c
net/netfilter/nft_set_pipapo.h
net/netlink/af_netlink.c
net/netrom/af_netrom.c
net/netrom/nr_dev.c
net/netrom/nr_in.c
net/netrom/nr_out.c
net/netrom/nr_route.c
net/netrom/nr_subr.c
net/openvswitch/flow_netlink.c
net/phonet/datagram.c
net/phonet/pep.c
net/rds/rdma.c
net/rds/recv.c
net/rds/send.c
net/sched/act_mirred.c
net/sched/cls_flower.c
net/sched/em_canid.c
net/sched/em_cmp.c
net/sched/em_meta.c
net/sched/em_nbyte.c
net/sched/em_text.c
net/sched/em_u32.c
net/sched/sch_api.c
net/sctp/inqueue.c
net/smc/af_smc.c
net/switchdev/switchdev.c
net/tls/tls_main.c
net/tls/tls_sw.c
net/unix/af_unix.c
net/unix/garbage.c
net/wireless/nl80211.c
net/xdp/xsk.c
net/xfrm/xfrm_algo.c
net/xfrm/xfrm_device.c
net/xfrm/xfrm_output.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c
rust/Makefile
rust/alloc/alloc.rs
rust/alloc/boxed.rs
rust/alloc/collections/mod.rs
rust/alloc/lib.rs
rust/alloc/raw_vec.rs
rust/alloc/vec/into_iter.rs
rust/alloc/vec/mod.rs
rust/bindings/bindings_helper.h
rust/kernel/allocator.rs
rust/kernel/error.rs
rust/kernel/init.rs
rust/kernel/ioctl.rs
rust/kernel/lib.rs
rust/kernel/str.rs
rust/kernel/sync.rs
rust/kernel/sync/arc.rs
rust/kernel/sync/condvar.rs
rust/kernel/sync/lock.rs
rust/kernel/sync/lock/mutex.rs
rust/kernel/sync/lock/spinlock.rs
rust/kernel/sync/locked_by.rs
rust/kernel/task.rs
rust/kernel/time.rs [new file with mode: 0644]
rust/kernel/types.rs
rust/kernel/workqueue.rs
rust/macros/module.rs
scripts/Kconfig.include
scripts/Makefile.build
scripts/Makefile.compiler
scripts/Makefile.host
scripts/Makefile.lib
scripts/Makefile.vmlinux_o
scripts/atomic/kerneldoc/add_unless
scripts/atomic/kerneldoc/cmpxchg
scripts/atomic/kerneldoc/dec_if_positive
scripts/atomic/kerneldoc/dec_unless_positive
scripts/atomic/kerneldoc/inc_not_zero
scripts/atomic/kerneldoc/inc_unless_negative
scripts/atomic/kerneldoc/try_cmpxchg
scripts/bpf_doc.py
scripts/clang-tools/gen_compile_commands.py
scripts/gdb/linux/constants.py.in
scripts/gdb/linux/mm.py
scripts/gdb/linux/symbols.py
scripts/generate_rust_target.rs
scripts/link-vmlinux.sh
scripts/min-tool-version.sh
scripts/mksysmap
scripts/mod/modpost.c
scripts/mod/sumversion.c
security/apparmor/lsm.c
security/integrity/digsig.c
security/landlock/fs.c
security/security.c
security/selinux/hooks.c
security/tomoyo/common.c
sound/core/Makefile
sound/core/pcm_native.c
sound/core/ump.c
sound/firewire/amdtp-stream.c
sound/pci/hda/Kconfig
sound/pci/hda/cs35l41_hda_property.c
sound/pci/hda/hda_controller.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/tas2781_hda_i2c.c
sound/soc/amd/yc/acp6x-mach.c
sound/soc/amd/yc/pci-acp6x.c
sound/soc/codecs/cs35l45.c
sound/soc/codecs/cs35l56-shared.c
sound/soc/codecs/cs35l56.c
sound/soc/codecs/cs35l56.h
sound/soc/codecs/cs42l43.c
sound/soc/codecs/madera.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/tas2781-comlib.c
sound/soc/codecs/tas2781-i2c.c
sound/soc/codecs/wm8962.c
sound/soc/fsl/fsl_xcvr.c
sound/soc/intel/avs/core.c
sound/soc/intel/avs/topology.c
sound/soc/intel/boards/bytcht_cx2072x.c
sound/soc/intel/boards/bytcht_da7213.c
sound/soc/intel/boards/bytcht_es8316.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5651.c
sound/soc/intel/boards/bytcr_wm5102.c
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/boards/cht_bsw_rt5672.c
sound/soc/qcom/lpass-cdc-dma.c
sound/soc/qcom/qdsp6/q6apm-dai.c
sound/soc/sh/rcar/adg.c
sound/soc/soc-card.c
sound/soc/sof/amd/acp-ipc.c
sound/soc/sof/amd/acp.c
sound/soc/sof/intel/pci-lnl.c
sound/soc/sof/intel/pci-tgl.c
sound/soc/sof/ipc3-topology.c
sound/soc/sof/ipc3.c
sound/soc/sof/ipc4-pcm.c
sound/usb/midi.c
tools/arch/x86/include/asm/cpufeatures.h
tools/arch/x86/include/asm/disabled-features.h
tools/arch/x86/include/asm/msr-index.h
tools/arch/x86/lib/insn.c
tools/arch/x86/lib/x86-opcode-map.txt
tools/net/ynl/lib/ynl.c
tools/objtool/arch/x86/decode.c
tools/objtool/arch/x86/special.c
tools/objtool/check.c
tools/testing/cxl/Kbuild
tools/testing/cxl/test/cxl.c
tools/testing/cxl/test/mock.c
tools/testing/cxl/test/mock.h
tools/testing/kunit/kunit_kernel.py
tools/testing/selftests/Makefile
tools/testing/selftests/bpf/prog_tests/iters.c
tools/testing/selftests/bpf/prog_tests/read_vsyscall.c [new file with mode: 0644]
tools/testing/selftests/bpf/prog_tests/timer.c
tools/testing/selftests/bpf/prog_tests/xdp_bonding.c
tools/testing/selftests/bpf/progs/iters_task.c
tools/testing/selftests/bpf/progs/read_vsyscall.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/timer.c
tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c
tools/testing/selftests/drivers/net/bonding/bond_options.sh
tools/testing/selftests/dt/Makefile
tools/testing/selftests/dt/test_unprobed_devices.sh
tools/testing/selftests/filesystems/overlayfs/dev_in_maps.c
tools/testing/selftests/ftrace/ftracetest
tools/testing/selftests/ftrace/test.d/00basic/test_ownership.tc
tools/testing/selftests/ftrace/test.d/ftrace/func_hotplug.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc
tools/testing/selftests/futex/functional/futex_requeue_pi.c
tools/testing/selftests/iommu/config
tools/testing/selftests/iommu/iommufd.c
tools/testing/selftests/iommu/iommufd_utils.h
tools/testing/selftests/kselftest/ktap_helpers.sh [moved from tools/testing/selftests/dt/ktap_helpers.sh with 66% similarity]
tools/testing/selftests/kvm/aarch64/arch_timer.c
tools/testing/selftests/kvm/aarch64/hypercalls.c
tools/testing/selftests/kvm/aarch64/page_fault_test.c
tools/testing/selftests/kvm/aarch64/smccc_filter.c
tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c
tools/testing/selftests/kvm/demand_paging_test.c
tools/testing/selftests/kvm/dirty_log_perf_test.c
tools/testing/selftests/kvm/dirty_log_test.c
tools/testing/selftests/kvm/get-reg-list.c
tools/testing/selftests/kvm/guest_print_test.c
tools/testing/selftests/kvm/hardware_disable_test.c
tools/testing/selftests/kvm/include/test_util.h
tools/testing/selftests/kvm/include/x86_64/processor.h
tools/testing/selftests/kvm/kvm_create_max_vcpus.c
tools/testing/selftests/kvm/kvm_page_table_test.c
tools/testing/selftests/kvm/lib/aarch64/processor.c
tools/testing/selftests/kvm/lib/aarch64/vgic.c
tools/testing/selftests/kvm/lib/elf.c
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/lib/memstress.c
tools/testing/selftests/kvm/lib/riscv/processor.c
tools/testing/selftests/kvm/lib/s390x/processor.c
tools/testing/selftests/kvm/lib/test_util.c
tools/testing/selftests/kvm/lib/userfaultfd_util.c
tools/testing/selftests/kvm/lib/x86_64/processor.c
tools/testing/selftests/kvm/lib/x86_64/vmx.c
tools/testing/selftests/kvm/memslot_modification_stress_test.c
tools/testing/selftests/kvm/memslot_perf_test.c
tools/testing/selftests/kvm/riscv/get-reg-list.c
tools/testing/selftests/kvm/rseq_test.c
tools/testing/selftests/kvm/s390x/memop.c
tools/testing/selftests/kvm/s390x/resets.c
tools/testing/selftests/kvm/s390x/sync_regs_test.c
tools/testing/selftests/kvm/set_memory_region_test.c
tools/testing/selftests/kvm/system_counter_offset_test.c
tools/testing/selftests/kvm/x86_64/amx_test.c
tools/testing/selftests/kvm/x86_64/cpuid_test.c
tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c
tools/testing/selftests/kvm/x86_64/flds_emulation.h
tools/testing/selftests/kvm/x86_64/hyperv_clock.c
tools/testing/selftests/kvm/x86_64/hyperv_features.c
tools/testing/selftests/kvm/x86_64/hyperv_ipi.c
tools/testing/selftests/kvm/x86_64/hyperv_tlb_flush.c
tools/testing/selftests/kvm/x86_64/kvm_clock_test.c
tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c
tools/testing/selftests/kvm/x86_64/platform_info_test.c
tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c
tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c
tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c
tools/testing/selftests/kvm/x86_64/sync_regs_test.c
tools/testing/selftests/kvm/x86_64/ucna_injection_test.c
tools/testing/selftests/kvm/x86_64/userspace_io_test.c
tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c
tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c
tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c
tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c
tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c
tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c
tools/testing/selftests/kvm/x86_64/xss_msr_test.c
tools/testing/selftests/landlock/common.h
tools/testing/selftests/landlock/fs_test.c
tools/testing/selftests/landlock/net_test.c
tools/testing/selftests/lib.mk
tools/testing/selftests/livepatch/.gitignore [new file with mode: 0644]
tools/testing/selftests/livepatch/Makefile
tools/testing/selftests/livepatch/README
tools/testing/selftests/livepatch/config
tools/testing/selftests/livepatch/functions.sh
tools/testing/selftests/livepatch/test-callbacks.sh
tools/testing/selftests/livepatch/test-ftrace.sh
tools/testing/selftests/livepatch/test-livepatch.sh
tools/testing/selftests/livepatch/test-shadow-vars.sh
tools/testing/selftests/livepatch/test-state.sh
tools/testing/selftests/livepatch/test-syscall.sh [new file with mode: 0755]
tools/testing/selftests/livepatch/test-sysfs.sh
tools/testing/selftests/livepatch/test_klp-call_getpid.c [new file with mode: 0644]
tools/testing/selftests/livepatch/test_modules/Makefile [new file with mode: 0644]
tools/testing/selftests/livepatch/test_modules/test_klp_atomic_replace.c [moved from lib/livepatch/test_klp_atomic_replace.c with 100% similarity]
tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_busy.c [moved from lib/livepatch/test_klp_callbacks_busy.c with 100% similarity]
tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo.c [moved from lib/livepatch/test_klp_callbacks_demo.c with 100% similarity]
tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo2.c [moved from lib/livepatch/test_klp_callbacks_demo2.c with 100% similarity]
tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_mod.c [moved from lib/livepatch/test_klp_callbacks_mod.c with 100% similarity]
tools/testing/selftests/livepatch/test_modules/test_klp_livepatch.c [moved from lib/livepatch/test_klp_livepatch.c with 100% similarity]
tools/testing/selftests/livepatch/test_modules/test_klp_shadow_vars.c [moved from lib/livepatch/test_klp_shadow_vars.c with 100% similarity]
tools/testing/selftests/livepatch/test_modules/test_klp_state.c [moved from lib/livepatch/test_klp_state.c with 100% similarity]
tools/testing/selftests/livepatch/test_modules/test_klp_state2.c [moved from lib/livepatch/test_klp_state2.c with 100% similarity]
tools/testing/selftests/livepatch/test_modules/test_klp_state3.c [moved from lib/livepatch/test_klp_state3.c with 100% similarity]
tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c [new file with mode: 0644]
tools/testing/selftests/mm/uffd-unit-tests.c
tools/testing/selftests/move_mount_set_group/move_mount_set_group_test.c
tools/testing/selftests/mqueue/setting [new file with mode: 0644]
tools/testing/selftests/net/config
tools/testing/selftests/net/forwarding/bridge_locked_port.sh
tools/testing/selftests/net/forwarding/bridge_mdb.sh
tools/testing/selftests/net/forwarding/tc_actions.sh
tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh
tools/testing/selftests/net/gro.sh
tools/testing/selftests/net/ioam6.sh
tools/testing/selftests/net/ioam6_parser.c
tools/testing/selftests/net/ip_local_port_range.c
tools/testing/selftests/net/mptcp/diag.sh
tools/testing/selftests/net/mptcp/mptcp_join.sh
tools/testing/selftests/net/mptcp/mptcp_lib.sh
tools/testing/selftests/net/mptcp/pm_netlink.sh
tools/testing/selftests/net/mptcp/simult_flows.sh
tools/testing/selftests/net/mptcp/userspace_pm.sh
tools/testing/selftests/net/net_helper.sh
tools/testing/selftests/net/openvswitch/openvswitch.sh
tools/testing/selftests/net/openvswitch/ovs-dpctl.py
tools/testing/selftests/net/pmtu.sh
tools/testing/selftests/net/so_txtime.sh
tools/testing/selftests/net/test_bridge_backup_port.sh
tools/testing/selftests/net/tls.c
tools/testing/selftests/net/veth.sh
tools/testing/selftests/netfilter/Makefile
tools/testing/selftests/netfilter/bridge_netfilter.sh [new file with mode: 0644]
tools/testing/selftests/pidfd/pidfd_getfd_test.c
tools/testing/selftests/power_supply/Makefile [new file with mode: 0644]
tools/testing/selftests/power_supply/helpers.sh [new file with mode: 0644]
tools/testing/selftests/power_supply/test_power_supply_properties.sh [new file with mode: 0755]
tools/testing/selftests/powerpc/math/fpu_signal.c
tools/testing/selftests/powerpc/papr_vpd/papr_vpd.c
tools/testing/selftests/rcutorture/bin/torture.sh
tools/testing/selftests/resctrl/cache.c
tools/testing/selftests/resctrl/cat_test.c
tools/testing/selftests/resctrl/cmt_test.c
tools/testing/selftests/resctrl/fill_buf.c
tools/testing/selftests/resctrl/mba_test.c
tools/testing/selftests/resctrl/mbm_test.c
tools/testing/selftests/resctrl/resctrl.h
tools/testing/selftests/resctrl/resctrl_tests.c
tools/testing/selftests/resctrl/resctrl_val.c
tools/testing/selftests/resctrl/resctrlfs.c
tools/testing/selftests/rust/Makefile [new file with mode: 0644]
tools/testing/selftests/rust/config [new file with mode: 0644]
tools/testing/selftests/rust/test_probe_samples.sh [new file with mode: 0755]
tools/testing/selftests/sched/cs_prctl_test.c
tools/testing/selftests/thermal/intel/power_floor/.gitignore [new file with mode: 0644]
tools/testing/selftests/thermal/intel/workload_hint/.gitignore [new file with mode: 0644]
tools/testing/selftests/uevent/.gitignore [new file with mode: 0644]
tools/tracing/rtla/Makefile
tools/tracing/rtla/src/osnoise_hist.c
tools/tracing/rtla/src/osnoise_top.c
tools/tracing/rtla/src/timerlat_hist.c
tools/tracing/rtla/src/timerlat_top.c
tools/tracing/rtla/src/utils.c
tools/tracing/rtla/src/utils.h
tools/verification/rv/Makefile
tools/verification/rv/src/in_kernel.c
tools/workqueue/wq_dump.py
virt/kvm/kvm_main.c

index ee8f03cc7f726fa22b518a45c1044e4e05498ec5..bd9f1025ac44e0e289a6843de2c4497be2b76118 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -191,10 +191,11 @@ Gao Xiang <xiang@kernel.org> <gaoxiang25@huawei.com>
 Gao Xiang <xiang@kernel.org> <hsiangkao@aol.com>
 Gao Xiang <xiang@kernel.org> <hsiangkao@linux.alibaba.com>
 Gao Xiang <xiang@kernel.org> <hsiangkao@redhat.com>
-Geliang Tang <geliang.tang@linux.dev> <geliang.tang@suse.com>
-Geliang Tang <geliang.tang@linux.dev> <geliangtang@xiaomi.com>
-Geliang Tang <geliang.tang@linux.dev> <geliangtang@gmail.com>
-Geliang Tang <geliang.tang@linux.dev> <geliangtang@163.com>
+Geliang Tang <geliang@kernel.org> <geliang.tang@linux.dev>
+Geliang Tang <geliang@kernel.org> <geliang.tang@suse.com>
+Geliang Tang <geliang@kernel.org> <geliangtang@xiaomi.com>
+Geliang Tang <geliang@kernel.org> <geliangtang@gmail.com>
+Geliang Tang <geliang@kernel.org> <geliangtang@163.com>
 Georgi Djakov <djakov@kernel.org> <georgi.djakov@linaro.org>
 Gerald Schaefer <gerald.schaefer@linux.ibm.com> <geraldsc@de.ibm.com>
 Gerald Schaefer <gerald.schaefer@linux.ibm.com> <gerald.schaefer@de.ibm.com>
@@ -324,6 +325,7 @@ Kenneth W Chen <kenneth.w.chen@intel.com>
 Kenneth Westfield <quic_kwestfie@quicinc.com> <kwestfie@codeaurora.org>
 Kiran Gunda <quic_kgunda@quicinc.com> <kgunda@codeaurora.org>
 Kirill Tkhai <tkhai@ya.ru> <ktkhai@virtuozzo.com>
+Kishon Vijay Abraham I <kishon@kernel.org> <kishon@ti.com>
 Konstantin Khlebnikov <koct9i@gmail.com> <khlebnikov@yandex-team.ru>
 Konstantin Khlebnikov <koct9i@gmail.com> <k.khlebnikov@samsung.com>
 Koushik <raghavendra.koushik@neterion.com>
@@ -552,6 +554,7 @@ Senthilkumar N L <quic_snlakshm@quicinc.com> <snlakshm@codeaurora.org>
 Serge Hallyn <sergeh@kernel.org> <serge.hallyn@canonical.com>
 Serge Hallyn <sergeh@kernel.org> <serue@us.ibm.com>
 Seth Forshee <sforshee@kernel.org> <seth.forshee@canonical.com>
+Shakeel Butt <shakeel.butt@linux.dev> <shakeelb@google.com>
 Shannon Nelson <shannon.nelson@amd.com> <snelson@pensando.io>
 Shannon Nelson <shannon.nelson@amd.com> <shannon.nelson@intel.com>
 Shannon Nelson <shannon.nelson@amd.com> <shannon.nelson@oracle.com>
@@ -607,6 +610,11 @@ TripleX Chung <xxx.phy@gmail.com> <triplex@zh-kernel.org>
 TripleX Chung <xxx.phy@gmail.com> <zhongyu@18mail.cn>
 Tsuneo Yoshioka <Tsuneo.Yoshioka@f-secure.com>
 Tudor Ambarus <tudor.ambarus@linaro.org> <tudor.ambarus@microchip.com>
+Tvrtko Ursulin <tursulin@ursulin.net> <tvrtko.ursulin@intel.com>
+Tvrtko Ursulin <tursulin@ursulin.net> <tvrtko.ursulin@linux.intel.com>
+Tvrtko Ursulin <tursulin@ursulin.net> <tvrtko.ursulin@sophos.com>
+Tvrtko Ursulin <tursulin@ursulin.net> <tvrtko.ursulin@onelan.co.uk>
+Tvrtko Ursulin <tursulin@ursulin.net> <tvrtko@ursulin.net>
 Tycho Andersen <tycho@tycho.pizza> <tycho@tycho.ws>
 Tzung-Bi Shih <tzungbi@kernel.org> <tzungbi@google.com>
 Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
diff --git a/CREDITS b/CREDITS
index df8d6946739f68655a8b077f0ebcc4bf4612944b..3c2bb55847c607f027ddc6c50c259545327c0fe8 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -63,6 +63,11 @@ D: dosfs, LILO, some fd features, ATM, various other hacks here and there
 S: Buenos Aires
 S: Argentina
 
+NTFS FILESYSTEM
+N: Anton Altaparmakov
+E: anton@tuxera.com
+D: NTFS filesystem
+
 N: Tim Alpaerts
 E: tim_alpaerts@toyota-motor-europe.com
 D: 802.2 class II logical link control layer,
index 55db27815361b2d9ad511e026bee60a615ae03d5..53e508c6936a515216ad3af96ddfb170f6e50cf7 100644 (file)
@@ -1,4 +1,4 @@
-What:          /sys/class/<iface>/statistics/collisions
+What:          /sys/class/net/<iface>/statistics/collisions
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -6,7 +6,7 @@ Description:
                Indicates the number of collisions seen by this network device.
                This value might not be relevant with all MAC layers.
 
-What:          /sys/class/<iface>/statistics/multicast
+What:          /sys/class/net/<iface>/statistics/multicast
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -14,7 +14,7 @@ Description:
                Indicates the number of multicast packets received by this
                network device.
 
-What:          /sys/class/<iface>/statistics/rx_bytes
+What:          /sys/class/net/<iface>/statistics/rx_bytes
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -23,7 +23,7 @@ Description:
                See the network driver for the exact meaning of when this
                value is incremented.
 
-What:          /sys/class/<iface>/statistics/rx_compressed
+What:          /sys/class/net/<iface>/statistics/rx_compressed
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -32,7 +32,7 @@ Description:
                network device. This value might only be relevant for interfaces
                that support packet compression (e.g: PPP).
 
-What:          /sys/class/<iface>/statistics/rx_crc_errors
+What:          /sys/class/net/<iface>/statistics/rx_crc_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -41,7 +41,7 @@ Description:
                by this network device. Note that the specific meaning might
                depend on the MAC layer used by the interface.
 
-What:          /sys/class/<iface>/statistics/rx_dropped
+What:          /sys/class/net/<iface>/statistics/rx_dropped
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -51,7 +51,7 @@ Description:
                packet processing. See the network driver for the exact
                meaning of this value.
 
-What:          /sys/class/<iface>/statistics/rx_errors
+What:          /sys/class/net/<iface>/statistics/rx_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -59,7 +59,7 @@ Description:
                Indicates the number of receive errors on this network device.
                See the network driver for the exact meaning of this value.
 
-What:          /sys/class/<iface>/statistics/rx_fifo_errors
+What:          /sys/class/net/<iface>/statistics/rx_fifo_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -68,7 +68,7 @@ Description:
                network device. See the network driver for the exact
                meaning of this value.
 
-What:          /sys/class/<iface>/statistics/rx_frame_errors
+What:          /sys/class/net/<iface>/statistics/rx_frame_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -78,7 +78,7 @@ Description:
                on the MAC layer protocol used. See the network driver for
                the exact meaning of this value.
 
-What:          /sys/class/<iface>/statistics/rx_length_errors
+What:          /sys/class/net/<iface>/statistics/rx_length_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -87,7 +87,7 @@ Description:
                error, oversized or undersized. See the network driver for the
                exact meaning of this value.
 
-What:          /sys/class/<iface>/statistics/rx_missed_errors
+What:          /sys/class/net/<iface>/statistics/rx_missed_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -96,7 +96,7 @@ Description:
                due to lack of capacity in the receive side. See the network
                driver for the exact meaning of this value.
 
-What:          /sys/class/<iface>/statistics/rx_nohandler
+What:          /sys/class/net/<iface>/statistics/rx_nohandler
 Date:          February 2016
 KernelVersion: 4.6
 Contact:       netdev@vger.kernel.org
@@ -104,7 +104,7 @@ Description:
                Indicates the number of received packets that were dropped on
                an inactive device by the network core.
 
-What:          /sys/class/<iface>/statistics/rx_over_errors
+What:          /sys/class/net/<iface>/statistics/rx_over_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -114,7 +114,7 @@ Description:
                (e.g: larger than MTU). See the network driver for the exact
                meaning of this value.
 
-What:          /sys/class/<iface>/statistics/rx_packets
+What:          /sys/class/net/<iface>/statistics/rx_packets
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -122,7 +122,7 @@ Description:
                Indicates the total number of good packets received by this
                network device.
 
-What:          /sys/class/<iface>/statistics/tx_aborted_errors
+What:          /sys/class/net/<iface>/statistics/tx_aborted_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -132,7 +132,7 @@ Description:
                a medium collision). See the network driver for the exact
                meaning of this value.
 
-What:          /sys/class/<iface>/statistics/tx_bytes
+What:          /sys/class/net/<iface>/statistics/tx_bytes
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -143,7 +143,7 @@ Description:
                transmitted packets or all packets that have been queued for
                transmission.
 
-What:          /sys/class/<iface>/statistics/tx_carrier_errors
+What:          /sys/class/net/<iface>/statistics/tx_carrier_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -152,7 +152,7 @@ Description:
                because of carrier errors (e.g: physical link down). See the
                network driver for the exact meaning of this value.
 
-What:          /sys/class/<iface>/statistics/tx_compressed
+What:          /sys/class/net/<iface>/statistics/tx_compressed
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -161,7 +161,7 @@ Description:
                this might only be relevant for devices that support
                compression (e.g: PPP).
 
-What:          /sys/class/<iface>/statistics/tx_dropped
+What:          /sys/class/net/<iface>/statistics/tx_dropped
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -170,7 +170,7 @@ Description:
                See the driver for the exact reasons as to why the packets were
                dropped.
 
-What:          /sys/class/<iface>/statistics/tx_errors
+What:          /sys/class/net/<iface>/statistics/tx_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -179,7 +179,7 @@ Description:
                a network device. See the driver for the exact reasons as to
                why the packets were dropped.
 
-What:          /sys/class/<iface>/statistics/tx_fifo_errors
+What:          /sys/class/net/<iface>/statistics/tx_fifo_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -188,7 +188,7 @@ Description:
                FIFO error. See the driver for the exact reasons as to why the
                packets were dropped.
 
-What:          /sys/class/<iface>/statistics/tx_heartbeat_errors
+What:          /sys/class/net/<iface>/statistics/tx_heartbeat_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -197,7 +197,7 @@ Description:
                reported as heartbeat errors. See the driver for the exact
                reasons as to why the packets were dropped.
 
-What:          /sys/class/<iface>/statistics/tx_packets
+What:          /sys/class/net/<iface>/statistics/tx_packets
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
@@ -206,7 +206,7 @@ Description:
                device. See the driver for whether this reports the number of all
                attempted or successful transmissions.
 
-What:          /sys/class/<iface>/statistics/tx_window_errors
+What:          /sys/class/net/<iface>/statistics/tx_window_errors
 Date:          April 2005
 KernelVersion: 2.6.12
 Contact:       netdev@vger.kernel.org
index a1db6db475055e23a9bbfeabcce63e8e7b0dbc23..710d47be11e04587e0a02a0e175f1c91c54d6913 100644 (file)
@@ -516,6 +516,7 @@ What:               /sys/devices/system/cpu/vulnerabilities
                /sys/devices/system/cpu/vulnerabilities/mds
                /sys/devices/system/cpu/vulnerabilities/meltdown
                /sys/devices/system/cpu/vulnerabilities/mmio_stale_data
+               /sys/devices/system/cpu/vulnerabilities/reg_file_data_sampling
                /sys/devices/system/cpu/vulnerabilities/retbleed
                /sys/devices/system/cpu/vulnerabilities/spec_store_bypass
                /sys/devices/system/cpu/vulnerabilities/spectre_v1
index 7af70adf3690e3b0b3a3c148a087ecb3f788d54a..c7c9444f92a880ff3f9971fc52f71a0e2756d5f1 100644 (file)
@@ -4,18 +4,18 @@ KernelVersion:        6.5
 Contact:       Miquel Raynal <miquel.raynal@bootlin.com>
 Description:
                The "cells" folder contains one file per cell exposed by the
-               NVMEM device. The name of the file is: <name>@<where>, with
-               <name> being the cell name and <where> its location in the NVMEM
-               device, in hexadecimal (without the '0x' prefix, to mimic device
-               tree node names). The length of the file is the size of the cell
-               (when known). The content of the file is the binary content of
-               the cell (may sometimes be ASCII, likely without trailing
-               character).
+               NVMEM device. The name of the file is: "<name>@<byte>,<bit>",
+               with <name> being the cell name and <where> its location in
+               the NVMEM device, in hexadecimal bytes and bits (without the
+               '0x' prefix, to mimic device tree node names). The length of
+               the file is the size of the cell (when known). The content of
+               the file is the binary content of the cell (may sometimes be
+               ASCII, likely without trailing character).
                Note: This file is only present if CONFIG_NVMEM_SYSFS
                is enabled.
 
                Example::
 
-                 hexdump -C /sys/bus/nvmem/devices/1-00563/cells/product-name@d
+                 hexdump -C /sys/bus/nvmem/devices/1-00563/cells/product-name@d,0
                  00000000  54 4e 34 38 4d 2d 50 2d  44 4e         |TN48M-P-DN|
                  0000000a
index 2d42998a89a6378a94521d49785c4f1632b25a34..3e6407de231c998ac7f0539c3d856458097d8971 100644 (file)
@@ -68,7 +68,8 @@ over a rather long period of time, but improvements are always welcome!
        rcu_read_lock_sched(), or by the appropriate update-side lock.
        Explicit disabling of preemption (preempt_disable(), for example)
        can serve as rcu_read_lock_sched(), but is less readable and
-       prevents lockdep from detecting locking issues.
+       prevents lockdep from detecting locking issues.  Acquiring a
+       spinlock also enters an RCU read-side critical section.
 
        Please note that you *cannot* rely on code known to be built
        only in non-preemptible kernels.  Such code can and will break,
@@ -382,16 +383,17 @@ over a rather long period of time, but improvements are always welcome!
        must use whatever locking or other synchronization is required
        to safely access and/or modify that data structure.
 
-       Do not assume that RCU callbacks will be executed on the same
-       CPU that executed the corresponding call_rcu() or call_srcu().
-       For example, if a given CPU goes offline while having an RCU
-       callback pending, then that RCU callback will execute on some
-       surviving CPU.  (If this was not the case, a self-spawning RCU
-       callback would prevent the victim CPU from ever going offline.)
-       Furthermore, CPUs designated by rcu_nocbs= might well *always*
-       have their RCU callbacks executed on some other CPUs, in fact,
-       for some  real-time workloads, this is the whole point of using
-       the rcu_nocbs= kernel boot parameter.
+       Do not assume that RCU callbacks will be executed on
+       the same CPU that executed the corresponding call_rcu(),
+       call_srcu(), call_rcu_tasks(), call_rcu_tasks_rude(), or
+       call_rcu_tasks_trace().  For example, if a given CPU goes offline
+       while having an RCU callback pending, then that RCU callback
+       will execute on some surviving CPU.  (If this was not the case,
+       a self-spawning RCU callback would prevent the victim CPU from
+       ever going offline.)  Furthermore, CPUs designated by rcu_nocbs=
+       might well *always* have their RCU callbacks executed on some
+       other CPUs, in fact, for some  real-time workloads, this is the
+       whole point of using the rcu_nocbs= kernel boot parameter.
 
        In addition, do not assume that callbacks queued in a given order
        will be invoked in that order, even if they all are queued on the
@@ -444,7 +446,7 @@ over a rather long period of time, but improvements are always welcome!
        real-time workloads than is synchronize_rcu_expedited().
 
        It is also permissible to sleep in RCU Tasks Trace read-side
-       critical, which are delimited by rcu_read_lock_trace() and
+       critical section, which are delimited by rcu_read_lock_trace() and
        rcu_read_unlock_trace().  However, this is a specialized flavor
        of RCU, and you should not use it without first checking with
        its current users.  In most cases, you should instead use SRCU.
@@ -490,6 +492,12 @@ over a rather long period of time, but improvements are always welcome!
                since the last time that you passed that same object to
                call_rcu() (or friends).
 
+       CONFIG_RCU_STRICT_GRACE_PERIOD:
+               combine with KASAN to check for pointers leaked out
+               of RCU read-side critical sections.  This Kconfig
+               option is tough on both performance and scalability,
+               and so is limited to four-CPU systems.
+
        __rcu sparse checks:
                tag the pointer to the RCU-protected data structure
                with __rcu, and sparse will warn you if you access that
index 659d5913784d0d9e2d196a04bdfb7fadb57d5eed..2524dcdadde2b801b33a4ce0a93f31948ea7aefb 100644 (file)
@@ -408,7 +408,10 @@ member of the rcu_dereference() to use in various situations:
        RCU flavors, an RCU read-side critical section is entered
        using rcu_read_lock(), anything that disables bottom halves,
        anything that disables interrupts, or anything that disables
-       preemption.
+       preemption.  Please note that spinlock critical sections
+       are also implied RCU read-side critical sections, even when
+       they are preemptible, as they are in kernels built with
+       CONFIG_PREEMPT_RT=y.
 
 2.     If the access might be within an RCU read-side critical section
        on the one hand, or protected by (say) my_lock on the other,
index 60ce02475142d881b0238f67eee5b9306830745e..872ac665223fbd51f7e06fd6fcf9eddd0de5a65f 100644 (file)
@@ -172,14 +172,25 @@ rcu_read_lock()
        critical section.  Reference counts may be used in conjunction
        with RCU to maintain longer-term references to data structures.
 
+       Note that anything that disables bottom halves, preemption,
+       or interrupts also enters an RCU read-side critical section.
+       Acquiring a spinlock also enters an RCU read-side critical
+       sections, even for spinlocks that do not disable preemption,
+       as is the case in kernels built with CONFIG_PREEMPT_RT=y.
+       Sleeplocks do *not* enter RCU read-side critical sections.
+
 rcu_read_unlock()
 ^^^^^^^^^^^^^^^^^
        void rcu_read_unlock(void);
 
        This temporal primitives is used by a reader to inform the
        reclaimer that the reader is exiting an RCU read-side critical
-       section.  Note that RCU read-side critical sections may be nested
-       and/or overlapping.
+       section.  Anything that enables bottom halves, preemption,
+       or interrupts also exits an RCU read-side critical section.
+       Releasing a spinlock also exits an RCU read-side critical section.
+
+       Note that RCU read-side critical sections may be nested and/or
+       overlapping.
 
 synchronize_rcu()
 ^^^^^^^^^^^^^^^^^
@@ -952,8 +963,8 @@ unfortunately any spinlock in a ``SLAB_TYPESAFE_BY_RCU`` object must be
 initialized after each and every call to kmem_cache_alloc(), which renders
 reference-free spinlock acquisition completely unsafe.  Therefore, when
 using ``SLAB_TYPESAFE_BY_RCU``, make proper use of a reference counter.
-(Those willing to use a kmem_cache constructor may also use locking,
-including cache-friendly sequence locking.)
+(Those willing to initialize their locks in a kmem_cache constructor
+may also use locking, including cache-friendly sequence locking.)
 
 With traditional reference counting -- such as that implemented by the
 kref library in Linux -- there is typically code that runs when the last
diff --git a/Documentation/admin-guide/RAS/address-translation.rst b/Documentation/admin-guide/RAS/address-translation.rst
new file mode 100644 (file)
index 0000000..f0ca17b
--- /dev/null
@@ -0,0 +1,24 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Address translation
+===================
+
+x86 AMD
+-------
+
+Zen-based AMD systems include a Data Fabric that manages the layout of
+physical memory. Devices attached to the Fabric, like memory controllers,
+I/O, etc., may not have a complete view of the system physical memory map.
+These devices may provide a "normalized", i.e. device physical, address
+when reporting memory errors. Normalized addresses must be translated to
+a system physical address for the kernel to action on the memory.
+
+AMD Address Translation Library (CONFIG_AMD_ATL) provides translation for
+this case.
+
+Glossary of acronyms used in address translation for Zen-based systems
+
+* CCM               = Cache Coherent Moderator
+* COD               = Cluster-on-Die
+* COH_ST            = Coherent Station
+* DF                = Data Fabric
similarity index 73%
rename from Documentation/RAS/ras.rst
rename to Documentation/admin-guide/RAS/error-decoding.rst
index 2556b397cd271fc536daf727a9f7ea178fac6e02..26a72f3fe5de83230db5c51403fc8c462649b490 100644 (file)
@@ -1,15 +1,10 @@
 .. SPDX-License-Identifier: GPL-2.0
 
-Reliability, Availability and Serviceability features
-=====================================================
-
-This documents different aspects of the RAS functionality present in the
-kernel.
-
 Error decoding
----------------
+==============
 
-* x86
+x86
+---
 
 Error decoding on AMD systems should be done using the rasdaemon tool:
 https://github.com/mchehab/rasdaemon/
diff --git a/Documentation/admin-guide/RAS/index.rst b/Documentation/admin-guide/RAS/index.rst
new file mode 100644 (file)
index 0000000..f408704
--- /dev/null
@@ -0,0 +1,7 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. toctree::
+   :maxdepth: 2
+
+   main
+   error-decoding
+   address-translation
similarity index 99%
rename from Documentation/admin-guide/ras.rst
rename to Documentation/admin-guide/RAS/main.rst
index 8e03751d126d01f6bed53b5f694f2c0a95c59893..7ac1d4ccc5099391470fc41c690187b6f3c820b5 100644 (file)
@@ -1,8 +1,12 @@
+.. SPDX-License-Identifier: GPL-2.0
 .. include:: <isonum.txt>
 
-============================================
-Reliability, Availability and Serviceability
-============================================
+==================================================
+Reliability, Availability and Serviceability (RAS)
+==================================================
+
+This documents different aspects of the RAS functionality present in the
+kernel.
 
 RAS concepts
 ************
index ae646d621a8ab6d208585bf0fdcd53e583ff76b7..7d3415eea05d027572241bd8150762e159577ed8 100644 (file)
@@ -179,7 +179,7 @@ files describing that cpuset:
  - cpuset.mem_hardwall flag:  is memory allocation hardwalled
  - cpuset.memory_pressure: measure of how much paging pressure in cpuset
  - cpuset.memory_spread_page flag: if set, spread page cache evenly on allowed nodes
- - cpuset.memory_spread_slab flag: if set, spread slab cache evenly on allowed nodes
+ - cpuset.memory_spread_slab flag: OBSOLETE. Doesn't have any function.
  - cpuset.sched_load_balance flag: if set, load balance within CPUs on that cpuset
  - cpuset.sched_relax_domain_level: the searching range when migrating tasks
 
index 0fa724d82abb60821fb3bce63e6ec859d0b629d2..493a8e386700ae3c19035159eab62ee7be48a954 100644 (file)
@@ -65,10 +65,12 @@ files include::
 
 1. Page fault accounting
 
-hugetlb.<hugepagesize>.limit_in_bytes
-hugetlb.<hugepagesize>.max_usage_in_bytes
-hugetlb.<hugepagesize>.usage_in_bytes
-hugetlb.<hugepagesize>.failcnt
+::
+
+  hugetlb.<hugepagesize>.limit_in_bytes
+  hugetlb.<hugepagesize>.max_usage_in_bytes
+  hugetlb.<hugepagesize>.usage_in_bytes
+  hugetlb.<hugepagesize>.failcnt
 
 The HugeTLB controller allows users to limit the HugeTLB usage (page fault) per
 control group and enforces the limit during page fault. Since HugeTLB
@@ -82,10 +84,12 @@ getting SIGBUS.
 
 2. Reservation accounting
 
-hugetlb.<hugepagesize>.rsvd.limit_in_bytes
-hugetlb.<hugepagesize>.rsvd.max_usage_in_bytes
-hugetlb.<hugepagesize>.rsvd.usage_in_bytes
-hugetlb.<hugepagesize>.rsvd.failcnt
+::
+
+  hugetlb.<hugepagesize>.rsvd.limit_in_bytes
+  hugetlb.<hugepagesize>.rsvd.max_usage_in_bytes
+  hugetlb.<hugepagesize>.rsvd.usage_in_bytes
+  hugetlb.<hugepagesize>.rsvd.failcnt
 
 The HugeTLB controller allows to limit the HugeTLB reservations per control
 group and enforces the controller limit at reservation time and at the fault of
index de99caabf65a3f3ba3a35dd947236195e9dcebfa..ff0b440ef2dc90be293208c597f8729039ce8540 100644 (file)
@@ -21,3 +21,4 @@ are configurable at compile, boot or run time.
    cross-thread-rsb
    srso
    gather_data_sampling
+   reg-file-data-sampling
diff --git a/Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst b/Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst
new file mode 100644 (file)
index 0000000..0585d02
--- /dev/null
@@ -0,0 +1,104 @@
+==================================
+Register File Data Sampling (RFDS)
+==================================
+
+Register File Data Sampling (RFDS) is a microarchitectural vulnerability that
+only affects Intel Atom parts(also branded as E-cores). RFDS may allow
+a malicious actor to infer data values previously used in floating point
+registers, vector registers, or integer registers. RFDS does not provide the
+ability to choose which data is inferred. CVE-2023-28746 is assigned to RFDS.
+
+Affected Processors
+===================
+Below is the list of affected Intel processors [#f1]_:
+
+   ===================  ============
+   Common name          Family_Model
+   ===================  ============
+   ATOM_GOLDMONT           06_5CH
+   ATOM_GOLDMONT_D         06_5FH
+   ATOM_GOLDMONT_PLUS      06_7AH
+   ATOM_TREMONT_D          06_86H
+   ATOM_TREMONT            06_96H
+   ALDERLAKE               06_97H
+   ALDERLAKE_L             06_9AH
+   ATOM_TREMONT_L          06_9CH
+   RAPTORLAKE              06_B7H
+   RAPTORLAKE_P            06_BAH
+   ATOM_GRACEMONT          06_BEH
+   RAPTORLAKE_S            06_BFH
+   ===================  ============
+
+As an exception to this table, Intel Xeon E family parts ALDERLAKE(06_97H) and
+RAPTORLAKE(06_B7H) codenamed Catlow are not affected. They are reported as
+vulnerable in Linux because they share the same family/model with an affected
+part. Unlike their affected counterparts, they do not enumerate RFDS_CLEAR or
+CPUID.HYBRID. This information could be used to distinguish between the
+affected and unaffected parts, but it is deemed not worth adding complexity as
+the reporting is fixed automatically when these parts enumerate RFDS_NO.
+
+Mitigation
+==========
+Intel released a microcode update that enables software to clear sensitive
+information using the VERW instruction. Like MDS, RFDS deploys the same
+mitigation strategy to force the CPU to clear the affected buffers before an
+attacker can extract the secrets. This is achieved by using the otherwise
+unused and obsolete VERW instruction in combination with a microcode update.
+The microcode clears the affected CPU buffers when the VERW instruction is
+executed.
+
+Mitigation points
+-----------------
+VERW is executed by the kernel before returning to user space, and by KVM
+before VMentry. None of the affected cores support SMT, so VERW is not required
+at C-state transitions.
+
+New bits in IA32_ARCH_CAPABILITIES
+----------------------------------
+Newer processors and microcode update on existing affected processors added new
+bits to IA32_ARCH_CAPABILITIES MSR. These bits can be used to enumerate
+vulnerability and mitigation capability:
+
+- Bit 27 - RFDS_NO - When set, processor is not affected by RFDS.
+- Bit 28 - RFDS_CLEAR - When set, processor is affected by RFDS, and has the
+  microcode that clears the affected buffers on VERW execution.
+
+Mitigation control on the kernel command line
+---------------------------------------------
+The kernel command line allows to control RFDS mitigation at boot time with the
+parameter "reg_file_data_sampling=". The valid arguments are:
+
+  ==========  =================================================================
+  on          If the CPU is vulnerable, enable mitigation; CPU buffer clearing
+              on exit to userspace and before entering a VM.
+  off         Disables mitigation.
+  ==========  =================================================================
+
+Mitigation default is selected by CONFIG_MITIGATION_RFDS.
+
+Mitigation status information
+-----------------------------
+The Linux kernel provides a sysfs interface to enumerate the current
+vulnerability status of the system: whether the system is vulnerable, and
+which mitigations are active. The relevant sysfs file is:
+
+       /sys/devices/system/cpu/vulnerabilities/reg_file_data_sampling
+
+The possible values in this file are:
+
+  .. list-table::
+
+     * - 'Not affected'
+       - The processor is not vulnerable
+     * - 'Vulnerable'
+       - The processor is vulnerable, but no mitigation enabled
+     * - 'Vulnerable: No microcode'
+       - The processor is vulnerable but microcode is not updated.
+     * - 'Mitigation: Clear Register File'
+       - The processor is vulnerable and the CPU buffer clearing mitigation is
+        enabled.
+
+References
+----------
+.. [#f1] Affected Processors
+   https://www.intel.com/content/www/us/en/developer/topic-technology/software-security-guidance/processors-affected-consolidated-product-cpu-model.html
index 32a8893e5617764e1a9ca1ae4e106150decf2952..cce768afec6bed11a961643dcdc2d1ae97848684 100644 (file)
@@ -473,8 +473,8 @@ Spectre variant 2
    -mindirect-branch=thunk-extern -mindirect-branch-register options.
    If the kernel is compiled with a Clang compiler, the compiler needs
    to support -mretpoline-external-thunk option.  The kernel config
-   CONFIG_RETPOLINE needs to be turned on, and the CPU needs to run with
-   the latest updated microcode.
+   CONFIG_MITIGATION_RETPOLINE needs to be turned on, and the CPU needs
+   to run with the latest updated microcode.
 
    On Intel Skylake-era systems the mitigation covers most, but not all,
    cases. See :ref:`[3] <spec_ref3>` for more details.
@@ -609,8 +609,8 @@ kernel command line.
                Selecting 'on' will, and 'auto' may, choose a
                mitigation method at run time according to the
                CPU, the available microcode, the setting of the
-               CONFIG_RETPOLINE configuration option, and the
-               compiler with which the kernel was built.
+               CONFIG_MITIGATION_RETPOLINE configuration option,
+               and the compiler with which the kernel was built.
 
                Selecting 'on' will also enable the mitigation
                against user space to user space task attacks.
index fb40a1f6f79e18d85ddb1ff254c9a04fed9ade2b..dfc06fab94322581e732405f3d722da3bba529bb 100644 (file)
@@ -122,7 +122,7 @@ configure specific aspects of kernel behavior to your liking.
    pmf
    pnp
    rapidio
-   ras
+   RAS/index
    rtc
    serial-console
    svga
index 5762e7477a0c8edb28d59e0a2176a23fb627016b..0302a93b1d40b7b0e6265306e580bfe32c9afd1b 100644 (file)
@@ -191,9 +191,7 @@ Dump-capture kernel config options (Arch Dependent, i386 and x86_64)
    CPU is enough for kdump kernel to dump vmcore on most of systems.
 
    However, you can also specify nr_cpus=X to enable multiple processors
-   in kdump kernel. In this case, "disable_cpu_apicid=" is needed to
-   tell kdump kernel which cpu is 1st kernel's BSP. Please refer to
-   admin-guide/kernel-parameters.txt for more details.
+   in kdump kernel.
 
    With CONFIG_SMP=n, the above things are not related.
 
@@ -454,8 +452,7 @@ Notes on loading the dump-capture kernel:
   to use multi-thread programs with it, such as parallel dump feature of
   makedumpfile. Otherwise, the multi-thread program may have a great
   performance degradation. To enable multi-cpu support, you should bring up an
-  SMP dump-capture kernel and specify maxcpus/nr_cpus, disable_cpu_apicid=[X]
-  options while loading it.
+  SMP dump-capture kernel and specify maxcpus/nr_cpus options while loading it.
 
 * For s390x there are two kdump modes: If a ELF header is specified with
   the elfcorehdr= kernel parameter, it is used by the kdump kernel as it
index 4410384596a90b0ab26b4cf43bac54aaf78193fe..e8bdf5e86a9ba15b9d52858e66b7478307b6660f 100644 (file)
@@ -108,6 +108,7 @@ is applicable::
        CMA     Contiguous Memory Area support is enabled.
        DRM     Direct Rendering Management support is enabled.
        DYNAMIC_DEBUG Build in debug messages and enable them at runtime
+       EARLY   Parameter processed too early to be embedded in initrd.
        EDD     BIOS Enhanced Disk Drive Services (EDD) is enabled
        EFI     EFI Partitioning (GPT) is enabled
        EVM     Extended Verification Module
index 31b3a25680d08cfac3603d58b3d3783bbf1e34bb..825398d66c6963664cf34f3e4e64853e47d79211 100644 (file)
@@ -9,7 +9,7 @@
                        accept_memory=eager can be used to accept all memory
                        at once during boot.
 
-       acpi=           [HW,ACPI,X86,ARM64,RISCV64]
+       acpi=           [HW,ACPI,X86,ARM64,RISCV64,EARLY]
                        Advanced Configuration and Power Interface
                        Format: { force | on | off | strict | noirq | rsdt |
                                  copy_dsdt }
@@ -26,7 +26,7 @@
 
                        See also Documentation/power/runtime_pm.rst, pci=noacpi
 
-       acpi_apic_instance=     [ACPI, IOAPIC]
+       acpi_apic_instance=     [ACPI,IOAPIC,EARLY]
                        Format: <int>
                        2: use 2nd APIC table, if available
                        1,0: use 1st APIC table
@@ -41,7 +41,7 @@
                        If set to native, use the device's native backlight mode.
                        If set to none, disable the ACPI backlight interface.
 
-       acpi_force_32bit_fadt_addr
+       acpi_force_32bit_fadt_addr [ACPI,EARLY]
                        force FADT to use 32 bit addresses rather than the
                        64 bit X_* addresses. Some firmware have broken 64
                        bit addresses for force ACPI ignore these and use
@@ -97,7 +97,7 @@
                        no: ACPI OperationRegions are not marked as reserved,
                        no further checks are performed.
 
-       acpi_force_table_verification   [HW,ACPI]
+       acpi_force_table_verification   [HW,ACPI,EARLY]
                        Enable table checksum verification during early stage.
                        By default, this is disabled due to x86 early mapping
                        size limitation.
        acpi_no_memhotplug [ACPI] Disable memory hotplug.  Useful for kdump
                           kernels.
 
-       acpi_no_static_ssdt     [HW,ACPI]
+       acpi_no_static_ssdt     [HW,ACPI,EARLY]
                        Disable installation of static SSDTs at early boot time
                        By default, SSDTs contained in the RSDT/XSDT will be
                        installed automatically and they will appear under
                        Ignore the ACPI-based watchdog interface (WDAT) and let
                        a native driver control the watchdog device instead.
 
-       acpi_rsdp=      [ACPI,EFI,KEXEC]
+       acpi_rsdp=      [ACPI,EFI,KEXEC,EARLY]
                        Pass the RSDP address to the kernel, mostly used
                        on machines running EFI runtime service to boot the
                        second kernel for kdump.
                        to assume that this machine's pmtimer latches its value
                        and always returns good values.
 
-       acpi_sci=       [HW,ACPI] ACPI System Control Interrupt trigger mode
+       acpi_sci=       [HW,ACPI,EARLY] ACPI System Control Interrupt trigger mode
                        Format: { level | edge | high | low }
 
-       acpi_skip_timer_override [HW,ACPI]
+       acpi_skip_timer_override [HW,ACPI,EARLY]
                        Recognize and ignore IRQ0/pin2 Interrupt Override.
                        For broken nForce2 BIOS resulting in XT-PIC timer.
 
                        behave incorrectly in some ways with respect to system
                        suspend and resume to be ignored (use wisely).
 
-       acpi_use_timer_override [HW,ACPI]
+       acpi_use_timer_override [HW,ACPI,EARLY]
                        Use timer override. For some broken Nvidia NF5 boards
                        that require a timer override, but don't have HPET
 
-       add_efi_memmap  [EFI; X86] Include EFI memory map in
+       add_efi_memmap  [EFI,X86,EARLY] Include EFI memory map in
                        kernel's map of available physical RAM.
 
        agp=            [AGP]
                        do not want to use tracing_snapshot_alloc() as it needs
                        to be done where GFP_KERNEL allocations are allowed.
 
-       allow_mismatched_32bit_el0 [ARM64]
+       allow_mismatched_32bit_el0 [ARM64,EARLY]
                        Allow execve() of 32-bit applications and setting of the
                        PER_LINUX32 personality on systems where only a strict
                        subset of the CPUs support 32-bit EL0. When this
                                     This mode requires kvm-amd.avic=1.
                                     (Default when IOMMU HW support is present.)
 
-       amd_pstate=     [X86]
+       amd_pstate=     [X86,EARLY]
                        disable
                          Do not enable amd_pstate as the default
                          scaling driver for the supported processors
                        not play well with APC CPU idle - disable it if you have
                        APC and your system crashes randomly.
 
-       apic=           [APIC,X86] Advanced Programmable Interrupt Controller
+       apic=           [APIC,X86,EARLY] Advanced Programmable Interrupt Controller
                        Change the output verbosity while booting
                        Format: { quiet (default) | verbose | debug }
                        Change the amount of debugging information output
                        Format: apic=driver_name
                        Examples: apic=bigsmp
 
-       apic_extnmi=    [APIC,X86] External NMI delivery setting
+       apic_extnmi=    [APIC,X86,EARLY] External NMI delivery setting
                        Format: { bsp (default) | all | none }
                        bsp:  External NMI is delivered only to CPU 0
                        all:  External NMIs are broadcast to all CPUs as a
        bert_disable    [ACPI]
                        Disable BERT OS support on buggy BIOSes.
 
-       bgrt_disable    [ACPI][X86]
+       bgrt_disable    [ACPI,X86,EARLY]
                        Disable BGRT to avoid flickering OEM logo.
 
        blkdevparts=    Manual partition parsing of block device(s) for
                        embedded devices based on command line input.
                        See Documentation/block/cmdline-partition.rst
 
-       boot_delay=     Milliseconds to delay each printk during boot.
+       boot_delay=     [KNL,EARLY]
+                       Milliseconds to delay each printk during boot.
                        Only works if CONFIG_BOOT_PRINTK_DELAY is enabled,
                        and you may also have to specify "lpj=".  Boot_delay
                        values larger than 10 seconds (10000) are assumed
                        erroneous and ignored.
                        Format: integer
 
-       bootconfig      [KNL]
+       bootconfig      [KNL,EARLY]
                        Extended command line options can be added to an initrd
                        and this will cause the kernel to look for it.
 
                        trust validation.
                        format: { id:<keyid> | builtin }
 
-       cca=            [MIPS] Override the kernel pages' cache coherency
+       cca=            [MIPS,EARLY] Override the kernel pages' cache coherency
                        algorithm.  Accepted values range from 0 to 7
                        inclusive. See arch/mips/include/asm/pgtable-bits.h
                        for platform specific values (SB1, Loongson3 and
                        [X86-64] hpet,tsc
 
        clocksource.arm_arch_timer.evtstrm=
-                       [ARM,ARM64]
+                       [ARM,ARM64,EARLY]
                        Format: <bool>
                        Enable/disable the eventstream feature of the ARM
                        architected timer so that code using WFE-based polling
                        loops can be debugged more effectively on production
                        systems.
 
-       clocksource.max_cswd_read_retries= [KNL]
-                       Number of clocksource_watchdog() retries due to
-                       external delays before the clock will be marked
-                       unstable.  Defaults to two retries, that is,
-                       three attempts to read the clock under test.
-
        clocksource.verify_n_cpus= [KNL]
                        Limit the number of CPUs checked for clocksources
                        marked with CLOCK_SOURCE_VERIFY_PERCPU that
                        10 seconds when built into the kernel.
 
        cma=nn[MG]@[start[MG][-end[MG]]]
-                       [KNL,CMA]
+                       [KNL,CMA,EARLY]
                        Sets the size of kernel global memory area for
                        contiguous memory allocations and optionally the
                        placement constraint by the physical address range of
                        kernel/dma/contiguous.c
 
        cma_pernuma=nn[MG]
-                       [KNL,CMA]
+                       [KNL,CMA,EARLY]
                        Sets the size of kernel per-numa memory area for
                        contiguous memory allocations. A value of 0 disables
                        per-numa CMA altogether. And If this option is not
                        they will fallback to the global default memory area.
 
        numa_cma=<node>:nn[MG][,<node>:nn[MG]]
-                       [KNL,CMA]
+                       [KNL,CMA,EARLY]
                        Sets the size of kernel numa memory area for
                        contiguous memory allocations. It will reserve CMA
                        area for the specified node.
                        a hypervisor.
                        Default: yes
 
-       coherent_pool=nn[KMG]   [ARM,KNL]
+       coherent_pool=nn[KMG]   [ARM,KNL,EARLY]
                        Sets the size of memory pool for coherent, atomic dma
                        allocations, by default set to 256K.
 
        condev=         [HW,S390] console device
        conmode=
 
-       con3215_drop=   [S390] 3215 console drop mode.
+       con3215_drop=   [S390,EARLY] 3215 console drop mode.
                        Format: y|n|Y|N|1|0
                        When set to true, drop data on the 3215 console when
                        the console buffer is full. In this case the
                        kernel before the cpufreq driver probes.
 
        cpu_init_udelay=N
-                       [X86] Delay for N microsec between assert and de-assert
+                       [X86,EARLY] Delay for N microsec between assert and de-assert
                        of APIC INIT to start processors.  This delay occurs
                        on every CPU online, such as boot, and resume from suspend.
                        Default: 10000
                        kernel more unstable.
 
        crashkernel=size[KMG][@offset[KMG]]
-                       [KNL] Using kexec, Linux can switch to a 'crash kernel'
+                       [KNL,EARLY] Using kexec, Linux can switch to a 'crash kernel'
                        upon panic. This parameter reserves the physical
                        memory region [offset, offset + size] for that kernel
                        image. If '@offset' is omitted, then a suitable offset
                        Format: <port#>,<type>
                        See also Documentation/input/devices/joystick-parport.rst
 
-       debug           [KNL] Enable kernel debugging (events log level).
+       debug           [KNL,EARLY] Enable kernel debugging (events log level).
 
        debug_boot_weak_hash
-                       [KNL] Enable printing [hashed] pointers early in the
+                       [KNL,EARLY] Enable printing [hashed] pointers early in the
                        boot sequence.  If enabled, we use a weak hash instead
                        of siphash to hash pointers.  Use this option if you are
                        seeing instances of '(___ptrval___)') and need to see a
                        will print _a_lot_ more information - normally only
                        useful to lockdep developers.
 
-       debug_objects   [KNL] Enable object debugging
+       debug_objects   [KNL,EARLY] Enable object debugging
 
        debug_guardpage_minorder=
-                       [KNL] When CONFIG_DEBUG_PAGEALLOC is set, this
+                       [KNL,EARLY] When CONFIG_DEBUG_PAGEALLOC is set, this
                        parameter allows control of the order of pages that will
                        be intentionally kept free (and hence protected) by the
                        buddy allocator. Bigger value increase the probability
                        help tracking down these problems.
 
        debug_pagealloc=
-                       [KNL] When CONFIG_DEBUG_PAGEALLOC is set, this parameter
+                       [KNL,EARLY] When CONFIG_DEBUG_PAGEALLOC is set, this parameter
                        enables the feature at boot time. By default, it is
                        disabled and the system will work mostly the same as a
                        kernel built without CONFIG_DEBUG_PAGEALLOC.
                        useful to also enable the page_owner functionality.
                        on: enable the feature
 
-       debugfs=        [KNL] This parameter enables what is exposed to userspace
-                       and debugfs internal clients.
+       debugfs=        [KNL,EARLY] This parameter enables what is exposed to
+                       userspace and debugfs internal clients.
                        Format: { on, no-mount, off }
                        on:     All functions are enabled.
                        no-mount:
        dhash_entries=  [KNL]
                        Set number of hash buckets for dentry cache.
 
-       disable_1tb_segments [PPC]
+       disable_1tb_segments [PPC,EARLY]
                        Disables the use of 1TB hash page table segments. This
                        causes the kernel to fall back to 256MB segments which
                        can be useful when debugging issues that require an SLB
        disable=        [IPV6]
                        See Documentation/networking/ipv6.rst.
 
-       disable_radix   [PPC]
+       disable_radix   [PPC,EARLY]
                        Disable RADIX MMU mode on POWER9
 
        disable_tlbie   [PPC]
                        Disable TLBIE instruction. Currently does not work
                        with KVM, with HASH MMU, or with coherent accelerators.
 
-       disable_cpu_apicid= [X86,APIC,SMP]
-                       Format: <int>
-                       The number of initial APIC ID for the
-                       corresponding CPU to be disabled at boot,
-                       mostly used for the kdump 2nd kernel to
-                       disable BSP to wake up multiple CPUs without
-                       causing system reset or hang due to sending
-                       INIT from AP to BSP.
-
-       disable_ddw     [PPC/PSERIES]
+       disable_ddw     [PPC/PSERIES,EARLY]
                        Disable Dynamic DMA Window support. Use this
                        to workaround buggy firmware.
 
        disable_ipv6=   [IPV6]
                        See Documentation/networking/ipv6.rst.
 
-       disable_mtrr_cleanup [X86]
+       disable_mtrr_cleanup [X86,EARLY]
                        The kernel tries to adjust MTRR layout from continuous
                        to discrete, to make X server driver able to add WB
                        entry later. This parameter disables that.
 
-       disable_mtrr_trim [X86, Intel and AMD only]
+       disable_mtrr_trim [X86, Intel and AMD only,EARLY]
                        By default the kernel will trim any uncacheable
                        memory out of your available memory pool based on
                        MTRR settings.  This parameter disables that behavior,
                        possibly causing your machine to run very slowly.
 
-       disable_timer_pin_1 [X86]
+       disable_timer_pin_1 [X86,EARLY]
                        Disable PIN 1 of APIC timer
                        Can be useful to work around chipset bugs.
 
                        The filter can be disabled or changed to another
                        driver later using sysfs.
 
+       reg_file_data_sampling=
+                       [X86] Controls mitigation for Register File Data
+                       Sampling (RFDS) vulnerability. RFDS is a CPU
+                       vulnerability which may allow userspace to infer
+                       kernel data values previously stored in floating point
+                       registers, vector registers, or integer registers.
+                       RFDS only affects Intel Atom processors.
+
+                       on:     Turns ON the mitigation.
+                       off:    Turns OFF the mitigation.
+
+                       This parameter overrides the compile time default set
+                       by CONFIG_MITIGATION_RFDS. Mitigation cannot be
+                       disabled when other VERW based mitigations (like MDS)
+                       are enabled. In order to disable RFDS mitigation all
+                       VERW based mitigations need to be disabled.
+
+                       For details see:
+                       Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst
+
        driver_async_probe=  [KNL]
                        List of driver names to be probed asynchronously. *
                        matches with all driver names. If * is specified, the
 
        dscc4.setup=    [NET]
 
-       dt_cpu_ftrs=    [PPC]
+       dt_cpu_ftrs=    [PPC,EARLY]
                        Format: {"off" | "known"}
                        Control how the dt_cpu_ftrs device-tree binding is
                        used for CPU feature discovery and setup (if it
                        Documentation/admin-guide/dynamic-debug-howto.rst
                        for details.
 
-       early_ioremap_debug [KNL]
+       early_ioremap_debug [KNL,EARLY]
                        Enable debug messages in early_ioremap support. This
                        is useful for tracking down temporary early mappings
                        which are not unmapped.
 
-       earlycon=       [KNL] Output early console device and options.
+       earlycon=       [KNL,EARLY] Output early console device and options.
 
                        When used with no options, the early console is
                        determined by stdout-path property in device tree's
                        address must be provided, and the serial port must
                        already be setup and configured.
 
-       earlyprintk=    [X86,SH,ARM,M68k,S390]
+       earlyprintk=    [X86,SH,ARM,M68k,S390,UM,EARLY]
                        earlyprintk=vga
                        earlyprintk=sclp
                        earlyprintk=xen
        edd=            [EDD]
                        Format: {"off" | "on" | "skip[mbr]"}
 
-       efi=            [EFI]
+       efi=            [EFI,EARLY]
                        Format: { "debug", "disable_early_pci_dma",
                                  "nochunk", "noruntime", "nosoftreserve",
                                  "novamap", "no_disable_early_pci_dma" }
                        no_disable_early_pci_dma: Leave the busmaster bit set
                        on all PCI bridges while in the EFI boot stub
 
-       efi_no_storage_paranoia [EFI; X86]
+       efi_no_storage_paranoia [EFI,X86,EARLY]
                        Using this parameter you can use more than 50% of
                        your efi variable storage. Use this parameter only if
                        you are really sure that your UEFI does sane gc and
                        fulfills the spec otherwise your board may brick.
 
-       efi_fake_mem=   nn[KMG]@ss[KMG]:aa[,nn[KMG]@ss[KMG]:aa,..] [EFI; X86]
+       efi_fake_mem=   nn[KMG]@ss[KMG]:aa[,nn[KMG]@ss[KMG]:aa,..] [EFI,X86,EARLY]
                        Add arbitrary attribute to specific memory range by
                        updating original EFI memory map.
                        Region of memory which aa attribute is added to is
        eisa_irq_edge=  [PARISC,HW]
                        See header of drivers/parisc/eisa.c.
 
-       ekgdboc=        [X86,KGDB] Allow early kernel console debugging
+       ekgdboc=        [X86,KGDB,EARLY] Allow early kernel console debugging
                        Format: ekgdboc=kbd
 
                        This is designed to be used in conjunction with
                        See comment before function elanfreq_setup() in
                        arch/x86/kernel/cpu/cpufreq/elanfreq.c.
 
-       elfcorehdr=[size[KMG]@]offset[KMG] [PPC,SH,X86,S390]
+       elfcorehdr=[size[KMG]@]offset[KMG] [PPC,SH,X86,S390,EARLY]
                        Specifies physical address of start of kernel core
                        image elf header and optionally the size. Generally
                        kexec loader will pass this option to capture kernel.
                        See Documentation/admin-guide/kdump/kdump.rst for details.
 
-       enable_mtrr_cleanup [X86]
+       enable_mtrr_cleanup [X86,EARLY]
                        The kernel tries to adjust MTRR layout from continuous
                        to discrete, to make X server driver able to add WB
                        entry later. This parameter enables that.
                        Permit 'security.evm' to be updated regardless of
                        current integrity status.
 
-       early_page_ext [KNL] Enforces page_ext initialization to earlier
+       early_page_ext [KNL,EARLY] Enforces page_ext initialization to earlier
                        stages so cover more early boot allocations.
                        Please note that as side effect some optimizations
                        might be disabled to achieve that (e.g. parallelized
                        Warning: use of this parameter will taint the kernel
                        and may cause unknown problems.
 
+       fred=           [X86-64]
+                       Enable/disable Flexible Return and Event Delivery.
+                       Format: { on | off }
+                       on: enable FRED when it's present.
+                       off: disable FRED, the default setting.
+
        ftrace=[tracer]
                        [FTRACE] will set and start the specified tracer
                        as early as possible in order to facilitate early
                        can be changed at run time by the max_graph_depth file
                        in the tracefs tracing directory. default: 0 (no limit)
 
-       fw_devlink=     [KNL] Create device links between consumer and supplier
+       fw_devlink=     [KNL,EARLY] Create device links between consumer and supplier
                        devices by scanning the firmware to infer the
                        consumer/supplier relationships. This feature is
                        especially useful when drivers are loaded as modules as
                        rpm --  Like "on", but also use to order runtime PM.
 
        fw_devlink.strict=<bool>
-                       [KNL] Treat all inferred dependencies as mandatory
+                       [KNL,EARLY] Treat all inferred dependencies as mandatory
                        dependencies. This only applies for fw_devlink=on|rpm.
                        Format: <bool>
 
        fw_devlink.sync_state =
-                       [KNL] When all devices that could probe have finished
+                       [KNL,EARLY] When all devices that could probe have finished
                        probing, this parameter controls what to do with
                        devices that haven't yet received their sync_state()
                        calls.
 
        gamma=          [HW,DRM]
 
-       gart_fix_e820=  [X86-64] disable the fix e820 for K8 GART
+       gart_fix_e820=  [X86-64,EARLY] disable the fix e820 for K8 GART
                        Format: off | on
                        default: on
 
        gather_data_sampling=
-                       [X86,INTEL] Control the Gather Data Sampling (GDS)
+                       [X86,INTEL,EARLY] Control the Gather Data Sampling (GDS)
                        mitigation.
 
                        Gather Data Sampling is a hardware vulnerability which
                                (that will set all pages holding image data
                                during restoration read-only).
 
-       highmem=nn[KMG] [KNL,BOOT] forces the highmem zone to have an exact
+       highmem=nn[KMG] [KNL,BOOT,EARLY] forces the highmem zone to have an exact
                        size of <nn>. This works even on boxes that have no
                        highmem otherwise. This also works to reduce highmem
                        size on bigger boxes.
 
        hlt             [BUGS=ARM,SH]
 
-       hostname=       [KNL] Set the hostname (aka UTS nodename).
+       hostname=       [KNL,EARLY] Set the hostname (aka UTS nodename).
                        Format: <string>
                        This allows setting the system's hostname during early
                        startup. This sets the name returned by gethostname.
                        Documentation/admin-guide/mm/hugetlbpage.rst.
                        Format: size[KMG]
 
-       hugetlb_cma=    [HW,CMA] The size of a CMA area used for allocation
+       hugetlb_cma=    [HW,CMA,EARLY] The size of a CMA area used for allocation
                        of gigantic hugepages. Or using node format, the size
                        of a CMA area per node can be specified.
                        Format: nn[KMGTPE] or (node format)
                                If specified, z/VM IUCV HVC accepts connections
                                from listed z/VM user IDs only.
 
-       hv_nopvspin     [X86,HYPER_V] Disables the paravirt spinlock optimizations
-                                     which allow the hypervisor to 'idle' the
-                                     guest on lock contention.
+       hv_nopvspin     [X86,HYPER_V,EARLY]
+                       Disables the paravirt spinlock optimizations
+                       which allow the hypervisor to 'idle' the guest
+                       on lock contention.
 
        i2c_bus=        [HW]    Override the default board specific I2C bus speed
                                or register an additional I2C bus that is not
                        Format: <io>[,<membase>[,<icn_id>[,<icn_id2>]]]
 
 
-       idle=           [X86]
+       idle=           [X86,EARLY]
                        Format: idle=poll, idle=halt, idle=nomwait
                        Poll forces a polling idle loop that can slightly
                        improve the performance of waking up a idle CPU, but
                        mode generally follows that for the NaN encoding,
                        except where unsupported by hardware.
 
-       ignore_loglevel [KNL]
+       ignore_loglevel [KNL,EARLY]
                        Ignore loglevel setting - this will print /all/
                        kernel messages to the console. Useful for debugging.
                        We also add it as printk module parameter, so users
                        unpacking being completed before device_ and
                        late_ initcalls.
 
-       initrd=         [BOOT] Specify the location of the initial ramdisk
+       initrd=         [BOOT,EARLY] Specify the location of the initial ramdisk
 
-       initrdmem=      [KNL] Specify a physical address and size from which to
+       initrdmem=      [KNL,EARLY] Specify a physical address and size from which to
                        load the initrd. If an initrd is compiled in or
                        specified in the bootparams, it takes priority over this
                        setting.
                        Format: ss[KMG],nn[KMG]
                        Default is 0, 0
 
-       init_on_alloc=  [MM] Fill newly allocated pages and heap objects with
+       init_on_alloc=  [MM,EARLY] Fill newly allocated pages and heap objects with
                        zeroes.
                        Format: 0 | 1
                        Default set by CONFIG_INIT_ON_ALLOC_DEFAULT_ON.
 
-       init_on_free=   [MM] Fill freed pages and heap objects with zeroes.
+       init_on_free=   [MM,EARLY] Fill freed pages and heap objects with zeroes.
                        Format: 0 | 1
                        Default set by CONFIG_INIT_ON_FREE_DEFAULT_ON.
 
                        0       disables intel_idle and fall back on acpi_idle.
                        1 to 9  specify maximum depth of C-state.
 
-       intel_pstate=   [X86]
+       intel_pstate=   [X86,EARLY]
                        disable
                          Do not enable intel_pstate as the default
                          scaling driver for the supported processors
                          Allow per-logical-CPU P-State performance control limits using
                          cpufreq sysfs interface
 
-       intremap=       [X86-64, Intel-IOMMU]
+       intremap=       [X86-64,Intel-IOMMU,EARLY]
                        on      enable Interrupt Remapping (default)
                        off     disable Interrupt Remapping
                        nosid   disable Source ID checking
                strict  regions from userspace.
                relaxed
 
-       iommu=          [X86]
+       iommu=          [X86,EARLY]
                off
                force
                noforce
                nobypass        [PPC/POWERNV]
                        Disable IOMMU bypass, using IOMMU for PCI devices.
 
-       iommu.forcedac= [ARM64, X86] Control IOVA allocation for PCI devices.
+       iommu.forcedac= [ARM64,X86,EARLY] Control IOVA allocation for PCI devices.
                        Format: { "0" | "1" }
                        0 - Try to allocate a 32-bit DMA address first, before
                          falling back to the full range if needed.
                          forcing Dual Address Cycle for PCI cards supporting
                          greater than 32-bit addressing.
 
-       iommu.strict=   [ARM64, X86, S390] Configure TLB invalidation behaviour
+       iommu.strict=   [ARM64,X86,S390,EARLY] Configure TLB invalidation behaviour
                        Format: { "0" | "1" }
                        0 - Lazy mode.
                          Request that DMA unmap operations use deferred
                        legacy driver-specific options takes precedence.
 
        iommu.passthrough=
-                       [ARM64, X86] Configure DMA to bypass the IOMMU by default.
+                       [ARM64,X86,EARLY] Configure DMA to bypass the IOMMU by default.
                        Format: { "0" | "1" }
                        0 - Use IOMMU translation for DMA.
                        1 - Bypass the IOMMU for DMA.
                        See comment before marvel_specify_io7 in
                        arch/alpha/kernel/core_marvel.c.
 
-       io_delay=       [X86] I/O delay method
+       io_delay=       [X86,EARLY] I/O delay method
                0x80
                        Standard port 0x80 based delay
                0xed
        ip=             [IP_PNP]
                        See Documentation/admin-guide/nfs/nfsroot.rst.
 
-       ipcmni_extend   [KNL] Extend the maximum number of unique System V
+       ipcmni_extend   [KNL,EARLY] Extend the maximum number of unique System V
                        IPC identifiers from 32,768 to 16,777,216.
 
        irqaffinity=    [SMP] Set the default irq affinity mask
                        The argument is a cpu list, as described above.
 
        irqchip.gicv2_force_probe=
-                       [ARM, ARM64]
+                       [ARM,ARM64,EARLY]
                        Format: <bool>
                        Force the kernel to look for the second 4kB page
                        of a GICv2 controller even if the memory range
                        exposed by the device tree is too small.
 
        irqchip.gicv3_nolpi=
-                       [ARM, ARM64]
+                       [ARM,ARM64,EARLY]
                        Force the kernel to ignore the availability of
                        LPIs (and by consequence ITSs). Intended for system
                        that use the kernel as a bootloader, and thus want
                        to let secondary kernels in charge of setting up
                        LPIs.
 
-       irqchip.gicv3_pseudo_nmi= [ARM64]
+       irqchip.gicv3_pseudo_nmi= [ARM64,EARLY]
                        Enables support for pseudo-NMIs in the kernel. This
                        requires the kernel to be built with
                        CONFIG_ARM64_PSEUDO_NMI.
                        parameter KASAN will print report only for the first
                        invalid access.
 
-       keep_bootcon    [KNL]
+       keep_bootcon    [KNL,EARLY]
                        Do not unregister boot console at start. This is only
                        useful for debugging when something happens in the window
                        between unregistering the boot console and initializing
 
        keepinitrd      [HW,ARM] See retain_initrd.
 
-       kernelcore=     [KNL,X86,IA-64,PPC]
+       kernelcore=     [KNL,X86,IA-64,PPC,EARLY]
                        Format: nn[KMGTPE] | nn% | "mirror"
                        This parameter specifies the amount of memory usable by
                        the kernel for non-movable allocations.  The requested
                        for Movable pages.  "nn[KMGTPE]", "nn%", and "mirror"
                        are exclusive, so you cannot specify multiple forms.
 
-       kgdbdbgp=       [KGDB,HW] kgdb over EHCI usb debug port.
+       kgdbdbgp=       [KGDB,HW,EARLY] kgdb over EHCI usb debug port.
                        Format: <Controller#>[,poll interval]
                        The controller # is the number of the ehci usb debug
                        port as it is probed via PCI.  The poll interval is
                         kms, kbd format: kms,kbd
                         kms, kbd and serial format: kms,kbd,<ser_dev>[,baud]
 
-       kgdboc_earlycon=        [KGDB,HW]
+       kgdboc_earlycon=        [KGDB,HW,EARLY]
                        If the boot console provides the ability to read
                        characters and can work in polling mode, you can use
                        this parameter to tell kgdb to use it as a backend
                        blank and the first boot console that implements
                        read() will be picked.
 
-       kgdbwait        [KGDB] Stop kernel execution and enter the
+       kgdbwait        [KGDB,EARLY] Stop kernel execution and enter the
                        kernel debugger at the earliest opportunity.
 
        kmac=           [MIPS] Korina ethernet MAC address.
                        Configure the RouterBoard 532 series on-chip
                        Ethernet adapter MAC address.
 
-       kmemleak=       [KNL] Boot-time kmemleak enable/disable
+       kmemleak=       [KNL,EARLY] Boot-time kmemleak enable/disable
                        Valid arguments: on, off
                        Default: on
                        Built with CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y,
                        See also Documentation/trace/kprobetrace.rst "Kernel
                        Boot Parameter" section.
 
-       kpti=           [ARM64] Control page table isolation of user
-                       and kernel address spaces.
+       kpti=           [ARM64,EARLY] Control page table isolation of
+                       user and kernel address spaces.
                        Default: enabled on cores which need mitigation.
                        0: force disabled
                        1: force enabled
                        for NPT.
 
        kvm-arm.mode=
-                       [KVM,ARM] Select one of KVM/arm64's modes of operation.
+                       [KVM,ARM,EARLY] Select one of KVM/arm64's modes of
+                       operation.
 
                        none: Forcefully disable KVM.
 
                        used with extreme caution.
 
        kvm-arm.vgic_v3_group0_trap=
-                       [KVM,ARM] Trap guest accesses to GICv3 group-0
+                       [KVM,ARM,EARLY] Trap guest accesses to GICv3 group-0
                        system registers
 
        kvm-arm.vgic_v3_group1_trap=
-                       [KVM,ARM] Trap guest accesses to GICv3 group-1
+                       [KVM,ARM,EARLY] Trap guest accesses to GICv3 group-1
                        system registers
 
        kvm-arm.vgic_v3_common_trap=
-                       [KVM,ARM] Trap guest accesses to GICv3 common
+                       [KVM,ARM,EARLY] Trap guest accesses to GICv3 common
                        system registers
 
        kvm-arm.vgic_v4_enable=
-                       [KVM,ARM] Allow use of GICv4 for direct injection of
-                       LPIs.
+                       [KVM,ARM,EARLY] Allow use of GICv4 for direct
+                       injection of LPIs.
 
-       kvm_cma_resv_ratio=n [PPC]
+       kvm_cma_resv_ratio=n [PPC,EARLY]
                        Reserves given percentage from system memory area for
                        contiguous memory allocation for KVM hash pagetable
                        allocation.
                        (enabled). Disable by KVM if hardware lacks support
                        for it.
 
-       l1d_flush=      [X86,INTEL]
+       l1d_flush=      [X86,INTEL,EARLY]
                        Control mitigation for L1D based snooping vulnerability.
 
                        Certain CPUs are vulnerable to an exploit against CPU
 
                        on         - enable the interface for the mitigation
 
-       l1tf=           [X86] Control mitigation of the L1TF vulnerability on
+       l1tf=           [X86,EARLY] Control mitigation of the L1TF vulnerability on
                              affected CPUs
 
                        The kernel PTE inversion protection is unconditionally
 
        l3cr=           [PPC]
 
-       lapic           [X86-32,APIC] Enable the local APIC even if BIOS
+       lapic           [X86-32,APIC,EARLY] Enable the local APIC even if BIOS
                        disabled it.
 
        lapic=          [X86,APIC] Do not use TSC deadline
                        back to the programmable timer unit in the LAPIC.
                        Format: notscdeadline
 
-       lapic_timer_c2_ok       [X86,APIC] trust the local apic timer
+       lapic_timer_c2_ok       [X86,APIC,EARLY] trust the local apic timer
                        in C2 power state.
 
        libata.dma=     [LIBATA] DMA control
        lockd.nlm_udpport=M     [NFS] Assign UDP port.
                        Format: <integer>
 
-       lockdown=       [SECURITY]
+       lockdown=       [SECURITY,EARLY]
                        { integrity | confidentiality }
                        Enable the kernel lockdown feature. If set to
                        integrity, kernel features that allow userland to
        logibm.irq=     [HW,MOUSE] Logitech Bus Mouse Driver
                        Format: <irq>
 
-       loglevel=       All Kernel Messages with a loglevel smaller than the
+       loglevel=       [KNL,EARLY]
+                       All Kernel Messages with a loglevel smaller than the
                        console loglevel will be printed to the console. It can
                        also be changed with klogd or other programs. The
                        loglevels are defined as follows:
                        6 (KERN_INFO)           informational
                        7 (KERN_DEBUG)          debug-level messages
 
-       log_buf_len=n[KMG]      Sets the size of the printk ring buffer,
-                       in bytes.  n must be a power of two and greater
-                       than the minimal size. The minimal size is defined
-                       by LOG_BUF_SHIFT kernel config parameter. There is
-                       also CONFIG_LOG_CPU_MAX_BUF_SHIFT config parameter
-                       that allows to increase the default size depending on
-                       the number of CPUs. See init/Kconfig for more details.
+       log_buf_len=n[KMG] [KNL,EARLY]
+                       Sets the size of the printk ring buffer, in bytes.
+                       n must be a power of two and greater than the
+                       minimal size. The minimal size is defined by
+                       LOG_BUF_SHIFT kernel config parameter. There
+                       is also CONFIG_LOG_CPU_MAX_BUF_SHIFT config
+                       parameter that allows to increase the default size
+                       depending on the number of CPUs. See init/Kconfig
+                       for more details.
 
        logo.nologo     [FB] Disables display of the built-in Linux logo.
                        This may be used to provide more screen space for
        max_addr=nn[KMG]        [KNL,BOOT,IA-64] All physical memory greater
                        than or equal to this physical address is ignored.
 
-       maxcpus=        [SMP] Maximum number of processors that an SMP kernel
+       maxcpus=        [SMP,EARLY] Maximum number of processors that an SMP kernel
                        will bring up during bootup.  maxcpus=n : n >= 0 limits
                        the kernel to bring up 'n' processors. Surely after
                        bootup you can bring up the other plugged cpu by executing
                        Format: <first>,<last>
                        Specifies range of consoles to be captured by the MDA.
 
-       mds=            [X86,INTEL]
+       mds=            [X86,INTEL,EARLY]
                        Control mitigation for the Micro-architectural Data
                        Sampling (MDS) vulnerability.
 
 
                        For details see: Documentation/admin-guide/hw-vuln/mds.rst
 
-       mem=nn[KMG]     [HEXAGON] Set the memory size.
+       mem=nn[KMG]     [HEXAGON,EARLY] Set the memory size.
                        Must be specified, otherwise memory size will be 0.
 
-       mem=nn[KMG]     [KNL,BOOT] Force usage of a specific amount of memory
-                       Amount of memory to be used in cases as follows:
+       mem=nn[KMG]     [KNL,BOOT,EARLY] Force usage of a specific amount
+                       of memory Amount of memory to be used in cases
+                       as follows:
 
                        1 for test;
                        2 when the kernel is not able to see the whole system memory;
                        if system memory of hypervisor is not sufficient.
 
        mem=nn[KMG]@ss[KMG]
-                       [ARM,MIPS] - override the memory layout reported by
-                       firmware.
+                       [ARM,MIPS,EARLY] - override the memory layout
+                       reported by firmware.
                        Define a memory region of size nn[KMG] starting at
                        ss[KMG].
                        Multiple different regions can be specified with
        mem=nopentium   [BUGS=X86-32] Disable usage of 4MB pages for kernel
                        memory.
 
-       memblock=debug  [KNL] Enable memblock debug messages.
+       memblock=debug  [KNL,EARLY] Enable memblock debug messages.
 
        memchunk=nn[KMG]
                        [KNL,SH] Allow user to override the default size for
                        option.
                        See Documentation/admin-guide/mm/memory-hotplug.rst.
 
-       memmap=exactmap [KNL,X86] Enable setting of an exact
+       memmap=exactmap [KNL,X86,EARLY] Enable setting of an exact
                        E820 memory map, as specified by the user.
                        Such memmap=exactmap lines can be constructed based on
                        BIOS output or other requirements. See the memmap=nn@ss
                        option description.
 
        memmap=nn[KMG]@ss[KMG]
-                       [KNL, X86, MIPS, XTENSA] Force usage of a specific region of memory.
+                       [KNL, X86,MIPS,XTENSA,EARLY] Force usage of a specific region of memory.
                        Region of memory to be used is from ss to ss+nn.
                        If @ss[KMG] is omitted, it is equivalent to mem=nn[KMG],
                        which limits max address to nn[KMG].
                                memmap=100M@2G,100M#3G,1G!1024G
 
        memmap=nn[KMG]#ss[KMG]
-                       [KNL,ACPI] Mark specific memory as ACPI data.
+                       [KNL,ACPI,EARLY] Mark specific memory as ACPI data.
                        Region of memory to be marked is from ss to ss+nn.
 
        memmap=nn[KMG]$ss[KMG]
-                       [KNL,ACPI] Mark specific memory as reserved.
+                       [KNL,ACPI,EARLY] Mark specific memory as reserved.
                        Region of memory to be reserved is from ss to ss+nn.
                        Example: Exclude memory from 0x18690000-0x1869ffff
                                 memmap=64K$0x18690000
                        like Grub2, otherwise '$' and the following number
                        will be eaten.
 
-       memmap=nn[KMG]!ss[KMG]
+       memmap=nn[KMG]!ss[KMG,EARLY]
                        [KNL,X86] Mark specific memory as protected.
                        Region of memory to be used, from ss to ss+nn.
                        The memory region may be marked as e820 type 12 (0xc)
                        and is NVDIMM or ADR memory.
 
        memmap=<size>%<offset>-<oldtype>+<newtype>
-                       [KNL,ACPI] Convert memory within the specified region
+                       [KNL,ACPI,EARLY] Convert memory within the specified region
                        from <oldtype> to <newtype>. If "-<oldtype>" is left
                        out, the whole region will be marked as <newtype>,
                        even if previously unavailable. If "+<newtype>" is left
                        specified as e820 types, e.g., 1 = RAM, 2 = reserved,
                        3 = ACPI, 12 = PRAM.
 
-       memory_corruption_check=0/1 [X86]
+       memory_corruption_check=0/1 [X86,EARLY]
                        Some BIOSes seem to corrupt the first 64k of
                        memory when doing things like suspend/resume.
                        Setting this option will scan the memory
                        affects the same memory, you can use memmap=
                        to prevent the kernel from using that memory.
 
-       memory_corruption_check_size=size [X86]
+       memory_corruption_check_size=size [X86,EARLY]
                        By default it checks for corruption in the low
                        64k, making this memory unavailable for normal
                        use.  Use this parameter to scan for
                        corruption in more or less memory.
 
-       memory_corruption_check_period=seconds [X86]
+       memory_corruption_check_period=seconds [X86,EARLY]
                        By default it checks for corruption every 60
                        seconds.  Use this parameter to check at some
                        other rate.  0 disables periodic checking.
                        Note that even when enabled, there are a few cases where
                        the feature is not effective.
 
-       memtest=        [KNL,X86,ARM,M68K,PPC,RISCV] Enable memtest
+       memtest=        [KNL,X86,ARM,M68K,PPC,RISCV,EARLY] Enable memtest
                        Format: <integer>
                        default : 0 <disable>
                        Specifies the number of memtest passes to be
 
        mem_encrypt=    [X86-64] AMD Secure Memory Encryption (SME) control
                        Valid arguments: on, off
-                       Default (depends on kernel configuration option):
-                         on  (CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT=y)
-                         off (CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT=n)
+                       Default: off
                        mem_encrypt=on:         Activate SME
                        mem_encrypt=off:        Do not activate SME
 
                        https://repo.or.cz/w/linux-2.6/mini2440.git
 
        mitigations=
-                       [X86,PPC,S390,ARM64] Control optional mitigations for
+                       [X86,PPC,S390,ARM64,EARLY] Control optional mitigations for
                        CPU vulnerabilities.  This is a set of curated,
                        arch-independent options, each of which is an
                        aggregation of existing arch-specific options.
                                               nospectre_bhb [ARM64]
                                               nospectre_v1 [X86,PPC]
                                               nospectre_v2 [X86,PPC,S390,ARM64]
+                                              reg_file_data_sampling=off [X86]
                                               retbleed=off [X86]
+                                              spec_rstack_overflow=off [X86]
                                               spec_store_bypass_disable=off [X86,PPC]
                                               spectre_v2_user=off [X86]
                                               srbds=off [X86,INTEL]
                                               retbleed=auto,nosmt [X86]
 
        mminit_loglevel=
-                       [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this
+                       [KNL,EARLY] When CONFIG_DEBUG_MEMORY_INIT is set, this
                        parameter allows control of the logging verbosity for
                        the additional memory initialisation checks. A value
                        of 0 disables mminit logging and a level of 4 will
                        so loglevel=8 may also need to be specified.
 
        mmio_stale_data=
-                       [X86,INTEL] Control mitigation for the Processor
+                       [X86,INTEL,EARLY] Control mitigation for the Processor
                        MMIO Stale Data vulnerabilities.
 
                        Processor MMIO Stale Data is a class of
        mousedev.yres=  [MOUSE] Vertical screen resolution, used for devices
                        reporting absolute coordinates, such as tablets
 
-       movablecore=    [KNL,X86,IA-64,PPC]
+       movablecore=    [KNL,X86,IA-64,PPC,EARLY]
                        Format: nn[KMGTPE] | nn%
                        This parameter is the complement to kernelcore=, it
                        specifies the amount of memory used for migratable
                        that the amount of memory usable for all allocations
                        is not too small.
 
-       movable_node    [KNL] Boot-time switch to make hotplugable memory
+       movable_node    [KNL,EARLY] Boot-time switch to make hotplugable memory
                        NUMA nodes to be movable. This means that the memory
                        of such nodes will be usable only for movable
                        allocations which rules out almost all kernel
                        [HW] Make the MicroTouch USB driver use raw coordinates
                        ('y', default) or cooked coordinates ('n')
 
-       mtrr=debug      [X86]
+       mtrr=debug      [X86,EARLY]
                        Enable printing debug information related to MTRR
                        registers at boot time.
 
-       mtrr_chunk_size=nn[KMG] [X86]
+       mtrr_chunk_size=nn[KMG,X86,EARLY]
                        used for mtrr cleanup. It is largest continuous chunk
                        that could hold holes aka. UC entries.
 
-       mtrr_gran_size=nn[KMG] [X86]
+       mtrr_gran_size=nn[KMG,X86,EARLY]
                        Used for mtrr cleanup. It is granularity of mtrr block.
                        Default is 1.
                        Large value could prevent small alignment from
                        using up MTRRs.
 
-       mtrr_spare_reg_nr=n [X86]
+       mtrr_spare_reg_nr=n [X86,EARLY]
                        Format: <integer>
                        Range: 0,7 : spare reg number
                        Default : 1
                        emulation library even if a 387 maths coprocessor
                        is present.
 
-       no4lvl          [RISCV] Disable 4-level and 5-level paging modes. Forces
-                       kernel to use 3-level paging instead.
+       no4lvl          [RISCV,EARLY] Disable 4-level and 5-level paging modes.
+                       Forces kernel to use 3-level paging instead.
 
-       no5lvl          [X86-64,RISCV] Disable 5-level paging mode. Forces
+       no5lvl          [X86-64,RISCV,EARLY] Disable 5-level paging mode. Forces
                        kernel to use 4-level paging instead.
 
        noaliencache    [MM, NUMA, SLAB] Disables the allocation of alien
 
        noalign         [KNL,ARM]
 
-       noaltinstr      [S390] Disables alternative instructions patching
-                       (CPU alternatives feature).
+       noaltinstr      [S390,EARLY] Disables alternative instructions
+                       patching (CPU alternatives feature).
 
-       noapic          [SMP,APIC] Tells the kernel to not make use of any
+       noapic          [SMP,APIC,EARLY] Tells the kernel to not make use of any
                        IOAPICs that may be present in the system.
 
        noautogroup     Disable scheduler automatic task group creation.
 
-       nocache         [ARM]
+       nocache         [ARM,EARLY]
 
        no_console_suspend
                        [HW] Never suspend the console
                        turn on/off it dynamically.
 
        no_debug_objects
-                       [KNL] Disable object debugging
+                       [KNL,EARLY] Disable object debugging
 
        nodsp           [SH] Disable hardware DSP at boot time.
 
-       noefi           Disable EFI runtime services support.
+       noefi           [EFI,EARLY] Disable EFI runtime services support.
 
-       no_entry_flush  [PPC] Don't flush the L1-D cache when entering the kernel.
+       no_entry_flush  [PPC,EARLY] Don't flush the L1-D cache when entering the kernel.
 
        noexec          [IA-64]
 
                        real-time systems.
 
        no_hash_pointers
+                       [KNL,EARLY]
                        Force pointers printed to the console or buffers to be
                        unhashed.  By default, when a pointer is printed via %p
                        format string, that pointer is "hashed", i.e. obscured
                        the impact of the sleep instructions. This is also
                        useful when using JTAG debugger.
 
-       nohugeiomap     [KNL,X86,PPC,ARM64] Disable kernel huge I/O mappings.
+       nohugeiomap     [KNL,X86,PPC,ARM64,EARLY] Disable kernel huge I/O mappings.
 
-       nohugevmalloc   [KNL,X86,PPC,ARM64] Disable kernel huge vmalloc mappings.
+       nohugevmalloc   [KNL,X86,PPC,ARM64,EARLY] Disable kernel huge vmalloc mappings.
 
        nohz=           [KNL] Boottime enable/disable dynamic ticks
                        Valid arguments: on, off
        noinitrd        [RAM] Tells the kernel not to load any configured
                        initial RAM disk.
 
-       nointremap      [X86-64, Intel-IOMMU] Do not enable interrupt
+       nointremap      [X86-64,Intel-IOMMU,EARLY] Do not enable interrupt
                        remapping.
                        [Deprecated - use intremap=off]
 
        nointroute      [IA-64]
 
-       noinvpcid       [X86] Disable the INVPCID cpu feature.
+       noinvpcid       [X86,EARLY] Disable the INVPCID cpu feature.
 
        noiotrap        [SH] Disables trapped I/O port accesses.
 
 
        nojitter        [IA-64] Disables jitter checking for ITC timers.
 
-       nokaslr         [KNL]
+       nokaslr         [KNL,EARLY]
                        When CONFIG_RANDOMIZE_BASE is set, this disables
                        kernel and module base offset ASLR (Address Space
                        Layout Randomization).
 
-       no-kvmapf       [X86,KVM] Disable paravirtualized asynchronous page
+       no-kvmapf       [X86,KVM,EARLY] Disable paravirtualized asynchronous page
                        fault handling.
 
-       no-kvmclock     [X86,KVM] Disable paravirtualized KVM clock driver
+       no-kvmclock     [X86,KVM,EARLY] Disable paravirtualized KVM clock driver
 
-       nolapic         [X86-32,APIC] Do not enable or use the local APIC.
+       nolapic         [X86-32,APIC,EARLY] Do not enable or use the local APIC.
 
-       nolapic_timer   [X86-32,APIC] Do not use the local APIC timer.
+       nolapic_timer   [X86-32,APIC,EARLY] Do not use the local APIC timer.
 
        nomca           [IA-64] Disable machine check abort handling
 
                        shutdown the other cpus.  Instead use the REBOOT_VECTOR
                        irq.
 
-       nopat           [X86] Disable PAT (page attribute table extension of
+       nopat           [X86,EARLY] Disable PAT (page attribute table extension of
                        pagetables) support.
 
-       nopcid          [X86-64] Disable the PCID cpu feature.
+       nopcid          [X86-64,EARLY] Disable the PCID cpu feature.
 
        nopku           [X86] Disable Memory Protection Keys CPU feature found
                        in some Intel CPUs.
 
-       nopti           [X86-64]
+       nopti           [X86-64,EARLY]
                        Equivalent to pti=off
 
-       nopv=           [X86,XEN,KVM,HYPER_V,VMWARE]
+       nopv=           [X86,XEN,KVM,HYPER_V,VMWARE,EARLY]
                        Disables the PV optimizations forcing the guest to run
                        as generic guest with no PV drivers. Currently support
                        XEN HVM, KVM, HYPER_V and VMWARE guest.
 
-       nopvspin        [X86,XEN,KVM]
+       nopvspin        [X86,XEN,KVM,EARLY]
                        Disables the qspinlock slow path using PV optimizations
                        which allow the hypervisor to 'idle' the guest on lock
                        contention.
                        This is required for the Braillex ib80-piezo Braille
                        reader made by F.H. Papenmeier (Germany).
 
-       nosgx           [X86-64,SGX] Disables Intel SGX kernel support.
+       nosgx           [X86-64,SGX,EARLY] Disables Intel SGX kernel support.
 
-       nosmap          [PPC]
+       nosmap          [PPC,EARLY]
                        Disable SMAP (Supervisor Mode Access Prevention)
                        even if it is supported by processor.
 
-       nosmep          [PPC64s]
+       nosmep          [PPC64s,EARLY]
                        Disable SMEP (Supervisor Mode Execution Prevention)
                        even if it is supported by processor.
 
-       nosmp           [SMP] Tells an SMP kernel to act as a UP kernel,
+       nosmp           [SMP,EARLY] Tells an SMP kernel to act as a UP kernel,
                        and disable the IO APIC.  legacy for "maxcpus=0".
 
-       nosmt           [KNL,MIPS,PPC,S390] Disable symmetric multithreading (SMT).
+       nosmt           [KNL,MIPS,PPC,S390,EARLY] Disable symmetric multithreading (SMT).
                        Equivalent to smt=1.
 
                        [KNL,X86,PPC] Disable symmetric multithreading (SMT).
        nosoftlockup    [KNL] Disable the soft-lockup detector.
 
        nospec_store_bypass_disable
-                       [HW] Disable all mitigations for the Speculative Store Bypass vulnerability
+                       [HW,EARLY] Disable all mitigations for the Speculative
+                       Store Bypass vulnerability
 
-       nospectre_bhb   [ARM64] Disable all mitigations for Spectre-BHB (branch
+       nospectre_bhb   [ARM64,EARLY] Disable all mitigations for Spectre-BHB (branch
                        history injection) vulnerability. System may allow data leaks
                        with this option.
 
-       nospectre_v1    [X86,PPC] Disable mitigations for Spectre Variant 1
+       nospectre_v1    [X86,PPC,EARLY] Disable mitigations for Spectre Variant 1
                        (bounds check bypass). With this option data leaks are
                        possible in the system.
 
-       nospectre_v2    [X86,PPC_E500,ARM64] Disable all mitigations for
-                       the Spectre variant 2 (indirect branch prediction)
-                       vulnerability. System may allow data leaks with this
-                       option.
+       nospectre_v2    [X86,PPC_E500,ARM64,EARLY] Disable all mitigations
+                       for the Spectre variant 2 (indirect branch
+                       prediction) vulnerability. System may allow data
+                       leaks with this option.
 
-       no-steal-acc    [X86,PV_OPS,ARM64,PPC/PSERIES,RISCV] Disable
+       no-steal-acc    [X86,PV_OPS,ARM64,PPC/PSERIES,RISCV,EARLY] Disable
                        paravirtualized steal time accounting. steal time is
                        computed, but won't influence scheduler behaviour
 
                        broken timer IRQ sources.
 
        no_uaccess_flush
-                       [PPC] Don't flush the L1-D cache after accessing user data.
+                       [PPC,EARLY] Don't flush the L1-D cache after accessing user data.
 
        novmcoredd      [KNL,KDUMP]
                        Disable device dump. Device dump allows drivers to
                        is set.
 
        no-vmw-sched-clock
-                       [X86,PV_OPS] Disable paravirtualized VMware scheduler
-                       clock and use the default one.
+                       [X86,PV_OPS,EARLY] Disable paravirtualized VMware
+                       scheduler clock and use the default one.
 
        nowatchdog      [KNL] Disable both lockup detectors, i.e.
                        soft-lockup and NMI watchdog (hard-lockup).
 
-       nowb            [ARM]
+       nowb            [ARM,EARLY]
 
-       nox2apic        [X86-64,APIC] Do not enable x2APIC mode.
+       nox2apic        [X86-64,APIC,EARLY] Do not enable x2APIC mode.
 
                        NOTE: this parameter will be ignored on systems with the
                        LEGACY_XAPIC_DISABLED bit set in the
                        purges which is reported from either PAL_VM_SUMMARY or
                        SAL PALO.
 
-       nr_cpus=        [SMP] Maximum number of processors that an SMP kernel
+       nr_cpus=        [SMP,EARLY] Maximum number of processors that an SMP kernel
                        could support.  nr_cpus=n : n >= 1 limits the kernel to
                        support 'n' processors. It could be larger than the
                        number of already plugged CPU during bootup, later in
 
        nr_uarts=       [SERIAL] maximum number of UARTs to be registered.
 
-       numa=off        [KNL, ARM64, PPC, RISCV, SPARC, X86] Disable NUMA, Only
-                       set up a single NUMA node spanning all memory.
+       numa=off        [KNL, ARM64, PPC, RISCV, SPARC, X86, EARLY]
+                       Disable NUMA, Only set up a single NUMA node
+                       spanning all memory.
 
        numa_balancing= [KNL,ARM64,PPC,RISCV,S390,X86] Enable or disable automatic
                        NUMA balancing.
                        This can be set from sysctl after boot.
                        See Documentation/admin-guide/sysctl/vm.rst for details.
 
-       ohci1394_dma=early      [HW] enable debugging via the ohci1394 driver.
+       ohci1394_dma=early      [HW,EARLY] enable debugging via the ohci1394 driver.
                        See Documentation/core-api/debugging-via-ohci1394.rst for more
                        info.
 
                                   Once locked, the boundary cannot be changed.
                                   1 indicates lock status, 0 indicates unlock status.
 
-       oops=panic      Always panic on oopses. Default is to just kill the
+       oops=panic      [KNL,EARLY]
+                       Always panic on oopses. Default is to just kill the
                        process, but there is a small probability of
                        deadlocking the machine.
                        This will also cause panics on machine check exceptions.
                        can be read from sysfs at:
                        /sys/module/page_alloc/parameters/shuffle.
 
-       page_owner=     [KNL] Boot-time page_owner enabling option.
+       page_owner=     [KNL,EARLY] Boot-time page_owner enabling option.
                        Storage of the information about who allocated
                        each page is disabled in default. With this switch,
                        we can turn it on.
                        on: enable the feature
 
-       page_poison=    [KNL] Boot-time parameter changing the state of
+       page_poison=    [KNL,EARLY] Boot-time parameter changing the state of
                        poisoning on the buddy allocator, available with
                        CONFIG_PAGE_POISONING=y.
                        off: turn off poisoning (default)
                        timeout < 0: reboot immediately
                        Format: <timeout>
 
-       panic_on_taint= Bitmask for conditionally calling panic() in add_taint()
+       panic_on_taint= [KNL,EARLY]
+                       Bitmask for conditionally calling panic() in add_taint()
                        Format: <hex>[,nousertaint]
                        Hexadecimal bitmask representing the set of TAINT flags
                        that will cause the kernel to panic when add_taint() is
 
        pcbit=          [HW,ISDN]
 
-       pci=option[,option...]  [PCI] various PCI subsystem options.
+       pci=option[,option...]  [PCI,EARLY] various PCI subsystem options.
 
                                Some options herein operate on a specific device
                                or a set of devices (<pci_dev>). These are
                        Format: { 0 | 1 }
                        See arch/parisc/kernel/pdc_chassis.c
 
-       percpu_alloc=   Select which percpu first chunk allocator to use.
+       percpu_alloc=   [MM,EARLY]
+                       Select which percpu first chunk allocator to use.
                        Currently supported values are "embed" and "page".
                        Archs may support subset or none of the selections.
                        See comments in mm/percpu.c for details on each
                        execution priority.
 
        ppc_strict_facility_enable
-                       [PPC] This option catches any kernel floating point,
+                       [PPC,ENABLE] This option catches any kernel floating point,
                        Altivec, VSX and SPE outside of regions specifically
                        allowed (eg kernel_enable_fpu()/kernel_disable_fpu()).
                        There is some performance impact when enabling this.
 
-       ppc_tm=         [PPC]
+       ppc_tm=         [PPC,EARLY]
                        Format: {"off"}
                        Disable Hardware Transactional Memory
 
                        [KNL] Number of legacy pty's. Overwrites compiled-in
                        default number.
 
-       quiet           [KNL] Disable most log messages
+       quiet           [KNL,EARLY] Disable most log messages
 
        r128=           [HW,DRM]
 
        ramdisk_start=  [RAM] RAM disk image start address
 
        random.trust_cpu=off
-                       [KNL] Disable trusting the use of the CPU's
+                       [KNL,EARLY] Disable trusting the use of the CPU's
                        random number generator (if available) to
                        initialize the kernel's RNG.
 
        random.trust_bootloader=off
-                       [KNL] Disable trusting the use of the a seed
+                       [KNL,EARLY] Disable trusting the use of the a seed
                        passed by the bootloader (if available) to
                        initialize the kernel's RNG.
 
        randomize_kstack_offset=
-                       [KNL] Enable or disable kernel stack offset
+                       [KNL,EARLY] Enable or disable kernel stack offset
                        randomization, which provides roughly 5 bits of
                        entropy, frustrating memory corruption attacks
                        that depend on stack address determinism or
                        this kernel boot parameter, forcibly setting it
                        to zero.
 
+       rcutree.enable_rcu_lazy= [KNL]
+                       To save power, batch RCU callbacks and flush after
+                       delay, memory pressure or callback list growing too
+                       big.
+
        rcuscale.gp_async= [KNL]
                        Measure performance of asynchronous
                        grace-period primitives such as call_rcu().
                        Run specified binary instead of /init from the ramdisk,
                        used for early userspace startup. See initrd.
 
-       rdrand=         [X86]
+       rdrand=         [X86,EARLY]
                        force - Override the decision by the kernel to hide the
                                advertisement of RDRAND support (this affects
                                certain AMD processors because of buggy BIOS
                        them.  If <base> is less than 0x10000, the region
                        is assumed to be I/O ports; otherwise it is memory.
 
-       reservetop=     [X86-32]
+       reservetop=     [X86-32,EARLY]
                        Format: nn[KMG]
                        Reserves a hole at the top of the kernel virtual
                        address space.
                        [KNL] Disable ring 3 MONITOR/MWAIT feature on supported
                        CPUs.
 
-       riscv_isa_fallback [RISCV]
+       riscv_isa_fallback [RISCV,EARLY]
                        When CONFIG_RISCV_ISA_FALLBACK is not enabled, permit
                        falling back to detecting extension support by parsing
                        "riscv,isa" property on devicetree systems when the
 
        ro              [KNL] Mount root device read-only on boot
 
-       rodata=         [KNL]
+       rodata=         [KNL,EARLY]
                on      Mark read-only kernel memory as read-only (default).
                off     Leave read-only kernel memory writable for debugging.
                full    Mark read-only kernel memory and aliases as read-only
                        [arm64]
 
        rockchip.usb_uart
+                       [EARLY]
                        Enable the uart passthrough on the designated usb port
                        on Rockchip SoCs. When active, the signals of the
                        debug-uart get routed to the D+ and D- pins of the usb
        sa1100ir        [NET]
                        See drivers/net/irda/sa1100_ir.c.
 
-       sched_verbose   [KNL] Enables verbose scheduler debug messages.
+       sched_verbose   [KNL,EARLY] Enables verbose scheduler debug messages.
 
        schedstats=     [KNL,X86] Enable or disable scheduled statistics.
                        Allowed values are enable and disable. This feature
                        non-zero "wait" parameter.  See weight_single
                        and weight_many.
 
-       skew_tick=      [KNL] Offset the periodic timer tick per cpu to mitigate
+       skew_tick=      [KNL,EARLY] Offset the periodic timer tick per cpu to mitigate
                        xtime_lock contention on larger systems, and/or RCU lock
                        contention on all systems with CONFIG_MAXSMP set.
                        Format: { "0" | "1" }
                                1: Fast pin select (default)
                                2: ATC IRMode
 
-       smt=            [KNL,MIPS,S390] Set the maximum number of threads (logical
-                       CPUs) to use per physical CPU on systems capable of
-                       symmetric multithreading (SMT). Will be capped to the
-                       actual hardware limit.
+       smt=            [KNL,MIPS,S390,EARLY] Set the maximum number of threads
+                       (logical CPUs) to use per physical CPU on systems
+                       capable of symmetric multithreading (SMT). Will
+                       be capped to the actual hardware limit.
                        Format: <integer>
                        Default: -1 (no limit)
 
        sonypi.*=       [HW] Sony Programmable I/O Control Device driver
                        See Documentation/admin-guide/laptops/sonypi.rst
 
-       spectre_v2=     [X86] Control mitigation of Spectre variant 2
+       spectre_v2=     [X86,EARLY] Control mitigation of Spectre variant 2
                        (indirect branch speculation) vulnerability.
                        The default operation protects the kernel from
                        user space attacks.
                        Selecting 'on' will, and 'auto' may, choose a
                        mitigation method at run time according to the
                        CPU, the available microcode, the setting of the
-                       CONFIG_RETPOLINE configuration option, and the
-                       compiler with which the kernel was built.
+                       CONFIG_MITIGATION_RETPOLINE configuration option,
+                       and the compiler with which the kernel was built.
 
                        Selecting 'on' will also enable the mitigation
                        against user space to user space task attacks.
                        spectre_v2_user=auto.
 
        spec_rstack_overflow=
-                       [X86] Control RAS overflow mitigation on AMD Zen CPUs
+                       [X86,EARLY] Control RAS overflow mitigation on AMD Zen CPUs
 
                        off             - Disable mitigation
                        microcode       - Enable microcode mitigation only
                                          (cloud-specific mitigation)
 
        spec_store_bypass_disable=
-                       [HW] Control Speculative Store Bypass (SSB) Disable mitigation
+                       [HW,EARLY] Control Speculative Store Bypass (SSB) Disable mitigation
                        (Speculative Store Bypass vulnerability)
 
                        Certain CPUs are vulnerable to an exploit against a
                        #DB exception for bus lock is triggered only when
                        CPL > 0.
 
-       srbds=          [X86,INTEL]
+       srbds=          [X86,INTEL,EARLY]
                        Control the Special Register Buffer Data Sampling
                        (SRBDS) mitigation.
 
                        srcutree.convert_to_big must have the 0x10 bit
                        set for contention-based conversions to occur.
 
-       ssbd=           [ARM64,HW]
+       ssbd=           [ARM64,HW,EARLY]
                        Speculative Store Bypass Disable control
 
                        On CPUs that are vulnerable to the Speculative
                        growing up) the main stack are reserved for no other
                        mapping. Default value is 256 pages.
 
-       stack_depot_disable= [KNL]
+       stack_depot_disable= [KNL,EARLY]
                        Setting this to true through kernel command line will
                        disable the stack depot thereby saving the static memory
                        consumed by the stack hash table. By default this is set
                        be used to filter out binaries which have
                        not yet been made aware of AT_MINSIGSTKSZ.
 
-       stress_hpt      [PPC]
+       stress_hpt      [PPC,EARLY]
                        Limits the number of kernel HPT entries in the hash
                        page table to increase the rate of hash page table
                        faults on kernel addresses.
 
-       stress_slb      [PPC]
+       stress_slb      [PPC,EARLY]
                        Limits the number of kernel SLB entries, and flushes
                        them frequently to increase the rate of SLB faults
                        on kernel addresses.
                        This parameter controls use of the Protected
                        Execution Facility on pSeries.
 
-       swiotlb=        [ARM,IA-64,PPC,MIPS,X86]
+       swiotlb=        [ARM,IA-64,PPC,MIPS,X86,EARLY]
                        Format: { <int> [,<int>] | force | noforce }
                        <int> -- Number of I/O TLB slabs
                        <int> -- Second integer after comma. Number of swiotlb
                                 wouldn't be automatically used by the kernel
                        noforce -- Never use bounce buffers (for debugging)
 
-       switches=       [HW,M68k]
+       switches=       [HW,M68k,EARLY]
 
        sysctl.*=       [KNL]
                        Set a sysctl parameter, right before loading the init
                        <deci-seconds>: poll all this frequency
                        0: no polling (default)
 
-       threadirqs      [KNL]
+       threadirqs      [KNL,EARLY]
                        Force threading of all interrupt handlers except those
                        marked explicitly IRQF_NO_THREAD.
 
-       topology=       [S390]
+       topology=       [S390,EARLY]
                        Format: {off | on}
                        Specify if the kernel should make use of the cpu
                        topology information if the hardware supports this.
                        can be overridden by a later tsc=nowatchdog.  A console
                        message will flag any such suppression or overriding.
 
-       tsc_early_khz=  [X86] Skip early TSC calibration and use the given
+       tsc_early_khz=  [X86,EARLY] Skip early TSC calibration and use the given
                        value instead. Useful when the early TSC frequency discovery
                        procedure is not reliable, such as on overclocked systems
                        with CPUID.16h support and partial CPUID.15h support.
                        See Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
                        for more details.
 
-       tsx_async_abort= [X86,INTEL] Control mitigation for the TSX Async
+       tsx_async_abort= [X86,INTEL,EARLY] Control mitigation for the TSX Async
                        Abort (TAA) vulnerability.
 
                        Similar to Micro-architectural Data Sampling (MDS)
        unknown_nmi_panic
                        [X86] Cause panic on unknown NMI.
 
-       unwind_debug    [X86-64]
+       unwind_debug    [X86-64,EARLY]
                        Enable unwinder debug output.  This can be
                        useful for debugging certain unwinder error
                        conditions, including corrupt stacks and
                        Example: user_debug=31
 
        userpte=
-                       [X86] Flags controlling user PTE allocations.
+                       [X86,EARLY] Flags controlling user PTE allocations.
 
                                nohigh = do not allocate PTE pages in
                                        HIGHMEM regardless of setting
        vector=         [IA-64,SMP]
                        vector=percpu: enable percpu vector domain
 
-       video=          [FB] Frame buffer configuration
+       video=          [FB,EARLY] Frame buffer configuration
                        See Documentation/fb/modedb.rst.
 
        video.brightness_switch_enabled= [ACPI]
                          P     Enable page structure init time poisoning
                          -     Disable all of the above options
 
-       vmalloc=nn[KMG] [KNL,BOOT] Forces the vmalloc area to have an exact
-                       size of <nn>. This can be used to increase the
-                       minimum size (128MB on x86). It can also be used to
-                       decrease the size and leave more room for directly
-                       mapped kernel RAM.
+       vmalloc=nn[KMG] [KNL,BOOT,EARLY] Forces the vmalloc area to have an
+                       exact size of <nn>. This can be used to increase
+                       the minimum size (128MB on x86). It can also be
+                       used to decrease the size and leave more room
+                       for directly mapped kernel RAM.
 
-       vmcp_cma=nn[MG] [KNL,S390]
+       vmcp_cma=nn[MG] [KNL,S390,EARLY]
                        Sets the memory size reserved for contiguous memory
                        allocations for the vmcp device driver.
 
        vmpoff=         [KNL,S390] Perform z/VM CP command after power off.
                        Format: <command>
 
-       vsyscall=       [X86-64]
+       vsyscall=       [X86-64,EARLY]
                        Controls the behavior of vsyscalls (i.e. calls to
                        fixed addresses of 0xffffffffff600x00 from legacy
                        code).  Most statically-linked binaries and older
                        threshold repeatedly. They are likely good
                        candidates for using WQ_UNBOUND workqueues instead.
 
+       workqueue.cpu_intensive_warning_thresh=<uint>
+                       If CONFIG_WQ_CPU_INTENSIVE_REPORT is set, the kernel
+                       will report the work functions which violate the
+                       intensive_threshold_us repeatedly. In order to prevent
+                       spurious warnings, start printing only after a work
+                       function has violated this threshold number of times.
+
+                       The default is 4 times. 0 disables the warning.
+
        workqueue.power_efficient
                        Per-cpu workqueues are generally preferred because
                        they show better performance thanks to cache
                        When enabled, memory and cache locality will be
                        impacted.
 
-       writecombine=   [LOONGARCH] Control the MAT (Memory Access Type) of
-                       ioremap_wc().
+       writecombine=   [LOONGARCH,EARLY] Control the MAT (Memory Access
+                       Type) of ioremap_wc().
 
                        on   - Enable writecombine, use WUC for ioremap_wc()
                        off  - Disable writecombine, use SUC for ioremap_wc()
 
-       x2apic_phys     [X86-64,APIC] Use x2apic physical mode instead of
+       x2apic_phys     [X86-64,APIC,EARLY] Use x2apic physical mode instead of
                        default x2apic cluster mode on platforms
                        supporting x2apic.
 
                        save/restore/migration must be enabled to handle larger
                        domains.
 
-       xen_emul_unplug=                [HW,X86,XEN]
+       xen_emul_unplug=                [HW,X86,XEN,EARLY]
                        Unplug Xen emulated devices
                        Format: [unplug0,][unplug1]
                        ide-disks -- unplug primary master IDE devices
                                the unplug protocol
                        never -- do not unplug even if version check succeeds
 
-       xen_legacy_crash        [X86,XEN]
+       xen_legacy_crash        [X86,XEN,EARLY]
                        Crash from Xen panic notifier, without executing late
                        panic() code such as dumping handler.
 
-       xen_msr_safe=   [X86,XEN]
+       xen_msr_safe=   [X86,XEN,EARLY]
                        Format: <bool>
                        Select whether to always use non-faulting (safe) MSR
                        access functions when running as Xen PV guest. The
                        default value is controlled by CONFIG_XEN_PV_MSR_SAFE.
 
-       xen_nopvspin    [X86,XEN]
+       xen_nopvspin    [X86,XEN,EARLY]
                        Disables the qspinlock slowpath using Xen PV optimizations.
                        This parameter is obsoleted by "nopvspin" parameter, which
                        has equivalent effect for XEN platform.
                        has equivalent effect for XEN platform.
 
        xen_no_vector_callback
-                       [KNL,X86,XEN] Disable the vector callback for Xen
+                       [KNL,X86,XEN,EARLY] Disable the vector callback for Xen
                        event channel interrupts.
 
        xen_scrub_pages=        [XEN]
                        with /sys/devices/system/xen_memory/xen_memory0/scrub_pages.
                        Default value controlled with CONFIG_XEN_SCRUB_PAGES_DEFAULT.
 
-       xen_timer_slop= [X86-64,XEN]
+       xen_timer_slop= [X86-64,XEN,EARLY]
                        Set the timer slop (in nanoseconds) for the virtual Xen
                        timers (default is 100000). This adjusts the minimum
                        delta of virtualized Xen timers, where lower values
                        host controller quirks. Meaning of each bit can be
                        consulted in header drivers/usb/host/xhci.h.
 
-       xmon            [PPC]
+       xmon            [PPC,EARLY]
                        Format: { early | on | rw | ro | off }
                        Controls if xmon debugger is enabled. Default is off.
                        Passing only "xmon" is equivalent to "xmon=early".
index e8c2ce1f9df68df5976b7cc536d3f48c0501ba4b..45a7f4932fe07f295cd452313bfcb64c59809218 100644 (file)
@@ -243,3 +243,10 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | ASR            | ASR8601         | #8601001        | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
++----------------+-----------------+-----------------+-----------------------------+
+| Microsoft      | Azure Cobalt 100| #2139208        | ARM64_ERRATUM_2139208       |
++----------------+-----------------+-----------------+-----------------------------+
+| Microsoft      | Azure Cobalt 100| #2067961        | ARM64_ERRATUM_2067961       |
++----------------+-----------------+-----------------+-----------------------------+
+| Microsoft      | Azure Cobalt 100| #2253138        | ARM64_ERRATUM_2253138       |
++----------------+-----------------+-----------------+-----------------------------+
index 07caa8fff852ee254c8805928e353e4dc440186c..414bc7402ae7dbf2755f0f0d8f702bd457e5bf54 100644 (file)
@@ -87,14 +87,14 @@ The state of SME in the Linux kernel can be documented as follows:
          kernel is non-zero).
 
 SME can also be enabled and activated in the BIOS. If SME is enabled and
-activated in the BIOS, then all memory accesses will be encrypted and it will
-not be necessary to activate the Linux memory encryption support.  If the BIOS
-merely enables SME (sets bit 23 of the MSR_AMD64_SYSCFG), then Linux can activate
-memory encryption by default (CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT=y) or
-by supplying mem_encrypt=on on the kernel command line.  However, if BIOS does
-not enable SME, then Linux will not be able to activate memory encryption, even
-if configured to do so by default or the mem_encrypt=on command line parameter
-is specified.
+activated in the BIOS, then all memory accesses will be encrypted and it
+will not be necessary to activate the Linux memory encryption support.
+
+If the BIOS merely enables SME (sets bit 23 of the MSR_AMD64_SYSCFG),
+then memory encryption can be enabled by supplying mem_encrypt=on on the
+kernel command line.  However, if BIOS does not enable SME, then Linux
+will not be able to activate memory encryption, even if configured to do
+so by default or the mem_encrypt=on command line parameter is specified.
 
 Secure Nested Paging (SNP)
 ==========================
index c513855a54bb99fa10c5e4029dc5ca38aeb03681..4fd492cb49704fa21fd368fe0832f332e952c83d 100644 (file)
@@ -878,7 +878,8 @@ Protocol:   2.10+
   address if possible.
 
   A non-relocatable kernel will unconditionally move itself and to run
-  at this address.
+  at this address. A relocatable kernel will move itself to this address if it
+  loaded below this address.
 
 ============   =======
 Field name:    init_size
index e73fdff62c0aa10a0d6de89e6a62f8b2185920a7..c58c72362911cd0a10be8e96eba4cb9940d3b576 100644 (file)
@@ -95,6 +95,9 @@ The kernel provides a function to invoke the buffer clearing:
 
     mds_clear_cpu_buffers()
 
+Also macro CLEAR_CPU_BUFFERS can be used in ASM late in exit-to-user path.
+Other than CFLAGS.ZF, this macro doesn't clobber any registers.
+
 The mitigation is invoked on kernel/userspace, hypervisor/guest and C-state
 (idle) transitions.
 
@@ -138,17 +141,30 @@ Mitigation points
 
    When transitioning from kernel to user space the CPU buffers are flushed
    on affected CPUs when the mitigation is not disabled on the kernel
-   command line. The migitation is enabled through the static key
-   mds_user_clear.
-
-   The mitigation is invoked in prepare_exit_to_usermode() which covers
-   all but one of the kernel to user space transitions.  The exception
-   is when we return from a Non Maskable Interrupt (NMI), which is
-   handled directly in do_nmi().
-
-   (The reason that NMI is special is that prepare_exit_to_usermode() can
-    enable IRQs.  In NMI context, NMIs are blocked, and we don't want to
-    enable IRQs with NMIs blocked.)
+   command line. The mitigation is enabled through the feature flag
+   X86_FEATURE_CLEAR_CPU_BUF.
+
+   The mitigation is invoked just before transitioning to userspace after
+   user registers are restored. This is done to minimize the window in
+   which kernel data could be accessed after VERW e.g. via an NMI after
+   VERW.
+
+   **Corner case not handled**
+   Interrupts returning to kernel don't clear CPUs buffers since the
+   exit-to-user path is expected to do that anyways. But, there could be
+   a case when an NMI is generated in kernel after the exit-to-user path
+   has cleared the buffers. This case is not handled and NMI returning to
+   kernel don't clear CPU buffers because:
+
+   1. It is rare to get an NMI after VERW, but before returning to userspace.
+   2. For an unprivileged user, there is no known way to make that NMI
+      less rare or target it.
+   3. It would take a large number of these precisely-timed NMIs to mount
+      an actual attack.  There's presumably not enough bandwidth.
+   4. The NMI in question occurs after a VERW, i.e. when user state is
+      restored and most interesting data is already scrubbed. Whats left
+      is only the data that NMI touches, and that may or may not be of
+      any interest.
 
 
 2. C-State transition
index e08d35177bc028b4878207e3feadcbce71e9811e..57e8392f61d35460927904f0436164d129a6ee50 100644 (file)
@@ -26,9 +26,9 @@ comments in pti.c).
 
 This approach helps to ensure that side-channel attacks leveraging
 the paging structures do not function when PTI is enabled.  It can be
-enabled by setting CONFIG_PAGE_TABLE_ISOLATION=y at compile time.
-Once enabled at compile-time, it can be disabled at boot with the
-'nopti' or 'pti=' kernel parameters (see kernel-parameters.txt).
+enabled by setting CONFIG_MITIGATION_PAGE_TABLE_ISOLATION=y at compile
+time.  Once enabled at compile-time, it can be disabled at boot with
+the 'nopti' or 'pti=' kernel parameters (see kernel-parameters.txt).
 
 Page Table Management
 =====================
index 08ebf9edbfc1ed4982e550c283a03bc00e6af345..7352ab89a55ae4fc79dfe7cee997e2345576d2fe 100644 (file)
@@ -47,17 +47,21 @@ AMD nomenclature for package is 'Node'.
 
 Package-related topology information in the kernel:
 
-  - cpuinfo_x86.x86_max_cores:
+  - topology_num_threads_per_package()
 
-    The number of cores in a package. This information is retrieved via CPUID.
+    The number of threads in a package.
 
-  - cpuinfo_x86.x86_max_dies:
+  - topology_num_cores_per_package()
 
-    The number of dies in a package. This information is retrieved via CPUID.
+    The number of cores in a package.
+
+  - topology_max_dies_per_package()
+
+    The maximum number of dies in a package.
 
   - cpuinfo_x86.topo.die_id:
 
-    The physical ID of the die. This information is retrieved via CPUID.
+    The physical ID of the die.
 
   - cpuinfo_x86.topo.pkg_id:
 
@@ -96,16 +100,6 @@ are SMT- or CMT-type threads.
 AMDs nomenclature for a CMT core is "Compute Unit". The kernel always uses
 "core".
 
-Core-related topology information in the kernel:
-
-  - smp_num_siblings:
-
-    The number of threads in a core. The number of threads in a package can be
-    calculated by::
-
-       threads_per_package = cpuinfo_x86.x86_max_cores * smp_num_siblings
-
-
 Threads
 =======
 A thread is a single scheduling unit. It's the equivalent to a logical Linux
diff --git a/Documentation/arch/x86/x86_64/fred.rst b/Documentation/arch/x86/x86_64/fred.rst
new file mode 100644 (file)
index 0000000..9f57e7b
--- /dev/null
@@ -0,0 +1,96 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=========================================
+Flexible Return and Event Delivery (FRED)
+=========================================
+
+Overview
+========
+
+The FRED architecture defines simple new transitions that change
+privilege level (ring transitions). The FRED architecture was
+designed with the following goals:
+
+1) Improve overall performance and response time by replacing event
+   delivery through the interrupt descriptor table (IDT event
+   delivery) and event return by the IRET instruction with lower
+   latency transitions.
+
+2) Improve software robustness by ensuring that event delivery
+   establishes the full supervisor context and that event return
+   establishes the full user context.
+
+The new transitions defined by the FRED architecture are FRED event
+delivery and, for returning from events, two FRED return instructions.
+FRED event delivery can effect a transition from ring 3 to ring 0, but
+it is used also to deliver events incident to ring 0. One FRED
+instruction (ERETU) effects a return from ring 0 to ring 3, while the
+other (ERETS) returns while remaining in ring 0. Collectively, FRED
+event delivery and the FRED return instructions are FRED transitions.
+
+In addition to these transitions, the FRED architecture defines a new
+instruction (LKGS) for managing the state of the GS segment register.
+The LKGS instruction can be used by 64-bit operating systems that do
+not use the new FRED transitions.
+
+Furthermore, the FRED architecture is easy to extend for future CPU
+architectures.
+
+Software based event dispatching
+================================
+
+FRED operates differently from IDT in terms of event handling. Instead
+of directly dispatching an event to its handler based on the event
+vector, FRED requires the software to dispatch an event to its handler
+based on both the event's type and vector. Therefore, an event dispatch
+framework must be implemented to facilitate the event-to-handler
+dispatch process. The FRED event dispatch framework takes control
+once an event is delivered, and employs a two-level dispatch.
+
+The first level dispatching is event type based, and the second level
+dispatching is event vector based.
+
+Full supervisor/user context
+============================
+
+FRED event delivery atomically save and restore full supervisor/user
+context upon event delivery and return. Thus it avoids the problem of
+transient states due to %cr2 and/or %dr6, and it is no longer needed
+to handle all the ugly corner cases caused by half baked entry states.
+
+FRED allows explicit unblock of NMI with new event return instructions
+ERETS/ERETU, avoiding the mess caused by IRET which unconditionally
+unblocks NMI, e.g., when an exception happens during NMI handling.
+
+FRED always restores the full value of %rsp, thus ESPFIX is no longer
+needed when FRED is enabled.
+
+LKGS
+====
+
+LKGS behaves like the MOV to GS instruction except that it loads the
+base address into the IA32_KERNEL_GS_BASE MSR instead of the GS
+segment’s descriptor cache. With LKGS, it ends up with avoiding
+mucking with kernel GS, i.e., an operating system can always operate
+with its own GS base address.
+
+Because FRED event delivery from ring 3 and ERETU both swap the value
+of the GS base address and that of the IA32_KERNEL_GS_BASE MSR, plus
+the introduction of LKGS instruction, the SWAPGS instruction is no
+longer needed when FRED is enabled, thus is disallowed (#UD).
+
+Stack levels
+============
+
+4 stack levels 0~3 are introduced to replace the nonreentrant IST for
+event handling, and each stack level should be configured to use a
+dedicated stack.
+
+The current stack level could be unchanged or go higher upon FRED
+event delivery. If unchanged, the CPU keeps using the current event
+stack. If higher, the CPU switches to a new event stack specified by
+the MSR of the new stack level, i.e., MSR_IA32_FRED_RSP[123].
+
+Only execution of a FRED return instruction ERET[US], could lower the
+current stack level, causing the CPU to switch back to the stack it was
+on before a previous event delivery that promoted the stack level.
index a56070fc8e77a9555ff093002705906a99d4d5bc..ad15e9bd623f684e537f794b9e970485a7391dfd 100644 (file)
@@ -15,3 +15,4 @@ x86_64 Support
    cpu-hotplug-spec
    machinecheck
    fsgs
+   fred
index 5830b01c56429d38f18e12778ebce543605b3296..da64c9fb7e072378c53423b1f7b575ef124b6834 100644 (file)
@@ -388,6 +388,12 @@ latex_elements = {
         verbatimhintsturnover=false,
     ''',
 
+    #
+    # Some of our authors are fond of deep nesting; tell latex to
+    # cope.
+    #
+    'maxlistdepth': '10',
+
     # For CJK One-half spacing, need to be in front of hyperref
     'extrapackages': r'\usepackage{setspace}',
 
index 3599cf9267b4766c4628dde7d27d98fb95e325a9..ed73c612174d4c99d3329cc1443b553537e049db 100644 (file)
@@ -77,10 +77,12 @@ wants a function to be executed asynchronously it has to set up a work
 item pointing to that function and queue that work item on a
 workqueue.
 
-Special purpose threads, called worker threads, execute the functions
-off of the queue, one after the other.  If no work is queued, the
-worker threads become idle.  These worker threads are managed in so
-called worker-pools.
+A work item can be executed in either a thread or the BH (softirq) context.
+
+For threaded workqueues, special purpose threads, called [k]workers, execute
+the functions off of the queue, one after the other. If no work is queued,
+the worker threads become idle. These worker threads are managed in
+worker-pools.
 
 The cmwq design differentiates between the user-facing workqueues that
 subsystems and drivers queue work items on and the backend mechanism
@@ -91,6 +93,12 @@ for high priority ones, for each possible CPU and some extra
 worker-pools to serve work items queued on unbound workqueues - the
 number of these backing pools is dynamic.
 
+BH workqueues use the same framework. However, as there can only be one
+concurrent execution context, there's no need to worry about concurrency.
+Each per-CPU BH worker pool contains only one pseudo worker which represents
+the BH execution context. A BH workqueue can be considered a convenience
+interface to softirq.
+
 Subsystems and drivers can create and queue work items through special
 workqueue API functions as they see fit. They can influence some
 aspects of the way the work items are executed by setting flags on the
@@ -106,7 +114,7 @@ unless specifically overridden, a work item of a bound workqueue will
 be queued on the worklist of either normal or highpri worker-pool that
 is associated to the CPU the issuer is running on.
 
-For any worker pool implementation, managing the concurrency level
+For any thread pool implementation, managing the concurrency level
 (how many execution contexts are active) is an important issue.  cmwq
 tries to keep the concurrency at a minimal but sufficient level.
 Minimal to save resources and sufficient in that the system is used at
@@ -164,6 +172,17 @@ resources, scheduled and executed.
 ``flags``
 ---------
 
+``WQ_BH``
+  BH workqueues can be considered a convenience interface to softirq. BH
+  workqueues are always per-CPU and all BH work items are executed in the
+  queueing CPU's softirq context in the queueing order.
+
+  All BH workqueues must have 0 ``max_active`` and ``WQ_HIGHPRI`` is the
+  only allowed additional flag.
+
+  BH work items cannot sleep. All other features such as delayed queueing,
+  flushing and canceling are supported.
+
 ``WQ_UNBOUND``
   Work items queued to an unbound wq are served by the special
   worker-pools which host workers which are not bound to any
@@ -237,15 +256,11 @@ may queue at the same time.  Unless there is a specific need for
 throttling the number of active work items, specifying '0' is
 recommended.
 
-Some users depend on the strict execution ordering of ST wq.  The
-combination of ``@max_active`` of 1 and ``WQ_UNBOUND`` used to
-achieve this behavior.  Work items on such wq were always queued to the
-unbound worker-pools and only one work item could be active at any given
-time thus achieving the same ordering property as ST wq.
-
-In the current implementation the above configuration only guarantees
-ST behavior within a given NUMA node. Instead ``alloc_ordered_workqueue()`` should
-be used to achieve system-wide ST behavior.
+Some users depend on strict execution ordering where only one work item
+is in flight at any given time and the work items are processed in
+queueing order. While the combination of ``@max_active`` of 1 and
+``WQ_UNBOUND`` used to achieve this behavior, this is no longer the
+case. Use ``alloc_ordered_queue()`` instead.
 
 
 Example Execution Scenarios
index ab376b316c36d6e3bebd0fe050ff28314d5b60b2..7f3582a67318bebe42dffd5a666a8babdca0fb49 100644 (file)
@@ -245,6 +245,10 @@ Contributing new tests (details)
    TEST_PROGS, TEST_GEN_PROGS mean it is the executable tested by
    default.
 
+   TEST_GEN_MODS_DIR should be used by tests that require modules to be built
+   before the test starts. The variable will contain the name of the directory
+   containing the modules.
+
    TEST_CUSTOM_PROGS should be used by tests that require custom build
    rules and prevent common build rule use.
 
index 2323fd5b7cdae1ebe440275d8f67649354a6f448..129cf698fa8a66fd2be5111074319da545f4cc98 100644 (file)
@@ -28,7 +28,10 @@ $(obj)/%.example.dts: $(src)/%.yaml check_dtschema_version FORCE
 find_all_cmd = find $(srctree)/$(src) \( -name '*.yaml' ! \
                -name 'processed-schema*' \)
 
-find_cmd = $(find_all_cmd) | sed 's|^$(srctree)/$(src)/||' | grep -F -e "$(subst :," -e ",$(DT_SCHEMA_FILES))" | sed 's|^|$(srctree)/$(src)/|'
+find_cmd = $(find_all_cmd) | \
+               sed 's|^$(srctree)/||' | \
+               grep -F -e "$(subst :," -e ",$(DT_SCHEMA_FILES))" | \
+               sed 's|^|$(srctree)/|'
 CHK_DT_DOCS := $(shell $(find_cmd))
 
 quiet_cmd_yamllint = LINT    $(src)
index caab7ceeda45a8cebe43d775ac9258dfb1d2d4eb..949537cea6be23b281633fd4843682a79fcca40e 100644 (file)
@@ -7,19 +7,11 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Amlogic SoC based Platforms
 
 maintainers:
+  - Neil Armstrong <neil.armstrong@linaro.org>
+  - Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+  - Jerome Brunet <jbrunet@baylibre.com>
   - Kevin Hilman <khilman@baylibre.com>
 
-description: |+
-  Work in progress statement:
-
-  Device tree files and bindings applying to Amlogic SoCs and boards are
-  considered "unstable". Any Amlogic device tree binding may change at
-  any time. Be sure to use a device tree binary and a kernel image
-  generated from the same source tree.
-
-  Please refer to Documentation/devicetree/bindings/ABI.rst for a definition of a
-  stable binding/ABI.
-
 properties:
   $nodename:
     const: '/'
@@ -146,6 +138,7 @@ properties:
           - enum:
               - amediatech,x96-max
               - amlogic,u200
+              - freebox,fbx8am
               - radxa,zero
               - seirobotics,sei510
           - const: amlogic,g12a
index d1bdee98f9af08da9777c95ebee4b41a599a6638..3c5f1688dbd787fef8501a807112a3818435a158 100644 (file)
@@ -10,9 +10,9 @@ maintainers:
   - Linus Walleij <linus.walleij@linaro.org>
 
 description: |+
-  The ARM RealView series of reference designs were built to explore the ARM
-  11, Cortex A-8 and Cortex A-9 CPUs. This included new features compared to
-  the earlier CPUs such as TrustZone and multicore (MPCore).
+  The ARM RealView series of reference designs were built to explore the Arm11,
+  Cortex-A8, and Cortex-A9 CPUs. This included new features compared to the
+  earlier CPUs such as TrustZone and multicore (MPCore).
 
 properties:
   $nodename:
index 89d75fbb1de450335812e1544da5b41338627625..82f37328cc694cdad5e2683d49abee2500616ec6 100644 (file)
@@ -179,6 +179,12 @@ properties:
           - const: microchip,sama7g5
           - const: microchip,sama7
 
+      - description: Microchip SAMA7G54 Curiosity Board
+        items:
+          - const: microchip,sama7g54-curiosity
+          - const: microchip,sama7g5
+          - const: microchip,sama7
+
       - description: Microchip LAN9662 Evaluation Boards.
         items:
           - enum:
index 228dcc5c7d6f3ec31426c4a44e87af4253b378a8..0027201e19f8b05f83970087eda4e3da9726e0d8 100644 (file)
@@ -384,7 +384,8 @@ properties:
               - toradex,apalis_imx6q-ixora      # Apalis iMX6Q/D Module on Ixora Carrier Board
               - toradex,apalis_imx6q-ixora-v1.1 # Apalis iMX6Q/D Module on Ixora V1.1 Carrier Board
               - toradex,apalis_imx6q-ixora-v1.2 # Apalis iMX6Q/D Module on Ixora V1.2 Carrier Board
-              - toradex,apalis_imx6q-eval       # Apalis iMX6Q/D Module on Apalis Evaluation Board
+              - toradex,apalis_imx6q-eval       # Apalis iMX6Q/D Module on Apalis Evaluation Board v1.0/v1.1
+              - toradex,apalis_imx6q-eval-v1.2  # Apalis iMX6Q/D Module on Apalis Evaluation Board v1.2
           - const: toradex,apalis_imx6q
           - const: fsl,imx6q
 
@@ -469,6 +470,7 @@ properties:
               - prt,prtvt7                # Protonic VT7 board
               - rex,imx6dl-rex-basic      # Rex Basic i.MX6 Dual Lite Board
               - riot,imx6s-riotboard      # RIoTboard i.MX6S
+              - sielaff,imx6dl-board      # Sielaff i.MX6 Solo Board
               - skov,imx6dl-skov-revc-lt2 # SKOV IMX6 CPU SoloCore lt2
               - skov,imx6dl-skov-revc-lt6 # SKOV IMX6 CPU SoloCore lt6
               - solidrun,cubox-i/dl            # SolidRun Cubox-i Solo/DualLite
@@ -708,6 +710,7 @@ properties:
               - toradex,colibri-imx6ull      # Colibri iMX6ULL Modules
               - toradex,colibri-imx6ull-emmc # Colibri iMX6ULL 1GB (eMMC) Module
               - toradex,colibri-imx6ull-wifi # Colibri iMX6ULL Wi-Fi / BT Modules
+              - uni-t,uti260b             # UNI-T UTi260B Thermal Camera
           - const: fsl,imx6ull
 
       - description: i.MX6ULL Armadeus Systems OPOS6ULDev Board
@@ -1026,7 +1029,7 @@ properties:
         items:
           - enum:
               - dimonoff,gateway-evk # i.MX8MN Dimonoff Gateway EVK Board
-              - rve,rve-gateway # i.MX8MN RVE Gateway Board
+              - rve,gateway # i.MX8MN RVE Gateway Board
               - variscite,var-som-mx8mn-symphony
           - const: variscite,var-som-mx8mn
           - const: fsl,imx8mn
@@ -1194,7 +1197,8 @@ properties:
       - description: i.MX8QM Boards with Toradex Apalis iMX8 Modules
         items:
           - enum:
-              - toradex,apalis-imx8-eval            # Apalis iMX8 Module on Apalis Evaluation Board
+              - toradex,apalis-imx8-eval            # Apalis iMX8 Module on Apalis Evaluation V1.0/V1.1 Board
+              - toradex,apalis-imx8-eval-v1.2       # Apalis iMX8 Module on Apalis Evaluation V1.2 Board
               - toradex,apalis-imx8-ixora-v1.1      # Apalis iMX8 Module on Ixora V1.1 Carrier Board
           - const: toradex,apalis-imx8
           - const: fsl,imx8qm
@@ -1202,7 +1206,8 @@ properties:
       - description: i.MX8QM Boards with Toradex Apalis iMX8 V1.1 Modules
         items:
           - enum:
-              - toradex,apalis-imx8-v1.1-eval       # Apalis iMX8 V1.1 Module on Apalis Eval. Board
+              - toradex,apalis-imx8-v1.1-eval       # Apalis iMX8 V1.1 Module on Apalis Eval. V1.0/V1.1 Board
+              - toradex,apalis-imx8-v1.1-eval-v1.2  # Apalis iMX8 V1.1 Module on Apalis Eval. V1.2 Board
               - toradex,apalis-imx8-v1.1-ixora-v1.1 # Apalis iMX8 V1.1 Module on Ixora V1.1 C. Board
               - toradex,apalis-imx8-v1.1-ixora-v1.2 # Apalis iMX8 V1.1 Module on Ixora V1.2 C. Board
           - const: toradex,apalis-imx8-v1.1
@@ -1232,6 +1237,22 @@ properties:
           - const: toradex,colibri-imx8x
           - const: fsl,imx8qxp
 
+      - description:
+          TQMa8Xx is a series of SOM featuring NXP i.MX8X system-on-chip
+          variants. It is designed to be clicked on different carrier boards
+          MBa8Xx is the starterkit
+        oneOf:
+          - items:
+              - enum:
+                  - tq,imx8dxp-tqma8xdp-mba8xx # TQ-Systems GmbH TQMa8XDP SOM on MBa8Xx
+              - const: tq,imx8dxp-tqma8xdp     # TQ-Systems GmbH TQMa8XDP SOM (with i.MX8DXP)
+              - const: fsl,imx8dxp
+          - items:
+              - enum:
+                  - tq,imx8qxp-tqma8xqp-mba8xx # TQ-Systems GmbH TQMa8XQP SOM on MBa8Xx
+              - const: tq,imx8qxp-tqma8xqp     # TQ-Systems GmbH TQMa8XQP SOM (with i.MX8QXP)
+              - const: fsl,imx8qxp
+
       - description: i.MX8ULP based Boards
         items:
           - enum:
@@ -1275,6 +1296,18 @@ properties:
           - const: tq,imx93-tqma9352        # TQ-Systems GmbH i.MX93 TQMa93xxCA/LA SOM
           - const: fsl,imx93
 
+      - description: PHYTEC phyCORE-i.MX93 SoM based boards
+        items:
+          - const: phytec,imx93-phyboard-segin # phyBOARD-Segin with i.MX93
+          - const: phytec,imx93-phycore-som    # phyCORE-i.MX93 SoM
+          - const: fsl,imx93
+
+      - description: Variscite VAR-SOM-MX93 based boards
+        items:
+          - const: variscite,var-som-mx93-symphony
+          - const: variscite,var-som-mx93
+          - const: fsl,imx93
+
       - description:
           Freescale Vybrid Platform Device Tree Bindings
 
diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-38x.txt b/Documentation/devicetree/bindings/arm/marvell/armada-38x.txt
deleted file mode 100644 (file)
index 202953f..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-Marvell Armada 38x Platforms Device Tree Bindings
--------------------------------------------------
-
-Boards with a SoC of the Marvell Armada 38x family shall have the
-following property:
-
-Required root node property:
-
- - compatible: must contain "marvell,armada380"
-
-In addition, boards using the Marvell Armada 385 SoC shall have the
-following property before the previous one:
-
-Required root node property:
-
-compatible: must contain "marvell,armada385"
-
-In addition, boards using the Marvell Armada 388 SoC shall have the
-following property before the previous one:
-
-Required root node property:
-
-compatible: must contain "marvell,armada388"
-
-Example:
-
-compatible = "marvell,a385-rd", "marvell,armada385", "marvell,armada380";
diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-38x.yaml b/Documentation/devicetree/bindings/arm/marvell/armada-38x.yaml
new file mode 100644 (file)
index 0000000..cdf805b
--- /dev/null
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/marvell/armada-38x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Marvell Armada 38x Platforms
+
+maintainers:
+  - Gregory CLEMENT <gregory.clement@bootlin.com>
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+
+      - description:
+          Netgear Armada 380 GS110EM Managed Switch.
+        items:
+          - const: netgear,gs110emx
+          - const: marvell,armada380
+
+      - description:
+          Marvell Armada 385 Development Boards.
+        items:
+          - enum:
+              - marvell,a385-db-amc
+              - marvell,a385-db-ap
+          - const: marvell,armada385
+          - const: marvell,armada380
+
+      - description:
+          SolidRun Armada 385 based single-board computers.
+        items:
+          - enum:
+              - solidrun,clearfog-gtr-l8
+              - solidrun,clearfog-gtr-s4
+          - const: marvell,armada385
+          - const: marvell,armada380
+
+      - description:
+          Kobol Armada 388 based Helios-4 NAS.
+        items:
+          - const: kobol,helios4
+          - const: marvell,armada388
+          - const: marvell,armada385
+          - const: marvell,armada380
+
+      - description:
+          Marvell Armada 388 Development Boards.
+        items:
+          - enum:
+              - marvell,a388-gp
+          - const: marvell,armada388
+          - const: marvell,armada385
+          - const: marvell,armada380
+
+      - description:
+          SolidRun Armada 388 clearfog family single-board computers.
+        items:
+          - enum:
+              - solidrun,clearfog-base-a1
+              - solidrun,clearfog-pro-a1
+          - const: solidrun,clearfog-a1
+          - const: marvell,armada388
+          - const: marvell,armada385
+          - const: marvell,armada380
+
+additionalProperties: true
index 6f2f64ae76fcf3067b2076e2586f64b29c8b17eb..09f9ffd3ff7b2c5f357bb87ec4d46a4a671b9cde 100644 (file)
@@ -17,6 +17,7 @@ properties:
     const: '/'
   compatible:
     oneOf:
+      # Sort by SoC (last) compatible, then board compatible
       - items:
           - enum:
               - mediatek,mt2701-evb
@@ -84,6 +85,11 @@ properties:
           - const: mediatek,mt7629
       - items:
           - enum:
+              - xiaomi,ax3000t
+          - const: mediatek,mt7981b
+      - items:
+          - enum:
+              - acelink,ew-7886cax
               - bananapi,bpi-r3
               - mediatek,mt7986a-rfb
           - const: mediatek,mt7986a
@@ -91,6 +97,10 @@ properties:
           - enum:
               - mediatek,mt7986b-rfb
           - const: mediatek,mt7986b
+      - items:
+          - enum:
+              - bananapi,bpi-r4
+          - const: mediatek,mt7988a
       - items:
           - enum:
               - mediatek,mt8127-moose
@@ -129,75 +139,10 @@ properties:
           - enum:
               - mediatek,mt8173-evb
           - const: mediatek,mt8173
-      - items:
-          - enum:
-              - mediatek,mt8183-evb
-          - const: mediatek,mt8183
-      - description: Google Hayato rev5
-        items:
-          - const: google,hayato-rev5-sku2
-          - const: google,hayato-sku2
-          - const: google,hayato
-          - const: mediatek,mt8192
-      - description: Google Hayato
-        items:
-          - const: google,hayato-rev1
-          - const: google,hayato
-          - const: mediatek,mt8192
-      - description: Google Spherion rev4 (Acer Chromebook 514)
-        items:
-          - const: google,spherion-rev4
-          - const: google,spherion
-          - const: mediatek,mt8192
-      - description: Google Spherion (Acer Chromebook 514)
-        items:
-          - const: google,spherion-rev3
-          - const: google,spherion-rev2
-          - const: google,spherion-rev1
-          - const: google,spherion-rev0
-          - const: google,spherion
-          - const: mediatek,mt8192
-      - description: Acer Tomato (Acer Chromebook Spin 513 CP513-2H)
-        items:
-          - enum:
-              - google,tomato-rev2
-              - google,tomato-rev1
-          - const: google,tomato
-          - const: mediatek,mt8195
-      - description: Acer Tomato rev3 - 4 (Acer Chromebook Spin 513 CP513-2H)
-        items:
-          - const: google,tomato-rev4
-          - const: google,tomato-rev3
-          - const: google,tomato
-          - const: mediatek,mt8195
-      - items:
-          - enum:
-              - mediatek,mt8186-evb
-          - const: mediatek,mt8186
-      - items:
-          - enum:
-              - mediatek,mt8188-evb
-          - const: mediatek,mt8188
-      - items:
-          - enum:
-              - mediatek,mt8192-evb
-          - const: mediatek,mt8192
-      - items:
-          - enum:
-              - mediatek,mt8195-demo
-              - mediatek,mt8195-evb
-          - const: mediatek,mt8195
       - description: Google Burnet (HP Chromebook x360 11MK G3 EE)
         items:
           - const: google,burnet
           - const: mediatek,mt8183
-      - description: Google Krane (Lenovo IdeaPad Duet, 10e,...)
-        items:
-          - enum:
-              - google,krane-sku0
-              - google,krane-sku176
-          - const: google,krane
-          - const: mediatek,mt8183
       - description: Google Cozmo (Acer Chromebook 314)
         items:
           - const: google,cozmo
@@ -255,6 +200,13 @@ properties:
               - google,kodama-sku32
           - const: google,kodama
           - const: mediatek,mt8183
+      - description: Google Krane (Lenovo IdeaPad Duet, 10e,...)
+        items:
+          - enum:
+              - google,krane-sku0
+              - google,krane-sku176
+          - const: google,krane
+          - const: mediatek,mt8183
       - description: Google Makomo (Lenovo 100e Chromebook 2nd Gen MTK 2)
         items:
           - enum:
@@ -276,10 +228,125 @@ properties:
               - google,willow-sku1
           - const: google,willow
           - const: mediatek,mt8183
+      - items:
+          - enum:
+              - mediatek,mt8183-evb
+          - const: mediatek,mt8183
       - items:
           - enum:
               - mediatek,mt8183-pumpkin
           - const: mediatek,mt8183
+      - description: Google Magneton (Lenovo IdeaPad Slim 3 Chromebook (14M868))
+        items:
+          - const: google,steelix-sku393219
+          - const: google,steelix-sku393216
+          - const: google,steelix
+          - const: mediatek,mt8186
+      - description: Google Magneton (Lenovo IdeaPad Slim 3 Chromebook (14M868))
+        items:
+          - const: google,steelix-sku393220
+          - const: google,steelix-sku393217
+          - const: google,steelix
+          - const: mediatek,mt8186
+      - description: Google Magneton (Lenovo IdeaPad Slim 3 Chromebook (14M868))
+        items:
+          - const: google,steelix-sku393221
+          - const: google,steelix-sku393218
+          - const: google,steelix
+          - const: mediatek,mt8186
+      - description: Google Rusty (Lenovo 100e Chromebook Gen 4)
+        items:
+          - const: google,steelix-sku196609
+          - const: google,steelix-sku196608
+          - const: google,steelix
+          - const: mediatek,mt8186
+      - description: Google Steelix (Lenovo 300e Yoga Chromebook Gen 4)
+        items:
+          - enum:
+              - google,steelix-sku131072
+              - google,steelix-sku131073
+          - const: google,steelix
+          - const: mediatek,mt8186
+      - description: Google Tentacruel (ASUS Chromebook CM14 Flip CM1402F)
+        items:
+          - const: google,tentacruel-sku262147
+          - const: google,tentacruel-sku262146
+          - const: google,tentacruel-sku262145
+          - const: google,tentacruel-sku262144
+          - const: google,tentacruel
+          - const: mediatek,mt8186
+      - description: Google Tentacruel (ASUS Chromebook CM14 Flip CM1402F)
+        items:
+          - const: google,tentacruel-sku262151
+          - const: google,tentacruel-sku262150
+          - const: google,tentacruel-sku262149
+          - const: google,tentacruel-sku262148
+          - const: google,tentacruel
+          - const: mediatek,mt8186
+      - description: Google Tentacool (ASUS Chromebook CM14 CM1402C)
+        items:
+          - const: google,tentacruel-sku327681
+          - const: google,tentacruel
+          - const: mediatek,mt8186
+      - description: Google Tentacool (ASUS Chromebook CM14 CM1402C)
+        items:
+          - const: google,tentacruel-sku327683
+          - const: google,tentacruel
+          - const: mediatek,mt8186
+      - items:
+          - enum:
+              - mediatek,mt8186-evb
+          - const: mediatek,mt8186
+      - items:
+          - enum:
+              - mediatek,mt8188-evb
+          - const: mediatek,mt8188
+      - description: Google Hayato
+        items:
+          - const: google,hayato-rev1
+          - const: google,hayato
+          - const: mediatek,mt8192
+      - description: Google Hayato rev5
+        items:
+          - const: google,hayato-rev5-sku2
+          - const: google,hayato-sku2
+          - const: google,hayato
+          - const: mediatek,mt8192
+      - description: Google Spherion (Acer Chromebook 514)
+        items:
+          - const: google,spherion-rev3
+          - const: google,spherion-rev2
+          - const: google,spherion-rev1
+          - const: google,spherion-rev0
+          - const: google,spherion
+          - const: mediatek,mt8192
+      - description: Google Spherion rev4 (Acer Chromebook 514)
+        items:
+          - const: google,spherion-rev4
+          - const: google,spherion
+          - const: mediatek,mt8192
+      - items:
+          - enum:
+              - mediatek,mt8192-evb
+          - const: mediatek,mt8192
+      - description: Acer Tomato (Acer Chromebook Spin 513 CP513-2H)
+        items:
+          - enum:
+              - google,tomato-rev2
+              - google,tomato-rev1
+          - const: google,tomato
+          - const: mediatek,mt8195
+      - description: Acer Tomato rev3 - 4 (Acer Chromebook Spin 513 CP513-2H)
+        items:
+          - const: google,tomato-rev4
+          - const: google,tomato-rev3
+          - const: google,tomato
+          - const: mediatek,mt8195
+      - items:
+          - enum:
+              - mediatek,mt8195-demo
+              - mediatek,mt8195-evb
+          - const: mediatek,mt8195
       - items:
           - enum:
               - mediatek,mt8365-evk
@@ -287,6 +354,7 @@ properties:
       - items:
           - enum:
               - mediatek,mt8395-evk
+              - radxa,nio-12l
           - const: mediatek,mt8395
           - const: mediatek,mt8195
       - items:
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,saw2.txt b/Documentation/devicetree/bindings/arm/msm/qcom,saw2.txt
deleted file mode 100644 (file)
index c0e3c3a..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-SPM AVS Wrapper 2 (SAW2)
-
-The SAW2 is a wrapper around the Subsystem Power Manager (SPM) and the
-Adaptive Voltage Scaling (AVS) hardware. The SPM is a programmable
-power-controller that transitions a piece of hardware (like a processor or
-subsystem) into and out of low power modes via a direct connection to
-the PMIC. It can also be wired up to interact with other processors in the
-system, notifying them when a low power state is entered or exited.
-
-Multiple revisions of the SAW hardware are supported using these Device Nodes.
-SAW2 revisions differ in the register offset and configuration data. Also, the
-same revision of the SAW in different SoCs may have different configuration
-data due the differences in hardware capabilities. Hence the SoC name, the
-version of the SAW hardware in that SoC and the distinction between cpu (big
-or Little) or cache, may be needed to uniquely identify the SAW register
-configuration and initialization data. The compatible string is used to
-indicate this parameter.
-
-PROPERTIES
-
-- compatible:
-       Usage: required
-       Value type: <string>
-       Definition: Must have
-                       "qcom,saw2"
-                   A more specific value could be one of:
-                       "qcom,apq8064-saw2-v1.1-cpu"
-                       "qcom,msm8226-saw2-v2.1-cpu"
-                       "qcom,msm8974-saw2-v2.1-cpu"
-                       "qcom,apq8084-saw2-v2.1-cpu"
-
-- reg:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: the first element specifies the base address and size of
-                   the register region. An optional second element specifies
-                   the base address and size of the alias register region.
-
-- regulator:
-       Usage: optional
-       Value type: boolean
-       Definition: Indicates that this SPM device acts as a regulator device
-                       device for the core (CPU or Cache) the SPM is attached
-                       to.
-
-Example 1:
-
-       power-controller@2099000 {
-               compatible = "qcom,saw2";
-               reg = <0x02099000 0x1000>, <0x02009000 0x1000>;
-               regulator;
-       };
-
-Example 2:
-       saw0: power-controller@f9089000 {
-               compatible = "qcom,apq8084-saw2-v2.1-cpu", "qcom,saw2";
-               reg = <0xf9089000 0x1000>, <0xf9009000 0x1000>;
-       };
index 1a5fb889a4440fbd41d2fd415c1b67f10cbcdbc8..66beaac60e1dc4b1e23fe41badee1f7c01cf4405 100644 (file)
@@ -10,17 +10,10 @@ maintainers:
   - Bjorn Andersson <bjorn.andersson@linaro.org>
 
 description: |
-  Some qcom based bootloaders identify the dtb blob based on a set of
-  device properties like SoC and platform and revisions of those components.
-  To support this scheme, we encode this information into the board compatible
-  string.
-
-  Each board must specify a top-level board compatible string with the following
-  format:
-
-       compatible = "qcom,<SoC>[-<soc_version>][-<foundry_id>]-<board>[/<subtype>][-<board_version>]"
-
-  The 'SoC' and 'board' elements are required. All other elements are optional.
+  For devices using the Qualcomm SoC the "compatible" properties consists of
+  one or several "manufacturer,model" strings, describing the device itself,
+  followed by one or several "qcom,<SoC>" strings, describing the SoC used in
+  the device.
 
   The 'SoC' element must be one of the following strings:
 
@@ -90,43 +83,9 @@ description: |
         sm8650
         x1e80100
 
-  The 'board' element must be one of the following strings:
-
-        adp
-        cdp
-        dragonboard
-        idp
-        liquid
-        mtp
-        qcp
-        qrd
-        rb2
-        ride
-        sbc
-        x100
-
-  The 'soc_version' and 'board_version' elements take the form of v<Major>.<Minor>
-  where the minor number may be omitted when it's zero, i.e.  v1.0 is the same
-  as v1. If all versions of the 'board_version' elements match, then a
-  wildcard '*' should be used, e.g. 'v*'.
-
-  The 'foundry_id' and 'subtype' elements are one or more digits from 0 to 9.
-
-  Examples:
-
-       "qcom,msm8916-v1-cdp-pm8916-v2.1"
-
-  A CDP board with an msm8916 SoC, version 1 paired with a pm8916 PMIC of version
-  2.1.
-
-       "qcom,apq8074-v2.0-2-dragonboard/1-v0.1"
-
-  A dragonboard board v0.1 of subtype 1 with an apq8074 SoC version 2, made in
-  foundry 2.
-
   There are many devices in the list below that run the standard ChromeOS
   bootloader setup and use the open source depthcharge bootloader to boot the
-  OS. These devices do not use the scheme described above. For details, see:
+  OS. These devices use the bootflow explained at
   https://docs.kernel.org/arch/arm/google/chromebook-boot-flow.html
 
 properties:
@@ -187,6 +146,7 @@ properties:
               - microsoft,superman-lte
               - microsoft,tesla
               - motorola,peregrine
+              - samsung,matisselte
           - const: qcom,msm8926
           - const: qcom,msm8226
 
@@ -244,11 +204,15 @@ properties:
               - samsung,a5u-eur
               - samsung,e5
               - samsung,e7
+              - samsung,fortuna3g
+              - samsung,gprimeltecan
               - samsung,grandmax
+              - samsung,grandprimelte
               - samsung,gt510
               - samsung,gt58
               - samsung,j5
               - samsung,j5x
+              - samsung,rossa
               - samsung,serranove
               - thwc,uf896
               - thwc,ufi001c
@@ -988,6 +952,7 @@ properties:
 
       - items:
           - enum:
+              - xiaomi,curtana
               - xiaomi,joyeuse
           - const: qcom,sm7125
 
@@ -1035,6 +1000,7 @@ properties:
 
       - items:
           - enum:
+              - qcom,sm8550-hdk
               - qcom,sm8550-mtp
               - qcom,sm8550-qrd
           - const: qcom,sm8550
index 5cf5cbef2cf550efec0910622c18cbc046bbd374..fcf7316ecd74cdb9e34e8eca98e3a2a65b882e28 100644 (file)
@@ -37,29 +37,16 @@ properties:
               - anbernic,rg351v
           - const: rockchip,rk3326
 
-      - description: Anbernic RG353P
+      - description: Anbernic RK3566 Handheld Gaming Console
         items:
-          - const: anbernic,rg353p
-          - const: rockchip,rk3566
-
-      - description: Anbernic RG353PS
-        items:
-          - const: anbernic,rg353ps
-          - const: rockchip,rk3566
-
-      - description: Anbernic RG353V
-        items:
-          - const: anbernic,rg353v
-          - const: rockchip,rk3566
-
-      - description: Anbernic RG353VS
-        items:
-          - const: anbernic,rg353vs
-          - const: rockchip,rk3566
-
-      - description: Anbernic RG503
-        items:
-          - const: anbernic,rg503
+          - enum:
+              - anbernic,rg353p
+              - anbernic,rg353ps
+              - anbernic,rg353v
+              - anbernic,rg353vs
+              - anbernic,rg503
+              - anbernic,rg-arc-d
+              - anbernic,rg-arc-s
           - const: rockchip,rk3566
 
       - description: Asus Tinker board
@@ -237,6 +224,13 @@ properties:
               - friendlyarm,nanopi-r5s
           - const: rockchip,rk3568
 
+      - description: FriendlyElec NanoPi R6 series boards
+        items:
+          - enum:
+              - friendlyarm,nanopi-r6c
+              - friendlyarm,nanopi-r6s
+          - const: rockchip,rk3588s
+
       - description: FriendlyElec NanoPC T6
         items:
           - const: friendlyarm,nanopc-t6
@@ -626,9 +620,9 @@ properties:
           - const: openailab,eaidk-610
           - const: rockchip,rk3399
 
-      - description: Orange Pi RK3399 board
+      - description: Xunlong Orange Pi RK3399 board
         items:
-          - const: rockchip,rk3399-orangepi
+          - const: xunlong,rk3399-orangepi
           - const: rockchip,rk3399
 
       - description: Phytec phyCORE-RK3288 Rapid Development Kit
@@ -655,6 +649,14 @@ properties:
           - const: pine64,pinephone-pro
           - const: rockchip,rk3399
 
+      - description: Pine64 PineTab2
+        items:
+          - enum:
+              - pine64,pinetab2-v0.1
+              - pine64,pinetab2-v2.0
+          - const: pine64,pinetab2
+          - const: rockchip,rk3566
+
       - description: Pine64 Rock64
         items:
           - const: pine64,rock64
@@ -692,11 +694,17 @@ properties:
       - description: Powkiddy RK3566 Handheld Gaming Console
         items:
           - enum:
+              - powkiddy,rgb10max3
               - powkiddy,rgb30
               - powkiddy,rk2023
               - powkiddy,x55
           - const: rockchip,rk3566
 
+      - description: QNAP TS-433-4G 4-Bay NAS
+        items:
+          - const: qnap,ts433
+          - const: rockchip,rk3568
+
       - description: Radxa Compute Module 3(CM3)
         items:
           - enum:
@@ -878,6 +886,11 @@ properties:
           - const: rockchip,rv1108-evb
           - const: rockchip,rv1108
 
+      - description: Rockchip Toybrick TB-RK3588X board
+        items:
+          - const: rockchip,rk3588-toybrick-x0
+          - const: rockchip,rk3588
+
       - description: Theobroma Systems PX30-uQ7 with Haikou baseboard
         items:
           - const: tsd,px30-ringneck-haikou
@@ -898,6 +911,12 @@ properties:
           - const: tsd,rk3588-jaguar
           - const: rockchip,rk3588
 
+      - description: Theobroma Systems RK3588-Q7 with Haikou baseboard
+        items:
+          - const: tsd,rk3588-tiger-haikou
+          - const: tsd,rk3588-tiger
+          - const: rockchip,rk3588
+
       - description: Tronsmart Orion R68 Meta
         items:
           - const: tronsmart,orion-r68-meta
@@ -940,9 +959,9 @@ properties:
           - const: rockchip,rk3568-evb1-v10
           - const: rockchip,rk3568
 
-      - description: Rockchip RK3568 Banana Pi R2 Pro
+      - description: Sinovoip RK3568 Banana Pi R2 Pro
         items:
-          - const: rockchip,rk3568-bpi-r2pro
+          - const: sinovoip,rk3568-bpi-r2pro
           - const: rockchip,rk3568
 
       - description: Sonoff iHost Smart Home Hub
index a9d8e85565b8996cbd5c78f52db847062805e0f5..09d835db6db57af63019633ece6f74b0b8d7d215 100644 (file)
@@ -815,6 +815,12 @@ properties:
           - const: allwinner,r7-tv-dongle
           - const: allwinner,sun5i-a10s
 
+      - description: Remix Mini PC
+        items:
+          - const: jide,remix-mini-pc
+          - const: allwinner,sun50i-h64
+          - const: allwinner,sun50i-a64
+
       - description: RerVision H3-DVK
         items:
           - const: rervision,h3-dvk
@@ -835,6 +841,12 @@ properties:
           - const: sinlinx,sina33
           - const: allwinner,sun8i-a33
 
+      - description: Sipeed Longan Pi 3H board for the Sipeed Longan Module 3H
+        items:
+          - const: sipeed,longan-pi-3h
+          - const: sipeed,longan-module-3h
+          - const: allwinner,sun50i-h618
+
       - description: SourceParts PopStick v1.1
         items:
           - const: sourceparts,popstick-v1.1
index fcf956406168e7100d54070a46b96ea3febe6dca..8fb4923517d00cd6d8a4f27d70fbaa7dadd63500 100644 (file)
@@ -64,6 +64,14 @@ properties:
       - items:
           - const: asus,tf700t
           - const: nvidia,tegra30
+      - description: LG Optimus 4X P880
+        items:
+          - const: lg,p880
+          - const: nvidia,tegra30
+      - description: LG Optimus Vu P895
+        items:
+          - const: lg,p895
+          - const: nvidia,tegra30
       - items:
           - const: toradex,apalis_t30-eval
           - const: toradex,apalis_t30
index 0faa403f68c8791bb81d8576eda9e76bf978124e..ea4fbf655220be10199a4ff5cf8200db18c690ca 100644 (file)
@@ -27,7 +27,7 @@ properties:
       - const: pmc
       - const: wake
       - const: aotag
-      - const: scratch
+      - enum: [ scratch, misc ]
       - const: misc
 
   interrupt-controller: true
@@ -41,25 +41,43 @@ properties:
     description: If present, inverts the PMU interrupt signal.
     $ref: /schemas/types.yaml#/definitions/flag
 
-if:
-  properties:
-    compatible:
-      contains:
-        const: nvidia,tegra186-pmc
-then:
-  properties:
-    reg:
-      maxItems: 4
-
-    reg-names:
-      maxItems: 4
-else:
-  properties:
-    reg:
-      minItems: 5
-
-    reg-names:
-      minItems: 5
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: nvidia,tegra186-pmc
+    then:
+      properties:
+        reg:
+          maxItems: 4
+        reg-names:
+          maxItems: 4
+          contains:
+            const: scratch
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: nvidia,tegra194-pmc
+    then:
+      properties:
+        reg:
+          minItems: 5
+        reg-names:
+          minItems: 5
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: nvidia,tegra234-pmc
+    then:
+      properties:
+        reg-names:
+          contains:
+            const: misc
 
 patternProperties:
   "^[a-z0-9]+-[a-z0-9]+$":
index c6506bccfe88fa23f4b6b6a610941881678c2217..52b51fd7044ef444124e5d7ae7c395620d8e728e 100644 (file)
@@ -87,12 +87,20 @@ properties:
           - const: tq,am642-tqma6442l
           - const: ti,am642
 
+      - description: K3 AM642 SoC SolidRun SoM based boards
+        items:
+          - enum:
+              - solidrun,am642-hummingboard-t
+          - const: solidrun,am642-sr-som
+          - const: ti,am642
+
       - description: K3 AM654 SoC
         items:
           - enum:
               - siemens,iot2050-advanced
               - siemens,iot2050-advanced-m2
               - siemens,iot2050-advanced-pg2
+              - siemens,iot2050-advanced-sm
               - siemens,iot2050-basic
               - siemens,iot2050-basic-pg2
               - ti,am654-evm
@@ -123,6 +131,12 @@ properties:
               - ti,j721s2-evm
           - const: ti,j721s2
 
+      - description: K3 J722S SoC and Boards
+        items:
+          - enum:
+              - ti,j722s-evm
+          - const: ti,j722s
+
       - description: K3 J784s4 SoC
         items:
           - enum:
index b29ce598f9aaea327bcd177dc6bf143ee8693ebf..9952e0ef77674c11d115dab50a904841410e148a 100644 (file)
@@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Ceva AHCI SATA Controller
 
 maintainers:
-  - Piyush Mehta <piyush.mehta@amd.com>
+  - Mubin Sayyed <mubin.sayyed@amd.com>
+  - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
 
 description: |
   The Ceva SATA controller mostly conforms to the AHCI interface with some
diff --git a/Documentation/devicetree/bindings/bus/imx-weim.txt b/Documentation/devicetree/bindings/bus/imx-weim.txt
deleted file mode 100644 (file)
index e7f5020..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-Device tree bindings for i.MX Wireless External Interface Module (WEIM)
-
-The term "wireless" does not imply that the WEIM is literally an interface
-without wires. It simply means that this module was originally designed for
-wireless and mobile applications that use low-power technology.
-
-The actual devices are instantiated from the child nodes of a WEIM node.
-
-Required properties:
-
- - compatible:         Should contain one of the following:
-                         "fsl,imx1-weim"
-                         "fsl,imx27-weim"
-                         "fsl,imx51-weim"
-                         "fsl,imx50-weim"
-                         "fsl,imx6q-weim"
- - reg:                        A resource specifier for the register space
-                       (see the example below)
- - clocks:             the clock, see the example below.
- - #address-cells:     Must be set to 2 to allow memory address translation
- - #size-cells:                Must be set to 1 to allow CS address passing
- - ranges:             Must be set up to reflect the memory layout with four
-                       integer values for each chip-select line in use:
-
-                          <cs-number> 0 <physical address of mapping> <size>
-
-Optional properties:
-
- - fsl,weim-cs-gpr:    For "fsl,imx50-weim" and "fsl,imx6q-weim" type of
-                       devices, it should be the phandle to the system General
-                       Purpose Register controller that contains WEIM CS GPR
-                       register, e.g. IOMUXC_GPR1 on i.MX6Q.  IOMUXC_GPR1[11:0]
-                       should be set up as one of the following 4 possible
-                       values depending on the CS space configuration.
-
-                       IOMUXC_GPR1[11:0]    CS0    CS1    CS2    CS3
-                       ---------------------------------------------
-                               05          128M     0M     0M     0M
-                               033          64M    64M     0M     0M
-                               0113         64M    32M    32M     0M
-                               01111        32M    32M    32M    32M
-
-                       In case that the property is absent, the reset value or
-                       what bootloader sets up in IOMUXC_GPR1[11:0] will be
-                       used.
-
- - fsl,burst-clk-enable        For "fsl,imx50-weim" and "fsl,imx6q-weim" type of
-                       devices, the presence of this property indicates that
-                       the weim bus should operate in Burst Clock Mode.
-
- - fsl,continuous-burst-clk    Make Burst Clock to output continuous clock.
-                       Without this option Burst Clock will output clock
-                       only when necessary. This takes effect only if
-                       "fsl,burst-clk-enable" is set.
-
-Timing property for child nodes. It is mandatory, not optional.
-
- - fsl,weim-cs-timing: The timing array, contains timing values for the
-                       child node. We get the CS indexes from the address
-                       ranges in the child node's "reg" property.
-                       The number of registers depends on the selected chip:
-                       For i.MX1, i.MX21 ("fsl,imx1-weim") there are two
-                       registers: CSxU, CSxL.
-                       For i.MX25, i.MX27, i.MX31 and i.MX35 ("fsl,imx27-weim")
-                       there are three registers: CSCRxU, CSCRxL, CSCRxA.
-                       For i.MX50, i.MX53 ("fsl,imx50-weim"),
-                       i.MX51 ("fsl,imx51-weim") and i.MX6Q ("fsl,imx6q-weim")
-                       there are six registers: CSxGCR1, CSxGCR2, CSxRCR1,
-                       CSxRCR2, CSxWCR1, CSxWCR2.
-
-Example for an imx6q-sabreauto board, the NOR flash connected to the WEIM:
-
-       weim: weim@21b8000 {
-               compatible = "fsl,imx6q-weim";
-               reg = <0x021b8000 0x4000>;
-               clocks = <&clks 196>;
-               #address-cells = <2>;
-               #size-cells = <1>;
-               ranges = <0 0 0x08000000 0x08000000>;
-               fsl,weim-cs-gpr = <&gpr>;
-
-               nor@0,0 {
-                       compatible = "cfi-flash";
-                       reg = <0 0 0x02000000>;
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       bank-width = <2>;
-                       fsl,weim-cs-timing = <0x00620081 0x00000001 0x1c022000
-                                       0x0000c000 0x1404a38e 0x00000000>;
-               };
-       };
-
-Example for an imx6q-based board, a multi-chipselect device connected to WEIM:
-
-In this case, both chip select 0 and 1 will be configured with the same timing
-array values.
-
-       weim: weim@21b8000 {
-               compatible = "fsl,imx6q-weim";
-               reg = <0x021b8000 0x4000>;
-               clocks = <&clks 196>;
-               #address-cells = <2>;
-               #size-cells = <1>;
-               ranges = <0 0 0x08000000 0x02000000
-                         1 0 0x0a000000 0x02000000
-                         2 0 0x0c000000 0x02000000
-                         3 0 0x0e000000 0x02000000>;
-               fsl,weim-cs-gpr = <&gpr>;
-
-               acme@0 {
-                       compatible = "acme,whatever";
-                       reg = <0 0 0x100>, <0 0x400000 0x800>,
-                               <1 0x400000 0x800>;
-                       fsl,weim-cs-timing = <0x024400b1 0x00001010 0x20081100
-                               0x00000000 0xa0000240 0x00000000>;
-               };
-       };
index 3eebc03a309be24fca83f928ffeab18fed09b13b..1d2bcea41c8588b0dbe10c6c870e3d75f09b220b 100644 (file)
@@ -30,14 +30,16 @@ properties:
       - google,gs101-cmu-top
       - google,gs101-cmu-apm
       - google,gs101-cmu-misc
+      - google,gs101-cmu-peric0
+      - google,gs101-cmu-peric1
 
   clocks:
     minItems: 1
-    maxItems: 2
+    maxItems: 3
 
   clock-names:
     minItems: 1
-    maxItems: 2
+    maxItems: 3
 
   "#clock-cells":
     const: 1
@@ -85,8 +87,30 @@ allOf:
 
         clock-names:
           items:
-            - const: dout_cmu_misc_bus
-            - const: dout_cmu_misc_sss
+            - const: bus
+            - const: sss
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - google,gs101-cmu-peric0
+              - google,gs101-cmu-peric1
+
+    then:
+      properties:
+        clocks:
+          items:
+            - description: External reference clock (24.576 MHz)
+            - description: Connectivity Peripheral 0/1 bus clock (from CMU_TOP)
+            - description: Connectivity Peripheral 0/1 IP clock (from CMU_TOP)
+
+        clock-names:
+          items:
+            - const: oscclk
+            - const: bus
+            - const: ip
 
 additionalProperties: false
 
index 6c4846b34e4b504996bc9f8ec2fc83b4d67ae57b..a1085ef4fd05ad30d66a28855e82daf8a843485c 100644 (file)
@@ -31,10 +31,15 @@ properties:
       - const: bi_tcxo_ao
       - const: sleep_clk
 
+  power-domains:
+    items:
+      - description: CX domain
+
 required:
   - compatible
   - clocks
   - clock-names
+  - power-domains
 
 allOf:
   - $ref: qcom,gcc.yaml#
@@ -44,6 +49,7 @@ unevaluatedProperties: false
 examples:
   - |
     #include <dt-bindings/clock/qcom,rpmh.h>
+    #include <dt-bindings/power/qcom-rpmpd.h>
     clock-controller@100000 {
       compatible = "qcom,gcc-sc8180x";
       reg = <0x00100000 0x1f0000>;
@@ -51,6 +57,7 @@ examples:
                <&rpmhcc RPMH_CXO_CLK_A>,
                <&sleep_clk>;
       clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk";
+      power-domains = <&rpmhpd SC8180X_CX>;
       #clock-cells = <1>;
       #reset-cells = <1>;
       #power-domain-cells = <1>;
index 48986460f9947df633612907b2bf0674397a424b..fa0e5b6b02b817c4673c8b3000d60d198a8b144b 100644 (file)
@@ -17,6 +17,7 @@ description: |
     include/dt-bindings/clock/qcom,sm8450-camcc.h
     include/dt-bindings/clock/qcom,sm8550-camcc.h
     include/dt-bindings/clock/qcom,sc8280xp-camcc.h
+    include/dt-bindings/clock/qcom,x1e80100-camcc.h
 
 allOf:
   - $ref: qcom,gcc.yaml#
@@ -27,6 +28,7 @@ properties:
       - qcom,sc8280xp-camcc
       - qcom,sm8450-camcc
       - qcom,sm8550-camcc
+      - qcom,x1e80100-camcc
 
   clocks:
     items:
index 1a384e8532a59cc99f8e58e3df4b570b16668690..36974309cf6964b821a06d4be73dfb599617c17d 100644 (file)
@@ -18,6 +18,7 @@ description: |
     include/dt-bindings/clock/qcom,sm8550-gpucc.h
     include/dt-bindings/reset/qcom,sm8450-gpucc.h
     include/dt-bindings/reset/qcom,sm8650-gpucc.h
+    include/dt-bindings/reset/qcom,x1e80100-gpucc.h
 
 properties:
   compatible:
@@ -25,6 +26,7 @@ properties:
       - qcom,sm8450-gpucc
       - qcom,sm8550-gpucc
       - qcom,sm8650-gpucc
+      - qcom,x1e80100-gpucc
 
   clocks:
     items:
index c129f8c16b503b4cec31d004d12ac6771ac6d8c8..bad0260764d464b9bf360e50442016a610fa7915 100644 (file)
@@ -14,12 +14,17 @@ description: |
   Qualcomm display clock control module provides the clocks, resets and power
   domains on SM8550.
 
-  See also:: include/dt-bindings/clock/qcom,sm8550-dispcc.h
+  See also:
+  - include/dt-bindings/clock/qcom,sm8550-dispcc.h
+  - include/dt-bindings/clock/qcom,sm8650-dispcc.h
+  - include/dt-bindings/clock/qcom,x1e80100-dispcc.h
 
 properties:
   compatible:
     enum:
       - qcom,sm8550-dispcc
+      - qcom,sm8650-dispcc
+      - qcom,x1e80100-dispcc
 
   clocks:
     items:
index af16b05eac96e4894b2d5c664410ace34c8a74bd..48fdd562d7439424ebf4cc7ff43cc0c381bde524 100644 (file)
@@ -23,6 +23,7 @@ properties:
       - enum:
           - qcom,sm8550-tcsr
           - qcom,sm8650-tcsr
+          - qcom,x1e80100-tcsr
       - const: syscon
 
   clocks:
diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8650-dispcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8650-dispcc.yaml
deleted file mode 100644 (file)
index 5e0c45c..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/clock/qcom,sm8650-dispcc.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Qualcomm Display Clock & Reset Controller for SM8650
-
-maintainers:
-  - Bjorn Andersson <andersson@kernel.org>
-  - Neil Armstrong <neil.armstrong@linaro.org>
-
-description: |
-  Qualcomm display clock control module provides the clocks, resets and power
-  domains on SM8650.
-
-  See also:: include/dt-bindings/clock/qcom,sm8650-dispcc.h
-
-properties:
-  compatible:
-    enum:
-      - qcom,sm8650-dispcc
-
-  clocks:
-    items:
-      - description: Board XO source
-      - description: Board Always On XO source
-      - description: Display's AHB clock
-      - description: sleep clock
-      - description: Byte clock from DSI PHY0
-      - description: Pixel clock from DSI PHY0
-      - description: Byte clock from DSI PHY1
-      - description: Pixel clock from DSI PHY1
-      - description: Link clock from DP PHY0
-      - description: VCO DIV clock from DP PHY0
-      - description: Link clock from DP PHY1
-      - description: VCO DIV clock from DP PHY1
-      - description: Link clock from DP PHY2
-      - description: VCO DIV clock from DP PHY2
-      - description: Link clock from DP PHY3
-      - description: VCO DIV clock from DP PHY3
-
-  '#clock-cells':
-    const: 1
-
-  '#reset-cells':
-    const: 1
-
-  '#power-domain-cells':
-    const: 1
-
-  reg:
-    maxItems: 1
-
-  power-domains:
-    description:
-      A phandle and PM domain specifier for the MMCX power domain.
-    maxItems: 1
-
-  required-opps:
-    description:
-      A phandle to an OPP node describing required MMCX performance point.
-    maxItems: 1
-
-required:
-  - compatible
-  - reg
-  - clocks
-  - '#clock-cells'
-  - '#reset-cells'
-  - '#power-domain-cells'
-
-additionalProperties: false
-
-examples:
-  - |
-    #include <dt-bindings/clock/qcom,sm8650-gcc.h>
-    #include <dt-bindings/clock/qcom,rpmh.h>
-    #include <dt-bindings/power/qcom-rpmpd.h>
-    #include <dt-bindings/power/qcom,rpmhpd.h>
-    clock-controller@af00000 {
-      compatible = "qcom,sm8650-dispcc";
-      reg = <0x0af00000 0x10000>;
-      clocks = <&rpmhcc RPMH_CXO_CLK>,
-               <&rpmhcc RPMH_CXO_CLK_A>,
-               <&gcc GCC_DISP_AHB_CLK>,
-               <&sleep_clk>,
-               <&dsi0_phy 0>,
-               <&dsi0_phy 1>,
-               <&dsi1_phy 0>,
-               <&dsi1_phy 1>,
-               <&dp0_phy 0>,
-               <&dp0_phy 1>,
-               <&dp1_phy 0>,
-               <&dp1_phy 1>,
-               <&dp2_phy 0>,
-               <&dp2_phy 1>,
-               <&dp3_phy 0>,
-               <&dp3_phy 1>;
-      #clock-cells = <1>;
-      #reset-cells = <1>;
-      #power-domain-cells = <1>;
-      power-domains = <&rpmhpd RPMHPD_MMCX>;
-      required-opps = <&rpmhpd_opp_low_svs>;
-    };
-...
index 9c3dc6c4fa94218ced7148777399a2f5741143f8..084259d30232aa6814483fd901aab357d95c5474 100644 (file)
@@ -50,6 +50,7 @@ properties:
       - renesas,r8a779a0-cpg-mssr # R-Car V3U
       - renesas,r8a779f0-cpg-mssr # R-Car S4-8
       - renesas,r8a779g0-cpg-mssr # R-Car V4H
+      - renesas,r8a779h0-cpg-mssr # R-Car V4M
 
   reg:
     maxItems: 1
index 21d995f29a1e3068be328506cf01d8f0f5d3d383..b8e9cf6ce4e61145bb6a30d90396b982449b2f08 100644 (file)
@@ -29,19 +29,22 @@ properties:
 
   audio-ports:
     description:
-      Array of 8-bit values, 2 values per DAI (Documentation/sound/soc/dai.rst).
+      Array of 2 values per DAI (Documentation/sound/soc/dai.rst).
       The implementation allows one or two DAIs.
       If two DAIs are defined, they must be of different type.
     $ref: /schemas/types.yaml#/definitions/uint32-matrix
+    minItems: 1
+    maxItems: 2
     items:
-      minItems: 1
       items:
         - description: |
             The first value defines the DAI type: TDA998x_SPDIF or TDA998x_I2S
             (see include/dt-bindings/display/tda998x.h).
+          enum: [ 1, 2 ]
         - description:
             The second value defines the tda998x AP_ENA reg content when the
             DAI in question is used.
+          maximum: 0xff
 
   '#sound-dai-cells':
     enum: [ 0, 1 ]
index bc92928c805b9a10900552fce47c06a4d26c5a54..619edcf6c79183c09d944e9522cbb50b1fef2290 100644 (file)
@@ -29,6 +29,7 @@ properties:
   vddi-supply:
     description: regulator that supplies the vddi voltage
   backlight: true
+  port: true
 
 required:
   - compatible
index 8e584857ddd4fb9d93cf4607805b8e38589e7cb8..ab8f32c440dfa905f9979feb7ef6104988cac960 100644 (file)
@@ -26,6 +26,12 @@ properties:
       - description: For implementations complying for Versal.
         const: xlnx,versal-firmware
 
+      - description: For implementations complying for Versal NET.
+        items:
+          - enum:
+              - xlnx,versal-net-firmware
+          - const: xlnx,versal-firmware
+
   method:
     description: |
                  The method of calling the PM-API firmware layer.
@@ -41,7 +47,53 @@ properties:
   "#power-domain-cells":
     const: 1
 
-  versal_fpga:
+  clock-controller:
+    $ref: /schemas/clock/xlnx,versal-clk.yaml#
+    description: The clock controller is a hardware block of Xilinx versal
+      clock tree. It reads required input clock frequencies from the devicetree
+      and acts as clock provider for all clock consumers of PS clocks.list of
+      clock specifiers which are external input clocks to the given clock
+      controller.
+    type: object
+
+  gpio:
+    $ref: /schemas/gpio/xlnx,zynqmp-gpio-modepin.yaml#
+    description: The gpio node describes connect to PS_MODE pins via firmware
+      interface.
+    type: object
+
+  soc-nvmem:
+    $ref: /schemas/nvmem/xlnx,zynqmp-nvmem.yaml#
+    description: The ZynqMP MPSoC provides access to the hardware related data
+      like SOC revision, IDCODE and specific purpose efuses.
+    type: object
+
+  pcap:
+    $ref: /schemas/fpga/xlnx,zynqmp-pcap-fpga.yaml
+    description: The ZynqMP SoC uses the PCAP (Processor Configuration Port) to
+      configure the Programmable Logic (PL). The configuration uses the
+      firmware interface.
+    type: object
+
+  pinctrl:
+    $ref: /schemas/pinctrl/xlnx,zynqmp-pinctrl.yaml#
+    description: The pinctrl node provides access to pinconfig and pincontrol
+      functionality available in firmware.
+    type: object
+
+  power-management:
+    $ref: /schemas/power/reset/xlnx,zynqmp-power.yaml#
+    description: The zynqmp-power node describes the power management
+      configurations. It will control remote suspend/shutdown interfaces.
+    type: object
+
+  reset-controller:
+    $ref: /schemas/reset/xlnx,zynqmp-reset.yaml#
+    description: The reset-controller node describes connection to the reset
+      functionality via firmware interface.
+    type: object
+
+  versal-fpga:
     $ref: /schemas/fpga/xlnx,versal-fpga.yaml#
     description: Compatible of the FPGA device.
     type: object
@@ -53,15 +105,6 @@ properties:
       vector.
     type: object
 
-  clock-controller:
-    $ref: /schemas/clock/xlnx,versal-clk.yaml#
-    description: The clock controller is a hardware block of Xilinx versal
-      clock tree. It reads required input clock frequencies from the devicetree
-      and acts as clock provider for all clock consumers of PS clocks.list of
-      clock specifiers which are external input clocks to the given clock
-      controller.
-    type: object
-
 required:
   - compatible
 
@@ -73,7 +116,38 @@ examples:
     firmware {
       zynqmp_firmware: zynqmp-firmware {
         #power-domain-cells = <1>;
+        soc-nvmem {
+          compatible = "xlnx,zynqmp-nvmem-fw";
+          nvmem-layout {
+            compatible = "fixed-layout";
+            #address-cells = <1>;
+            #size-cells = <1>;
+
+            soc_revision: soc-revision@0 {
+                reg = <0x0 0x4>;
+            };
+          };
+        };
+        gpio {
+          compatible = "xlnx,zynqmp-gpio-modepin";
+          gpio-controller;
+          #gpio-cells = <2>;
+        };
+        pcap {
+          compatible = "xlnx,zynqmp-pcap-fpga";
         };
+        pinctrl {
+          compatible = "xlnx,zynqmp-pinctrl";
+        };
+        power-management {
+          compatible = "xlnx,zynqmp-power";
+          interrupts = <0 35 4>;
+        };
+        reset-controller {
+          compatible = "xlnx,zynqmp-reset";
+          #reset-cells = <1>;
+        };
+      };
     };
 
     sata {
@@ -84,7 +158,7 @@ examples:
       compatible = "xlnx,versal-firmware";
       method = "smc";
 
-      versal_fpga: versal_fpga {
+      versal_fpga: versal-fpga {
         compatible = "xlnx,versal-fpga";
       };
 
index 26f18834caa3aeaeea769cb4d193fc0b3755cf61..80833462f620f397913ecf9907acf5c0e411bb30 100644 (file)
@@ -26,7 +26,7 @@ additionalProperties: false
 
 examples:
   - |
-    versal_fpga: versal_fpga {
+    versal_fpga: versal-fpga {
          compatible = "xlnx,versal-fpga";
     };
 
index b1fd632718d49659483fd7e6773377adeb66d938..bb93baa888794b83d1613cecca79a383b528914a 100644 (file)
@@ -12,7 +12,8 @@ description:
   PS_MODE). Every pin can be configured as input/output.
 
 maintainers:
-  - Piyush Mehta <piyush.mehta@amd.com>
+  - Mubin Sayyed <mubin.sayyed@amd.com>
+  - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
 
 properties:
   compatible:
similarity index 91%
rename from Documentation/devicetree/bindings/gpu/img,powervr.yaml
rename to Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml
index a13298f1a182752de6824d3537bd41b3fc03a483..256e252f8087fa0d6081f771a01601d34b66fe19 100644 (file)
@@ -2,10 +2,10 @@
 # Copyright (c) 2023 Imagination Technologies Ltd.
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/gpu/img,powervr.yaml#
+$id: http://devicetree.org/schemas/gpu/img,powervr-rogue.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Imagination Technologies PowerVR and IMG GPU
+title: Imagination Technologies PowerVR and IMG Rogue GPUs
 
 maintainers:
   - Frank Binns <frank.binns@imgtec.com>
diff --git a/Documentation/devicetree/bindings/gpu/img,powervr-sgx.yaml b/Documentation/devicetree/bindings/gpu/img,powervr-sgx.yaml
new file mode 100644 (file)
index 0000000..f5898b0
--- /dev/null
@@ -0,0 +1,138 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2023 Imagination Technologies Ltd.
+# Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpu/img,powervr-sgx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Imagination Technologies PowerVR SGX GPUs
+
+maintainers:
+  - Frank Binns <frank.binns@imgtec.com>
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - ti,omap3430-gpu # Rev 121
+              - ti,omap3630-gpu # Rev 125
+          - const: img,powervr-sgx530
+      - items:
+          - enum:
+              - ingenic,jz4780-gpu # Rev 130
+              - ti,omap4430-gpu # Rev 120
+          - const: img,powervr-sgx540
+      - items:
+          - enum:
+              - allwinner,sun6i-a31-gpu # MP2 Rev 115
+              - ti,omap4470-gpu # MP1 Rev 112
+              - ti,omap5432-gpu # MP2 Rev 105
+              - ti,am5728-gpu # MP2 Rev 116
+              - ti,am6548-gpu # MP1 Rev 117
+          - const: img,powervr-sgx544
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    minItems: 1
+    maxItems: 3
+
+  clock-names:
+    minItems: 1
+    items:
+      - const: core
+      - const: mem
+      - const: sys
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: ti,am6548-gpu
+    then:
+      required:
+        - power-domains
+    else:
+      properties:
+        power-domains: false
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - allwinner,sun6i-a31-gpu
+              - ingenic,jz4780-gpu
+    then:
+      required:
+        - clocks
+        - clock-names
+    else:
+      properties:
+        clocks: false
+        clock-names: false
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: allwinner,sun6i-a31-gpu
+    then:
+      properties:
+        clocks:
+          minItems: 2
+          maxItems: 2
+        clock-names:
+          minItems: 2
+          maxItems: 2
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: ingenic,jz4780-gpu
+    then:
+      properties:
+        clocks:
+          maxItems: 1
+        clock-names:
+          maxItems: 1
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/soc/ti,sci_pm_domain.h>
+
+    gpu@7000000 {
+        compatible = "ti,am6548-gpu", "img,powervr-sgx544";
+        reg = <0x7000000 0x10000>;
+        interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
+        power-domains = <&k3_pds 65 TI_SCI_PD_EXCLUSIVE>;
+    };
+
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    gpu: gpu@1c40000 {
+        compatible = "allwinner,sun6i-a31-gpu", "img,powervr-sgx544";
+        reg = <0x01c40000 0x10000>;
+        interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&ccu 1>, <&ccu 2>;
+        clock-names = "core", "mem";
+    };
index df9c57bca2a89cd81ac4d6c8eabf4ec24f51a171..cc8bba5537b94b67b04cc5d791e882160a63530e 100644 (file)
@@ -33,6 +33,7 @@ properties:
           - const: samsung,exynos7-hsi2c
       - items:
           - enum:
+              - google,gs101-hsi2c
               - samsung,exynos850-hsi2c
           - const: samsung,exynosautov9-hsi2c
       - const: samsung,exynos5-hsi2c    # Exynos5250 and Exynos5420
index 3d06db98e978000a6db760bb87d35d9d36621a70..a93744763787d0b901e530d7e13eea8682ae8c2b 100644 (file)
@@ -36,6 +36,7 @@ properties:
               - amlogic,meson-a1-gpio-intc
               - amlogic,meson-s4-gpio-intc
               - amlogic,c3-gpio-intc
+              - amlogic,t7-gpio-intc
           - const: amlogic,meson-gpio-intc
 
   reg:
diff --git a/Documentation/devicetree/bindings/interrupt-controller/starfive,jh8100-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/starfive,jh8100-intc.yaml
new file mode 100644 (file)
index 0000000..ada5788
--- /dev/null
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/starfive,jh8100-intc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive External Interrupt Controller
+
+description:
+  StarFive SoC JH8100 contain a external interrupt controller. It can be used
+  to handle high-level input interrupt signals. It also send the output
+  interrupt signal to RISC-V PLIC.
+
+maintainers:
+  - Changhuang Liang <changhuang.liang@starfivetech.com>
+
+properties:
+  compatible:
+    const: starfive,jh8100-intc
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    description: APB clock for the interrupt controller
+    maxItems: 1
+
+  resets:
+    description: APB reset for the interrupt controller
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - resets
+  - interrupts
+  - interrupt-controller
+  - "#interrupt-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    interrupt-controller@12260000 {
+      compatible = "starfive,jh8100-intc";
+      reg = <0x12260000 0x10000>;
+      clocks = <&syscrg_ne 76>;
+      resets = <&syscrg_ne 13>;
+      interrupts = <45>;
+      interrupt-controller;
+      #interrupt-cells = <1>;
+    };
index a2051b31fa29d332e889ce5456e1524af6efd443..b45743d0a9ec09752ff0c632ea30d16ea5ea10ab 100644 (file)
@@ -16,14 +16,18 @@ description: |+
 
 properties:
   compatible:
-    enum:
-      - mediatek,mt8173-vcodec-enc-vp8
-      - mediatek,mt8173-vcodec-enc
-      - mediatek,mt8183-vcodec-enc
-      - mediatek,mt8188-vcodec-enc
-      - mediatek,mt8192-vcodec-enc
-      - mediatek,mt8195-vcodec-enc
-
+    oneOf:
+      - items:
+          - enum:
+              - mediatek,mt8173-vcodec-enc-vp8
+              - mediatek,mt8173-vcodec-enc
+              - mediatek,mt8183-vcodec-enc
+              - mediatek,mt8188-vcodec-enc
+              - mediatek,mt8192-vcodec-enc
+              - mediatek,mt8195-vcodec-enc
+      - items:
+          - const: mediatek,mt8186-vcodec-enc
+          - const: mediatek,mt8183-vcodec-enc
   reg:
     maxItems: 1
 
@@ -109,10 +113,7 @@ allOf:
       properties:
         compatible:
           enum:
-            - mediatek,mt8173-vcodec-enc
-            - mediatek,mt8188-vcodec-enc
-            - mediatek,mt8192-vcodec-enc
-            - mediatek,mt8195-vcodec-enc
+            - mediatek,mt8173-vcodec-enc-vp8
 
     then:
       properties:
@@ -122,8 +123,8 @@ allOf:
             maxItems: 1
         clock-names:
           items:
-            - const: venc_sel
-    else:  # for vp8 hw encoder
+            - const: venc_lt_sel
+    else:
       properties:
         clock:
           items:
@@ -131,7 +132,7 @@ allOf:
             maxItems: 1
         clock-names:
           items:
-            - const: venc_lt_sel
+            - const: venc_sel
 
 additionalProperties: false
 
index 37800e1908cc9396314bf0c5ac4f8072a8a7a371..83c020a673d6e6fba706133c76d09ae1c78945ea 100644 (file)
@@ -38,7 +38,8 @@ properties:
     maxItems: 1
 
   iommus:
-    maxItems: 2
+    minItems: 2
+    maxItems: 4
     description: |
       Points to the respective IOMMU block with master port as argument, see
       Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details.
diff --git a/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim-peripherals.yaml b/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim-peripherals.yaml
new file mode 100644 (file)
index 0000000..82fc5f4
--- /dev/null
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/fsl/fsl,imx-weim-peripherals.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX WEIM Bus Peripheral Nodes
+
+maintainers:
+  - Shawn Guo <shawnguo@kernel.org>
+  - Sascha Hauer <s.hauer@pengutronix.de>
+
+description:
+  This binding is meant for the child nodes of the WEIM node. The node
+  represents any device connected to the WEIM bus. It may be a Flash chip,
+  RAM chip or Ethernet controller, etc. These properties are meant for
+  configuring the WEIM settings/timings and will accompany the bindings
+  supported by the respective device.
+
+properties:
+  reg: true
+
+  fsl,weim-cs-timing:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description:
+      Timing values for the child node.
+    minItems: 2
+    maxItems: 6
+
+# the WEIM child will have its own native properties
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim.yaml b/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim.yaml
new file mode 100644 (file)
index 0000000..3f40ca5
--- /dev/null
@@ -0,0 +1,204 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/fsl/fsl,imx-weim.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX Wireless External Interface Module (WEIM)
+
+maintainers:
+  - Shawn Guo <shawnguo@kernel.org>
+  - Sascha Hauer <s.hauer@pengutronix.de>
+
+description:
+  The term "wireless" does not imply that the WEIM is literally an interface
+  without wires. It simply means that this module was originally designed for
+  wireless and mobile applications that use low-power technology. The actual
+  devices are instantiated from the child nodes of a WEIM node.
+
+properties:
+  $nodename:
+    pattern: "^memory-controller@[0-9a-f]+$"
+
+  compatible:
+    oneOf:
+      - enum:
+          - fsl,imx1-weim
+          - fsl,imx27-weim
+          - fsl,imx50-weim
+          - fsl,imx51-weim
+          - fsl,imx6q-weim
+      - items:
+          - enum:
+              - fsl,imx31-weim
+              - fsl,imx35-weim
+          - const: fsl,imx27-weim
+      - items:
+          - enum:
+              - fsl,imx6sx-weim
+              - fsl,imx6ul-weim
+          - const: fsl,imx6q-weim
+
+  "#address-cells":
+    const: 2
+
+  "#size-cells":
+    const: 1
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  ranges: true
+
+  fsl,weim-cs-gpr:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: |
+      Phandle to the system General Purpose Register controller that contains
+      WEIM CS GPR register, e.g. IOMUXC_GPR1 on i.MX6Q. IOMUXC_GPR1[11:0]
+      should be set up as one of the following 4 possible values depending on
+      the CS space configuration.
+
+      IOMUXC_GPR1[11:0]    CS0    CS1    CS2    CS3
+      ---------------------------------------------
+              05          128M     0M     0M     0M
+              033          64M    64M     0M     0M
+              0113         64M    32M    32M     0M
+              01111        32M    32M    32M    32M
+
+      In case that the property is absent, the reset value or what bootloader
+      sets up in IOMUXC_GPR1[11:0] will be used.
+
+  fsl,burst-clk-enable:
+    type: boolean
+    description:
+      The presence of this property indicates that the weim bus should operate
+      in Burst Clock Mode.
+
+  fsl,continuous-burst-clk:
+    type: boolean
+    description:
+      Make Burst Clock to output continuous clock. Without this option Burst
+      Clock will output clock only when necessary.
+
+patternProperties:
+  "^.*@[0-7],[0-9a-f]+$":
+    type: object
+    description: Devices attached to chip selects are represented as subnodes.
+    $ref: fsl,imx-weim-peripherals.yaml
+    additionalProperties: true
+    required:
+      - fsl,weim-cs-timing
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - "#address-cells"
+  - "#size-cells"
+  - ranges
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          not:
+            contains:
+              enum:
+                - fsl,imx50-weim
+                - fsl,imx6q-weim
+    then:
+      properties:
+        fsl,weim-cs-gpr: false
+        fsl,burst-clk-enable: false
+  - if:
+      not:
+        required:
+          - fsl,burst-clk-enable
+    then:
+      properties:
+        fsl,continuous-burst-clk: false
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: fsl,imx1-weim
+    then:
+      patternProperties:
+        "^.*@[0-7],[0-9a-f]+$":
+          properties:
+            fsl,weim-cs-timing:
+              items:
+                items:
+                  - description: CSxU
+                  - description: CSxL
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx27-weim
+              - fsl,imx31-weim
+              - fsl,imx35-weim
+    then:
+      patternProperties:
+        "^.*@[0-7],[0-9a-f]+$":
+          properties:
+            fsl,weim-cs-timing:
+              items:
+                items:
+                  - description: CSCRxU
+                  - description: CSCRxL
+                  - description: CSCRxA
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - fsl,imx50-weim
+              - fsl,imx51-weim
+              - fsl,imx6q-weim
+              - fsl,imx6sx-weim
+              - fsl,imx6ul-weim
+    then:
+      patternProperties:
+        "^.*@[0-7],[0-9a-f]+$":
+          properties:
+            fsl,weim-cs-timing:
+              items:
+                items:
+                  - description: CSxGCR1
+                  - description: CSxGCR2
+                  - description: CSxRCR1
+                  - description: CSxRCR2
+                  - description: CSxWCR1
+                  - description: CSxWCR2
+
+additionalProperties: false
+
+examples:
+  - |
+    memory-controller@21b8000 {
+        compatible = "fsl,imx6q-weim";
+        reg = <0x021b8000 0x4000>;
+        clocks = <&clks 196>;
+        #address-cells = <2>;
+        #size-cells = <1>;
+        ranges = <0 0 0x08000000 0x08000000>;
+        fsl,weim-cs-gpr = <&gpr>;
+
+        flash@0,0 {
+            compatible = "cfi-flash";
+            reg = <0 0 0x02000000>;
+            #address-cells = <1>;
+            #size-cells = <1>;
+            bank-width = <2>;
+            fsl,weim-cs-timing = <0x00620081 0x00000001 0x1c022000
+                                  0x0000c000 0x1404a38e 0x00000000>;
+        };
+    };
index 8d9dae15ade00e15e7453bb1fc8070c8b5c79aa9..00deeb09f87d5c2b5700d93a663b278e3e1d03e0 100644 (file)
@@ -37,5 +37,6 @@ allOf:
   - $ref: ingenic,nemc-peripherals.yaml#
   - $ref: intel,ixp4xx-expansion-peripheral-props.yaml#
   - $ref: ti,gpmc-child.yaml#
+  - $ref: fsl/fsl,imx-weim-peripherals.yaml
 
 additionalProperties: true
index f54e553e6c0e6a6e4c0d56e485f567f814dcaf12..71896cb10692630a78c21bf9fdb81491680cdd31 100644 (file)
@@ -145,7 +145,7 @@ patternProperties:
   "^emc-table@[0-9]+$":
     $ref: "#/$defs/emc-table"
 
-  "^emc-tables@[a-z0-9-]+$":
+  "^emc-tables@[a-f0-9-]+$":
     type: object
     properties:
       reg:
index 25f3bb9890ae624a71bf65a06f2fe639ac89853c..d7745dd53b51ce471e360fcc55f9cbb51af9007c 100644 (file)
@@ -45,6 +45,7 @@ properties:
       - items:
           - enum:
               - renesas,r8a779g0-rpc-if       # R-Car V4H
+              - renesas,r8a779h0-rpc-if       # R-Car V4M
           - const: renesas,rcar-gen4-rpc-if   # a generic R-Car gen4 device
 
       - items:
index 14f1833d37c9b8cb10226e204488914acfd07769..84ac6f50a6fc3ff23968beb1d3c7b1f251692186 100644 (file)
@@ -23,7 +23,9 @@ maintainers:
 
 properties:
   compatible:
-    const: st,stm32mp1-fmc2-ebi
+    enum:
+      - st,stm32mp1-fmc2-ebi
+      - st,stm32mp25-fmc2-ebi
 
   reg:
     maxItems: 1
@@ -34,6 +36,9 @@ properties:
   resets:
     maxItems: 1
 
+  power-domains:
+    maxItems: 1
+
   "#address-cells":
     const: 2
 
index 5ea8b73663a50c3f55999fb8cc911af491d46086..16ff892f7bbd0aa8f965d602e5ccbd3b18ec9253 100644 (file)
@@ -78,8 +78,8 @@ examples:
     pcie@0 {
         #address-cells = <3>;
         #size-cells = <2>;
-        ranges = <0x0 0x0 0x0 0x0 0x0 0x0>;
-        reg = <0x0 0x0 0x0 0x0 0x0 0x0>;
+        ranges = <0x02000000 0x0 0x100000 0x10000000 0x0 0x0>;
+        reg = <0x0 0x1000>;
         device_type = "pci";
 
         switch@0,0 {
index 475aff7714d6419a9cb7266c65bffffce733b29d..ea35d19be829a37a657f6a3fb45153981ea16fb9 100644 (file)
@@ -65,9 +65,11 @@ properties:
 
   rx-internal-delay-ps:
     enum: [0, 1800]
+    default: 0
 
   tx-internal-delay-ps:
     enum: [0, 2000]
+    default: 0
 
   '#address-cells':
     const: 1
index 0720b54881c2c87a8c10ca3f2454ed3c9d77fce1..e76fb273490ff5885e0ea492db8ddb331a00abd5 100644 (file)
@@ -45,6 +45,7 @@ properties:
       - renesas,r8a779a0-sysc # R-Car V3U
       - renesas,r8a779f0-sysc # R-Car S4-8
       - renesas,r8a779g0-sysc # R-Car V4H
+      - renesas,r8a779h0-sysc # R-Car V4M
 
   reg:
     maxItems: 1
index e7e4872477517b2d3081ed607bfea3e56987e132..58b4a45d338006ff923d1a01d1a77245ebde194f 100644 (file)
@@ -50,6 +50,7 @@ properties:
       - renesas,r8a779a0-rst      # R-Car V3U
       - renesas,r8a779f0-rst      # R-Car S4-8
       - renesas,r8a779g0-rst      # R-Car V4H
+      - renesas,r8a779h0-rst      # R-Car V4M
 
   reg:
     maxItems: 1
index 49db668014297040f85b628137769951663992ed..1f1b42dde94d5086020f0a89d183eafa1ea17589 100644 (file)
@@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Zynq UltraScale+ MPSoC and Versal reset
 
 maintainers:
-  - Piyush Mehta <piyush.mehta@amd.com>
+  - Mubin Sayyed <mubin.sayyed@amd.com>
+  - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
 
 description: |
   The Zynq UltraScale+ MPSoC and Versal has several different resets.
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,pbs.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,pbs.yaml
new file mode 100644 (file)
index 0000000..b502ca7
--- /dev/null
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/qcom/qcom,pbs.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies, Inc. Programmable Boot Sequencer
+
+maintainers:
+  - Anjelique Melendez <quic_amelende@quicinc.com>
+
+description: |
+  The Qualcomm Technologies, Inc. Programmable Boot Sequencer (PBS)
+  supports triggering power up and power down sequences for clients
+  upon request.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - qcom,pmi632-pbs
+      - const: qcom,pbs
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/spmi/spmi.h>
+
+    pmic@0 {
+      reg = <0x0 SPMI_USID>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      pbs@7400 {
+        compatible = "qcom,pmi632-pbs", "qcom,pbs";
+        reg = <0x7400>;
+      };
+    };
index 61df97ffe1e409b49c35e4c219d85a98ca563e74..d3f3259ef77d5c8ef1ae9abe1cbd0620b462d715 100644 (file)
@@ -32,6 +32,7 @@ properties:
       - items:
           - enum:
               - qcom,sm8650-pmic-glink
+              - qcom,x1e80100-pmic-glink
           - const: qcom,sm8550-pmic-glink
           - const: qcom,pmic-glink
 
@@ -65,6 +66,7 @@ allOf:
               enum:
                 - qcom,sm8450-pmic-glink
                 - qcom,sm8550-pmic-glink
+                - qcom,x1e80100-pmic-glink
     then:
       properties:
         orientation-gpios: false
index 031800985b5ebf7ef6bd9b775327097e78b38ecc..9410404f87f1afb864c79614ada2659745a37ae9 100644 (file)
@@ -35,6 +35,8 @@ properties:
     description: Phandle to an RPM MSG RAM slice containing the master stats
     minItems: 1
     maxItems: 5
+    items:
+      maxItems: 1
 
   qcom,master-names:
     $ref: /schemas/types.yaml#/definitions/string-array
similarity index 53%
rename from Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml
rename to Documentation/devicetree/bindings/soc/qcom/qcom,saw2.yaml
index 20c8cd38ff0d3e985565fdfbe2202c8748a02d23..ca4bce81727381b0ecd1278e58b7027365ab85fb 100644 (file)
@@ -1,23 +1,33 @@
 # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/soc/qcom/qcom,spm.yaml#
+$id: http://devicetree.org/schemas/soc/qcom/qcom,saw2.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Qualcomm Subsystem Power Manager
+title: Qualcomm Subsystem Power Manager / SPM AVS Wrapper 2 (SAW2)
 
 maintainers:
   - Andy Gross <agross@kernel.org>
   - Bjorn Andersson <bjorn.andersson@linaro.org>
 
 description: |
-  This binding describes the Qualcomm Subsystem Power Manager, used to control
-  the peripheral logic surrounding the application cores in Qualcomm platforms.
+  The Qualcomm Subsystem Power Manager is used to control the peripheral logic
+  surrounding the application cores in Qualcomm platforms.
+
+  The SAW2 is a wrapper around the Subsystem Power Manager (SPM) and the
+  Adaptive Voltage Scaling (AVS) hardware. The SPM is a programmable
+  power-controller that transitions a piece of hardware (like a processor or
+  subsystem) into and out of low power modes via a direct connection to
+  the PMIC. It can also be wired up to interact with other processors in the
+  system, notifying them when a low power state is entered or exited.
 
 properties:
   compatible:
     items:
       - enum:
+          - qcom,ipq4019-saw2-cpu
+          - qcom,ipq4019-saw2-l2
+          - qcom,ipq8064-saw2-cpu
           - qcom,sdm660-gold-saw2-v4.1-l2
           - qcom,sdm660-silver-saw2-v4.1-l2
           - qcom,msm8998-gold-saw2-v4.1-l2
@@ -26,16 +36,27 @@ properties:
           - qcom,msm8916-saw2-v3.0-cpu
           - qcom,msm8939-saw2-v3.0-cpu
           - qcom,msm8226-saw2-v2.1-cpu
+          - qcom,msm8226-saw2-v2.1-l2
+          - qcom,msm8960-saw2-cpu
           - qcom,msm8974-saw2-v2.1-cpu
+          - qcom,msm8974-saw2-v2.1-l2
           - qcom,msm8976-gold-saw2-v2.3-l2
           - qcom,msm8976-silver-saw2-v2.3-l2
           - qcom,apq8084-saw2-v2.1-cpu
+          - qcom,apq8084-saw2-v2.1-l2
           - qcom,apq8064-saw2-v1.1-cpu
       - const: qcom,saw2
 
   reg:
-    description: Base address and size of the SPM register region
-    maxItems: 1
+    items:
+      - description: Base address and size of the SPM register region
+      - description: Base address and size of the alias register region
+    minItems: 1
+
+  regulator:
+    $ref: /schemas/regulator/regulator.yaml#
+    description: Indicates that this SPM device acts as a regulator device
+      device for the core (CPU or Cache) the SPM is attached to.
 
 required:
   - compatible
@@ -82,4 +103,17 @@ examples:
         reg = <0x17912000 0x1000>;
     };
 
+  - |
+    /*
+     * Example 3: SAW2 with the bundled regulator definition.
+     */
+    power-manager@2089000 {
+        compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2";
+        reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
+
+        regulator {
+            regulator-min-microvolt = <850000>;
+            regulator-max-microvolt = <1300000>;
+        };
+    };
 ...
diff --git a/Documentation/devicetree/bindings/soc/renesas/renesas-soc.yaml b/Documentation/devicetree/bindings/soc/renesas/renesas-soc.yaml
new file mode 100644 (file)
index 0000000..5ddd31f
--- /dev/null
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/renesas/renesas-soc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas SoC compatibles naming convention
+
+maintainers:
+  - Geert Uytterhoeven <geert+renesas@glider.be>
+  - Niklas Söderlund <niklas.soderlund@ragnatech.se>
+
+description: |
+  Guidelines for new compatibles for SoC blocks/components.
+  When adding new compatibles in new bindings, use the format::
+    renesas,SoC-IP
+
+  For example::
+   renesas,r8a77965-csi2
+
+  When adding new compatibles to existing bindings, use the format in the
+  existing binding, even if it contradicts the above.
+
+select:
+  properties:
+    compatible:
+      contains:
+        pattern: "^renesas,.+-.+$"
+  required:
+    - compatible
+
+properties:
+  compatible:
+    minItems: 1
+    maxItems: 4
+    items:
+      anyOf:
+        # Preferred naming style for compatibles of SoC components
+        - pattern: "^renesas,(emev2|r(7s|8a|9a)[a-z0-9]+|rcar|rmobile|rz[a-z0-9]*|sh(7[a-z0-9]+)?|mobile)-[a-z0-9-]+$"
+        - pattern: "^renesas,(condor|falcon|gr-peach|gray-hawk|salvator|sk-rz|smar(c(2)?)?|spider|white-hawk)(.*)?$"
+
+        # Legacy compatibles
+        #
+        # New compatibles are not allowed.
+        - pattern: "^renesas,(can|cpg|dmac|du|(g)?ether(avb)?|gpio|hscif|(r)?i[i2]c|imr|intc|ipmmu|irqc|jpu|mmcif|msiof|mtu2|pci(e)?|pfc|pwm|[rq]spi|rcar_sound|sata|scif[ab]*|sdhi|thermal|tmu|tpu|usb(2|hs)?|vin|xhci)-[a-z0-9-]+$"
+        - pattern: "^renesas,(d|s)?bsc(3)?-(r8a73a4|r8a7740|sh73a0)$"
+        - pattern: "^renesas,em-(gio|sti|uart)$"
+        - pattern: "^renesas,fsi2-(r8a7740|sh73a0)$"
+        - pattern: "^renesas,hspi-r8a777[89]$"
+        - pattern: "^renesas,sysc-(r8a73a4|r8a7740|rmobile|sh73a0)$"
+        - enum:
+            - renesas,imr-lx4
+            - renesas,mtu2-r7s72100
+
+        # None SoC component compatibles
+        #
+        # Compatibles with the Renesas vendor prefix that do not relate to any SoC
+        # component are OK. New compatibles are allowed.
+        - enum:
+            - renesas,smp-sram
+
+        # Do not fail compatibles not matching the select pattern
+        #
+        # Some SoC components in addition to a Renesas compatible list
+        # compatibles not related to Renesas. The select pattern for this
+        # schema hits all compatibles that have at lest one Renesas compatible
+        # and try to validate all values in that compatible array, allow all
+        # that don't match the schema select pattern. For example,
+        #
+        #   compatible = "renesas,r9a07g044-mali", "arm,mali-bifrost";
+        - pattern: "^(?!renesas,.+-.+).+$"
+
+additionalProperties: true
index 16ca3ff7b1aea146645ebd58a9d1b8c1b4c321b9..c1ce4da2dc325e586fb8cf7c0d1d0400be321daf 100644 (file)
@@ -348,12 +348,25 @@ properties:
               - renesas,white-hawk-cpu # White Hawk CPU board (RTP8A779G0ASKB0FC0SA000)
           - const: renesas,r8a779g0
 
+      - description: R-Car V4H (R8A779G2)
+        items:
+          - enum:
+              - renesas,white-hawk-single # White Hawk Single board (RTP8A779G2ASKB0F10SA001)
+          - const: renesas,r8a779g2
+          - const: renesas,r8a779g0
+
       - items:
           - enum:
               - renesas,white-hawk-breakout # White Hawk BreakOut board (RTP8A779G0ASKB0SB0SA000)
           - const: renesas,white-hawk-cpu
           - const: renesas,r8a779g0
 
+      - description: R-Car V4M (R8A779H0)
+        items:
+          - enum:
+              - renesas,gray-hawk-single # Gray Hawk Single board (RTP8A779H0ASKB0F10S)
+          - const: renesas,r8a779h0
+
       - description: R-Car H3e (R8A779M0)
         items:
           - enum:
@@ -475,12 +488,6 @@ properties:
               - renesas,r9a07g054l2 # Dual Cortex-A55 RZ/V2L
           - const: renesas,r9a07g054
 
-      - description: RZ/V2M (R9A09G011)
-        items:
-          - enum:
-              - renesas,rzv2mevk2   # RZ/V2M Eval Board v2.0
-          - const: renesas,r9a09g011
-
       - description: RZ/G3S (R9A08G045)
         items:
           - enum:
@@ -500,6 +507,12 @@ properties:
           - const: renesas,r9a08g045s33 # PCIe support
           - const: renesas,r9a08g045
 
+      - description: RZ/V2M (R9A09G011)
+        items:
+          - enum:
+              - renesas,rzv2mevk2   # RZ/V2M Eval Board v2.0
+          - const: renesas,r9a09g011
+
 additionalProperties: true
 
 ...
index 9793ea6f0fe65d35ca124554108537376fc689dd..0b87c266760c6ed4326bc3ee458c77987745bae1 100644 (file)
@@ -22,12 +22,15 @@ properties:
               - rockchip,rk3568-usb2phy-grf
               - rockchip,rk3588-bigcore0-grf
               - rockchip,rk3588-bigcore1-grf
+              - rockchip,rk3588-hdptxphy-grf
               - rockchip,rk3588-ioc
               - rockchip,rk3588-php-grf
               - rockchip,rk3588-pipe-phy-grf
               - rockchip,rk3588-sys-grf
               - rockchip,rk3588-pcie3-phy-grf
               - rockchip,rk3588-pcie3-pipe-grf
+              - rockchip,rk3588-usb-grf
+              - rockchip,rk3588-usbdpphy-grf
               - rockchip,rk3588-vo-grf
               - rockchip,rk3588-vop-grf
               - rockchip,rv1108-usbgrf
@@ -66,6 +69,9 @@ properties:
   reg:
     maxItems: 1
 
+  clocks:
+    maxItems: 1
+
   "#address-cells":
     const: 1
 
@@ -248,6 +254,22 @@ allOf:
 
           unevaluatedProperties: false
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - rockchip,rk3588-vo-grf
+
+    then:
+      required:
+        - clocks
+
+    else:
+      properties:
+        clocks: false
+
+
 examples:
   - |
     #include <dt-bindings/clock/rk3399-cru.h>
index 1794e3799f2110e716c44ef8cd1da737eeb16270..c0c6ce8fc7863e1bc942fa3cea9c66906d1cdca1 100644 (file)
@@ -72,6 +72,8 @@ allOf:
         compatible:
           contains:
             enum:
+              - google,gs101-peric0-sysreg
+              - google,gs101-peric1-sysreg
               - samsung,exynos850-cmgp-sysreg
               - samsung,exynos850-peri-sysreg
               - samsung,exynos850-sysreg
index d4c0fe1fe435803db9fcbeddb72c295bfb3cd0e2..131aba5ed9f48f30637b81188467e7f72755a93b 100644 (file)
@@ -117,20 +117,70 @@ properties:
           - const: xlnx,zynqmp
 
       - description: Xilinx Kria SOMs
+        minItems: 3
         items:
-          - const: xlnx,zynqmp-sm-k26-rev1
-          - const: xlnx,zynqmp-sm-k26-revB
-          - const: xlnx,zynqmp-sm-k26-revA
-          - const: xlnx,zynqmp-sm-k26
-          - const: xlnx,zynqmp
+          enum:
+            - xlnx,zynqmp-sm-k26-rev2
+            - xlnx,zynqmp-sm-k26-rev1
+            - xlnx,zynqmp-sm-k26-revB
+            - xlnx,zynqmp-sm-k26-revA
+            - xlnx,zynqmp-sm-k26
+            - xlnx,zynqmp
+        allOf:
+          - contains:
+              const: xlnx,zynqmp
+          - contains:
+              const: xlnx,zynqmp-sm-k26
 
       - description: Xilinx Kria SOMs (starter)
+        minItems: 3
         items:
-          - const: xlnx,zynqmp-smk-k26-rev1
-          - const: xlnx,zynqmp-smk-k26-revB
-          - const: xlnx,zynqmp-smk-k26-revA
-          - const: xlnx,zynqmp-smk-k26
-          - const: xlnx,zynqmp
+          enum:
+            - xlnx,zynqmp-smk-k26-rev2
+            - xlnx,zynqmp-smk-k26-rev1
+            - xlnx,zynqmp-smk-k26-revB
+            - xlnx,zynqmp-smk-k26-revA
+            - xlnx,zynqmp-smk-k26
+            - xlnx,zynqmp
+        allOf:
+          - contains:
+              const: xlnx,zynqmp
+          - contains:
+              const: xlnx,zynqmp-smk-k26
+
+      - description: Xilinx Kria SOM KV260 revA/Y/Z
+        minItems: 3
+        items:
+          enum:
+            - xlnx,zynqmp-sk-kv260-revA
+            - xlnx,zynqmp-sk-kv260-revY
+            - xlnx,zynqmp-sk-kv260-revZ
+            - xlnx,zynqmp-sk-kv260
+            - xlnx,zynqmp
+        allOf:
+          - contains:
+              const: xlnx,zynqmp-sk-kv260-revA
+          - contains:
+              const: xlnx,zynqmp-sk-kv260
+          - contains:
+              const: xlnx,zynqmp
+
+      - description: Xilinx Kria SOM KV260 rev2/1/B
+        minItems: 3
+        items:
+          enum:
+            - xlnx,zynqmp-sk-kv260-rev2
+            - xlnx,zynqmp-sk-kv260-rev1
+            - xlnx,zynqmp-sk-kv260-revB
+            - xlnx,zynqmp-sk-kv260
+            - xlnx,zynqmp
+        allOf:
+          - contains:
+              const: xlnx,zynqmp-sk-kv260-revB
+          - contains:
+              const: xlnx,zynqmp-sk-kv260
+          - contains:
+              const: xlnx,zynqmp
 
       - description: AMD MicroBlaze V (QEMU)
         items:
index ec4b6e547ca6efad4b77697c567e30da74707261..cdcd7c6f21eb241663c44fd8d066dc1700a8994b 100644 (file)
@@ -7,7 +7,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Google SC7280-Herobrine ASoC sound card driver
 
 maintainers:
-  - Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
   - Judy Hsiao <judyhsiao@chromium.org>
 
 description:
index c29d7942915cccbaf58679f702c642632f5495b8..241d20f3aad08a845c57e3dead8fba25c4856e6a 100644 (file)
@@ -64,7 +64,7 @@ examples:
     #include <dt-bindings/clock/tegra30-car.h>
     #include <dt-bindings/soc/tegra-pmc.h>
     sound {
-        compatible = "lge,tegra-audio-max98089-p895",
+        compatible = "lg,tegra-audio-max98089-p895",
                      "nvidia,tegra-audio-max98089";
         nvidia,model = "LG Optimus Vu MAX98089";
 
index a1c96985951ff2b1083ed64d86bcf24235ad9101..cf07b8f787a6eda6fb7031407cbf5c37ff171bf1 100644 (file)
@@ -56,7 +56,7 @@ properties:
   ranges: true
 
 patternProperties:
-  "^sram@[a-z0-9]+":
+  "^sram@[a-f0-9]+":
     $ref: /schemas/sram/sram.yaml#
     unevaluatedProperties: false
 
index 90390624a8be5e7abc0b18374f19705db999a97d..3c1241b2a43f99d361e0af89aed61f4318c9b914 100644 (file)
@@ -42,7 +42,7 @@ properties:
 
   resets:
     description: Reset controller to reset the TPM
-    $ref: /schemas/types.yaml#/definitions/phandle
+    maxItems: 1
 
   reset-gpios:
     description: Output GPIO pin to reset the TPM
index 88cc1e3a0c887c367c7ed83ff2a0835398a20b93..b2b509b3944d85714316c8f91b042054373416a4 100644 (file)
@@ -55,9 +55,12 @@ properties:
 
   samsung,sysreg:
     $ref: /schemas/types.yaml#/definitions/phandle-array
-    description: Should be phandle/offset pair. The phandle to the syscon node
-                 which indicates the FSYSx sysreg interface and the offset of
-                 the control register for UFS io coherency setting.
+    items:
+      - items:
+          - description: phandle to FSYSx sysreg node
+          - description: offset of the control register for UFS io coherency setting
+    description:
+      Phandle and offset to the FSYSx sysreg for UFS io coherency setting.
 
   dma-coherent: true
 
index bb373eb025a5f92b085d62b21354d94eaa002e65..00f87a558c7dd3b8af7392f87448ac8a00fbcd95 100644 (file)
@@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Xilinx SuperSpeed DWC3 USB SoC controller
 
 maintainers:
-  - Piyush Mehta <piyush.mehta@amd.com>
+  - Mubin Sayyed <mubin.sayyed@amd.com>
+  - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
 
 properties:
   compatible:
index 6d4cfd943f5847ff43cbccd13e5f210a95448c1c..445183d9d6db1adaa1ab9d04cb4271eadbe22ffc 100644 (file)
@@ -16,8 +16,9 @@ description:
   USB 2.0 traffic.
 
 maintainers:
-  - Piyush Mehta <piyush.mehta@amd.com>
   - Michal Simek <michal.simek@amd.com>
+  - Mubin Sayyed <mubin.sayyed@amd.com>
+  - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
 
 properties:
   compatible:
index 868dffe314bcba9123a4e99b9966de738b0ea8f3..a7f75fe366652bb2dcec6bf6e87c5879d31f1fce 100644 (file)
@@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Xilinx udc controller
 
 maintainers:
-  - Piyush Mehta <piyush.mehta@amd.com>
+  - Mubin Sayyed <mubin.sayyed@amd.com>
+  - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
 
 properties:
   compatible:
index 1a0dc04f1db47865766c3c71981cbdbd64c8343e..d371eb57216453b905af6521e45704d099312c53 100644 (file)
@@ -39,6 +39,8 @@ patternProperties:
     description: ShenZhen Asia Better Technology Ltd.
   "^acbel,.*":
     description: Acbel Polytech Inc.
+  "^acelink,.*":
+    description: Acelink Technology Co., Ltd.
   "^acer,.*":
     description: Acer Inc.
   "^acme,.*":
@@ -500,6 +502,8 @@ patternProperties:
     description: FocalTech Systems Co.,Ltd
   "^forlinx,.*":
     description: Baoding Forlinx Embedded Technology Co., Ltd.
+  "^freebox,.*":
+    description: Freebox SAS
   "^freecom,.*":
     description: Freecom Gmbh
   "^frida,.*":
@@ -719,6 +723,8 @@ patternProperties:
     description: JetHome (IP Sokolov P.A.)
   "^jianda,.*":
     description: Jiandangjing Technology Co., Ltd.
+  "^jide,.*":
+    description: Jide Tech
   "^joz,.*":
     description: JOZ BV
   "^kam,.*":
@@ -1484,6 +1490,8 @@ patternProperties:
     description: Ufi Space Co., Ltd.
   "^ugoos,.*":
     description: Ugoos Industrial Co., Ltd.
+  "^uni-t,.*":
+    description: Uni-Trend Technology (China) Co., Ltd.
   "^uniwest,.*":
     description: United Western Technologies Corp (UniWest)
   "^upisemi,.*":
index e3d593841aa7ddd96237283b27470a9fba97ec89..ea8d16600e16a8530b7e633368bb53b75e878c15 100644 (file)
@@ -545,7 +545,7 @@ In such scenario, dpll device input signal shall be also configurable
 to drive dpll with signal recovered from the PHY netdevice.
 This is done by exposing a pin to the netdevice - attaching pin to the
 netdevice itself with
-``netdev_dpll_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)``.
+``dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)``.
 Exposed pin id handle ``DPLL_A_PIN_ID`` is then identifiable by the user
 as it is attached to rtnetlink respond to get ``RTM_NEWLINK`` command in
 nested attribute ``IFLA_DPLL_PIN``.
index 9e38e4c221ca5dc1be598bc1ab45bdd890f1419e..eb770f891b275f3e8b905f1bb794494a61dde54d 100644 (file)
@@ -116,7 +116,7 @@ before and after the reference count increment. This pattern can be seen
 in get_file_rcu() and __files_get_rcu().
 
 In addition, it isn't possible to access or check fields in struct file
-without first aqcuiring a reference on it under rcu lookup. Not doing
+without first acquiring a reference on it under rcu lookup. Not doing
 that was always very dodgy and it was only usable for non-pointer data
 in struct file. With SLAB_TYPESAFE_BY_RCU it is necessary that callers
 either first acquire a reference or they must hold the files_lock of the
index e18bc5ae3b35f89ecc61fc6266d5151c53dbd34d..0ea1e44fa02823ffd51f4739a3a9aab635a35bbe 100644 (file)
@@ -98,7 +98,6 @@ Documentation for filesystem implementations.
    isofs
    nilfs2
    nfs/index
-   ntfs
    ntfs3
    ocfs2
    ocfs2-online-filecheck
index d5bf4b6b7509b01c9a2d5225a6bb5b2e1ef327b2..e664061ed55dc1bdc6d7d16c086f3050c32909d6 100644 (file)
@@ -29,7 +29,7 @@ prototypes::
        char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
        struct vfsmount *(*d_automount)(struct path *path);
        int (*d_manage)(const struct path *, bool);
-       struct dentry *(*d_real)(struct dentry *, const struct inode *);
+       struct dentry *(*d_real)(struct dentry *, enum d_real_type type);
 
 locking rules:
 
diff --git a/Documentation/filesystems/ntfs.rst b/Documentation/filesystems/ntfs.rst
deleted file mode 100644 (file)
index 5bb093a..0000000
+++ /dev/null
@@ -1,466 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-================================
-The Linux NTFS filesystem driver
-================================
-
-
-.. Table of contents
-
-   - Overview
-   - Web site
-   - Features
-   - Supported mount options
-   - Known bugs and (mis-)features
-   - Using NTFS volume and stripe sets
-     - The Device-Mapper driver
-     - The Software RAID / MD driver
-     - Limitations when using the MD driver
-
-
-Overview
-========
-
-Linux-NTFS comes with a number of user-space programs known as ntfsprogs.
-These include mkntfs, a full-featured ntfs filesystem format utility,
-ntfsundelete used for recovering files that were unintentionally deleted
-from an NTFS volume and ntfsresize which is used to resize an NTFS partition.
-See the web site for more information.
-
-To mount an NTFS 1.2/3.x (Windows NT4/2000/XP/2003) volume, use the file
-system type 'ntfs'.  The driver currently supports read-only mode (with no
-fault-tolerance, encryption or journalling) and very limited, but safe, write
-support.
-
-For fault tolerance and raid support (i.e. volume and stripe sets), you can
-use the kernel's Software RAID / MD driver.  See section "Using Software RAID
-with NTFS" for details.
-
-
-Web site
-========
-
-There is plenty of additional information on the linux-ntfs web site
-at http://www.linux-ntfs.org/
-
-The web site has a lot of additional information, such as a comprehensive
-FAQ, documentation on the NTFS on-disk format, information on the Linux-NTFS
-userspace utilities, etc.
-
-
-Features
-========
-
-- This is a complete rewrite of the NTFS driver that used to be in the 2.4 and
-  earlier kernels.  This new driver implements NTFS read support and is
-  functionally equivalent to the old ntfs driver and it also implements limited
-  write support.  The biggest limitation at present is that files/directories
-  cannot be created or deleted.  See below for the list of write features that
-  are so far supported.  Another limitation is that writing to compressed files
-  is not implemented at all.  Also, neither read nor write access to encrypted
-  files is so far implemented.
-- The new driver has full support for sparse files on NTFS 3.x volumes which
-  the old driver isn't happy with.
-- The new driver supports execution of binaries due to mmap() now being
-  supported.
-- The new driver supports loopback mounting of files on NTFS which is used by
-  some Linux distributions to enable the user to run Linux from an NTFS
-  partition by creating a large file while in Windows and then loopback
-  mounting the file while in Linux and creating a Linux filesystem on it that
-  is used to install Linux on it.
-- A comparison of the two drivers using::
-
-       time find . -type f -exec md5sum "{}" \;
-
-  run three times in sequence with each driver (after a reboot) on a 1.4GiB
-  NTFS partition, showed the new driver to be 20% faster in total time elapsed
-  (from 9:43 minutes on average down to 7:53).  The time spent in user space
-  was unchanged but the time spent in the kernel was decreased by a factor of
-  2.5 (from 85 CPU seconds down to 33).
-- The driver does not support short file names in general.  For backwards
-  compatibility, we implement access to files using their short file names if
-  they exist.  The driver will not create short file names however, and a
-  rename will discard any existing short file name.
-- The new driver supports exporting of mounted NTFS volumes via NFS.
-- The new driver supports async io (aio).
-- The new driver supports fsync(2), fdatasync(2), and msync(2).
-- The new driver supports readv(2) and writev(2).
-- The new driver supports access time updates (including mtime and ctime).
-- The new driver supports truncate(2) and open(2) with O_TRUNC.  But at present
-  only very limited support for highly fragmented files, i.e. ones which have
-  their data attribute split across multiple extents, is included.  Another
-  limitation is that at present truncate(2) will never create sparse files,
-  since to mark a file sparse we need to modify the directory entry for the
-  file and we do not implement directory modifications yet.
-- The new driver supports write(2) which can both overwrite existing data and
-  extend the file size so that you can write beyond the existing data.  Also,
-  writing into sparse regions is supported and the holes are filled in with
-  clusters.  But at present only limited support for highly fragmented files,
-  i.e. ones which have their data attribute split across multiple extents, is
-  included.  Another limitation is that write(2) will never create sparse
-  files, since to mark a file sparse we need to modify the directory entry for
-  the file and we do not implement directory modifications yet.
-
-Supported mount options
-=======================
-
-In addition to the generic mount options described by the manual page for the
-mount command (man 8 mount, also see man 5 fstab), the NTFS driver supports the
-following mount options:
-
-======================= =======================================================
-iocharset=name         Deprecated option.  Still supported but please use
-                       nls=name in the future.  See description for nls=name.
-
-nls=name               Character set to use when returning file names.
-                       Unlike VFAT, NTFS suppresses names that contain
-                       unconvertible characters.  Note that most character
-                       sets contain insufficient characters to represent all
-                       possible Unicode characters that can exist on NTFS.
-                       To be sure you are not missing any files, you are
-                       advised to use nls=utf8 which is capable of
-                       representing all Unicode characters.
-
-utf8=<bool>            Option no longer supported.  Currently mapped to
-                       nls=utf8 but please use nls=utf8 in the future and
-                       make sure utf8 is compiled either as module or into
-                       the kernel.  See description for nls=name.
-
-uid=
-gid=
-umask=                 Provide default owner, group, and access mode mask.
-                       These options work as documented in mount(8).  By
-                       default, the files/directories are owned by root and
-                       he/she has read and write permissions, as well as
-                       browse permission for directories.  No one else has any
-                       access permissions.  I.e. the mode on all files is by
-                       default rw------- and for directories rwx------, a
-                       consequence of the default fmask=0177 and dmask=0077.
-                       Using a umask of zero will grant all permissions to
-                       everyone, i.e. all files and directories will have mode
-                       rwxrwxrwx.
-
-fmask=
-dmask=                 Instead of specifying umask which applies both to
-                       files and directories, fmask applies only to files and
-                       dmask only to directories.
-
-sloppy=<BOOL>          If sloppy is specified, ignore unknown mount options.
-                       Otherwise the default behaviour is to abort mount if
-                       any unknown options are found.
-
-show_sys_files=<BOOL>  If show_sys_files is specified, show the system files
-                       in directory listings.  Otherwise the default behaviour
-                       is to hide the system files.
-                       Note that even when show_sys_files is specified, "$MFT"
-                       will not be visible due to bugs/mis-features in glibc.
-                       Further, note that irrespective of show_sys_files, all
-                       files are accessible by name, i.e. you can always do
-                       "ls -l \$UpCase" for example to specifically show the
-                       system file containing the Unicode upcase table.
-
-case_sensitive=<BOOL>  If case_sensitive is specified, treat all file names as
-                       case sensitive and create file names in the POSIX
-                       namespace.  Otherwise the default behaviour is to treat
-                       file names as case insensitive and to create file names
-                       in the WIN32/LONG name space.  Note, the Linux NTFS
-                       driver will never create short file names and will
-                       remove them on rename/delete of the corresponding long
-                       file name.
-                       Note that files remain accessible via their short file
-                       name, if it exists.  If case_sensitive, you will need
-                       to provide the correct case of the short file name.
-
-disable_sparse=<BOOL>  If disable_sparse is specified, creation of sparse
-                       regions, i.e. holes, inside files is disabled for the
-                       volume (for the duration of this mount only).  By
-                       default, creation of sparse regions is enabled, which
-                       is consistent with the behaviour of traditional Unix
-                       filesystems.
-
-errors=opt             What to do when critical filesystem errors are found.
-                       Following values can be used for "opt":
-
-                         ========  =========================================
-                         continue  DEFAULT, try to clean-up as much as
-                                   possible, e.g. marking a corrupt inode as
-                                   bad so it is no longer accessed, and then
-                                   continue.
-                         recover   At present only supported is recovery of
-                                   the boot sector from the backup copy.
-                                   If read-only mount, the recovery is done
-                                   in memory only and not written to disk.
-                         ========  =========================================
-
-                       Note that the options are additive, i.e. specifying::
-
-                          errors=continue,errors=recover
-
-                       means the driver will attempt to recover and if that
-                       fails it will clean-up as much as possible and
-                       continue.
-
-mft_zone_multiplier=   Set the MFT zone multiplier for the volume (this
-                       setting is not persistent across mounts and can be
-                       changed from mount to mount but cannot be changed on
-                       remount).  Values of 1 to 4 are allowed, 1 being the
-                       default.  The MFT zone multiplier determines how much
-                       space is reserved for the MFT on the volume.  If all
-                       other space is used up, then the MFT zone will be
-                       shrunk dynamically, so this has no impact on the
-                       amount of free space.  However, it can have an impact
-                       on performance by affecting fragmentation of the MFT.
-                       In general use the default.  If you have a lot of small
-                       files then use a higher value.  The values have the
-                       following meaning:
-
-                             =====         =================================
-                             Value          MFT zone size (% of volume size)
-                             =====         =================================
-                               1               12.5%
-                               2               25%
-                               3               37.5%
-                               4               50%
-                             =====         =================================
-
-                       Note this option is irrelevant for read-only mounts.
-======================= =======================================================
-
-
-Known bugs and (mis-)features
-=============================
-
-- The link count on each directory inode entry is set to 1, due to Linux not
-  supporting directory hard links.  This may well confuse some user space
-  applications, since the directory names will have the same inode numbers.
-  This also speeds up ntfs_read_inode() immensely.  And we haven't found any
-  problems with this approach so far.  If you find a problem with this, please
-  let us know.
-
-
-Please send bug reports/comments/feedback/abuse to the Linux-NTFS development
-list at sourceforge: linux-ntfs-dev@lists.sourceforge.net
-
-
-Using NTFS volume and stripe sets
-=================================
-
-For support of volume and stripe sets, you can either use the kernel's
-Device-Mapper driver or the kernel's Software RAID / MD driver.  The former is
-the recommended one to use for linear raid.  But the latter is required for
-raid level 5.  For striping and mirroring, either driver should work fine.
-
-
-The Device-Mapper driver
-------------------------
-
-You will need to create a table of the components of the volume/stripe set and
-how they fit together and load this into the kernel using the dmsetup utility
-(see man 8 dmsetup).
-
-Linear volume sets, i.e. linear raid, has been tested and works fine.  Even
-though untested, there is no reason why stripe sets, i.e. raid level 0, and
-mirrors, i.e. raid level 1 should not work, too.  Stripes with parity, i.e.
-raid level 5, unfortunately cannot work yet because the current version of the
-Device-Mapper driver does not support raid level 5.  You may be able to use the
-Software RAID / MD driver for raid level 5, see the next section for details.
-
-To create the table describing your volume you will need to know each of its
-components and their sizes in sectors, i.e. multiples of 512-byte blocks.
-
-For NT4 fault tolerant volumes you can obtain the sizes using fdisk.  So for
-example if one of your partitions is /dev/hda2 you would do::
-
-    $ fdisk -ul /dev/hda
-
-    Disk /dev/hda: 81.9 GB, 81964302336 bytes
-    255 heads, 63 sectors/track, 9964 cylinders, total 160086528 sectors
-    Units = sectors of 1 * 512 = 512 bytes
-
-       Device Boot      Start         End      Blocks   Id  System
-       /dev/hda1   *          63     4209029     2104483+  83  Linux
-       /dev/hda2         4209030    37768814    16779892+  86  NTFS
-       /dev/hda3        37768815    46170809     4200997+  83  Linux
-
-And you would know that /dev/hda2 has a size of 37768814 - 4209030 + 1 =
-33559785 sectors.
-
-For Win2k and later dynamic disks, you can for example use the ldminfo utility
-which is part of the Linux LDM tools (the latest version at the time of
-writing is linux-ldm-0.0.8.tar.bz2).  You can download it from:
-
-       http://www.linux-ntfs.org/
-
-Simply extract the downloaded archive (tar xvjf linux-ldm-0.0.8.tar.bz2), go
-into it (cd linux-ldm-0.0.8) and change to the test directory (cd test).  You
-will find the precompiled (i386) ldminfo utility there.  NOTE: You will not be
-able to compile this yourself easily so use the binary version!
-
-Then you would use ldminfo in dump mode to obtain the necessary information::
-
-    $ ./ldminfo --dump /dev/hda
-
-This would dump the LDM database found on /dev/hda which describes all of your
-dynamic disks and all the volumes on them.  At the bottom you will see the
-VOLUME DEFINITIONS section which is all you really need.  You may need to look
-further above to determine which of the disks in the volume definitions is
-which device in Linux.  Hint: Run ldminfo on each of your dynamic disks and
-look at the Disk Id close to the top of the output for each (the PRIVATE HEADER
-section).  You can then find these Disk Ids in the VBLK DATABASE section in the
-<Disk> components where you will get the LDM Name for the disk that is found in
-the VOLUME DEFINITIONS section.
-
-Note you will also need to enable the LDM driver in the Linux kernel.  If your
-distribution did not enable it, you will need to recompile the kernel with it
-enabled.  This will create the LDM partitions on each device at boot time.  You
-would then use those devices (for /dev/hda they would be /dev/hda1, 2, 3, etc)
-in the Device-Mapper table.
-
-You can also bypass using the LDM driver by using the main device (e.g.
-/dev/hda) and then using the offsets of the LDM partitions into this device as
-the "Start sector of device" when creating the table.  Once again ldminfo would
-give you the correct information to do this.
-
-Assuming you know all your devices and their sizes things are easy.
-
-For a linear raid the table would look like this (note all values are in
-512-byte sectors)::
-
-    # Offset into      Size of this    Raid type       Device          Start sector
-    # volume   device                                          of device
-    0          1028161         linear          /dev/hda1       0
-    1028161            3903762         linear          /dev/hdb2       0
-    4931923            2103211         linear          /dev/hdc1       0
-
-For a striped volume, i.e. raid level 0, you will need to know the chunk size
-you used when creating the volume.  Windows uses 64kiB as the default, so it
-will probably be this unless you changes the defaults when creating the array.
-
-For a raid level 0 the table would look like this (note all values are in
-512-byte sectors)::
-
-    # Offset   Size        Raid     Number   Chunk  1st        Start   2nd       Start
-    # into     of the   type     of          size   Device     in      Device    in
-    # volume   volume       stripes                    device            device
-    0     2056320  striped  2        128    /dev/hda1  0       /dev/hdb1 0
-
-If there are more than two devices, just add each of them to the end of the
-line.
-
-Finally, for a mirrored volume, i.e. raid level 1, the table would look like
-this (note all values are in 512-byte sectors)::
-
-    # Ofs Size   Raid   Log  Number Region Should Number Source  Start Target Start
-    # in  of the type   type of log size   sync?  of     Device  in    Device in
-    # vol volume                params              mirrors         Device       Device
-    0    2056320 mirror core 2 16     nosync 2    /dev/hda1 0   /dev/hdb1 0
-
-If you are mirroring to multiple devices you can specify further targets at the
-end of the line.
-
-Note the "Should sync?" parameter "nosync" means that the two mirrors are
-already in sync which will be the case on a clean shutdown of Windows.  If the
-mirrors are not clean, you can specify the "sync" option instead of "nosync"
-and the Device-Mapper driver will then copy the entirety of the "Source Device"
-to the "Target Device" or if you specified multiple target devices to all of
-them.
-
-Once you have your table, save it in a file somewhere (e.g. /etc/ntfsvolume1),
-and hand it over to dmsetup to work with, like so::
-
-    $ dmsetup create myvolume1 /etc/ntfsvolume1
-
-You can obviously replace "myvolume1" with whatever name you like.
-
-If it all worked, you will now have the device /dev/device-mapper/myvolume1
-which you can then just use as an argument to the mount command as usual to
-mount the ntfs volume.  For example::
-
-    $ mount -t ntfs -o ro /dev/device-mapper/myvolume1 /mnt/myvol1
-
-(You need to create the directory /mnt/myvol1 first and of course you can use
-anything you like instead of /mnt/myvol1 as long as it is an existing
-directory.)
-
-It is advisable to do the mount read-only to see if the volume has been setup
-correctly to avoid the possibility of causing damage to the data on the ntfs
-volume.
-
-
-The Software RAID / MD driver
------------------------------
-
-An alternative to using the Device-Mapper driver is to use the kernel's
-Software RAID / MD driver.  For which you need to set up your /etc/raidtab
-appropriately (see man 5 raidtab).
-
-Linear volume sets, i.e. linear raid, as well as stripe sets, i.e. raid level
-0, have been tested and work fine (though see section "Limitations when using
-the MD driver with NTFS volumes" especially if you want to use linear raid).
-Even though untested, there is no reason why mirrors, i.e. raid level 1, and
-stripes with parity, i.e. raid level 5, should not work, too.
-
-You have to use the "persistent-superblock 0" option for each raid-disk in the
-NTFS volume/stripe you are configuring in /etc/raidtab as the persistent
-superblock used by the MD driver would damage the NTFS volume.
-
-Windows by default uses a stripe chunk size of 64k, so you probably want the
-"chunk-size 64k" option for each raid-disk, too.
-
-For example, if you have a stripe set consisting of two partitions /dev/hda5
-and /dev/hdb1 your /etc/raidtab would look like this::
-
-    raiddev /dev/md0
-           raid-level  0
-           nr-raid-disks       2
-           nr-spare-disks      0
-           persistent-superblock       0
-           chunk-size  64k
-           device              /dev/hda5
-           raid-disk   0
-           device              /dev/hdb1
-           raid-disk   1
-
-For linear raid, just change the raid-level above to "raid-level linear", for
-mirrors, change it to "raid-level 1", and for stripe sets with parity, change
-it to "raid-level 5".
-
-Note for stripe sets with parity you will also need to tell the MD driver
-which parity algorithm to use by specifying the option "parity-algorithm
-which", where you need to replace "which" with the name of the algorithm to
-use (see man 5 raidtab for available algorithms) and you will have to try the
-different available algorithms until you find one that works.  Make sure you
-are working read-only when playing with this as you may damage your data
-otherwise.  If you find which algorithm works please let us know (email the
-linux-ntfs developers list linux-ntfs-dev@lists.sourceforge.net or drop in on
-IRC in channel #ntfs on the irc.freenode.net network) so we can update this
-documentation.
-
-Once the raidtab is setup, run for example raid0run -a to start all devices or
-raid0run /dev/md0 to start a particular md device, in this case /dev/md0.
-
-Then just use the mount command as usual to mount the ntfs volume using for
-example::
-
-    mount -t ntfs -o ro /dev/md0 /mnt/myntfsvolume
-
-It is advisable to do the mount read-only to see if the md volume has been
-setup correctly to avoid the possibility of causing damage to the data on the
-ntfs volume.
-
-
-Limitations when using the Software RAID / MD driver
------------------------------------------------------
-
-Using the md driver will not work properly if any of your NTFS partitions have
-an odd number of sectors.  This is especially important for linear raid as all
-data after the first partition with an odd number of sectors will be offset by
-one or more sectors so if you mount such a partition with write support you
-will cause massive damage to the data on the volume which will only become
-apparent when you try to use the volume again under Windows.
-
-So when using linear raid, make sure that all your partitions have an even
-number of sectors BEFORE attempting to use it.  You have been warned!
-
-Even better is to simply use the Device-Mapper for linear raid and then you do
-not have this problem with odd numbers of sectors.
index eebcc0f9e2bcd1f3eecc99c00ec656fe45cbbd8e..6e903a903f8f691d55af7f3ae200f959fc7978a2 100644 (file)
@@ -1264,7 +1264,7 @@ defined:
                char *(*d_dname)(struct dentry *, char *, int);
                struct vfsmount *(*d_automount)(struct path *);
                int (*d_manage)(const struct path *, bool);
-               struct dentry *(*d_real)(struct dentry *, const struct inode *);
+               struct dentry *(*d_real)(struct dentry *, enum d_real_type type);
        };
 
 ``d_revalidate``
@@ -1419,16 +1419,14 @@ defined:
        the dentry being transited from.
 
 ``d_real``
-       overlay/union type filesystems implement this method to return
-       one of the underlying dentries hidden by the overlay.  It is
-       used in two different modes:
+       overlay/union type filesystems implement this method to return one
+       of the underlying dentries of a regular file hidden by the overlay.
 
-       Called from file_dentry() it returns the real dentry matching
-       the inode argument.  The real dentry may be from a lower layer
-       already copied up, but still referenced from the file.  This
-       mode is selected with a non-NULL inode argument.
+       The 'type' argument takes the values D_REAL_DATA or D_REAL_METADATA
+       for returning the real underlying dentry that refers to the inode
+       hosting the file's data or metadata respectively.
 
-       With NULL inode the topmost real underlying dentry is returned.
+       For non-regular files, the 'dentry' argument is returned.
 
 Each dentry has a pointer to its parent dentry, as well as a hash list
 of child dentries.  Child dentries are basically like files in a
index 36e61783437c1034cfbeb19aa662be64fea80857..9dfdc826618c08f5f62f81f1cea543dea3223967 100644 (file)
@@ -113,7 +113,6 @@ to ReStructured Text format, or are simply too old.
    :maxdepth: 1
 
    staging/index
-   RAS/ras
 
 
 Translations
index e8877db0461fb45ed939bd859df9d7bc0ef7077e..ac49836d8ecf8909ef75e8e04fbab45d89d1f888 100644 (file)
 # that are possible for CORE. So for example if CORE_BELL_A_ADVANCED is 'y',
 # CORE must be 'y' too.
 #
-#  * What influences CORE_BELL_A_ADVANCED ?
+#  * What influences CORE_BELL_A_ADVANCED?
 #
 # As the name implies CORE_BELL_A_ADVANCED is an advanced feature of
 # CORE_BELL_A so naturally it depends on CORE_BELL_A. So if CORE_BELL_A is 'y'
 # we know CORE_BELL_A_ADVANCED can be 'y' too.
 #
-#   * What influences CORE_BELL_A ?
+#   * What influences CORE_BELL_A?
 #
 # CORE_BELL_A depends on CORE, so CORE influences CORE_BELL_A.
 #
@@ -34,7 +34,7 @@
 # the "recursive dependency detected" error.
 #
 # Reading the Documentation/kbuild/Kconfig.recursion-issue-01 file it may be
-# obvious that an easy to solution to this problem should just be the removal
+# obvious that an easy solution to this problem should just be the removal
 # of the "select CORE" from CORE_BELL_A_ADVANCED as that is implicit already
 # since CORE_BELL_A depends on CORE. Recursive dependency issues are not always
 # so trivial to resolve, we provide another example below of practical
index b14aed18065f43ce24e9217eefd455814c953efc..3dcc9ece272aad6842a6297c6d5bf2cca2c2acc3 100644 (file)
@@ -384,8 +384,6 @@ operations:
             - type
 
       dump:
-        pre: dpll-lock-dumpit
-        post: dpll-unlock-dumpit
         reply: *dev-attrs
 
     -
@@ -473,8 +471,6 @@ operations:
             - fractional-frequency-offset
 
       dump:
-        pre: dpll-lock-dumpit
-        post: dpll-unlock-dumpit
         request:
           attributes:
             - id
index e33ad2401ad70c8a678fec93ebfda3ca4909f9db..562f46b41274493c77176a1e563269fc9e4b2b85 100644 (file)
@@ -126,7 +126,7 @@ Users may also set the RoCE capability of the function using
 `devlink port function set roce` command.
 
 Users may also set the function as migratable using
-'devlink port function set migratable' command.
+`devlink port function set migratable` command.
 
 Users may also set the IPsec crypto capability of the function using
 `devlink port function set ipsec_crypto` command.
index a2babd0d7954e6729ed8533518dbef039f5fdeac..595d7ef5fc8b090788e7a3439843c060951d1098 100644 (file)
@@ -1,9 +1,9 @@
 .. SPDX-License-Identifier: GPL-2.0
 .. Copyright (C) 2023 Google LLC
 
-=====================================================
-inet_connection_sock struct fast path usage breakdown
-=====================================================
+==========================================
+inet_sock struct fast path usage breakdown
+==========================================
 
 Type                    Name                  fastpath_tx_access  fastpath_rx_access  comment
 ..struct                ..inet_sock                                                     
index e75a53593bb9606f1c0595d8f7227881ec932b9c..dceb49d56a91158232543e920c7ed23bed74106e 100644 (file)
@@ -136,8 +136,8 @@ struct_netpoll_info*                npinfo                  -
 possible_net_t                      nd_net                  -                   read_mostly         (dev_net)napi_busy_loop,tcp_v(4/6)_rcv,ip(v6)_rcv,ip(6)_input,ip(6)_input_finish
 void*                               ml_priv                                                         
 enum_netdev_ml_priv_type            ml_priv_type                                                    
-struct_pcpu_lstats__percpu*         lstats                                                          
-struct_pcpu_sw_netstats__percpu*    tstats                                                          
+struct_pcpu_lstats__percpu*         lstats                  read_mostly                             dev_lstats_add()
+struct_pcpu_sw_netstats__percpu*    tstats                  read_mostly                             dev_sw_netstats_tx_add()
 struct_pcpu_dstats__percpu*         dstats                                                          
 struct_garp_port*                   garp_port                                                       
 struct_mrp_port*                    mrp_port                                                        
index 97d7a5c8e01c02658c7f445ed92a2d1f7cc61d31..1c154cbd18487e385c8ae7a1e39d3b5f5ab086a2 100644 (file)
@@ -38,13 +38,13 @@ u32                           max_window              read_mostly         -
 u32                           mss_cache               read_mostly         read_mostly         tcp_rate_check_app_limited,tcp_current_mss,tcp_sync_mss,tcp_sndbuf_expand,tcp_tso_should_defer(tx);tcp_update_pacing_rate,tcp_clean_rtx_queue(rx)
 u32                           window_clamp            read_mostly         read_write          tcp_rcv_space_adjust,__tcp_select_window
 u32                           rcv_ssthresh            read_mostly         -                   __tcp_select_window
-u82                           scaling_ratio                                                   
+u8                            scaling_ratio           read_mostly         read_mostly         tcp_win_from_space
 struct                        tcp_rack                                                        
 u16                           advmss                  -                   read_mostly         tcp_rcv_space_adjust
 u8                            compressed_ack                                                  
 u8:2                          dup_ack_counter                                                 
 u8:1                          tlp_retrans                                                     
-u8:1                          tcp_usec_ts                                                     
+u8:1                          tcp_usec_ts             read_mostly         read_mostly
 u32                           chrono_start            read_write          -                   tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data)
 u32[3]                        chrono_stat             read_write          -                   tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data)
 u8:2                          chrono_type             read_write          -                   tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data)
index 50b3d1cb11159b5fad1082d521598984a881594f..c78ecc1e176fc03cad1e35606b9d9c8d7572b4eb 100644 (file)
@@ -31,7 +31,7 @@ you probably needn't concern yourself with pcmciautils.
 ====================== ===============  ========================================
 GNU C                  5.1              gcc --version
 Clang/LLVM (optional)  11.0.0           clang --version
-Rust (optional)        1.74.1           rustc --version
+Rust (optional)        1.76.0           rustc --version
 bindgen (optional)     0.65.1           bindgen --version
 GNU make               3.82             make --version
 bash                   4.2              bash --version
diff --git a/Documentation/process/cve.rst b/Documentation/process/cve.rst
new file mode 100644 (file)
index 0000000..5e2753e
--- /dev/null
@@ -0,0 +1,121 @@
+====
+CVEs
+====
+
+Common Vulnerabilities and Exposure (CVE®) numbers were developed as an
+unambiguous way to identify, define, and catalog publicly disclosed
+security vulnerabilities.  Over time, their usefulness has declined with
+regards to the kernel project, and CVE numbers were very often assigned
+in inappropriate ways and for inappropriate reasons.  Because of this,
+the kernel development community has tended to avoid them.  However, the
+combination of continuing pressure to assign CVEs and other forms of
+security identifiers, and ongoing abuses by individuals and companies
+outside of the kernel community has made it clear that the kernel
+community should have control over those assignments.
+
+The Linux kernel developer team does have the ability to assign CVEs for
+potential Linux kernel security issues.  This assignment is independent
+of the :doc:`normal Linux kernel security bug reporting
+process<../process/security-bugs>`.
+
+A list of all assigned CVEs for the Linux kernel can be found in the
+archives of the linux-cve mailing list, as seen on
+https://lore.kernel.org/linux-cve-announce/.  To get notice of the
+assigned CVEs, please `subscribe
+<https://subspace.kernel.org/subscribing.html>`_ to that mailing list.
+
+Process
+=======
+
+As part of the normal stable release process, kernel changes that are
+potentially security issues are identified by the developers responsible
+for CVE number assignments and have CVE numbers automatically assigned
+to them.  These assignments are published on the linux-cve-announce
+mailing list as announcements on a frequent basis.
+
+Note, due to the layer at which the Linux kernel is in a system, almost
+any bug might be exploitable to compromise the security of the kernel,
+but the possibility of exploitation is often not evident when the bug is
+fixed.  Because of this, the CVE assignment team is overly cautious and
+assign CVE numbers to any bugfix that they identify.  This
+explains the seemingly large number of CVEs that are issued by the Linux
+kernel team.
+
+If the CVE assignment team misses a specific fix that any user feels
+should have a CVE assigned to it, please email them at <cve@kernel.org>
+and the team there will work with you on it.  Note that no potential
+security issues should be sent to this alias, it is ONLY for assignment
+of CVEs for fixes that are already in released kernel trees.  If you
+feel you have found an unfixed security issue, please follow the
+:doc:`normal Linux kernel security bug reporting
+process<../process/security-bugs>`.
+
+No CVEs will be automatically assigned for unfixed security issues in
+the Linux kernel; assignment will only automatically happen after a fix
+is available and applied to a stable kernel tree, and it will be tracked
+that way by the git commit id of the original fix.  If anyone wishes to
+have a CVE assigned before an issue is resolved with a commit, please
+contact the kernel CVE assignment team at <cve@kernel.org> to get an
+identifier assigned from their batch of reserved identifiers.
+
+No CVEs will be assigned for any issue found in a version of the kernel
+that is not currently being actively supported by the Stable/LTS kernel
+team.  A list of the currently supported kernel branches can be found at
+https://kernel.org/releases.html
+
+Disputes of assigned CVEs
+=========================
+
+The authority to dispute or modify an assigned CVE for a specific kernel
+change lies solely with the maintainers of the relevant subsystem
+affected.  This principle ensures a high degree of accuracy and
+accountability in vulnerability reporting.  Only those individuals with
+deep expertise and intimate knowledge of the subsystem can effectively
+assess the validity and scope of a reported vulnerability and determine
+its appropriate CVE designation.  Any attempt to modify or dispute a CVE
+outside of this designated authority could lead to confusion, inaccurate
+reporting, and ultimately, compromised systems.
+
+Invalid CVEs
+============
+
+If a security issue is found in a Linux kernel that is only supported by
+a Linux distribution due to the changes that have been made by that
+distribution, or due to the distribution supporting a kernel version
+that is no longer one of the kernel.org supported releases, then a CVE
+can not be assigned by the Linux kernel CVE team, and must be asked for
+from that Linux distribution itself.
+
+Any CVE that is assigned against the Linux kernel for an actively
+supported kernel version, by any group other than the kernel assignment
+CVE team should not be treated as a valid CVE.  Please notify the
+kernel CVE assignment team at <cve@kernel.org> so that they can work to
+invalidate such entries through the CNA remediation process.
+
+Applicability of specific CVEs
+==============================
+
+As the Linux kernel can be used in many different ways, with many
+different ways of accessing it by external users, or no access at all,
+the applicability of any specific CVE is up to the user of Linux to
+determine, it is not up to the CVE assignment team.  Please do not
+contact us to attempt to determine the applicability of any specific
+CVE.
+
+Also, as the source tree is so large, and any one system only uses a
+small subset of the source tree, any users of Linux should be aware that
+large numbers of assigned CVEs are not relevant for their systems.
+
+In short, we do not know your use case, and we do not know what portions
+of the kernel that you use, so there is no way for us to determine if a
+specific CVE is relevant for your system.
+
+As always, it is best to take all released kernel changes, as they are
+tested together in a unified whole by many community members, and not as
+individual cherry-picked changes.  Also note that for many bugs, the
+solution to the overall problem is not found in a single change, but by
+the sum of many fixes on top of each other.  Ideally CVEs will be
+assigned to all fixes for all issues, but sometimes we will fail to
+notice fixes, therefore assume that some changes without a CVE assigned
+might be relevant to take.
+
index 6cb732dfcc72245639e93638083c60fdb7141195..de9cbb7bd7eb2b3a064a93ca2b025bdaf63a42c7 100644 (file)
@@ -81,6 +81,7 @@ of special classes of bugs: regressions and security problems.
 
    handling-regressions
    security-bugs
+   cve
    embargoed-hardware-issues
 
 Maintainer information
index 84ee60fceef24cbf1ba9e090ac91c94abd4064b5..fd96e4a3cef9c09382e34419ec3f8ac1c5514cf4 100644 (file)
@@ -431,7 +431,7 @@ patchwork checks
 Checks in patchwork are mostly simple wrappers around existing kernel
 scripts, the sources are available at:
 
-https://github.com/kuba-moo/nipa/tree/master/tests
+https://github.com/linux-netdev/nipa/tree/master/tests
 
 **Do not** post your patches just to run them through the checks.
 You must ensure that your patches are ready by testing them locally
index 08dd0f804410b6dde4635c77ed930b70e57c8cac..497bb39727c8b05808720a5b41fbeca68ab81681 100644 (file)
@@ -304,13 +304,15 @@ following tag ordering scheme:
 
  - Reported-by: ``Reporter <reporter@mail>``
 
+ - Closes: ``URL or Message-ID of the bug report this is fixing``
+
  - Originally-by: ``Original author <original-author@mail>``
 
  - Suggested-by: ``Suggester <suggester@mail>``
 
  - Co-developed-by: ``Co-author <co-author@mail>``
 
-   Signed-off: ``Co-author <co-author@mail>``
+   Signed-off-by: ``Co-author <co-author@mail>``
 
    Note, that Co-developed-by and Signed-off-by of the co-author(s) must
    come in pairs.
@@ -478,7 +480,7 @@ Multi-line comments::
         * Larger multi-line comments should be split into paragraphs.
         */
 
-No tail comments:
+No tail comments (see below):
 
   Please refrain from using tail comments. Tail comments disturb the
   reading flow in almost all contexts, but especially in code::
@@ -499,6 +501,34 @@ No tail comments:
        /* This magic initialization needs a comment. Maybe not? */
        seed = MAGIC_CONSTANT;
 
+  Use C++ style, tail comments when documenting structs in headers to
+  achieve a more compact layout and better readability::
+
+        // eax
+        u32     x2apic_shift    :  5, // Number of bits to shift APIC ID right
+                                      // for the topology ID at the next level
+                                : 27; // Reserved
+        // ebx
+        u32     num_processors  : 16, // Number of processors at current level
+                                : 16; // Reserved
+
+  versus::
+
+       /* eax */
+               /*
+                * Number of bits to shift APIC ID right for the topology ID
+                * at the next level
+                */
+         u32     x2apic_shift    :  5,
+                /* Reserved */
+                                : 27;
+
+       /* ebx */
+               /* Number of processors at current level */
+       u32     num_processors  : 16,
+               /* Reserved */
+                               : 16;
+
 Comment the important things:
 
   Comments should be added where the operation is not obvious. Documenting
index 692a3ba56cca83742f77edc5161167060d76f414..56c560a00b37a6a3e99a7d9edaa45a103d7398bb 100644 (file)
@@ -99,9 +99,8 @@ CVE assignment
 The security team does not assign CVEs, nor do we require them for
 reports or fixes, as this can needlessly complicate the process and may
 delay the bug handling.  If a reporter wishes to have a CVE identifier
-assigned, they should find one by themselves, for example by contacting
-MITRE directly.  However under no circumstances will a patch inclusion
-be delayed to wait for a CVE identifier to arrive.
+assigned for a confirmed issue, they can contact the :doc:`kernel CVE
+assignment team<../process/cve>` to obtain one.
 
 Non-disclosure agreements
 -------------------------
index 236c6dd3c647f815b5096df2d23ae5ac38cb364a..081397827a7eab66bb45648bf0e9e9f67497125e 100644 (file)
@@ -77,27 +77,3 @@ configuration:
        #[cfg(CONFIG_X="y")]   // Enabled as a built-in (`y`)
        #[cfg(CONFIG_X="m")]   // Enabled as a module   (`m`)
        #[cfg(not(CONFIG_X))]  // Disabled
-
-
-Testing
--------
-
-There are the tests that come from the examples in the Rust documentation
-and get transformed into KUnit tests. These can be run via KUnit. For example
-via ``kunit_tool`` (``kunit.py``) on the command line::
-
-       ./tools/testing/kunit/kunit.py run --make_options LLVM=1 --arch x86_64 --kconfig_add CONFIG_RUST=y
-
-Alternatively, KUnit can run them as kernel built-in at boot. Refer to
-Documentation/dev-tools/kunit/index.rst for the general KUnit documentation
-and Documentation/dev-tools/kunit/architecture.rst for the details of kernel
-built-in vs. command line testing.
-
-Additionally, there are the ``#[test]`` tests. These can be run using
-the ``rusttest`` Make target::
-
-       make LLVM=1 rusttest
-
-This requires the kernel ``.config`` and downloads external repositories.
-It runs the ``#[test]`` tests on the host (currently) and thus is fairly
-limited in what these tests can test.
index 965f2db529e0ff9b02990e870345e7be5cf1d1cb..46d35bd395cf5c4a8cca021a9c204e218c5e672f 100644 (file)
@@ -40,6 +40,7 @@ configurations.
     general-information
     coding-guidelines
     arch-support
+    testing
 
 .. only::  subproject and html
 
diff --git a/Documentation/rust/testing.rst b/Documentation/rust/testing.rst
new file mode 100644 (file)
index 0000000..6658998
--- /dev/null
@@ -0,0 +1,135 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Testing
+=======
+
+This document contains useful information how to test the Rust code in the
+kernel.
+
+There are two sorts of tests:
+
+- The KUnit tests.
+- The ``#[test]`` tests.
+
+The KUnit tests
+---------------
+
+These are the tests that come from the examples in the Rust documentation. They
+get transformed into KUnit tests.
+
+Usage
+*****
+
+These tests can be run via KUnit. For example via ``kunit_tool`` (``kunit.py``)
+on the command line::
+
+       ./tools/testing/kunit/kunit.py run --make_options LLVM=1 --arch x86_64 --kconfig_add CONFIG_RUST=y
+
+Alternatively, KUnit can run them as kernel built-in at boot. Refer to
+Documentation/dev-tools/kunit/index.rst for the general KUnit documentation
+and Documentation/dev-tools/kunit/architecture.rst for the details of kernel
+built-in vs. command line testing.
+
+To use these KUnit doctests, the following must be enabled::
+
+       CONFIG_KUNIT
+          Kernel hacking -> Kernel Testing and Coverage -> KUnit - Enable support for unit tests
+       CONFIG_RUST_KERNEL_DOCTESTS
+          Kernel hacking -> Rust hacking -> Doctests for the `kernel` crate
+
+in the kernel config system.
+
+KUnit tests are documentation tests
+***********************************
+
+These documentation tests are typically examples of usage of any item (e.g.
+function, struct, module...).
+
+They are very convenient because they are just written alongside the
+documentation. For instance:
+
+.. code-block:: rust
+
+       /// Sums two numbers.
+       ///
+       /// ```
+       /// assert_eq!(mymod::f(10, 20), 30);
+       /// ```
+       pub fn f(a: i32, b: i32) -> i32 {
+           a + b
+       }
+
+In userspace, the tests are collected and run via ``rustdoc``. Using the tool
+as-is would be useful already, since it allows verifying that examples compile
+(thus enforcing they are kept in sync with the code they document) and as well
+as running those that do not depend on in-kernel APIs.
+
+For the kernel, however, these tests get transformed into KUnit test suites.
+This means that doctests get compiled as Rust kernel objects, allowing them to
+run against a built kernel.
+
+A benefit of this KUnit integration is that Rust doctests get to reuse existing
+testing facilities. For instance, the kernel log would look like::
+
+       KTAP version 1
+       1..1
+           KTAP version 1
+           # Subtest: rust_doctests_kernel
+           1..59
+           # rust_doctest_kernel_build_assert_rs_0.location: rust/kernel/build_assert.rs:13
+           ok 1 rust_doctest_kernel_build_assert_rs_0
+           # rust_doctest_kernel_build_assert_rs_1.location: rust/kernel/build_assert.rs:56
+           ok 2 rust_doctest_kernel_build_assert_rs_1
+           # rust_doctest_kernel_init_rs_0.location: rust/kernel/init.rs:122
+           ok 3 rust_doctest_kernel_init_rs_0
+           ...
+           # rust_doctest_kernel_types_rs_2.location: rust/kernel/types.rs:150
+           ok 59 rust_doctest_kernel_types_rs_2
+       # rust_doctests_kernel: pass:59 fail:0 skip:0 total:59
+       # Totals: pass:59 fail:0 skip:0 total:59
+       ok 1 rust_doctests_kernel
+
+Tests using the `? <https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator>`_
+operator are also supported as usual, e.g.:
+
+.. code-block:: rust
+
+       /// ```
+       /// # use kernel::{spawn_work_item, workqueue};
+       /// spawn_work_item!(workqueue::system(), || pr_info!("x"))?;
+       /// # Ok::<(), Error>(())
+       /// ```
+
+The tests are also compiled with Clippy under ``CLIPPY=1``, just like normal
+code, thus also benefitting from extra linting.
+
+In order for developers to easily see which line of doctest code caused a
+failure, a KTAP diagnostic line is printed to the log. This contains the
+location (file and line) of the original test (i.e. instead of the location in
+the generated Rust file)::
+
+       # rust_doctest_kernel_types_rs_2.location: rust/kernel/types.rs:150
+
+Rust tests appear to assert using the usual ``assert!`` and ``assert_eq!``
+macros from the Rust standard library (``core``). We provide a custom version
+that forwards the call to KUnit instead. Importantly, these macros do not
+require passing context, unlike those for KUnit testing (i.e.
+``struct kunit *``). This makes them easier to use, and readers of the
+documentation do not need to care about which testing framework is used. In
+addition, it may allow us to test third-party code more easily in the future.
+
+A current limitation is that KUnit does not support assertions in other tasks.
+Thus, we presently simply print an error to the kernel log if an assertion
+actually failed. Additionally, doctests are not run for nonpublic functions.
+
+The ``#[test]`` tests
+---------------------
+
+Additionally, there are the ``#[test]`` tests. These can be run using the
+``rusttest`` Make target::
+
+       make LLVM=1 rusttest
+
+This requires the kernel ``.config`` and downloads external repositories. It
+runs the ``#[test]`` tests on the host (currently) and thus is fairly limited in
+what these tests can test.
index b9df61eb45013872ca82b463048494e041b3f127..03ace5f01b5c021e12adba23b83b8cb074c949ba 100644 (file)
@@ -109,7 +109,7 @@ class KernelFeat(Directive):
             else:
                 out_lines += line + "\n"
 
-        nodeList = self.nestedParse(out_lines, fname)
+        nodeList = self.nestedParse(out_lines, self.arguments[0])
         return nodeList
 
     def nestedParse(self, lines, fname):
index 47161e6eba9976fa8e67a14905f284ea05d82f21..32c2b32b2b5ee91a27abacfa0332620e208b8723 100644 (file)
@@ -29,10 +29,7 @@ all_languages = {
 }
 
 class LanguagesNode(nodes.Element):
-    def __init__(self, current_language, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-
-        self.current_language = current_language
+    pass
 
 class TranslationsTransform(Transform):
     default_priority = 900
@@ -49,7 +46,8 @@ class TranslationsTransform(Transform):
             # normalize docname to be the untranslated one
             docname = os.path.join(*components[2:])
 
-        new_nodes = LanguagesNode(all_languages[this_lang_code])
+        new_nodes = LanguagesNode()
+        new_nodes['current_language'] = all_languages[this_lang_code]
 
         for lang_code, lang_name in all_languages.items():
             if lang_code == this_lang_code:
@@ -84,7 +82,7 @@ def process_languages(app, doctree, docname):
 
         html_content = app.builder.templates.render('translations.html',
             context={
-                'current_language': node.current_language,
+                'current_language': node['current_language'],
                 'languages': languages,
             })
 
index 457e16f06e04defe9f998ba74ff6577b7ff13490..3731ecf1e4370df533430bb2debdc046acdffb88 100644 (file)
@@ -82,8 +82,9 @@ Code  Seq#    Include File                                           Comments
 0x10  00-0F  drivers/char/s390/vmcp.h
 0x10  10-1F  arch/s390/include/uapi/sclp_ctl.h
 0x10  20-2F  arch/s390/include/uapi/asm/hypfs.h
-0x12  all    linux/fs.h
+0x12  all    linux/fs.h                                              BLK* ioctls
              linux/blkpg.h
+0x15  all    linux/fs.h                                              FS_IOC_* ioctls
 0x1b  all                                                            InfiniBand Subsystem
                                                                      <http://infiniband.sourceforge.net/>
 0x20  all    drivers/cdrom/cm206.h
index 68b0d2363af820256c70ba2d5284244247ee979f..e1eaf6a830ce4d87839c9c293e4980070bd5b606 100644 (file)
@@ -67,6 +67,23 @@ counter (e.g. counter overflow), then -EIO will be returned.
                 };
         };
 
+The host ioctls are issued to a file descriptor of the /dev/sev device.
+The ioctl accepts the command ID/input structure documented below.
+
+::
+
+        struct sev_issue_cmd {
+                /* Command ID */
+                __u32 cmd;
+
+                /* Command request structure */
+                __u64 data;
+
+                /* Firmware error code on failure (see psp-sev.h) */
+                __u32 error;
+        };
+
+
 2.1 SNP_GET_REPORT
 ------------------
 
@@ -124,6 +141,41 @@ be updated with the expected value.
 
 See GHCB specification for further detail on how to parse the certificate blob.
 
+2.4 SNP_PLATFORM_STATUS
+-----------------------
+:Technology: sev-snp
+:Type: hypervisor ioctl cmd
+:Parameters (out): struct sev_user_data_snp_status
+:Returns (out): 0 on success, -negative on error
+
+The SNP_PLATFORM_STATUS command is used to query the SNP platform status. The
+status includes API major, minor version and more. See the SEV-SNP
+specification for further details.
+
+2.5 SNP_COMMIT
+--------------
+:Technology: sev-snp
+:Type: hypervisor ioctl cmd
+:Returns (out): 0 on success, -negative on error
+
+SNP_COMMIT is used to commit the currently installed firmware using the
+SEV-SNP firmware SNP_COMMIT command. This prevents roll-back to a previously
+committed firmware version. This will also update the reported TCB to match
+that of the currently installed firmware.
+
+2.6 SNP_SET_CONFIG
+------------------
+:Technology: sev-snp
+:Type: hypervisor ioctl cmd
+:Parameters (in): struct sev_user_data_snp_config
+:Returns (out): 0 on success, -negative on error
+
+SNP_SET_CONFIG is used to set the system-wide configuration such as
+reported TCB version in the attestation report. The command is similar
+to SNP_CONFIG command defined in the SEV-SNP spec. The current values of
+the firmware parameters affected by this command can be queried via
+SNP_PLATFORM_STATUS.
+
 3. SEV-SNP CPUID Enforcement
 ============================
 
index 4a7a1b738bbead3563cbc70a67c038725d0aadfd..de447e11b4a5c3b9a0948712e59d1d065130a1f7 100644 (file)
@@ -10,3 +10,4 @@ Hyper-V Enlightenments
    overview
    vmbus
    clocks
+   vpci
diff --git a/Documentation/virt/hyperv/vpci.rst b/Documentation/virt/hyperv/vpci.rst
new file mode 100644 (file)
index 0000000..b65b212
--- /dev/null
@@ -0,0 +1,316 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+PCI pass-thru devices
+=========================
+In a Hyper-V guest VM, PCI pass-thru devices (also called
+virtual PCI devices, or vPCI devices) are physical PCI devices
+that are mapped directly into the VM's physical address space.
+Guest device drivers can interact directly with the hardware
+without intermediation by the host hypervisor.  This approach
+provides higher bandwidth access to the device with lower
+latency, compared with devices that are virtualized by the
+hypervisor.  The device should appear to the guest just as it
+would when running on bare metal, so no changes are required
+to the Linux device drivers for the device.
+
+Hyper-V terminology for vPCI devices is "Discrete Device
+Assignment" (DDA).  Public documentation for Hyper-V DDA is
+available here: `DDA`_
+
+.. _DDA: https://learn.microsoft.com/en-us/windows-server/virtualization/hyper-v/plan/plan-for-deploying-devices-using-discrete-device-assignment
+
+DDA is typically used for storage controllers, such as NVMe,
+and for GPUs.  A similar mechanism for NICs is called SR-IOV
+and produces the same benefits by allowing a guest device
+driver to interact directly with the hardware.  See Hyper-V
+public documentation here: `SR-IOV`_
+
+.. _SR-IOV: https://learn.microsoft.com/en-us/windows-hardware/drivers/network/overview-of-single-root-i-o-virtualization--sr-iov-
+
+This discussion of vPCI devices includes DDA and SR-IOV
+devices.
+
+Device Presentation
+-------------------
+Hyper-V provides full PCI functionality for a vPCI device when
+it is operating, so the Linux device driver for the device can
+be used unchanged, provided it uses the correct Linux kernel
+APIs for accessing PCI config space and for other integration
+with Linux.  But the initial detection of the PCI device and
+its integration with the Linux PCI subsystem must use Hyper-V
+specific mechanisms.  Consequently, vPCI devices on Hyper-V
+have a dual identity.  They are initially presented to Linux
+guests as VMBus devices via the standard VMBus "offer"
+mechanism, so they have a VMBus identity and appear under
+/sys/bus/vmbus/devices.  The VMBus vPCI driver in Linux at
+drivers/pci/controller/pci-hyperv.c handles a newly introduced
+vPCI device by fabricating a PCI bus topology and creating all
+the normal PCI device data structures in Linux that would
+exist if the PCI device were discovered via ACPI on a bare-
+metal system.  Once those data structures are set up, the
+device also has a normal PCI identity in Linux, and the normal
+Linux device driver for the vPCI device can function as if it
+were running in Linux on bare-metal.  Because vPCI devices are
+presented dynamically through the VMBus offer mechanism, they
+do not appear in the Linux guest's ACPI tables.  vPCI devices
+may be added to a VM or removed from a VM at any time during
+the life of the VM, and not just during initial boot.
+
+With this approach, the vPCI device is a VMBus device and a
+PCI device at the same time.  In response to the VMBus offer
+message, the hv_pci_probe() function runs and establishes a
+VMBus connection to the vPCI VSP on the Hyper-V host.  That
+connection has a single VMBus channel.  The channel is used to
+exchange messages with the vPCI VSP for the purpose of setting
+up and configuring the vPCI device in Linux.  Once the device
+is fully configured in Linux as a PCI device, the VMBus
+channel is used only if Linux changes the vCPU to be interrupted
+in the guest, or if the vPCI device is removed from
+the VM while the VM is running.  The ongoing operation of the
+device happens directly between the Linux device driver for
+the device and the hardware, with VMBus and the VMBus channel
+playing no role.
+
+PCI Device Setup
+----------------
+PCI device setup follows a sequence that Hyper-V originally
+created for Windows guests, and that can be ill-suited for
+Linux guests due to differences in the overall structure of
+the Linux PCI subsystem compared with Windows.  Nonetheless,
+with a bit of hackery in the Hyper-V virtual PCI driver for
+Linux, the virtual PCI device is setup in Linux so that
+generic Linux PCI subsystem code and the Linux driver for the
+device "just work".
+
+Each vPCI device is set up in Linux to be in its own PCI
+domain with a host bridge.  The PCI domainID is derived from
+bytes 4 and 5 of the instance GUID assigned to the VMBus vPCI
+device.  The Hyper-V host does not guarantee that these bytes
+are unique, so hv_pci_probe() has an algorithm to resolve
+collisions.  The collision resolution is intended to be stable
+across reboots of the same VM so that the PCI domainIDs don't
+change, as the domainID appears in the user space
+configuration of some devices.
+
+hv_pci_probe() allocates a guest MMIO range to be used as PCI
+config space for the device.  This MMIO range is communicated
+to the Hyper-V host over the VMBus channel as part of telling
+the host that the device is ready to enter d0.  See
+hv_pci_enter_d0().  When the guest subsequently accesses this
+MMIO range, the Hyper-V host intercepts the accesses and maps
+them to the physical device PCI config space.
+
+hv_pci_probe() also gets BAR information for the device from
+the Hyper-V host, and uses this information to allocate MMIO
+space for the BARs.  That MMIO space is then setup to be
+associated with the host bridge so that it works when generic
+PCI subsystem code in Linux processes the BARs.
+
+Finally, hv_pci_probe() creates the root PCI bus.  At this
+point the Hyper-V virtual PCI driver hackery is done, and the
+normal Linux PCI machinery for scanning the root bus works to
+detect the device, to perform driver matching, and to
+initialize the driver and device.
+
+PCI Device Removal
+------------------
+A Hyper-V host may initiate removal of a vPCI device from a
+guest VM at any time during the life of the VM.  The removal
+is instigated by an admin action taken on the Hyper-V host and
+is not under the control of the guest OS.
+
+A guest VM is notified of the removal by an unsolicited
+"Eject" message sent from the host to the guest over the VMBus
+channel associated with the vPCI device.  Upon receipt of such
+a message, the Hyper-V virtual PCI driver in Linux
+asynchronously invokes Linux kernel PCI subsystem calls to
+shutdown and remove the device.  When those calls are
+complete, an "Ejection Complete" message is sent back to
+Hyper-V over the VMBus channel indicating that the device has
+been removed.  At this point, Hyper-V sends a VMBus rescind
+message to the Linux guest, which the VMBus driver in Linux
+processes by removing the VMBus identity for the device.  Once
+that processing is complete, all vestiges of the device having
+been present are gone from the Linux kernel.  The rescind
+message also indicates to the guest that Hyper-V has stopped
+providing support for the vPCI device in the guest.  If the
+guest were to attempt to access that device's MMIO space, it
+would be an invalid reference. Hypercalls affecting the device
+return errors, and any further messages sent in the VMBus
+channel are ignored.
+
+After sending the Eject message, Hyper-V allows the guest VM
+60 seconds to cleanly shutdown the device and respond with
+Ejection Complete before sending the VMBus rescind
+message.  If for any reason the Eject steps don't complete
+within the allowed 60 seconds, the Hyper-V host forcibly
+performs the rescind steps, which will likely result in
+cascading errors in the guest because the device is now no
+longer present from the guest standpoint and accessing the
+device MMIO space will fail.
+
+Because ejection is asynchronous and can happen at any point
+during the guest VM lifecycle, proper synchronization in the
+Hyper-V virtual PCI driver is very tricky.  Ejection has been
+observed even before a newly offered vPCI device has been
+fully setup.  The Hyper-V virtual PCI driver has been updated
+several times over the years to fix race conditions when
+ejections happen at inopportune times. Care must be taken when
+modifying this code to prevent re-introducing such problems.
+See comments in the code.
+
+Interrupt Assignment
+--------------------
+The Hyper-V virtual PCI driver supports vPCI devices using
+MSI, multi-MSI, or MSI-X.  Assigning the guest vCPU that will
+receive the interrupt for a particular MSI or MSI-X message is
+complex because of the way the Linux setup of IRQs maps onto
+the Hyper-V interfaces.  For the single-MSI and MSI-X cases,
+Linux calls hv_compse_msi_msg() twice, with the first call
+containing a dummy vCPU and the second call containing the
+real vCPU.  Furthermore, hv_irq_unmask() is finally called
+(on x86) or the GICD registers are set (on arm64) to specify
+the real vCPU again.  Each of these three calls interact
+with Hyper-V, which must decide which physical CPU should
+receive the interrupt before it is forwarded to the guest VM.
+Unfortunately, the Hyper-V decision-making process is a bit
+limited, and can result in concentrating the physical
+interrupts on a single CPU, causing a performance bottleneck.
+See details about how this is resolved in the extensive
+comment above the function hv_compose_msi_req_get_cpu().
+
+The Hyper-V virtual PCI driver implements the
+irq_chip.irq_compose_msi_msg function as hv_compose_msi_msg().
+Unfortunately, on Hyper-V the implementation requires sending
+a VMBus message to the Hyper-V host and awaiting an interrupt
+indicating receipt of a reply message.  Since
+irq_chip.irq_compose_msi_msg can be called with IRQ locks
+held, it doesn't work to do the normal sleep until awakened by
+the interrupt. Instead hv_compose_msi_msg() must send the
+VMBus message, and then poll for the completion message. As
+further complexity, the vPCI device could be ejected/rescinded
+while the polling is in progress, so this scenario must be
+detected as well.  See comments in the code regarding this
+very tricky area.
+
+Most of the code in the Hyper-V virtual PCI driver (pci-
+hyperv.c) applies to Hyper-V and Linux guests running on x86
+and on arm64 architectures.  But there are differences in how
+interrupt assignments are managed.  On x86, the Hyper-V
+virtual PCI driver in the guest must make a hypercall to tell
+Hyper-V which guest vCPU should be interrupted by each
+MSI/MSI-X interrupt, and the x86 interrupt vector number that
+the x86_vector IRQ domain has picked for the interrupt.  This
+hypercall is made by hv_arch_irq_unmask().  On arm64, the
+Hyper-V virtual PCI driver manages the allocation of an SPI
+for each MSI/MSI-X interrupt.  The Hyper-V virtual PCI driver
+stores the allocated SPI in the architectural GICD registers,
+which Hyper-V emulates, so no hypercall is necessary as with
+x86.  Hyper-V does not support using LPIs for vPCI devices in
+arm64 guest VMs because it does not emulate a GICv3 ITS.
+
+The Hyper-V virtual PCI driver in Linux supports vPCI devices
+whose drivers create managed or unmanaged Linux IRQs.  If the
+smp_affinity for an unmanaged IRQ is updated via the /proc/irq
+interface, the Hyper-V virtual PCI driver is called to tell
+the Hyper-V host to change the interrupt targeting and
+everything works properly.  However, on x86 if the x86_vector
+IRQ domain needs to reassign an interrupt vector due to
+running out of vectors on a CPU, there's no path to inform the
+Hyper-V host of the change, and things break.  Fortunately,
+guest VMs operate in a constrained device environment where
+using all the vectors on a CPU doesn't happen. Since such a
+problem is only a theoretical concern rather than a practical
+concern, it has been left unaddressed.
+
+DMA
+---
+By default, Hyper-V pins all guest VM memory in the host
+when the VM is created, and programs the physical IOMMU to
+allow the VM to have DMA access to all its memory.  Hence
+it is safe to assign PCI devices to the VM, and allow the
+guest operating system to program the DMA transfers.  The
+physical IOMMU prevents a malicious guest from initiating
+DMA to memory belonging to the host or to other VMs on the
+host. From the Linux guest standpoint, such DMA transfers
+are in "direct" mode since Hyper-V does not provide a virtual
+IOMMU in the guest.
+
+Hyper-V assumes that physical PCI devices always perform
+cache-coherent DMA.  When running on x86, this behavior is
+required by the architecture.  When running on arm64, the
+architecture allows for both cache-coherent and
+non-cache-coherent devices, with the behavior of each device
+specified in the ACPI DSDT.  But when a PCI device is assigned
+to a guest VM, that device does not appear in the DSDT, so the
+Hyper-V VMBus driver propagates cache-coherency information
+from the VMBus node in the ACPI DSDT to all VMBus devices,
+including vPCI devices (since they have a dual identity as a VMBus
+device and as a PCI device).  See vmbus_dma_configure().
+Current Hyper-V versions always indicate that the VMBus is
+cache coherent, so vPCI devices on arm64 always get marked as
+cache coherent and the CPU does not perform any sync
+operations as part of dma_map/unmap_*() calls.
+
+vPCI protocol versions
+----------------------
+As previously described, during vPCI device setup and teardown
+messages are passed over a VMBus channel between the Hyper-V
+host and the Hyper-v vPCI driver in the Linux guest.  Some
+messages have been revised in newer versions of Hyper-V, so
+the guest and host must agree on the vPCI protocol version to
+be used.  The version is negotiated when communication over
+the VMBus channel is first established.  See
+hv_pci_protocol_negotiation(). Newer versions of the protocol
+extend support to VMs with more than 64 vCPUs, and provide
+additional information about the vPCI device, such as the
+guest virtual NUMA node to which it is most closely affined in
+the underlying hardware.
+
+Guest NUMA node affinity
+------------------------
+When the vPCI protocol version provides it, the guest NUMA
+node affinity of the vPCI device is stored as part of the Linux
+device information for subsequent use by the Linux driver. See
+hv_pci_assign_numa_node().  If the negotiated protocol version
+does not support the host providing NUMA affinity information,
+the Linux guest defaults the device NUMA node to 0.  But even
+when the negotiated protocol version includes NUMA affinity
+information, the ability of the host to provide such
+information depends on certain host configuration options.  If
+the guest receives NUMA node value "0", it could mean NUMA
+node 0, or it could mean "no information is available".
+Unfortunately it is not possible to distinguish the two cases
+from the guest side.
+
+PCI config space access in a CoCo VM
+------------------------------------
+Linux PCI device drivers access PCI config space using a
+standard set of functions provided by the Linux PCI subsystem.
+In Hyper-V guests these standard functions map to functions
+hv_pcifront_read_config() and hv_pcifront_write_config()
+in the Hyper-V virtual PCI driver.  In normal VMs,
+these hv_pcifront_*() functions directly access the PCI config
+space, and the accesses trap to Hyper-V to be handled.
+But in CoCo VMs, memory encryption prevents Hyper-V
+from reading the guest instruction stream to emulate the
+access, so the hv_pcifront_*() functions must invoke
+hypercalls with explicit arguments describing the access to be
+made.
+
+Config Block back-channel
+-------------------------
+The Hyper-V host and Hyper-V virtual PCI driver in Linux
+together implement a non-standard back-channel communication
+path between the host and guest.  The back-channel path uses
+messages sent over the VMBus channel associated with the vPCI
+device.  The functions hyperv_read_cfg_blk() and
+hyperv_write_cfg_blk() are the primary interfaces provided to
+other parts of the Linux kernel.  As of this writing, these
+interfaces are used only by the Mellanox mlx5 driver to pass
+diagnostic data to a Hyper-V host running in the Azure public
+cloud.  The functions hyperv_read_cfg_blk() and
+hyperv_write_cfg_blk() are implemented in a separate module
+(pci-hyperv-intf.c, under CONFIG_PCI_HYPERV_INTERFACE) that
+effectively stubs them out when running in non-Hyper-V
+environments.
index 3ec0b7a455a0cf489b93683a49b5362cded0b570..09c7e585ff5800da5a72a1f9dbd8b719f0b6d595 100644 (file)
@@ -8791,6 +8791,11 @@ means the VM type with value @n is supported.  Possible values of @n are::
   #define KVM_X86_DEFAULT_VM   0
   #define KVM_X86_SW_PROTECTED_VM      1
 
+Note, KVM_X86_SW_PROTECTED_VM is currently only for development and testing.
+Do not use KVM_X86_SW_PROTECTED_VM for "real" VMs, and especially not in
+production.  The behavior and effective ABI for software-protected VMs is
+unstable.
+
 9. Known KVM API problems
 =========================
 
index 73d898383e51f9c3a7ef6769cf9f6f6095f522e9..c660e9be8ce6940e8faafa985cc2f1e517daf957 100644 (file)
@@ -897,6 +897,12 @@ Q: https://patchwork.kernel.org/project/linux-rdma/list/
 F:     drivers/infiniband/hw/efa/
 F:     include/uapi/rdma/efa-abi.h
 
+AMD ADDRESS TRANSLATION LIBRARY (ATL)
+M:     Yazen Ghannam <Yazen.Ghannam@amd.com>
+L:     linux-edac@vger.kernel.org
+S:     Supported
+F:     drivers/ras/amd/atl/*
+
 AMD AXI W1 DRIVER
 M:     Kris Chaplin <kris.chaplin@amd.com>
 R:     Thomas Delev <thomas.delev@amd.com>
@@ -1395,6 +1401,7 @@ F:        drivers/hwmon/max31760.c
 
 ANALOGBITS PLL LIBRARIES
 M:     Paul Walmsley <paul.walmsley@sifive.com>
+M:     Samuel Holland <samuel.holland@sifive.com>
 S:     Supported
 F:     drivers/clk/analogbits/*
 F:     include/linux/clk/analogbits*
@@ -2156,7 +2163,7 @@ M:        Shawn Guo <shawnguo@kernel.org>
 M:     Sascha Hauer <s.hauer@pengutronix.de>
 R:     Pengutronix Kernel Team <kernel@pengutronix.de>
 R:     Fabio Estevam <festevam@gmail.com>
-R:     NXP Linux Team <linux-imx@nxp.com>
+L:     imx@lists.linux.dev
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
@@ -2542,13 +2549,14 @@ F:      drivers/*/*/*wpcm*
 F:     drivers/*/*wpcm*
 
 ARM/NXP S32G ARCHITECTURE
-M:     Chester Lin <chester62515@gmail.com>
-R:     Andreas Färber <afaerber@suse.de>
+R:     Chester Lin <chester62515@gmail.com>
 R:     Matthias Brugger <mbrugger@suse.com>
-R:     NXP S32 Linux Team <s32@nxp.com>
+R:     Ghennadi Procopciuc <ghennadi.procopciuc@oss.nxp.com>
+L:     NXP S32 Linux Team <s32@nxp.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm64/boot/dts/freescale/s32g*.dts*
+F:     drivers/pinctrl/nxp/
 
 ARM/Orion SoC/Technologic Systems TS-78xx platform support
 M:     Alexander Clouter <alex@digriz.org.uk>
@@ -5378,7 +5386,7 @@ CONTROL GROUP - MEMORY RESOURCE CONTROLLER (MEMCG)
 M:     Johannes Weiner <hannes@cmpxchg.org>
 M:     Michal Hocko <mhocko@kernel.org>
 M:     Roman Gushchin <roman.gushchin@linux.dev>
-M:     Shakeel Butt <shakeelb@google.com>
+M:     Shakeel Butt <shakeel.butt@linux.dev>
 R:     Muchun Song <muchun.song@linux.dev>
 L:     cgroups@vger.kernel.org
 L:     linux-mm@kvack.org
@@ -5610,6 +5618,11 @@ S:       Maintained
 F:     Documentation/devicetree/bindings/net/can/ctu,ctucanfd.yaml
 F:     drivers/net/can/ctucanfd/
 
+CVE ASSIGNMENT CONTACT
+M:     CVE Assignment Team <cve@kernel.org>
+S:     Maintained
+F:     Documentation/process/cve.rst
+
 CW1200 WLAN driver
 S:     Orphan
 F:     drivers/net/wireless/st/cw1200/
@@ -7577,7 +7590,6 @@ R:        Robert Richter <rric@kernel.org>
 L:     linux-edac@vger.kernel.org
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras.git edac-for-next
-F:     Documentation/admin-guide/ras.rst
 F:     Documentation/driver-api/edac.rst
 F:     drivers/edac/
 F:     include/linux/edac.h
@@ -8490,7 +8502,7 @@ FREESCALE IMX / MXC FEC DRIVER
 M:     Wei Fang <wei.fang@nxp.com>
 R:     Shenwei Wang <shenwei.wang@nxp.com>
 R:     Clark Wang <xiaoning.wang@nxp.com>
-R:     NXP Linux Team <linux-imx@nxp.com>
+L:     imx@lists.linux.dev
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/net/fsl,fec.yaml
@@ -8525,7 +8537,7 @@ F:        drivers/i2c/busses/i2c-imx.c
 FREESCALE IMX LPI2C DRIVER
 M:     Dong Aisheng <aisheng.dong@nxp.com>
 L:     linux-i2c@vger.kernel.org
-L:     linux-imx@nxp.com
+L:     imx@lists.linux.dev
 S:     Maintained
 F:     Documentation/devicetree/bindings/i2c/i2c-imx-lpi2c.yaml
 F:     drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -9080,6 +9092,7 @@ F:        Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
 F:     arch/arm64/boot/dts/exynos/google/
 F:     drivers/clk/samsung/clk-gs101.c
 F:     include/dt-bindings/clock/google,gs101.h
+K:     [gG]oogle.?[tT]ensor
 
 GPD POCKET FAN DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
@@ -10471,7 +10484,8 @@ M:      Donald Robson <donald.robson@imgtec.com>
 M:     Matt Coster <matt.coster@imgtec.com>
 S:     Supported
 T:     git git://anongit.freedesktop.org/drm/drm-misc
-F:     Documentation/devicetree/bindings/gpu/img,powervr.yaml
+F:     Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml
+F:     Documentation/devicetree/bindings/gpu/img,powervr-sgx.yaml
 F:     Documentation/gpu/imagination/
 F:     drivers/gpu/drm/imagination/
 F:     include/uapi/drm/pvr_drm.h
@@ -10729,7 +10743,7 @@ INTEL DRM I915 DRIVER (Meteor Lake, DG2 and older excluding Poulsbo, Moorestown
 M:     Jani Nikula <jani.nikula@linux.intel.com>
 M:     Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
 M:     Rodrigo Vivi <rodrigo.vivi@intel.com>
-M:     Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
+M:     Tvrtko Ursulin <tursulin@ursulin.net>
 L:     intel-gfx@lists.freedesktop.org
 S:     Supported
 W:     https://drm.pages.freedesktop.org/intel-docs/
@@ -11151,6 +11165,16 @@ L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/wwan/iosm/
 
+INTEL(R) FLEXIBLE RETURN AND EVENT DELIVERY
+M:     Xin Li <xin@zytor.com>
+M:     "H. Peter Anvin" <hpa@zytor.com>
+S:     Supported
+F:     Documentation/arch/x86/x86_64/fred.rst
+F:     arch/x86/entry/entry_64_fred.S
+F:     arch/x86/entry/entry_fred.c
+F:     arch/x86/include/asm/fred.h
+F:     arch/x86/kernel/fred.c
+
 INTEL(R) TRACE HUB
 M:     Alexander Shishkin <alexander.shishkin@linux.intel.com>
 S:     Supported
@@ -12511,7 +12535,6 @@ F:      arch/powerpc/include/asm/livepatch.h
 F:     include/linux/livepatch.h
 F:     kernel/livepatch/
 F:     kernel/module/livepatch.c
-F:     lib/livepatch/
 F:     samples/livepatch/
 F:     tools/testing/selftests/livepatch/
 
@@ -14106,6 +14129,17 @@ F:     mm/
 F:     tools/mm/
 F:     tools/testing/selftests/mm/
 
+MEMORY MAPPING
+M:     Andrew Morton <akpm@linux-foundation.org>
+R:     Liam R. Howlett <Liam.Howlett@oracle.com>
+R:     Vlastimil Babka <vbabka@suse.cz>
+R:     Lorenzo Stoakes <lstoakes@gmail.com>
+L:     linux-mm@kvack.org
+S:     Maintained
+W:     http://www.linux-mm.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
+F:     mm/mmap.c
+
 MEMORY TECHNOLOGY DEVICES (MTD)
 M:     Miquel Raynal <miquel.raynal@bootlin.com>
 M:     Richard Weinberger <richard@nod.at>
@@ -14364,7 +14398,7 @@ MICROCHIP MCP16502 PMIC DRIVER
 M:     Claudiu Beznea <claudiu.beznea@tuxon.dev>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
-F:     Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt
+F:     Documentation/devicetree/bindings/regulator/microchip,mcp16502.yaml
 F:     drivers/regulator/mcp16502.c
 
 MICROCHIP MCP3564 ADC DRIVER
@@ -15237,6 +15271,8 @@ F:      Documentation/networking/
 F:     Documentation/networking/net_cachelines/
 F:     Documentation/process/maintainer-netdev.rst
 F:     Documentation/userspace-api/netlink/
+F:     include/linux/framer/framer-provider.h
+F:     include/linux/framer/framer.h
 F:     include/linux/in.h
 F:     include/linux/indirect_call_wrapper.h
 F:     include/linux/net.h
@@ -15324,7 +15360,7 @@ K:      \bmdo_
 NETWORKING [MPTCP]
 M:     Matthieu Baerts <matttbe@kernel.org>
 M:     Mat Martineau <martineau@kernel.org>
-R:     Geliang Tang <geliang.tang@linux.dev>
+R:     Geliang Tang <geliang@kernel.org>
 L:     netdev@vger.kernel.org
 L:     mptcp@lists.linux.dev
 S:     Maintained
@@ -15571,16 +15607,6 @@ W:     https://github.com/davejiang/linux/wiki
 T:     git https://github.com/davejiang/linux.git
 F:     drivers/ntb/hw/intel/
 
-NTFS FILESYSTEM
-M:     Anton Altaparmakov <anton@tuxera.com>
-R:     Namjae Jeon <linkinjeon@kernel.org>
-L:     linux-ntfs-dev@lists.sourceforge.net
-S:     Supported
-W:     http://www.tuxera.com/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs.git
-F:     Documentation/filesystems/ntfs.rst
-F:     fs/ntfs/
-
 NTFS3 FILESYSTEM
 M:     Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
 L:     ntfs3@lists.linux.dev
@@ -15709,7 +15735,7 @@ F:      drivers/iio/gyro/fxas21002c_spi.c
 NXP i.MX 7D/6SX/6UL/93 AND VF610 ADC DRIVER
 M:     Haibo Chen <haibo.chen@nxp.com>
 L:     linux-iio@vger.kernel.org
-L:     linux-imx@nxp.com
+L:     imx@lists.linux.dev
 S:     Maintained
 F:     Documentation/devicetree/bindings/iio/adc/fsl,imx7d-adc.yaml
 F:     Documentation/devicetree/bindings/iio/adc/fsl,vf610-adc.yaml
@@ -15746,7 +15772,7 @@ F:      drivers/gpu/drm/imx/dcss/
 NXP i.MX 8QXP ADC DRIVER
 M:     Cai Huoqing <cai.huoqing@linux.dev>
 M:     Haibo Chen <haibo.chen@nxp.com>
-L:     linux-imx@nxp.com
+L:     imx@lists.linux.dev
 L:     linux-iio@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/iio/adc/nxp,imx8qxp-adc.yaml
@@ -15754,7 +15780,7 @@ F:      drivers/iio/adc/imx8qxp-adc.c
 
 NXP i.MX 8QXP/8QM JPEG V4L2 DRIVER
 M:     Mirela Rabulea <mirela.rabulea@nxp.com>
-R:     NXP Linux Team <linux-imx@nxp.com>
+L:     imx@lists.linux.dev
 L:     linux-media@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml
@@ -15764,7 +15790,7 @@ NXP i.MX CLOCK DRIVERS
 M:     Abel Vesa <abelvesa@kernel.org>
 R:     Peng Fan <peng.fan@nxp.com>
 L:     linux-clk@vger.kernel.org
-L:     linux-imx@nxp.com
+L:     imx@lists.linux.dev
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux.git clk/imx
 F:     Documentation/devicetree/bindings/clock/imx*
@@ -16725,6 +16751,7 @@ F:      drivers/pci/controller/dwc/*layerscape*
 PCI DRIVER FOR FU740
 M:     Paul Walmsley <paul.walmsley@sifive.com>
 M:     Greentime Hu <greentime.hu@sifive.com>
+M:     Samuel Holland <samuel.holland@sifive.com>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
@@ -16837,6 +16864,7 @@ F:      drivers/pci/controller/dwc/*designware*
 
 PCI DRIVER FOR TI DRA7XX/J721E
 M:     Vignesh Raghavendra <vigneshr@ti.com>
+R:     Siddharth Vadapalli <s-vadapalli@ti.com>
 L:     linux-omap@vger.kernel.org
 L:     linux-pci@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -17263,9 +17291,12 @@ M:     Shawn Guo <shawnguo@kernel.org>
 M:     Jacky Bai <ping.bai@nxp.com>
 R:     Pengutronix Kernel Team <kernel@pengutronix.de>
 L:     linux-gpio@vger.kernel.org
+L:     NXP S32 Linux Team <s32@nxp.com>
 S:     Maintained
 F:     Documentation/devicetree/bindings/pinctrl/fsl,*
+F:     Documentation/devicetree/bindings/pinctrl/nxp,s32*
 F:     drivers/pinctrl/freescale/
+F:     drivers/pinctrl/nxp/
 
 PIN CONTROLLER - INTEL
 M:     Mika Westerberg <mika.westerberg@linux.intel.com>
@@ -17319,14 +17350,6 @@ S:     Supported
 F:     drivers/gpio/gpio-sama5d2-piobu.c
 F:     drivers/pinctrl/pinctrl-at91*
 
-PIN CONTROLLER - NXP S32
-M:     Chester Lin <clin@suse.com>
-R:     NXP S32 Linux Team <s32@nxp.com>
-L:     linux-gpio@vger.kernel.org
-S:     Maintained
-F:     Documentation/devicetree/bindings/pinctrl/nxp,s32*
-F:     drivers/pinctrl/nxp/
-
 PIN CONTROLLER - QUALCOMM
 M:     Bjorn Andersson <andersson@kernel.org>
 L:     linux-arm-msm@vger.kernel.org
@@ -17343,7 +17366,6 @@ F:      Documentation/devicetree/bindings/pinctrl/renesas,*
 F:     drivers/pinctrl/renesas/
 
 PIN CONTROLLER - SAMSUNG
-M:     Tomasz Figa <tomasz.figa@gmail.com>
 M:     Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
 M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
 R:     Alim Akhtar <alim.akhtar@samsung.com>
@@ -17493,6 +17515,7 @@ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 F:     fs/timerfd.c
 F:     include/linux/time_namespace.h
 F:     include/linux/timer*
+F:     include/trace/events/timer*
 F:     kernel/time/*timer*
 F:     kernel/time/namespace.c
 
@@ -17529,6 +17552,7 @@ F:      Documentation/devicetree/bindings/power/supply/
 F:     drivers/power/supply/
 F:     include/linux/power/
 F:     include/linux/power_supply.h
+F:     tools/testing/selftests/power_supply/
 
 POWERNV OPERATOR PANEL LCD DISPLAY DRIVER
 M:     Suraj Jitindar Singh <sjitindarsingh@gmail.com>
@@ -17976,33 +18000,34 @@ F:    drivers/media/tuners/qt1010*
 
 QUALCOMM ATH12K WIRELESS DRIVER
 M:     Kalle Valo <kvalo@kernel.org>
-M:     Jeff Johnson <quic_jjohnson@quicinc.com>
+M:     Jeff Johnson <jjohnson@kernel.org>
 L:     ath12k@lists.infradead.org
 S:     Supported
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/ath12k
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
 F:     drivers/net/wireless/ath/ath12k/
+N:     ath12k
 
 QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
 M:     Kalle Valo <kvalo@kernel.org>
-M:     Jeff Johnson <quic_jjohnson@quicinc.com>
+M:     Jeff Johnson <jjohnson@kernel.org>
 L:     ath10k@lists.infradead.org
 S:     Supported
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/ath10k
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
-F:     Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
 F:     drivers/net/wireless/ath/ath10k/
+N:     ath10k
 
 QUALCOMM ATHEROS ATH11K WIRELESS DRIVER
 M:     Kalle Valo <kvalo@kernel.org>
-M:     Jeff Johnson <quic_jjohnson@quicinc.com>
+M:     Jeff Johnson <jjohnson@kernel.org>
 L:     ath11k@lists.infradead.org
 S:     Supported
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/ath11k
 B:     https://wireless.wiki.kernel.org/en/users/Drivers/ath11k/bugreport
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
-F:     Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
 F:     drivers/net/wireless/ath/ath11k/
+N:     ath11k
 
 QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
 M:     Toke Høiland-Jørgensen <toke@toke.dk>
@@ -18356,11 +18381,17 @@ M:    Tony Luck <tony.luck@intel.com>
 M:     Borislav Petkov <bp@alien8.de>
 L:     linux-edac@vger.kernel.org
 S:     Maintained
-F:     Documentation/admin-guide/ras.rst
+F:     Documentation/admin-guide/RAS
 F:     drivers/ras/
 F:     include/linux/ras.h
 F:     include/ras/ras_event.h
 
+RAS FRU MEMORY POISON MANAGER (FMPM)
+M:     Yazen Ghannam <Yazen.Ghannam@amd.com>
+L:     linux-edac@vger.kernel.org
+S:     Maintained
+F:     drivers/ras/amd/fmpm.c
+
 RC-CORE / LIRC FRAMEWORK
 M:     Sean Young <sean@mess.org>
 L:     linux-media@vger.kernel.org
@@ -18850,6 +18881,7 @@ F:      Documentation/devicetree/bindings/riscv/
 F:     arch/riscv/boot/dts/
 X:     arch/riscv/boot/dts/allwinner/
 X:     arch/riscv/boot/dts/renesas/
+X:     arch/riscv/boot/dts/sophgo/
 
 RISC-V PMU DRIVERS
 M:     Atish Patra <atishp@atishpatra.org>
@@ -19098,6 +19130,7 @@ F:      Documentation/rust/
 F:     rust/
 F:     samples/rust/
 F:     scripts/*rust*
+F:     tools/testing/selftests/rust/
 K:     \b(?i:rust)\b
 
 RXRPC SOCKETS (AF_RXRPC)
@@ -19391,7 +19424,6 @@ F:      drivers/media/platform/samsung/exynos4-is/
 SAMSUNG SOC CLOCK DRIVERS
 M:     Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
 M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
-M:     Tomasz Figa <tomasz.figa@gmail.com>
 M:     Chanwoo Choi <cw00.choi@samsung.com>
 R:     Alim Akhtar <alim.akhtar@samsung.com>
 L:     linux-samsung-soc@vger.kernel.org
@@ -19633,7 +19665,7 @@ F:      drivers/mmc/host/sdhci-of-at91.c
 
 SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) NXP i.MX DRIVER
 M:     Haibo Chen <haibo.chen@nxp.com>
-L:     linux-imx@nxp.com
+L:     imx@lists.linux.dev
 L:     linux-mmc@vger.kernel.org
 S:     Maintained
 F:     drivers/mmc/host/sdhci-esdhc-imx.c
@@ -19968,36 +20000,15 @@ S:    Maintained
 F:     drivers/watchdog/simatic-ipc-wdt.c
 
 SIFIVE DRIVERS
-M:     Palmer Dabbelt <palmer@dabbelt.com>
 M:     Paul Walmsley <paul.walmsley@sifive.com>
+M:     Samuel Holland <samuel.holland@sifive.com>
 L:     linux-riscv@lists.infradead.org
 S:     Supported
+F:     drivers/dma/sf-pdma/
 N:     sifive
+K:     fu[57]40
 K:     [^@]sifive
 
-SIFIVE CACHE DRIVER
-M:     Conor Dooley <conor@kernel.org>
-L:     linux-riscv@lists.infradead.org
-S:     Maintained
-F:     Documentation/devicetree/bindings/cache/sifive,ccache0.yaml
-F:     drivers/cache/sifive_ccache.c
-
-SIFIVE FU540 SYSTEM-ON-CHIP
-M:     Paul Walmsley <paul.walmsley@sifive.com>
-M:     Palmer Dabbelt <palmer@dabbelt.com>
-L:     linux-riscv@lists.infradead.org
-S:     Supported
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pjw/sifive.git
-N:     fu540
-K:     fu540
-
-SIFIVE PDMA DRIVER
-M:     Green Wan <green.wan@sifive.com>
-S:     Maintained
-F:     Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml
-F:     drivers/dma/sf-pdma/
-
-
 SILEAD TOUCHSCREEN DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
 L:     linux-input@vger.kernel.org
@@ -20206,8 +20217,8 @@ F:      Documentation/devicetree/bindings/net/socionext,uniphier-ave4.yaml
 F:     drivers/net/ethernet/socionext/sni_ave.c
 
 SOCIONEXT (SNI) NETSEC NETWORK DRIVER
-M:     Jassi Brar <jaswinder.singh@linaro.org>
 M:     Ilias Apalodimas <ilias.apalodimas@linaro.org>
+M:     Masahisa Kojima <kojima.masahisa@socionext.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/net/socionext,synquacer-netsec.yaml
@@ -20448,12 +20459,13 @@ F:    drivers/char/sonypi.c
 F:     drivers/platform/x86/sony-laptop.c
 F:     include/linux/sony-laptop.h
 
-SOPHGO DEVICETREES
-M:     Chao Wei <chao.wei@sophgo.com>
+SOPHGO DEVICETREES and DRIVERS
 M:     Chen Wang <unicorn_wang@outlook.com>
+M:     Inochi Amaoto <inochiama@outlook.com>
+T:     git https://github.com/sophgo/linux.git
 S:     Maintained
-F:     arch/riscv/boot/dts/sophgo/
-F:     Documentation/devicetree/bindings/riscv/sophgo.yaml
+N:     sophgo
+K:     sophgo
 
 SOUND
 M:     Jaroslav Kysela <perex@perex.cz>
@@ -20960,6 +20972,12 @@ F:     Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml
 F:     drivers/phy/starfive/phy-jh7110-pcie.c
 F:     drivers/phy/starfive/phy-jh7110-usb.c
 
+STARFIVE JH8100 EXTERNAL INTERRUPT CONTROLLER DRIVER
+M:     Changhuang Liang <changhuang.liang@starfivetech.com>
+S:     Supported
+F:     Documentation/devicetree/bindings/interrupt-controller/starfive,jh8100-intc.yaml
+F:     drivers/irqchip/irq-starfive-jh8100-intc.c
+
 STATIC BRANCH/CALL
 M:     Peter Zijlstra <peterz@infradead.org>
 M:     Josh Poimboeuf <jpoimboe@kernel.org>
@@ -21325,6 +21343,7 @@ F:      drivers/clk/clk-sc[mp]i.c
 F:     drivers/cpufreq/sc[mp]i-cpufreq.c
 F:     drivers/firmware/arm_scmi/
 F:     drivers/firmware/arm_scpi.c
+F:     drivers/hwmon/scmi-hwmon.c
 F:     drivers/pmdomain/arm/
 F:     drivers/powercap/arm_scmi_powercap.c
 F:     drivers/regulator/scmi-regulator.c
@@ -22009,6 +22028,14 @@ F:     Documentation/devicetree/bindings/media/i2c/ti,ds90*
 F:     drivers/media/i2c/ds90*
 F:     include/media/i2c/ds90*
 
+TI HDC302X HUMIDITY DRIVER
+M:     Javier Carrasco <javier.carrasco.cruz@gmail.com>
+M:     Li peiyu <579lpy@gmail.com>
+L:     linux-iio@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml
+F:     drivers/iio/humidity/hdc3020.c
+
 TI ICSSG ETHERNET DRIVER (ICSSG)
 R:     MD Danish Anwar <danishanwar@ti.com>
 R:     Roger Quadros <rogerq@kernel.org>
@@ -22864,9 +22891,8 @@ S:      Maintained
 F:     drivers/usb/typec/mux/pi3usb30532.c
 
 USB TYPEC PORT CONTROLLER DRIVERS
-M:     Guenter Roeck <linux@roeck-us.net>
 L:     linux-usb@vger.kernel.org
-S:     Maintained
+S:     Orphan
 F:     drivers/usb/typec/tcpm/
 
 USB UHCI DRIVER
@@ -24129,7 +24155,7 @@ F:      Documentation/devicetree/bindings/net/can/xilinx,can.yaml
 F:     drivers/net/can/xilinx_can.c
 
 XILINX EVENT MANAGEMENT DRIVER
-M:     Abhyuday Godhasara <abhyuday.godhasara@xilinx.com>
+M:     Michal Simek <michal.simek@amd.com>
 S:     Maintained
 F:     drivers/soc/xilinx/xlnx_event_manager.c
 F:     include/linux/firmware/xlnx-event-manager.h
index 7e0b2ad98905b91223d13ba03890d7839976ae0c..d18fa2a6240ddeee632215061d10ba3c7fb6ce24 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 6
 PATCHLEVEL = 8
 SUBLEVEL = 0
-EXTRAVERSION = -rc4
+EXTRAVERSION =
 NAME = Hurr durr I'ma ninja sloth
 
 # *DOCUMENTATION*
@@ -294,15 +294,15 @@ may-sync-config   := 1
 single-build   :=
 
 ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
-        ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
+    ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
                need-config :=
-        endif
+    endif
 endif
 
 ifneq ($(filter $(no-sync-config-targets), $(MAKECMDGOALS)),)
-        ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),)
+    ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),)
                may-sync-config :=
-        endif
+    endif
 endif
 
 need-compiler := $(may-sync-config)
@@ -323,9 +323,9 @@ endif
 # We cannot build single targets and the others at the same time
 ifneq ($(filter $(single-targets), $(MAKECMDGOALS)),)
        single-build := 1
-        ifneq ($(filter-out $(single-targets), $(MAKECMDGOALS)),)
+    ifneq ($(filter-out $(single-targets), $(MAKECMDGOALS)),)
                mixed-build := 1
-        endif
+    endif
 endif
 
 # For "make -j clean all", "make -j mrproper defconfig all", etc.
@@ -1201,7 +1201,7 @@ prepare0: archprepare
 # All the preparing..
 prepare: prepare0
 ifdef CONFIG_RUST
-       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh
+       +$(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh
        $(Q)$(MAKE) $(build)=rust
 endif
 
@@ -1711,7 +1711,7 @@ $(DOC_TARGETS):
 # "Is Rust available?" target
 PHONY += rustavailable
 rustavailable:
-       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh && echo "Rust is available!"
+       +$(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh && echo "Rust is available!"
 
 # Documentation target
 #
index a5af0edd3eb8f3b64e6e51bffb2ac491cb31bc26..fd18b7db2c777bb1223ffd0a4bcf0d5b11633330 100644 (file)
@@ -1078,17 +1078,107 @@ config HAVE_ARCH_COMPAT_MMAP_BASES
          and vice-versa 32-bit applications to call 64-bit mmap().
          Required for applications doing different bitness syscalls.
 
+config HAVE_PAGE_SIZE_4KB
+       bool
+
+config HAVE_PAGE_SIZE_8KB
+       bool
+
+config HAVE_PAGE_SIZE_16KB
+       bool
+
+config HAVE_PAGE_SIZE_32KB
+       bool
+
+config HAVE_PAGE_SIZE_64KB
+       bool
+
+config HAVE_PAGE_SIZE_256KB
+       bool
+
+choice
+       prompt "MMU page size"
+
+config PAGE_SIZE_4KB
+       bool "4KiB pages"
+       depends on HAVE_PAGE_SIZE_4KB
+       help
+         This option select the standard 4KiB Linux page size and the only
+         available option on many architectures. Using 4KiB page size will
+         minimize memory consumption and is therefore recommended for low
+         memory systems.
+         Some software that is written for x86 systems makes incorrect
+         assumptions about the page size and only runs on 4KiB pages.
+
+config PAGE_SIZE_8KB
+       bool "8KiB pages"
+       depends on HAVE_PAGE_SIZE_8KB
+       help
+         This option is the only supported page size on a few older
+         processors, and can be slightly faster than 4KiB pages.
+
+config PAGE_SIZE_16KB
+       bool "16KiB pages"
+       depends on HAVE_PAGE_SIZE_16KB
+       help
+         This option is usually a good compromise between memory
+         consumption and performance for typical desktop and server
+         workloads, often saving a level of page table lookups compared
+         to 4KB pages as well as reducing TLB pressure and overhead of
+         per-page operations in the kernel at the expense of a larger
+         page cache.
+
+config PAGE_SIZE_32KB
+       bool "32KiB pages"
+       depends on HAVE_PAGE_SIZE_32KB
+       help
+         Using 32KiB page size will result in slightly higher performance
+         kernel at the price of higher memory consumption compared to
+         16KiB pages.  This option is available only on cnMIPS cores.
+         Note that you will need a suitable Linux distribution to
+         support this.
+
+config PAGE_SIZE_64KB
+       bool "64KiB pages"
+       depends on HAVE_PAGE_SIZE_64KB
+       help
+         Using 64KiB page size will result in slightly higher performance
+         kernel at the price of much higher memory consumption compared to
+         4KiB or 16KiB pages.
+         This is not suitable for general-purpose workloads but the
+         better performance may be worth the cost for certain types of
+         supercomputing or database applications that work mostly with
+         large in-memory data rather than small files.
+
+config PAGE_SIZE_256KB
+       bool "256KiB pages"
+       depends on HAVE_PAGE_SIZE_256KB
+       help
+         256KiB pages have little practical value due to their extreme
+         memory usage.  The kernel will only be able to run applications
+         that have been compiled with '-zmax-page-size' set to 256KiB
+         (the default is 64KiB or 4KiB on most architectures).
+
+endchoice
+
 config PAGE_SIZE_LESS_THAN_64KB
        def_bool y
-       depends on !ARM64_64K_PAGES
        depends on !PAGE_SIZE_64KB
-       depends on !PARISC_PAGE_SIZE_64KB
        depends on PAGE_SIZE_LESS_THAN_256KB
 
 config PAGE_SIZE_LESS_THAN_256KB
        def_bool y
        depends on !PAGE_SIZE_256KB
 
+config PAGE_SHIFT
+       int
+       default 12 if PAGE_SIZE_4KB
+       default 13 if PAGE_SIZE_8KB
+       default 14 if PAGE_SIZE_16KB
+       default 15 if PAGE_SIZE_32KB
+       default 16 if PAGE_SIZE_64KB
+       default 18 if PAGE_SIZE_256KB
+
 # This allows to use a set of generic functions to determine mmap base
 # address by giving priority to top-down scheme only if the process
 # is not in legacy mode (compat task, unlimited stack size or
index d6968d090d49a7b9abe3a8ec1a8f446910ed2447..4f490250d32302087a6decd3a70e0f21b9611035 100644 (file)
@@ -14,6 +14,7 @@ config ALPHA
        select PCI_DOMAINS if PCI
        select PCI_SYSCALL if PCI
        select HAVE_ASM_MODVERSIONS
+       select HAVE_PAGE_SIZE_8KB
        select HAVE_PCSPKR_PLATFORM
        select HAVE_PERF_EVENTS
        select NEED_DMA_MAP_STATE
index 4db1ebc0ed99c201a11af6b9117aa7e253eace17..70419e6be1a354b3b846e958dfc2bb899253f5c9 100644 (file)
@@ -6,7 +6,7 @@
 #include <asm/pal.h>
 
 /* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT     13
+#define PAGE_SHIFT     CONFIG_PAGE_SHIFT
 #define PAGE_SIZE      (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
index 7439b2377df5799e371669faa7cc96229dadca38..8e9dd63b220c68f1f9cbb4cfa470192900ea10f2 100644 (file)
@@ -467,11 +467,6 @@ smp_prepare_cpus(unsigned int max_cpus)
        smp_num_cpus = smp_num_probed;
 }
 
-void
-smp_prepare_boot_cpu(void)
-{
-}
-
 int
 __cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
index 1b0483c51cc16952d54fc1aa09a8944ccf6510fd..4092bec198beca44d6c019643db6829293f7320d 100644 (file)
@@ -284,14 +284,17 @@ choice
 
 config ARC_PAGE_SIZE_8K
        bool "8KB"
+       select HAVE_PAGE_SIZE_8KB
        help
          Choose between 8k vs 16k
 
 config ARC_PAGE_SIZE_16K
+       select HAVE_PAGE_SIZE_16KB
        bool "16KB"
 
 config ARC_PAGE_SIZE_4K
        bool "4KB"
+       select HAVE_PAGE_SIZE_4KB
        depends on ARC_MMU_V3 || ARC_MMU_V4
 
 endchoice
index 2a4ad619abfba65fab6d73a5df120a3f615cf890..7fd9e741b5274d505b1cde2eb7fb8d466d635394 100644 (file)
 #include <linux/const.h>
 
 /* PAGE_SHIFT determines the page size */
-#if defined(CONFIG_ARC_PAGE_SIZE_16K)
-#define PAGE_SHIFT 14
-#elif defined(CONFIG_ARC_PAGE_SIZE_4K)
-#define PAGE_SHIFT 12
+#ifdef __KERNEL__
+#define PAGE_SHIFT CONFIG_PAGE_SHIFT
 #else
 /*
  * Default 8k
index 8d9b188caa27bcd965cd3f94a6a4a4739657c97d..b2f2c59279a6799ad89daf3ce709b8d010915920 100644 (file)
@@ -39,11 +39,6 @@ struct plat_smp_ops  __weak plat_smp_ops;
 /* XXX: per cpu ? Only needed once in early secondary boot */
 struct task_struct *secondary_idle_tsk;
 
-/* Called from start_kernel */
-void __init smp_prepare_boot_cpu(void)
-{
-}
-
 static int __init arc_get_cpu_map(const char *name, struct cpumask *cpumask)
 {
        unsigned long dt_root = of_get_flat_dt_root();
index 0af6709570d147f3cb914454ec7a9364a621ea9b..9d52ba3a8ad1a3898f9cf5f3c06b6986686f3460 100644 (file)
@@ -116,6 +116,7 @@ config ARM
        select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_NMI
        select HAVE_OPTPROBES if !THUMB2_KERNEL
+       select HAVE_PAGE_SIZE_4KB
        select HAVE_PCI if MMU
        select HAVE_PERF_EVENTS
        select HAVE_PERF_REGS
index 473280d5adce3426165ac80c01da4aa81659839a..d82908b1b1bb44e2413898ea66ed5d5583af44bd 100644 (file)
@@ -158,9 +158,7 @@ textofs-$(CONFIG_ARCH_REALTEK)  := 0x00108000
 ifeq ($(CONFIG_ARCH_SA1100),y)
 textofs-$(CONFIG_SA1111) := 0x00208000
 endif
-textofs-$(CONFIG_ARCH_IPQ40XX) := 0x00208000
-textofs-$(CONFIG_ARCH_MSM8X60) := 0x00208000
-textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000
+textofs-$(CONFIG_ARCH_QCOM_RESERVE_SMEM) := 0x00208000
 textofs-$(CONFIG_ARCH_MESON) := 0x00208000
 textofs-$(CONFIG_ARCH_AXXIA) := 0x00308000
 
index 9f39b5a2bb35ee80d62ece671e0b91a4bcbc3b53..c12361d0317f5142ea14b5c5893967ee0d81a060 100644 (file)
        vcc-pg-supply = <&reg_dldo1>;
 };
 
+&reg_aldo1 {
+       regulator-always-on;
+       regulator-min-microvolt = <3300000>;
+       regulator-max-microvolt = <3300000>;
+       regulator-name = "vcc-3v3-tv-usb";
+};
+
 &reg_aldo2 {
        regulator-always-on;
        regulator-min-microvolt = <1800000>;
index ff68dfb4eb7874a00d398bf7dfc2d242385c5620..90bd12feac010108def3f68756edf4e2d76c2e84 100644 (file)
                msix: msix@fbe00000 {
                        compatible = "al,alpine-msix";
                        reg = <0x0 0xfbe00000 0x0 0x100000>;
-                       interrupt-controller;
                        msi-controller;
                        al,msi-base-spi = <96>;
                        al,msi-num-spis = <64>;
index 8e3860d5d9160057f2699a5c8e73053e993e13ef..8cb0fc78b2af9fc757962506c992181a48766865 100644 (file)
@@ -23,7 +23,7 @@
                #size-cells = <1>;
                ranges;
 
-               cbus: cbus@c1100000 {
+               cbus: bus@c1100000 {
                        compatible = "simple-bus";
                        reg = <0xc1100000 0x200000>;
                        #address-cells = <1>;
                        };
                };
 
-               aobus: aobus@c8100000 {
+               aobus: bus@c8100000 {
                        compatible = "simple-bus";
                        reg = <0xc8100000 0x100000>;
                        #address-cells = <1>;
                        reg = <0xd9040000 0x10000>;
                };
 
-               secbus: secbus@da000000 {
+               secbus: bus@da000000 {
                        compatible = "simple-bus";
                        reg = <0xda000000 0x6000>;
                        #address-cells = <1>;
index 59932fbfd5d5f03768e20097f4344b715830f4fd..f57be9ae150f40855a638296fc4cbbbe6c5d5bd3 100644 (file)
 };
 
 &hwrng {
-       compatible = "amlogic,meson8-rng", "amlogic,meson-rng";
        clocks = <&clkc CLKID_RNG0>;
        clock-names = "core";
 };
index 5198f5177c2c161c28292faaf4d995a7c6d5d112..2d9d24d3a95d69f5e634ab64ff17e5840cd78975 100644 (file)
 };
 
 &hwrng {
-       compatible = "amlogic,meson8b-rng", "amlogic,meson-rng";
        clocks = <&clkc CLKID_RNG0>;
        clock-names = "core";
 };
index efed325af88d206fc5cc6f4d9b6e6d7f4f05cb77..d99bac02232b3703a04b8d03f36cf5eb12bd9f4e 100644 (file)
 
                /* Direct-mapped development chip ROM */
                pb1176_rom@10200000 {
-                       compatible = "direct-mapped";
+                       compatible = "mtd-rom";
                        reg = <0x10200000 0x4000>;
                        bank-width = <1>;
                };
index 7072a70da00d950b1ec5362a532cc01a67b014f4..367850ea091287c9a166d5d7e53816d1d296f892 100644 (file)
 
        bridge {
                compatible = "ti,ths8134b", "ti,ths8134";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                ports {
                        #address-cells = <1>;
 
        vga {
                compatible = "vga-connector";
+               label = "J30";
 
                port {
                        vga_con_in: endpoint {
index f31dcf7e5862e9229716dbbcfe427b38a578a7e2..de45aa99e2608911a8fbd6347b950d0cebf9f802 100644 (file)
@@ -32,8 +32,6 @@
 
        bridge {
                compatible = "ti,ths8134b", "ti,ths8134";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                ports {
                        #address-cells = <1>;
@@ -59,6 +57,7 @@
 
        vga {
                compatible = "vga-connector";
+               label = "J1";
 
                port {
                        vga_con_in: endpoint {
index 5916e4877eace701c1affb59ea6d446a43079679..8bf35666412b1086a420ac3becacd348b8e7c8d8 100644 (file)
@@ -20,7 +20,9 @@
        #address-cells = <1>;
        #size-cells = <1>;
 
-       chosen { };
+       chosen {
+               stdout-path = &v2m_serial0;
+       };
 
        aliases {
                serial0 = &v2m_serial0;
index 530491ae5eb26060f68802cf3318914f7fb2d361..857cb26ed6d7e8acd13c5695daa9fb3b8699c3c1 100644 (file)
        i2c0: i2c-bus@40 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x40 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c1: i2c-bus@80 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x80 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c2: i2c-bus@c0 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0xc0 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c3: i2c-bus@100 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x100 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c4: i2c-bus@140 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x140 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c5: i2c-bus@180 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x180 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c6: i2c-bus@1c0 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x1c0 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c7: i2c-bus@300 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x300 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c8: i2c-bus@340 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x340 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c9: i2c-bus@380 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x380 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c10: i2c-bus@3c0 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x3c0 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c11: i2c-bus@400 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x400 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c12: i2c-bus@440 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x440 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
        i2c13: i2c-bus@480 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x480 0x40>;
                compatible = "aspeed,ast2400-i2c-bus";
index 04f98d1dbb97c84c318c7e6a133fbf4572237c47..e6f3cf3c721e574f8b9975254cdcc79e3ce3b725 100644 (file)
                                interrupts = <40>;
                                reg = <0x1e780200 0x0100>;
                                clocks = <&syscon ASPEED_CLK_APB>;
+                               #interrupt-cells = <2>;
                                interrupt-controller;
                                bus-frequency = <12000000>;
                                pinctrl-names = "default";
        i2c0: i2c-bus@40 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x40 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c1: i2c-bus@80 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x80 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c2: i2c-bus@c0 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0xc0 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c3: i2c-bus@100 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x100 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c4: i2c-bus@140 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x140 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c5: i2c-bus@180 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x180 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c6: i2c-bus@1c0 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x1c0 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c7: i2c-bus@300 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x300 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c8: i2c-bus@340 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x340 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c9: i2c-bus@380 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x380 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c10: i2c-bus@3c0 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x3c0 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c11: i2c-bus@400 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x400 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c12: i2c-bus@440 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x440 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
        i2c13: i2c-bus@480 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
 
                reg = <0x480 0x40>;
                compatible = "aspeed,ast2500-i2c-bus";
index c4d1faade8be33d52c91f797f3fedaa0b22566a2..29f94696d8b189cba0113e7a65bbb25611358710 100644 (file)
                                reg = <0x1e780500 0x100>;
                                interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&syscon ASPEED_CLK_APB2>;
+                               #interrupt-cells = <2>;
                                interrupt-controller;
                                bus-frequency = <12000000>;
                                pinctrl-names = "default";
                                reg = <0x1e780600 0x100>;
                                interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&syscon ASPEED_CLK_APB2>;
+                               #interrupt-cells = <2>;
                                interrupt-controller;
                                bus-frequency = <12000000>;
                                pinctrl-names = "default";
        i2c0: i2c-bus@80 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x80 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c1: i2c-bus@100 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x100 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c2: i2c-bus@180 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x180 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c3: i2c-bus@200 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x200 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c4: i2c-bus@280 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x280 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c5: i2c-bus@300 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x300 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c6: i2c-bus@380 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x380 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c7: i2c-bus@400 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x400 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c8: i2c-bus@480 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x480 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c9: i2c-bus@500 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x500 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c10: i2c-bus@580 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x580 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c11: i2c-bus@600 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x600 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c12: i2c-bus@680 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x680 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c13: i2c-bus@700 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x700 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c14: i2c-bus@780 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x780 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
        i2c15: i2c-bus@800 {
                #address-cells = <1>;
                #size-cells = <0>;
-               #interrupt-cells = <1>;
                reg = <0x800 0x80>;
                compatible = "aspeed,ast2600-i2c-bus";
                clocks = <&syscon ASPEED_CLK_APB2>;
index f9f79ed825181b7e71b12f87d7ba21ade0fd6d4d..07ca0d993c9fdb27ef50e3c450f3472ebe67f858 100644 (file)
                        #gpio-cells = <2>;
                        gpio-controller;
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupt-parent = <&mailbox>;
                        interrupts = <0>;
                };
                        gpio-controller;
                        interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                };
 
                i2c1: i2c@1800b000 {
                        gpio-controller;
 
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
                        gpio-ranges = <&pinctrl 0 42 1>,
                                        <&pinctrl 1 44 3>,
index 788a6806191a33a04aa326a0645d5af06365571d..75545b10ef2fa69570f42422e15a2341d4cfaf92 100644 (file)
                        gpio-controller;
                        ngpios = <4>;
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
                };
 
index 9d20ba3b1ffb13d4983f28e66de7ae140af528be..6a4482c9316741d89eb67371ac13a3670783b8fc 100644 (file)
                        gpio-controller;
                        ngpios = <32>;
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
                        gpio-ranges = <&pinctrl 0 0 32>;
                };
                        gpio-controller;
                        ngpios = <4>;
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
                };
 
index 396149664297fdf81f4b15499003af95af58c684..b4dbcf8f168ef1e7025be988fb6238d1e3bd35bd 100644 (file)
        gpio_keys {
                compatible = "gpio-keys";
 
-               button-esc {
+               button-reset {
                        debounce-interval = <100>;
                        wakeup-source;
-                       linux,code = <KEY_ESC>;
+                       linux,code = <KEY_RESTART>;
                        label = "reset";
                        /* Collides with LPC_LAD[0], UART DCD, SSP 97RST */
                        gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
        };
 
        /* This is a RealTek RTL8366RB switch and PHY using SMI over GPIO */
-       switch {
+       ethernet-switch {
                compatible = "realtek,rtl8366rb";
                /* 22 = MDIO (has input reads), 21 = MDC (clock, output only) */
                mdc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>;
                        #interrupt-cells = <1>;
                };
 
-               ports {
+               ethernet-ports {
                        #address-cells = <1>;
                        #size-cells = <0>;
 
-                       port@0 {
+                       ethernet-port@0 {
                                reg = <0>;
                                label = "lan0";
                                phy-handle = <&phy0>;
                        };
-                       port@1 {
+                       ethernet-port@1 {
                                reg = <1>;
                                label = "lan1";
                                phy-handle = <&phy1>;
                        };
-                       port@2 {
+                       ethernet-port@2 {
                                reg = <2>;
                                label = "lan2";
                                phy-handle = <&phy2>;
                        };
-                       port@3 {
+                       ethernet-port@3 {
                                reg = <3>;
                                label = "lan3";
                                phy-handle = <&phy3>;
                        };
-                       port@4 {
+                       ethernet-port@4 {
                                reg = <4>;
                                label = "wan";
                                phy-handle = <&phy4>;
                        };
-                       rtl8366rb_cpu_port: port@5 {
+                       rtl8366rb_cpu_port: ethernet-port@5 {
                                reg = <5>;
                                label = "cpu";
                                ethernet = <&gmac0>;
                        #address-cells = <1>;
                        #size-cells = <0>;
 
-                       phy0: phy@0 {
+                       phy0: ethernet-phy@0 {
                                reg = <0>;
                                interrupt-parent = <&switch_intc>;
                                interrupts = <0>;
                        };
-                       phy1: phy@1 {
+                       phy1: ethernet-phy@1 {
                                reg = <1>;
                                interrupt-parent = <&switch_intc>;
                                interrupts = <1>;
                        };
-                       phy2: phy@2 {
+                       phy2: ethernet-phy@2 {
                                reg = <2>;
                                interrupt-parent = <&switch_intc>;
                                interrupts = <2>;
                        };
-                       phy3: phy@3 {
+                       phy3: ethernet-phy@3 {
                                reg = <3>;
                                interrupt-parent = <&switch_intc>;
                                interrupts = <3>;
                        };
-                       phy4: phy@4 {
+                       phy4: ethernet-phy@4 {
                                reg = <4>;
                                interrupt-parent = <&switch_intc>;
                                interrupts = <12>;
index 138c47e1ac1b1dee69caba7009adb486b8339715..8c54d3a5a721728c3250775dc1bd6e078cfffcca 100644 (file)
        gpio_keys {
                compatible = "gpio-keys";
 
-               button-esc {
+               button-reset {
                        debounce-interval = <100>;
                        wakeup-source;
-                       linux,code = <KEY_ESC>;
+                       linux,code = <KEY_RESTART>;
                        label = "reset";
                        gpios = <&gpio1 31 GPIO_ACTIVE_LOW>;
                };
index 91c19e8ebfe8b7810fd2e28fd15016cc43d40b59..4992ec276de92e923eb5a91c6d82d44bd8de4fad 100644 (file)
@@ -43,7 +43,7 @@
                button-setup {
                        debounce-interval = <50>;
                        wakeup-source;
-                       linux,code = <KEY_SETUP>;
+                       linux,code = <KEY_RESTART>;
                        label = "factory reset";
                        /* Conflict with NAND flash */
                        gpios = <&gpio0 18 GPIO_ACTIVE_LOW>;
@@ -93,7 +93,7 @@
                cs-gpios = <&gpio1 31 GPIO_ACTIVE_HIGH>;
                num-chipselects = <1>;
 
-               switch@0 {
+               ethernet-switch@0 {
                        compatible = "vitesse,vsc7385";
                        reg = <0>;
                        /* Specified for 2.5 MHz or below */
                        gpio-controller;
                        #gpio-cells = <2>;
 
-                       ports {
+                       ethernet-ports {
                                #address-cells = <1>;
                                #size-cells = <0>;
 
-                               port@0 {
+                               ethernet-port@0 {
                                        reg = <0>;
                                        label = "lan1";
                                };
-                               port@1 {
+                               ethernet-port@1 {
                                        reg = <1>;
                                        label = "lan2";
                                };
-                               port@2 {
+                               ethernet-port@2 {
                                        reg = <2>;
                                        label = "lan3";
                                };
-                               port@3 {
+                               ethernet-port@3 {
                                        reg = <3>;
                                        label = "lan4";
                                };
-                               vsc: port@6 {
+                               vsc: ethernet-port@6 {
                                        reg = <6>;
                                        label = "cpu";
                                        ethernet = <&gmac1>;
index d0efd76695da6e80b402d0af6baf1cf362c5651a..f8c6f6e5cdea6acaf4e9019fa29b92acb84b1e75 100644 (file)
@@ -30,7 +30,7 @@
                button-setup {
                        debounce-interval = <100>;
                        wakeup-source;
-                       linux,code = <KEY_SETUP>;
+                       linux,code = <KEY_RESTART>;
                        label = "factory reset";
                        /* Conflict with NAND flash */
                        gpios = <&gpio0 18 GPIO_ACTIVE_LOW>;
@@ -78,7 +78,7 @@
                cs-gpios = <&gpio1 31 GPIO_ACTIVE_HIGH>;
                num-chipselects = <1>;
 
-               switch@0 {
+               ethernet-switch@0 {
                        compatible = "vitesse,vsc7395";
                        reg = <0>;
                        /* Specified for 2.5 MHz or below */
                        gpio-controller;
                        #gpio-cells = <2>;
 
-                       ports {
+                       ethernet-ports {
                                #address-cells = <1>;
                                #size-cells = <0>;
 
-                               port@0 {
+                               ethernet-port@0 {
                                        reg = <0>;
                                        label = "lan1";
                                };
-                               port@1 {
+                               ethernet-port@1 {
                                        reg = <1>;
                                        label = "lan2";
                                };
-                               port@2 {
+                               ethernet-port@2 {
                                        reg = <2>;
                                        label = "lan3";
                                };
-                               port@3 {
+                               ethernet-port@3 {
                                        reg = <3>;
                                        label = "lan4";
                                };
-                               vsc: port@6 {
+                               vsc: ethernet-port@6 {
                                        reg = <6>;
                                        label = "cpu";
                                        ethernet = <&gmac1>;
index 3c88c59ab481c895014619902aa998c9d0efc4f7..6a0c89e0c9184b3f68248e23b29610dfcdac519f 100644 (file)
@@ -10,7 +10,7 @@
 
 / {
        model = "Wiliboard WBD-111";
-       compatible = "wiliboard,wbd111", "cortina,gemini";
+       compatible = "wiligear,wiliboard-wbd111", "cortina,gemini";
        #address-cells = <1>;
        #size-cells = <1>;
 
        gpio_keys {
                compatible = "gpio-keys";
 
-               button-setup {
+               button-reset {
                        debounce-interval = <100>;
                        wakeup-source;
-                       linux,code = <KEY_SETUP>;
+                       linux,code = <KEY_RESTART>;
                        label = "reset";
                        /* Conflict with ICE */
                        gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
index ff72bbc4db3e20439669e4f31072e16ac4757e2a..d8b34ebad4b05607d9c402a7762943b2b0977af1 100644 (file)
@@ -10,7 +10,7 @@
 
 / {
        model = "Wiliboard WBD-222";
-       compatible = "wiliboard,wbd222", "cortina,gemini";
+       compatible = "wiligear,wiliboard-wbd222", "cortina,gemini";
        #address-cells = <1>;
        #size-cells = <1>;
 
        gpio_keys {
                compatible = "gpio-keys";
 
-               button-setup {
+               button-reset {
                        debounce-interval = <100>;
                        wakeup-source;
-                       linux,code = <KEY_SETUP>;
+                       linux,code = <KEY_RESTART>;
                        label = "reset";
                        /* Conflict with ICE */
                        gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
index 4d70f6afd13ab5ee5df7ea621b56f81f4e642d41..6d5e69035f94dcaa3f323c833c1edd064d4f7dfd 100644 (file)
@@ -60,6 +60,8 @@
                         * We have slots (IDSEL) 1 and 2 with one assigned IRQ
                         * each handling all IRQs.
                         */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0xf800 0 0 7>;
                        interrupt-map =
                        /* IDSEL 1 */
                        <0x0800 0 0 1 &gpio0 11 IRQ_TYPE_LEVEL_LOW>, /* INT A on slot 1 is irq 11 */
index 9ec0169bacf8c2098814ec6c1399e41c910df464..5f4c849915db71390ab3050b7277b7893b075307 100644 (file)
@@ -89,6 +89,8 @@
                         * The slots have Ethernet, Ethernet, NEC and MPCI.
                         * The IDSELs are 11, 12, 13, 14.
                         */
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0xf800 0 0 7>;
                        interrupt-map =
                        /* IDSEL 11 - Ethernet A */
                        <0x5800 0 0 1 &gpio0 4 IRQ_TYPE_LEVEL_LOW>, /* INT A on slot 11 is irq 4 */
index 1707d1b015452d26c138ac198f1dc01982cea779..cb85f8e31dfc501ea57759949009a2b337ad72f2 100644 (file)
@@ -4,6 +4,18 @@
 
 / {
        model = "SolidRun Clearfog GTR L8";
+       compatible = "solidrun,clearfog-gtr-l8", "marvell,armada385",
+                    "marvell,armada380";
+
+       /* CON25 */
+       sfp1: sfp-1 {
+               compatible = "sff,sfp";
+               pinctrl-0 = <&cf_gtr_sfp1_pins>;
+               pinctrl-names = "default";
+               i2c-bus = <&i2c0>;
+               mod-def0-gpio = <&gpio0 24 GPIO_ACTIVE_LOW>;
+               tx-disable-gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>;
+       };
 };
 
 &mdio {
 
                        ethernet-port@1 {
                                reg = <1>;
-                               label = "lan8";
+                               label = "lan1";
                                phy-handle = <&switch0phy0>;
                        };
 
                        ethernet-port@2 {
                                reg = <2>;
-                               label = "lan7";
+                               label = "lan2";
                                phy-handle = <&switch0phy1>;
                        };
 
                        ethernet-port@3 {
                                reg = <3>;
-                               label = "lan6";
+                               label = "lan3";
                                phy-handle = <&switch0phy2>;
                        };
 
                        ethernet-port@4 {
                                reg = <4>;
-                               label = "lan5";
+                               label = "lan4";
                                phy-handle = <&switch0phy3>;
                        };
 
                        ethernet-port@5 {
                                reg = <5>;
-                               label = "lan4";
+                               label = "lan5";
                                phy-handle = <&switch0phy4>;
                        };
 
                        ethernet-port@6 {
                                reg = <6>;
-                               label = "lan3";
+                               label = "lan6";
                                phy-handle = <&switch0phy5>;
                        };
 
                        ethernet-port@7 {
                                reg = <7>;
-                               label = "lan2";
+                               label = "lan7";
                                phy-handle = <&switch0phy6>;
                        };
 
                        ethernet-port@8 {
                                reg = <8>;
-                               label = "lan1";
+                               label = "lan8";
                                phy-handle = <&switch0phy7>;
                        };
 
+                       ethernet-port@9 {
+                               reg = <9>;
+                               label = "lan-sfp";
+                               phy-mode = "sgmii";
+                               sfp = <&sfp1>;
+                               managed = "in-band-status";
+                       };
+
                        ethernet-port@10 {
                                reg = <10>;
                                phy-mode = "2500base-x";
-
                                ethernet = <&eth1>;
+
                                fixed-link {
                                        speed = <2500>;
                                        full-duplex;
index a7678a784c180145cd818e7782253d43179fefb3..5f83d981449ac80017ef21d6f88d5cce7ae56273 100644 (file)
@@ -4,6 +4,8 @@
 
 / {
        model = "SolidRun Clearfog GTR S4";
+       compatible = "solidrun,clearfog-gtr-s4", "marvell,armada385",
+                    "marvell,armada380";
 };
 
 &sfp0 {
index d1452a04e9040dc6e1e6de073617e5b2469307f9..f3a3cb6ac31148360d84b2231a43c7ca5bb015de 100644 (file)
                        };
 
                        pinctrl@18000 {
-                               cf_gtr_switch_reset_pins: cf-gtr-switch-reset-pins {
-                                       marvell,pins = "mpp18";
-                                       marvell,function = "gpio";
-                               };
-
-                               cf_gtr_usb3_con_vbus: cf-gtr-usb3-con-vbus {
-                                       marvell,pins = "mpp22";
+                               cf_gtr_fan_pwm: cf-gtr-fan-pwm {
+                                       marvell,pins = "mpp23";
                                        marvell,function = "gpio";
                                };
 
-                               cf_gtr_fan_pwm: cf-gtr-fan-pwm {
-                                       marvell,pins = "mpp23";
+                               cf_gtr_front_button_pins: cf-gtr-front-button-pins {
+                                       marvell,pins = "mpp53";
                                        marvell,function = "gpio";
                                };
 
                                        marvell,function = "i2c1";
                                };
 
+                               cf_gtr_isolation_pins: cf-gtr-isolation-pins {
+                                       marvell,pins = "mpp47";
+                                       marvell,function = "gpio";
+                               };
+
+                               cf_gtr_led_pins: led-pins {
+                                       marvell,pins = "mpp42", "mpp52";
+                                       marvell,function = "gpio";
+                               };
+
+                               cf_gtr_lte_disable_pins: lte-disable-pins {
+                                       marvell,pins = "mpp34";
+                                       marvell,function = "gpio";
+                               };
+
+                               cf_gtr_pci_pins: pci-pins {
+                                       // pci reset
+                                       marvell,pins = "mpp33", "mpp35", "mpp44";
+                                       marvell,function = "gpio";
+                               };
+
+                               cf_gtr_poe_reset_pins: cf-gtr-poe-reset-pins {
+                                       marvell,pins = "mpp48";
+                                       marvell,function = "gpio";
+                               };
+
+                               cf_gtr_rear_button_pins: cf-gtr-rear-button-pins {
+                                       marvell,pins = "mpp36";
+                                       marvell,function = "gpio";
+                               };
+
                                cf_gtr_sdhci_pins: cf-gtr-sdhci-pins {
                                        marvell,pins = "mpp21", "mpp28",
                                                       "mpp37", "mpp38",
                                        marvell,function = "sd0";
                                };
 
-                               cf_gtr_isolation_pins: cf-gtr-isolation-pins {
-                                       marvell,pins = "mpp47";
+                               cf_gtr_sfp0_pins: sfp0-pins {
+                                       /* sfp modabs, txdisable */
+                                       marvell,pins = "mpp25", "mpp46";
                                        marvell,function = "gpio";
                                };
 
-                               cf_gtr_poe_reset_pins: cf-gtr-poe-reset-pins {
-                                       marvell,pins = "mpp48";
+                               cf_gtr_sfp1_pins: sfp1-pins {
+                                       /* sfp modabs, txdisable */
+                                       marvell,pins = "mpp24", "mpp54";
                                        marvell,function = "gpio";
                                };
 
                                        marvell,function = "spi1";
                                };
 
-                               cf_gtr_front_button_pins: cf-gtr-front-button-pins {
-                                       marvell,pins = "mpp53";
+                               cf_gtr_switch_reset_pins: cf-gtr-switch-reset-pins {
+                                       marvell,pins = "mpp18";
                                        marvell,function = "gpio";
                                };
 
-                               cf_gtr_rear_button_pins: cf-gtr-rear-button-pins {
-                                       marvell,pins = "mpp36";
+                               cf_gtr_usb3_con_vbus: cf-gtr-usb3-con-vbus {
+                                       marvell,pins = "mpp22";
+                                       marvell,function = "gpio";
+                               };
+
+                               cf_gtr_wifi_disable_pins: wifi-disable-pins {
+                                       marvell,pins = "mpp30", "mpp31";
                                        marvell,function = "gpio";
                                };
                        };
                };
 
                pcie {
+                       pinctrl-0 = <&cf_gtr_pci_pins>;
+                       pinctrl-names = "default";
                        status = "okay";
                        /*
                         * The PCIe units are accessible through
                         * the mini-PCIe connectors on the board.
                         */
+                       /* CON3 - serdes 0 */
                        pcie@1,0 {
                                reset-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
                                status = "okay";
                        };
 
+                       /* CON4 - serdes 2 */
                        pcie@2,0 {
                                reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
                                status = "okay";
                        };
 
+                       /* CON2 - serdes 4 */
                        pcie@3,0 {
                                reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
                                status = "okay";
                };
        };
 
-       sfp0: sfp {
+       /* CON5 */
+       sfp0: sfp-0 {
                compatible = "sff,sfp";
+               pinctrl-0 = <&cf_gtr_sfp0_pins>;
+               pinctrl-names = "default";
                i2c-bus = <&i2c1>;
-               los-gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>;
                mod-def0-gpio = <&gpio0 25 GPIO_ACTIVE_LOW>;
                tx-disable-gpio = <&gpio1 14 GPIO_ACTIVE_HIGH>;
        };
 
        gpio-leds {
                compatible = "gpio-leds";
+               pinctrl-0 = <&cf_gtr_led_pins>;
+               pinctrl-names = "default";
 
                led1 {
                        function = LED_FUNCTION_CPU;
 };
 
 &gpio0 {
-       pinctrl-0 = <&cf_gtr_fan_pwm>;
+       pinctrl-0 = <&cf_gtr_fan_pwm &cf_gtr_wifi_disable_pins>;
        pinctrl-names = "default";
 
        wifi-disable {
 };
 
 &gpio1 {
-       pinctrl-0 = <&cf_gtr_isolation_pins &cf_gtr_poe_reset_pins>;
+       pinctrl-0 = <&cf_gtr_isolation_pins &cf_gtr_poe_reset_pins &cf_gtr_lte_disable_pins>;
        pinctrl-names = "default";
 
        lte-disable {
index 3290ccad2374575d86f522c08e75826b40c32918..09bf2e6d4ed06b81d7e8ebe40bb0ddf65ed44d85 100644 (file)
@@ -10,8 +10,9 @@
 
 / {
        model = "SolidRun Clearfog A1";
-       compatible = "solidrun,clearfog-a1", "marvell,armada388",
-               "marvell,armada385", "marvell,armada380";
+       compatible = "solidrun,clearfog-pro-a1", "solidrun,clearfog-a1",
+                    "marvell,armada388", "marvell,armada385",
+                    "marvell,armada380";
 
        soc {
                internal-regs {
index bfde99486a876a420bf5d94e3b59d4bf47be1d84..bcaaf8320c45558b5d46c5e97773b7426d4bd285 100644 (file)
                /* connect xtal input as source of pll0 and pll1 */
                silabs,pll-source = <0 0>, <1 0>;
 
-               clkout0 {
+               clkout@0 {
                        reg = <0>;
                        silabs,drive-strength = <8>;
                        silabs,multisynth-source = <0>;
                        silabs,pll-master;
                };
 
-               clkout2 {
+               clkout@2 {
                        reg = <2>;
                        silabs,drive-strength = <8>;
                        silabs,multisynth-source = <1>;
index dffb9f84e67c50c63ba5268a9975c62b93e75157..c841eb8e7fb1d0404301f4f8b21899fb60b77a25 100644 (file)
@@ -65,6 +65,7 @@
                        gpio2: gpio-expander@20 {
                                #gpio-cells = <2>;
                                #interrupt-cells = <2>;
+                               interrupt-controller;
                                compatible = "semtech,sx1505q";
                                reg = <0x20>;
 
@@ -79,6 +80,7 @@
                        gpio3: gpio-expander@21 {
                                #gpio-cells = <2>;
                                #interrupt-cells = <2>;
+                               interrupt-controller;
                                compatible = "semtech,sx1505q";
                                reg = <0x21>;
 
index 04f1ae1382e7a357ed51bd455154abf3f1a6de61..bc64348b8218519620bf22acbef2fd2f038ae608 100644 (file)
@@ -28,7 +28,7 @@
 &twsi1 {
        status = "okay";
        pmic: max8925@3c {
-               compatible = "maxium,max8925";
+               compatible = "maxim,max8925";
                reg = <0x3c>;
                interrupts = <1>;
                interrupt-parent = <&intcmux4>;
index efde9546c8f4da518659902391797a6a8a62bcaa..0c45c8d17468b70cab29d2cae9169473a8132e38 100644 (file)
@@ -11,6 +11,7 @@ DTC_FLAGS_at91-sama5d2_xplained := -@
 DTC_FLAGS_at91-sama5d3_eds := -@
 DTC_FLAGS_at91-sama5d3_xplained := -@
 DTC_FLAGS_at91-sama5d4_xplained := -@
+DTC_FLAGS_at91-sama7g54_curiosity := -@
 DTC_FLAGS_at91-sama7g5ek := -@
 dtb-$(CONFIG_SOC_AT91RM9200) += \
        at91rm9200ek.dtb \
@@ -87,6 +88,7 @@ dtb-$(CONFIG_SOC_SAM_V7) += \
        at91-sama5d4ek.dtb \
        at91-vinco.dtb
 dtb-$(CONFIG_SOC_SAMA7G5) += \
+       at91-sama7g54_curiosity.dtb \
        at91-sama7g5ek.dtb
 
 dtb-$(CONFIG_SOC_LAN966) += \
diff --git a/arch/arm/boot/dts/microchip/at91-sama7g54_curiosity.dts b/arch/arm/boot/dts/microchip/at91-sama7g54_curiosity.dts
new file mode 100644 (file)
index 0000000..4f609e9
--- /dev/null
@@ -0,0 +1,482 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * at91-sama7g54_curiosity.dts - Device Tree file for SAMA7G54 Curiosity Board
+ *
+ * Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Mihai Sain <mihai.sain@microchip.com>
+ *
+ */
+/dts-v1/;
+#include "sama7g5-pinfunc.h"
+#include "sama7g5.dtsi"
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/mfd/atmel-flexcom.h>
+#include <dt-bindings/pinctrl/at91.h>
+
+/ {
+       model = "Microchip SAMA7G54 Curiosity";
+       compatible = "microchip,sama7g54-curiosity", "microchip,sama7g5", "microchip,sama7";
+
+       aliases {
+               serial0 = &uart3;
+               i2c0 = &i2c10;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_key_gpio_default>;
+
+               button-user {
+                       label = "user-button";
+                       gpios = <&pioA PIN_PD19 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_PROG1>;
+                       wakeup-source;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_led_gpio_default>;
+
+               led-red {
+                       color = <LED_COLOR_ID_RED>;
+                       function = LED_FUNCTION_POWER;
+                       gpios = <&pioA PIN_PD13 GPIO_ACTIVE_HIGH>;
+                       default-state = "off";
+               };
+
+               led-green {
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_BOOT;
+                       gpios = <&pioA PIN_PD14 GPIO_ACTIVE_HIGH>;
+                       default-state = "off";
+               };
+
+               led-blue {
+                       color = <LED_COLOR_ID_BLUE>;
+                       function = LED_FUNCTION_CPU;
+                       gpios = <&pioA PIN_PB15 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       memory@60000000 {
+               device_type = "memory";
+               reg = <0x60000000 0x10000000>; /* 256 MiB DDR3L-1066 16-bit */
+       };
+};
+
+&adc {
+       vddana-supply = <&vddout25>;
+       vref-supply = <&vddout25>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_mikrobus1_an_default &pinctrl_mikrobus2_an_default>;
+       status = "okay";
+};
+
+&cpu0 {
+       cpu-supply = <&vddcpu>;
+};
+
+&dma0 {
+       status = "okay";
+};
+
+&dma1 {
+       status = "okay";
+};
+
+&dma2 {
+       status = "okay";
+};
+
+&ebi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_nand_default>;
+       status = "okay";
+
+       nand_controller: nand-controller {
+               status = "okay";
+
+               nand@3 {
+                       reg = <0x3 0x0 0x800000>;
+                       atmel,rb = <0>;
+                       nand-bus-width = <8>;
+                       nand-ecc-mode = "hw";
+                       nand-ecc-strength = <8>;
+                       nand-ecc-step-size = <512>;
+                       nand-on-flash-bbt;
+                       label = "nand";
+
+                       partitions {
+                               compatible = "fixed-partitions";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               at91bootstrap@0 {
+                                       label = "nand: at91bootstrap";
+                                       reg = <0x0 0x40000>;
+                               };
+
+                               bootloader@40000 {
+                                       label = "nand: u-boot";
+                                       reg = <0x40000 0x100000>;
+                               };
+
+                               bootloaderenv@140000 {
+                                       label = "nand: u-boot env";
+                                       reg = <0x140000 0x40000>;
+                               };
+
+                               dtb@180000 {
+                                       label = "nand: device tree";
+                                       reg = <0x180000 0x80000>;
+                               };
+
+                               kernel@200000 {
+                                       label = "nand: kernel";
+                                       reg = <0x200000 0x600000>;
+                               };
+
+                               rootfs@800000 {
+                                       label = "nand: rootfs";
+                                       reg = <0x800000 0x1f800000>;
+                               };
+                       };
+               };
+       };
+};
+
+&flx3 {
+       atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+       status = "okay";
+
+       uart3: serial@200 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_flx3_default>;
+               status = "okay";
+       };
+};
+
+&flx10 {
+       atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+       status = "okay";
+
+       i2c10: i2c@600 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_flx10_default>;
+               i2c-analog-filter;
+               i2c-digital-filter;
+               i2c-digital-filter-width-ns = <35>;
+               status = "okay";
+
+               eeprom@51 {
+                       compatible = "atmel,24c02";
+                       reg = <0x51>;
+                       pagesize = <16>;
+                       size = <256>;
+                       vcc-supply = <&vdd_3v3>;
+               };
+
+               pmic@5b {
+                       compatible = "microchip,mcp16502";
+                       reg = <0x5b>;
+
+                       regulators {
+                               vdd_3v3: VDD_IO {
+                                       regulator-name = "VDD_IO";
+                                       regulator-min-microvolt = <3300000>;
+                                       regulator-max-microvolt = <3300000>;
+                                       regulator-initial-mode = <2>;
+                                       regulator-allowed-modes = <2>, <4>;
+                                       regulator-always-on;
+
+                                       regulator-state-standby {
+                                               regulator-on-in-suspend;
+                                               regulator-suspend-microvolt = <3300000>;
+                                               regulator-mode = <4>;
+                                       };
+
+                                       regulator-state-mem {
+                                               regulator-off-in-suspend;
+                                               regulator-mode = <4>;
+                                       };
+                               };
+
+                               vddioddr: VDD_DDR {
+                                       regulator-name = "VDD_DDR";
+                                       regulator-min-microvolt = <1350000>;
+                                       regulator-max-microvolt = <1350000>;
+                                       regulator-initial-mode = <2>;
+                                       regulator-allowed-modes = <2>, <4>;
+                                       regulator-always-on;
+
+                                       regulator-state-standby {
+                                               regulator-on-in-suspend;
+                                               regulator-suspend-microvolt = <1350000>;
+                                               regulator-mode = <4>;
+                                       };
+
+                                       regulator-state-mem {
+                                               regulator-on-in-suspend;
+                                               regulator-suspend-microvolt = <1350000>;
+                                               regulator-mode = <4>;
+                                       };
+                               };
+
+                               vddcore: VDD_CORE {
+                                       regulator-name = "VDD_CORE";
+                                       regulator-min-microvolt = <1150000>;
+                                       regulator-max-microvolt = <1150000>;
+                                       regulator-initial-mode = <2>;
+                                       regulator-allowed-modes = <2>, <4>;
+                                       regulator-always-on;
+
+                                       regulator-state-standby {
+                                               regulator-on-in-suspend;
+                                               regulator-suspend-voltage = <1150000>;
+                                               regulator-mode = <4>;
+                                       };
+
+                                       regulator-state-mem {
+                                               regulator-off-in-suspend;
+                                               regulator-mode = <4>;
+                                       };
+                               };
+
+                               vddcpu: VDD_OTHER {
+                                       regulator-name = "VDD_OTHER";
+                                       regulator-min-microvolt = <1050000>;
+                                       regulator-max-microvolt = <1250000>;
+                                       regulator-initial-mode = <2>;
+                                       regulator-allowed-modes = <2>, <4>;
+                                       regulator-ramp-delay = <3125>;
+                                       regulator-always-on;
+
+                                       regulator-state-standby {
+                                               regulator-on-in-suspend;
+                                               regulator-suspend-voltage = <1050000>;
+                                               regulator-mode = <4>;
+                                       };
+
+                                       regulator-state-mem {
+                                               regulator-off-in-suspend;
+                                               regulator-mode = <4>;
+                                       };
+                               };
+
+                               vldo1: LDO1 {
+                                       regulator-name = "LDO1";
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
+                                       regulator-always-on;
+
+                                       regulator-state-standby {
+                                               regulator-suspend-voltage = <1800000>;
+                                               regulator-on-in-suspend;
+                                       };
+
+                                       regulator-state-mem {
+                                               regulator-off-in-suspend;
+                                       };
+                               };
+
+                               vldo2: LDO2 {
+                                       regulator-name = "LDO2";
+                                       regulator-min-microvolt = <3300000>;
+                                       regulator-max-microvolt = <3300000>;
+                                       regulator-always-on;
+
+                                       regulator-state-standby {
+                                               regulator-suspend-voltage = <3300000>;
+                                               regulator-on-in-suspend;
+                                       };
+
+                                       regulator-state-mem {
+                                               regulator-off-in-suspend;
+                                       };
+                               };
+                       };
+               };
+       };
+};
+
+&main_xtal {
+       clock-frequency = <24000000>;
+};
+
+&qspi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_qspi1_default>;
+       status = "okay";
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0x0>;
+               spi-max-frequency = <100000000>;
+               spi-tx-bus-width = <4>;
+               spi-rx-bus-width = <4>;
+               m25p,fast-read;
+       };
+};
+
+&pioA {
+       pinctrl_flx3_default: flx3-default {
+               pinmux = <PIN_PD16__FLEXCOM3_IO0>,
+                        <PIN_PD17__FLEXCOM3_IO1>;
+               bias-pull-up;
+       };
+
+       pinctrl_flx10_default: flx10-default {
+               pinmux = <PIN_PC30__FLEXCOM10_IO0>,
+                        <PIN_PC31__FLEXCOM10_IO1>;
+               bias-pull-up;
+       };
+
+       pinctrl_key_gpio_default: key-gpio-default {
+               pinmux = <PIN_PD19__GPIO>;
+               bias-pull-up;
+       };
+
+       pinctrl_led_gpio_default: led-gpio-default {
+               pinmux = <PIN_PD13__GPIO>,
+                        <PIN_PD14__GPIO>,
+                        <PIN_PB15__GPIO>;
+               bias-pull-up;
+       };
+
+       pinctrl_mikrobus1_an_default: mikrobus1-an-default {
+               pinmux = <PIN_PC15__GPIO>;
+               bias-disable;
+       };
+
+       pinctrl_mikrobus2_an_default: mikrobus2-an-default {
+               pinmux = <PIN_PC13__GPIO>;
+               bias-disable;
+       };
+
+       pinctrl_nand_default: nand-default {
+               pinmux = <PIN_PD9__D0>,
+                        <PIN_PD10__D1>,
+                        <PIN_PD11__D2>,
+                        <PIN_PC21__D3>,
+                        <PIN_PC22__D4>,
+                        <PIN_PC23__D5>,
+                        <PIN_PC24__D6>,
+                        <PIN_PD2__D7>,
+                        <PIN_PD3__NANDRDY>,
+                        <PIN_PD4__NCS3_NANDCS>,
+                        <PIN_PD5__NWE_NWR0_NANDWE>,
+                        <PIN_PD6__NRD_NANDOE>,
+                        <PIN_PD7__A21_NANDALE>,
+                        <PIN_PD8__A22_NANDCLE>;
+               bias-disable;
+               slew-rate = <0>;
+       };
+
+       pinctrl_qspi1_default: qspi1-default {
+               pinmux = <PIN_PB22__QSPI1_IO3>,
+                        <PIN_PB23__QSPI1_IO2>,
+                        <PIN_PB24__QSPI1_IO1>,
+                        <PIN_PB25__QSPI1_IO0>,
+                        <PIN_PB26__QSPI1_CS>,
+                        <PIN_PB27__QSPI1_SCK>;
+               bias-pull-up;
+               slew-rate = <0>;
+       };
+
+       pinctrl_sdmmc0_default: sdmmc0-default {
+               pinmux = <PIN_PA0__SDMMC0_CK>,
+                        <PIN_PA1__SDMMC0_CMD>,
+                        <PIN_PA2__SDMMC0_RSTN>,
+                        <PIN_PA3__SDMMC0_DAT0>,
+                        <PIN_PA4__SDMMC0_DAT1>,
+                        <PIN_PA5__SDMMC0_DAT2>,
+                        <PIN_PA6__SDMMC0_DAT3>;
+               bias-pull-up;
+               slew-rate = <0>;
+       };
+
+       pinctrl_sdmmc1_default: sdmmc1-default {
+               pinmux = <PIN_PB29__SDMMC1_CMD>,
+                        <PIN_PB30__SDMMC1_CK>,
+                        <PIN_PB31__SDMMC1_DAT0>,
+                        <PIN_PC0__SDMMC1_DAT1>,
+                        <PIN_PC1__SDMMC1_DAT2>,
+                        <PIN_PC2__SDMMC1_DAT3>,
+                        <PIN_PC4__SDMMC1_CD>;
+               bias-pull-up;
+               slew-rate = <0>;
+       };
+};
+
+&rtt {
+       atmel,rtt-rtc-time-reg = <&gpbr 0x0>;
+};
+
+/* M.2 slot for wireless card */
+&sdmmc0 {
+       bus-width = <4>;
+       cd-gpios = <&pioA 31 GPIO_ACTIVE_LOW>;
+       disable-wp;
+       sdhci-caps-mask = <0x0 0x00200000>;
+       vmmc-supply = <&vdd_3v3>;
+       vqmmc-supply = <&vdd_3v3>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sdmmc0_default>;
+       status = "okay";
+};
+
+/* micro SD socket */
+&sdmmc1 {
+       bus-width = <4>;
+       disable-wp;
+       sdhci-caps-mask = <0x0 0x00200000>;
+       vmmc-supply = <&vdd_3v3>;
+       vqmmc-supply = <&vdd_3v3>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sdmmc1_default>;
+       status = "okay";
+};
+
+&slow_xtal {
+       clock-frequency = <32768>;
+};
+
+&shdwc {
+       debounce-delay-us = <976>;
+       status = "okay";
+
+       input@0 {
+               reg = <0>;
+       };
+};
+
+&tcb0 {
+       timer0: timer@0 {
+               compatible = "atmel,tcb-timer";
+               reg = <0>;
+       };
+
+       timer1: timer@1 {
+               compatible = "atmel,tcb-timer";
+               reg = <1>;
+       };
+};
+
+&trng {
+       status = "okay";
+};
+
+&vddout25 {
+       vin-supply = <&vdd_3v3>;
+       status = "okay";
+};
index 92f2c05c873f631a26480a0e09a00619c8e36b5e..af70eb8a3a021259753dd3e75e5f515eabe6fee7 100644 (file)
 };
 
 &usart3 {
+       atmel,use-dma-rx;
+       atmel,use-dma-tx;
        status = "okay";
 
        pinctrl-0 = <&pinctrl_usart3
index 5f4eaa618ab47c7ee5b5cb3a43170544afbbc730..9618b8d965b0c6975de0bf59901a211b1388c73c 100644 (file)
@@ -39,6 +39,8 @@
 };
 
 &dbgu {
+       atmel,use-dma-rx;
+       atmel,use-dma-tx;
        status = "okay";
 };
 
index 73d570a172690cf6ec284c85f8f88c2edb9d63dc..291540e5d81e769a6c23af493b50e9aad089bc0e 100644 (file)
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(8))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(9))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(8))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(9))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(8))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(9))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(10))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(11))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(10))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(11))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(10))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(11))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(22))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(23))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(22))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(23))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(24))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(25))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(24))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(25))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(12))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(13))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(12))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(13))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(14))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(15))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(14))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(15))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(16))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(17))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(16))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(17))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(0))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(1))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(0))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(1))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(0))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(1))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(2))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(3))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(2))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(3))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(2))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(3))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(4))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(5))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(4))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(5))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(4))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(5))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(6))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(7))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(6))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(7))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(6))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(7))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(18))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(19))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(18))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(19))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(20))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(21))>;
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(20))>,
-                                               <&dma0
+                                              <&dma0
                                                (AT91_XDMAC_DT_MEM_IF(0) |
                                                 AT91_XDMAC_DT_PER_IF(1) |
                                                 AT91_XDMAC_DT_PERID(21))>;
index 269e0a3ca269cde4914c8513ccbe4262cb8bc475..75778be126a3d9e88d3160eee7c8514bf2e9f1f0 100644 (file)
                };
 
                flx0: flexcom@e1818000 {
-                       compatible = "atmel,sama5d2-flexcom";
+                       compatible = "microchip,sama7g5-flexcom", "atmel,sama5d2-flexcom";
                        reg = <0xe1818000 0x200>;
                        clocks = <&pmc PMC_TYPE_PERIPHERAL 38>;
                        #address-cells = <1>;
                                clocks = <&pmc PMC_TYPE_PERIPHERAL 38>;
                                clock-names = "usart";
                                dmas = <&dma1 AT91_XDMAC_DT_PERID(6)>,
-                                       <&dma1 AT91_XDMAC_DT_PERID(5)>;
+                                      <&dma1 AT91_XDMAC_DT_PERID(5)>;
                                dma-names = "tx", "rx";
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                };
 
                flx1: flexcom@e181c000 {
-                       compatible = "atmel,sama5d2-flexcom";
+                       compatible = "microchip,sama7g5-flexcom", "atmel,sama5d2-flexcom";
                        reg = <0xe181c000 0x200>;
                        clocks = <&pmc PMC_TYPE_PERIPHERAL 39>;
                        #address-cells = <1>;
                                clocks = <&pmc PMC_TYPE_PERIPHERAL 39>;
                                atmel,fifo-size = <32>;
                                dmas = <&dma0 AT91_XDMAC_DT_PERID(8)>,
-                                       <&dma0 AT91_XDMAC_DT_PERID(7)>;
+                                      <&dma0 AT91_XDMAC_DT_PERID(7)>;
                                dma-names = "tx", "rx";
                                status = "disabled";
                        };
                };
 
                flx3: flexcom@e1824000 {
-                       compatible = "atmel,sama5d2-flexcom";
+                       compatible = "microchip,sama7g5-flexcom", "atmel,sama5d2-flexcom";
                        reg = <0xe1824000 0x200>;
                        clocks = <&pmc PMC_TYPE_PERIPHERAL 41>;
                        #address-cells = <1>;
                                clocks = <&pmc PMC_TYPE_PERIPHERAL 41>;
                                clock-names = "usart";
                                dmas = <&dma1 AT91_XDMAC_DT_PERID(12)>,
-                                       <&dma1 AT91_XDMAC_DT_PERID(11)>;
+                                      <&dma1 AT91_XDMAC_DT_PERID(11)>;
                                dma-names = "tx", "rx";
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                };
 
                flx4: flexcom@e2018000 {
-                       compatible = "atmel,sama5d2-flexcom";
+                       compatible = "microchip,sama7g5-flexcom", "atmel,sama5d2-flexcom";
                        reg = <0xe2018000 0x200>;
                        clocks = <&pmc PMC_TYPE_PERIPHERAL 42>;
                        #address-cells = <1>;
                                clocks = <&pmc PMC_TYPE_PERIPHERAL 42>;
                                clock-names = "usart";
                                dmas = <&dma1 AT91_XDMAC_DT_PERID(14)>,
-                                       <&dma1 AT91_XDMAC_DT_PERID(13)>;
+                                      <&dma1 AT91_XDMAC_DT_PERID(13)>;
                                dma-names = "tx", "rx";
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                };
 
                flx7: flexcom@e2024000 {
-                       compatible = "atmel,sama5d2-flexcom";
+                       compatible = "microchip,sama7g5-flexcom", "atmel,sama5d2-flexcom";
                        reg = <0xe2024000 0x200>;
                        clocks = <&pmc PMC_TYPE_PERIPHERAL 45>;
                        #address-cells = <1>;
                                clocks = <&pmc PMC_TYPE_PERIPHERAL 45>;
                                clock-names = "usart";
                                dmas = <&dma1 AT91_XDMAC_DT_PERID(20)>,
-                                       <&dma1 AT91_XDMAC_DT_PERID(19)>;
+                                      <&dma1 AT91_XDMAC_DT_PERID(19)>;
                                dma-names = "tx", "rx";
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                };
 
                flx8: flexcom@e2818000 {
-                       compatible = "atmel,sama5d2-flexcom";
+                       compatible = "microchip,sama7g5-flexcom", "atmel,sama5d2-flexcom";
                        reg = <0xe2818000 0x200>;
                        clocks = <&pmc PMC_TYPE_PERIPHERAL 46>;
                        #address-cells = <1>;
                                clocks = <&pmc PMC_TYPE_PERIPHERAL 46>;
                                atmel,fifo-size = <32>;
                                dmas = <&dma0 AT91_XDMAC_DT_PERID(22)>,
-                                       <&dma0 AT91_XDMAC_DT_PERID(21)>;
+                                      <&dma0 AT91_XDMAC_DT_PERID(21)>;
                                dma-names = "tx", "rx";
                                status = "disabled";
                        };
                };
 
                flx9: flexcom@e281c000 {
-                       compatible = "atmel,sama5d2-flexcom";
+                       compatible = "microchip,sama7g5-flexcom", "atmel,sama5d2-flexcom";
                        reg = <0xe281c000 0x200>;
                        clocks = <&pmc PMC_TYPE_PERIPHERAL 47>;
                        #address-cells = <1>;
                                clocks = <&pmc PMC_TYPE_PERIPHERAL 47>;
                                atmel,fifo-size = <32>;
                                dmas = <&dma0 AT91_XDMAC_DT_PERID(24)>,
-                                       <&dma0 AT91_XDMAC_DT_PERID(23)>;
+                                      <&dma0 AT91_XDMAC_DT_PERID(23)>;
+                               dma-names = "tx", "rx";
+                               status = "disabled";
+                       };
+               };
+
+               flx10: flexcom@e2820000 {
+                       compatible = "microchip,sama7g5-flexcom", "atmel,sama5d2-flexcom";
+                       reg = <0xe2820000 0x200>;
+                       clocks = <&pmc PMC_TYPE_PERIPHERAL 48>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0xe2820000 0x800>;
+                       status = "disabled";
+
+                       i2c10: i2c@600 {
+                               compatible = "microchip,sama7g5-i2c", "microchip,sam9x60-i2c";
+                               reg = <0x600 0x200>;
+                               interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               clocks = <&pmc PMC_TYPE_PERIPHERAL 48>;
+                               atmel,fifo-size = <32>;
+                               dmas = <&dma0 AT91_XDMAC_DT_PERID(26)>,
+                                      <&dma0 AT91_XDMAC_DT_PERID(25)>;
                                dma-names = "tx", "rx";
                                status = "disabled";
                        };
                };
 
                flx11: flexcom@e2824000 {
-                       compatible = "atmel,sama5d2-flexcom";
+                       compatible = "microchip,sama7g5-flexcom", "atmel,sama5d2-flexcom";
                        reg = <0xe2824000 0x200>;
                        clocks = <&pmc PMC_TYPE_PERIPHERAL 49>;
                        #address-cells = <1>;
                                #size-cells = <0>;
                                atmel,fifo-size = <32>;
                                dmas = <&dma0 AT91_XDMAC_DT_PERID(28)>,
-                                           <&dma0 AT91_XDMAC_DT_PERID(27)>;
+                                      <&dma0 AT91_XDMAC_DT_PERID(27)>;
                                dma-names = "tx", "rx";
                                status = "disabled";
                        };
index fd671c7a1e5d64c6eafb0a7434c7d14b19f4d1b6..6e1f0f164cb4f511d19774a8c39a9a3090d85b9d 100644 (file)
                                interrupts = <2 IRQ_TYPE_LEVEL_HIGH>,
                                             <3 IRQ_TYPE_LEVEL_HIGH>,
                                             <4 IRQ_TYPE_LEVEL_HIGH>;
+                               #interrupt-cells = <2>;
                                interrupt-controller;
                        };
 
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
+                               #interrupt-cells = <2>;
                                interrupt-controller;
                        };
 
index 60091bf7e48b008bd06784f91a508aacbaa8ece9..96972559253c8c8af18db189919fb2e14472fd1c 100644 (file)
@@ -39,5 +39,7 @@ dtb-$(CONFIG_ARCH_TEGRA_3x_SOC) += \
        tegra30-cardhu-a02.dtb \
        tegra30-cardhu-a04.dtb \
        tegra30-colibri-eval-v3.dtb \
+       tegra30-lg-p880.dtb \
+       tegra30-lg-p895.dtb \
        tegra30-ouya.dtb \
        tegra30-pegatron-chagall.dtb
index a2ee3718020048133d22faa74ac7e69ba45b01a7..8125c1b3e8d7915365503d6c088f83d176a99fb5 100644 (file)
                        interrupt-parent = <&gpio>;
                        interrupts = <TEGRA_GPIO(C, 7) IRQ_TYPE_LEVEL_LOW>;
                        reg = <0>;
+                       wakeup-source;
 
                        google,cros-ec-spi-msg-delay = <2000>;
 
index 3924ee385dee0671054353d7d2ab5f42ccefa848..df98dc2a67b8587b1e6c6f8348748f781e6c5f79 100644 (file)
                        interrupt-parent = <&gpio>;
                        interrupts = <TEGRA_GPIO(C, 7) IRQ_TYPE_LEVEL_LOW>;
                        reg = <0>;
+                       wakeup-source;
 
                        google,cros-ec-spi-msg-delay = <2000>;
 
index 1640763fd4af2216c225b95e60e954afd5255fb5..ff0d684622f74d13eb1b4b2c7178c38e93ab4293 100644 (file)
                        compatible = "st,stmpe811";
                        reg = <0x41>;
                        irq-gpio = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>;
-                       interrupt-controller;
                        id = <0>;
                        blocks = <0x5>;
                        irq-trigger = <0x1>;
index 3b6fad273cabf17a6ddff7ede1d72de13079ed1f..d38f1dd38a9068371c25ddf82f4c284a555ffb03 100644 (file)
                        compatible = "st,stmpe811";
                        reg = <0x41>;
                        irq-gpio = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>;
-                       interrupt-controller;
                        id = <0>;
                        blocks = <0x5>;
                        irq-trigger = <0x1>;
index a9342e04b14bb350d92896597b13b03691ac6136..15f53babdc21779464022f50b8e51f9516b2d191 100644 (file)
                        reg = <0x1c>;
 
                        realtek,dmic1-data-pin = <1>;
+
+                       clocks = <&tegra_pmc TEGRA_PMC_CLK_OUT_1>;
+                       clock-names = "mclk";
                };
 
                nct72: temperature-sensor@4c {
index 4eb526fe9c55888d6a595d68d3a95616bb913404..81c8a5fd92ccea33b3673d61302d39397e8fa72f 100644 (file)
                        compatible = "st,stmpe811";
                        reg = <0x41>;
                        irq-gpio = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>;
-                       interrupt-controller;
                        id = <0>;
                        blocks = <0x5>;
                        irq-trigger = <0x1>;
diff --git a/arch/arm/boot/dts/nvidia/tegra30-lg-p880.dts b/arch/arm/boot/dts/nvidia/tegra30-lg-p880.dts
new file mode 100644 (file)
index 0000000..2f7754f
--- /dev/null
@@ -0,0 +1,489 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+
+#include "tegra30-lg-x3.dtsi"
+
+/ {
+       model = "LG Optimus 4X HD P880";
+       compatible = "lg,p880", "nvidia,tegra30";
+
+       aliases {
+               mmc1 = &sdmmc3; /* uSD slot */
+               mmc2 = &sdmmc1; /* WiFi */
+       };
+
+       pinmux@70000868 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&state_default>;
+
+               state_default: pinmux {
+                       /* WLAN SDIO pinmux */
+                       host-wlan-wake {
+                               nvidia,pins = "pu4";
+                               nvidia,function = "pwm1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* GNSS UART-B pinmux */
+                       uartb-rxd {
+                               nvidia,pins = "uart2_rxd_pc3";
+                               nvidia,function = "uartb";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       uartb-txd {
+                               nvidia,pins = "uart2_txd_pc2";
+                               nvidia,function = "uartb";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       gps-reset {
+                               nvidia,pins = "kb_row7_pr7";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+
+                       /* MicroSD pinmux */
+                       sdmmc3-clk {
+                               nvidia,pins = "sdmmc3_clk_pa6";
+                               nvidia,function = "sdmmc3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc3-data {
+                               nvidia,pins = "sdmmc3_cmd_pa7",
+                                               "sdmmc3_dat0_pb7",
+                                               "sdmmc3_dat1_pb6",
+                                               "sdmmc3_dat2_pb5",
+                                               "sdmmc3_dat3_pb4";
+                               nvidia,function = "sdmmc3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       microsd-detect {
+                               nvidia,pins = "clk2_out_pw5";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* GPIO keys pinmux */
+                       volume-up {
+                               nvidia,pins = "ulpi_data6_po7";
+                               nvidia,function = "spi2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* Sensors pinmux */
+                       current-alert-irq {
+                               nvidia,pins = "uart2_rts_n_pj6";
+                               nvidia,function = "uartb";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* AUDIO pinmux */
+                       sub-mic-ldo {
+                               nvidia,pins = "gmi_cs7_n_pi6";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+               };
+       };
+
+       i2c@7000c400 {
+               touchscreen@20 {
+                       rmi4-f11@11 {
+                               syna,clip-x-high = <1110>;
+                               syna,clip-y-high = <1973>;
+
+                               touchscreen-inverted-y;
+                       };
+               };
+       };
+
+       memory-controller@7000f000 {
+               emc-timings-0 {
+                       /* SAMSUNG 1GB K4P8G304EB FGC1 533MHz */
+                       nvidia,ram-code = <0>;
+
+                       timing-12750000 {
+                               clock-frequency = <12750000>;
+
+                               nvidia,emem-configuration = < 0x00050001 0xc0000010
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000003 0x00000001 0x00000002 0x00000004
+                                       0x00000001 0x00000000 0x00000002 0x00000002
+                                       0x02020001 0x00060402 0x77230303 0x001f0000 >;
+                       };
+
+                       timing-25500000 {
+                               clock-frequency = <25500000>;
+
+                               nvidia,emem-configuration = < 0x00020001 0xc0000010
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000003 0x00000001 0x00000002 0x00000004
+                                       0x00000001 0x00000000 0x00000002 0x00000002
+                                       0x02020001 0x00060402 0x73e30303 0x001f0000 >;
+                       };
+
+                       timing-51000000 {
+                               clock-frequency = <51000000>;
+
+                               nvidia,emem-configuration = < 0x00010001 0xc0000010
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000003 0x00000001 0x00000002 0x00000004
+                                       0x00000001 0x00000000 0x00000002 0x00000002
+                                       0x02020001 0x00060402 0x72c30303 0x001f0000 >;
+                       };
+
+                       timing-102000000 {
+                               clock-frequency = <102000000>;
+
+                               nvidia,emem-configuration = < 0x00000001 0xc0000018
+                                       0x00000001 0x00000001 0x00000003 0x00000001
+                                       0x00000003 0x00000001 0x00000002 0x00000004
+                                       0x00000001 0x00000000 0x00000002 0x00000002
+                                       0x02020001 0x00060403 0x72430504 0x001f0000 >;
+                       };
+
+                       timing-204000000 {
+                               clock-frequency = <204000000>;
+
+                               nvidia,emem-configuration = < 0x00000003 0xc0000025
+                                       0x00000001 0x00000001 0x00000006 0x00000003
+                                       0x00000005 0x00000001 0x00000002 0x00000004
+                                       0x00000001 0x00000000 0x00000003 0x00000002
+                                       0x02030001 0x00070506 0x71e40a07 0x001f0000 >;
+                       };
+
+                       timing-266500000 {
+                               clock-frequency = <266500000>;
+
+                               nvidia,emem-configuration = < 0x00000004 0xC0000030
+                                       0x00000001 0x00000002 0x00000008 0x00000004
+                                       0x00000006 0x00000001 0x00000002 0x00000005
+                                       0x00000001 0x00000000 0x00000003 0x00000003
+                                       0x03030001 0x00090608 0x70040c09 0x001f0000 >;
+                       };
+
+                       timing-533000000 {
+                               clock-frequency = <533000000>;
+
+                               nvidia,emem-configuration = < 0x00000008 0xC0000060
+                                       0x00000003 0x00000004 0x00000010 0x0000000a
+                                       0x0000000d 0x00000002 0x00000002 0x00000008
+                                       0x00000002 0x00000000 0x00000004 0x00000005
+                                       0x05040002 0x00110b10 0x70281811 0x001f0000 >;
+                       };
+               };
+       };
+
+       memory-controller@7000f400 {
+               emc-timings-0 {
+                       /* SAMSUNG 1GB K4P8G304EB FGC1 533MHz */
+                       nvidia,ram-code = <0>;
+
+                       timing-12750000 {
+                               clock-frequency = <12750000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x00010022>;
+                               nvidia,emc-mode-2 = <0x00020001>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x00000009>;
+                               nvidia,emc-cfg-dyn-self-ref;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x00000000
+                                       0x00000001 0x00000002 0x00000002 0x00000004
+                                       0x00000004 0x00000001 0x00000005 0x00000002
+                                       0x00000002 0x00000001 0x00000001 0x00000000
+                                       0x00000001 0x00000003 0x00000001 0x0000000b
+                                       0x00000009 0x0000002f 0x00000000 0x0000000b
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000001 0x00000007 0x00000002 0x00000002
+                                       0x00000003 0x00000008 0x00000004 0x00000001
+                                       0x00000002 0x00000036 0x00000004 0x00000004
+                                       0x00000000 0x00000000 0x00004282 0x007800a4
+                                       0x00008000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00100220 0x0800201c 0x00000000
+                                       0x77ffc004 0x01f1f008 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x00000009 0x00090009 0xa0f10000 0x00000000
+                                       0x00000000 0x80000164 0xe0000000 0xff00ff00 >;
+                       };
+
+                       timing-25500000 {
+                               clock-frequency = <25500000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x00010022>;
+                               nvidia,emc-mode-2 = <0x00020001>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x00000009>;
+                               nvidia,emc-cfg-dyn-self-ref;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x00000001
+                                       0x00000003 0x00000002 0x00000002 0x00000004
+                                       0x00000004 0x00000001 0x00000005 0x00000002
+                                       0x00000002 0x00000001 0x00000001 0x00000000
+                                       0x00000001 0x00000003 0x00000001 0x0000000b
+                                       0x00000009 0x00000060 0x00000000 0x00000018
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000001 0x00000007 0x00000004 0x00000004
+                                       0x00000003 0x00000008 0x00000004 0x00000001
+                                       0x00000002 0x0000006b 0x00000004 0x00000004
+                                       0x00000000 0x00000000 0x00004282 0x007800a4
+                                       0x00008000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00100220 0x0800201c 0x00000000
+                                       0x77ffc004 0x01f1f008 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x0000000a 0x00090009 0xa0f10000 0x00000000
+                                       0x00000000 0x800001c5 0xe0000000 0xff00ff00 >;
+                       };
+
+                       timing-51000000 {
+                               clock-frequency = <51000000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x00010022>;
+                               nvidia,emc-mode-2 = <0x00020001>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x00000009>;
+                               nvidia,emc-cfg-dyn-self-ref;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x00000003
+                                       0x00000006 0x00000002 0x00000002 0x00000004
+                                       0x00000004 0x00000001 0x00000005 0x00000002
+                                       0x00000002 0x00000001 0x00000001 0x00000000
+                                       0x00000001 0x00000003 0x00000001 0x0000000b
+                                       0x00000009 0x000000c0 0x00000000 0x00000030
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000001 0x00000007 0x00000008 0x00000008
+                                       0x00000003 0x00000008 0x00000004 0x00000001
+                                       0x00000002 0x000000d5 0x00000004 0x00000004
+                                       0x00000000 0x00000000 0x00004282 0x007800a4
+                                       0x00008000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00100220 0x0800201c 0x00000000
+                                       0x77ffc004 0x01f1f008 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x00000013 0x00090009 0xa0f10000 0x00000000
+                                       0x00000000 0x80000287 0xe0000000 0xff00ff00 >;
+                       };
+
+                       timing-102000000 {
+                               clock-frequency = <102000000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x00010022>;
+                               nvidia,emc-mode-2 = <0x00020001>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x0000000a>;
+                               nvidia,emc-cfg-dyn-self-ref;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x00000006
+                                       0x0000000d 0x00000004 0x00000002 0x00000004
+                                       0x00000004 0x00000001 0x00000005 0x00000002
+                                       0x00000002 0x00000001 0x00000001 0x00000000
+                                       0x00000001 0x00000003 0x00000001 0x0000000b
+                                       0x00000009 0x00000181 0x00000000 0x00000060
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000001 0x00000007 0x0000000f 0x0000000f
+                                       0x00000003 0x00000008 0x00000004 0x00000001
+                                       0x00000002 0x000001a9 0x00000004 0x00000004
+                                       0x00000000 0x00000000 0x00004282 0x007800a4
+                                       0x00008000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00100220 0x0800201c 0x00000000
+                                       0x77ffc004 0x01f1f008 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x00000025 0x00090009 0xa0f10000 0x00000000
+                                       0x00000000 0x8000040b 0xe0000000 0xff00ff00 >;
+                       };
+
+                       timing-204000000 {
+                               clock-frequency = <204000000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x00010042>;
+                               nvidia,emc-mode-2 = <0x00020001>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x00000013>;
+                               nvidia,emc-cfg-dyn-self-ref;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x0000000c
+                                       0x0000001a 0x00000008 0x00000003 0x00000005
+                                       0x00000004 0x00000001 0x00000006 0x00000003
+                                       0x00000003 0x00000002 0x00000002 0x00000000
+                                       0x00000001 0x00000003 0x00000001 0x0000000c
+                                       0x0000000a 0x00000303 0x00000000 0x000000c0
+                                       0x00000001 0x00000001 0x00000003 0x00000000
+                                       0x00000001 0x00000007 0x0000001d 0x0000001d
+                                       0x00000004 0x0000000b 0x00000005 0x00000001
+                                       0x00000002 0x00000351 0x00000004 0x00000006
+                                       0x00000000 0x00000000 0x00004282 0x004400a4
+                                       0x00008000 0x00070000 0x00070000 0x00070000
+                                       0x00070000 0x00070000 0x00070000 0x00070000
+                                       0x00070000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00080000 0x00080000 0x00080000
+                                       0x00080000 0x000e0220 0x0800201c 0x00000000
+                                       0x77ffc004 0x01f1f008 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x0000004a 0x00090009 0xa0f10000 0x00000000
+                                       0x00000000 0x80000713 0xe0000000 0xff00ff00 >;
+                       };
+
+                       timing-266500000 {
+                               clock-frequency = <266500000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x00010042>;
+                               nvidia,emc-mode-2 = <0x00020002>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x00000018>;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x0000000f
+                                       0x00000022 0x0000000b 0x00000004 0x00000005
+                                       0x00000005 0x00000001 0x00000007 0x00000004
+                                       0x00000004 0x00000002 0x00000002 0x00000000
+                                       0x00000002 0x00000005 0x00000002 0x0000000c
+                                       0x0000000b 0x000003ef 0x00000000 0x000000fb
+                                       0x00000001 0x00000001 0x00000004 0x00000000
+                                       0x00000001 0x00000009 0x00000026 0x00000026
+                                       0x00000004 0x0000000e 0x00000006 0x00000001
+                                       0x00000002 0x00000455 0x00000000 0x00000004
+                                       0x00000000 0x00000000 0x00006282 0x003200a4
+                                       0x00008000 0x00050000 0x00050000 0x00050000
+                                       0x00050000 0x00050000 0x00050000 0x00050000
+                                       0x00050000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00060000 0x00060000 0x00060000
+                                       0x00060000 0x000b0220 0x0800003d 0x00000000
+                                       0x77ffc004 0x01f1f008 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x00000060 0x000a000a 0xa0f10000 0x00000000
+                                       0x00000000 0x800008ee 0xe0000000 0xff00ff00 >;
+                       };
+
+                       timing-533000000 {
+                               clock-frequency = <533000000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x000100c2>;
+                               nvidia,emc-mode-2 = <0x00020006>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x00000030>;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x0000001f
+                                       0x00000045 0x00000016 0x00000009 0x00000008
+                                       0x00000009 0x00000003 0x0000000d 0x00000009
+                                       0x00000009 0x00000005 0x00000003 0x00000000
+                                       0x00000004 0x00000009 0x00000006 0x0000000d
+                                       0x00000010 0x000007df 0x00000000 0x000001f7
+                                       0x00000003 0x00000003 0x00000009 0x00000000
+                                       0x00000001 0x0000000f 0x0000004b 0x0000004b
+                                       0x00000008 0x0000001b 0x0000000c 0x00000001
+                                       0x00000002 0x000008aa 0x00000000 0x00000006
+                                       0x00000000 0x00000000 0x00006282 0xf0120091
+                                       0x00008000 0x0000000a 0x0000000a 0x0000000a
+                                       0x0000000a 0x0000000a 0x0000000a 0x0000000a
+                                       0x0000000a 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x0000000a 0x0000000a 0x0000000a
+                                       0x0000000a 0x00090220 0x0800003d 0x00000000
+                                       0x77ffc004 0x01f1f408 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x000000c0 0x000e000e 0xa0f10000 0x00000000
+                                       0x00000000 0x800010d9 0xe0000000 0xff00ff88 >;
+                       };
+               };
+       };
+
+       sdmmc3: mmc@78000400 {
+               status = "okay";
+
+               cd-gpios = <&gpio TEGRA_GPIO(W, 5) GPIO_ACTIVE_LOW>;
+               bus-width = <4>;
+
+               vmmc-supply = <&vdd_usd>;
+               vqmmc-supply = <&vdd_1v8_vio>;
+       };
+
+       battery: battery-cell {
+               compatible = "simple-battery";
+               device-chemistry = "lithium-ion";
+               charge-full-design-microamp-hours = <2150000>;
+               energy-full-design-microwatt-hours = <8200000>;
+               operating-range-celsius = <0 45>;
+       };
+
+       gpio-keys {
+               key-volume-up {
+                       label = "Volume Up";
+                       gpios = <&gpio TEGRA_GPIO(O, 7) GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEUP>;
+                       debounce-interval = <10>;
+                       wakeup-event-action = <EV_ACT_ASSERTED>;
+                       wakeup-source;
+               };
+       };
+
+       sound {
+               compatible = "lg,tegra-audio-max98089-p880",
+                            "nvidia,tegra-audio-max98089";
+               nvidia,model = "LG Optimus 4X HD MAX98089";
+
+               nvidia,int-mic-en-gpios = <&gpio TEGRA_GPIO(I, 6) GPIO_ACTIVE_HIGH>;
+       };
+};
diff --git a/arch/arm/boot/dts/nvidia/tegra30-lg-p895.dts b/arch/arm/boot/dts/nvidia/tegra30-lg-p895.dts
new file mode 100644 (file)
index 0000000..e32fafc
--- /dev/null
@@ -0,0 +1,496 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+
+#include "tegra30-lg-x3.dtsi"
+
+/ {
+       model = "LG Optimus Vu P895";
+       compatible = "lg,p895", "nvidia,tegra30";
+
+       pinmux@70000868 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&state_default>;
+
+               state_default: pinmux {
+                       /* GNSS UART-B pinmux */
+                       uartb-cts-rxd {
+                               nvidia,pins = "uart2_cts_n_pj5",
+                                               "uart2_rxd_pc3";
+                               nvidia,function = "uartb";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       uartb-rts-txd {
+                               nvidia,pins = "uart2_rts_n_pj6",
+                                               "uart2_txd_pc2";
+                               nvidia,function = "uartb";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       gps-reset {
+                               nvidia,pins = "spdif_out_pk5";
+                               nvidia,function = "spdif";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+
+                       /* GPIO keys pinmux */
+                       memo-key {
+                               nvidia,pins = "sdmmc3_dat1_pb6";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       volume-up {
+                               nvidia,pins = "gmi_cs7_n_pi6";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* Sensors pinmux */
+                       current-alert-irq {
+                               nvidia,pins = "spi1_cs0_n_px6";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* Panel pinmux */
+                       panel-vdd {
+                               nvidia,pins = "pbb0";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+
+                       /* AUDIO pinmux */
+                       sub-mic-ldo {
+                               nvidia,pins = "gmi_dqs_pi2";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+
+                       /* Modem pinmux */
+                       usim-detect {
+                               nvidia,pins = "clk2_out_pw5";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* GPIO power/drive control */
+                       drive-sdmmc4 {
+                               nvidia,pins = "drive_gma",
+                                               "drive_gmb",
+                                               "drive_gmc",
+                                               "drive_gmd";
+                               nvidia,pull-down-strength = <9>;
+                               nvidia,pull-up-strength = <9>;
+                               nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_SLOWEST>;
+                               nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_SLOWEST>;
+                       };
+               };
+       };
+
+       i2c@7000c400 {
+               touchscreen@20 {
+                       rmi4-f11@11 {
+                               syna,clip-x-high = <1535>;
+                               syna,clip-y-high = <2047>;
+                       };
+               };
+       };
+
+       memory-controller@7000f000 {
+               emc-timings-2 {
+                       /* Hynix 1GB H9TCNNN8JDMMPR LPDDR2 533MHz */
+                       nvidia,ram-code = <2>;
+
+                       timing-12750000 {
+                               clock-frequency = <12750000>;
+
+                               nvidia,emem-configuration = < 0x00020001 0xc0000010
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000003 0x00000001 0x00000002 0x00000004
+                                       0x00000001 0x00000000 0x00000002 0x00000002
+                                       0x02020001 0x00060402 0x77230303 0x001f0000 >;
+                       };
+
+                       timing-25500000 {
+                               clock-frequency = <25500000>;
+
+                               nvidia,emem-configuration = < 0x00030003 0xc0000010
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000003 0x00000001 0x00000002 0x00000004
+                                       0x00000001 0x00000000 0x00000002 0x00000002
+                                       0x02020001 0x00060402 0x73e30303 0x001f0000 >;
+                       };
+
+                       timing-51000000 {
+                               clock-frequency = <51000000>;
+
+                               nvidia,emem-configuration = < 0x00010003 0xc0000010
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000003 0x00000001 0x00000002 0x00000004
+                                       0x00000001 0x00000000 0x00000002 0x00000002
+                                       0x02020001 0x00060402 0x72c30303 0x001f0000 >;
+                       };
+
+                       timing-102000000 {
+                               clock-frequency = <102000000>;
+
+                               nvidia,emem-configuration = < 0x00000003 0xc0000018
+                                       0x00000001 0x00000001 0x00000003 0x00000001
+                                       0x00000003 0x00000001 0x00000002 0x00000004
+                                       0x00000001 0x00000000 0x00000002 0x00000002
+                                       0x02020001 0x00060403 0x72430504 0x001f0000 >;
+                       };
+
+                       timing-204000000 {
+                               clock-frequency = <204000000>;
+
+                               nvidia,emem-configuration = < 0x00000006 0xc0000025
+                                       0x00000001 0x00000001 0x00000006 0x00000003
+                                       0x00000005 0x00000001 0x00000002 0x00000004
+                                       0x00000001 0x00000000 0x00000003 0x00000002
+                                       0x02030001 0x00070506 0x71e40a07 0x001f0000 >;
+                       };
+
+                       timing-266500000 {
+                               clock-frequency = <266500000>;
+
+                               nvidia,emem-configuration = < 0x00000008 0xc0000030
+                                       0x00000001 0x00000002 0x00000008 0x00000004
+                                       0x00000006 0x00000001 0x00000002 0x00000005
+                                       0x00000001 0x00000000 0x00000003 0x00000003
+                                       0x03030001 0x00090608 0x70040c09 0x001f0000 >;
+                       };
+
+                       timing-533000000 {
+                               clock-frequency = <533000000>;
+
+                               nvidia,emem-configuration = < 0x0000000f 0xc0000060
+                                       0x00000003 0x00000004 0x00000010 0x0000000a
+                                       0x0000000d 0x00000002 0x00000002 0x00000008
+                                       0x00000002 0x00000000 0x00000004 0x00000005
+                                       0x05040002 0x00110b10 0x70281811 0x001f0000 >;
+                       };
+               };
+       };
+
+       memory-controller@7000f400 {
+               emc-timings-2 {
+                       /* Hynix 1GB H9TCNNN8JDMMPR LPDDR2 533MHz */
+                       nvidia,ram-code = <2>;
+
+                       timing-12750000 {
+                               clock-frequency = <12750000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x00010022>;
+                               nvidia,emc-mode-2 = <0x00020001>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x00000009>;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x00000000
+                                       0x00000001 0x00000002 0x00000002 0x00000004
+                                       0x00000004 0x00000001 0x00000005 0x00000002
+                                       0x00000002 0x00000001 0x00000001 0x00000000
+                                       0x00000001 0x00000003 0x00000001 0x0000000b
+                                       0x00000009 0x0000002f 0x00000000 0x0000000b
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000001 0x00000007 0x00000002 0x00000002
+                                       0x00000003 0x00000008 0x00000004 0x00000004
+                                       0x00000002 0x00000036 0x00000004 0x00000004
+                                       0x00000000 0x00000000 0x00004282 0x007800a4
+                                       0x00008000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00100220 0x0800201c 0x00000000
+                                       0x77ffc004 0x01f1f008 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x00000009 0x00090009 0xa0f10000 0x00000000
+                                       0x00000000 0x80000164 0xe0000000 0xff00ff00 >;
+                       };
+
+                       timing-25500000 {
+                               clock-frequency = <25500000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x00010022>;
+                               nvidia,emc-mode-2 = <0x00020001>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x00000009>;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x00000001
+                                       0x00000003 0x00000002 0x00000002 0x00000004
+                                       0x00000004 0x00000001 0x00000005 0x00000002
+                                       0x00000002 0x00000001 0x00000001 0x00000000
+                                       0x00000001 0x00000003 0x00000001 0x0000000b
+                                       0x00000009 0x00000060 0x00000000 0x00000018
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000001 0x00000007 0x00000004 0x00000004
+                                       0x00000003 0x00000008 0x00000004 0x00000004
+                                       0x00000002 0x0000006b 0x00000004 0x00000004
+                                       0x00000000 0x00000000 0x00004282 0x007800a4
+                                       0x00008000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00100220 0x0800201c 0x00000000
+                                       0x77ffc004 0x01f1f008 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x0000000a 0x00090009 0xa0f10000 0x00000000
+                                       0x00000000 0x800001c5 0xd0000000 0xff00ff00 >;
+                       };
+
+                       timing-51000000 {
+                               clock-frequency = <51000000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x00010022>;
+                               nvidia,emc-mode-2 = <0x00020001>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x00000009>;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x00000003
+                                       0x00000006 0x00000002 0x00000002 0x00000004
+                                       0x00000004 0x00000001 0x00000005 0x00000002
+                                       0x00000002 0x00000001 0x00000001 0x00000000
+                                       0x00000001 0x00000003 0x00000001 0x0000000b
+                                       0x00000009 0x000000c0 0x00000000 0x00000030
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000001 0x00000007 0x00000008 0x00000008
+                                       0x00000003 0x00000008 0x00000004 0x00000004
+                                       0x00000002 0x000000d5 0x00000004 0x00000004
+                                       0x00000000 0x00000000 0x00004282 0x007800a4
+                                       0x00008000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00100220 0x0800201c 0x00000000
+                                       0x77ffc004 0x01f1f008 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x00000013 0x00090009 0xa0f10000 0x00000000
+                                       0x00000000 0x80000287 0xd0000000 0xff00ff00 >;
+                       };
+
+                       timing-102000000 {
+                               clock-frequency = <102000000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x00010022>;
+                               nvidia,emc-mode-2 = <0x00020001>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x0000000a>;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x00000006
+                                       0x0000000d 0x00000004 0x00000002 0x00000004
+                                       0x00000004 0x00000001 0x00000005 0x00000002
+                                       0x00000002 0x00000001 0x00000001 0x00000000
+                                       0x00000001 0x00000003 0x00000001 0x0000000b
+                                       0x00000009 0x00000181 0x00000000 0x00000060
+                                       0x00000001 0x00000001 0x00000002 0x00000000
+                                       0x00000001 0x00000007 0x0000000f 0x0000000f
+                                       0x00000003 0x00000008 0x00000004 0x00000004
+                                       0x00000002 0x000001a9 0x00000004 0x00000006
+                                       0x00000000 0x00000000 0x00004282 0x007800a4
+                                       0x00008000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x000fc000 0x000fc000 0x000fc000
+                                       0x000fc000 0x00100220 0x0800201c 0x00000000
+                                       0x77ffc004 0x01f1f008 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x00000025 0x00090009 0xa0f10000 0x00000000
+                                       0x00000000 0x8000040b 0xd0000000 0xff00ff00 >;
+                       };
+
+                       timing-204000000 {
+                               clock-frequency = <204000000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x00010042>;
+                               nvidia,emc-mode-2 = <0x00020001>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x00000013>;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x0000000c
+                                       0x0000001a 0x00000008 0x00000003 0x00000005
+                                       0x00000004 0x00000001 0x00000006 0x00000003
+                                       0x00000003 0x00000002 0x00000002 0x00000000
+                                       0x00000001 0x00000004 0x00000001 0x0000000c
+                                       0x0000000a 0x00000303 0x00000000 0x000000c0
+                                       0x00000001 0x00000001 0x00000003 0x00000000
+                                       0x00000001 0x00000007 0x0000001d 0x0000001d
+                                       0x00000004 0x0000000b 0x00000005 0x00000004
+                                       0x00000002 0x00000351 0x00000005 0x00000004
+                                       0x00000000 0x00000000 0x00004282 0x004400a4
+                                       0x00008000 0x00080000 0x00080000 0x00080000
+                                       0x00080000 0x00072000 0x00072000 0x00072000
+                                       0x00072000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00080000 0x00080000 0x00080000
+                                       0x00080000 0x000e0220 0x0800201c 0x00000000
+                                       0x77ffc004 0x01f1f008 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x0000004a 0x00090009 0xa0f10000 0x00000000
+                                       0x00000000 0x80000713 0xe0000000 0xff00ff00 >;
+                       };
+
+                       timing-266500000 {
+                               clock-frequency = <266500000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x00010042>;
+                               nvidia,emc-mode-2 = <0x00020002>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x00000018>;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x0000000f
+                                       0x00000022 0x0000000b 0x00000004 0x00000005
+                                       0x00000005 0x00000001 0x00000007 0x00000004
+                                       0x00000004 0x00000002 0x00000002 0x00000000
+                                       0x00000002 0x00000005 0x00000002 0x0000000c
+                                       0x0000000b 0x000003ef 0x00000000 0x000000fb
+                                       0x00000001 0x00000001 0x00000004 0x00000000
+                                       0x00000001 0x00000009 0x00000026 0x00000026
+                                       0x00000004 0x0000000e 0x00000006 0x00000004
+                                       0x00000002 0x00000455 0x00000000 0x00000004
+                                       0x00000000 0x00000000 0x00006282 0x003200a4
+                                       0x00008000 0x00070000 0x00070000 0x00070000
+                                       0x00070000 0x00072000 0x00072000 0x00072000
+                                       0x00072000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00080002 0x00080002 0x00080002
+                                       0x00080002 0x000e0220 0x0800003d 0x00000000
+                                       0x77ffc004 0x01f1f008 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x00000060 0x000a000a 0xa0f10000 0x00000000
+                                       0x00000000 0x800008ee 0xe0000000 0xff00ff00 >;
+                       };
+
+                       timing-533000000 {
+                               clock-frequency = <533000000>;
+
+                               nvidia,emc-auto-cal-interval = <0x001fffff>;
+                               nvidia,emc-mode-1 = <0x000100c2>;
+                               nvidia,emc-mode-2 = <0x00020006>;
+                               nvidia,emc-mode-reset = <0x00000000>;
+                               nvidia,emc-zcal-cnt-long = <0x00000030>;
+                               nvidia,emc-cfg-periodic-qrst;
+
+                               nvidia,emc-configuration =  < 0x0000001f
+                                       0x00000045 0x00000016 0x00000009 0x00000008
+                                       0x00000009 0x00000003 0x0000000d 0x00000009
+                                       0x00000009 0x00000005 0x00000003 0x00000000
+                                       0x00000004 0x0000000a 0x00000006 0x0000000d
+                                       0x00000010 0x000007df 0x00000000 0x000001f7
+                                       0x00000003 0x00000003 0x00000009 0x00000000
+                                       0x00000001 0x0000000f 0x0000004b 0x0000004b
+                                       0x00000008 0x0000001b 0x0000000c 0x00000004
+                                       0x00000002 0x000008aa 0x00000000 0x00000004
+                                       0x00000000 0x00000000 0x00006282 0xf0120091
+                                       0x00008000 0x0000000c 0x0000000c 0x0000000c
+                                       0x0000000c 0x0000000a 0x0000000a 0x0000000a
+                                       0x0000000a 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x00000000 0x00000000 0x00000000
+                                       0x00000000 0x0000000c 0x0000000c 0x0000000c
+                                       0x0000000c 0x000c0220 0x0800003d 0x00000000
+                                       0x77ffc004 0x01f1f408 0x00000000 0x00000007
+                                       0x08000068 0x08000000 0x00000802 0x00064000
+                                       0x000000c0 0x000e000e 0xa0f10000 0x00000000
+                                       0x00000000 0x800010d9 0xe0000000 0xff00ff88 >;
+                       };
+               };
+       };
+
+       battery: battery-cell {
+               compatible = "simple-battery";
+               device-chemistry = "lithium-ion";
+               charge-full-design-microamp-hours = <2080000>;
+               energy-full-design-microwatt-hours = <7700000>;
+               operating-range-celsius = <0 45>;
+       };
+
+       gpio-keys {
+               key-memo {
+                       label = "Memo";
+                       gpios = <&gpio TEGRA_GPIO(B, 6) GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_MEMO>;
+                       debounce-interval = <10>;
+                       wakeup-event-action = <EV_ACT_ASSERTED>;
+                       wakeup-source;
+               };
+
+               key-volume-up {
+                       label = "Volume Up";
+                       gpios = <&gpio TEGRA_GPIO(I, 6) GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEUP>;
+                       debounce-interval = <10>;
+                       wakeup-event-action = <EV_ACT_ASSERTED>;
+                       wakeup-source;
+               };
+       };
+
+       gpio-leds {
+               led-power {
+                       label = "power::white";
+                       gpios = <&gpio TEGRA_GPIO(R, 3) GPIO_ACTIVE_HIGH>;
+
+                       linux,default-trigger = "battery-charging";
+
+                       color = <LED_COLOR_ID_WHITE>;
+                       function = LED_FUNCTION_CHARGING;
+               };
+       };
+
+       regulator-lcd3v {
+               gpio = <&gpio TEGRA_GPIO(BB, 0) GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       sound {
+               compatible = "lg,tegra-audio-max98089-p895",
+                            "nvidia,tegra-audio-max98089";
+               nvidia,model = "LG Optimus Vu MAX98089";
+
+               nvidia,int-mic-en-gpios = <&gpio TEGRA_GPIO(I, 2) GPIO_ACTIVE_HIGH>;
+       };
+};
diff --git a/arch/arm/boot/dts/nvidia/tegra30-lg-x3.dtsi b/arch/arm/boot/dts/nvidia/tegra30-lg-x3.dtsi
new file mode 100644 (file)
index 0000000..909260a
--- /dev/null
@@ -0,0 +1,1812 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <dt-bindings/input/gpio-keys.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/mfd/max77620.h>
+#include <dt-bindings/thermal/thermal.h>
+
+#include "tegra30.dtsi"
+#include "tegra30-cpu-opp.dtsi"
+#include "tegra30-cpu-opp-microvolt.dtsi"
+
+/ {
+       chassis-type = "handset";
+
+       aliases {
+               mmc0 = &sdmmc4; /* eMMC */
+               mmc1 = &sdmmc1; /* WiFi */
+
+               rtc0 = &pmic;
+               rtc1 = "/rtc@7000e000";
+
+               serial0 = &uartd; /* Console */
+               serial1 = &uartc; /* Bluetooth */
+               serial2 = &uartb; /* GPS */
+       };
+
+       /*
+        * The decompressor and also some bootloaders rely on a
+        * pre-existing /chosen node to be available to insert the
+        * command line and merge other ATAGS info.
+        */
+       chosen { };
+
+       firmware {
+               trusted-foundations {
+                       compatible = "tlm,trusted-foundations";
+                       tlm,version-major = <2>;
+                       tlm,version-minor = <8>;
+               };
+       };
+
+       memory@80000000 {
+               reg = <0x80000000 0x40000000>;
+       };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               linux,cma@80000000 {
+                       compatible = "shared-dma-pool";
+                       alloc-ranges = <0x80000000 0x30000000>;
+                       size = <0x10000000>;            /* 256MiB */
+                       linux,cma-default;
+                       reusable;
+               };
+
+               ramoops@bed00000 {
+                       compatible = "ramoops";
+                       reg = <0xbed00000 0x10000>;     /* 64kB */
+                       console-size = <0x8000>;        /* 32kB */
+                       record-size = <0x400>;          /* 1kB */
+                       ecc-size = <16>;
+               };
+
+               trustzone@bfe00000 {
+                       reg = <0xbfe00000 0x200000>;    /* 2MB */
+                       no-map;
+               };
+       };
+
+       vde@6001a000 {
+               assigned-clocks = <&tegra_car TEGRA30_CLK_VDE>;
+               assigned-clock-parents = <&tegra_car TEGRA30_CLK_PLL_P>;
+               assigned-clock-rates = <408000000>;
+       };
+
+       pinmux@70000868 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&state_default>;
+
+               state_default: pinmux {
+                       /* WLAN SDIO pinmux */
+                       sdmmc1-clk {
+                               nvidia,pins = "sdmmc1_clk_pz0";
+                               nvidia,function = "sdmmc1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc1-cmd {
+                               nvidia,pins = "sdmmc1_cmd_pz1",
+                                               "sdmmc1_dat3_py4",
+                                               "sdmmc1_dat2_py5",
+                                               "sdmmc1_dat1_py6",
+                                               "sdmmc1_dat0_py7";
+                               nvidia,function = "sdmmc1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       wlan-reset {
+                               nvidia,pins = "pv3";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       wlan-host-wake {
+                               nvidia,pins = "pu6";
+                               nvidia,function = "pwm3";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* GNSS UART-B pinmux */
+                       gps-pwr-en {
+                               nvidia,pins = "kb_row6_pr6";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       gps-ldo-en {
+                               nvidia,pins = "ulpi_dir_py1";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       gps-clk-ref {
+                               nvidia,pins = "gmi_ad8_ph0";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+
+                       /* Bluetooth UART-C pinmux */
+                       uartc-cts-rxd {
+                               nvidia,pins = "uart3_cts_n_pa1",
+                                               "uart3_rxd_pw7";
+                               nvidia,function = "uartc";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       uartc-rts-txd {
+                               nvidia,pins = "uart3_rts_n_pc0",
+                                               "uart3_txd_pw6";
+                               nvidia,function = "uartc";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       bt-reset {
+                               nvidia,pins = "clk2_req_pcc5";
+                               nvidia,function = "dap";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       bt-dev-wake {
+                               nvidia,pins = "kb_row11_ps3";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       bt-host-wake {
+                               nvidia,pins = "kb_row12_ps4";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       bt-pcm-dap4 {
+                               nvidia,pins = "dap4_fs_pp4",
+                                               "dap4_din_pp5",
+                                               "dap4_dout_pp6",
+                                               "dap4_sclk_pp7";
+                               nvidia,function = "i2s3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* EMMC pinmux */
+                       sdmmc4-clk {
+                               nvidia,pins = "sdmmc4_clk_pcc4";
+                               nvidia,function = "sdmmc4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc4-data {
+                               nvidia,pins = "sdmmc4_cmd_pt7",
+                                               "sdmmc4_dat0_paa0",
+                                               "sdmmc4_dat1_paa1",
+                                               "sdmmc4_dat2_paa2",
+                                               "sdmmc4_dat3_paa3",
+                                               "sdmmc4_dat4_paa4",
+                                               "sdmmc4_dat5_paa5",
+                                               "sdmmc4_dat6_paa6",
+                                               "sdmmc4_dat7_paa7";
+                               nvidia,function = "sdmmc4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       sdmmc4-reset {
+                               nvidia,pins = "sdmmc4_rst_n_pcc3";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* I2C pinmux */
+                       gen1-i2c {
+                               nvidia,pins = "gen1_i2c_scl_pc4",
+                                               "gen1_i2c_sda_pc5";
+                               nvidia,function = "i2c1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                               nvidia,lock = <TEGRA_PIN_DISABLE>;
+                       };
+                       gen2-i2c {
+                               nvidia,pins = "gen2_i2c_scl_pt5",
+                                               "gen2_i2c_sda_pt6";
+                               nvidia,function = "i2c2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                               nvidia,lock = <TEGRA_PIN_DISABLE>;
+                       };
+                       cam-i2c {
+                               nvidia,pins = "cam_i2c_scl_pbb1",
+                                               "cam_i2c_sda_pbb2";
+                               nvidia,function = "i2c3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                               nvidia,lock = <TEGRA_PIN_DISABLE>;
+                       };
+                       ddc-i2c {
+                               nvidia,pins = "ddc_scl_pv4",
+                                               "ddc_sda_pv5";
+                               nvidia,function = "i2c4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,lock = <TEGRA_PIN_DISABLE>;
+                       };
+                       pwr-i2c {
+                               nvidia,pins = "pwr_i2c_scl_pz6",
+                                               "pwr_i2c_sda_pz7";
+                               nvidia,function = "i2cpwr";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                               nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+                               nvidia,lock = <TEGRA_PIN_DISABLE>;
+                       };
+                       mhl-i2c {
+                               nvidia,pins = "kb_col6_pq6",
+                                               "kb_col7_pq7";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* GPIO keys pinmux */
+                       power-key {
+                               nvidia,pins = "gmi_wp_n_pc7";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       volume-down {
+                               nvidia,pins = "ulpi_data3_po4";
+                               nvidia,function = "spi3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* Sensors pinmux */
+                       sen-vdd {
+                               nvidia,pins = "spi1_miso_px7";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       proxi-vdd {
+                               nvidia,pins = "spi2_miso_px1";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       sen-vio {
+                               nvidia,pins = "lcd_dc1_pd2";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       nct-irq {
+                               nvidia,pins = "gmi_iordy_pi5";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       bat-irq {
+                               nvidia,pins = "kb_row8_ps0";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       charger-irq {
+                               nvidia,pins = "gmi_cs1_n_pj2";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       mpu-irq {
+                               nvidia,pins = "gmi_ad12_ph4";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       compass-irq {
+                               nvidia,pins = "gmi_ad13_ph5";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       light-irq {
+                               nvidia,pins = "gmi_cs4_n_pk2";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* LED pinmux */
+                       backlight-en {
+                               nvidia,pins = "lcd_dc0_pn6";
+                               nvidia,function = "rsvd3";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       flash-led-en {
+                               nvidia,pins = "pbb3";
+                               nvidia,function = "vgp3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       keypad-led {
+                               nvidia,pins = "kb_row2_pr2",
+                                               "kb_row3_pr3";
+                               nvidia,function = "rsvd3";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+
+                       /* NFC pinmux */
+                       nfc-irq {
+                               nvidia,pins = "spi2_cs1_n_pw2";
+                               nvidia,function = "spi2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       nfc-ven {
+                               nvidia,pins = "spi1_sck_px5";
+                               nvidia,function = "spi1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       nfc-firm {
+                               nvidia,pins = "kb_row0_pr0";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+
+                       /* DC pinmux */
+                       lcd-pwr {
+                               nvidia,pins = "lcd_pwr0_pb2",
+                                               "lcd_pwr1_pc1";
+                               nvidia,function = "displaya";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       lcd-wr-n {
+                               nvidia,pins = "lcd_wr_n_pz3";
+                               nvidia,function = "displaya";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       lcd-id {
+                               nvidia,pins = "lcd_m1_pw1";
+                               nvidia,function = "displaya";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       lcd-pclk {
+                               nvidia,pins = "lcd_pclk_pb3",
+                                               "lcd_de_pj1",
+                                               "lcd_hsync_pj3",
+                                               "lcd_vsync_pj4";
+                               nvidia,function = "displaya";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       lcd-rgb-blue {
+                               nvidia,pins = "lcd_d0_pe0",
+                                               "lcd_d1_pe1",
+                                               "lcd_d2_pe2",
+                                               "lcd_d3_pe3",
+                                               "lcd_d4_pe4",
+                                               "lcd_d5_pe5",
+                                               "lcd_d18_pm2",
+                                               "lcd_d19_pm3";
+                               nvidia,function = "displaya";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       lcd-rgb-green {
+                               nvidia,pins = "lcd_d6_pe6",
+                                               "lcd_d7_pe7",
+                                               "lcd_d8_pf0",
+                                               "lcd_d9_pf1",
+                                               "lcd_d10_pf2",
+                                               "lcd_d11_pf3",
+                                               "lcd_d20_pm4",
+                                               "lcd_d21_pm5";
+                               nvidia,function = "displaya";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       lcd-rgb-red {
+                               nvidia,pins = "lcd_d12_pf4",
+                                               "lcd_d13_pf5",
+                                               "lcd_d14_pf6",
+                                               "lcd_d15_pf7",
+                                               "lcd_d16_pm0",
+                                               "lcd_d17_pm1",
+                                               "lcd_d22_pm6",
+                                               "lcd_d23_pm7";
+                               nvidia,function = "displaya";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* Bridge pinmux */
+                       bridge-reset {
+                               nvidia,pins = "ulpi_data1_po2";
+                               nvidia,function = "spi3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       rgb-ic-en {
+                               nvidia,pins = "gmi_a18_pb1";
+                               nvidia,function = "uartd";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       bridge-clk {
+                               nvidia,pins = "clk3_out_pee0";
+                               nvidia,function = "extperiph3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       rgb-bridge {
+                               nvidia,pins = "lcd_sdin_pz2",
+                                               "lcd_sdout_pn5",
+                                               "lcd_cs0_n_pn4",
+                                               "lcd_sck_pz4";
+                               nvidia,function = "spi5";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* Panel pinmux */
+                       panel-reset {
+                               nvidia,pins = "lcd_cs1_n_pw0";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       panel-vio {
+                               nvidia,pins = "ulpi_clk_py0";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+
+                       /* Touchscreen pinmux */
+                       touch-vdd {
+                               nvidia,pins = "kb_col1_pq1";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       touch-vio {
+                               nvidia,pins = "spi1_mosi_px4";
+                               nvidia,function = "spi2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       touch-irq-n {
+                               nvidia,pins = "kb_col3_pq3";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       touch-rst-n {
+                               nvidia,pins = "ulpi_data0_po1";
+                               nvidia,function = "spi3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       touch-maker-id {
+                               nvidia,pins = "kb_col2_pq2";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* MHL pinmux */
+                       mhl-vio {
+                               nvidia,pins = "pv2";
+                               nvidia,function = "owr";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       mhl-rst-n {
+                               nvidia,pins = "clk3_req_pee1";
+                               nvidia,function = "dev3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       mhl-irq {
+                               nvidia,pins = "crt_vsync_pv7";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       mhl-sel {
+                               nvidia,pins = "kb_row10_ps2";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       hdmi-hpd {
+                               nvidia,pins = "hdmi_int_pn7";
+                               nvidia,function = "hdmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* AUDIO pinmux */
+                       hp-detect {
+                               nvidia,pins = "pbb6";
+                               nvidia,function = "vgp6";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       hp-hook {
+                               nvidia,pins = "ulpi_data4_po5";
+                               nvidia,function = "ulpi";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ear-mic-en {
+                               nvidia,pins = "spi2_mosi_px0";
+                               nvidia,function = "spi2";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       audio-irq {
+                               nvidia,pins = "spi2_cs2_n_pw3";
+                               nvidia,function = "spi3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       audio-mclk {
+                               nvidia,pins = "clk1_out_pw4";
+                               nvidia,function = "extperiph1";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap-i2s0 {
+                               nvidia,pins = "dap1_fs_pn0",
+                                               "dap1_din_pn1",
+                                               "dap1_dout_pn2",
+                                               "dap1_sclk_pn3";
+                               nvidia,function = "i2s0";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       dap-i2s1 {
+                               nvidia,pins = "dap2_fs_pa2",
+                                               "dap2_sclk_pa3",
+                                               "dap2_din_pa4",
+                                               "dap2_dout_pa5";
+                               nvidia,function = "i2s1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* MUIC pinmux */
+                       muic-irq {
+                               nvidia,pins = "gmi_cs0_n_pj0";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       muic-dp2t {
+                               nvidia,pins = "pcc2";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       muic-usif {
+                               nvidia,pins = "ulpi_stp_py3";
+                               nvidia,function = "spi1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       ifx-usb-vbus-en {
+                               nvidia,pins = "kb_row4_pr4";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       pcb-rev {
+                               nvidia,pins = "gmi_wait_pi7",
+                                               "gmi_rst_n_pi4";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       jtag-rtck {
+                               nvidia,pins = "jtag_rtck_pu7";
+                               nvidia,function = "rtck";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+
+                       /* Camera pinmux */
+                       cam-mclk {
+                               nvidia,pins = "cam_mclk_pcc0";
+                               nvidia,function = "vi_alt3";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       cam-pmic-en {
+                               nvidia,pins = "pbb4";
+                               nvidia,function = "vgp4";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       front-cam-rst {
+                               nvidia,pins = "pbb5";
+                               nvidia,function = "vgp5";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       front-cam-vio {
+                               nvidia,pins = "ulpi_nxt_py2";
+                               nvidia,function = "rsvd2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       rear-cam-rst {
+                               nvidia,pins = "gmi_cs3_n_pk4";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       rear-cam-eprom-pr {
+                               nvidia,pins = "gmi_cs2_n_pk3";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       rear-cam-vcm-pwdn {
+                               nvidia,pins = "kb_row1_pr1";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* Haptic pinmux */
+                       haptic-en {
+                               nvidia,pins = "gmi_ad9_ph1";
+                               nvidia,function = "gmi";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       haptic-osc {
+                               nvidia,pins = "gmi_ad11_ph3";
+                               nvidia,function = "pwm3";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+
+                       /* Modem pinmux */
+                       cp2ap-ack1-host-active {
+                               nvidia,pins = "pu5";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       cp2ap-ack2-host-wakeup {
+                               nvidia,pins = "pv0";
+                               nvidia,function = "rsvd4";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ap2cp-ack2-suspend-req {
+                               nvidia,pins = "kb_row14_ps6";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ap2cp-ack1-slave-wakeup {
+                               nvidia,pins = "kb_row15_ps7";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       cp-kkp {
+                               nvidia,pins = "kb_col0_pq0";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       cp-crash-irq {
+                               nvidia,pins = "kb_row13_ps5";
+                               nvidia,function = "kbc";
+                               nvidia,pull = <TEGRA_PIN_PULL_UP>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       ap2cp-uarta-tx-ipc {
+                               nvidia,pins = "pu0";
+                               nvidia,function = "uarta";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       ap2cp-uarta-rx-ipc {
+                               nvidia,pins = "pu1";
+                               nvidia,function = "uarta";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       fota-ap-cts-cp-rts {
+                               nvidia,pins = "pu2";
+                               nvidia,function = "uarta";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       fota-ap-rts-cp-cts {
+                               nvidia,pins = "pu3";
+                               nvidia,function = "uarta";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_ENABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+                       modem-enable {
+                               nvidia,pins = "ulpi_data7_po0";
+                               nvidia,function = "hsi";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       modem-reset {
+                               nvidia,pins = "pv1";
+                               nvidia,function = "rsvd1";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+                       };
+                       dap-i2s2 {
+                               nvidia,pins = "dap3_fs_pp0",
+                                               "dap3_din_pp1",
+                                               "dap3_dout_pp2",
+                                               "dap3_sclk_pp3";
+                               nvidia,function = "i2s2";
+                               nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+                               nvidia,tristate = <TEGRA_PIN_DISABLE>;
+                               nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+                       };
+
+                       /* GPIO power/drive control */
+                       drive-i2c {
+                               nvidia,pins = "drive_dbg",
+                                               "drive_at5",
+                                               "drive_gme",
+                                               "drive_ddc",
+                                               "drive_ao1";
+                               nvidia,high-speed-mode = <TEGRA_PIN_DISABLE>;
+                               nvidia,schmitt = <TEGRA_PIN_ENABLE>;
+                               nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>;
+                               nvidia,pull-down-strength = <31>;
+                               nvidia,pull-up-strength = <31>;
+                               nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_FASTEST>;
+                               nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_FASTEST>;
+                       };
+
+                       drive-uart3 {
+                               nvidia,pins = "drive_uart3";
+                               nvidia,high-speed-mode = <TEGRA_PIN_DISABLE>;
+                               nvidia,schmitt = <TEGRA_PIN_ENABLE>;
+                               nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>;
+                               nvidia,pull-down-strength = <31>;
+                               nvidia,pull-up-strength = <31>;
+                               nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_FASTEST>;
+                               nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_FASTEST>;
+                       };
+
+                       drive-gmi {
+                               nvidia,pins = "drive_at3";
+                               nvidia,high-speed-mode = <TEGRA_PIN_DISABLE>;
+                               nvidia,schmitt = <TEGRA_PIN_ENABLE>;
+                               nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>;
+                               nvidia,pull-down-strength = <31>;
+                               nvidia,pull-up-strength = <31>;
+                               nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_FASTEST>;
+                               nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_FASTEST>;
+                       };
+               };
+       };
+
+       uartb: serial@70006040 {
+               compatible = "nvidia,tegra30-hsuart";
+               reset-names = "serial";
+               /delete-property/ reg-shift;
+               status = "okay";
+
+               /* GNSS GSD5T */
+       };
+
+       uartc: serial@70006200 {
+               compatible = "nvidia,tegra30-hsuart";
+               reset-names = "serial";
+               /delete-property/ reg-shift;
+               status = "okay";
+
+               nvidia,adjust-baud-rates = <0 9600 100>,
+                                          <9600 115200 200>,
+                                          <1000000 4000000 136>;
+
+               /* BCM4330B1 37.4 MHz Class 1.5 ExtLNA */
+               bluetooth {
+                       compatible = "brcm,bcm4330-bt";
+                       max-speed = <4000000>;
+
+                       clocks = <&tegra_pmc TEGRA_PMC_CLK_BLINK>;
+                       clock-names = "txco";
+
+                       interrupt-parent = <&gpio>;
+                       interrupts = <TEGRA_GPIO(S, 4) IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "host-wakeup";
+
+                       device-wakeup-gpios = <&gpio TEGRA_GPIO(S, 3) GPIO_ACTIVE_HIGH>;
+                       shutdown-gpios = <&gpio TEGRA_GPIO(CC, 5) GPIO_ACTIVE_HIGH>;
+
+                       vbat-supply = <&vdd_3v3_vbat>;
+                       vddio-supply = <&vdd_1v8_vio>;
+               };
+       };
+
+       uartd: serial@70006300 {
+               /delete-property/ dmas;
+               /delete-property/ dma-names;
+               status = "okay";
+
+               /* Console */
+       };
+
+       pwm@7000a000 {
+               status = "okay";
+       };
+
+       gen1_i2c: i2c@7000c000 {
+               status = "okay";
+               clock-frequency = <400000>;
+
+               /* Aichi AMI306 digital compass */
+               magnetometer@e {
+                       compatible = "asahi-kasei,ak8974";
+                       reg = <0x0e>;
+
+                       interrupt-parent = <&gpio>;
+                       interrupts = <TEGRA_GPIO(H, 5) IRQ_TYPE_EDGE_RISING>;
+
+                       avdd-supply = <&vdd_3v0_sen>;
+                       dvdd-supply = <&vdd_1v8_vio>;
+
+                       mount-matrix = "-1",  "0",  "0",
+                                       "0",  "1",  "0",
+                                       "0",  "0", "-1";
+               };
+
+               max98089: audio-codec@10 {
+                       compatible = "maxim,max98089";
+                       reg = <0x10>;
+
+                       clocks = <&tegra_pmc TEGRA_PMC_CLK_OUT_1>;
+                       clock-names = "mclk";
+
+                       assigned-clocks = <&tegra_pmc TEGRA_PMC_CLK_OUT_1>;
+                       assigned-clock-parents = <&tegra_car TEGRA30_CLK_EXTERN1>;
+               };
+
+               nfc@28 {
+                       compatible = "nxp,pn544-i2c";
+                       reg = <0x28>;
+
+                       interrupt-parent = <&gpio>;
+                       interrupts = <TEGRA_GPIO(W, 2) IRQ_TYPE_EDGE_RISING>;
+
+                       enable-gpios = <&gpio TEGRA_GPIO(X, 5) GPIO_ACTIVE_HIGH>;
+                       firmware-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>;
+               };
+
+               imu@68 {
+                       compatible = "invensense,mpu6050";
+                       reg = <0x68>;
+
+                       interrupt-parent = <&gpio>;
+                       interrupts = <TEGRA_GPIO(H, 4) IRQ_TYPE_EDGE_RISING>;
+
+                       vdd-supply = <&vdd_3v0_sen>;
+                       vddio-supply = <&vdd_1v8_sen>;
+
+                       mount-matrix =  "1",  "0",  "0",
+                                       "0",  "1",  "0",
+                                       "0",  "0", "-1";
+               };
+       };
+
+       gen2_i2c: i2c@7000c400 {
+               status = "okay";
+               clock-frequency = <400000>;
+
+               /* Synaptics RMI4 S3203B touchcreen */
+               touchscreen@20 {
+                       compatible = "syna,rmi4-i2c";
+                       reg = <0x20>;
+
+                       interrupt-parent = <&gpio>;
+                       interrupts = <TEGRA_GPIO(Q, 3) IRQ_TYPE_EDGE_FALLING>;
+
+                       vdd-supply = <&vdd_3v0_touch>;
+                       vio-supply = <&vdd_1v8_touch>;
+
+                       syna,reset-delay-ms = <20>;
+                       syna,startup-delay-ms = <200>;
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       rmi4-f01@1 {
+                               reg = <0x1>;
+                               syna,nosleep-mode = <1>;
+                       };
+
+                       rmi4-f11@11 {
+                               reg = <0x11>;
+                               syna,sensor-type = <1>;
+
+                               syna,clip-x-low = <0>;
+                               syna,clip-y-low = <0>;
+                       };
+               };
+       };
+
+       cam_i2c: i2c@7000c500 {
+               status = "okay";
+               clock-frequency = <400000>;
+
+               dw9714: coil@c {
+                       compatible = "dongwoon,dw9714";
+                       reg = <0x0c>;
+
+                       enable-gpios = <&gpio TEGRA_GPIO(R, 1) GPIO_ACTIVE_HIGH>;
+
+                       vcc-supply = <&vcc_focuser>;
+               };
+
+               camera-pmic@7d {
+                       compatible = "ti,lp8720";
+                       reg = <0x7d>;
+
+                       enable-gpios = <&gpio TEGRA_GPIO(BB, 4) GPIO_ACTIVE_HIGH>;
+
+                       vt_1v2_front: ldo1 {
+                               regulator-name = "vt_1v2_dig";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                       };
+
+                       vt_2v7_front: ldo2 {
+                               regulator-name = "vt_2v7_vana";
+                               regulator-min-microvolt = <2700000>;
+                               regulator-max-microvolt = <2700000>;
+                       };
+
+                       vdd_2v7_rear: ldo3 {
+                               regulator-name = "8m_2v7_vana";
+                               regulator-min-microvolt = <2700000>;
+                               regulator-max-microvolt = <2800000>;
+                       };
+
+                       vio_1v8_rear: ldo4 {
+                               regulator-name = "vio_1v8_cam";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                       };
+
+                       vcc_focuser: ldo5 {
+                               regulator-name = "8m_2v8_vcm";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                       };
+
+                       vdd_1v2_rear: buck {
+                               regulator-name = "8m_1v2_cam";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                       };
+               };
+       };
+
+       hdmi_ddc: i2c@7000c700 {
+               status = "okay";
+               clock-frequency = <100000>;
+       };
+
+       pwr_i2c: i2c@7000d000 {
+               status = "okay";
+               clock-frequency = <400000>;
+
+               pmic: max77663@1c {
+                       compatible = "maxim,max77663";
+                       reg = <0x1c>;
+
+                       interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+
+                       #gpio-cells = <2>;
+                       gpio-controller;
+
+                       system-power-controller;
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&max77663_default>;
+
+                       max77663_default: pinmux {
+                               gpio1 {
+                                       pins = "gpio1";
+                                       function = "gpio";
+                                       drive-open-drain = <1>;
+                               };
+
+                               gpio4 {
+                                       pins = "gpio4";
+                                       function = "32k-out1";
+                               };
+                       };
+
+                       fps {
+                               fps0 {
+                                       maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN0>;
+                               };
+
+                               fps1 {
+                                       maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN1>;
+                               };
+
+                               fps2 {
+                                       maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN0>;
+                               };
+                       };
+
+                       regulators {
+                               in-sd0-supply = <&vdd_5v0_vbus>;
+                               in-sd1-supply = <&vdd_5v0_vbus>;
+                               in-sd2-supply = <&vdd_5v0_vbus>;
+                               in-sd3-supply = <&vdd_5v0_vbus>;
+
+                               in-ldo0-1-supply = <&vdd_1v8_vio>;
+                               in-ldo2-supply   = <&vdd_3v3_vbat>;
+                               in-ldo3-5-supply = <&vdd_3v3_vbat>;
+                               in-ldo4-6-supply = <&vdd_3v3_vbat>;
+                               in-ldo7-8-supply = <&vdd_1v8_vio>;
+
+                               vdd_cpu: sd0 {
+                                       regulator-name = "vdd_cpu";
+                                       regulator-min-microvolt = <800000>;
+                                       regulator-max-microvolt = <1250000>;
+                                       regulator-coupled-with = <&vdd_core>;
+                                       regulator-coupled-max-spread = <300000>;
+                                       regulator-max-step-microvolt = <100000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       nvidia,tegra-cpu-regulator;
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                               };
+
+                               vdd_core: sd1 {
+                                       regulator-name = "vdd_core";
+                                       regulator-min-microvolt = <950000>;
+                                       regulator-max-microvolt = <1350000>;
+                                       regulator-coupled-with = <&vdd_cpu>;
+                                       regulator-coupled-max-spread = <300000>;
+                                       regulator-max-step-microvolt = <100000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       nvidia,tegra-core-regulator;
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_1>;
+                               };
+
+                               vdd_1v8_vio: sd2 {
+                                       regulator-name = "vdd_1v8_gen";
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                               };
+
+                               sd3 {
+                                       regulator-name = "vddio_ddr";
+                                       regulator-min-microvolt = <1200000>;
+                                       regulator-max-microvolt = <1200000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                               };
+
+                               ldo0 {
+                                       regulator-name = "avdd_pll";
+                                       regulator-min-microvolt = <1200000>;
+                                       regulator-max-microvolt = <1200000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_1>;
+                               };
+
+                               ldo1 {
+                                       regulator-name = "vdd_ddr_hs";
+                                       regulator-min-microvolt = <1000000>;
+                                       regulator-max-microvolt = <1000000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                               };
+
+                               avdd_3v3_periph: ldo2 {
+                                       regulator-name = "avdd_usb";
+                                       regulator-min-microvolt = <3300000>;
+                                       regulator-max-microvolt = <3300000>;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                               };
+
+                               vdd_usd: ldo3 {
+                                       regulator-name = "vdd_sdmmc3";
+                                       regulator-min-microvolt = <3000000>;
+                                       regulator-max-microvolt = <3000000>;
+                                       regulator-always-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                               };
+
+                               ldo4 {
+                                       regulator-name = "vdd_rtc";
+                                       regulator-min-microvolt = <1200000>;
+                                       regulator-max-microvolt = <1200000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
+                               };
+
+                               vcore_emmc: ldo5 {
+                                       regulator-name = "vdd_ddr_rx";
+                                       regulator-min-microvolt = <2850000>;
+                                       regulator-max-microvolt = <2850000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
+                               };
+
+                               avdd_1v8_hdmi_pll: ldo6 {
+                                       regulator-name = "avdd_osc";
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
+                                       regulator-always-on;
+                                       regulator-boot-on;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                               };
+
+                               vdd_1v2_mhl: ldo7 {
+                                       regulator-name = "vdd_1v2_mhl";
+                                       regulator-min-microvolt = <1050000>;
+                                       regulator-max-microvolt = <1250000>;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                               };
+
+                               ldo8 {
+                                       regulator-name = "avdd_dsi_csi";
+                                       regulator-min-microvolt = <1200000>;
+                                       regulator-max-microvolt = <1200000>;
+
+                                       maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
+                               };
+                       };
+               };
+
+               fuel-gauge@36 {
+                       compatible = "maxim,max17043";
+                       reg = <0x36>;
+
+                       interrupt-parent = <&gpio>;
+                       interrupts = <TEGRA_GPIO(S, 0) IRQ_TYPE_EDGE_FALLING>;
+
+                       monitored-battery = <&battery>;
+
+                       maxim,alert-low-soc-level = <10>;
+                       wakeup-source;
+               };
+
+               power-sensor@40 {
+                       compatible = "ti,ina230";
+                       reg = <0x40>;
+
+                       vs-supply = <&vdd_3v0_sen>;
+               };
+
+               nct72: temperature-sensor@4c {
+                       compatible = "onnn,nct1008";
+                       reg = <0x4c>;
+
+                       interrupt-parent = <&gpio>;
+                       interrupts = <TEGRA_GPIO(I, 5) IRQ_TYPE_EDGE_FALLING>;
+
+                       vcc-supply = <&vdd_3v0_sen>;
+                       #thermal-sensor-cells = <1>;
+               };
+       };
+
+       i2c-mhl {
+               compatible = "i2c-gpio";
+
+               sda-gpios = <&gpio TEGRA_GPIO(Q, 7) (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+               scl-gpios = <&gpio TEGRA_GPIO(Q, 6) (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+
+               i2c-gpio,delay-us = <5>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       spi@7000dc00 {
+               status = "okay";
+               spi-max-frequency = <25000000>;
+
+               /* DSI bridge */
+       };
+
+       pmc@7000e400 {
+               status = "okay";
+               nvidia,invert-interrupt;
+               nvidia,suspend-mode = <2>;
+               nvidia,cpu-pwr-good-time = <2000>;
+               nvidia,cpu-pwr-off-time = <200>;
+               nvidia,core-pwr-good-time = <3845 3845>;
+               nvidia,core-pwr-off-time = <0>;
+               nvidia,core-power-req-active-high;
+               nvidia,sys-clock-req-active-high;
+               core-supply = <&vdd_core>;
+
+               i2c-thermtrip {
+                       nvidia,i2c-controller-id = <4>;
+                       nvidia,bus-addr = <0x1c>;
+                       nvidia,reg-addr = <0x41>;
+                       nvidia,reg-data = <0x02>;
+               };
+       };
+
+       hda@70030000 {
+               status = "okay";
+       };
+
+       ahub@70080000 {
+               /* HIFI CODEC */
+               i2s@70080300 {          /* i2s0 */
+                       status = "okay";
+               };
+
+               /* BASEBAND */
+               i2s@70080500 {          /* i2s2 */
+                       status = "okay";
+               };
+
+               /* BT SCO */
+               i2s@70080600 {          /* i2s3 */
+                       status = "okay";
+               };
+       };
+
+       sdmmc1: mmc@78000000 {
+               status = "okay";
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               assigned-clocks = <&tegra_car TEGRA30_CLK_SDMMC1>;
+               assigned-clock-parents = <&tegra_car TEGRA30_CLK_PLL_C>;
+               assigned-clock-rates = <50000000>;
+
+               max-frequency = <50000000>;
+               keep-power-in-suspend;
+               bus-width = <4>;
+               non-removable;
+
+               mmc-pwrseq = <&brcm_wifi_pwrseq>;
+               vmmc-supply = <&vdd_3v3_vbat>;
+               vqmmc-supply = <&vdd_1v8_vio>;
+
+               /* BCM4330B1 37.4 MHz Class 1.5 ExtLNA */
+               wifi@1 {
+                       compatible = "brcm,bcm4329-fmac";
+                       reg = <1>;
+
+                       interrupt-parent = <&gpio>;
+                       interrupts = <TEGRA_GPIO(U, 6) IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "host-wake";
+               };
+       };
+
+       sdmmc4: mmc@78000600 {
+               status = "okay";
+               bus-width = <8>;
+
+               non-removable;
+               mmc-ddr-1_8v;
+
+               vmmc-supply = <&vcore_emmc>;
+               vqmmc-supply = <&vdd_1v8_vio>;
+       };
+
+       /* Micro USB */
+       usb@7d000000 {
+               compatible = "nvidia,tegra30-udc";
+               status = "okay";
+               dr_mode = "peripheral";
+       };
+
+       usb-phy@7d000000 {
+               status = "okay";
+               dr_mode = "peripheral";
+               nvidia,hssync-start-delay = <0>;
+               nvidia,xcvr-lsfslew = <2>;
+               nvidia,xcvr-lsrslew = <2>;
+               vbus-supply = <&avdd_3v3_periph>;
+       };
+
+       /* PMIC has a built-in 32KHz oscillator which is used by PMC */
+       clk32k_in: clock-32k {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <32768>;
+               clock-output-names = "pmic-oscillator";
+       };
+
+       gps_refclk: clock-gps {
+               compatible = "fixed-clock";
+               clock-frequency = <26000000>;
+               clock-accuracy = <100>;
+               #clock-cells = <0>;
+       };
+
+       gps_osc: clock-gps-osc-gate {
+               compatible = "gpio-gate-clock";
+               enable-gpios = <&gpio TEGRA_GPIO(H, 0) GPIO_ACTIVE_HIGH>;
+               clocks = <&gps_refclk>;
+               #clock-cells = <0>;
+       };
+
+       cpus {
+               cpu0: cpu@0 {
+                       cpu-supply = <&vdd_cpu>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+                       #cooling-cells = <2>;
+               };
+               cpu1: cpu@1 {
+                       cpu-supply = <&vdd_cpu>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+                       #cooling-cells = <2>;
+               };
+               cpu2: cpu@2 {
+                       cpu-supply = <&vdd_cpu>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+                       #cooling-cells = <2>;
+               };
+               cpu3: cpu@3 {
+                       cpu-supply = <&vdd_cpu>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+                       #cooling-cells = <2>;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               key-power {
+                       label = "Power";
+                       gpios = <&gpio TEGRA_GPIO(C, 7) GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_POWER>;
+                       debounce-interval = <10>;
+                       wakeup-event-action = <EV_ACT_ASSERTED>;
+                       wakeup-source;
+               };
+
+               key-volume-down {
+                       label = "Volume Down";
+                       gpios = <&gpio TEGRA_GPIO(O, 4) GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEDOWN>;
+                       debounce-interval = <10>;
+                       wakeup-event-action = <EV_ACT_ASSERTED>;
+                       wakeup-source;
+               };
+       };
+
+       gpio-leds {
+               compatible = "gpio-leds";
+
+               led-keypad {
+                       label = "keypad::white";
+                       gpios = <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
+
+                       color = <LED_COLOR_ID_WHITE>;
+                       function = LED_FUNCTION_KBD_BACKLIGHT;
+               };
+       };
+
+       opp-table-actmon {
+               /delete-node/ opp-625000000;
+               /delete-node/ opp-667000000;
+               /delete-node/ opp-750000000;
+               /delete-node/ opp-800000000;
+               /delete-node/ opp-900000000;
+       };
+
+       opp-table-emc {
+               /delete-node/ opp-625000000-1200;
+               /delete-node/ opp-625000000-1250;
+               /delete-node/ opp-667000000-1200;
+               /delete-node/ opp-750000000-1300;
+               /delete-node/ opp-800000000-1300;
+               /delete-node/ opp-900000000-1350;
+       };
+
+       brcm_wifi_pwrseq: pwrseq-wifi {
+               compatible = "mmc-pwrseq-simple";
+
+               clocks = <&tegra_pmc TEGRA_PMC_CLK_BLINK>;
+               clock-names = "ext_clock";
+
+               reset-gpios = <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_LOW>;
+               post-power-on-delay-ms = <300>;
+               power-off-delay-us = <300>;
+       };
+
+       vdd_5v0_vbus: regulator-vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       vdd_3v3_vbat: regulator-vbat {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_vbat";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vdd_5v0_vbus>;
+       };
+
+       vdd_3v0_sen: regulator-sen3v {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_3v0_sensor";
+               regulator-min-microvolt = <3000000>;
+               regulator-max-microvolt = <3000000>;
+               regulator-boot-on;
+               gpio = <&gpio TEGRA_GPIO(X, 7) GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               vin-supply = <&vdd_3v3_vbat>;
+       };
+
+       vdd_3v0_proxi: regulator-proxi {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_3v0_proxi";
+               regulator-min-microvolt = <3000000>;
+               regulator-max-microvolt = <3000000>;
+               regulator-boot-on;
+               gpio = <&gpio TEGRA_GPIO(X, 1) GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               vin-supply = <&vdd_3v3_vbat>;
+       };
+
+       vdd_1v8_sen: regulator-sen1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_1v8_sensor";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               gpio = <&gpio TEGRA_GPIO(D, 2) GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               vin-supply = <&vdd_3v3_vbat>;
+       };
+
+       vcc_3v0_lcd: regulator-lcd3v {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_3v0_lcd";
+               regulator-min-microvolt = <3000000>;
+               regulator-max-microvolt = <3000000>;
+               regulator-boot-on;
+               vin-supply = <&vdd_3v3_vbat>;
+       };
+
+       iovcc_1v8_lcd: regulator-lcd1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "iovcc_1v8_lcd";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               gpio = <&gpio TEGRA_GPIO(Y, 0) GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               vin-supply = <&vdd_3v3_vbat>;
+       };
+
+       vio_1v8_mhl: regulator-mhl1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "vio_1v8_mhl";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               gpio = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               vin-supply = <&vdd_3v3_vbat>;
+       };
+
+       vdd_3v0_touch: regulator-touchpwr {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_3v0_touch";
+               regulator-min-microvolt = <3000000>;
+               regulator-max-microvolt = <3000000>;
+               regulator-boot-on;
+               gpio = <&gpio TEGRA_GPIO(Q, 1) GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               vin-supply = <&vdd_3v3_vbat>;
+       };
+
+       vdd_1v8_touch: regulator-touchvio {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_1v8_touch";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               gpio = <&gpio TEGRA_GPIO(X, 4) GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               vin-supply = <&vdd_3v3_vbat>;
+       };
+
+       vcc_1v8_gps: regulator-gps {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_1v8_gps";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               gpio = <&gpio TEGRA_GPIO(Y, 1) GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               vin-supply = <&vdd_3v3_vbat>;
+       };
+
+       vio_1v8_front: regulator-frontvio {
+               compatible = "regulator-fixed";
+               regulator-name = "vt_1v8_cam_vio";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               gpio = <&gpio TEGRA_GPIO(Y, 2) GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               vin-supply = <&vdd_3v3_vbat>;
+       };
+
+       sound {
+               nvidia,audio-routing =
+                       "Headphone Jack", "HPL",
+                       "Headphone Jack", "HPR",
+                       "Int Spk", "SPKL",
+                       "Int Spk", "SPKR",
+                       "Earpiece", "RECL",
+                       "Earpiece", "RECR",
+                       "INA1", "Mic Jack",
+                       "MIC1", "MICBIAS",
+                       "MICBIAS", "Internal Mic 1",
+                       "MIC2", "Internal Mic 2";
+
+               nvidia,i2s-controller = <&tegra_i2s0>;
+               nvidia,audio-codec = <&max98089>;
+
+               nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(BB, 6) GPIO_ACTIVE_LOW>;
+               nvidia,mic-det-gpios = <&gpio TEGRA_GPIO(O, 5) GPIO_ACTIVE_HIGH>;
+               nvidia,ext-mic-en-gpios = <&gpio TEGRA_GPIO(X, 0) GPIO_ACTIVE_HIGH>;
+               nvidia,coupled-mic-hp-det;
+
+               clocks = <&tegra_car TEGRA30_CLK_PLL_A>,
+                        <&tegra_car TEGRA30_CLK_PLL_A_OUT0>,
+                        <&tegra_pmc TEGRA_PMC_CLK_OUT_1>;
+               clock-names = "pll_a", "pll_a_out0", "mclk";
+
+               assigned-clocks = <&tegra_car TEGRA30_CLK_EXTERN1>,
+                                 <&tegra_pmc TEGRA_PMC_CLK_OUT_1>;
+
+               assigned-clock-parents = <&tegra_car TEGRA30_CLK_PLL_A_OUT0>,
+                                        <&tegra_car TEGRA30_CLK_EXTERN1>;
+       };
+
+       thermal-zones {
+               /*
+                * NCT72 has two sensors:
+                *
+                *      0: internal that monitors ambient/skin temperature
+                *      1: external that is connected to the CPU's diode
+                *
+                * Ideally we should use userspace thermal governor,
+                * but it's a much more complex solution. The "skin"
+                * zone exists as a simpler solution which prevents
+                * this device from getting too hot from a user's
+                * tactile perspective. The CPU zone is intended to
+                * protect silicon from damage.
+                */
+
+               skin-thermal {
+                       polling-delay-passive = <1000>; /* milliseconds */
+                       polling-delay = <5000>; /* milliseconds */
+
+                       thermal-sensors = <&nct72 0>;
+
+                       trips {
+                               trip0: skin-alert {
+                                       /* throttle at 50C until temperature drops to 49.8C */
+                                       temperature = <50000>;
+                                       hysteresis = <200>;
+                                       type = "passive";
+                               };
+
+                               trip1: skin-crit {
+                                       /* shut down at 60C */
+                                       temperature = <60000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&trip0>;
+                                       cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&actmon THERMAL_NO_LIMIT
+                                                                 THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu-thermal {
+                       polling-delay-passive = <1000>; /* milliseconds */
+                       polling-delay = <5000>; /* milliseconds */
+
+                       thermal-sensors = <&nct72 1>;
+
+                       trips {
+                               trip2: cpu-alert {
+                                       /* throttle at 75C until temperature drops to 74.8C */
+                                       temperature = <75000>;
+                                       hysteresis = <200>;
+                                       type = "passive";
+                               };
+
+                               trip3: cpu-crit {
+                                       /* shut down at 90C */
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map1 {
+                                       trip = <&trip2>;
+                                       cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&actmon THERMAL_NO_LIMIT
+                                                                 THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+       };
+};
index a724d1a7a9a0783bfe80722c773547b316b3db0b..4052cad859fa9f2928ae99edcde3cbc2480cdb4b 100644 (file)
@@ -45,7 +45,9 @@ dtb-$(CONFIG_SOC_IMX53) += \
        imx53-mba53.dtb \
        imx53-ppd.dtb \
        imx53-qsb.dtb \
+       imx53-qsb-hdmi.dtb \
        imx53-qsrb.dtb \
+       imx53-qsrb-hdmi.dtb \
        imx53-sk-imx53.dtb \
        imx53-sk-imx53-atm0700d4-lvds.dtb \
        imx53-sk-imx53-atm0700d4-rgb.dtb \
@@ -54,6 +56,8 @@ dtb-$(CONFIG_SOC_IMX53) += \
        imx53-tx53-x13x.dtb \
        imx53-usbarmory.dtb \
        imx53-voipac-bsb.dtb
+imx53-qsb-hdmi-dtbs := imx53-qsb.dtb imx53-qsb-hdmi.dtbo
+imx53-qsrb-hdmi-dtbs := imx53-qsrb.dtb imx53-qsb-hdmi.dtbo
 dtb-$(CONFIG_SOC_IMX6Q) += \
        imx6dl-alti6p.dtb \
        imx6dl-apf6dev.dtb \
@@ -118,6 +122,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
        imx6dl-sabrelite.dtb \
        imx6dl-sabresd.dtb \
        imx6dl-savageboard.dtb \
+       imx6dl-sielaff.dtb \
        imx6dl-skov-revc-lt2.dtb \
        imx6dl-skov-revc-lt6.dtb \
        imx6dl-solidsense.dtb \
@@ -147,6 +152,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
        imx6dl-yapp4-phoenix.dtb \
        imx6dl-yapp4-ursa.dtb \
        imx6q-apalis-eval.dtb \
+       imx6q-apalis-eval-v1.2.dtb \
        imx6q-apalis-ixora.dtb \
        imx6q-apalis-ixora-v1.1.dtb \
        imx6q-apalis-ixora-v1.2.dtb \
index e66eef87a7a4fdfe33c8249946400b5fd7075f8a..058e9435524fe1d12a95e7dba36ec92a073403b3 100644 (file)
@@ -54,7 +54,7 @@
                #size-cells = <1>;
        };
 
-       eth: eth@4,c00000 {
+       eth: ethernet@4,c00000 {
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_eth>;
                compatible = "davicom,dm9000";
index 1ac10965fdfdd5284cfa860f168fccdc57c64433..389ecb1ebf8f1b39832aa279f3cbd1ec15c74332 100644 (file)
                        };
                };
 
-               weim: weim@220000 {
+               weim: memory-controller@220000 {
                        #address-cells = <2>;
                        #size-cells = <1>;
                        compatible = "fsl,imx1-weim";
index ec472695c71ea9e8f05a7b424c84589ec4c95957..ec3ccc8f4095ff476f3feb9e2a744da80f5808f6 100644 (file)
                        status = "disabled";
                };
 
-               weim: weim@d8002000 {
+               weim: memory-controller@d8002000 {
                        #address-cells = <2>;
                        #size-cells = <1>;
                        compatible = "fsl,imx27-weim";
index e1ae7c175f7d55e2cf3c4103a7c571a042b3e71c..00006c90d9a71a6a363632740ac6158f6adbb953 100644 (file)
                                status = "disabled";
                        };
 
-                       weim: weim@b8002000 {
+                       weim: memory-controller@b8002000 {
                                compatible = "fsl,imx31-weim", "fsl,imx27-weim";
                                reg = <0xb8002000 0x1000>;
                                clocks = <&clks 56>;
index 2d20e5541acc8388e3ab41307166f068200c34a3..442dc15677b87ed59aa8dc5109ea746cb021ac2a 100644 (file)
                                status = "disabled";
                        };
 
-                       weim: weim@b8002000 {
+                       weim: memory-controller@b8002000 {
                                #address-cells = <2>;
                                #size-cells = <1>;
                                clocks = <&clks 0>;
index c96d6311dfa7cf4b9cda9db8024d91daab7dfe77..4efce49022e44159d36abfb1fc9bc71ea068c1e7 100644 (file)
                                reg = <0x83fd8000 0x1000>;
                        };
 
-                       weim: weim@83fda000 {
+                       weim: memory-controller@83fda000 {
                                #address-cells = <2>;
                                #size-cells = <1>;
                                compatible = "fsl,imx51-weim";
diff --git a/arch/arm/boot/dts/nxp/imx/imx53-qsb-hdmi.dtso b/arch/arm/boot/dts/nxp/imx/imx53-qsb-hdmi.dtso
new file mode 100644 (file)
index 0000000..c84e9b0
--- /dev/null
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * DT overlay for MCIMXHDMICARD as used with the iMX53 QSB or QSRB boards
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/dts-v1/;
+/plugin/;
+
+&{/} {
+       /delete-node/ panel;
+
+       hdmi: connector-hdmi {
+               compatible = "hdmi-connector";
+               label = "hdmi";
+               type = "a";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&sii9022_out>;
+                       };
+               };
+       };
+
+       reg_1p2v: regulator-1p2v {
+               compatible = "regulator-fixed";
+               regulator-name = "1P2V";
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <1200000>;
+               regulator-always-on;
+               vin-supply = <&reg_3p2v>;
+       };
+};
+
+&display0 {
+       status = "okay";
+};
+
+&display0 {
+       port@1 {
+               display0_out: endpoint {
+                       remote-endpoint = <&sii9022_in>;
+               };
+       };
+};
+
+&i2c2 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       sii9022: bridge-hdmi@39 {
+               compatible = "sil,sii9022";
+               reg = <0x39>;
+               reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+               interrupts-extended = <&gpio3 31 IRQ_TYPE_LEVEL_LOW>;
+               iovcc-supply = <&reg_3p2v>;
+               #sound-dai-cells = <0>;
+               sil,i2s-data-lanes = <0>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               sii9022_in: endpoint {
+                                       remote-endpoint = <&display0_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               sii9022_out: endpoint {
+                                       remote-endpoint = <&hdmi_connector_in>;
+                               };
+                       };
+               };
+       };
+};
+
+&tve {
+       status = "disabled";
+};
diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-sielaff.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-sielaff.dts
new file mode 100644 (file)
index 0000000..7de8d5f
--- /dev/null
@@ -0,0 +1,533 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Copyright (C) 2022 Kontron Electronics GmbH
+ */
+
+/dts-v1/;
+
+#include "imx6dl.dtsi"
+#include <dt-bindings/clock/imx6qdl-clock.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+       model = "Sielaff i.MX6 Solo";
+       compatible = "sielaff,imx6dl-board", "fsl,imx6dl";
+
+       chosen {
+               stdout-path = &uart2;
+       };
+
+       backlight: pwm-backlight {
+               compatible = "pwm-backlight";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_backlight>;
+               pwms = <&pwm3 0 50000 0>;
+               brightness-levels = <0 0 64 88 112 136 184 232 255>;
+               default-brightness-level = <4>;
+               enable-gpios = <&gpio6 16 GPIO_ACTIVE_HIGH>;
+               power-supply = <&reg_backlight>;
+       };
+
+       cec {
+               compatible = "cec-gpio";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_hdmi_cec>;
+               cec-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+               hdmi-phandle = <&hdmi>;
+       };
+
+       enet_ref: clock-enet-ref {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <50000000>;
+               clock-output-names = "enet-ref";
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_keys>;
+
+               key-0 {
+                       gpios = <&gpio2 16 0>;
+                       debounce-interval = <10>;
+                       linux,code = <1>;
+               };
+
+               key-1 {
+                       gpios = <&gpio3 27 0>;
+                       debounce-interval = <10>;
+                       linux,code = <2>;
+               };
+
+               key-2 {
+                       gpios = <&gpio5 4 0>;
+                       debounce-interval = <10>;
+                       linux,code = <3>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_leds>;
+
+               led-debug {
+                       label = "debug-led";
+                       gpios = <&gpio5 21 GPIO_ACTIVE_HIGH>;
+                       default-state = "off";
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       memory@80000000 {
+               reg = <0x80000000 0x20000000>;
+               device_type = "memory";
+       };
+
+       osc_eth_phy: clock-osc-eth-phy {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <25000000>;
+               clock-output-names = "osc-eth-phy";
+       };
+
+       panel {
+               compatible = "lg,lb070wv8";
+               backlight = <&backlight>;
+               power-supply = <&reg_3v3>;
+
+               port {
+                       panel_in_lvds: endpoint {
+                               remote-endpoint = <&lvds_out>;
+                       };
+               };
+       };
+
+       reg_3v3: regulator-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "3v3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       reg_backlight: regulator-backlight {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_backlight>;
+               enable-active-high;
+               gpio = <&gpio1 23 GPIO_ACTIVE_HIGH>;
+               regulator-name = "backlight";
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+       };
+
+       reg_usb_otg_vbus: regulator-usb-otg-vbus {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_usbotg_vbus>;
+               enable-active-high;
+               gpio = <&gpio4 15 GPIO_ACTIVE_HIGH>;
+               regulator-name = "usb_otg_vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+       };
+};
+
+&ecspi2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi2>;
+       cs-gpios = <&gpio5 29 GPIO_ACTIVE_LOW>;
+       status = "okay";
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <20000000>;
+       };
+};
+
+&fec {
+       /*
+        * Set PTP clock to external instead of internal reference, as the
+        * REF_CLK from the PHY is fed back into the i.MX6 and the GPR
+        * register needs to be set accordingly (see mach-imx6q.c).
+        */
+       clocks = <&clks IMX6QDL_CLK_ENET>,
+                <&clks IMX6QDL_CLK_ENET>,
+                <&enet_ref>,
+                <&clks IMX6QDL_CLK_ENET_REF>;
+       clock-names = "ipg", "ahb", "ptp", "enet_out";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_enet>;
+       phy-connection-type = "rmii";
+       phy-handle = <&ethphy>;
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy: ethernet-phy@1 {
+                       reg = <1>;
+                       clocks = <&osc_eth_phy>;
+                       clock-names = "rmii-ref";
+                       micrel,led-mode = <1>;
+                       reset-assert-us = <500>;
+                       reset-deassert-us = <100>;
+                       reset-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
+               };
+       };
+};
+
+&gpio1 {
+       gpio-line-names =
+               "", "", "", "", "", "", "", "",
+               "", "", "", "", "", "", "key-out", "key-in",
+               "", "", "", "", "", "", "", "",
+               "", "", "", "", "", "", "", "";
+};
+
+&gpio2 {
+       gpio-line-names =
+               "", "", "", "", "", "", "", "",
+               "lan9500a-rst", "", "", "", "", "", "", "",
+               "", "", "", "", "", "", "", "",
+               "", "", "", "", "", "", "", "";
+};
+
+&gpmi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpmi_nand>;
+       status = "okay";
+};
+
+&hdmi {
+       ddc-i2c-bus = <&i2c4>;
+       status = "okay";
+};
+
+&i2c2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       clock-frequency = <100000>;
+       status = "okay";
+
+       rtc@51 {
+               compatible = "nxp,pcf8563";
+               reg = <0x51>;
+       };
+};
+
+&i2c3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       clock-frequency = <100000>;
+       status = "okay";
+
+       touchscreen@55 {
+               compatible = "sitronix,st1633";
+               reg = <0x55>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_touch>;
+               interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+               interrupt-parent = <&gpio5>;
+               gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
+               status = "disabled";
+       };
+
+       touchscreen@5d {
+               compatible = "goodix,gt928";
+               reg = <0x5d>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_touch>;
+               interrupts = <18 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-parent = <&gpio5>;
+               irq-gpios = <&gpio5 18 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+               status = "disabled";
+       };
+};
+
+&i2c4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c4>;
+       clock-frequency = <100000>;
+       status = "okay";
+};
+
+&ldb {
+       status = "okay";
+
+       lvds: lvds-channel@0 {
+               fsl,data-mapping = "spwg";
+               fsl,data-width = <24>;
+               status = "okay";
+
+               port@4 {
+                       reg = <4>;
+
+                       lvds_out: endpoint {
+                               remote-endpoint = <&panel_in_lvds>;
+                       };
+               };
+       };
+};
+
+&pwm3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm3>;
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       status = "okay";
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       status = "okay";
+};
+
+&usbh1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbh1>;
+       disable-over-current;
+       status = "okay";
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       usb1@1 {
+               compatible = "usb4b4,6570";
+               reg = <1>;
+               clocks = <&clks IMX6QDL_CLK_CKO>;
+
+               assigned-clocks = <&clks IMX6QDL_CLK_CKO>,
+                                 <&clks IMX6QDL_CLK_CKO2_SEL>;
+               assigned-clock-parents = <&clks IMX6QDL_CLK_CKO2>,
+                                        <&clks IMX6QDL_CLK_OSC>;
+               assigned-clock-rates = <12000000 0>;
+       };
+};
+
+&usbotg {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg>;
+       dr_mode = "host";
+       over-current-active-low;
+       vbus-supply = <&reg_usb_otg_vbus>;
+       status = "okay";
+};
+
+&usdhc3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&reg_3v3>;
+       voltage-ranges = <3300 3300>;
+       no-1-8-v;
+       status = "okay";
+};
+
+&wdog1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdog>;
+       fsl,ext-reset-output;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hog>;
+
+       pinctrl_hog: hoggrp {
+               fsl,pins = <
+                       MX6QDL_PAD_RGMII_RD0__GPIO6_IO25        0x1b0b0 /* PMIC_IRQ */
+                       MX6QDL_PAD_SD2_DAT3__GPIO1_IO12         0x1b0b0
+                       MX6QDL_PAD_SD2_DAT1__GPIO1_IO14         0x1b0b0
+                       MX6QDL_PAD_SD2_DAT0__GPIO1_IO15         0x1b0b0
+                       MX6QDL_PAD_SD4_DAT0__GPIO2_IO08         0x1b0b0
+                       MX6QDL_PAD_EIM_D29__GPIO3_IO29          0x1b0b0
+               >;
+       };
+
+       pinctrl_backlight: backlightgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_CS3__GPIO6_IO16        0x100b1
+               >;
+       };
+
+       pinctrl_ecspi2: ecspi2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_DAT10__ECSPI2_MISO      0x100b1
+                       MX6QDL_PAD_CSI0_DAT9__ECSPI2_MOSI       0x100b1
+                       MX6QDL_PAD_CSI0_DAT8__ECSPI2_SCLK       0x100b1
+                       MX6QDL_PAD_CSI0_DAT11__GPIO5_IO29       0x100b1
+               >;
+       };
+
+       pinctrl_enet: enetgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_MDIO__ENET_MDIO         0x1b0b0
+                       MX6QDL_PAD_ENET_MDC__ENET_MDC           0x1b0b0
+                       MX6QDL_PAD_ENET_RXD0__ENET_RX_DATA0     0x1b0b0
+                       MX6QDL_PAD_ENET_RXD1__ENET_RX_DATA1     0x1b0b0
+                       MX6QDL_PAD_ENET_CRS_DV__ENET_RX_EN      0x1b0b0
+                       MX6QDL_PAD_ENET_RX_ER__ENET_RX_ER       0x1b0b0
+                       MX6QDL_PAD_ENET_TXD0__ENET_TX_DATA0     0x1b0b0
+                       MX6QDL_PAD_ENET_TXD1__ENET_TX_DATA1     0x1b0b0
+                       MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN       0x1b0b0
+                       MX6QDL_PAD_GPIO_16__ENET_REF_CLK        0x4001b0a8
+                       MX6QDL_PAD_EIM_A25__GPIO5_IO02          0x100b1
+               >;
+       };
+
+       pinctrl_gpio_keys: gpiokeysgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_A22__GPIO2_IO16          0x1b080
+                       MX6QDL_PAD_EIM_D27__GPIO3_IO27          0x1b080
+                       MX6QDL_PAD_EIM_A24__GPIO5_IO04          0x1b080
+               >;
+       };
+
+       pinctrl_gpio_leds: gpioledsgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21       0x1b0b0
+               >;
+       };
+
+       pinctrl_gpmi_nand: gpminandgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_CLE__NAND_CLE          0xb0b1
+                       MX6QDL_PAD_NANDF_ALE__NAND_ALE          0xb0b1
+                       MX6QDL_PAD_NANDF_WP_B__NAND_WP_B        0xb0b1
+                       MX6QDL_PAD_NANDF_RB0__NAND_READY_B      0xb000
+                       MX6QDL_PAD_NANDF_CS0__NAND_CE0_B        0xb0b1
+                       MX6QDL_PAD_SD4_CMD__NAND_RE_B           0xb0b1
+                       MX6QDL_PAD_SD4_CLK__NAND_WE_B           0xb0b1
+                       MX6QDL_PAD_NANDF_D0__NAND_DATA00        0xb0b1
+                       MX6QDL_PAD_NANDF_D1__NAND_DATA01        0xb0b1
+                       MX6QDL_PAD_NANDF_D2__NAND_DATA02        0xb0b1
+                       MX6QDL_PAD_NANDF_D3__NAND_DATA03        0xb0b1
+                       MX6QDL_PAD_NANDF_D4__NAND_DATA04        0xb0b1
+                       MX6QDL_PAD_NANDF_D5__NAND_DATA05        0xb0b1
+                       MX6QDL_PAD_NANDF_D6__NAND_DATA06        0xb0b1
+                       MX6QDL_PAD_NANDF_D7__NAND_DATA07        0xb0b1
+               >;
+       };
+
+       pinctrl_hdmi_cec: hdmicecgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_A21__GPIO2_IO17          0x1b8b1
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL3__I2C2_SCL           0x4001b8b1
+                       MX6QDL_PAD_KEY_ROW3__I2C2_SDA           0x4001b8b1
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_5__I2C3_SCL             0x4001f8b1
+                       MX6QDL_PAD_GPIO_6__I2C3_SDA             0x4001f8b1
+               >;
+       };
+
+       pinctrl_i2c4: i2c4grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_7__I2C4_SCL             0x4001b8b1
+                       MX6QDL_PAD_GPIO_8__I2C4_SDA             0x4001b8b1
+               >;
+       };
+
+       pinctrl_pwm3: pwm3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_DAT1__PWM3_OUT           0x1b0b1
+               >;
+       };
+
+       pinctrl_reg_backlight: regbacklightgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_ENET_REF_CLK__GPIO1_IO23     0x1b0b1
+               >;
+       };
+
+       pinctrl_reg_usbotg_vbus: regusbotgvbusgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_ROW4__GPIO4_IO15         0x1b0b1
+               >;
+       };
+
+       pinctrl_touch: touchgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_2__GPIO1_IO02           0x1b0b0
+                       MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18      0x1b0b0
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA      0x1b0b1
+                       MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA      0x1b0b1
+               >;
+       };
+
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA      0x1b0b1
+                       MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA      0x1b0b1
+               >;
+       };
+
+       pinctrl_uart3: uart3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D24__UART3_TX_DATA       0x1b0b0
+                       MX6QDL_PAD_EIM_D25__UART3_RX_DATA       0x1b0b0
+               >;
+       };
+
+       pinctrl_usbh1: usbh1grp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_3__USB_H1_OC            0x1b0b1
+                       MX6QDL_PAD_CSI0_MCLK__CCM_CLKO1         0x1b0b0
+               >;
+       };
+
+       pinctrl_usbotg: usbotggrp {
+               fsl,pins = <
+                       MX6QDL_PAD_KEY_COL4__USB_OTG_OC         0x1b0b1
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD3_CMD__SD3_CMD             0x17059
+                       MX6QDL_PAD_SD3_CLK__SD3_CLK             0x10059
+                       MX6QDL_PAD_SD3_DAT0__SD3_DATA0          0x17059
+                       MX6QDL_PAD_SD3_DAT1__SD3_DATA1          0x17059
+                       MX6QDL_PAD_SD3_DAT2__SD3_DATA2          0x17059
+                       MX6QDL_PAD_SD3_DAT3__SD3_DATA3          0x17059
+                       MX6QDL_PAD_GPIO_4__GPIO1_IO04           0x100b1
+               >;
+       };
+
+       pinctrl_wdog: wdoggrp {
+               fsl,pins = <
+                       MX6QDL_PAD_GPIO_9__WDOG1_B              0x1b0b0
+               >;
+       };
+};
index 3be38a3c4bb11c1eaa458ef30f033ef1cd67a529..c32ea040fecdda4a78dd13795c0a3186620ea1f5 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
-               phy_port2: phy@1 {
-                       reg = <1>;
-               };
-
-               phy_port3: phy@2 {
-                       reg = <2>;
-               };
-
                switch@10 {
                        compatible = "qca,qca8334";
-                       reg = <10>;
+                       reg = <0x10>;
                        reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
 
                        switch_ports: ports {
                                eth2: port@2 {
                                        reg = <2>;
                                        label = "eth2";
+                                       phy-mode = "internal";
                                        phy-handle = <&phy_port2>;
                                };
 
                                eth1: port@3 {
                                        reg = <3>;
                                        label = "eth1";
+                                       phy-mode = "internal";
                                        phy-handle = <&phy_port3>;
                                };
                        };
+
+                       mdio {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               phy_port2: ethernet-phy@1 {
+                                       reg = <1>;
+                               };
+
+                               phy_port3: ethernet-phy@2 {
+                                       reg = <2>;
+                               };
+                       };
                };
        };
 };
diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-apalis-eval-v1.2.dts b/arch/arm/boot/dts/nxp/imx/imx6q-apalis-eval-v1.2.dts
new file mode 100644 (file)
index 0000000..15d4a98
--- /dev/null
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2024 Toradex
+ */
+
+/dts-v1/;
+
+#include "imx6q-apalis-eval.dtsi"
+
+/ {
+       model = "Toradex Apalis iMX6Q/D Module on Apalis Evaluation Board v1.2";
+       compatible = "toradex,apalis_imx6q-eval-v1.2", "toradex,apalis_imx6q",
+                    "fsl,imx6q";
+
+       reg_3v3_mmc: regulator-3v3-mmc {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio2 0 GPIO_ACTIVE_HIGH>;
+               off-on-delay-us = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_enable_3v3_mmc>;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "3.3V_MMC";
+               startup-delay-us = <10000>;
+       };
+
+       reg_3v3_sd: regulator-3v3-sd {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio2 1 GPIO_ACTIVE_HIGH>;
+               off-on-delay-us = <100000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_enable_3v3_sd>;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "3.3V_SD";
+               startup-delay-us = <10000>;
+       };
+
+       reg_can1: regulator-can1 {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio2 3 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_enable_can1_power>;
+               regulator-name = "5V_SW_CAN1";
+               startup-delay-us = <10000>;
+       };
+
+       reg_can2: regulator-can2 {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_enable_can2_power>;
+               regulator-name = "5V_SW_CAN2";
+               startup-delay-us = <10000>;
+       };
+
+       sound-carrier {
+               compatible = "simple-audio-card";
+               simple-audio-card,bitclock-master = <&codec_dai>;
+               simple-audio-card,format = "i2s";
+               simple-audio-card,frame-master = <&codec_dai>;
+               simple-audio-card,name = "apalis-nau8822";
+               simple-audio-card,routing =
+                       "Headphones", "LHP",
+                       "Headphones", "RHP",
+                       "Speaker", "LSPK",
+                       "Speaker", "RSPK",
+                       "Line Out", "AUXOUT1",
+                       "Line Out", "AUXOUT2",
+                       "LAUX", "Line In",
+                       "RAUX", "Line In",
+                       "LMICP", "Mic In",
+                       "RMICP", "Mic In";
+               simple-audio-card,widgets =
+                       "Headphones", "Headphones",
+                       "Line Out", "Line Out",
+                       "Speaker", "Speaker",
+                       "Microphone", "Mic In",
+                       "Line", "Line In";
+
+               codec_dai: simple-audio-card,codec {
+                       sound-dai = <&nau8822_1a>;
+                       system-clock-frequency = <12288000>;
+               };
+
+               simple-audio-card,cpu {
+                       sound-dai = <&ssi2>;
+               };
+       };
+};
+
+&can1 {
+       xceiver-supply = <&reg_can1>;
+       status = "okay";
+};
+
+&can2 {
+       xceiver-supply = <&reg_can2>;
+       status = "okay";
+};
+
+/* I2C1_SDA/SCL on MXM3 209/211 */
+&i2c1 {
+       /* Audio Codec */
+       nau8822_1a: audio-codec@1a {
+               compatible = "nuvoton,nau8822";
+               reg = <0x1a>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_nau8822>;
+               #sound-dai-cells = <0>;
+       };
+
+       /* Current measurement into module VCC */
+       hwmon@40 {
+               compatible = "ti,ina219";
+               reg = <0x40>;
+               shunt-resistor = <5000>;
+       };
+
+       /* Temperature Sensor */
+       temperature-sensor@4f {
+               compatible = "ti,tmp75c";
+               reg = <0x4f>;
+       };
+
+       /* EEPROM */
+       eeprom@57 {
+               compatible = "st,24c02", "atmel,24c02";
+               reg = <0x57>;
+               pagesize = <16>;
+               size = <256>;
+       };
+};
+
+&pcie {
+       status = "okay";
+};
+
+&ssi2 {
+       status = "okay";
+};
+
+/* MMC1 */
+&usdhc1 {
+       bus-width = <4>;
+       pinctrl-0 = <&pinctrl_usdhc1_4bit &pinctrl_mmc_cd>;
+       vmmc-supply = <&reg_3v3_mmc>;
+       status = "okay";
+};
+
+/* SD1 */
+&usdhc2 {
+       cd-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>;
+       pinctrl-0 = <&pinctrl_usdhc2 &pinctrl_sd_cd>;
+       vmmc-supply = <&reg_3v3_sd>;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_enable_3v3_mmc: enable3v3mmcgrp {
+               fsl,pins = <
+                       /* MMC1_PWR_CTRL */
+                       MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0
+               >;
+       };
+
+       pinctrl_enable_3v3_sd: enable3v3sdgrp {
+               fsl,pins = <
+                       /* SD1_PWR_CTRL */
+                       MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0
+               >;
+       };
+
+       pinctrl_enable_can1_power: enablecan1powergrp {
+               fsl,pins = <
+                       /* CAN1_PWR_EN */
+                       MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0
+               >;
+       };
+
+       pinctrl_enable_can2_power: enablecan2powergrp {
+               fsl,pins = <
+                       /* CAN2_PWR_EN */
+                       MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0
+               >;
+       };
+
+       pinctrl_nau8822: nau8822grp {
+               fsl,pins = <
+                       MX6QDL_PAD_DISP0_DAT16__AUD5_TXC        0x130b0
+                       MX6QDL_PAD_DISP0_DAT17__AUD5_TXD        0x130b0
+                       MX6QDL_PAD_DISP0_DAT18__AUD5_TXFS       0x130b0
+                       MX6QDL_PAD_DISP0_DAT19__AUD5_RXD        0x130b0
+               >;
+       };
+};
index 3fc079dfd61eed40ed9d13b8e13e922ffcf04ae0..e1077e2da5f42652f5ec07c29174f34e21fd7231 100644 (file)
@@ -7,29 +7,13 @@
 
 /dts-v1/;
 
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/interrupt-controller/irq.h>
-#include "imx6q.dtsi"
-#include "imx6qdl-apalis.dtsi"
+#include "imx6q-apalis-eval.dtsi"
 
 / {
        model = "Toradex Apalis iMX6Q/D Module on Apalis Evaluation Board";
        compatible = "toradex,apalis_imx6q-eval", "toradex,apalis_imx6q",
                     "fsl,imx6q";
 
-       aliases {
-               i2c0 = &i2c1;
-               i2c1 = &i2c3;
-               i2c2 = &i2c2;
-               rtc0 = &rtc_i2c;
-               rtc1 = &snvs_rtc;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-       };
-
        reg_pcie_switch: regulator-pcie-switch {
                compatible = "regulator-fixed";
                enable-active-high;
                startup-delay-us = <100000>;
                status = "okay";
        };
-
-       reg_3v3_sw: regulator-3v3-sw {
-               compatible = "regulator-fixed";
-               regulator-always-on;
-               regulator-max-microvolt = <3300000>;
-               regulator-min-microvolt = <3300000>;
-               regulator-name = "3.3V_SW";
-       };
 };
 
 &can1 {
 
 /* I2C1_SDA/SCL on MXM3 209/211 (e.g. RTC on carrier board) */
 &i2c1 {
-       status = "okay";
-
+       /* PCIe Switch */
        pcie-switch@58 {
                compatible = "plx,pex8605";
                reg = <0x58>;
        };
-
-       /* M41T0M6 real time clock on carrier board */
-       rtc_i2c: rtc@68 {
-               compatible = "st,m41t0";
-               reg = <0x68>;
-       };
-};
-
-/*
- * I2C3_SDA/SCL (CAM) on MXM3 pin 201/203 (e.g. camera sensor on carrier
- * board)
- */
-&i2c3 {
-       status = "okay";
 };
 
 &pcie {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_reset_moci>;
-       /* active-high meaning opposite of regular PERST# active-low polarity */
-       reset-gpio = <&gpio1 28 GPIO_ACTIVE_HIGH>;
-       reset-gpio-active-high;
        vpcie-supply = <&reg_pcie_switch>;
        status = "okay";
 };
 
-&pwm1 {
-       status = "okay";
-};
-
-&pwm2 {
-       status = "okay";
-};
-
-&pwm3 {
-       status = "okay";
-};
-
-&pwm4 {
-       status = "okay";
-};
-
-&reg_usb_host_vbus {
-       status = "okay";
-};
-
-&reg_usb_otg_vbus {
-       status = "okay";
-};
-
-&sata {
-       status = "okay";
-};
-
 &sound_spdif {
        status = "okay";
 };
 
-&spdif {
-       status = "okay";
-};
-
-&uart1 {
-       status = "okay";
-};
-
-&uart2 {
-       status = "okay";
-};
-
-&uart4 {
-       status = "okay";
-};
-
-&uart5 {
-       status = "okay";
-};
-
-&usbh1 {
-       disable-over-current;
-       vbus-supply = <&reg_usb_host_vbus>;
-       status = "okay";
-};
-
-&usbotg {
-       disable-over-current;
-       vbus-supply = <&reg_usb_otg_vbus>;
-       status = "okay";
-};
-
 /* MMC1 */
 &usdhc1 {
        status = "okay";
diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-apalis-eval.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-apalis-eval.dtsi
new file mode 100644 (file)
index 0000000..b6c45ad
--- /dev/null
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2014-2024 Toradex
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "imx6q.dtsi"
+#include "imx6qdl-apalis.dtsi"
+
+/ {
+       aliases {
+               i2c0 = &i2c1;
+               i2c1 = &i2c3;
+               i2c2 = &i2c2;
+               rtc0 = &rtc_i2c;
+               rtc1 = &snvs_rtc;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       reg_3v3_sw: regulator-3v3-sw {
+               compatible = "regulator-fixed";
+               regulator-always-on;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "3.3V_SW";
+       };
+};
+
+&i2c1 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "okay";
+
+       /* M41T0M6 real time clock on carrier board */
+       rtc_i2c: rtc@68 {
+               compatible = "st,m41t0";
+               reg = <0x68>;
+       };
+};
+
+/*
+ * I2C3_SDA/SCL (CAM) on MXM3 pin 201/203 (e.g. camera sensor on carrier
+ * board)
+ */
+&i2c3 {
+       status = "okay";
+};
+
+&pcie {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_reset_moci>;
+       /* active-high meaning opposite of regular PERST# active-low polarity */
+       reset-gpio = <&gpio1 28 GPIO_ACTIVE_HIGH>;
+       reset-gpio-active-high;
+};
+
+&pwm1 {
+       status = "okay";
+};
+
+&pwm2 {
+       status = "okay";
+};
+
+&pwm3 {
+       status = "okay";
+};
+
+&pwm4 {
+       status = "okay";
+};
+
+&reg_usb_host_vbus {
+       status = "okay";
+};
+
+&reg_usb_otg_vbus {
+       status = "okay";
+};
+
+&sata {
+       status = "okay";
+};
+
+&spdif {
+       status = "okay";
+};
+
+&uart1 {
+       status = "okay";
+};
+
+&uart2 {
+       status = "okay";
+};
+
+&uart4 {
+       status = "okay";
+};
+
+&uart5 {
+       status = "okay";
+};
+
+&usbh1 {
+       disable-over-current;
+       vbus-supply = <&reg_usb_host_vbus>;
+       status = "okay";
+};
+
+&usbotg {
+       disable-over-current;
+       vbus-supply = <&reg_usb_otg_vbus>;
+       status = "okay";
+};
index db8c332df6a1d53f1b3eff6572a9f080ac10fe0a..cad112e054758f7ce364f2346eb4e1e291086a61 100644 (file)
 
                #address-cells = <3>;
                #size-cells = <2>;
-               #interrupt-cells = <1>;
 
                bridge@2,1 {
                        compatible = "pci10b5,8605";
 
                        #address-cells = <3>;
                        #size-cells = <2>;
-                       #interrupt-cells = <1>;
 
                        /* Intel Corporation I210 Gigabit Network Connection */
                        ethernet@3,0 {
 
                        #address-cells = <3>;
                        #size-cells = <2>;
-                       #interrupt-cells = <1>;
 
                        /* Intel Corporation I210 Gigabit Network Connection */
                        switch_nic: ethernet@4,0 {
index 99f4f6ac71d4a18f6f6eb2f0476c47280ba844b7..c1ae7c47b44227c2438d4e7c73fbafd6eaa269b9 100644 (file)
                                reg = <0x74>;
                                gpio-controller;
                                #gpio-cells = <2>;
+                               #interrupt-cells = <2>;
                                interrupt-controller;
                                interrupt-parent = <&gpio2>;
                                interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
 
                #address-cells = <3>;
                #size-cells = <2>;
-               #interrupt-cells = <1>;
        };
 };
 
index 2ae93f57fe5acac1f3f437b082e258ed81a391e0..ea40623d12e5fddc11b2af150ca6a80af93510a3 100644 (file)
                blocks = <0x5>;
                id = <0>;
                interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
-               interrupt-controller;
                interrupt-parent = <&gpio4>;
                irq-trigger = <0x1>;
                pinctrl-names = "default";
index 55c90f6393ad5e1176b5f8af6ca94bcf9c368477..d3a7a6eeb8e09edff6963de86527e13899e3c956 100644 (file)
                blocks = <0x5>;
                interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
                interrupt-parent = <&gpio6>;
-               interrupt-controller;
                id = <0>;
                irq-trigger = <0x1>;
                pinctrl-names = "default";
index a63e73adc1fc532175d8cd1baca8ede060f4d2f8..42b2ba23aefc9e26ddb3a8e0317013e30602fdbe 100644 (file)
                pinctrl-0 = <&pinctrl_pmic>;
                interrupt-parent = <&gpio2>;
                interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
-               interrupt-controller;
 
                onkey {
                        compatible = "dlg,da9063-onkey";
index bfade71490807a955882d8c35dc5bffbbdee8086..a955c77cd4998a56d6ee5e94eb0de7835b974291 100644 (file)
 #include <dt-bindings/sound/fsl-imx-audmux.h>
 
 / {
+       aliases {
+               rtc0 = &carrier_rtc;
+               rtc1 = &snvs_rtc;
+       };
+
        /* Will be filled by the bootloader */
        memory@10000000 {
                device_type = "memory";
        status = "okay";
 
        /* Pro baseboard model */
-       rtc@68 {
+       carrier_rtc: rtc@68 {
                compatible = "nxp,pcf8523";
                reg = <0x68>;
        };
index 0883ef99cded09b219ae81cbb0b68eb97e48df8c..e6017f9bf6409bd646559b424b79af5ffe01f4e5 100644 (file)
 #include <dt-bindings/sound/fsl-imx-audmux.h>
 
 / {
+       aliases {
+               rtc0 = &pcf8523;
+               rtc1 = &snvs_rtc;
+       };
+
        /* Will be filled by the bootloader */
        memory@10000000 {
                device_type = "memory";
index 113974520d544b72ff3397629935037c1d1cae53..c0c47adc5866e3ea157b499f15d8edf8b2d1fcde 100644 (file)
                reg = <0x58>;
                interrupt-parent = <&gpio2>;
                interrupts = <9 IRQ_TYPE_LEVEL_LOW>; /* active-low GPIO2_9 */
+               #interrupt-cells = <2>;
                interrupt-controller;
 
                regulators {
index 86b4269e0e0117b3906b625537444533c28510fb..85e278eb201610a1c851c4093025bb205e02a3b3 100644 (file)
                interrupt-parent = <&gpio1>;
                interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
                interrupt-controller;
+               #interrupt-cells = <2>;
                gpio-controller;
                #gpio-cells = <2>;
 
index 2731faede1cb4dce10cf11f7f141b58b3df69e96..d59d5d0e1d19ea6aff4c54ff26178140ff7dbc51 100644 (file)
        aliases {
                can0 = &can1;
                can1 = &can2;
+               ethernet0 = &fec;
+               ethernet1 = &lan1;
+               ethernet2 = &lan2;
                mdio-gpio0 = &mdio;
                nand = &gpmi;
                rtc0 = &i2c_rtc;
                rtc1 = &snvs;
+               switch0 = &switch;
                usb0 = &usbh1;
                usb1 = &usbotg;
        };
@@ -60,7 +64,7 @@
                gpios = <&gpio1 31 GPIO_ACTIVE_HIGH>,
                        <&gpio1 22 GPIO_ACTIVE_HIGH>;
 
-               switch@0 {
+               switch: switch@0 {
                        compatible = "microchip,ksz8873";
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_switch>;
                                #address-cells = <1>;
                                #size-cells = <0>;
 
-                               ports@0 {
+                               lan1: ports@0 {
                                        reg = <0>;
                                        phy-mode = "internal";
                                        label = "lan1";
                                };
 
-                               ports@1 {
+                               lan2: ports@1 {
                                        reg = <1>;
                                        phy-mode = "internal";
                                        label = "lan2";
index 81142c523fa8c399096af322674de1e9b7c5bfd5..8431b8a994f4c19a2e696019ab4dfaab62af5676 100644 (file)
                                status = "disabled";
                        };
 
-                       weim: weim@21b8000 {
+                       weim: memory-controller@21b8000 {
                                #address-cells = <2>;
                                #size-cells = <1>;
                                compatible = "fsl,imx6q-weim";
index 815119c12bd48286df5bf2f0d936508d994c08a1..5636fb3661e8a4e345e74767e329e403d2a58c9e 100644 (file)
                interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
                vdd-supply = <&ldo1_reg>;
                reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
-               x-size = <1072>;
-               y-size = <1448>;
+               touchscreen-size-x = <1072>;
+               touchscreen-size-y = <1448>;
+               touchscreen-swapped-x-y;
+               touchscreen-inverted-x;
        };
 
        /* TODO: TPS65185 PMIC for E Ink at 0x68 */
index 28111efb19a6634a638ef5ff0cbf4e5dcc2d312e..6aa61235e39e8eff3807b7bcb9a3e16537f7a5f5 100644 (file)
                                clocks = <&clks IMX6SL_CLK_DUMMY>;
                        };
 
-                       weim: weim@21b8000 {
+                       weim: memory-controller@21b8000 {
                                #address-cells = <2>;
                                #size-cells = <1>;
                                reg = <0x021b8000 0x4000>;
index df3a375f0a3e85e007fe86f0c8d2a980770cda61..0de359d62a472f9942ffb1de8c844400dbd035ba 100644 (file)
                                status = "disabled";
                        };
 
-                       weim: weim@21b8000 {
+                       weim: memory-controller@21b8000 {
                                #address-cells = <2>;
                                #size-cells = <1>;
                                compatible = "fsl,imx6sx-weim", "fsl,imx6q-weim";
index 2ac40d69425b3cdf78d3c686643b3e9e0987bbdf..f10f0525490b66f413c9fa9a41d08f8a82ae35f2 100644 (file)
 &tsc {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_tsc>;
-       xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
+       xnur-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
        measure-delay-time = <0xffff>;
        pre-charge-time = <0xfff>;
        status = "okay";
index 875ae699c5cb80d7c5cc683e701d9338ab75ddc5..2ca18f3dad0aa6576398235398047753a79b285b 100644 (file)
 &tsc {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_tsc>;
-       xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
+       xnur-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
 };
 
 &sai2 {
index 18cac19aa9b0f8e00a497da6bf9752e1b4807a09..af337f18a266ca846be7ae3652a40ff69f507809 100644 (file)
 &tsc {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_tsc>;
-       xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
+       xnur-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
        measure-delay-time = <0xffff>;
        pre-charge-time = <0xffff>;
        status = "okay";
index a27a7554c2e7fdaaeadb52b5d8530ff0ba87fd0b..235aa676618bb4c17e768ed44ca465bffef6e16b 100644 (file)
                                };
                        };
 
-                       tsc: tsc@2040000 {
+                       tsc: touchscreen@2040000 {
                                compatible = "fsl,imx6ul-tsc";
                                reg = <0x02040000 0x4000>, <0x0219c000 0x4000>;
                                interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
                                fsl,num-rx-queues = <1>;
                                fsl,stop-mode = <&gpr 0x10 4>;
                                fsl,magic-packet;
+                               nvmem-cells = <&fec2_mac_addr>;
+                               nvmem-cell-names = "mac-address";
                                status = "disabled";
                        };
 
                                        nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
                                        nvmem-cell-names = "calib", "temp_grade";
                                        clocks = <&clks IMX6UL_CLK_PLL3_USB_OTG>;
+                                       #thermal-sensor-cells = <0>;
                                };
                        };
 
                                clocks = <&clks IMX6UL_CLK_USBOH3>;
                                fsl,usbphy = <&usbphy1>;
                                fsl,usbmisc = <&usbmisc 0>;
-                               fsl,anatop = <&anatop>;
                                ahb-burst-config = <0x0>;
                                tx-burst-size-dword = <0x10>;
                                rx-burst-size-dword = <0x10>;
                                fsl,num-rx-queues = <1>;
                                fsl,stop-mode = <&gpr 0x10 3>;
                                fsl,magic-packet;
+                               nvmem-cells = <&fec1_mac_addr>;
+                               nvmem-cell-names = "mac-address";
                                status = "disabled";
                        };
 
                                clocks = <&clks IMX6UL_CLK_MMDC_P0_IPG>;
                        };
 
-                       weim: weim@21b8000 {
+                       weim: memory-controller@21b8000 {
                                #address-cells = <2>;
                                #size-cells = <1>;
                                compatible = "fsl,imx6ul-weim", "fsl,imx6q-weim";
                                cpu_speed_grade: speed-grade@10 {
                                        reg = <0x10 4>;
                                };
+
+                               fec1_mac_addr: mac-addr@88 {
+                                       reg = <0x88 6>;
+                               };
+
+                               fec2_mac_addr: mac-addr@8e {
+                                       reg = <0x8e 6>;
+                               };
                        };
 
                        csi: csi@21c4000 {
index 040421f9c9700d66a9c94d906bbc95836ab38289..5e39f8dc1351fb027814ee1dad3bbdc3b391abee 100644 (file)
  */
 
 /*
- * To use usdhc1 as SD card, the WiFi node must be deleted.
+ * To use usdhc1 as SD card, the WiFi node must be deleted. The associated
+ * pwrseq node is also deleted in order to ensure that GPIO H is released.
  * BT is also not available, so remove BT from the UART node.
  */
 /delete-node/ &brcmf;
+/delete-node/ &usdhc1_pwrseq;
 /delete-node/ &bluetooth;
 
 / {
index 830b5a5064f28b45e7f387fbe2d506540bedafa8..a74f5273f9b3a37faa6bdca000056b74d5647b39 100644 (file)
@@ -52,7 +52,7 @@
        };
 
        /* SoM with WiFi/BT: WiFi pin WL_REG_ON is connected to a DHCOM GPIO */
-       /omit-if-no-ref/ usdhc1_pwrseq: usdhc1-pwrseq {
+       usdhc1_pwrseq: usdhc1-pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; /* GPIO H */
        };
        pinctrl-names = "default";
        pre-charge-time = <0xfff>;
        touchscreen-average-samples = <32>;
-       xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
+       xnur-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
 };
 
 /* DHCOM UART1 */
index 45315adfaa86ffad824e3693a1308e689057e5ae..75486e1b0c15f53ff10449603f15f128c775a8b6 100644 (file)
        /*
         * Due to the design as a solderable SOM, there are no capacitors
         * below the SoC, therefore higher voltages are required.
+        * Due to CPU lifetime consideration of the SoC manufacturer and
+        * the preferred area of operation in the industrial related
+        * environment, set the maximum frequency for each DHCOM i.MX6ULL
+        * to 792MHz, as with the industrial type.
         */
+       clock-frequency = <792000000>;
        operating-points = <
                /* kHz  uV */
-               900000  1275000
                792000  1250000 /* Voltage increased */
                528000  1175000
                396000  1025000
@@ -39,7 +43,6 @@
        >;
        fsl,soc-operating-points = <
                /* KHz  uV */
-               900000  1250000
                792000  1250000 /* Voltage increased */
                528000  1175000
                396000  1175000
index 2bccd45e9fc22d47267e93f8b37c825dfb37b589..8a1776067ecc35a166d2a690b62987615ffeaa4f 100644 (file)
@@ -75,7 +75,7 @@
                                clocks = <&clks IMX6UL_CLK_DUMMY>;
                        };
 
-                       iomuxc_snvs: iomuxc-snvs@2290000 {
+                       iomuxc_snvs: pinctrl@2290000 {
                                compatible = "fsl,imx6ull-iomuxc-snvs";
                                reg = <0x02290000 0x4000>;
                        };
index 3df6dff7734ae4d0d5766f155411e825f72f0e11..1235a71c6abe96564059010e214f87304d7d4e8c 100644 (file)
@@ -18,6 +18,8 @@
                mmc0 = &usdhc3;
                mmc1 = &usdhc1;
                /delete-property/ mmc2;
+               rtc0 = &ds1339;
+               rtc1 = &snvs_rtc;
        };
 
        beeper {
        gpio_buttons: gpio-keys {
                compatible = "gpio-keys";
 
+               /*
+                * NOTE: These buttons are attached to a GPIO-expander.
+                * Enabling wakeup-source, enables wakeup on all inputs.
+                * If PE_GPIO[3..6] are used as inputs, they cause a
+                * wakeup as well.
+                */
                button-0 {
                        /* #SWITCH_A */
                        label = "S11";
                        linux,code = <KEY_1>;
                        gpios = <&pca9555 13 GPIO_ACTIVE_LOW>;
+                       wakeup-source;
                };
 
                button-1 {
@@ -44,6 +53,7 @@
                        label = "S12";
                        linux,code = <KEY_2>;
                        gpios = <&pca9555 14 GPIO_ACTIVE_LOW>;
+                       wakeup-source;
                };
 
                button-2 {
@@ -51,6 +61,7 @@
                        label = "S13";
                        linux,code = <KEY_3>;
                        gpios = <&pca9555 15 GPIO_ACTIVE_LOW>;
+                       wakeup-source;
                };
        };
 
                regulator-always-on;
        };
 
+       reg_vcc_3v3: regulator-vcc-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
        sound {
                compatible = "fsl,imx-audio-tlv320aic32x4";
                model = "imx-audio-tlv320aic32x4";
 
 &ecspi1 {
        pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_ecspi1>;
+       pinctrl-0 = <&pinctrl_ecspi1>, <&pinctrl_ecspi1_ss0>;
        cs-gpios = <&gpio4 0 GPIO_ACTIVE_LOW>, <&gpio4 1 GPIO_ACTIVE_LOW>,
-                  <&gpio4 2 GPIO_ACTIVE_LOW>;
+                  <&gpio4 2 GPIO_ACTIVE_LOW>, <&gpio4 19 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet1>;
        phy-mode = "rgmii-id";
-       phy-reset-gpios = <&gpio7 15 GPIO_ACTIVE_LOW>;
-       phy-reset-duration = <1>;
        phy-supply = <&reg_fec1_pwdn>;
        phy-handle = <&ethphy1_0>;
        fsl,magic-packet;
                ethphy1_0: ethernet-phy@0 {
                        compatible = "ethernet-phy-ieee802.3-c22";
                        reg = <0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_enet1_phy>;
                        ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_50_NS>;
                        ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_50_NS>;
                        ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
                        ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
+                       reset-gpios = <&gpio7 15 GPIO_ACTIVE_LOW>;
+                       reset-assert-us = <1000>;
+                       reset-deassert-us = <500>;
                };
        };
 };
        lm75: temperature-sensor@49 {
                compatible = "national,lm75";
                reg = <0x49>;
+               vs-supply = <&reg_vcc_3v3>;
        };
 };
 
 &i2c2 {
        clock-frequency = <100000>;
-       pinctrl-names = "default";
+       pinctrl-names = "default", "gpio";
        pinctrl-0 = <&pinctrl_i2c2>;
+       pinctrl-1 = <&pinctrl_i2c2_recovery>;
+       scl-gpios = <&gpio4 10 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio4 11 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        status = "okay";
 
        tlv320aic32x4: audio-codec@18 {
                interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
                interrupt-controller;
                #interrupt-cells = <2>;
+               vcc-supply = <&reg_vcc_3v3>;
        };
 };
 
 &i2c3 {
        clock-frequency = <100000>;
-       pinctrl-names = "default";
+       pinctrl-names = "default", "gpio";
        pinctrl-0 = <&pinctrl_i2c3>;
+       pinctrl-1 = <&pinctrl_i2c3_recovery>;
+       scl-gpios = <&gpio4 12 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio4 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        status = "okay";
 };
 
        pinctrl-0 = <&pinctrl_hog_mba7_1>;
 
        pinctrl_ecspi1: ecspi1grp {
+               fsl,pins =
+                       <MX7D_PAD_ECSPI1_MISO__ECSPI1_MISO              0x7c>,
+                       <MX7D_PAD_ECSPI1_MOSI__ECSPI1_MOSI              0x74>,
+                       <MX7D_PAD_ECSPI1_SCLK__ECSPI1_SCLK              0x74>,
+                       <MX7D_PAD_UART1_RX_DATA__GPIO4_IO0              0x74>,
+                       <MX7D_PAD_UART1_TX_DATA__GPIO4_IO1              0x74>,
+                       <MX7D_PAD_UART2_RX_DATA__GPIO4_IO2              0x74>;
+       };
+
+       pinctrl_ecspi1_ss0: ecspi1ss0grp {
                fsl,pins = <
-                       MX7D_PAD_ECSPI1_MISO__ECSPI1_MISO               0x7c
-                       MX7D_PAD_ECSPI1_MOSI__ECSPI1_MOSI               0x74
-                       MX7D_PAD_ECSPI1_SCLK__ECSPI1_SCLK               0x74
-                       MX7D_PAD_UART1_RX_DATA__GPIO4_IO0               0x74
-                       MX7D_PAD_UART1_TX_DATA__GPIO4_IO1               0x74
-                       MX7D_PAD_UART2_RX_DATA__GPIO4_IO2               0x74
+                       MX7D_PAD_ECSPI1_SS0__GPIO4_IO19                 0x74
                >;
        };
 
        pinctrl_ecspi2: ecspi2grp {
-               fsl,pins = <
-                       MX7D_PAD_ECSPI2_MISO__ECSPI2_MISO               0x7c
-                       MX7D_PAD_ECSPI2_MOSI__ECSPI2_MOSI               0x74
-                       MX7D_PAD_ECSPI2_SCLK__ECSPI2_SCLK               0x74
-                       MX7D_PAD_ECSPI2_SS0__ECSPI2_SS0                 0x74
-               >;
+               fsl,pins =
+                       <MX7D_PAD_ECSPI2_MISO__ECSPI2_MISO              0x7c>,
+                       <MX7D_PAD_ECSPI2_MOSI__ECSPI2_MOSI              0x74>,
+                       <MX7D_PAD_ECSPI2_SCLK__ECSPI2_SCLK              0x74>,
+                       <MX7D_PAD_ECSPI2_SS0__ECSPI2_SS0                0x74>;
        };
 
        pinctrl_enet1: enet1grp {
-               fsl,pins = <
-                       MX7D_PAD_GPIO1_IO10__ENET1_MDIO                 0x02
-                       MX7D_PAD_GPIO1_IO11__ENET1_MDC                  0x00
-                       MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC       0x71
-                       MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0       0x71
-                       MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1       0x71
-                       MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2       0x71
-                       MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3       0x71
-                       MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x71
-                       MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC       0x79
-                       MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0       0x79
-                       MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1       0x79
-                       MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2       0x79
-                       MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3       0x79
-                       MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x79
+               fsl,pins =
+                       <MX7D_PAD_GPIO1_IO10__ENET1_MDIO                        0x02>,
+                       <MX7D_PAD_GPIO1_IO11__ENET1_MDC                         0x00>,
+                       <MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC              0x71>,
+                       <MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0              0x71>,
+                       <MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1              0x71>,
+                       <MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2              0x71>,
+                       <MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3              0x71>,
+                       <MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL        0x71>,
+                       <MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC              0x79>,
+                       <MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0              0x79>,
+                       <MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1              0x79>,
+                       <MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2              0x79>,
+                       <MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3              0x79>,
+                       <MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL        0x79>;
+       };
+
+       pinctrl_enet1_phy: enet1phygrp {
+               fsl,pins =
                        /* Reset: SION, 100kPU, SRE_FAST, DSE_X1 */
-                       MX7D_PAD_ENET1_COL__GPIO7_IO15          0x40000070
+                       <MX7D_PAD_ENET1_COL__GPIO7_IO15                         0x40000070>,
                        /* INT/PWDN: SION, 100kPU, HYS, SRE_FAST, DSE_X1 */
-                       MX7D_PAD_GPIO1_IO09__GPIO1_IO9          0x40000078
-               >;
+                       <MX7D_PAD_GPIO1_IO09__GPIO1_IO9                         0x40000078>;
        };
 
        pinctrl_flexcan1: flexcan1grp {
-               fsl,pins = <
-                       MX7D_PAD_GPIO1_IO12__FLEXCAN1_RX        0x5a
-                       MX7D_PAD_GPIO1_IO13__FLEXCAN1_TX        0x52
-               >;
+               fsl,pins =
+                       <MX7D_PAD_GPIO1_IO12__FLEXCAN1_RX       0x5a>,
+                       <MX7D_PAD_GPIO1_IO13__FLEXCAN1_TX       0x52>;
        };
 
        pinctrl_flexcan2: flexcan2grp {
-               fsl,pins = <
-                       MX7D_PAD_GPIO1_IO14__FLEXCAN2_RX        0x5a
-                       MX7D_PAD_GPIO1_IO15__FLEXCAN2_TX        0x52
-               >;
+               fsl,pins =
+                       <MX7D_PAD_GPIO1_IO14__FLEXCAN2_RX       0x5a>,
+                       <MX7D_PAD_GPIO1_IO15__FLEXCAN2_TX       0x52>;
        };
 
        pinctrl_hog_mba7_1: hogmba71grp {
-               fsl,pins = <
+               fsl,pins =
                        /* Limitation: WDOG2_B / WDOG2_RESET not usable */
-                       MX7D_PAD_ENET1_RX_CLK__GPIO7_IO13       0x4000007c
-                       MX7D_PAD_ENET1_CRS__GPIO7_IO14          0x40000074
+                       <MX7D_PAD_ENET1_RX_CLK__GPIO7_IO13      0x4000007c>,
+                       <MX7D_PAD_ENET1_CRS__GPIO7_IO14         0x40000074>,
                        /* #BOOT_EN */
-                       MX7D_PAD_UART2_TX_DATA__GPIO4_IO3       0x40000010
-               >;
+                       <MX7D_PAD_UART2_TX_DATA__GPIO4_IO3      0x40000010>;
        };
 
        pinctrl_i2c2: i2c2grp {
-               fsl,pins = <
-                       MX7D_PAD_I2C2_SCL__I2C2_SCL             0x40000078
-                       MX7D_PAD_I2C2_SDA__I2C2_SDA             0x40000078
-               >;
+               fsl,pins =
+                       <MX7D_PAD_I2C2_SCL__I2C2_SCL            0x40000078>,
+                       <MX7D_PAD_I2C2_SDA__I2C2_SDA            0x40000078>;
+       };
+
+       pinctrl_i2c2_recovery: i2c2recoverygrp {
+               fsl,pins =
+                       <MX7D_PAD_I2C2_SCL__GPIO4_IO10          0x40000078>,
+                       <MX7D_PAD_I2C2_SDA__GPIO4_IO11          0x40000078>;
        };
 
        pinctrl_i2c3: i2c3grp {
-               fsl,pins = <
-                       MX7D_PAD_I2C3_SCL__I2C3_SCL             0x40000078
-                       MX7D_PAD_I2C3_SDA__I2C3_SDA             0x40000078
-               >;
+               fsl,pins =
+                       <MX7D_PAD_I2C3_SCL__I2C3_SCL            0x40000078>,
+                       <MX7D_PAD_I2C3_SDA__I2C3_SDA            0x40000078>;
+       };
+
+       pinctrl_i2c3_recovery: i2c3recoverygrp {
+               fsl,pins =
+                       <MX7D_PAD_I2C3_SCL__GPIO4_IO12          0x40000078>,
+                       <MX7D_PAD_I2C3_SDA__GPIO4_IO13          0x40000078>;
        };
 
        pinctrl_pca9555: pca95550grp {
-               fsl,pins = <
-                       MX7D_PAD_ENET1_TX_CLK__GPIO7_IO12       0x78
-               >;
+               fsl,pins =
+                       <MX7D_PAD_ENET1_TX_CLK__GPIO7_IO12      0x78>;
        };
 
        pinctrl_sai1: sai1grp {
-               fsl,pins = <
-                       MX7D_PAD_SAI1_MCLK__SAI1_MCLK           0x11
-                       MX7D_PAD_SAI1_RX_BCLK__SAI1_RX_BCLK     0x1c
-                       MX7D_PAD_SAI1_RX_DATA__SAI1_RX_DATA0    0x1c
-                       MX7D_PAD_SAI1_RX_SYNC__SAI2_RX_SYNC     0x1c
-
-                       MX7D_PAD_SAI1_TX_BCLK__SAI1_TX_BCLK     0x1c
-                       MX7D_PAD_SAI1_TX_DATA__SAI1_TX_DATA0    0x14
-                       MX7D_PAD_SAI1_TX_SYNC__SAI1_TX_SYNC     0x14
-               >;
+               fsl,pins =
+                       <MX7D_PAD_SAI1_MCLK__SAI1_MCLK          0x11>,
+                       <MX7D_PAD_SAI1_RX_BCLK__SAI1_RX_BCLK    0x1c>,
+                       <MX7D_PAD_SAI1_RX_DATA__SAI1_RX_DATA0   0x1c>,
+                       <MX7D_PAD_SAI1_RX_SYNC__SAI2_RX_SYNC    0x1c>,
+
+                       <MX7D_PAD_SAI1_TX_BCLK__SAI1_TX_BCLK    0x1c>,
+                       <MX7D_PAD_SAI1_TX_DATA__SAI1_TX_DATA0   0x14>,
+                       <MX7D_PAD_SAI1_TX_SYNC__SAI1_TX_SYNC    0x14>;
        };
 
        pinctrl_uart3: uart3grp {
-               fsl,pins = <
-                       MX7D_PAD_UART3_RX_DATA__UART3_DCE_RX    0x7e
-                       MX7D_PAD_UART3_TX_DATA__UART3_DCE_TX    0x76
-                       MX7D_PAD_UART3_CTS_B__UART3_DCE_CTS     0x76
-                       MX7D_PAD_UART3_RTS_B__UART3_DCE_RTS     0x7e
-               >;
+               fsl,pins =
+                       <MX7D_PAD_UART3_RX_DATA__UART3_DCE_RX   0x7e>,
+                       <MX7D_PAD_UART3_TX_DATA__UART3_DCE_TX   0x76>,
+                       <MX7D_PAD_UART3_CTS_B__UART3_DCE_CTS    0x76>,
+                       <MX7D_PAD_UART3_RTS_B__UART3_DCE_RTS    0x7e>;
        };
 
        pinctrl_uart4: uart4grp {
-               fsl,pins = <
-                       MX7D_PAD_SAI2_TX_SYNC__UART4_DCE_RX     0x7e
-                       MX7D_PAD_SAI2_TX_BCLK__UART4_DCE_TX     0x76
-                       MX7D_PAD_SAI2_RX_DATA__UART4_DCE_CTS    0x76
-                       MX7D_PAD_SAI2_TX_DATA__UART4_DCE_RTS    0x7e
-               >;
+               fsl,pins =
+                       <MX7D_PAD_SAI2_TX_SYNC__UART4_DCE_RX    0x7e>,
+                       <MX7D_PAD_SAI2_TX_BCLK__UART4_DCE_TX    0x76>,
+                       <MX7D_PAD_SAI2_RX_DATA__UART4_DCE_CTS   0x76>,
+                       <MX7D_PAD_SAI2_TX_DATA__UART4_DCE_RTS   0x7e>;
        };
 
        pinctrl_uart5: uart5grp {
-               fsl,pins = <
-                       MX7D_PAD_I2C4_SCL__UART5_DCE_RX         0x7e
-                       MX7D_PAD_I2C4_SDA__UART5_DCE_TX         0x76
-               >;
+               fsl,pins =
+                       <MX7D_PAD_I2C4_SCL__UART5_DCE_RX        0x7e>,
+                       <MX7D_PAD_I2C4_SDA__UART5_DCE_TX        0x76>;
        };
 
        pinctrl_uart6: uart6grp {
-               fsl,pins = <
-                       MX7D_PAD_EPDC_DATA08__UART6_DCE_RX      0x7d
-                       MX7D_PAD_EPDC_DATA09__UART6_DCE_TX      0x75
-                       MX7D_PAD_EPDC_DATA11__UART6_DCE_CTS     0x75
-                       MX7D_PAD_EPDC_DATA10__UART6_DCE_RTS     0x7d
-               >;
+               fsl,pins =
+                       <MX7D_PAD_EPDC_DATA08__UART6_DCE_RX     0x7d>,
+                       <MX7D_PAD_EPDC_DATA09__UART6_DCE_TX     0x75>,
+                       <MX7D_PAD_EPDC_DATA11__UART6_DCE_CTS    0x75>,
+                       <MX7D_PAD_EPDC_DATA10__UART6_DCE_RTS    0x7d>;
        };
 
        pinctrl_uart7: uart7grp {
-               fsl,pins = <
-                       MX7D_PAD_EPDC_DATA12__UART7_DCE_RX      0x7e
-                       MX7D_PAD_EPDC_DATA13__UART7_DCE_TX      0x76
-                       MX7D_PAD_EPDC_DATA15__UART7_DCE_CTS     0x76
+               fsl,pins =
+                       <MX7D_PAD_EPDC_DATA12__UART7_DCE_RX     0x7e>,
+                       <MX7D_PAD_EPDC_DATA13__UART7_DCE_TX     0x76>,
+                       <MX7D_PAD_EPDC_DATA15__UART7_DCE_CTS    0x76>,
                        /* Limitation: RTS is not connected */
-                       MX7D_PAD_EPDC_DATA14__UART7_DCE_RTS     0x7e
-               >;
+                       <MX7D_PAD_EPDC_DATA14__UART7_DCE_RTS    0x7e>;
        };
 
-       pinctrl_usdhc1_gpio: usdhc1grp_gpio {
-               fsl,pins = <
+       pinctrl_usdhc1_gpio: usdhc1_gpiogrp {
+               fsl,pins =
                        /* WP */
-                       MX7D_PAD_SD1_WP__GPIO5_IO1              0x7c
+                       <MX7D_PAD_SD1_WP__GPIO5_IO1             0x7c>,
                        /* CD */
-                       MX7D_PAD_SD1_CD_B__GPIO5_IO0            0x7c
+                       <MX7D_PAD_SD1_CD_B__GPIO5_IO0           0x7c>,
                        /* VSELECT */
-                       MX7D_PAD_GPIO1_IO08__SD1_VSELECT        0x59
-               >;
+                       <MX7D_PAD_GPIO1_IO08__SD1_VSELECT       0x59>;
        };
 
        pinctrl_usdhc1: usdhc1grp {
-               fsl,pins = <
-                       MX7D_PAD_SD1_CMD__SD1_CMD               0x5e
-                       MX7D_PAD_SD1_CLK__SD1_CLK               0x57
-                       MX7D_PAD_SD1_DATA0__SD1_DATA0           0x5e
-                       MX7D_PAD_SD1_DATA1__SD1_DATA1           0x5e
-                       MX7D_PAD_SD1_DATA2__SD1_DATA2           0x5e
-                       MX7D_PAD_SD1_DATA3__SD1_DATA3           0x5e
-               >;
-       };
-
-       pinctrl_usdhc1_100mhz: usdhc1grp_100mhz {
-               fsl,pins = <
-                       MX7D_PAD_SD1_CMD__SD1_CMD               0x5a
-                       MX7D_PAD_SD1_CLK__SD1_CLK               0x57
-                       MX7D_PAD_SD1_DATA0__SD1_DATA0           0x5a
-                       MX7D_PAD_SD1_DATA1__SD1_DATA1           0x5a
-                       MX7D_PAD_SD1_DATA2__SD1_DATA2           0x5a
-                       MX7D_PAD_SD1_DATA3__SD1_DATA3           0x5a
-               >;
-       };
-
-       pinctrl_usdhc1_200mhz: usdhc1grp_200mhz {
-               fsl,pins = <
-                       MX7D_PAD_SD1_CMD__SD1_CMD               0x5b
-                       MX7D_PAD_SD1_CLK__SD1_CLK               0x57
-                       MX7D_PAD_SD1_DATA0__SD1_DATA0           0x5b
-                       MX7D_PAD_SD1_DATA1__SD1_DATA1           0x5b
-                       MX7D_PAD_SD1_DATA2__SD1_DATA2           0x5b
-                       MX7D_PAD_SD1_DATA3__SD1_DATA3           0x5b
-               >;
+               fsl,pins =
+                       <MX7D_PAD_SD1_CMD__SD1_CMD              0x5e>,
+                       <MX7D_PAD_SD1_CLK__SD1_CLK              0x57>,
+                       <MX7D_PAD_SD1_DATA0__SD1_DATA0          0x5e>,
+                       <MX7D_PAD_SD1_DATA1__SD1_DATA1          0x5e>,
+                       <MX7D_PAD_SD1_DATA2__SD1_DATA2          0x5e>,
+                       <MX7D_PAD_SD1_DATA3__SD1_DATA3          0x5e>;
+       };
+
+       pinctrl_usdhc1_100mhz: usdhc1_100mhzgrp {
+               fsl,pins =
+                       <MX7D_PAD_SD1_CMD__SD1_CMD              0x5a>,
+                       <MX7D_PAD_SD1_CLK__SD1_CLK              0x57>,
+                       <MX7D_PAD_SD1_DATA0__SD1_DATA0          0x5a>,
+                       <MX7D_PAD_SD1_DATA1__SD1_DATA1          0x5a>,
+                       <MX7D_PAD_SD1_DATA2__SD1_DATA2          0x5a>,
+                       <MX7D_PAD_SD1_DATA3__SD1_DATA3          0x5a>;
+       };
+
+       pinctrl_usdhc1_200mhz: usdhc1_200mhzgrp {
+               fsl,pins =
+                       <MX7D_PAD_SD1_CMD__SD1_CMD              0x5b>,
+                       <MX7D_PAD_SD1_CLK__SD1_CLK              0x57>,
+                       <MX7D_PAD_SD1_DATA0__SD1_DATA0          0x5b>,
+                       <MX7D_PAD_SD1_DATA1__SD1_DATA1          0x5b>,
+                       <MX7D_PAD_SD1_DATA2__SD1_DATA2          0x5b>,
+                       <MX7D_PAD_SD1_DATA3__SD1_DATA3          0x5b>;
        };
 };
 
 &iomuxc_lpsr {
        pinctrl_pwm1: pwm1grp {
-               fsl,pins = <
+               fsl,pins =
                        /* LCD_CONTRAST */
-                       MX7D_PAD_LPSR_GPIO1_IO01__PWM1_OUT      0x50
-               >;
+                       <MX7D_PAD_LPSR_GPIO1_IO01__PWM1_OUT     0x50>;
        };
 
        pinctrl_usbotg1: usbotg1grp {
-               fsl,pins = <
-                       MX7D_PAD_LPSR_GPIO1_IO04__USB_OTG1_OC   0x5c
-                       MX7D_PAD_LPSR_GPIO1_IO05__GPIO1_IO5     0x59
-               >;
+               fsl,pins =
+                       <MX7D_PAD_LPSR_GPIO1_IO04__USB_OTG1_OC  0x5c>,
+                       <MX7D_PAD_LPSR_GPIO1_IO05__GPIO1_IO5    0x59>;
        };
 
        pinctrl_wdog1: wdog1grp {
-               fsl,pins = <
-                       MX7D_PAD_LPSR_GPIO1_IO00__WDOG1_WDOG_B  0x30
-               >;
+               fsl,pins =
+                       <MX7D_PAD_LPSR_GPIO1_IO00__WDOG1_WDOG_B 0x30>;
        };
 };
 
        status = "okay";
 };
 
+&snvs_pwrkey {
+       status = "okay";
+};
+
 &uart3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart3>;
 };
 
 &usbh {
+       disable-over-current;
        status = "okay";
 };
 
        vmmc-supply = <&reg_sd1_vmmc>;
        bus-width = <4>;
        no-1-8-v;
+       no-sdio;
+       no-emmc;
        status = "okay";
 };
 
index 3fc3130f9defe4da6905870081d3bc661334a463..028961eb71089c44da441392f06e8741114b89b0 100644 (file)
 };
 
 &i2c1 {
-       pinctrl-names = "default";
+       pinctrl-names = "default", "gpio";
        pinctrl-0 = <&pinctrl_i2c1>;
+       pinctrl-1 = <&pinctrl_i2c1_recovery>;
+       scl-gpios = <&gpio4 8 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio4 9 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        clock-frequency = <100000>;
        status = "okay";
 
                        };
 
                        vgen4_reg: v33 {
-                               regulator-min-microvolt = <2850000>;
+                               regulator-min-microvolt = <3300000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-always-on;
                        };
        };
 
        /* NXP SE97BTP with temperature sensor + eeprom, TQMa7x 02xx */
-       se97b: temperature-sensor-eeprom@1e {
+       se97b: temperature-sensor@1e {
                compatible = "nxp,se97b", "jedec,jc-42.4-temp";
                reg = <0x1e>;
        };
        /* ST M24C64 */
        m24c64: eeprom@50 {
                compatible = "atmel,24c64";
+               read-only;
                reg = <0x50>;
                pagesize = <32>;
+               vcc-supply = <&vgen4_reg>;
                status = "okay";
        };
 
        at24c02: eeprom@56 {
-               compatible = "atmel,24c02";
+               compatible = "nxp,se97b", "atmel,24c02";
                reg = <0x56>;
                pagesize = <16>;
+               vcc-supply = <&vgen4_reg>;
                status = "okay";
        };
 
 
 &iomuxc {
        pinctrl_i2c1: i2c1grp {
-               fsl,pins = <
-                       MX7D_PAD_I2C1_SDA__I2C1_SDA     0x40000078
-                       MX7D_PAD_I2C1_SCL__I2C1_SCL     0x40000078
-               >;
+               fsl,pins =
+                       <MX7D_PAD_I2C1_SDA__I2C1_SDA    0x40000078>,
+                       <MX7D_PAD_I2C1_SCL__I2C1_SCL    0x40000078>;
+       };
+
+       pinctrl_i2c1_recovery: i2c1recoverygrp {
+               fsl,pins =
+                       <MX7D_PAD_I2C1_SDA__GPIO4_IO9   0x40000078>,
+                       <MX7D_PAD_I2C1_SCL__GPIO4_IO8   0x40000078>;
        };
 
        pinctrl_pmic1: pmic1grp {
-               fsl,pins = <
-                       MX7D_PAD_SD2_RESET_B__GPIO5_IO11        0x4000005C
-               >;
+               fsl,pins =
+                       <MX7D_PAD_SD2_RESET_B__GPIO5_IO11       0x4000005C>;
        };
 
        pinctrl_qspi: qspigrp {
-               fsl,pins = <
-                       MX7D_PAD_EPDC_DATA00__QSPI_A_DATA0      0x5A
-                       MX7D_PAD_EPDC_DATA01__QSPI_A_DATA1      0x5A
-                       MX7D_PAD_EPDC_DATA02__QSPI_A_DATA2      0x5A
-                       MX7D_PAD_EPDC_DATA03__QSPI_A_DATA3      0x5A
-                       MX7D_PAD_EPDC_DATA05__QSPI_A_SCLK       0x11
-                       MX7D_PAD_EPDC_DATA06__QSPI_A_SS0_B      0x54
-                       MX7D_PAD_EPDC_DATA07__QSPI_A_SS1_B      0x54
-               >;
+               fsl,pins =
+                       <MX7D_PAD_EPDC_DATA00__QSPI_A_DATA0     0x5A>,
+                       <MX7D_PAD_EPDC_DATA01__QSPI_A_DATA1     0x5A>,
+                       <MX7D_PAD_EPDC_DATA02__QSPI_A_DATA2     0x5A>,
+                       <MX7D_PAD_EPDC_DATA03__QSPI_A_DATA3     0x5A>,
+                       <MX7D_PAD_EPDC_DATA05__QSPI_A_SCLK      0x11>,
+                       <MX7D_PAD_EPDC_DATA06__QSPI_A_SS0_B     0x54>,
+                       <MX7D_PAD_EPDC_DATA07__QSPI_A_SS1_B     0x54>;
        };
 
        pinctrl_qspi_reset: qspi_resetgrp {
-               fsl,pins = <
+               fsl,pins =
                        /* #QSPI_RESET */
-                       MX7D_PAD_EPDC_DATA04__GPIO2_IO4         0x52
-               >;
+                       <MX7D_PAD_EPDC_DATA04__GPIO2_IO4        0x52>;
        };
 
        pinctrl_usdhc3: usdhc3grp {
-               fsl,pins = <
-                       MX7D_PAD_SD3_CMD__SD3_CMD               0x59
-                       MX7D_PAD_SD3_CLK__SD3_CLK               0x56
-                       MX7D_PAD_SD3_DATA0__SD3_DATA0           0x59
-                       MX7D_PAD_SD3_DATA1__SD3_DATA1           0x59
-                       MX7D_PAD_SD3_DATA2__SD3_DATA2           0x59
-                       MX7D_PAD_SD3_DATA3__SD3_DATA3           0x59
-                       MX7D_PAD_SD3_DATA4__SD3_DATA4           0x59
-                       MX7D_PAD_SD3_DATA5__SD3_DATA5           0x59
-                       MX7D_PAD_SD3_DATA6__SD3_DATA6           0x59
-                       MX7D_PAD_SD3_DATA7__SD3_DATA7           0x59
-                       MX7D_PAD_SD3_STROBE__SD3_STROBE         0x19
-               >;
+               fsl,pins =
+                       <MX7D_PAD_SD3_CMD__SD3_CMD              0x59>,
+                       <MX7D_PAD_SD3_CLK__SD3_CLK              0x56>,
+                       <MX7D_PAD_SD3_DATA0__SD3_DATA0          0x59>,
+                       <MX7D_PAD_SD3_DATA1__SD3_DATA1          0x59>,
+                       <MX7D_PAD_SD3_DATA2__SD3_DATA2          0x59>,
+                       <MX7D_PAD_SD3_DATA3__SD3_DATA3          0x59>,
+                       <MX7D_PAD_SD3_DATA4__SD3_DATA4          0x59>,
+                       <MX7D_PAD_SD3_DATA5__SD3_DATA5          0x59>,
+                       <MX7D_PAD_SD3_DATA6__SD3_DATA6          0x59>,
+                       <MX7D_PAD_SD3_DATA7__SD3_DATA7          0x59>,
+                       <MX7D_PAD_SD3_STROBE__SD3_STROBE        0x19>;
        };
 
-       pinctrl_usdhc3_100mhz: usdhc3grp_100mhz {
-               fsl,pins = <
-                       MX7D_PAD_SD3_CMD__SD3_CMD               0x5a
-                       MX7D_PAD_SD3_CLK__SD3_CLK               0x51
-                       MX7D_PAD_SD3_DATA0__SD3_DATA0           0x5a
-                       MX7D_PAD_SD3_DATA1__SD3_DATA1           0x5a
-                       MX7D_PAD_SD3_DATA2__SD3_DATA2           0x5a
-                       MX7D_PAD_SD3_DATA3__SD3_DATA3           0x5a
-                       MX7D_PAD_SD3_DATA4__SD3_DATA4           0x5a
-                       MX7D_PAD_SD3_DATA5__SD3_DATA5           0x5a
-                       MX7D_PAD_SD3_DATA6__SD3_DATA6           0x5a
-                       MX7D_PAD_SD3_DATA7__SD3_DATA7           0x5a
-                       MX7D_PAD_SD3_STROBE__SD3_STROBE         0x1a
-               >;
+       pinctrl_usdhc3_100mhz: usdhc3_100mhzgrp {
+               fsl,pins =
+                       <MX7D_PAD_SD3_CMD__SD3_CMD               0x5a>,
+                       <MX7D_PAD_SD3_CLK__SD3_CLK               0x51>,
+                       <MX7D_PAD_SD3_DATA0__SD3_DATA0           0x5a>,
+                       <MX7D_PAD_SD3_DATA1__SD3_DATA1           0x5a>,
+                       <MX7D_PAD_SD3_DATA2__SD3_DATA2           0x5a>,
+                       <MX7D_PAD_SD3_DATA3__SD3_DATA3           0x5a>,
+                       <MX7D_PAD_SD3_DATA4__SD3_DATA4           0x5a>,
+                       <MX7D_PAD_SD3_DATA5__SD3_DATA5           0x5a>,
+                       <MX7D_PAD_SD3_DATA6__SD3_DATA6           0x5a>,
+                       <MX7D_PAD_SD3_DATA7__SD3_DATA7           0x5a>,
+                       <MX7D_PAD_SD3_STROBE__SD3_STROBE         0x1a>;
        };
 
-       pinctrl_usdhc3_200mhz: usdhc3grp_200mhz {
-               fsl,pins = <
-                       MX7D_PAD_SD3_CMD__SD3_CMD               0x5b
-                       MX7D_PAD_SD3_CLK__SD3_CLK               0x51
-                       MX7D_PAD_SD3_DATA0__SD3_DATA0           0x5b
-                       MX7D_PAD_SD3_DATA1__SD3_DATA1           0x5b
-                       MX7D_PAD_SD3_DATA2__SD3_DATA2           0x5b
-                       MX7D_PAD_SD3_DATA3__SD3_DATA3           0x5b
-                       MX7D_PAD_SD3_DATA4__SD3_DATA4           0x5b
-                       MX7D_PAD_SD3_DATA5__SD3_DATA5           0x5b
-                       MX7D_PAD_SD3_DATA6__SD3_DATA6           0x5b
-                       MX7D_PAD_SD3_DATA7__SD3_DATA7           0x5b
-                       MX7D_PAD_SD3_STROBE__SD3_STROBE         0x1b
-               >;
+       pinctrl_usdhc3_200mhz: usdhc3_200mhzgrp {
+               fsl,pins =
+                       <MX7D_PAD_SD3_CMD__SD3_CMD               0x5b>,
+                       <MX7D_PAD_SD3_CLK__SD3_CLK               0x51>,
+                       <MX7D_PAD_SD3_DATA0__SD3_DATA0           0x5b>,
+                       <MX7D_PAD_SD3_DATA1__SD3_DATA1           0x5b>,
+                       <MX7D_PAD_SD3_DATA2__SD3_DATA2           0x5b>,
+                       <MX7D_PAD_SD3_DATA3__SD3_DATA3           0x5b>,
+                       <MX7D_PAD_SD3_DATA4__SD3_DATA4           0x5b>,
+                       <MX7D_PAD_SD3_DATA5__SD3_DATA5           0x5b>,
+                       <MX7D_PAD_SD3_DATA6__SD3_DATA6           0x5b>,
+                       <MX7D_PAD_SD3_DATA7__SD3_DATA7           0x5b>,
+                       <MX7D_PAD_SD3_STROBE__SD3_STROBE         0x1b>;
        };
 };
 
 &iomuxc_lpsr {
        pinctrl_wdog1: wdog1grp {
-               fsl,pins = <
-                       MX7D_PAD_LPSR_GPIO1_IO00__WDOG1_WDOG_B  0x30
-               >;
+               fsl,pins =
+                       <MX7D_PAD_LPSR_GPIO1_IO00__WDOG1_WDOG_B 0x30>;
        };
 };
 
        };
 };
 
-&sdma {
-       status = "okay";
-};
-
 &usdhc3 {
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc3>;
        assigned-clock-rates = <400000000>;
        bus-width = <8>;
        non-removable;
+       no-sd;
+       no-sdio;
        vmmc-supply = <&vgen4_reg>;
        vqmmc-supply = <&sw2_reg>;
        status = "okay";
index 32bf9fa9d00e1cd86daad4383afc19323d91b9bd..0443faa3dfae48259cbf2ad9bb0a530d72f166e5 100644 (file)
@@ -21,8 +21,6 @@
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet2>;
        phy-mode = "rgmii-id";
-       phy-reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;
-       phy-reset-duration = <1>;
        phy-supply = <&reg_fec2_pwdn>;
        phy-handle = <&ethphy2_0>;
        fsl,magic-packet;
                ethphy2_0: ethernet-phy@0 {
                        compatible = "ethernet-phy-ieee802.3-c22";
                        reg = <0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_enet2_phy>;
                        ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_50_NS>;
                        ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_50_NS>;
                        ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
                        ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
+                       reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;
+                       reset-assert-us = <1000>;
+                       reset-deassert-us = <500>;
                };
        };
 };
 
+&gpio2 {
+       pcie-dis-hog {
+               gpio-hog;
+               gpios = <29 GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "pcie-dis";
+       };
+
+       pcie-rst-hog {
+               gpio-hog;
+               gpios = <12 GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "pcie-rst";
+       };
+};
+
 &iomuxc {
        pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_hog_mba7_1>;
+       pinctrl-0 = <&pinctrl_hog_mba7_1>, <&pinctrl_hog_pcie>;
 
        pinctrl_enet2: enet2grp {
-               fsl,pins = <
-                       MX7D_PAD_SD2_CD_B__ENET2_MDIO                   0x02
-                       MX7D_PAD_SD2_WP__ENET2_MDC                      0x00
-                       MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC             0x71
-                       MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0            0x71
-                       MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1            0x71
-                       MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2            0x71
-                       MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3             0x71
-                       MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL          0x71
-                       MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC            0x79
-                       MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0            0x79
-                       MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1             0x79
-                       MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2             0x79
-                       MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3            0x79
-                       MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL         0x79
+               fsl,pins =
+                       <MX7D_PAD_SD2_CD_B__ENET2_MDIO                  0x02>,
+                       <MX7D_PAD_SD2_WP__ENET2_MDC                     0x00>,
+                       <MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC            0x71>,
+                       <MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0           0x71>,
+                       <MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1           0x71>,
+                       <MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2           0x71>,
+                       <MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3            0x71>,
+                       <MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL         0x71>,
+                       <MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC           0x79>,
+                       <MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0           0x79>,
+                       <MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1            0x79>,
+                       <MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2            0x79>,
+                       <MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3           0x79>,
+                       <MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL        0x79>;
+       };
+
+       pinctrl_enet2_phy: enet2phygrp {
+               fsl,pins =
                        /* Reset: SION, 100kPU, SRE_FAST, DSE_X1 */
-                       MX7D_PAD_EPDC_BDR0__GPIO2_IO28          0x40000070
+                       <MX7D_PAD_EPDC_BDR0__GPIO2_IO28         0x40000070>,
                        /* INT/PWDN: SION, 100kPU, HYS, SRE_FAST, DSE_X1 */
-                       MX7D_PAD_EPDC_PWR_STAT__GPIO2_IO31      0x40000078
-               >;
+                       <MX7D_PAD_EPDC_PWR_STAT__GPIO2_IO31     0x40000078>;
        };
 
-       pinctrl_pcie: pciegrp {
-               fsl,pins = <
-                       /* #pcie_wake */
-                       MX7D_PAD_EPDC_PWR_COM__GPIO2_IO30               0x70
+       pinctrl_hog_pcie: hogpciegrp {
+               fsl,pins =
                        /* #pcie_rst */
-                       MX7D_PAD_SD2_CLK__GPIO5_IO12                    0x70
+                       <MX7D_PAD_SD2_CLK__GPIO5_IO12                   0x70>,
                        /* #pcie_dis */
-                       MX7D_PAD_EPDC_BDR1__GPIO2_IO29                  0x70
-               >;
+                       <MX7D_PAD_EPDC_BDR1__GPIO2_IO29                 0x70>;
+       };
+
+       pinctrl_pcie: pciegrp {
+               fsl,pins =
+                       /* #pcie_wake */
+                       <MX7D_PAD_EPDC_PWR_COM__GPIO2_IO30              0x70>;
        };
 };
 
 &iomuxc_lpsr {
        pinctrl_usbotg2: usbotg2grp {
-               fsl,pins = <
-                       MX7D_PAD_LPSR_GPIO1_IO06__USB_OTG2_OC   0x5c
-                       MX7D_PAD_LPSR_GPIO1_IO07__GPIO1_IO7     0x59
-               >;
+               fsl,pins =
+                       <MX7D_PAD_LPSR_GPIO1_IO06__USB_OTG2_OC  0x5c>,
+                       <MX7D_PAD_LPSR_GPIO1_IO07__GPIO1_IO7    0x59>;
        };
 };
 
        /* probe deferral not supported */
        /* pcie-bus-supply = <&reg_mpcie_1v5>; */
        reset-gpio = <&gpio5 12 GPIO_ACTIVE_LOW>;
-       status = "okay";
+       status = "disabled";
 };
 
 &usbotg2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usbotg2>;
        vbus-supply = <&reg_usb_otg2_vbus>;
-       srp-disable;
-       hnp-disable;
-       adp-disable;
+       disable-over-current;
        dr_mode = "host";
        status = "okay";
 };
index 12361fcbe24aff98a70482f2a7885c6ce28cb3b2..1b965652291bfaf5d6bad76ac3eaf10974eac6ea 100644 (file)
@@ -63,6 +63,7 @@
                gpio-controller;
                #gpio-cells = <2>;
                #interrupt-cells = <2>;
+               interrupt-controller;
                reg = <0x25>;
        };
 
index ebf7befcc11e3e8cd5985d72c384ae2248635bcc..9c81c6baa2d39ae7cd73a34144598d513423c343 100644 (file)
                                        <&clks IMX7D_LCDIF_PIXEL_ROOT_CLK>;
                                clock-names = "pix", "axi";
                                status = "disabled";
-
-                               port {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
-
-                                       lcdif_out_mipi_dsi: endpoint@0 {
-                                               reg = <0>;
-                                               remote-endpoint = <&mipi_dsi_in_lcdif>;
-                                       };
-                               };
                        };
 
                        mipi_csi: mipi-csi@30750000 {
                                samsung,esc-clock-frequency = <20000000>;
                                samsung,pll-clock-frequency = <24000000>;
                                status = "disabled";
-
-                               ports {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
-
-                                       port@0 {
-                                               reg = <0>;
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               mipi_dsi_in_lcdif: endpoint@0 {
-                                                       reg = <0>;
-                                                       remote-endpoint = <&lcdif_out_mipi_dsi>;
-                                               };
-                                       };
-                               };
                        };
                };
 
index d471cc5efa949bbb67c4227a74b7d3e77815ab81..e86998ca77d6ef03dcf196bf6d8271c0ee50cf4c 100644 (file)
                        dr_mode = "host";
                        snps,quirk-frame-length-adjustment = <0x20>;
                        snps,dis_rxdet_inp3_quirk;
+                       usb3-lpm-capable;
                        snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       snps,host-vbus-glitches;
                };
 
                pcie@3400000 {
index 9ebb7371e2351185afadcf1984851adc9872e024..330d3aff6b6c26e75d06376884b66c5ae5e14f89 100644 (file)
                clocks = <&saif0>;
        };
 
-       at24@51 {
+       eeprom@51 {
                compatible = "atmel,24c32";
                pagesize = <32>;
                reg = <0x51>;
index b0ed68af0546702d9413c492da6796194208c347..029f49be40e373f706f7f67c34358ba9272ea0af 100644 (file)
                reg = <0x22>;
                gpio-controller;
                #gpio-cells = <2>;
+               #interrupt-cells = <2>;
                interrupt-controller;
                interrupt-parent = <&gpio3>;
                interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
index 9cc1e14e6cd09c509e796188c5fc289c3ed06b11..6478a39b3be5e42cf81dd5c6233bd3fc719b5f27 100644 (file)
@@ -36,6 +36,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \
        qcom-msm8926-microsoft-superman-lte.dtb \
        qcom-msm8926-microsoft-tesla.dtb \
        qcom-msm8926-motorola-peregrine.dtb \
+       qcom-msm8926-samsung-matisselte.dtb \
        qcom-msm8960-cdp.dtb \
        qcom-msm8960-samsung-expressatt.dtb \
        qcom-msm8974-lge-nexus5-hammerhead.dtb \
index 0a1fd5eb3c6d26c3e3319aeb5e2c42dc068bccb1..a70de21bf139bd3f67d9e848f75cac20839335fb 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "qcom-msm8226.dtsi"
 #include "pm8226.dtsi"
+#include <dt-bindings/clock/qcom,mmcc-msm8974.h>
 
 /delete-node/ &adsp_region;
 
                pinctrl-names = "default";
                pinctrl-0 = <&wlan_regulator_default_state>;
        };
+
+       pwm_vibrator: pwm {
+               compatible = "clk-pwm";
+               clocks = <&mmcc CAMSS_GP0_CLK>;
+
+               pinctrl-0 = <&vibrator_clk_default_state>;
+               pinctrl-names = "default";
+
+               #pwm-cells = <2>;
+       };
+
+       vibrator {
+               compatible = "pwm-vibrator";
+
+               pwms = <&pwm_vibrator 0 10000>;
+               pwm-names = "enable";
+
+               vcc-supply = <&pm8226_l28>;
+               enable-gpios = <&tlmm 62 GPIO_ACTIVE_HIGH>;
+
+               pinctrl-0 = <&vibrator_en_default_state>;
+               pinctrl-names = "default";
+       };
 };
 
 &adsp {
                };
        };
 
+       vibrator_clk_default_state: vibrator-clk-default-state {
+               pins = "gpio33";
+               function = "gp0_clk";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       vibrator_en_default_state: vibrator-en-default-state {
+               pins = "gpio62";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
        wlan_hostwake_default_state: wlan-hostwake-default-state {
                pins = "gpio37";
                function = "gpio";
index cffc069712b2f1b2cc36c80dd51284a77e7fed31..da3be658e822fb6408738e7e79453b87c39478e1 100644 (file)
 
 /dts-v1/;
 
-#include <dt-bindings/input/input.h>
-#include "qcom-msm8226.dtsi"
-#include "pm8226.dtsi"
-
-/delete-node/ &adsp_region;
-/delete-node/ &smem_region;
+#include "qcom-msm8226-samsung-matisse-common.dtsi"
 
 / {
        model = "Samsung Galaxy Tab 4 10.1";
        compatible = "samsung,matisse-wifi", "qcom,apq8026";
        chassis-type = "tablet";
 
-       aliases {
-               mmc0 = &sdhc_1; /* SDC1 eMMC slot */
-               mmc1 = &sdhc_2; /* SDC2 SD card slot */
-               display0 = &framebuffer0;
-       };
-
-       chosen {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               stdout-path = "display0";
-
-               framebuffer0: framebuffer@3200000 {
-                       compatible = "simple-framebuffer";
-                       reg = <0x03200000 0x800000>;
-                       width = <1280>;
-                       height = <800>;
-                       stride = <(1280 * 3)>;
-                       format = "r8g8b8";
-               };
-       };
-
-       gpio-hall-sensor {
-               compatible = "gpio-keys";
-
-               event-hall-sensor {
-                       label = "Hall Effect Sensor";
-                       gpios = <&tlmm 110 GPIO_ACTIVE_LOW>;
-                       linux,input-type = <EV_SW>;
-                       linux,code = <SW_LID>;
-                       debounce-interval = <15>;
-                       linux,can-disable;
-                       wakeup-source;
-               };
-       };
-
-       gpio-keys {
-               compatible = "gpio-keys";
-               autorepeat;
-
-               key-home {
-                       label = "Home";
-                       gpios = <&tlmm 108 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_HOMEPAGE>;
-                       debounce-interval = <15>;
-               };
-
-               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>;
-               };
-       };
-
-       i2c-backlight {
-               compatible = "i2c-gpio";
-               sda-gpios = <&tlmm 20 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
-               scl-gpios = <&tlmm 21 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
-
-               pinctrl-0 = <&backlight_i2c_default_state>;
-               pinctrl-names = "default";
-
-               i2c-gpio,delay-us = <4>;
-
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               backlight@2c {
-                       compatible = "ti,lp8556";
-                       reg = <0x2c>;
-
-                       dev-ctrl = /bits/ 8 <0x80>;
-                       init-brt = /bits/ 8 <0x3f>;
-
-                       pwms = <&backlight_pwm 0 100000>;
-                       pwm-names = "lp8556";
-
-                       rom-a0h {
-                               rom-addr = /bits/ 8 <0xa0>;
-                               rom-val = /bits/ 8 <0x44>;
-                       };
-
-                       rom-a1h {
-                               rom-addr = /bits/ 8 <0xa1>;
-                               rom-val = /bits/ 8 <0x6c>;
-                       };
-
-                       rom-a5h {
-                               rom-addr = /bits/ 8 <0xa5>;
-                               rom-val = /bits/ 8 <0x24>;
-                       };
-               };
-       };
-
-       backlight_pwm: pwm {
-               compatible = "clk-pwm";
-               #pwm-cells = <2>;
-               clocks = <&mmcc CAMSS_GP0_CLK>;
-               pinctrl-0 = <&backlight_pwm_default_state>;
-               pinctrl-names = "default";
-       };
-
-       reg_tsp_1p8v: regulator-tsp-1p8v {
-               compatible = "regulator-fixed";
-               regulator-name = "tsp_1p8v";
-               regulator-min-microvolt = <1800000>;
-               regulator-max-microvolt = <1800000>;
-
-               gpio = <&tlmm 31 GPIO_ACTIVE_HIGH>;
-               enable-active-high;
-
-               pinctrl-names = "default";
-               pinctrl-0 = <&tsp_en_default_state>;
-       };
-
        reg_tsp_3p3v: regulator-tsp-3p3v {
                compatible = "regulator-fixed";
                regulator-name = "tsp_3p3v";
                pinctrl-names = "default";
                pinctrl-0 = <&tsp_en1_default_state>;
        };
-
-       reserved-memory {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               framebuffer@3200000 {
-                       reg = <0x03200000 0x800000>;
-                       no-map;
-               };
-
-               mpss@8400000 {
-                       reg = <0x08400000 0x1f00000>;
-                       no-map;
-               };
-
-               mba@a300000 {
-                       reg = <0x0a300000 0x100000>;
-                       no-map;
-               };
-
-               reserved@cb00000 {
-                       reg = <0x0cb00000 0x700000>;
-                       no-map;
-               };
-
-               wcnss@d200000 {
-                       reg = <0x0d200000 0x700000>;
-                       no-map;
-               };
-
-               adsp_region: adsp@d900000 {
-                       reg = <0x0d900000 0x1800000>;
-                       no-map;
-               };
-
-               venus@f100000 {
-                       reg = <0x0f100000 0x500000>;
-                       no-map;
-               };
-
-               smem_region: smem@fa00000 {
-                       reg = <0x0fa00000 0x100000>;
-                       no-map;
-               };
-
-               reserved@fb00000 {
-                       reg = <0x0fb00000 0x260000>;
-                       no-map;
-               };
-
-               rfsa@fd60000 {
-                       reg = <0x0fd60000 0x20000>;
-                       no-map;
-               };
-
-               rmtfs@fd80000 {
-                       compatible = "qcom,rmtfs-mem";
-                       reg = <0x0fd80000 0x180000>;
-                       no-map;
-
-                       qcom,client-id = <1>;
-               };
-       };
-};
-
-&adsp {
-       status = "okay";
 };
 
 &blsp1_i2c2 {
        };
 };
 
-&blsp1_i2c4 {
-       status = "okay";
-
-       muic: usb-switch@25 {
-               compatible = "siliconmitus,sm5502-muic";
-               reg = <0x25>;
-
-               interrupt-parent = <&tlmm>;
-               interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
-
-               pinctrl-names = "default";
-               pinctrl-0 = <&muic_int_default_state>;
-       };
-};
-
 &blsp1_i2c5 {
        status = "okay";
 
                interrupt-parent = <&tlmm>;
                interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
 
+               linux,keycodes = <KEY_RESERVED>,
+                                <KEY_RESERVED>,
+                                <KEY_RESERVED>,
+                                <KEY_RESERVED>,
+                                <KEY_APPSELECT>,
+                                <KEY_BACK>;
+
                pinctrl-names = "default";
                pinctrl-0 = <&tsp_int_rst_default_state>;
 
        };
 };
 
-&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 = <1800000>;
-               };
-
-               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>;
-                       regulator-always-on;
-               };
-
-               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 {
-                       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>;
-                       regulator-always-on;
-               };
-
-               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 = <1800000>;
-                       regulator-max-microvolt = <3300000>;
-               };
-
-               pm8226_l16: l16 {
-                       regulator-min-microvolt = <3000000>;
-                       regulator-max-microvolt = <3350000>;
-               };
-
-               pm8226_l17: l17 {
-                       regulator-min-microvolt = <2950000>;
-                       regulator-max-microvolt = <2950000>;
-
-                       regulator-system-load = <200000>;
-                       regulator-allow-set-load;
-                       regulator-always-on;
-               };
-
-               pm8226_l18: l18 {
-                       regulator-min-microvolt = <2950000>;
-                       regulator-max-microvolt = <2950000>;
-               };
-
-               pm8226_l19: l19 {
-                       regulator-min-microvolt = <2850000>;
-                       regulator-max-microvolt = <3000000>;
-               };
-
-               pm8226_l20: l20 {
-                       regulator-min-microvolt = <3075000>;
-                       regulator-max-microvolt = <3075000>;
-               };
-
-               pm8226_l21: l21 {
-                       regulator-min-microvolt = <1800000>;
-                       regulator-max-microvolt = <2950000>;
-               };
-
-               pm8226_l22: l22 {
-                       regulator-min-microvolt = <1800000>;
-                       regulator-max-microvolt = <3000000>;
-               };
-
-               pm8226_l23: l23 {
-                       regulator-min-microvolt = <1800000>;
-                       regulator-max-microvolt = <3300000>;
-               };
-
-               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 = <1300000>;
-               };
-
-               pm8226_l27: l27 {
-                       regulator-min-microvolt = <1800000>;
-                       regulator-max-microvolt = <1800000>;
-               };
-
-               pm8226_l28: l28 {
-                       regulator-min-microvolt = <1800000>;
-                       regulator-max-microvolt = <2950000>;
-               };
-
-               pm8226_lvs1: lvs1 {};
-       };
-};
-
-&sdhc_1 {
-       vmmc-supply = <&pm8226_l17>;
-       vqmmc-supply = <&pm8226_l6>;
-
-       bus-width = <8>;
-       non-removable;
-
-       status = "okay";
+&pm8226_l3 {
+       regulator-max-microvolt = <1337500>;
 };
 
-&sdhc_2 {
-       vmmc-supply = <&pm8226_l18>;
-       vqmmc-supply = <&pm8226_l21>;
-
-       bus-width = <4>;
-       cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
-
-       status = "okay";
+&pm8226_s4 {
+       regulator-max-microvolt = <1800000>;
 };
 
 &tlmm {
-       accel_int_default_state: accel-int-default-state {
-               pins = "gpio54";
-               function = "gpio";
-               drive-strength = <2>;
-               bias-disable;
-       };
-
-       backlight_i2c_default_state: backlight-i2c-default-state {
-               pins = "gpio20", "gpio21";
-               function = "gpio";
-               drive-strength = <2>;
-               bias-disable;
-       };
-
-       backlight_pwm_default_state: backlight-pwm-default-state {
-               pins = "gpio33";
-               function = "gp0_clk";
-       };
-
-       muic_int_default_state: muic-int-default-state {
-               pins = "gpio67";
-               function = "gpio";
-               drive-strength = <2>;
-               bias-disable;
-       };
-
-       tsp_en_default_state: tsp-en-default-state {
-               pins = "gpio31";
-               function = "gpio";
-               drive-strength = <2>;
-               bias-disable;
-       };
-
        tsp_en1_default_state: tsp-en1-default-state {
                pins = "gpio73";
                function = "gpio";
                drive-strength = <2>;
                bias-disable;
        };
-
-       tsp_int_rst_default_state: tsp-int-rst-default-state {
-               pins = "gpio17";
-               function = "gpio";
-               drive-strength = <10>;
-               bias-pull-up;
-       };
-};
-
-&usb {
-       extcon = <&muic>, <&muic>;
-       status = "okay";
-};
-
-&usb_hs_phy {
-       extcon = <&muic>;
-       v1p8-supply = <&pm8226_l10>;
-       v3p3-supply = <&pm8226_l20>;
 };
index 3faf57035d544d32d1ad4602a0c79f3e753bdc8a..9a5ba978775aaa7c784cc676f799cf400333a26f 100644 (file)
 
        cpu-pmu {
                compatible = "qcom,krait-pmu";
-               interrupts = <1 10 0x304>;
+               interrupts = <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
        };
 
        clocks {
 
                modem_smsm: modem@1 {
                        reg = <1>;
-                       interrupts = <0 38 IRQ_TYPE_EDGE_RISING>;
+                       interrupts = <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>;
 
                        interrupt-controller;
                        #interrupt-cells = <2>;
 
                q6_smsm: q6@2 {
                        reg = <2>;
-                       interrupts = <0 89 IRQ_TYPE_EDGE_RISING>;
+                       interrupts = <GIC_SPI 89 IRQ_TYPE_EDGE_RISING>;
 
                        interrupt-controller;
                        #interrupt-cells = <2>;
 
                wcnss_smsm: wcnss@3 {
                        reg = <3>;
-                       interrupts = <0 204 IRQ_TYPE_EDGE_RISING>;
+                       interrupts = <GIC_SPI 204 IRQ_TYPE_EDGE_RISING>;
 
                        interrupt-controller;
                        #interrupt-cells = <2>;
 
                dsps_smsm: dsps@4 {
                        reg = <4>;
-                       interrupts = <0 137 IRQ_TYPE_EDGE_RISING>;
+                       interrupts = <GIC_SPI 137 IRQ_TYPE_EDGE_RISING>;
 
                        interrupt-controller;
                        #interrupt-cells = <2>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
-                       interrupts = <0 16 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
 
                        pinctrl-names = "default";
                        pinctrl-0 = <&ps_hold>;
                timer@200a000 {
                        compatible = "qcom,kpss-wdt-apq8064", "qcom,kpss-timer",
                                     "qcom,msm-timer";
-                       interrupts = <1 1 0x301>,
-                                    <1 2 0x301>,
-                                    <1 3 0x301>;
+                       interrupts = <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>,
+                                    <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>,
+                                    <GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>;
                        reg = <0x0200a000 0x100>;
                        clock-frequency = <27000000>;
                        cpu-offset = <0x80000>;
                        #clock-cells = <0>;
                };
 
-               saw0: power-controller@2089000 {
+               saw0: power-manager@2089000 {
                        compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2";
                        reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
-                       regulator;
+
+                       saw0_vreg: regulator {
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <1300000>;
+                       };
                };
 
-               saw1: power-controller@2099000 {
+               saw1: power-manager@2099000 {
                        compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2";
                        reg = <0x02099000 0x1000>, <0x02009000 0x1000>;
-                       regulator;
+
+                       saw1_vreg: regulator {
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <1300000>;
+                       };
                };
 
-               saw2: power-controller@20a9000 {
+               saw2: power-manager@20a9000 {
                        compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2";
                        reg = <0x020a9000 0x1000>, <0x02009000 0x1000>;
-                       regulator;
+
+                       saw2_vreg: regulator {
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <1300000>;
+                       };
                };
 
-               saw3: power-controller@20b9000 {
+               saw3: power-manager@20b9000 {
                        compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2";
                        reg = <0x020b9000 0x1000>, <0x02009000 0x1000>;
-                       regulator;
+
+                       saw3_vreg: regulator {
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <1300000>;
+                       };
                };
 
                sps_sic_non_secure: sps-sic-non-secure@12100000 {
                                compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
                                reg = <0x12450000 0x100>,
                                      <0x12400000 0x03>;
-                               interrupts = <0 193 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&gcc GSBI1_UART_CLK>, <&gcc GSBI1_H_CLK>;
                                clock-names = "core", "iface";
                                status = "disabled";
                                pinctrl-1 = <&i2c1_pins_sleep>;
                                pinctrl-names = "default", "sleep";
                                reg = <0x12460000 0x1000>;
-                               interrupts = <0 194 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&gcc GSBI1_QUP_CLK>, <&gcc GSBI1_H_CLK>;
                                clock-names = "core", "iface";
                                #address-cells = <1>;
                                pinctrl-0 = <&i2c2_pins>;
                                pinctrl-1 = <&i2c2_pins_sleep>;
                                pinctrl-names = "default", "sleep";
-                               interrupts = <0 196 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&gcc GSBI2_QUP_CLK>, <&gcc GSBI2_H_CLK>;
                                clock-names = "core", "iface";
                                #address-cells = <1>;
                                compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
                                reg = <0x1a240000 0x100>,
                                      <0x1a200000 0x03>;
-                               interrupts = <0 154 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&gcc GSBI5_UART_CLK>, <&gcc GSBI5_H_CLK>;
                                clock-names = "core", "iface";
                                status = "disabled";
                        gsbi5_spi: spi@1a280000 {
                                compatible = "qcom,spi-qup-v1.1.1";
                                reg = <0x1a280000 0x1000>;
-                               interrupts = <0 155 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
                                pinctrl-0 = <&spi5_default>;
                                pinctrl-1 = <&spi5_sleep>;
                                pinctrl-names = "default", "sleep";
                                compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
                                reg = <0x16540000 0x100>,
                                      <0x16500000 0x03>;
-                               interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&gcc GSBI6_UART_CLK>, <&gcc GSBI6_H_CLK>;
                                clock-names = "core", "iface";
                                status = "disabled";
                                compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
                                reg = <0x16640000 0x1000>,
                                      <0x16600000 0x1000>;
-                               interrupts = <0 158 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&gcc GSBI7_UART_CLK>, <&gcc GSBI7_H_CLK>;
                                clock-names = "core", "iface";
                                status = "disabled";
                sdcc3bam: dma-controller@12182000 {
                        compatible = "qcom,bam-v1.3.0";
                        reg = <0x12182000 0x8000>;
-                       interrupts = <0 96 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc SDC3_H_CLK>;
                        clock-names = "bam_clk";
                        #dma-cells = <1>;
                sdcc4bam: dma-controller@121c2000 {
                        compatible = "qcom,bam-v1.3.0";
                        reg = <0x121c2000 0x8000>;
-                       interrupts = <0 95 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc SDC4_H_CLK>;
                        clock-names = "bam_clk";
                        #dma-cells = <1>;
                sdcc1bam: dma-controller@12402000 {
                        compatible = "qcom,bam-v1.3.0";
                        reg = <0x12402000 0x8000>;
-                       interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc SDC1_H_CLK>;
                        clock-names = "bam_clk";
                        #dma-cells = <1>;
index 2b1f9d0fb510aa002659624f9f853e6cd113cb7f..8204e64d9a97fec9d45cce3edb4dfd2052c9bf28 100644 (file)
                        };
                };
 
-               saw0: power-controller@f9089000 {
+               saw0: power-manager@f9089000 {
                        compatible = "qcom,apq8084-saw2-v2.1-cpu", "qcom,saw2";
                        reg = <0xf9089000 0x1000>, <0xf9009000 0x1000>;
                };
 
-               saw1: power-controller@f9099000 {
+               saw1: power-manager@f9099000 {
                        compatible = "qcom,apq8084-saw2-v2.1-cpu", "qcom,saw2";
                        reg = <0xf9099000 0x1000>, <0xf9009000 0x1000>;
                };
 
-               saw2: power-controller@f90a9000 {
+               saw2: power-manager@f90a9000 {
                        compatible = "qcom,apq8084-saw2-v2.1-cpu", "qcom,saw2";
                        reg = <0xf90a9000 0x1000>, <0xf9009000 0x1000>;
                };
 
-               saw3: power-controller@f90b9000 {
+               saw3: power-manager@f90b9000 {
                        compatible = "qcom,apq8084-saw2-v2.1-cpu", "qcom,saw2";
                        reg = <0xf90b9000 0x1000>, <0xf9009000 0x1000>;
                };
 
-               saw_l2: power-controller@f9012000 {
-                       compatible = "qcom,saw2";
+               saw_l2: power-manager@f9012000 {
+                       compatible = "qcom,apq8084-saw2-v2.1-l2", "qcom,saw2";
                        reg = <0xf9012000 0x1000>;
-                       regulator;
                };
 
                acc0: power-manager@f9088000 {
index 0505270cf508cf4e2aa4d2f94bd45f63b65d6960..f7ac8f9d0b6fc00e6363f2f42e8356591fed9cc5 100644 (file)
        chosen {
                stdout-path = "serial0:115200n8";
        };
+};
 
-       soc {
-               rng@22000 {
-                       status = "okay";
-               };
-
-               pinctrl@1000000 {
-                       serial_pins: serial_pinmux {
-                               mux {
-                                       pins = "gpio60", "gpio61";
-                                       function = "blsp_uart0";
-                                       bias-disable;
-                               };
-                       };
-
-                       spi_0_pins: spi_0_pinmux {
-                               pinmux {
-                                       function = "blsp_spi0";
-                                       pins = "gpio55", "gpio56", "gpio57";
-                               };
-                               pinmux_cs {
-                                       function = "gpio";
-                                       pins = "gpio54";
-                               };
-                               pinconf {
-                                       pins = "gpio55", "gpio56", "gpio57";
-                                       drive-strength = <12>;
-                                       bias-disable;
-                               };
-                               pinconf_cs {
-                                       pins = "gpio54";
-                                       drive-strength = <2>;
-                                       bias-disable;
-                                       output-high;
-                               };
-                       };
-               };
+&prng {
+       status = "okay";
+};
 
-               blsp_dma: dma-controller@7884000 {
-                       status = "okay";
+&tlmm {
+       serial_pins: serial_pinmux {
+               mux {
+                       pins = "gpio60", "gpio61";
+                       function = "blsp_uart0";
+                       bias-disable;
                };
+       };
 
-               spi@78b5000 {
-                       pinctrl-0 = <&spi_0_pins>;
-                       pinctrl-names = "default";
-                       status = "okay";
-                       cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>;
-
-                       mx25l25635e@0 {
-                               #address-cells = <1>;
-                               #size-cells = <1>;
-                               reg = <0>;
-                               compatible = "mx25l25635e";
-                               spi-max-frequency = <24000000>;
-                       };
+       spi_0_pins: spi_0_pinmux {
+               pinmux {
+                       function = "blsp_spi0";
+                       pins = "gpio55", "gpio56", "gpio57";
                };
-
-               serial@78af000 {
-                       pinctrl-0 = <&serial_pins>;
-                       pinctrl-names = "default";
-                       status = "okay";
+               pinmux_cs {
+                       function = "gpio";
+                       pins = "gpio54";
                };
-
-               cryptobam: dma-controller@8e04000 {
-                       status = "okay";
+               pinconf {
+                       pins = "gpio55", "gpio56", "gpio57";
+                       drive-strength = <12>;
+                       bias-disable;
                };
-
-               crypto@8e3a000 {
-                       status = "okay";
+               pinconf_cs {
+                       pins = "gpio54";
+                       drive-strength = <2>;
+                       bias-disable;
+                       output-high;
                };
+       };
+};
 
-               watchdog@b017000 {
-                       status = "okay";
-               };
+&blsp_dma {
+       status = "okay";
+};
 
-               wifi@a000000 {
-                       status = "okay";
-               };
+&blsp1_spi1 {
+       pinctrl-0 = <&spi_0_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+       cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>;
 
-               wifi@a800000 {
-                       status = "okay";
-               };
+       flash@0 {
+               reg = <0>;
+               compatible = "jedec,spi-nor";
+               spi-max-frequency = <24000000>;
        };
 };
+
+&blsp1_uart1 {
+       pinctrl-0 = <&serial_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&cryptobam {
+       status = "okay";
+};
+
+&crypto {
+       status = "okay";
+};
+
+&watchdog {
+       status = "okay";
+};
+
+&wifi0 {
+       status = "okay";
+};
+
+&wifi1 {
+       status = "okay";
+};
index f989bd741cd185401dcfdfad23416d710faeed7d..681cb3fc8085dfd6ab9fe89daa0de281c157f641 100644 (file)
 
        timer {
                compatible = "arm,armv7-timer";
-               interrupts = <1 2 0xf08>,
-                            <1 3 0xf08>,
-                            <1 4 0xf08>,
-                            <1 1 0xf08>;
+               interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
                clock-frequency = <48000000>;
                always-on;
        };
                        reg = <0x0b0b8000 0x1000>, <0xb008000 0x1000>;
                };
 
-               saw0: regulator@b089000 {
-                       compatible = "qcom,saw2";
+               saw0: power-manager@b089000 {
+                       compatible = "qcom,ipq4019-saw2-cpu", "qcom,saw2";
                        reg = <0x0b089000 0x1000>, <0x0b009000 0x1000>;
-                       regulator;
                };
 
-               saw1: regulator@b099000 {
-                       compatible = "qcom,saw2";
+               saw1: power-manager@b099000 {
+                       compatible = "qcom,ipq4019-saw2-cpu", "qcom,saw2";
                        reg = <0x0b099000 0x1000>, <0x0b009000 0x1000>;
-                       regulator;
                };
 
-               saw2: regulator@b0a9000 {
-                       compatible = "qcom,saw2";
+               saw2: power-manager@b0a9000 {
+                       compatible = "qcom,ipq4019-saw2-cpu", "qcom,saw2";
                        reg = <0x0b0a9000 0x1000>, <0x0b009000 0x1000>;
-                       regulator;
                };
 
-               saw3: regulator@b0b9000 {
-                       compatible = "qcom,saw2";
+               saw3: power-manager@b0b9000 {
+                       compatible = "qcom,ipq4019-saw2-cpu", "qcom,saw2";
                        reg = <0x0b0b9000 0x1000>, <0x0b009000 0x1000>;
-                       regulator;
                };
 
-               saw_l2: regulator@b012000 {
-                       compatible = "qcom,saw2";
+               saw_l2: power-manager@b012000 {
+                       compatible = "qcom,ipq4019-saw2-l2", "qcom,saw2";
                        reg = <0xb012000 0x1000>;
-                       regulator;
                };
 
                blsp1_uart1: serial@78af000 {
                        clocks = <&gcc GCC_USB2_MASTER_CLK>,
                                 <&gcc GCC_USB2_SLEEP_CLK>,
                                 <&gcc GCC_USB2_MOCK_UTMI_CLK>;
-                       clock-names = "master", "sleep", "mock_utmi";
+                       clock-names = "core", "sleep", "mock_utmi";
                        ranges;
                        status = "disabled";
 
index 6a7f4dd0f775be4473eba87b140a6743c5f2d7fe..2eb6758b6a3a6f7c80bddfb89b31644fa51eaf5b 100644 (file)
                        #clock-cells = <0>;
                };
 
-               saw0: regulator@2089000 {
-                       compatible = "qcom,saw2";
+               saw0: power-manager@2089000 {
+                       compatible = "qcom,ipq8064-saw2-cpu", "qcom,saw2";
                        reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
-                       regulator;
                };
 
                acc1: clock-controller@2098000 {
                        #clock-cells = <0>;
                };
 
-               saw1: regulator@2099000 {
-                       compatible = "qcom,saw2";
+               saw1: power-manager@2099000 {
+                       compatible = "qcom,ipq8064-saw2-cpu", "qcom,saw2";
                        reg = <0x02099000 0x1000>, <0x02009000 0x1000>;
-                       regulator;
                };
 
                nss_common: syscon@3000000 {
                        ranges;
 
                        resets = <&gcc USB30_0_MASTER_RESET>;
-                       reset-names = "master";
 
                        status = "disabled";
 
                        ranges;
 
                        resets = <&gcc USB30_1_MASTER_RESET>;
-                       reset-names = "master";
 
                        status = "disabled";
 
diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226-samsung-matisse-common.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8226-samsung-matisse-common.dtsi
new file mode 100644 (file)
index 0000000..a15a44f
--- /dev/null
@@ -0,0 +1,457 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Matti Lehtimäki <matti.lehtimaki@gmail.com>
+ */
+
+#include <dt-bindings/input/input.h>
+#include "qcom-msm8226.dtsi"
+#include "pm8226.dtsi"
+
+/delete-node/ &adsp_region;
+/delete-node/ &smem_region;
+
+/ {
+       aliases {
+               mmc0 = &sdhc_1; /* SDC1 eMMC slot */
+               mmc1 = &sdhc_2; /* SDC2 SD card slot */
+               display0 = &framebuffer0;
+       };
+
+       chosen {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               stdout-path = "display0";
+
+               framebuffer0: framebuffer@3200000 {
+                       compatible = "simple-framebuffer";
+                       reg = <0x03200000 0x800000>;
+                       width = <1280>;
+                       height = <800>;
+                       stride = <(1280 * 3)>;
+                       format = "r8g8b8";
+               };
+       };
+
+       gpio-hall-sensor {
+               compatible = "gpio-keys";
+
+               event-hall-sensor {
+                       label = "Hall Effect Sensor";
+                       gpios = <&tlmm 110 GPIO_ACTIVE_LOW>;
+                       linux,input-type = <EV_SW>;
+                       linux,code = <SW_LID>;
+                       debounce-interval = <15>;
+                       linux,can-disable;
+                       wakeup-source;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               autorepeat;
+
+               key-home {
+                       label = "Home";
+                       gpios = <&tlmm 108 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_HOMEPAGE>;
+                       debounce-interval = <15>;
+               };
+
+               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>;
+               };
+       };
+
+       i2c-backlight {
+               compatible = "i2c-gpio";
+               sda-gpios = <&tlmm 20 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+               scl-gpios = <&tlmm 21 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+
+               pinctrl-0 = <&backlight_i2c_default_state>;
+               pinctrl-names = "default";
+
+               i2c-gpio,delay-us = <4>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               backlight@2c {
+                       compatible = "ti,lp8556";
+                       reg = <0x2c>;
+
+                       dev-ctrl = /bits/ 8 <0x80>;
+                       init-brt = /bits/ 8 <0x3f>;
+
+                       pwms = <&backlight_pwm 0 100000>;
+                       pwm-names = "lp8556";
+
+                       rom-a0h {
+                               rom-addr = /bits/ 8 <0xa0>;
+                               rom-val = /bits/ 8 <0x44>;
+                       };
+
+                       rom-a1h {
+                               rom-addr = /bits/ 8 <0xa1>;
+                               rom-val = /bits/ 8 <0x6c>;
+                       };
+
+                       rom-a5h {
+                               rom-addr = /bits/ 8 <0xa5>;
+                               rom-val = /bits/ 8 <0x24>;
+                       };
+               };
+       };
+
+       backlight_pwm: pwm {
+               compatible = "clk-pwm";
+               #pwm-cells = <2>;
+               clocks = <&mmcc CAMSS_GP0_CLK>;
+               pinctrl-0 = <&backlight_pwm_default_state>;
+               pinctrl-names = "default";
+       };
+
+       reg_tsp_1p8v: regulator-tsp-1p8v {
+               compatible = "regulator-fixed";
+               regulator-name = "tsp_1p8v";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+
+               gpio = <&tlmm 31 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&tsp_en_default_state>;
+       };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               framebuffer@3200000 {
+                       reg = <0x03200000 0x800000>;
+                       no-map;
+               };
+
+               mpss@8400000 {
+                       reg = <0x08400000 0x1f00000>;
+                       no-map;
+               };
+
+               mba@a300000 {
+                       reg = <0x0a300000 0x100000>;
+                       no-map;
+               };
+
+               reserved@cb00000 {
+                       reg = <0x0cb00000 0x700000>;
+                       no-map;
+               };
+
+               wcnss@d200000 {
+                       reg = <0x0d200000 0x700000>;
+                       no-map;
+               };
+
+               adsp_region: adsp@d900000 {
+                       reg = <0x0d900000 0x1800000>;
+                       no-map;
+               };
+
+               venus@f100000 {
+                       reg = <0x0f100000 0x500000>;
+                       no-map;
+               };
+
+               smem_region: smem@fa00000 {
+                       reg = <0x0fa00000 0x100000>;
+                       no-map;
+               };
+
+               reserved@fb00000 {
+                       reg = <0x0fb00000 0x260000>;
+                       no-map;
+               };
+
+               rfsa@fd60000 {
+                       reg = <0x0fd60000 0x20000>;
+                       no-map;
+               };
+
+               rmtfs@fd80000 {
+                       compatible = "qcom,rmtfs-mem";
+                       reg = <0x0fd80000 0x180000>;
+                       no-map;
+
+                       qcom,client-id = <1>;
+               };
+       };
+};
+
+&adsp {
+       status = "okay";
+};
+
+&blsp1_i2c4 {
+       status = "okay";
+
+       muic: usb-switch@25 {
+               compatible = "siliconmitus,sm5502-muic";
+               reg = <0x25>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&muic_int_default_state>;
+       };
+};
+
+&blsp1_uart3 {
+       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 = <1350000>;
+                       regulator-always-on;
+               };
+
+               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 {
+                       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>;
+                       regulator-always-on;
+               };
+
+               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 = <1800000>;
+                       regulator-max-microvolt = <3300000>;
+               };
+
+               pm8226_l16: l16 {
+                       regulator-min-microvolt = <3000000>;
+                       regulator-max-microvolt = <3350000>;
+               };
+
+               pm8226_l17: l17 {
+                       regulator-min-microvolt = <2950000>;
+                       regulator-max-microvolt = <2950000>;
+
+                       regulator-system-load = <200000>;
+                       regulator-allow-set-load;
+                       regulator-always-on;
+               };
+
+               pm8226_l18: l18 {
+                       regulator-min-microvolt = <2950000>;
+                       regulator-max-microvolt = <2950000>;
+               };
+
+               pm8226_l19: l19 {
+                       regulator-min-microvolt = <2850000>;
+                       regulator-max-microvolt = <3000000>;
+               };
+
+               pm8226_l20: l20 {
+                       regulator-min-microvolt = <3075000>;
+                       regulator-max-microvolt = <3075000>;
+               };
+
+               pm8226_l21: l21 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <2950000>;
+               };
+
+               pm8226_l22: l22 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <3000000>;
+               };
+
+               pm8226_l23: l23 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <3300000>;
+               };
+
+               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 = <1300000>;
+               };
+
+               pm8226_l27: l27 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+               pm8226_l28: l28 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <2950000>;
+               };
+
+               pm8226_lvs1: lvs1 {};
+       };
+};
+
+&sdhc_1 {
+       vmmc-supply = <&pm8226_l17>;
+       vqmmc-supply = <&pm8226_l6>;
+
+       bus-width = <8>;
+       non-removable;
+
+       status = "okay";
+};
+
+&sdhc_2 {
+       vmmc-supply = <&pm8226_l18>;
+       vqmmc-supply = <&pm8226_l21>;
+
+       bus-width = <4>;
+       cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
+
+       status = "okay";
+};
+
+&tlmm {
+       accel_int_default_state: accel-int-default-state {
+               pins = "gpio54";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       backlight_i2c_default_state: backlight-i2c-default-state {
+               pins = "gpio20", "gpio21";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       backlight_pwm_default_state: backlight-pwm-default-state {
+               pins = "gpio33";
+               function = "gp0_clk";
+       };
+
+       muic_int_default_state: muic-int-default-state {
+               pins = "gpio67";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       tsp_en_default_state: tsp-en-default-state {
+               pins = "gpio31";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       tsp_int_rst_default_state: tsp-int-rst-default-state {
+               pins = "gpio17";
+               function = "gpio";
+               drive-strength = <10>;
+               bias-pull-up;
+       };
+};
+
+&usb {
+       extcon = <&muic>, <&muic>;
+       status = "okay";
+};
+
+&usb_hs_phy {
+       extcon = <&muic>;
+       v1p8-supply = <&pm8226_l10>;
+       v3p3-supply = <&pm8226_l20>;
+};
index b492c95e5d301d25d6e9446081940bcb52a94569..270973e856259e4d3e55f8dcf28697a28f224814 100644 (file)
 
        chosen { };
 
-       memory@0 {
-               device_type = "memory";
-               reg = <0x0 0x0>;
-       };
-
        clocks {
                xo_board: xo_board {
                        compatible = "fixed-clock";
                };
        };
 
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               CPU0: cpu@0 {
+                       compatible = "arm,cortex-a7";
+                       enable-method = "qcom,msm8226-smp";
+                       device_type = "cpu";
+                       reg = <0>;
+                       next-level-cache = <&L2>;
+                       qcom,acc = <&acc0>;
+                       qcom,saw = <&saw0>;
+               };
+
+               CPU1: cpu@1 {
+                       compatible = "arm,cortex-a7";
+                       enable-method = "qcom,msm8226-smp";
+                       device_type = "cpu";
+                       reg = <1>;
+                       next-level-cache = <&L2>;
+                       qcom,acc = <&acc1>;
+                       qcom,saw = <&saw1>;
+               };
+
+               CPU2: cpu@2 {
+                       compatible = "arm,cortex-a7";
+                       enable-method = "qcom,msm8226-smp";
+                       device_type = "cpu";
+                       reg = <2>;
+                       next-level-cache = <&L2>;
+                       qcom,acc = <&acc2>;
+                       qcom,saw = <&saw2>;
+               };
+
+               CPU3: cpu@3 {
+                       compatible = "arm,cortex-a7";
+                       enable-method = "qcom,msm8226-smp";
+                       device_type = "cpu";
+                       reg = <3>;
+                       next-level-cache = <&L2>;
+                       qcom,acc = <&acc3>;
+                       qcom,saw = <&saw3>;
+               };
+
+               L2: l2-cache {
+                       compatible = "cache";
+                       cache-level = <2>;
+                       cache-unified;
+               };
+       };
+
        firmware {
                scm {
                        compatible = "qcom,scm-msm8226", "qcom,scm";
                };
        };
 
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0>;
+       };
+
        pmu {
                compatible = "arm,cortex-a7-pmu";
                interrupts = <GIC_PPI 7 (GIC_CPU_MASK_SIMPLE(4) |
                        reg = <0xf9011000 0x1000>;
                };
 
+               saw_l2: power-manager@f9012000 {
+                       compatible = "qcom,msm8226-saw2-v2.1-l2", "qcom,saw2";
+                       reg = <0xf9012000 0x1000>;
+               };
+
+               watchdog@f9017000 {
+                       compatible = "qcom,apss-wdt-msm8226", "qcom,kpss-wdt";
+                       reg = <0xf9017000 0x1000>;
+                       interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 4 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&sleep_clk>;
+               };
+
+               timer@f9020000 {
+                       compatible = "arm,armv7-timer-mem";
+                       reg = <0xf9020000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       frame@f9021000 {
+                               frame-number = <0>;
+                               interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0xf9021000 0x1000>,
+                                     <0xf9022000 0x1000>;
+                       };
+
+                       frame@f9023000 {
+                               frame-number = <1>;
+                               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0xf9023000 0x1000>;
+                               status = "disabled";
+                       };
+
+                       frame@f9024000 {
+                               frame-number = <2>;
+                               interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0xf9024000 0x1000>;
+                               status = "disabled";
+                       };
+
+                       frame@f9025000 {
+                               frame-number = <3>;
+                               interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0xf9025000 0x1000>;
+                               status = "disabled";
+                       };
+
+                       frame@f9026000 {
+                               frame-number = <4>;
+                               interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0xf9026000 0x1000>;
+                               status = "disabled";
+                       };
+
+                       frame@f9027000 {
+                               frame-number = <5>;
+                               interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0xf9027000 0x1000>;
+                               status = "disabled";
+                       };
+
+                       frame@f9028000 {
+                               frame-number = <6>;
+                               interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0xf9028000 0x1000>;
+                               status = "disabled";
+                       };
+               };
+
+               acc0: power-manager@f9088000 {
+                       compatible = "qcom,kpss-acc-v2";
+                       reg = <0xf9088000 0x1000>, <0xf9008000 0x1000>;
+               };
+
+               saw0: power-manager@f9089000 {
+                       compatible = "qcom,msm8226-saw2-v2.1-cpu", "qcom,saw2";
+                       reg = <0xf9089000 0x1000>;
+               };
+
+               acc1: power-manager@f9098000 {
+                       compatible = "qcom,kpss-acc-v2";
+                       reg = <0xf9098000 0x1000>, <0xf9008000 0x1000>;
+               };
+
+               saw1: power-manager@f9099000 {
+                       compatible = "qcom,msm8226-saw2-v2.1-cpu", "qcom,saw2";
+                       reg = <0xf9099000 0x1000>;
+               };
+
+               acc2: power-manager@f90a8000 {
+                       compatible = "qcom,kpss-acc-v2";
+                       reg = <0xf90a8000 0x1000>, <0xf9008000 0x1000>;
+               };
+
+               saw2: power-manager@f90a9000 {
+                       compatible = "qcom,msm8226-saw2-v2.1-cpu", "qcom,saw2";
+                       reg = <0xf90a9000 0x1000>;
+               };
+
+               acc3: power-manager@f90b8000 {
+                       compatible = "qcom,kpss-acc-v2";
+                       reg = <0xf90b8000 0x1000>, <0xf9008000 0x1000>;
+               };
+
+               saw3: power-manager@f90b9000 {
+                       compatible = "qcom,msm8226-saw2-v2.1-cpu", "qcom,saw2";
+                       reg = <0xf90b9000 0x1000>;
+               };
+
                sdhc_1: mmc@f9824900 {
                        compatible = "qcom,msm8226-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
                        status = "disabled";
                };
 
-               sdhc_2: mmc@f98a4900 {
+               sdhc_3: mmc@f9864900 {
                        compatible = "qcom,msm8226-sdhci", "qcom,sdhci-msm-v4";
-                       reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
+                       reg = <0xf9864900 0x11c>, <0xf9864000 0x800>;
                        reg-names = "hc", "core";
-                       interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
-                       clocks = <&gcc GCC_SDCC2_AHB_CLK>,
-                                <&gcc GCC_SDCC2_APPS_CLK>,
+                       clocks = <&gcc GCC_SDCC3_AHB_CLK>,
+                                <&gcc GCC_SDCC3_APPS_CLK>,
                                 <&rpmcc RPM_SMD_XO_CLK_SRC>;
                        clock-names = "iface", "core", "xo";
                        pinctrl-names = "default";
-                       pinctrl-0 = <&sdhc2_default_state>;
+                       pinctrl-0 = <&sdhc3_default_state>;
                        status = "disabled";
                };
 
-               sdhc_3: mmc@f9864900 {
+               sdhc_2: mmc@f98a4900 {
                        compatible = "qcom,msm8226-sdhci", "qcom,sdhci-msm-v4";
-                       reg = <0xf9864900 0x11c>, <0xf9864000 0x800>;
+                       reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
                        reg-names = "hc", "core";
-                       interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
-                       clocks = <&gcc GCC_SDCC3_AHB_CLK>,
-                                <&gcc GCC_SDCC3_APPS_CLK>,
+                       clocks = <&gcc GCC_SDCC2_AHB_CLK>,
+                                <&gcc GCC_SDCC2_APPS_CLK>,
                                 <&rpmcc RPM_SMD_XO_CLK_SRC>;
                        clock-names = "iface", "core", "xo";
                        pinctrl-names = "default";
-                       pinctrl-0 = <&sdhc3_default_state>;
+                       pinctrl-0 = <&sdhc2_default_state>;
                        status = "disabled";
                };
 
                };
 
                blsp1_i2c1: i2c@f9923000 {
-                       status = "disabled";
                        compatible = "qcom,i2c-qup-v2.1.1";
                        reg = <0xf9923000 0x1000>;
                        interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
                        pinctrl-0 = <&blsp1_i2c1_pins>;
                        #address-cells = <1>;
                        #size-cells = <0>;
+                       status = "disabled";
                };
 
                blsp1_i2c2: i2c@f9924000 {
-                       status = "disabled";
                        compatible = "qcom,i2c-qup-v2.1.1";
                        reg = <0xf9924000 0x1000>;
                        interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
                        pinctrl-0 = <&blsp1_i2c2_pins>;
                        #address-cells = <1>;
                        #size-cells = <0>;
+                       status = "disabled";
                };
 
                blsp1_i2c3: i2c@f9925000 {
-                       status = "disabled";
                        compatible = "qcom,i2c-qup-v2.1.1";
                        reg = <0xf9925000 0x1000>;
                        interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
                        pinctrl-0 = <&blsp1_i2c3_pins>;
                        #address-cells = <1>;
                        #size-cells = <0>;
+                       status = "disabled";
                };
 
                blsp1_i2c4: i2c@f9926000 {
-                       status = "disabled";
                        compatible = "qcom,i2c-qup-v2.1.1";
                        reg = <0xf9926000 0x1000>;
                        interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
                        pinctrl-0 = <&blsp1_i2c4_pins>;
                        #address-cells = <1>;
                        #size-cells = <0>;
+                       status = "disabled";
                };
 
                blsp1_i2c5: i2c@f9927000 {
-                       status = "disabled";
                        compatible = "qcom,i2c-qup-v2.1.1";
                        reg = <0xf9927000 0x1000>;
                        interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
                        pinctrl-0 = <&blsp1_i2c5_pins>;
                        #address-cells = <1>;
                        #size-cells = <0>;
+                       status = "disabled";
                };
 
                blsp1_i2c6: i2c@f9928000 {
                        status = "disabled";
                };
 
-               cci: cci@fda0c000 {
-                       compatible = "qcom,msm8226-cci";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       reg = <0xfda0c000 0x1000>;
-                       interrupts = <GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
-                       clocks = <&mmcc CAMSS_TOP_AHB_CLK>,
-                                <&mmcc CAMSS_CCI_CCI_AHB_CLK>,
-                                <&mmcc CAMSS_CCI_CCI_CLK>;
-                       clock-names = "camss_top_ahb",
-                                     "cci_ahb",
-                                     "cci";
-
-                       pinctrl-names = "default", "sleep";
-                       pinctrl-0 = <&cci_default>;
-                       pinctrl-1 = <&cci_sleep>;
-
-                       status = "disabled";
-
-                       cci_i2c0: i2c-bus@0 {
-                               reg = <0>;
-                               clock-frequency = <400000>;
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-                       };
-               };
-
                usb: usb@f9a55000 {
                        compatible = "qcom,ci-hdrc";
                        reg = <0xf9a55000 0x200>,
                        };
                };
 
+               rng@f9bff000 {
+                       compatible = "qcom,prng";
+                       reg = <0xf9bff000 0x200>;
+                       clocks = <&gcc GCC_PRNG_AHB_CLK>;
+                       clock-names = "core";
+               };
+
+               sram@fc190000 {
+                       compatible = "qcom,msm8226-rpm-stats";
+                       reg = <0xfc190000 0x10000>;
+               };
+
                gcc: clock-controller@fc400000 {
                        compatible = "qcom,gcc-msm8226";
                        reg = <0xfc400000 0x4000>;
                                      "sleep_clk";
                };
 
-               mmcc: clock-controller@fd8c0000 {
-                       compatible = "qcom,mmcc-msm8226";
-                       reg = <0xfd8c0000 0x6000>;
-                       #clock-cells = <1>;
-                       #reset-cells = <1>;
-                       #power-domain-cells = <1>;
-
-                       clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
-                                <&gcc GCC_MMSS_GPLL0_CLK_SRC>,
-                                <&gcc GPLL0_VOTE>,
-                                <&gcc GPLL1_VOTE>,
-                                <&rpmcc RPM_SMD_GFX3D_CLK_SRC>,
-                                <&mdss_dsi0_phy 1>,
-                                <&mdss_dsi0_phy 0>;
-                       clock-names = "xo",
-                                     "mmss_gpll0_vote",
-                                     "gpll0_vote",
-                                     "gpll1_vote",
-                                     "gfx3d_clk_src",
-                                     "dsi0pll",
-                                     "dsi0pllbyte";
-               };
-
-               tlmm: pinctrl@fd510000 {
-                       compatible = "qcom,msm8226-pinctrl";
-                       reg = <0xfd510000 0x4000>;
-                       gpio-controller;
-                       #gpio-cells = <2>;
-                       gpio-ranges = <&tlmm 0 0 117>;
-                       interrupt-controller;
-                       #interrupt-cells = <2>;
-                       interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+               rpm_msg_ram: sram@fc428000 {
+                       compatible = "qcom,rpm-msg-ram";
+                       reg = <0xfc428000 0x4000>;
 
-                       blsp1_i2c1_pins: blsp1-i2c1-state {
-                               pins = "gpio2", "gpio3";
-                               function = "blsp_i2c1";
-                               drive-strength = <2>;
-                               bias-disable;
-                       };
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0xfc428000 0x4000>;
 
-                       blsp1_i2c2_pins: blsp1-i2c2-state {
-                               pins = "gpio6", "gpio7";
-                               function = "blsp_i2c2";
-                               drive-strength = <2>;
-                               bias-disable;
+                       apss_master_stats: sram@150 {
+                               reg = <0x150 0x14>;
                        };
 
-                       blsp1_i2c3_pins: blsp1-i2c3-state {
-                               pins = "gpio10", "gpio11";
-                               function = "blsp_i2c3";
-                               drive-strength = <2>;
-                               bias-disable;
+                       mpss_master_stats: sram@b50 {
+                               reg = <0xb50 0x14>;
                        };
 
-                       blsp1_i2c4_pins: blsp1-i2c4-state {
-                               pins = "gpio14", "gpio15";
-                               function = "blsp_i2c4";
-                               drive-strength = <2>;
-                               bias-disable;
+                       lpss_master_stats: sram@1550 {
+                               reg = <0x1550 0x14>;
                        };
 
-                       blsp1_i2c5_pins: blsp1-i2c5-state {
-                               pins = "gpio18", "gpio19";
-                               function = "blsp_i2c5";
-                               drive-strength = <2>;
-                               bias-disable;
+                       pronto_master_stats: sram@1f50 {
+                               reg = <0x1f50 0x14>;
                        };
-
-                       blsp1_i2c6_pins: blsp1-i2c6-state {
-                               pins = "gpio22", "gpio23";
-                               function = "blsp_i2c6";
-                               drive-strength = <2>;
-                               bias-disable;
-                       };
-
-                       cci_default: cci-default-state {
-                               pins = "gpio29", "gpio30";
-                               function = "cci_i2c0";
-
-                               drive-strength = <2>;
-                               bias-disable;
-                       };
-
-                       cci_sleep: cci-sleep-state {
-                               pins = "gpio29", "gpio30";
-                               function = "gpio";
-
-                               drive-strength = <2>;
-                               bias-disable;
-                       };
-
-                       sdhc1_default_state: sdhc1-default-state {
-                               clk-pins {
-                                       pins = "sdc1_clk";
-                                       drive-strength = <10>;
-                                       bias-disable;
-                               };
-
-                               cmd-data-pins {
-                                       pins = "sdc1_cmd", "sdc1_data";
-                                       drive-strength = <10>;
-                                       bias-pull-up;
-                               };
-                       };
-
-                       sdhc2_default_state: sdhc2-default-state {
-                               clk-pins {
-                                       pins = "sdc2_clk";
-                                       drive-strength = <10>;
-                                       bias-disable;
-                               };
-
-                               cmd-data-pins {
-                                       pins = "sdc2_cmd", "sdc2_data";
-                                       drive-strength = <10>;
-                                       bias-pull-up;
-                               };
-                       };
-
-                       sdhc3_default_state: sdhc3-default-state {
-                               clk-pins {
-                                       pins = "gpio44";
-                                       function = "sdc3";
-                                       drive-strength = <8>;
-                                       bias-disable;
-                               };
-
-                               cmd-pins {
-                                       pins = "gpio43";
-                                       function = "sdc3";
-                                       drive-strength = <8>;
-                                       bias-pull-up;
-                               };
-
-                               data-pins {
-                                       pins = "gpio39", "gpio40", "gpio41", "gpio42";
-                                       function = "sdc3";
-                                       drive-strength = <8>;
-                                       bias-pull-up;
-                               };
-                       };
-               };
+               };
 
                tsens: thermal-sensor@fc4a9000 {
                        compatible = "qcom,msm8226-tsens", "qcom,tsens-v0_1";
                        #interrupt-cells = <4>;
                };
 
-               rng@f9bff000 {
-                       compatible = "qcom,prng";
-                       reg = <0xf9bff000 0x200>;
-                       clocks = <&gcc GCC_PRNG_AHB_CLK>;
-                       clock-names = "core";
+               tcsr_mutex: hwlock@fd484000 {
+                       compatible = "qcom,msm8226-tcsr-mutex", "qcom,tcsr-mutex";
+                       reg = <0xfd484000 0x1000>;
+                       #hwlock-cells = <1>;
                };
 
-               timer@f9020000 {
-                       compatible = "arm,armv7-timer-mem";
-                       reg = <0xf9020000 0x1000>;
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges;
-
-                       frame@f9021000 {
-                               frame-number = <0>;
-                               interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
-                                            <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0xf9021000 0x1000>,
-                                     <0xf9022000 0x1000>;
-                       };
+               tlmm: pinctrl@fd510000 {
+                       compatible = "qcom,msm8226-pinctrl";
+                       reg = <0xfd510000 0x4000>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       gpio-ranges = <&tlmm 0 0 117>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
 
-                       frame@f9023000 {
-                               frame-number = <1>;
-                               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0xf9023000 0x1000>;
-                               status = "disabled";
+                       blsp1_i2c1_pins: blsp1-i2c1-state {
+                               pins = "gpio2", "gpio3";
+                               function = "blsp_i2c1";
+                               drive-strength = <2>;
+                               bias-disable;
                        };
 
-                       frame@f9024000 {
-                               frame-number = <2>;
-                               interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0xf9024000 0x1000>;
-                               status = "disabled";
+                       blsp1_i2c2_pins: blsp1-i2c2-state {
+                               pins = "gpio6", "gpio7";
+                               function = "blsp_i2c2";
+                               drive-strength = <2>;
+                               bias-disable;
                        };
 
-                       frame@f9025000 {
-                               frame-number = <3>;
-                               interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0xf9025000 0x1000>;
-                               status = "disabled";
+                       blsp1_i2c3_pins: blsp1-i2c3-state {
+                               pins = "gpio10", "gpio11";
+                               function = "blsp_i2c3";
+                               drive-strength = <2>;
+                               bias-disable;
                        };
 
-                       frame@f9026000 {
-                               frame-number = <4>;
-                               interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0xf9026000 0x1000>;
-                               status = "disabled";
+                       blsp1_i2c4_pins: blsp1-i2c4-state {
+                               pins = "gpio14", "gpio15";
+                               function = "blsp_i2c4";
+                               drive-strength = <2>;
+                               bias-disable;
                        };
 
-                       frame@f9027000 {
-                               frame-number = <5>;
-                               interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0xf9027000 0x1000>;
-                               status = "disabled";
+                       blsp1_i2c5_pins: blsp1-i2c5-state {
+                               pins = "gpio18", "gpio19";
+                               function = "blsp_i2c5";
+                               drive-strength = <2>;
+                               bias-disable;
                        };
 
-                       frame@f9028000 {
-                               frame-number = <6>;
-                               interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0xf9028000 0x1000>;
-                               status = "disabled";
+                       blsp1_i2c6_pins: blsp1-i2c6-state {
+                               pins = "gpio22", "gpio23";
+                               function = "blsp_i2c6";
+                               drive-strength = <2>;
+                               bias-disable;
                        };
-               };
-
-               sram@fc190000 {
-                       compatible = "qcom,msm8226-rpm-stats";
-                       reg = <0xfc190000 0x10000>;
-               };
 
-               rpm_msg_ram: sram@fc428000 {
-                       compatible = "qcom,rpm-msg-ram";
-                       reg = <0xfc428000 0x4000>;
-
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges = <0 0xfc428000 0x4000>;
-
-                       apss_master_stats: sram@150 {
-                               reg = <0x150 0x14>;
-                       };
+                       cci_default: cci-default-state {
+                               pins = "gpio29", "gpio30";
+                               function = "cci_i2c0";
 
-                       mpss_master_stats: sram@b50 {
-                               reg = <0xb50 0x14>;
+                               drive-strength = <2>;
+                               bias-disable;
                        };
 
-                       lpss_master_stats: sram@1550 {
-                               reg = <0x1550 0x14>;
-                       };
+                       cci_sleep: cci-sleep-state {
+                               pins = "gpio29", "gpio30";
+                               function = "gpio";
 
-                       pronto_master_stats: sram@1f50 {
-                               reg = <0x1f50 0x14>;
+                               drive-strength = <2>;
+                               bias-disable;
                        };
-               };
-
-               tcsr_mutex: hwlock@fd484000 {
-                       compatible = "qcom,msm8226-tcsr-mutex", "qcom,tcsr-mutex";
-                       reg = <0xfd484000 0x1000>;
-                       #hwlock-cells = <1>;
-               };
-
-               adsp: remoteproc@fe200000 {
-                       compatible = "qcom,msm8226-adsp-pil";
-                       reg = <0xfe200000 0x100>;
-
-                       interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>,
-                                             <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
-                                             <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
-                                             <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
-                                             <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
-                       interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack";
-
-                       power-domains = <&rpmpd MSM8226_VDDCX>;
-                       power-domain-names = "cx";
-
-                       clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>;
-                       clock-names = "xo";
-
-                       memory-region = <&adsp_region>;
-
-                       qcom,smem-states = <&adsp_smp2p_out 0>;
-                       qcom,smem-state-names = "stop";
 
-                       status = "disabled";
+                       sdhc1_default_state: sdhc1-default-state {
+                               clk-pins {
+                                       pins = "sdc1_clk";
+                                       drive-strength = <10>;
+                                       bias-disable;
+                               };
 
-                       smd-edge {
-                               interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
+                               cmd-data-pins {
+                                       pins = "sdc1_cmd", "sdc1_data";
+                                       drive-strength = <10>;
+                                       bias-pull-up;
+                               };
+                       };
 
-                               qcom,ipc = <&apcs 8 8>;
-                               qcom,smd-edge = <1>;
+                       sdhc2_default_state: sdhc2-default-state {
+                               clk-pins {
+                                       pins = "sdc2_clk";
+                                       drive-strength = <10>;
+                                       bias-disable;
+                               };
 
-                               label = "lpass";
+                               cmd-data-pins {
+                                       pins = "sdc2_cmd", "sdc2_data";
+                                       drive-strength = <10>;
+                                       bias-pull-up;
+                               };
                        };
-               };
 
-               sram@fdd00000 {
-                       compatible = "qcom,msm8226-ocmem";
-                       reg = <0xfdd00000 0x2000>,
-                             <0xfec00000 0x20000>;
-                       reg-names = "ctrl", "mem";
-                       ranges = <0 0xfec00000 0x20000>;
-                       clocks = <&rpmcc RPM_SMD_OCMEMGX_CLK>;
-                       clock-names = "core";
+                       sdhc3_default_state: sdhc3-default-state {
+                               clk-pins {
+                                       pins = "gpio44";
+                                       function = "sdc3";
+                                       drive-strength = <8>;
+                                       bias-disable;
+                               };
 
-                       #address-cells = <1>;
-                       #size-cells = <1>;
+                               cmd-pins {
+                                       pins = "gpio43";
+                                       function = "sdc3";
+                                       drive-strength = <8>;
+                                       bias-pull-up;
+                               };
 
-                       gmu_sram: gmu-sram@0 {
-                               reg = <0x0 0x20000>;
+                               data-pins {
+                                       pins = "gpio39", "gpio40", "gpio41", "gpio42";
+                                       function = "sdc3";
+                                       drive-strength = <8>;
+                                       bias-pull-up;
+                               };
                        };
                };
 
-               sram@fe805000 {
-                       compatible = "qcom,msm8226-imem", "syscon", "simple-mfd";
-                       reg = <0xfe805000 0x1000>;
-
-                       reboot-mode {
-                               compatible = "syscon-reboot-mode";
-                               offset = <0x65c>;
+               mmcc: clock-controller@fd8c0000 {
+                       compatible = "qcom,mmcc-msm8226";
+                       reg = <0xfd8c0000 0x6000>;
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+                       #power-domain-cells = <1>;
 
-                               mode-bootloader = <0x77665500>;
-                               mode-normal = <0x77665501>;
-                               mode-recovery = <0x77665502>;
-                       };
+                       clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
+                                <&gcc GCC_MMSS_GPLL0_CLK_SRC>,
+                                <&gcc GPLL0_VOTE>,
+                                <&gcc GPLL1_VOTE>,
+                                <&rpmcc RPM_SMD_GFX3D_CLK_SRC>,
+                                <&mdss_dsi0_phy 1>,
+                                <&mdss_dsi0_phy 0>;
+                       clock-names = "xo",
+                                     "mmss_gpll0_vote",
+                                     "gpll0_vote",
+                                     "gpll1_vote",
+                                     "gfx3d_clk_src",
+                                     "dsi0pll",
+                                     "dsi0pllbyte";
                };
 
                mdss: display-subsystem@fd900000 {
                        };
                };
 
+               cci: cci@fda0c000 {
+                       compatible = "qcom,msm8226-cci";
+                       reg = <0xfda0c000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&mmcc CAMSS_TOP_AHB_CLK>,
+                                <&mmcc CAMSS_CCI_CCI_AHB_CLK>,
+                                <&mmcc CAMSS_CCI_CCI_CLK>;
+                       clock-names = "camss_top_ahb",
+                                     "cci_ahb",
+                                     "cci";
+
+                       pinctrl-names = "default", "sleep";
+                       pinctrl-0 = <&cci_default>;
+                       pinctrl-1 = <&cci_sleep>;
+
+                       status = "disabled";
+
+                       cci_i2c0: i2c-bus@0 {
+                               reg = <0>;
+                               clock-frequency = <400000>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+               };
+
                gpu: adreno@fdb00000 {
                        compatible = "qcom,adreno-305.18", "qcom,adreno";
                        reg = <0xfdb00000 0x10000>;
                                };
                        };
                };
+
+               sram@fdd00000 {
+                       compatible = "qcom,msm8226-ocmem";
+                       reg = <0xfdd00000 0x2000>,
+                             <0xfec00000 0x20000>;
+                       reg-names = "ctrl", "mem";
+                       ranges = <0 0xfec00000 0x20000>;
+                       clocks = <&rpmcc RPM_SMD_OCMEMGX_CLK>;
+                       clock-names = "core";
+
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       gmu_sram: gmu-sram@0 {
+                               reg = <0x0 0x20000>;
+                       };
+               };
+
+               adsp: remoteproc@fe200000 {
+                       compatible = "qcom,msm8226-adsp-pil";
+                       reg = <0xfe200000 0x100>;
+
+                       interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>,
+                                             <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                                             <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                                             <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                                             <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack";
+
+                       power-domains = <&rpmpd MSM8226_VDDCX>;
+                       power-domain-names = "cx";
+
+                       clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>;
+                       clock-names = "xo";
+
+                       memory-region = <&adsp_region>;
+
+                       qcom,smem-states = <&adsp_smp2p_out 0>;
+                       qcom,smem-state-names = "stop";
+
+                       status = "disabled";
+
+                       smd-edge {
+                               interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
+
+                               qcom,ipc = <&apcs 8 8>;
+                               qcom,smd-edge = <1>;
+
+                               label = "lpass";
+                       };
+               };
+
+               sram@fe805000 {
+                       compatible = "qcom,msm8226-imem", "syscon", "simple-mfd";
+                       reg = <0xfe805000 0x1000>;
+
+                       reboot-mode {
+                               compatible = "syscon-reboot-mode";
+                               offset = <0x65c>;
+
+                               mode-bootloader = <0x77665500>;
+                               mode-normal = <0x77665501>;
+                               mode-recovery = <0x77665502>;
+                       };
+               };
        };
 
        thermal-zones {
index a7c245b9c8f973c27472196ffb7ddf76a1a17670..455ba4bf1bf416027a71c06a126b9799d149516e 100644 (file)
@@ -47,7 +47,7 @@
 
        cpu-pmu {
                compatible = "qcom,scorpion-mp-pmu";
-               interrupts = <1 9 0x304>;
+               interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
        };
 
        clocks {
 
                timer@2000000 {
                        compatible = "qcom,scss-timer", "qcom,msm-timer";
-                       interrupts = <1 0 0x301>,
-                                    <1 1 0x301>,
-                                    <1 2 0x301>;
+                       interrupts = <GIC_PPI 0 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>,
+                                    <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>,
+                                    <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>;
                        reg = <0x02000000 0x100>;
-                       clock-frequency = <27000000>,
-                                         <32768>;
+                       clock-frequency = <27000000>;
                        cpu-offset = <0x40000>;
                };
 
                        gpio-controller;
                        gpio-ranges = <&tlmm 0 0 173>;
                        #gpio-cells = <2>;
-                       interrupts = <0 16 0x4>;
+                       interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
 
                                compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
                                reg = <0x19c40000 0x1000>,
                                      <0x19c00000 0x1000>;
-                               interrupts = <0 195 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&gcc GSBI12_UART_CLK>, <&gcc GSBI12_H_CLK>;
                                clock-names = "core", "iface";
                                status = "disabled";
                        gsbi12_i2c: i2c@19c80000 {
                                compatible = "qcom,i2c-qup-v1.1.1";
                                reg = <0x19c80000 0x1000>;
-                               interrupts = <0 196 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&gcc GSBI12_QUP_CLK>, <&gcc GSBI12_H_CLK>;
                                clock-names = "core", "iface";
                                #address-cells = <1>;
index ed328b24335f4bbaa342a8f47abf15ffb33eb261..3037344eb24055071cc77c9cfce0f1d0f95de921 100644 (file)
                };
 
                unknown@fb00000 {
-                       reg = <0x0fb00000 0x1b00000>;
+                       reg = <0x0fb00000 0x280000>;
+                       no-map;
+               };
+
+               rmtfs@fd80000 {
+                       compatible = "qcom,rmtfs-mem";
+                       reg = <0x0fd80000 0x180000>;
+                       no-map;
+
+                       qcom,client-id = <1>;
+               };
+
+               unknown@ff00000 {
+                       reg = <0x0ff00000 0x1700000>;
                        no-map;
                };
        };
diff --git a/arch/arm/boot/dts/qcom/qcom-msm8926-samsung-matisselte.dts b/arch/arm/boot/dts/qcom/qcom-msm8926-samsung-matisselte.dts
new file mode 100644 (file)
index 0000000..d0e1bc3
--- /dev/null
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Matti Lehtimäki <matti.lehtimaki@gmail.com>
+ * Copyright (c) 2023, Stefan Hansson <newbyte@postmarketos.org>
+ */
+
+/dts-v1/;
+
+#include "qcom-msm8226-samsung-matisse-common.dtsi"
+
+/ {
+       model = "Samsung Galaxy Tab 4 10.1 LTE";
+       compatible = "samsung,matisselte", "qcom,msm8926", "qcom,msm8226";
+       chassis-type = "tablet";
+
+       reg_tsp_3p3v: regulator-tsp-3p3v {
+               compatible = "regulator-fixed";
+               regulator-name = "tsp_3p3v";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               gpio = <&tlmm 32 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&tsp_en1_default_state>;
+       };
+};
+
+&tlmm {
+       tsp_en1_default_state: tsp-en1-default-state {
+               pins = "gpio32";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-disable;
+       };
+};
diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-pins.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8960-pins.dtsi
new file mode 100644 (file)
index 0000000..4fa9827
--- /dev/null
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+&msmgpio {
+       i2c3_default_state: i2c3-default-state {
+               i2c3-pins {
+                       pins = "gpio16", "gpio17";
+                       function = "gsbi3";
+                       drive-strength = <8>;
+                       bias-disable;
+               };
+       };
+
+       i2c3_sleep_state: i2c3-sleep-state {
+               i2c3-pins {
+                       pins = "gpio16", "gpio17";
+                       function = "gpio";
+                       drive-strength = <2>;
+                       bias-bus-hold;
+               };
+       };
+};
index 1a5116336ff0290691a152b14a60676f3d8f9baf..af6cc6393d740d30f3555825175ea6851d406166 100644 (file)
@@ -4,6 +4,9 @@
 
 #include "qcom-msm8960.dtsi"
 #include "pm8921.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/input/gpio-keys.h>
 
 / {
        model = "Samsung Galaxy Express SGH-I437";
        chosen {
                stdout-path = "serial0:115200n8";
        };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&gpio_keys_pin_a>;
+
+               key-home {
+                       label = "Home";
+                       gpios = <&msmgpio 40 GPIO_ACTIVE_LOW>;
+                       debounce-interval = <5>;
+                       linux,code = <KEY_HOMEPAGE>;
+                       wakeup-event-action = <EV_ACT_ASSERTED>;
+                       wakeup-source;
+               };
+
+               key-volume-up {
+                       label = "Volume Up";
+                       gpios = <&msmgpio 50 GPIO_ACTIVE_LOW>;
+                       debounce-interval = <5>;
+                       linux,code = <KEY_VOLUMEUP>;
+               };
+
+               key-volume-down {
+                       label = "Volume Down";
+                       gpios = <&msmgpio 81 GPIO_ACTIVE_LOW>;
+                       debounce-interval = <5>;
+                       linux,code = <KEY_VOLUMEDOWN>;
+               };
+       };
 };
 
 &gsbi5 {
        status = "okay";
 };
 
+&gsbi3 {
+       qcom,mode = <GSBI_PROT_I2C>;
+       status = "okay";
+};
+
+&gsbi3_i2c {
+       status = "okay";
+
+       // Atmel mXT224S touchscreen
+       touchscreen@4a {
+               compatible = "atmel,maxtouch";
+               reg = <0x4a>;
+               interrupt-parent = <&msmgpio>;
+               interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+               vdda-supply = <&pm8921_lvs6>;
+               vdd-supply = <&pm8921_l17>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&touchscreen>;
+       };
+};
+
 &msmgpio {
        spi1_default: spi1-default-state {
                mosi-pins {
                        bias-disable;
                };
        };
+
+       gpio_keys_pin_a: gpio-keys-active-state {
+               pins = "gpio40", "gpio50", "gpio81";
+               function = "gpio";
+               drive-strength = <8>;
+               bias-disable;
+       };
+
+       touchscreen: touchscreen-int-state {
+               pins = "gpio11";
+               function = "gpio";
+               output-enable;
+               bias-disable;
+               drive-strength = <2>;
+       };
 };
 
 &pm8921 {
                };
 
                pm8921_l17: l17 {
-                       regulator-min-microvolt = <1800000>;
+                       regulator-min-microvolt = <3300000>;
                        regulator-max-microvolt = <3300000>;
                        bias-pull-down;
                };
index f420740e068e825d6195d3a85512097449b272d8..922f9e49468a6b9c8898e5080ea0a6408633cff5 100644 (file)
                        #clock-cells = <0>;
                };
 
-               saw0: regulator@2089000 {
-                       compatible = "qcom,saw2";
+               saw0: power-manager@2089000 {
+                       compatible = "qcom,msm8960-saw2-cpu", "qcom,saw2";
                        reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
-                       regulator;
+
+                       saw0_vreg: regulator {
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <1300000>;
+                       };
                };
 
-               saw1: regulator@2099000 {
-                       compatible = "qcom,saw2";
+               saw1: power-manager@2099000 {
+                       compatible = "qcom,msm8960-saw2-cpu", "qcom,saw2";
                        reg = <0x02099000 0x1000>, <0x02009000 0x1000>;
-                       regulator;
+
+                       saw1_vreg: regulator {
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <1300000>;
+                       };
                };
 
                gsbi5: gsbi@16400000 {
                                };
                        };
                };
+
+               gsbi3: gsbi@16200000 {
+                       compatible = "qcom,gsbi-v1.0.0";
+                       reg = <0x16200000 0x100>;
+                       ranges;
+                       cell-index = <3>;
+                       clocks = <&gcc GSBI3_H_CLK>;
+                       clock-names = "iface";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       status = "disabled";
+
+                       gsbi3_i2c: i2c@16280000 {
+                               compatible = "qcom,i2c-qup-v1.1.1";
+                               reg = <0x16280000 0x1000>;
+                               pinctrl-0 = <&i2c3_default_state>;
+                               pinctrl-1 = <&i2c3_sleep_state>;
+                               pinctrl-names = "default", "sleep";
+                               interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&gcc GSBI3_QUP_CLK>,
+                                        <&gcc GSBI3_H_CLK>;
+                               clock-names = "core", "iface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
        };
 };
+#include "qcom-msm8960-pins.dtsi"
index b1413983787c2e2f6a6c38fdad8d97937ec4d0d3..5efc38d712cce272c9b5517b2202721d70119905 100644 (file)
@@ -31,7 +31,7 @@
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
-               interrupts = <GIC_PPI 9 0xf04>;
+               interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
 
                CPU0: cpu@0 {
                        compatible = "qcom,krait";
 
        pmu {
                compatible = "qcom,krait-pmu";
-               interrupts = <GIC_PPI 7 0xf04>;
+               interrupts = <GIC_PPI 7 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
        };
 
        rpm: remoteproc {
                        reg = <0xf9011000 0x1000>;
                };
 
-               saw_l2: power-controller@f9012000 {
-                       compatible = "qcom,saw2";
+               saw_l2: power-manager@f9012000 {
+                       compatible = "qcom,msm8974-saw2-v2.1-l2", "qcom,saw2";
                        reg = <0xf9012000 0x1000>;
-                       regulator;
                };
 
                watchdog@f9017000 {
                        reg = <0xf9088000 0x1000>, <0xf9008000 0x1000>;
                };
 
-               saw0: power-controller@f9089000 {
+               saw0: power-manager@f9089000 {
                        compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2";
                        reg = <0xf9089000 0x1000>, <0xf9009000 0x1000>;
                };
                        reg = <0xf9098000 0x1000>, <0xf9008000 0x1000>;
                };
 
-               saw1: power-controller@f9099000 {
+               saw1: power-manager@f9099000 {
                        compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2";
                        reg = <0xf9099000 0x1000>, <0xf9009000 0x1000>;
                };
                        reg = <0xf90a8000 0x1000>, <0xf9008000 0x1000>;
                };
 
-               saw2: power-controller@f90a9000 {
+               saw2: power-manager@f90a9000 {
                        compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2";
                        reg = <0xf90a9000 0x1000>, <0xf9009000 0x1000>;
                };
                        reg = <0xf90b8000 0x1000>, <0xf9008000 0x1000>;
                };
 
-               saw3: power-controller@f90b9000 {
+               saw3: power-manager@f90b9000 {
                        compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2";
                        reg = <0xf90b9000 0x1000>, <0xf9009000 0x1000>;
                };
                        status = "disabled";
                        compatible = "qcom,i2c-qup-v2.1.1";
                        reg = <0xf9923000 0x1000>;
-                       interrupts = <0 95 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
                        clock-names = "core", "iface";
                        pinctrl-names = "default", "sleep";
                        status = "disabled";
                        compatible = "qcom,i2c-qup-v2.1.1";
                        reg = <0xf9925000 0x1000>;
-                       interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc GCC_BLSP1_QUP3_I2C_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
                        clock-names = "core", "iface";
                        pinctrl-names = "default", "sleep";
                        status = "disabled";
                        compatible = "qcom,i2c-qup-v2.1.1";
                        reg = <0xf9968000 0x1000>;
-                       interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc GCC_BLSP2_QUP6_I2C_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
                        clock-names = "core", "iface";
                        pinctrl-names = "default", "sleep";
 
                qfprom: qfprom@fc4bc000 {
                        compatible = "qcom,msm8974-qfprom", "qcom,qfprom";
-                       reg = <0xfc4bc000 0x1000>;
+                       reg = <0xfc4bc000 0x2100>;
                        #address-cells = <1>;
                        #size-cells = <1>;
 
 
        timer {
                compatible = "arm,armv7-timer";
-               interrupts = <GIC_PPI 2 0xf08>,
-                            <GIC_PPI 3 0xf08>,
-                            <GIC_PPI 4 0xf08>,
-                            <GIC_PPI 1 0xf08>;
+               interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
                clock-frequency = <19200000>;
        };
 };
index 2045fc779f887030735f9310982bdef228f8a481..edc9aaf828c8395c5ebf299003d4fc9c80d1e592 100644 (file)
                                          "msi8";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
-                       interrupt-map = <0 0 0 1 &intc 0 0 0 141 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
-                                       <0 0 0 2 &intc 0 0 0 142 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
-                                       <0 0 0 3 &intc 0 0 0 143 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
-                                       <0 0 0 4 &intc 0 0 0 144 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
+                       interrupt-map = <0 0 0 1 &intc 0 141 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
+                                       <0 0 0 2 &intc 0 142 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
+                                       <0 0 0 3 &intc 0 143 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
+                                       <0 0 0 4 &intc 0 144 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
 
                        clocks = <&gcc GCC_PCIE_PIPE_CLK>,
                                 <&gcc GCC_PCIE_AUX_CLK>,
                                          <&gcc GCC_USB30_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <200000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 51 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 10 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 11 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 10 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq",
-                                         "dm_hs_phy_irq", "dp_hs_phy_irq";
+                                             <&pdc 51 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_GDSC>;
 
 
                        frame@17821000 {
                                frame-number = <0>;
-                               interrupts = <GIC_SPI 7 0x4>,
-                                            <GIC_SPI 6 0x4>;
+                               interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17821000 0x1000>,
                                      <0x17822000 0x1000>;
                        };
 
                        frame@17823000 {
                                frame-number = <1>;
-                               interrupts = <GIC_SPI 8 0x4>;
+                               interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17823000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17824000 {
                                frame-number = <2>;
-                               interrupts = <GIC_SPI 9 0x4>;
+                               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17824000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17825000 {
                                frame-number = <3>;
-                               interrupts = <GIC_SPI 10 0x4>;
+                               interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17825000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17826000 {
                                frame-number = <4>;
-                               interrupts = <GIC_SPI 11 0x4>;
+                               interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17826000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17827000 {
                                frame-number = <5>;
-                               interrupts = <GIC_SPI 12 0x4>;
+                               interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17827000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17828000 {
                                frame-number = <6>;
-                               interrupts = <GIC_SPI 13 0x4>;
+                               interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17828000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17829000 {
                                frame-number = <7>;
-                               interrupts = <GIC_SPI 14 0x4>;
+                               interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17829000 0x1000>;
                                status = "disabled";
                        };
index 40591a4da6a42fb7d0c0695e0e70c212a2b64c09..a949454212e942755fa3ca228bd0bfc2e8ee6ce2 100644 (file)
                        clocks = <&gcc GCC_USB30_SLV_AHB_CLK>,
                                 <&gcc GCC_USB30_MASTER_CLK>,
                                 <&gcc GCC_USB30_MSTR_AXI_CLK>,
-                                <&gcc GCC_USB30_MOCK_UTMI_CLK>,
-                                <&gcc GCC_USB30_SLEEP_CLK>;
-                       clock-names = "cfg_noc", "core", "iface", "mock_utmi",
-                                       "sleep";
+                                <&gcc GCC_USB30_SLEEP_CLK>,
+                                <&gcc GCC_USB30_MOCK_UTMI_CLK>;
+                       clock-names = "cfg_noc", "core", "iface", "sleep",
+                                     "mock_utmi";
 
                        assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>,
                                          <&gcc GCC_USB30_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <200000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 76 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 19 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 18 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 19 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq",
-                                         "ss_phy_irq",
+                                             <&pdc 76 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
                                          "dm_hs_phy_irq",
-                                         "dp_hs_phy_irq";
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_GDSC>;
 
 
                        frame@17821000 {
                                frame-number = <0>;
-                               interrupts = <GIC_SPI 7 0x4>,
-                                            <GIC_SPI 6 0x4>;
+                               interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17821000 0x1000>,
                                      <0x17822000 0x1000>;
                        };
 
                        frame@17823000 {
                                frame-number = <1>;
-                               interrupts = <GIC_SPI 8 0x4>;
+                               interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17823000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17824000 {
                                frame-number = <2>;
-                               interrupts = <GIC_SPI 9 0x4>;
+                               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17824000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17825000 {
                                frame-number = <3>;
-                               interrupts = <GIC_SPI 10 0x4>;
+                               interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17825000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17826000 {
                                frame-number = <4>;
-                               interrupts = <GIC_SPI 11 0x4>;
+                               interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17826000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17827000 {
                                frame-number = <5>;
-                               interrupts = <GIC_SPI 12 0x4>;
+                               interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17827000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17828000 {
                                frame-number = <6>;
-                               interrupts = <GIC_SPI 13 0x4>;
+                               interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17828000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17829000 {
                                frame-number = <7>;
-                               interrupts = <GIC_SPI 14 0x4>;
+                               interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <0x17829000 0x1000>;
                                status = "disabled";
                        };
 
        timer {
                compatible = "arm,armv7-timer";
-               interrupts = <1 13 0xf08>,
-                       <1 12 0xf08>,
-                       <1 10 0xf08>,
-                       <1 11 0xf08>;
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 12 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
                clock-frequency = <19200000>;
        };
 };
index ed75c01dbee10b140fb1e49531cd6ac9120a5deb..3d02f065f71c27c1bfdb1b8451e1005eb271f0fc 100644 (file)
        status = "okay";
 };
 
+&extal1_clk {
+       clock-frequency = <26000000>;
+};
+
+&extal2_clk {
+       clock-frequency = <48000000>;
+};
+
+&extalr_clk {
+       clock-frequency = <32768>;
+};
+
 &pfc {
        scifa0_pins: scifa0 {
                groups = "scifa0_data";
index c39066967053f06b37e879ce4c147172ec249d7f..ac654ff45d0e9a9c78ff2c94870b2b2b188075f5 100644 (file)
                extalr_clk: extalr {
                        compatible = "fixed-clock";
                        #clock-cells = <0>;
-                       clock-frequency = <32768>;
+                       /* This value must be overridden by the board. */
+                       clock-frequency = <0>;
                };
                extal1_clk: extal1 {
                        compatible = "fixed-clock";
                        #clock-cells = <0>;
-                       clock-frequency = <25000000>;
+                       /* This value must be overridden by the board. */
+                       clock-frequency = <0>;
                };
                extal2_clk: extal2 {
                        compatible = "fixed-clock";
                        #clock-cells = <0>;
-                       clock-frequency = <48000000>;
+                       /* This value must be overridden by the board. */
+                       clock-frequency = <0>;
                };
                fsiack_clk: fsiack {
                        compatible = "fixed-clock";
                        clock-div = <2>;
                        clock-mult = <1>;
                };
+               cp_clk: cp {
+                       compatible = "fixed-factor-clock";
+                       clocks = <&main_div2_clk>;
+                       #clock-cells = <0>;
+                       clock-div = <1>;
+                       clock-mult = <1>;
+               };
                pll0_div2_clk: pll0_div2 {
                        compatible = "fixed-factor-clock";
                        clocks = <&cpg_clocks R8A73A4_CLK_PLL0>;
                mstp4_clks: mstp4_clks@e6150140 {
                        compatible = "renesas,r8a73a4-mstp-clocks", "renesas,cpg-mstp-clocks";
                        reg = <0 0xe6150140 0 4>, <0 0xe615004c 0 4>;
-                       clocks = <&main_div2_clk>, <&cpg_clocks R8A73A4_CLK_ZS>,
-                                <&main_div2_clk>,
-                                <&cpg_clocks R8A73A4_CLK_HP>,
+                       clocks = <&cp_clk>, <&cpg_clocks R8A73A4_CLK_ZS>,
+                                <&cp_clk>, <&cpg_clocks R8A73A4_CLK_HP>,
                                 <&cpg_clocks R8A73A4_CLK_HP>;
                        #clock-cells = <1>;
                        clock-indices = <
                mstp5_clks: mstp5_clks@e6150144 {
                        compatible = "renesas,r8a73a4-mstp-clocks", "renesas,cpg-mstp-clocks";
                        reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>;
-                       clocks = <&extal2_clk>, <&cpg_clocks R8A73A4_CLK_HP>;
+                       clocks = <&cp_clk>, <&cpg_clocks R8A73A4_CLK_HP>;
                        #clock-cells = <1>;
                        clock-indices = <
                                R8A73A4_CLK_THERMAL R8A73A4_CLK_IIC8
index 55884ec701f8dab49ee2223dd0b9e03df7a07262..d13ab86c3ab47e37f6edd3beeaa785cb00e9abe5 100644 (file)
                interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "tuni0", "tuni1", "tuni2";
                clocks = <&mstp1_clks R8A7740_CLK_TMU0>;
                clock-names = "fck";
                power-domains = <&pd_a4r>;
                interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "tuni0", "tuni1", "tuni2";
                clocks = <&mstp1_clks R8A7740_CLK_TMU1>;
                clock-names = "fck";
                power-domains = <&pd_a4r>;
index 8d4530ed2fc6ad15c1b5f155edb814b06d9ae676..b80e832c92775756c8d964221363505d0dccdb5f 100644 (file)
                reg = <0xffd80000 0x30>;
                interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+                            <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                clocks = <&mstp0_clks R8A7778_CLK_TMU0>;
                clock-names = "fck";
                power-domains = <&cpg_clocks>;
                reg = <0xffd81000 0x30>;
                interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+                            <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                clocks = <&mstp0_clks R8A7778_CLK_TMU1>;
                clock-names = "fck";
                power-domains = <&cpg_clocks>;
                interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "tuni0", "tuni1", "tuni2";
                clocks = <&mstp0_clks R8A7778_CLK_TMU2>;
                clock-names = "fck";
                power-domains = <&cpg_clocks>;
                reg =   <0xffd90000 0x1000>,    /* SRU */
                        <0xffd91000 0x240>,     /* SSI */
                        <0xfffe0000 0x24>;      /* ADG */
+               reg-names = "sru", "ssi", "adg";
+
                clocks = <&mstp3_clks R8A7778_CLK_SSI8>,
                        <&mstp3_clks R8A7778_CLK_SSI7>,
                        <&mstp3_clks R8A7778_CLK_SSI6>,
index 7743af5e2a6f8025bb3f89a566f486921fedadd5..1944703cba4fc53be6a0a46fd8fb9a12137a418b 100644 (file)
                reg = <0xffd80000 0x30>;
                interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+                            <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                clocks = <&mstp0_clks R8A7779_CLK_TMU0>;
                clock-names = "fck";
                power-domains = <&sysc R8A7779_PD_ALWAYS_ON>;
                reg = <0xffd81000 0x30>;
                interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+                            <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                clocks = <&mstp0_clks R8A7779_CLK_TMU1>;
                clock-names = "fck";
                power-domains = <&sysc R8A7779_PD_ALWAYS_ON>;
                interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "tuni0", "tuni1", "tuni2";
                clocks = <&mstp0_clks R8A7779_CLK_TMU2>;
                clock-names = "fck";
                power-domains = <&sysc R8A7779_PD_ALWAYS_ON>;
index 2fba4d084001b9646ee012eb967e96a27695bfa6..8590981245a62057c2b61370e57a7627f36496e8 100644 (file)
                        interrupt-parent = <&irqc0>;
                        interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
                        interrupt-controller;
+                       #interrupt-cells = <2>;
 
                        rtc {
                                compatible = "dlg,da9063-rtc";
index f9bc5b4f019d02136aa99631c1b2e8c67e9651de..683f7395fab0b6961e5f00a3985fc9b690469237 100644 (file)
                interrupt-parent = <&irqc0>;
                interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
                interrupt-controller;
+               #interrupt-cells = <2>;
 
                onkey {
                        compatible = "dlg,da9063-onkey";
index e9c13bb03772af44eada731a13b5ee88a2e3de7c..0efd9f98c75aced03009396d1c6e6ac023d84c4a 100644 (file)
                interrupt-parent = <&irqc0>;
                interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
                interrupt-controller;
+               #interrupt-cells = <2>;
 
                rtc {
                        compatible = "dlg,da9063-rtc";
index 7e8bc06715f6564badf502267a33c3737c206cf9..93c86e9216455577271652dcbeb8623faba69885 100644 (file)
                interrupt-parent = <&irqc0>;
                interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
                interrupt-controller;
+               #interrupt-cells = <2>;
 
                watchdog {
                        compatible = "dlg,da9063-watchdog";
index 4f9838cf97ee4fb608b27bfc3d637edee39f3c95..540a9ad28f28ac1a08c7b4f5d3e6a23bcfc262e0 100644 (file)
                interrupt-parent = <&irqc>;
                interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
                interrupt-controller;
+               #interrupt-cells = <2>;
 
                rtc {
                        compatible = "dlg,da9063-rtc";
index 1744fdbf9e0ce08d2a30180e1462dd46a18152f9..1ea6c757893bc0bf5ae4d7c6a6c91854939f9b3f 100644 (file)
                interrupt-parent = <&irqc0>;
                interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
                interrupt-controller;
+               #interrupt-cells = <2>;
 
                rtc {
                        compatible = "dlg,da9063-rtc";
index c0d067df22a03d4e2590333965c7c8d7a6f539d6..b5ecafbb2e4de582e4449e7abba6217d4e35dcdb 100644 (file)
                interrupt-parent = <&gpio3>;
                interrupts = <31 IRQ_TYPE_LEVEL_LOW>;
                interrupt-controller;
+               #interrupt-cells = <2>;
 
                rtc {
                        compatible = "dlg,da9063-rtc";
index 43d480a7f3eacc21636788f15e2b27ce3d4dec43..595e074085eb4cd3cf9ad84d59b138051302ef5e 100644 (file)
                interrupt-parent = <&gpio3>;
                interrupts = <31 IRQ_TYPE_LEVEL_LOW>;
                interrupt-controller;
+               #interrupt-cells = <2>;
 
                onkey {
                        compatible = "dlg,da9063-onkey";
index 03a97881519a6ac7d3c88d2df7f1e8f9aae2ef07..21c1678f4e916b17e9130b5d3736d0d989d67863 100644 (file)
                regulator-boot-on;
        };
 
+       hdmi-connnector {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&hdmi_connector_out>;
+                       };
+               };
+       };
+
        /*
         * This is a vbus-supply, which also supplies the GL852G usb hub,
         * thus has to be always-on
        cpu-supply = <&vdd_arm>;
 };
 
+&display_subsystem {
+       status = "okay";
+};
+
 &emmc {
        bus-width = <8>;
        vmmc-supply = <&vcc_io>;
        status = "okay";
 };
 
+&hdmi {
+       status = "okay";
+};
+
+&hdmi_out {
+       hdmi_connector_out: endpoint {
+               remote-endpoint = <&hdmi_connector_in>;
+       };
+};
+
 &mdio {
        phy0: ethernet-phy@1 {
                compatible = "ethernet-phy-ieee802.3-c22";
 &usb2phy_otg {
        status = "okay";
 };
+
+&vop {
+       status = "okay";
+};
index e2264c40b924c6feef5822b3430f0aaf4ef02823..fb98873fd94e5994134a6107cadfeae57903ddb7 100644 (file)
                };
        };
 
+       display_subsystem: display-subsystem {
+               compatible = "rockchip,display-subsystem";
+               ports = <&vop_out>;
+               status = "disabled";
+       };
+
        gpu_opp_table: opp-table-1 {
                compatible = "operating-points-v2";
 
                };
        };
 
+       vop: vop@1010e000 {
+               compatible = "rockchip,rk3126-vop";
+               reg = <0x1010e000 0x300>;
+               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru ACLK_LCDC0>, <&cru DCLK_VOP>,
+                        <&cru HCLK_LCDC0>;
+               clock-names = "aclk_vop", "dclk_vop",
+                             "hclk_vop";
+               resets = <&cru SRST_VOP_A>, <&cru SRST_VOP_H>,
+                        <&cru SRST_VOP_D>;
+               reset-names = "axi", "ahb",
+                             "dclk";
+               power-domains = <&power RK3128_PD_VIO>;
+               status = "disabled";
+
+               vop_out: port {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       vop_out_hdmi: endpoint@0 {
+                               reg = <0>;
+                               remote-endpoint = <&hdmi_in_vop>;
+                       };
+               };
+       };
+
        qos_gpu: qos@1012d000 {
                compatible = "rockchip,rk3128-qos", "syscon";
                reg = <0x1012d000 0x20>;
                };
        };
 
+       hdmi: hdmi@20034000 {
+               compatible = "rockchip,rk3128-inno-hdmi";
+               reg = <0x20034000 0x4000>;
+               interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru PCLK_HDMI>, <&cru DCLK_VOP>;
+               clock-names = "pclk", "ref";
+               pinctrl-names = "default";
+               pinctrl-0 = <&hdmii2c_xfer &hdmi_hpd &hdmi_cec>;
+               power-domains = <&power RK3128_PD_VIO>;
+               status = "disabled";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       hdmi_in: port@0 {
+                               reg = <0>;
+                               hdmi_in_vop: endpoint {
+                                       remote-endpoint = <&vop_out_hdmi>;
+                               };
+                       };
+
+                       hdmi_out: port@1 {
+                               reg = <1>;
+                       };
+               };
+       };
+
        timer0: timer@20044000 {
                compatible = "rockchip,rk3128-timer", "rockchip,rk3288-timer";
                reg = <0x20044000 0x20>;
index 831561fc18146016771d539f82c26fa13637746c..96421355c2746a0ed9f589e5936e15934fd4bf13 100644 (file)
                status = "disabled";
 
                ports {
-                       hdmi_in: port {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-                               hdmi_in_vop: endpoint@0 {
-                                       reg = <0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       hdmi_in: port@0 {
+                               reg = <0>;
+
+                               hdmi_in_vop: endpoint {
                                        remote-endpoint = <&vop_out_hdmi>;
                                };
                        };
+
+                       hdmi_out: port@1 {
+                               reg = <1>;
+                       };
                };
        };
 
index ead343dc3df101a4ab98c4383f6302f600195597..3f1d640afafaed7e79e15d38910c86129eff7eae 100644 (file)
                compatible = "rockchip,rk3288-dw-hdmi";
                reg = <0x0 0xff980000 0x0 0x20000>;
                reg-io-width = <4>;
-               #sound-dai-cells = <0>;
-               rockchip,grf = <&grf>;
                interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru  PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>, <&cru SCLK_HDMI_CEC>;
                clock-names = "iahb", "isfr", "cec";
                power-domains = <&power RK3288_PD_VIO>;
+               rockchip,grf = <&grf>;
+               #sound-dai-cells = <0>;
                status = "disabled";
 
                ports {
-                       hdmi_in: port {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       hdmi_in: port@0 {
+                               reg = <0>;
                                #address-cells = <1>;
                                #size-cells = <0>;
+
                                hdmi_in_vopb: endpoint@0 {
                                        reg = <0>;
                                        remote-endpoint = <&vopb_out_hdmi>;
                                };
+
                                hdmi_in_vopl: endpoint@1 {
                                        reg = <1>;
                                        remote-endpoint = <&vopl_out_hdmi>;
                                };
                        };
+
+                       hdmi_out: port@1 {
+                               reg = <1>;
+                       };
                };
        };
 
index abf3006f0a842435b9d56750e805fe93261649c6..f3291f3bbc6fd2b480e975632847f9310c082225 100644 (file)
        pwm4: pwm@10280000 {
                compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm";
                reg = <0x10280000 0x10>;
-               interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>;
                clock-names = "pwm", "pclk";
                pinctrl-names = "default";
        pwm5: pwm@10280010 {
                compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm";
                reg = <0x10280010 0x10>;
-               interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>;
                clock-names = "pwm", "pclk";
                pinctrl-names = "default";
        pwm6: pwm@10280020 {
                compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm";
                reg = <0x10280020 0x10>;
-               interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>;
                clock-names = "pwm", "pclk";
                pinctrl-names = "default";
        pwm7: pwm@10280030 {
                compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm";
                reg = <0x10280030 0x10>;
-               interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>;
                clock-names = "pwm", "pclk";
                pinctrl-names = "default";
        pwm0: pwm@20040000 {
                compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm";
                reg = <0x20040000 0x10>;
-               interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru SCLK_PWM0_PMU>, <&cru PCLK_PWM0_PMU>;
                clock-names = "pwm", "pclk";
                pinctrl-names = "default";
        pwm1: pwm@20040010 {
                compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm";
                reg = <0x20040010 0x10>;
-               interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru SCLK_PWM0_PMU>, <&cru PCLK_PWM0_PMU>;
                clock-names = "pwm", "pclk";
                pinctrl-names = "default";
        pwm2: pwm@20040020 {
                compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm";
                reg = <0x20040020 0x10>;
-               interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru SCLK_PWM0_PMU>, <&cru PCLK_PWM0_PMU>;
                clock-names = "pwm", "pclk";
                pinctrl-names = "default";
        pwm3: pwm@20040030 {
                compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm";
                reg = <0x20040030 0x10>;
-               interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru SCLK_PWM0_PMU>, <&cru PCLK_PWM0_PMU>;
                clock-names = "pwm", "pclk";
                pinctrl-names = "default";
index 32b329e87a0cd3f880d123c832c265d54b9b1b4c..9a87dc0d5f66b67da3fec0bba8820845a2f7b1ce 100644 (file)
@@ -8,6 +8,8 @@
        aliases {
                ethernet0 = &gmac;
                mmc0 = &emmc;
+               mmc1 = &sdio;
+               mmc2 = &sdmmc;
        };
 
        chosen {
        pmuio1-supply = <&vcc3v3_sys>;
        vccio1-supply = <&vcc_1v8>;
        vccio2-supply = <&vccio_sd>;
-       vccio3-supply = <&vcc_1v8>;
+       vccio3-supply = <&vcc3v3_sd>;
        vccio4-supply = <&vcc_dovdd>;
        vccio5-supply = <&vcc_1v8>;
        vccio6-supply = <&vcc_1v8>;
        cap-sd-highspeed;
        cap-sdio-irq;
        keep-power-in-suspend;
-       max-frequency = <100000000>;
+       max-frequency = <50000000>;
        mmc-pwrseq = <&sdio_pwrseq>;
        non-removable;
        pinctrl-names = "default";
        pinctrl-0 = <&sdmmc1_clk &sdmmc1_cmd &sdmmc1_bus4>;
        rockchip,default-sample-phase = <90>;
-       sd-uhs-sdr104;
-       vmmc-supply = <&vcc3v3_sys>;
+       sd-uhs-sdr50;
+       vmmc-supply = <&vcc3v3_sd>;
        vqmmc-supply = <&vcc_1v8>;
        status = "okay";
 };
index 61aca5798f388dd3c33949bf648e40ae65efdc53..b79d456e976dfdd7514a75cb03c6d73b08ce950d 100644 (file)
@@ -18,7 +18,7 @@
 
        memory@40000000 {
                device_type = "memory";
-               reg = <0x40000000 0x40000000>;
+               reg = <0x40000000 0x3fc00000>;
        };
 };
 
index 77083f1a827314e8f8638224d74ed66382ffd7c8..1048ef5d9bc3ba7b10bd65cff9ebe6f3ba1fd14d 100644 (file)
@@ -11,7 +11,7 @@
 
        memory@40000000 {
                device_type = "memory";
-               reg = <0x40000000 0x80000000>;
+               reg = <0x40000000 0x7fc00000>;
        };
 };
 
index 0a151437fc7349d6258a208ff5488ed114e0d9b3..eee1000dea922793e343d95ffd2accd9d2407139 100644 (file)
@@ -9,7 +9,7 @@
 
        memory@40000000 {
                device_type = "memory";
-               reg = <0x40000000 0x80000000>;
+               reg = <0x40000000 0x7fc00000>;
        };
 
        /* bootargs are passed in by bootloader */
index 0b89d5682f857cc8a10fb5655866d2184e4d3cfa..28a6058027335e6af91e55bda8292e83a87a33aa 100644 (file)
@@ -23,7 +23,7 @@
 
        memory@40000000 {
                device_type = "memory";
-               reg = <0x40000000 0x80000000>;
+               reg = <0x40000000 0x7fc00000>;
        };
 
        aliases {
        status = "okay";
 };
 
+&i2c_1 {
+       samsung,i2c-sda-delay = <100>;
+       samsung,i2c-slave-addr = <0x10>;
+       samsung,i2c-max-bus-freq = <400000>;
+       pinctrl-0 = <&i2c1_bus>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       accelerometer@19 {
+               compatible = "st,lsm330dlc-accel";
+               reg = <0x19>;
+               interrupt-parent = <&gpx0>;
+               interrupts = <0 IRQ_TYPE_EDGE_RISING>;
+               pinctrl-0 = <&accelerometer_irq>;
+               pinctrl-names = "default";
+               mount-matrix =  "1",  "0",  "0",
+                               "0", "-1",  "0",
+                               "0",  "0", "-1";
+       };
+
+       gyro@6b {
+               compatible = "st,lsm330dlc-gyro";
+               reg = <0x6b>;
+               interrupt-parent = <&gpx0>;
+               interrupts = <6 IRQ_TYPE_EDGE_RISING>;
+               pinctrl-0 = <&gyro_data_enable &gyro_irq>;
+               pinctrl-names = "default";
+               mount-matrix =  "1",  "0",  "0",
+                               "0", "-1",  "0",
+                               "0",  "0", "-1";
+       };
+};
+
 &i2c_3 {
        samsung,i2c-sda-delay = <100>;
        samsung,i2c-slave-addr = <0x10>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
        };
 
+       gyro_data_enable: gyro-data-enable-pins {
+               samsung,pins = "gpl2-0";
+               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+       };
+
        uart_sel: uart-sel-pins {
                samsung,pins = "gpl2-7";
                samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
        };
 
+       accelerometer_irq: accelerometer-irq-pins {
+               samsung,pins = "gpx0-0";
+               samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+               samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+       };
+
        stmpe_adc_irq: stmpe-adc-irq-pins {
                samsung,pins = "gpx0-1";
                samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
        };
 
+       gyro_irq: gyro-irq-pins {
+               samsung,pins = "gpx0-6";
+               samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+               samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+       };
+
        max77686_irq: max77686-irq-pins {
                samsung,pins = "gpx0-7";
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
index f525b2f5e4e083ba499dc0ad11866fb78146f37c..246040967082551d4e136e3ec68f79d522c07030 100644 (file)
@@ -30,6 +30,7 @@
 
        aliases {
                mmc0 = &mmc_0;
+               mmc1 = &mmc_1;
                mmc2 = &mmc_2;
        };
 
@@ -39,7 +40,7 @@
 
        memory@20000000 {
                device_type = "memory";
-               reg = <0x20000000 0xc0000000>;
+               reg = <0x20000000 0xbfa00000>;
        };
 
        firmware@2073000 {
                        linux,code = <KEY_VOLUMEDOWN>;
                };
        };
+
+       mmc1_pwrseq: pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               reset-gpios = <&gpy7 7 GPIO_ACTIVE_LOW>;
+               clocks = <&s2mps11_osc S2MPS11_CLK_BT>;
+               clock-names = "ext_clock";
+       };
 };
 
 &cci {
        vqmmc-supply = <&ldo3_reg>;
 };
 
+/* WiFi */
+&mmc_1 {
+       bus-width = <4>;
+       cap-sd-highspeed;
+       cap-sdio-irq;
+       card-detect-delay = <200>;
+       keep-power-in-suspend;
+       mmc-pwrseq = <&mmc1_pwrseq>;
+       non-removable;
+       pinctrl-0 = <&sd1_clk>, <&sd1_cmd>, <&sd1_int>, <&sd1_bus1>,
+                   <&sd1_bus4>, <&wifi_en>;
+       pinctrl-names = "default";
+       vqmmc-supply = <&ldo2_reg>;
+       samsung,dw-mshc-ciu-div = <1>;
+       samsung,dw-mshc-ddr-timing = <0 2>;
+       samsung,dw-mshc-sdr-timing = <0 1>;
+       status = "okay";
+};
+
 /* External sdcard */
 &mmc_2 {
        status = "okay";
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
                samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
        };
+
+       wifi_en: wifi-en-pins {
+               samsung,pins = "gpy7-7";
+               samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+       };
 };
 
 &rtc {
index 4e757b6e28e1caee77fd0f0cd2efd4402a831703..3759742d38cac21ab63d929b0cd25c76fa3db94e 100644 (file)
                reg = <0>;
                spi-max-frequency = <3125000>;
                google,has-vbc-nvram;
+               wakeup-source;
 
                controller-data {
                        samsung,spi-feedback-delay = <1>;
index b4a851aa88814386c8969c2aa52843e6a7dbcdee..4a4c55a4beb369146f8c99aed457e14b7953ba78 100644 (file)
@@ -55,7 +55,7 @@
        thermal-zones {
                cpu0_thermal: cpu0-thermal {
                        thermal-sensors = <&tmu_cpu0>;
-                       polling-delay-passive = <250>;
+                       polling-delay-passive = <0>;
                        polling-delay = <0>;
                        trips {
                                cpu0_alert0: cpu-alert-0 {
                                        hysteresis = <0>; /* millicelsius */
                                        type = "critical";
                                };
-                               /*
-                                * Exynos542x supports only 4 trip-points
-                                * so for these polling mode is required.
-                                * Start polling at temperature level of last
-                                * interrupt-driven trip: cpu0_alert2
-                                */
                                cpu0_alert3: cpu-alert-3 {
                                        temperature = <70000>; /* millicelsius */
                                        hysteresis = <10000>; /* millicelsius */
                };
                cpu1_thermal: cpu1-thermal {
                        thermal-sensors = <&tmu_cpu1>;
-                       polling-delay-passive = <250>;
+                       polling-delay-passive = <0>;
                        polling-delay = <0>;
                        trips {
                                cpu1_alert0: cpu-alert-0 {
                };
                cpu2_thermal: cpu2-thermal {
                        thermal-sensors = <&tmu_cpu2>;
-                       polling-delay-passive = <250>;
+                       polling-delay-passive = <0>;
                        polling-delay = <0>;
                        trips {
                                cpu2_alert0: cpu-alert-0 {
                };
                cpu3_thermal: cpu3-thermal {
                        thermal-sensors = <&tmu_cpu3>;
-                       polling-delay-passive = <250>;
+                       polling-delay-passive = <0>;
                        polling-delay = <0>;
                        trips {
                                cpu3_alert0: cpu-alert-0 {
                };
                gpu_thermal: gpu-thermal {
                        thermal-sensors = <&tmu_gpu>;
-                       polling-delay-passive = <250>;
+                       polling-delay-passive = <0>;
                        polling-delay = <0>;
                        trips {
                                gpu_alert0: gpu-alert-0 {
index f91bc4ae008e43928de3c269b380c59d59cbce26..9bbbdce9103a66c763e74eb28adb8630ac18228a 100644 (file)
                reg = <0>;
                spi-max-frequency = <3125000>;
                google,has-vbc-nvram;
+               wakeup-source;
 
                controller-data {
                        samsung,spi-feedback-delay = <1>;
index 7892ad69b44152609c028852167ff56279e7ddca..9fedd6776208e38d8dd8e92ab2de317fa18db4ae 100644 (file)
@@ -23,6 +23,7 @@ dtb-$(CONFIG_ARCH_STM32) += \
        stm32f469-disco.dtb \
        stm32f746-disco.dtb \
        stm32f769-disco.dtb \
+       stm32f769-disco-mb1166-reva09.dtb \
        stm32429i-eval.dtb \
        stm32746g-eval.dtb \
        stm32h743i-eval.dtb \
index 7815669fe81348015c5354faadb1db13af12d637..dcb821f567fa3d7d7fa578ea1f4384e083817d24 100644 (file)
                        serial0 {
                                pinctrl_serial0: serial0-0 {
                                        st,pins {
-                                               tx =  <&pio17 0 ALT1 OUT>;
-                                               rx =  <&pio17 1 ALT1 IN>;
+                                               tx = <&pio17 0 ALT1 OUT>;
+                                               rx = <&pio17 1 ALT1 IN>;
                                        };
                                };
                                pinctrl_serial0_hw_flowctrl: serial0-0_hw_flowctrl {
                                        st,pins {
-                                               tx =  <&pio17 0 ALT1 OUT>;
-                                               rx =  <&pio17 1 ALT1 IN>;
+                                               tx = <&pio17 0 ALT1 OUT>;
+                                               rx = <&pio17 1 ALT1 IN>;
                                                cts = <&pio17 2 ALT1 IN>;
                                                rts = <&pio17 3 ALT1 OUT>;
                                        };
index 576235ec3c516ee2136dd2b4a9c95a2ded61a3b3..afa417b34b25ffd7351885071e72989dd635b382 100644 (file)
                reg = <0x42>;
                interrupts = <8 3>;
                interrupt-parent = <&gpioi>;
-               interrupt-controller;
                wakeup-source;
 
                stmpegpio: stmpe_gpio {
diff --git a/arch/arm/boot/dts/st/stm32f769-disco-mb1166-reva09.dts b/arch/arm/boot/dts/st/stm32f769-disco-mb1166-reva09.dts
new file mode 100644 (file)
index 0000000..ff7ff32
--- /dev/null
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Dario Binacchi <dario.binacchi@amarulasolutions.com>
+ */
+
+#include "stm32f769-disco.dts"
+
+&panel0 {
+       compatible = "frida,frd400b25025", "novatek,nt35510";
+       vddi-supply = <&vcc_3v3>;
+       vdd-supply = <&vcc_3v3>;
+       /delete-property/power-supply;
+};
index 5d12ae25b32746604e055d6e11f30bb42174a011..52c5baf58ab9c38b819701301b860ffce187a16e 100644 (file)
@@ -41,7 +41,7 @@
  */
 
 /dts-v1/;
-#include "stm32f746.dtsi"
+#include "stm32f769.dtsi"
 #include "stm32f769-pinctrl.dtsi"
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/gpio/gpio.h>
                reg = <0xC0000000 0x1000000>;
        };
 
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               linux,dma {
+                       compatible = "shared-dma-pool";
+                       linux,dma-default;
+                       no-map;
+                       size = <0x100000>;
+               };
+       };
+
        aliases {
                serial0 = &usart1;
        };
                clock-names = "main_clk";
        };
 
-       mmc_vcard: mmc_vcard {
+       vcc_3v3: vcc-3v3 {
                compatible = "regulator-fixed";
-               regulator-name = "mmc_vcard";
+               regulator-name = "vcc_3v3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
        clock-frequency = <25000000>;
 };
 
+&dsi {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "okay";
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
+                       dsi_in: endpoint {
+                               remote-endpoint = <&ltdc_out_dsi>;
+                       };
+               };
+
+               port@1 {
+                       reg = <1>;
+                       dsi_out: endpoint {
+                               remote-endpoint = <&dsi_panel_in>;
+                       };
+               };
+       };
+
+       panel0: panel@0 {
+               compatible = "orisetech,otm8009a";
+               reg = <0>; /* dsi virtual channel (0..3) */
+               reset-gpios = <&gpioj 15 GPIO_ACTIVE_LOW>;
+               power-supply = <&vcc_3v3>;
+               status = "okay";
+
+               port {
+                       dsi_panel_in: endpoint {
+                               remote-endpoint = <&dsi_out>;
+                       };
+               };
+       };
+};
+
 &i2c1 {
        pinctrl-0 = <&i2c1_pins_b>;
        pinctrl-names = "default";
        status = "okay";
 };
 
+&ltdc {
+       status = "okay";
+
+       port {
+               ltdc_out_dsi: endpoint {
+                       remote-endpoint = <&dsi_in>;
+               };
+       };
+};
+
 &rtc {
        status = "okay";
 };
 
 &sdio2 {
        status = "okay";
-       vmmc-supply = <&mmc_vcard>;
+       vmmc-supply = <&vcc_3v3>;
        cd-gpios = <&gpioi 15 GPIO_ACTIVE_LOW>;
        broken-cd;
        pinctrl-names = "default", "opendrain", "sleep";
diff --git a/arch/arm/boot/dts/st/stm32f769.dtsi b/arch/arm/boot/dts/st/stm32f769.dtsi
new file mode 100644 (file)
index 0000000..4e7d903
--- /dev/null
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Dario Binacchi <dario.binacchi@amarulasolutions.com>
+ */
+
+#include "stm32f746.dtsi"
+
+/ {
+       soc {
+               dsi: dsi@40016c00 {
+                       compatible = "st,stm32-dsi";
+                       reg = <0x40016c00 0x800>;
+                       clocks = <&rcc 1 CLK_F769_DSI>, <&clk_hse>;
+                       clock-names = "pclk", "ref";
+                       resets = <&rcc STM32F7_APB2_RESET(DSI)>;
+                       reset-names = "apb";
+                       status = "disabled";
+               };
+       };
+};
index b04d24c939c37404e79cadb123d98e8c7a0ac69c..3900f32da797b4bdfb243d189331c030efead9a6 100644 (file)
                        status = "disabled";
                };
 
+               crc1: crc@58009000 {
+                       compatible = "st,stm32f7-crc";
+                       reg = <0x58009000 0x400>;
+                       clocks = <&rcc CRC1>;
+                       status = "disabled";
+               };
+
                usbh_ohci: usb@5800c000 {
                        compatible = "generic-ohci";
                        reg = <0x5800c000 0x1000>;
index eea740d097c72ff1f866c540f7147a20993db6ae..52171214a3087d29c275986971a38764a278a98a 100644 (file)
        };
 };
 
+&crc1 {
+       status = "okay";
+};
+
+&cryp {
+       status = "okay";
+};
+
 &i2c1 {
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&i2c1_pins_a>;
index 6197d878894de26cb1c36a32332ae4ff7840d6e4..97cd24227cefbea8acd92799722bc98f215de2c0 100644 (file)
@@ -20,7 +20,7 @@
                dsi: dsi@5a000000 {
                        compatible = "st,stm32-dsi";
                        reg = <0x5a000000 0x800>;
-                       clocks = <&rcc DSI_K>, <&clk_hse>, <&rcc DSI_PX>;
+                       clocks = <&rcc DSI>, <&clk_hse>, <&rcc DSI_PX>;
                        clock-names = "pclk", "ref", "px_clk";
                        phy-dsi-supply = <&reg18>;
                        resets = <&rcc DSI_R>;
index ce5937270aa1df73519c42f55024f11628ca8406..306e1bc2a51467addd2a6378f19fda7b14e9f872 100644 (file)
@@ -30,7 +30,7 @@
 };
 
 &dsi {
-       clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
+       clocks = <&rcc DSI>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
 };
 
 &gpioz {
index c20a73841c1f67d3dc6b43941fa6cc064455f057..956da5f26c1c6736ef76f6f19ebb89ee3299b648 100644 (file)
@@ -36,7 +36,7 @@
 
 &dsi {
        phy-dsi-supply = <&scmi_reg18>;
-       clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
+       clocks = <&rcc DSI>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
 };
 
 &gpioz {
index 510cca5acb79ca449dc11ba043475cfc43becc4c..7a701f7ef0c70467181e71719f17712ca4341562 100644 (file)
@@ -64,7 +64,6 @@
                reg = <0x38>;
                interrupts = <2 2>;
                interrupt-parent = <&gpiof>;
-               interrupt-controller;
                touchscreen-size-x = <480>;
                touchscreen-size-y = <800>;
                status = "okay";
index 5e2eaf57ce22f1cfc08a688c497638c314df6373..8e4b0db198c2213f6142917985429ddc62b16ab7 100644 (file)
@@ -35,7 +35,7 @@
 };
 
 &dsi {
-       clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
+       clocks = <&rcc DSI>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
 };
 
 &gpioz {
index 3226fb945a8ec786686f600a7312d947b8da660f..72b9cab2d990bcbe1e845784b28fdc0a956e5c54 100644 (file)
@@ -36,7 +36,7 @@
 
 &dsi {
        phy-dsi-supply = <&scmi_reg18>;
-       clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
+       clocks = <&rcc DSI>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
 };
 
 &gpioz {
index 8a34d15e9005f073423ac38235e9d3a391ea7924..4cc1770316619deb619326ffe3448502e2e4d7be 100644 (file)
                compatible = "ti,lmp92064";
                reg = <0>;
 
-               reset-gpios = <&gpioa 4 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&gpioa 4 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
                shunt-resistor-micro-ohms = <15000>;
                spi-max-frequency = <5000000>;
                vdd-supply = <&reg_pb_3v3>;
index fc3a2386dbb90de2b6931e74f90d430e8ff4343a..cfaf8adde319fc2bc536a6bc17270d0d074456b8 100644 (file)
@@ -409,7 +409,7 @@ baseboard_eeprom: &sip_eeprom {
 &spi2 {
        pinctrl-names = "default";
        pinctrl-0 = <&spi2_pins_c>;
-       cs-gpios = <&gpiof 12 GPIO_ACTIVE_LOW>;
+       cs-gpios = <&gpiof 12 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>;
        status = "okay";
 };
 
@@ -471,6 +471,10 @@ baseboard_eeprom: &sip_eeprom {
                interrupt-parent = <&gpioa>;
                interrupts = <6 IRQ_TYPE_EDGE_RISING>;
 
+               /* Reduce RGMII EMI emissions by reducing drive strength */
+               microchip,hi-drive-strength-microamp = <2000>;
+               microchip,lo-drive-strength-microamp = <8000>;
+
                ports {
                        #address-cells = <1>;
                        #size-cells = <0>;
index f759fdfe1b104a910fd72fac44878b11d6012980..1d3fb5397ce34ccdff131bf88e9774f178766469 100644 (file)
                        reg = <0x40000 0x1000>;
                        cap-sd-highspeed;
                        cap-mmc-highspeed;
-                       interrupts = <16>;
+                       interrupts = <16>, <17>;
                        dmas = <&edma0 16 0>, <&edma0 17 0>;
                        dma-names = "rx", "tx";
                        clocks = <&psc0 5>;
                        reg = <0x21b000 0x1000>;
                        cap-sd-highspeed;
                        cap-mmc-highspeed;
-                       interrupts = <72>;
+                       interrupts = <72>, <73>;
                        dmas = <&edma1 28 0>, <&edma1 29 0>;
                        dma-names = "rx", "tx";
                        clocks = <&psc1 18>;
index 0397c3423d2db5d5ea4b9300565274b103565816..20bab90ee0ba7678202160c63b74497be229d297 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Device Tree Source for Keystone 2 clock tree
  *
- * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 clocks {
index cf30e007fea3836331daa9d9b1502ff960a7cffe..74720dbf311048f757165cf032d7397dcb4cb697 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Keystone 2 Edison SoC specific device tree
  *
- * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2014-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 clocks {
index 6978d6a362f3fa81e74a3dcf707b52f612a9c0fb..58099ce8d4495abfdab1261e7f4e26523530b0ba 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Keystone 2 Edison EVM device tree
  *
- * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 /dts-v1/;
 
index 5c88a90903b8452a1062d7043b925021f7b12cd2..e586350ae4dca8ca5c7b56ad26ccb38b4ef44b6c 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Device Tree Source for Keystone 2 Edison Netcp driver
  *
- * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 qmss: qmss@2a40000 {
index 65c32946c5223a1e0cdf2a43815eabce09f39e0e..662aa33cba1148e1bd47cd2495e701a93ef8929a 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Keystone 2 Edison soc device tree
  *
- * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/reset/ti-syscon.h>
index f0ddbbcdc9721595f8a2fc93f7bfa9f614b1f4eb..bf5f67d70235740fbf7e4204bc9c720d47700ae8 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Device Tree Source for K2G EVM
  *
- * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2016-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 /dts-v1/;
 
index 6ceb0d5c6388bf4b3d150d39861fad085efe2c20..264e1e0d23c80e89fb1a6d0e24ddd363ae3a2759 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Device Tree Source for K2G Industrial Communication Engine EVM
  *
- * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 /dts-v1/;
 
index 7109ca0316175d68a521bd6565720ceb658c7dab..974c8f2fa740022bfbb620501dc17d900cd174c4 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Device Tree Source for K2G Netcp driver
  *
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 qmss: qmss@4020000 {
index 102d59694d903707a55da8e30e79dc8863462665..790b29ab0fa2cdc0b73105a406de3eab23ade9c5 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Device Tree Source for K2G SOC
  *
- * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2016-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
index 4ba6912176ef1420d901720863cd2d33e18cb243..3ca4722087c93d9b91b1c9031b950a2491dca229 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Keystone 2 Kepler/Hawking SoC clock nodes
  *
- * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 clocks {
index 8dfb54295027e8394f9d0e110fc20b7a72a3c287..b824fad9a4ecfdefdbddcbfac162e40222c7877a 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Keystone 2 Kepler/Hawking EVM device tree
  *
- * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 /dts-v1/;
 
index c2ee775eab6aed4a16402b996e5f41acafb07c7f..3ab1b5d6f9bcb0f46d0f8a774769df48a4cdc08a 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Device Tree Source for Keystone 2 Hawking Netcp driver
  *
- * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 qmss: qmss@2a40000 {
index da6d3934c2e885f8999b4bec91b17cec1df6449e..4fdf4b30384f738d03436450da9ed67c4d54f9fd 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Keystone 2 Kepler/Hawking soc specific device tree
  *
- * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/reset/ti-syscon.h>
index 635528064deae78e60bbeeb2c07a922f9dea66d8..fcfc2fb6cc2d8c7e3e38fe48c73540300b0adbaf 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Keystone 2 lamarr SoC clock nodes
  *
- * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 clocks {
index be619e39a16f3eef9438b08470a04f7e1142795d..ccda63ab12fe099fc21ab3b6c3682483185bfb7b 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Keystone 2 Lamarr EVM device tree
  *
- * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2014-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 /dts-v1/;
 
index 1afebd7458c1138d724ca1547dd599ce1952225f..b8f880faaa3141147cecc18af829501793dfb09d 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Device Tree Source for Keystone 2 Lamarr Netcp driver
  *
- * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 qmss: qmss@2a40000 {
index 2062fe561642fbe26157b9ee12838702a49d0a09..330b437b667f66207fef06d6218b40940874b8fe 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Keystone 2 Lamarr SoC specific device tree
  *
- * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2014-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/reset/ti-syscon.h>
index 1fd04bb37a1538763be661ccd251f0fbd87800fe..ff16428860a9bdd890bdae8342a9511563bb9770 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2013-2017 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
index ea5882ed7010499140ed95a65b82574e31640ab7..f82d2231dfaa61d0ac3e24bee8f8ccac70b0d18d 100644 (file)
@@ -5,7 +5,7 @@
 
 /*
  * VScom OnRISC
- * http://www.vscom.de
+ * https://www.vscom.de
  */
 
 /dts-v1/;
index ea4f8dde6424453cfb98dbf04da24b0ea10b66d0..74a2191af14673ecfcb77564ec44c9701c6459d6 100644 (file)
@@ -5,7 +5,7 @@
 
 /*
  * VScom OnRISC
- * http://www.vscom.de
+ * https://www.vscom.de
  */
 
 /dts-v1/;
index ec914f27d11df2c4a5989b88984274bd120ecd5a..723ff88f76ac200a784beb54b6ea1545d8a84fc6 100644 (file)
@@ -5,7 +5,7 @@
 
 /*
  * VScom OnRISC
- * http://www.vscom.de
+ * https://www.vscom.de
  */
 
 /dts-v1/;
index 6a52e42b9e8132dd1b2b137ef7bb0b8b7bd4eb03..049fd8e1b40f5fde50efe604f4a85629f0a3d7cc 100644 (file)
@@ -5,7 +5,7 @@
 
 /*
  * VScom OnRISC
- * http://www.vscom.de
+ * https://www.vscom.de
  */
 
 /*#include "am33xx.dtsi"*/
index c14d5b70c72f6c3e3b80851be25c5c2b6f2e987f..a4beb718559c428c0fd337c576cc27c8d6d53af2 100644 (file)
@@ -5,7 +5,7 @@
 
 /*
  * VScom OnRISC
- * http://www.vscom.de
+ * https://www.vscom.de
  */
 
 #include "am33xx.dtsi"
index eba843e22ea16eb60a62d263e5a65ce796e842cf..46078af4b7a35e3af998d920aba49f16e3d7d19b 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * am335x-base0033.dts - Device Tree file for IGEP AQUILA EXPANSION
  *
- * Copyright (C) 2013 ISEE 2007 SL - http://www.isee.biz
+ * Copyright (C) 2013 ISEE 2007 SL - https://www.isee.biz
  */
 
 #include "am335x-igep0033.dtsi"
index 96451c8a815ccd996fcf6f6f9c27e78e4ee0d285..2d0216840ff5b280f812ce8e989d749df6efd8be 100644 (file)
         * For details, see linux-omap mailing list May 2015 thread
         *      [PATCH] ARM: dts: am335x-bone* enable pmic-shutdown-controller
         * In particular, messages:
-        *      http://www.spinics.net/lists/linux-omap/msg118585.html
-        *      http://www.spinics.net/lists/linux-omap/msg118615.html
+        *      https://www.spinics.net/lists/linux-omap/msg118585.html
+        *      https://www.spinics.net/lists/linux-omap/msg118615.html
         *
         * You can override this later with
         *      &tps {  /delete-property/ ti,pmic-shutdown-controller;  }
index 72990e7ffe10ee0ad399274455d518920520e6af..06767ea164b5980e8e344f06963e6a79868eecab 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * am335x-cm-t335.dts - Device Tree file for Compulab CM-T335
  *
- * Copyright (C) 2014 - 2015 CompuLab Ltd. - http://www.compulab.co.il/
+ * Copyright (C) 2014 - 2015 CompuLab Ltd. - https://www.compulab.co.il/
  */
 
 /dts-v1/;
index 57f78846c42d326ba98ed1599b3a2f143e13aa0e..eba888dcd60e7fa23c7ba905896286f774ba311f 100644 (file)
@@ -5,7 +5,7 @@
 
 /*
  * AM335x Starter Kit
- * http://www.ti.com/tool/tmdssk3358
+ * https://www.ti.com/tool/tmdssk3358
  */
 
 /dts-v1/;
index 205fe0ed7352231ab7dd057ab0d774225885e1a0..56e5d954a4900306e060a38542ca0b74bfa1d821 100644 (file)
    * For details, see linux-omap mailing list May 2015 thread
    *  [PATCH] ARM: dts: am335x-bone* enable pmic-shutdown-controller
    * In particular, messages:
-   *  http://www.spinics.net/lists/linux-omap/msg118585.html
-   *  http://www.spinics.net/lists/linux-omap/msg118615.html
+   *  https://www.spinics.net/lists/linux-omap/msg118585.html
+   *  https://www.spinics.net/lists/linux-omap/msg118615.html
    *
    * You can override this later with
    *  &tps {  /delete-property/ ti,pmic-shutdown-controller;  }
index 3c4228927f56e940af55645b7a5d959287898721..6f0f4fba043b96e95fd2e413674ee26bafe562cf 100644 (file)
@@ -5,7 +5,7 @@
 
 /*
  * AM335x ICE V2 board
- * http://www.ti.com/tool/tmdsice3359
+ * https://www.ti.com/tool/tmdsice3359
  */
 
 /dts-v1/;
index e85c33fd42f0217a3e62a14ea33b994a5fa7077a..c7a4a5476489a51e3b64b0b1e7ccaad45fffc862 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * am335x-igep0033.dtsi - Device Tree file for IGEP COM AQUILA AM335x
  *
- * Copyright (C) 2013 ISEE 2007 SL - http://www.isee.biz
+ * Copyright (C) 2013 ISEE 2007 SL - https://www.isee.biz
  */
 
 /dts-v1/;
index 58459926921773b155f2140fa3478a856b9aedc8..9c9359844a2061507c0892e4bcc4ccd5b0a0c0de 100644 (file)
@@ -2,7 +2,7 @@
 /* SPDX-FileCopyrightText: Alexander Shiyan, <shc_work@mail.ru> */
 
 /* Based on code by myc_c335x.dts, MYiRtech.com */
-/* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ */
+/* Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ */
 
 /dts-v1/;
 
index d3bba79b9358c9f18471f68c4e4873bba965daf9..fd91a3c01a63fee10b9adc7bd0e0ab10748a64df 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /* SPDX-FileCopyrightText: Alexander Shiyan, <shc_work@mail.ru> */
 /* Based on code by myd_c335x.dts, MYiRtech.com */
-/* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ */
+/* Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ */
 
 /dts-v1/;
 
index a475c0d913060bf153e79ec4084772e55c73b673..26b5510cb3d1661efd0584d149ea2e59aeb97111 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (C) 2013 Newflow Ltd - http://www.newflow.co.uk/
+ * Copyright (C) 2013 Newflow Ltd - https://www.newflow.co.uk/
  */
 /dts-v1/;
 
index f7fad48e36edfa827391782656324e7c9cc6ca3b..546e88f8fbad565e43deb6e56754600761f2612b 100644 (file)
@@ -5,7 +5,7 @@
 
 /*
  * VScom OnRISC
- * http://www.vscom.de
+ * https://www.vscom.de
  */
 
 /dts-v1/;
index 76751a324ad7562e1ef7bb71c91b57ba5e088b10..f66d57bb685ee116ea312eb221831790c1d47b17 100644 (file)
@@ -5,7 +5,7 @@
 
 /*
  * VScom OnRISC
- * http://www.vscom.de
+ * https://www.vscom.de
  */
 
 /dts-v1/;
index 5a9fcec040fae17359a8042f7cf26005af385546..5fb2c629f35c6f31f6382cfe63de6464f83148ff 100644 (file)
@@ -5,7 +5,7 @@
 
 /*
  * VScom OnRISC
- * http://www.vscom.de
+ * https://www.vscom.de
  */
 
 /dts-v1/;
index 3c9444e98c14b0537a1de5912fa0b04aca491f3a..f38f5bff2b9697b5b2575b8137e635110719b7e0 100644 (file)
@@ -3,7 +3,7 @@
  *
  * EETS GmbH PDU001 board device tree file
  *
- * Copyright (C) 2018 EETS GmbH - http://www.eets.ch/
+ * Copyright (C) 2018 EETS GmbH - https://www.eets.ch/
  *
  * Copyright (C) 2011, Texas Instruments, Incorporated - https://www.ti.com/
  *
index 5522759def2669b2800283fc8c3d8ae3c6de0939..7c9f65126c636178a5bee305480ed503ba40a5b6 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) 2021 Sancloud Ltd
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/
  */
 /dts-v1/;
 
index b1b400226d837f0fa48395c8b68e9e0b84c98d45..c6c96f6182a821e1057f62ccf01fd5aff7b783d7 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/
  * Copyright (C) 2021 SanCloud Ltd
  */
 /dts-v1/;
index 596774c847448f121751717a2df6c9a34df93ea6..2841e95d9a094125646a676417ec6df06c878040 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * am335x-sbc-t335.dts - Device Tree file for Compulab SBC-T335
  *
- * Copyright (C) 2014 - 2015 CompuLab Ltd. - http://www.compulab.co.il/
+ * Copyright (C) 2014 - 2015 CompuLab Ltd. - https://www.compulab.co.il/
  */
 
 #include "am335x-cm-t335.dts"
index 1115c812f6c8be454644fb46bbca1b98c716cf97..757ebd96b3f0b5ac160c85c368e6cdafdad9832b 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (C) 2015 Toby Churchill - http://www.toby-churchill.com/
+ * Copyright (C) 2015 Toby Churchill - https://www.toby-churchill.com/
+ * url above is defunct
  */
 /dts-v1/;
 
index 5b9e01a8aa5d5aa8a29e792a882885c5b70c4deb..989d5a6edeed9c7516b0848897a8764d1f6c9de9 100644 (file)
                        #size-cells = <1>;
                        ranges = <0 0x56000000 0x1000000>;
 
-                       /*
-                        * Closed source PowerVR driver, no child device
-                        * binding or driver in mainline
-                        */
+                       gpu@0 {
+                               compatible = "ti,omap3630-gpu", "img,powervr-sgx530";
+                               reg = <0x0 0x10000>; /* 64kB */
+                               interrupts = <37>;
+                       };
                };
        };
 };
index 77e58e686fb17b4436e7fb9472ad49cee32804be..19aad715dff70135d06928d90c1e68318c5f45d4 100644 (file)
                        clock-names = "fck", "ick";
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       ranges = <0 0x50000000 0x4000>;
+                       ranges = <0 0x50000000 0x10000>;
 
-                       /*
-                        * Closed source PowerVR driver, no child device
-                        * binding or driver in mainline
-                        */
+                       gpu@0 {
+                               compatible = "ti,omap3430-gpu", "img,powervr-sgx530";
+                               reg = <0x0 0x10000>; /* 64kB */
+                               interrupts = <21>;
+                       };
                };
        };
 };
index 9d2c064534f7d1b6d42a50cc4df65419e2dc956c..5fd1b380ece6280516c0e141f68a3a969b42d509 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
                        ranges = <0 0x56000000 0x1000000>;
+
+                       gpu@0 {
+                               compatible = "ti,omap3630-gpu", "img,powervr-sgx530";
+                               reg = <0x0 0x10000>; /* 64kB */
+                               interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+                       };
                };
        };
 };
index 9ec75d03eaff1f24e36369e19897c926295025dc..172516a7667e19cbe527e03018bee2fc010c4c3c 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (C) 2015 CompuLab, Ltd. - http://www.compulab.co.il/
+ * Copyright (C) 2015 CompuLab, Ltd. - https://www.compulab.co.il/
  */
 
 /dts-v1/;
index 34a5407bee151f9322f6962e8386ded10911404f..5ec57dcb06592c8305124f4f5b0a557cd269d9ee 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (C) 2015 CompuLab, Ltd. - http://www.compulab.co.il/
+ * Copyright (C) 2015 CompuLab, Ltd. - https://www.compulab.co.il/
  */
 
 #include "am437x-cm-t43.dts"
index c8e55642f9c6e5acc43a741a769f798be6cccb37..eb1ec85aba28bade102b2ed88ff179c41e3583ec 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (C) 2014-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2014-2019 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
                reg = <0x41>;
                interrupts = <30 IRQ_TYPE_LEVEL_LOW>;
                interrupt-parent = <&gpio2>;
-               interrupt-controller;
                id = <0>;
                blocks = <0x5>;
                irq-trigger = <0x1>;
index 4fd831ff206fa1ace68c2ea748b181280fdbdf62..d6e3152b02f70b2fe7822c393b57349ba0c21712 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Support for CompuLab CL-SOM-AM57x System-on-Module
  *
- * Copyright (C) 2015 CompuLab Ltd. - http://www.compulab.co.il/
+ * Copyright (C) 2015 CompuLab Ltd. - https://www.compulab.co.il/
  * Author: Dmitry Lifshitz <lifshitz@compulab.co.il>
  */
 
index 363115afb0a45d4c424c8264f05d1742e1696293..64675f4edb6013c8425445d0056684cbe421b6f4 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Support for CompuLab SBC-AM57x single board computer
  *
- * Copyright (C) 2015 CompuLab Ltd. - http://www.compulab.co.il/
+ * Copyright (C) 2015 CompuLab Ltd. - https://www.compulab.co.il/
  * Author: Dmitry Lifshitz <lifshitz@compulab.co.il>
  */
 
index f5e6216718d85b872604c1bb51c2943a180d431c..8a8fa1b2b26cfb609de7faca8ee53d0445f5c11d 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (C) 2015 CompuLab, Ltd. - http://www.compulab.co.il/
+ * Copyright (C) 2015 CompuLab, Ltd. - https://www.compulab.co.il/
  */
 
 / {
index 5733e3a4ea8e71e54a5c0bc3750ccb57f9470271..6e67d99832ac25240620828eb2e77633eb1b28c5 100644 (file)
@@ -80,7 +80,7 @@
                                                };
                                        };
 
-                                       phy_gmii_sel: phy-gmii-sel {
+                                       phy_gmii_sel: phy-gmii-sel@554 {
                                                compatible = "ti,dra7xx-phy-gmii-sel";
                                                reg = <0x554 0x4>;
                                                #phy-cells = <1>;
index 6509c742fb58c90497660ba34c950ef7a5c701a7..164fa88c459e97375b589cf579f34dc58f0ebbe8 100644 (file)
                        };
                };
 
-               abb_mpu: regulator-abb-mpu {
+               abb_mpu: regulator-abb-mpu@4ae07ddc {
                        compatible = "ti,abb-v3";
                        regulator-name = "abb_mpu";
                        #address-cells = <0>;
                        >;
                };
 
-               abb_ivahd: regulator-abb-ivahd {
+               abb_ivahd: regulator-abb-ivahd@4ae07e34 {
                        compatible = "ti,abb-v3";
                        regulator-name = "abb_ivahd";
                        #address-cells = <0>;
                        >;
                };
 
-               abb_dspeve: regulator-abb-dspeve {
+               abb_dspeve: regulator-abb-dspeve@4ae07e30 {
                        compatible = "ti,abb-v3";
                        regulator-name = "abb_dspeve";
                        #address-cells = <0>;
                        >;
                };
 
-               abb_gpu: regulator-abb-gpu {
+               abb_gpu: regulator-abb-gpu@4ae07de4 {
                        compatible = "ti,abb-v3";
                        regulator-name = "abb_gpu";
                        #address-cells = <0>;
                                        <SYSC_IDLE_SMART>;
                        ti,sysc-sidle = <SYSC_IDLE_FORCE>,
                                        <SYSC_IDLE_NO>,
-                                       <SYSC_IDLE_SMART>;
+                                       <SYSC_IDLE_SMART>,
+                                       <SYSC_IDLE_SMART_WKUP>;
                        clocks = <&gpu_clkctrl DRA7_GPU_CLKCTRL 0>;
                        clock-names = "fck";
                        #address-cells = <1>;
                        #size-cells = <1>;
                        ranges = <0 0x56000000 0x2000000>;
+
+                       gpu@0 {
+                               compatible = "ti,am5728-gpu", "img,powervr-sgx544";
+                               reg = <0x0 0x10000>; /* 64kB */
+                               interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+                       };
                };
 
                crossbar_mpu: crossbar@4a002a48 {
index 006189dad7a7b03ad93829b2f3337b4535f8b2f3..bb5239ae164dcebf93cbff27851a91b098374623 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
index 04a7a6d1d529cf7c0712d4e016dee0038372cbee..06466d36caa9f27b8782b47ab42c1bd8a11fda71 100644 (file)
                reg = <0x0558>;
        };
 
-       sys_32k_ck: clock-sys-32k {
+       sys_32k_ck: clock-sys-32k@6c4 {
                #clock-cells = <0>;
                compatible = "ti,mux-clock";
                clock-output-names = "sys_32k_ck";
index fc7233ac183a8f5249a1d066cf401adfa947ebf1..acdd0ee34421df15a0a5e77fefec7f007a31ac74 100644 (file)
                        clock-names = "fck", "ick";
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       ranges = <0 0x50000000 0x4000>;
+                       ranges = <0 0x50000000 0x10000>;
 
-                       /*
-                        * Closed source PowerVR driver, no child device
-                        * binding or driver in mainline
-                        */
+                       gpu@0 {
+                               compatible = "ti,omap3430-gpu", "img,powervr-sgx530";
+                               reg = <0x0 0x10000>; /* 64kB */
+                               interrupts = <21>;
+                       };
                };
        };
 
index e6d8070c1bf88da462b326823c0fcda0acf2effe..c3d79ecd56e3982cf4bb374271f9dbc790bb97df 100644 (file)
                        #size-cells = <1>;
                        ranges = <0 0x50000000 0x2000000>;
 
-                       /*
-                        * Closed source PowerVR driver, no child device
-                        * binding or driver in mainline
-                        */
+                       gpu@0 {
+                               compatible = "ti,omap3630-gpu", "img,powervr-sgx530";
+                               reg = <0x0 0x2000000>; /* 32MB */
+                               interrupts = <21>;
+                       };
                };
        };
 
index 24f7d0285f7995cf65b874354c6b294265cb8590..339e52ba3614b63a0a65afb70a9c9d3966ba0ce1 100644 (file)
@@ -85,6 +85,7 @@
                interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */
                interrupt-controller;
                #interrupt-cells = <1>;
+               system-power-controller;
 
                rtc {
                        compatible = "ti,twl4030-rtc";
index f528511c2537b68221faaaba30bab6131109b97c..97706d6296a68f9943ecd769a4e55a2503e75ea2 100644 (file)
                reg = <0x48>;
                /* IRQ# = 7 */
                interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */
+               system-power-controller;
        };
 
        twl6040: twl@4b {
index b2cb93edbc3a69a11bbf3ee6ecf74f5cfa2f3e08..b535d24c6140122899625625290a6a9088a5796f 100644 (file)
 
        /*
         * Ambient Light Sensor
-        * http://www.rohm.com/products/databook/sensor/pdf/bh1780gli-e.pdf
+        * https://www.rohm.com/products/databook/sensor/pdf/bh1780gli-e.pdf (defunct)
         */
        bh1780@29 {
                compatible = "rohm,bh1780";
index 2bbff9032be3ed6faefd4c1dc98106d5d21cbc1b..559b2bfe4ca7cd0ce74b81e4bd6faf9cca776457 100644 (file)
                        #size-cells = <1>;
                        ranges = <0 0x56000000 0x2000000>;
 
-                       /*
-                        * Closed source PowerVR driver, no child device
-                        * binding or driver in mainline
-                        */
+                       gpu@0 {
+                               compatible = "ti,omap4430-gpu", "img,powervr-sgx540";
+                               reg = <0x0 0x2000000>; /* 32MB */
+                               interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+                       };
                };
 
                /*
index d4ca2e3a14dd882f08dbd5c75e836f8b626a339c..0368e32f67e7ccdac21ee74ff7cb22589f4640cd 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (C) 2013 ISEE 2007 SL - http://www.isee.biz/
+ * Copyright (C) 2013 ISEE 2007 SL - https://www.isee.biz/
  */
 /dts-v1/;
 
index bac6fa83879368b447d9e0146d2c998ba6d81fe3..6a66214ad0e2f995c5b82f636d6560afe3ea8292 100644 (file)
                        #size-cells = <1>;
                        ranges = <0 0x56000000 0x2000000>;
 
-                       /*
-                        * Closed source PowerVR driver, no child device
-                        * binding or driver in mainline
-                        */
+                       gpu@0 {
+                               compatible = "ti,omap5432-gpu", "img,powervr-sgx544";
+                               reg = <0x0 0x2000000>; /* 32MB */
+                               interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+                       };
                };
 
                target-module@58000000 {
index 93e07c18781b5ed93ce1182e79f423d1b79393a7..a5d9c5738317aac9a140cc5993a9de7773a422b8 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /*
index 9d588cfaa5cb5e491a91cccea5c3067af231999e..8da969035c41219f835bfe18695a9aac73f6a9fc 100644 (file)
@@ -1,11 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /*
  * Integrated Power Management Chip
- * http://www.ti.com/lit/ds/symlink/twl6030.pdf
+ * https://www.ti.com/lit/ds/symlink/twl6030.pdf
  */
 &twl {
        compatible = "ti,twl6030";
index c98d5ff8a1ed084fab23d56a9a6a3efbf6e4c012..7ad48fdda1dac69a4a9612eabb573729bed7b3a6 100644 (file)
@@ -318,8 +318,11 @@ CONFIG_EXTCON_MAX77693=y
 CONFIG_EXTCON_MAX8997=y
 CONFIG_EXYNOS5422_DMC=y
 CONFIG_IIO=y
+CONFIG_IIO_ST_ACCEL_3AXIS=m
+# CONFIG_IIO_ST_ACCEL_SPI_3AXIS is not set
 CONFIG_EXYNOS_ADC=y
 CONFIG_STMPE_ADC=y
+CONFIG_IIO_ST_GYRO_3AXIS=m
 CONFIG_CM36651=y
 CONFIG_AK8975=y
 CONFIG_SENSORS_ISL29018=y
index 0a90583f9f017ed2f88cd20cb6f731440909e830..92d649a817b3e1f3cc972eed5241acf38cc84309 100644 (file)
@@ -208,6 +208,7 @@ CONFIG_PINCTRL_IMX8MQ=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_MXC=y
 CONFIG_GPIO_SIOX=m
+CONFIG_GPIO_VF610=y
 CONFIG_GPIO_MAX732X=y
 CONFIG_GPIO_PCA953X=y
 CONFIG_GPIO_PCF857X=y
@@ -297,6 +298,7 @@ CONFIG_FB_MODE_HELPERS=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_L4F00242T03=y
 CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_PWM=y
 CONFIG_BACKLIGHT_GPIO=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
index ecb3e286107a4c1a6d6cf34797329f1c2b215f41..b2955dcb5a53b9cd30a716839fb8c7ea55a845af 100644 (file)
@@ -183,6 +183,7 @@ CONFIG_PCIE_RCAR_HOST=y
 CONFIG_PCI_RCAR_GEN2=y
 CONFIG_PCI_LAYERSCAPE=y
 CONFIG_PCI_DRA7XX_EP=y
+CONFIG_PCI_KEYSTONE_HOST=y
 CONFIG_PCI_ENDPOINT=y
 CONFIG_PCI_ENDPOINT_CONFIGFS=y
 CONFIG_PCI_EPF_TEST=m
@@ -191,6 +192,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_OMAP_OCP2SCP=y
 CONFIG_ARM_SCMI_PROTOCOL=y
 CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_TI_SCI_PROTOCOL=y
 CONFIG_TRUSTED_FOUNDATIONS=y
 CONFIG_BCM47XX_NVRAM=y
 CONFIG_BCM47XX_SPROM=y
@@ -280,6 +282,8 @@ CONFIG_DWMAC_DWC_QOS_ETH=y
 CONFIG_TI_CPSW=y
 CONFIG_TI_CPSW_SWITCHDEV=y
 CONFIG_TI_CPTS=y
+CONFIG_TI_KEYSTONE_NETCP=y
+CONFIG_TI_KEYSTONE_NETCP_ETHSS=y
 CONFIG_XILINX_EMACLITE=y
 CONFIG_SFP=m
 CONFIG_BROADCOM_PHY=y
@@ -292,6 +296,8 @@ CONFIG_CAN_AT91=m
 CONFIG_CAN_FLEXCAN=m
 CONFIG_CAN_SUN4I=y
 CONFIG_CAN_XILINXCAN=y
+CONFIG_CAN_C_CAN=m
+CONFIG_CAN_C_CAN_PLATFORM=m
 CONFIG_CAN_RCAR=m
 CONFIG_CAN_MCP251X=y
 CONFIG_MDIO_MSCC_MIIM=m
@@ -335,6 +341,7 @@ CONFIG_INPUT_MISC=y
 CONFIG_INPUT_PM8941_PWRKEY=y
 CONFIG_INPUT_MAX77693_HAPTIC=m
 CONFIG_INPUT_MAX8997_HAPTIC=m
+CONFIG_INPUT_GPIO_DECODER=m
 CONFIG_INPUT_CPCAP_PWRBUTTON=m
 CONFIG_INPUT_AXP20X_PEK=m
 CONFIG_INPUT_DA9063_ONKEY=m
@@ -436,6 +443,7 @@ CONFIG_SPI_ATMEL_QUADSPI=m
 CONFIG_SPI_BCM2835=y
 CONFIG_SPI_BCM2835AUX=y
 CONFIG_SPI_CADENCE=y
+CONFIG_SPI_CADENCE_QUADSPI=y
 CONFIG_SPI_DAVINCI=y
 CONFIG_SPI_FSL_QUADSPI=m
 CONFIG_SPI_GXP=m
@@ -769,6 +777,7 @@ CONFIG_FB_EFI=y
 CONFIG_FB_WM8505=y
 CONFIG_FB_SH_MOBILE_LCDC=y
 CONFIG_FB_SIMPLE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_PWM=y
 CONFIG_BACKLIGHT_AS3711=y
 CONFIG_BACKLIGHT_GPIO=y
@@ -1047,7 +1056,6 @@ CONFIG_KEYBOARD_NVEC=y
 CONFIG_SERIO_NVEC_PS2=y
 CONFIG_NVEC_POWER=y
 CONFIG_NVEC_PAZ00=y
-CONFIG_STAGING_BOARD=y
 CONFIG_CHROME_PLATFORMS=y
 CONFIG_CROS_EC=m
 CONFIG_CROS_EC_I2C=m
@@ -1073,6 +1081,7 @@ CONFIG_HWSPINLOCK_OMAP=y
 CONFIG_HWSPINLOCK_QCOM=y
 CONFIG_OMAP2PLUS_MBOX=y
 CONFIG_BCM2835_MBOX=y
+CONFIG_TI_MESSAGE_MANAGER=y
 CONFIG_QCOM_APCS_IPC=y
 CONFIG_STM32_IPCC=m
 CONFIG_QCOM_IPCC=y
@@ -1133,11 +1142,15 @@ CONFIG_ARCH_TEGRA_2x_SOC=y
 CONFIG_ARCH_TEGRA_3x_SOC=y
 CONFIG_ARCH_TEGRA_114_SOC=y
 CONFIG_ARCH_TEGRA_124_SOC=y
+CONFIG_SOC_TI=y
+CONFIG_KEYSTONE_NAVIGATOR_QMSS=y
+CONFIG_KEYSTONE_NAVIGATOR_DMA=y
 CONFIG_RASPBERRYPI_POWER=y
 CONFIG_QCOM_CPR=y
 CONFIG_QCOM_RPMHPD=y
 CONFIG_QCOM_RPMPD=y
 CONFIG_ROCKCHIP_PM_DOMAINS=y
+CONFIG_TI_SCI_PM_DOMAINS=y
 CONFIG_ARM_EXYNOS_BUS_DEVFREQ=m
 CONFIG_ARM_TEGRA_DEVFREQ=m
 CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP=m
@@ -1150,6 +1163,8 @@ CONFIG_STM32_FMC2_EBI=y
 CONFIG_EXYNOS5422_DMC=m
 CONFIG_IIO=y
 CONFIG_IIO_SW_TRIGGER=y
+CONFIG_IIO_ST_ACCEL_3AXIS=m
+# CONFIG_IIO_ST_ACCEL_SPI_3AXIS is not set
 CONFIG_ASPEED_ADC=m
 CONFIG_AT91_ADC=m
 CONFIG_AT91_SAMA5D2_ADC=m
@@ -1169,6 +1184,7 @@ CONFIG_IIO_CROS_EC_SENSORS_CORE=m
 CONFIG_IIO_CROS_EC_SENSORS=m
 CONFIG_STM32_DAC=m
 CONFIG_MPU3050_I2C=y
+CONFIG_IIO_ST_GYRO_3AXIS=m
 CONFIG_CM36651=m
 CONFIG_IIO_CROS_EC_LIGHT_PROX=m
 CONFIG_SENSORS_ISL29018=y
@@ -1193,10 +1209,13 @@ CONFIG_PWM_STM32=m
 CONFIG_PWM_STM32_LP=m
 CONFIG_PWM_SUN4I=y
 CONFIG_PWM_TEGRA=y
+CONFIG_PWM_TIECAP=m
 CONFIG_PWM_VT8500=y
 CONFIG_KEYSTONE_IRQ=y
 CONFIG_RESET_MCHP_SPARX5=y
 CONFIG_RESET_SCMI=y
+CONFIG_RESET_TI_SCI=m
+CONFIG_RESET_TI_SYSCON=m
 CONFIG_PHY_SUN4I_USB=y
 CONFIG_PHY_SUN9I_USB=y
 CONFIG_PHY_BRCM_USB=m
index c47a638172a89bfdb3c29bdacff7a6b64ad96b6e..091e1840933cf2c61ab8c859a2474a7ca106cc00 100644 (file)
@@ -191,8 +191,6 @@ CONFIG_DW_DMAC=y
 CONFIG_RZN1_DMAMUX=y
 CONFIG_RCAR_DMAC=y
 CONFIG_RENESAS_USB_DMAC=y
-CONFIG_STAGING=y
-CONFIG_STAGING_BOARD=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_ARCH_EMEV2=y
 CONFIG_ARCH_R8A7794=y
index d68101655b74ef0cca647d2ff6e3c59d55fc4a11..9f21e170320fc57f1dc21a33d637bcfd3d1d3917 100644 (file)
@@ -4,7 +4,6 @@
 
 #include <asm/auxvec.h>
 #include <asm/hwcap.h>
-#include <asm/vdso_datapage.h>
 
 /*
  * ELF register definitions..
index 119aa85d1feb4d24726f3e3619c0f46c98b07f80..62af9f7f9e963ec1810093b2fd38ee4c5a822662 100644 (file)
@@ -8,7 +8,7 @@
 #define _ASMARM_PAGE_H
 
 /* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT             12
+#define PAGE_SHIFT             CONFIG_PAGE_SHIFT
 #define PAGE_SIZE              (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK              (~((1 << PAGE_SHIFT) - 1))
 
diff --git a/arch/arm/include/asm/vdso_datapage.h b/arch/arm/include/asm/vdso_datapage.h
deleted file mode 100644 (file)
index bef68f5..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Adapted from arm64 version.
- *
- * Copyright (C) 2012 ARM Limited
- */
-#ifndef __ASM_VDSO_DATAPAGE_H
-#define __ASM_VDSO_DATAPAGE_H
-
-#ifdef __KERNEL__
-
-#ifndef __ASSEMBLY__
-
-#include <vdso/datapage.h>
-#include <asm/page.h>
-
-union vdso_data_store {
-       struct vdso_data        data[CS_BASES];
-       u8                      page[PAGE_SIZE];
-};
-
-#endif /* !__ASSEMBLY__ */
-
-#endif /* __KERNEL__ */
-
-#endif /* __ASM_VDSO_DATAPAGE_H */
index 219cbc7e5d134b5bb0638d158266f809968977b6..4915662842ff1df4041ed504a456db581c063570 100644 (file)
 #include <asm/mpu.h>
 #include <asm/procinfo.h>
 #include <asm/suspend.h>
-#include <asm/vdso_datapage.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <linux/kbuild.h>
 #include <linux/arm-smccc.h>
+
+#include <vdso/datapage.h>
+
 #include "signal.h"
 
 /*
index f297d66a8a7624daca23ad2ff052c504fb859b34..d499ad461b004b05e1f0f13cbedad71b587f8478 100644 (file)
@@ -21,7 +21,6 @@
 #include <asm/cacheflush.h>
 #include <asm/page.h>
 #include <asm/vdso.h>
-#include <asm/vdso_datapage.h>
 #include <clocksource/arm_arch_timer.h>
 #include <vdso/helpers.h>
 #include <vdso/vsyscall.h>
@@ -35,9 +34,6 @@ extern char vdso_start[], vdso_end[];
 /* Total number of pages needed for the data and text portions of the VDSO. */
 unsigned int vdso_total_pages __ro_after_init;
 
-/*
- * The VDSO data page.
- */
 static union vdso_data_store vdso_data_store __page_aligned_data;
 struct vdso_data *vdso_data = vdso_data_store.data;
 
index 71b1139764204c506bae31fc31c23f7a51bf61a3..8b1ec60a9a467abcc3bc80c07be12bf734d7c236 100644 (file)
@@ -339,6 +339,7 @@ static struct gpiod_lookup_table ep93xx_i2c_gpiod_table = {
                                GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
                GPIO_LOOKUP_IDX("G", 0, NULL, 1,
                                GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
+               { }
        },
 };
 
index 444a7eaa320ca7b3850504333c9febc05e301ded..25893d1091903fae1eb392c3b648117b366fb36a 100644 (file)
@@ -452,7 +452,7 @@ static int mmdc_pmu_init(struct mmdc_pmu *pmu_mmdc,
                .active_events = 0,
        };
 
-       pmu_mmdc->id = ida_simple_get(&mmdc_ida, 0, 0, GFP_KERNEL);
+       pmu_mmdc->id = ida_alloc(&mmdc_ida, GFP_KERNEL);
 
        return pmu_mmdc->id;
 }
@@ -461,7 +461,7 @@ static void imx_mmdc_remove(struct platform_device *pdev)
 {
        struct mmdc_pmu *pmu_mmdc = platform_get_drvdata(pdev);
 
-       ida_simple_remove(&mmdc_ida, pmu_mmdc->id);
+       ida_free(&mmdc_ida, pmu_mmdc->id);
        cpuhp_state_remove_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node);
        perf_pmu_unregister(&pmu_mmdc->pmu);
        iounmap(pmu_mmdc->mmdc_base);
@@ -529,7 +529,7 @@ pmu_register_err:
        cpuhp_state_remove_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node);
        hrtimer_cancel(&pmu_mmdc->hrtimer);
 pmu_release_id:
-       ida_simple_remove(&mmdc_ida, pmu_mmdc->id);
+       ida_free(&mmdc_ida, pmu_mmdc->id);
 pmu_free:
        kfree(pmu_mmdc);
        return ret;
index cbf703f0d850f65abd62b1ed5bf18d465ab80291..a643b71e30a355decf4284015fc4fbcf1acd3283 100644 (file)
@@ -4,7 +4,6 @@ menuconfig ARCH_OMAP1
        depends on ARCH_MULTI_V4T || ARCH_MULTI_V5
        depends on CPU_LITTLE_ENDIAN
        depends on ATAGS
-       select ARCH_OMAP
        select ARCH_HAS_HOLES_MEMORYMODEL
        select ARCH_OMAP
        select CLKSRC_MMIO
index ef2f18a56b658fb2ab183c76300ef2a02568dc6e..fcf3d557aa7866415dd6c4a23f7db7f230e56bf8 100644 (file)
@@ -9,7 +9,7 @@
 #include "prm.h"
 
 /**
- * am3xx_restart - trigger a software restart of the SoC
+ * am33xx_restart - trigger a software restart of the SoC
  * @mode: the "reboot mode", see arch/arm/kernel/{setup,process}.c
  * @cmd: passed from the userspace program rebooting the system (if provided)
  *
@@ -18,7 +18,8 @@
  */
 void am33xx_restart(enum reboot_mode mode, const char *cmd)
 {
-       /* TODO: Handle mode and cmd if necessary */
+       /* TODO: Handle cmd if necessary */
+       prm_reboot_mode = mode;
 
        omap_prm_reset_system();
 }
index fde6ccb3df6ebbf10ad2cd728a81ccf98dc8594d..68e0baad2bbf62753edea18630cbd73286bd28ab 100644 (file)
@@ -246,6 +246,12 @@ DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)")
        .init_time      = omap_init_time_of,
        .dt_compat      = am33xx_boards_compat,
        .restart        = am33xx_restart,
+       /*
+        * Historically am33xx supported only REBOOT_WARM even though default
+        * reboot_mode was REBOOT_COLD. Reflect legacy de-facto behaviour in
+        * SYSFS.
+        */
+       .reboot_mode    = REBOOT_WARM,
 MACHINE_END
 #endif
 
index be4557d1fdac624e370c11380b49844cac5e91ca..011076a5952f0bfb24eadd13b8991b41b8115bae 100644 (file)
@@ -162,7 +162,7 @@ static int omap2_select_table_rate(struct clk_hw *hw, unsigned long rate,
 }
 
 /**
- * omap2xxx_clkt_vps_check_bootloader_rate - determine which of the rate
+ * omap2xxx_clkt_vps_check_bootloader_rates - determine which of the rate
  * table sets matches the current CORE DPLL hardware rate
  *
  * Check the MPU rate set by bootloader.  Sets the 'curr_prcm_set'
index d145e7ac709bad39fd29ce629becd98186f7afa8..69dc5b839335658ab2cd89fcceabbf56699a437e 100644 (file)
@@ -990,7 +990,7 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
 }
 
 /**
- * clkdm_deny_idle - disable hwsup idle transitions for clkdm
+ * clkdm_deny_idle_nolock - disable hwsup idle transitions for clkdm
  * @clkdm: struct clockdomain *
  *
  * Prevent the hardware from automatically switching the clockdomain
@@ -1110,7 +1110,7 @@ void clkdm_del_autodeps(struct clockdomain *clkdm)
 /**
  * clkdm_clk_enable - add an enabled downstream clock to this clkdm
  * @clkdm: struct clockdomain *
- * @clk: struct clk * of the enabled downstream clock
+ * @unused: struct clk * of the enabled downstream clock
  *
  * Increment the usecount of the clockdomain @clkdm and ensure that it
  * is awake before @clk is enabled.  Intended to be called by
index c824d4e3db632c9ff1827ae6fff31d4ac96d94ba..acdf72a541c02aa6718fd73dc9ed153cc881bd16 100644 (file)
@@ -357,7 +357,7 @@ static int am33xx_clkdm_save_context(struct clockdomain *clkdm)
 }
 
 /**
- * am33xx_restore_save_context - Restore the clockdomain transition context
+ * am33xx_clkdm_restore_context - Restore the clockdomain transition context
  * @clkdm: The clockdomain pointer whose context needs to be restored
  *
  * Restore the clockdomain transition context.
index 46670521b27883ecd0185c0d0ddf29d8a69d9230..49483a8880466665061a71d3a0030ed316f166be 100644 (file)
@@ -237,7 +237,7 @@ static void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs)
 }
 
 /**
- * omap4_cminst_clkdm_force_sleep - try to take a clockdomain out of idle
+ * omap4_cminst_clkdm_force_wakeup - try to take a clockdomain out of idle
  * @part: PRCM partition ID that the clockdomain registers exist in
  * @inst: CM instance register offset (*_INST macro)
  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
index 29c7350b06abd9d67d87a7d378d451b9e582cab0..c2e1aecd07ccbbed6d039023a2741db4848c063e 100644 (file)
@@ -47,7 +47,7 @@ static void __init omap_optee_init_check(void)
 }
 
 /**
- * omap_sec_dispatcher: Routine to dispatch low power secure
+ * omap_secure_dispatcher - Routine to dispatch low power secure
  * service routines
  * @idx: The HAL API index
  * @flag: The flag indicating criticality of operation
@@ -183,7 +183,7 @@ static u32 rx51_secure_dispatcher(u32 idx, u32 process, u32 flag, u32 nargs,
 /**
  * rx51_secure_update_aux_cr: Routine to modify the contents of Auxiliary Control Register
  *  @set_bits: bits to set in ACR
- *  @clr_bits: bits to clear in ACR
+ *  @clear_bits: bits to clear in ACR
  *
  * Return the non-zero error value on failure.
 */
index ba71928c0fcb7b9d8b348a1c85fdfdcbf9325383..111677878d9cd1ca090658fc037c574431632ae5 100644 (file)
@@ -900,7 +900,7 @@ static int _init_interface_clks(struct omap_hwmod *oh)
 }
 
 /**
- * _init_opt_clk - get a struct clk * for the hwmod's optional clocks
+ * _init_opt_clks - get a struct clk * for the hwmod's optional clocks
  * @oh: struct omap_hwmod *
  *
  * Called from _init_clocks().  Populates the @oh omap_hwmod_opt_clk
@@ -2297,7 +2297,7 @@ static void __init parse_module_flags(struct omap_hwmod *oh,
 /**
  * _init - initialize internal data for the hwmod @oh
  * @oh: struct omap_hwmod *
- * @n: (unused)
+ * @data: (unused)
  *
  * Look up the clocks and the address space used by the MPU to access
  * registers belonging to the hwmod @oh.  @oh must already be
@@ -2493,7 +2493,7 @@ static void _setup_postsetup(struct omap_hwmod *oh)
 /**
  * _setup - prepare IP block hardware for use
  * @oh: struct omap_hwmod *
- * @n: (unused, pass NULL)
+ * @data: (unused, pass NULL)
  *
  * Configure the IP block represented by @oh.  This may include
  * enabling the IP block, resetting it, and placing it into a
@@ -3367,8 +3367,9 @@ static int omap_hwmod_check_module(struct device *dev,
  * omap_hwmod_allocate_module - allocate new module
  * @dev: struct device
  * @oh: module
+ * @data: module data
  * @sysc_fields: sysc register bits
- * @clockdomain: clockdomain
+ * @clkdm: clockdomain
  * @rev_offs: revision register offset
  * @sysc_offs: sysconfig register offset
  * @syss_offs: sysstatus register offset
index 246f1e5da99fbd729f7702b2adac667fffe98eaf..439232233c394e632813cfd6bf84fcaa376a3798 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "omap_hwmod_common_data.h"
 
-/**
+/*
  * struct omap_hwmod_sysc_type1 - TYPE1 sysconfig scheme.
  *
  * To be used by hwmod structure to specify the sysconfig offsets
@@ -36,7 +36,7 @@ struct sysc_regbits omap_hwmod_sysc_type1 = {
        .autoidle_shift = SYSC_TYPE1_AUTOIDLE_SHIFT,
 };
 
-/**
+/*
  * struct omap_hwmod_sysc_type2 - TYPE2 sysconfig scheme.
  *
  * To be used by hwmod structure to specify the sysconfig offsets if the
@@ -50,7 +50,7 @@ struct sysc_regbits omap_hwmod_sysc_type2 = {
        .dmadisable_shift = SYSC_TYPE2_DMADISABLE_SHIFT,
 };
 
-/**
+/*
  * struct omap_hwmod_sysc_type3 - TYPE3 sysconfig scheme.
  * Used by some IPs on AM33xx
  */
index 668dc84fd31e0435f041b0f672e4d295eb185e92..4f31e61c0c90cac5528b32ae17de201292e484e6 100644 (file)
 #include "vc.h"
 
 /**
- * omap_cpcap_vsel_to_vdc - convert CPCAP VSEL value to microvolts DC
+ * omap_cpcap_vsel_to_uv - convert CPCAP VSEL value to microvolts DC
  * @vsel: CPCAP VSEL value to convert
  *
- * Returns the microvolts DC that the CPCAP PMIC should generate when
+ * Returns: the microvolts DC that the CPCAP PMIC should generate when
  * programmed with @vsel.
  */
 static unsigned long omap_cpcap_vsel_to_uv(unsigned char vsel)
@@ -35,7 +35,7 @@ static unsigned long omap_cpcap_vsel_to_uv(unsigned char vsel)
  * omap_cpcap_uv_to_vsel - convert microvolts DC to CPCAP VSEL value
  * @uv: microvolts DC to convert
  *
- * Returns the VSEL value necessary for the CPCAP PMIC to
+ * Returns: the VSEL value necessary for the CPCAP PMIC to
  * generate an output voltage equal to or greater than @uv microvolts DC.
  */
 static unsigned char omap_cpcap_uv_to_vsel(unsigned long uv)
@@ -82,10 +82,10 @@ static struct omap_voltdm_pmic omap_cpcap_iva = {
 };
 
 /**
- * omap_max8952_vsel_to_vdc - convert MAX8952 VSEL value to microvolts DC
+ * omap_max8952_vsel_to_uv - convert MAX8952 VSEL value to microvolts DC
  * @vsel: MAX8952 VSEL value to convert
  *
- * Returns the microvolts DC that the MAX8952 Regulator should generate when
+ * Returns: the microvolts DC that the MAX8952 Regulator should generate when
  * programmed with @vsel.
  */
 static unsigned long omap_max8952_vsel_to_uv(unsigned char vsel)
@@ -99,7 +99,7 @@ static unsigned long omap_max8952_vsel_to_uv(unsigned char vsel)
  * omap_max8952_uv_to_vsel - convert microvolts DC to MAX8952 VSEL value
  * @uv: microvolts DC to convert
  *
- * Returns the VSEL value necessary for the MAX8952 Regulator to
+ * Returns: the VSEL value necessary for the MAX8952 Regulator to
  * generate an output voltage equal to or greater than @uv microvolts DC.
  */
 static unsigned char omap_max8952_uv_to_vsel(unsigned long uv)
@@ -129,10 +129,10 @@ static struct omap_voltdm_pmic omap443x_max8952_mpu = {
 };
 
 /**
- * omap_fan5355_vsel_to_vdc - convert FAN535503 VSEL value to microvolts DC
+ * omap_fan535503_vsel_to_uv - convert FAN535503 VSEL value to microvolts DC
  * @vsel: FAN535503 VSEL value to convert
  *
- * Returns the microvolts DC that the FAN535503 Regulator should generate when
+ * Returns: the microvolts DC that the FAN535503 Regulator should generate when
  * programmed with @vsel.
  */
 static unsigned long omap_fan535503_vsel_to_uv(unsigned char vsel)
@@ -144,10 +144,10 @@ static unsigned long omap_fan535503_vsel_to_uv(unsigned char vsel)
 }
 
 /**
- * omap_fan535508_vsel_to_vdc - convert FAN535508 VSEL value to microvolts DC
+ * omap_fan535508_vsel_to_uv - convert FAN535508 VSEL value to microvolts DC
  * @vsel: FAN535508 VSEL value to convert
  *
- * Returns the microvolts DC that the FAN535508 Regulator should generate when
+ * Returns: the microvolts DC that the FAN535508 Regulator should generate when
  * programmed with @vsel.
  */
 static unsigned long omap_fan535508_vsel_to_uv(unsigned char vsel)
@@ -165,7 +165,7 @@ static unsigned long omap_fan535508_vsel_to_uv(unsigned char vsel)
  * omap_fan535503_uv_to_vsel - convert microvolts DC to FAN535503 VSEL value
  * @uv: microvolts DC to convert
  *
- * Returns the VSEL value necessary for the MAX8952 Regulator to
+ * Returns: the VSEL value necessary for the MAX8952 Regulator to
  * generate an output voltage equal to or greater than @uv microvolts DC.
  */
 static unsigned char omap_fan535503_uv_to_vsel(unsigned long uv)
@@ -184,7 +184,7 @@ static unsigned char omap_fan535503_uv_to_vsel(unsigned long uv)
  * omap_fan535508_uv_to_vsel - convert microvolts DC to FAN535508 VSEL value
  * @uv: microvolts DC to convert
  *
- * Returns the VSEL value necessary for the MAX8952 Regulator to
+ * Returns: the VSEL value necessary for the MAX8952 Regulator to
  * generate an output voltage equal to or greater than @uv microvolts DC.
  */
 static unsigned char omap_fan535508_uv_to_vsel(unsigned long uv)
index 5e05dd1324e7be4a135fe14f597e4cc6069976ec..2441d96b71446cdc5db75b6321780f83192256f7 100644 (file)
@@ -1162,7 +1162,7 @@ static int pwrdm_save_context(struct powerdomain *pwrdm, void *unused)
 }
 
 /**
- * pwrdm_save_context - restore powerdomain registers
+ * pwrdm_restore_context - restore powerdomain registers
  *
  * Restore powerdomain control registers after a suspend or resume
  * event.
index 3748c5266ae128960d8b9af912ec30835674b01f..9b97f8c76cd17114c5414fd05e1c0eead41494bc 100644 (file)
@@ -15,6 +15,7 @@
 #define AM33XX_GFX_MEM_STATEST_MASK                    (0x3 << 4)
 #define AM33XX_GLOBAL_WARM_SW_RST_MASK                 (1 << 1)
 #define AM33XX_RST_GLOBAL_WARM_SW_MASK                 (1 << 0)
+#define AM33XX_RST_GLOBAL_COLD_SW_MASK                 (1 << 1)
 #define AM33XX_PRUSS_MEM_ONSTATE_MASK                  (0x3 << 5)
 #define AM33XX_PRUSS_MEM_RETSTATE_MASK                 (1 << 7)
 #define AM33XX_PRUSS_MEM_STATEST_MASK                  (0x3 << 23)
index fc45a7ed09bb37cdc588d90b99f309ffa322703f..fc53a27eed01345cc8b3b775569fa47c5d787dfa 100644 (file)
@@ -15,6 +15,7 @@
 # ifndef __ASSEMBLER__
 extern struct omap_domain_base prm_base;
 extern u16 prm_features;
+extern enum reboot_mode prm_reboot_mode;
 int omap_prcm_init(void);
 int omap2_prcm_base_init(void);
 # endif
index 4b65a0f9cf7d91f6f2fc3a45f7607e38c0c23eee..505d685d6792efb9ffa7303be4a6ddae18f5f276 100644 (file)
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/reboot.h>
 
 #include "powerdomain.h"
 #include "prm33xx.h"
 #include "prm-regbits-33xx.h"
 
-#define AM33XX_PRM_RSTCTRL_OFFSET              0x0000
-
-#define AM33XX_RST_GLOBAL_WARM_SW_MASK         (1 << 0)
-
 /* Read a register in a PRM instance */
 static u32 am33xx_prm_read_reg(s16 inst, u16 idx)
 {
@@ -322,10 +319,19 @@ static int am33xx_check_vcvp(void)
  *
  * Immediately reboots the device through warm reset.
  */
-static void am33xx_prm_global_warm_sw_reset(void)
+static void am33xx_prm_global_sw_reset(void)
 {
-       am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK,
-                               AM33XX_RST_GLOBAL_WARM_SW_MASK,
+       /*
+        * Historically AM33xx performed warm reset for all requested reboot_mode.
+        * Keep this behaviour unchanged for all except newly added REBOOT_COLD.
+        */
+       u32 mask = AM33XX_RST_GLOBAL_WARM_SW_MASK;
+
+       if (prm_reboot_mode == REBOOT_COLD)
+               mask = AM33XX_RST_GLOBAL_COLD_SW_MASK;
+
+       am33xx_prm_rmw_reg_bits(mask,
+                               mask,
                                AM33XX_PRM_DEVICE_MOD,
                                AM33XX_PRM_RSTCTRL_OFFSET);
 
@@ -386,7 +392,7 @@ static struct prm_ll_data am33xx_prm_ll_data = {
        .assert_hardreset               = am33xx_prm_assert_hardreset,
        .deassert_hardreset             = am33xx_prm_deassert_hardreset,
        .is_hardreset_asserted          = am33xx_prm_is_hardreset_asserted,
-       .reset_system                   = am33xx_prm_global_warm_sw_reset,
+       .reset_system                   = am33xx_prm_global_sw_reset,
 };
 
 int __init am33xx_prm_init(const struct omap_prcm_init_data *data)
index 25093c1e5b9ac92724fe2cc016f228e2ac8dedbd..6c555438dd484c05d530995d76392a5764788d9d 100644 (file)
@@ -407,7 +407,7 @@ static bool omap44xx_prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx)
 }
 
 /**
- * omap44xx_prm_clear_context_lost_flags_old - clear context loss flags
+ * omap44xx_prm_clear_context_loss_flags_old - clear context loss flags
  * @part: PRM partition ID (e.g., OMAP4430_PRM_PARTITION)
  * @inst: PRM instance offset (e.g., OMAP4430_PRM_MPU_INST)
  * @idx: CONTEXT register offset
index fd896f2295a11af3545166a6deb6c10fee453743..ee4588acda503c99b5dd3debb3dfdb2abb9c3dc0 100644 (file)
@@ -66,6 +66,12 @@ struct omap_domain_base prm_base;
 
 u16 prm_features;
 
+/*
+ * Platforms that implement different reboot modes can store the requested
+ * mode here.
+ */
+enum reboot_mode prm_reboot_mode;
+
 /*
  * prm_ll_data: function pointers to SoC-specific implementations of
  * common PRM functions
@@ -370,7 +376,7 @@ bool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx)
 }
 
 /**
- * prm_clear_context_lost_flags_old - clear context loss flags (old API)
+ * prm_clear_context_loss_flags_old - clear context loss flags (old API)
  * @part: PRM partition ID (e.g., OMAP4430_PRM_PARTITION)
  * @inst: PRM instance offset (e.g., OMAP4430_PRM_MPU_INST)
  * @idx: CONTEXT register offset
@@ -497,6 +503,7 @@ int omap_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask)
 
 /**
  * omap_prm_vp_check_txdone - check voltage processor TX done status
+ * @vp_id: unique VP instance ID
  *
  * Checks if voltage processor transmission has been completed.
  * Returns non-zero if a transmission has completed, 0 otherwise.
@@ -514,6 +521,7 @@ u32 omap_prm_vp_check_txdone(u8 vp_id)
 
 /**
  * omap_prm_vp_clear_txdone - clears voltage processor TX done status
+ * @vp_id: unique VP instance ID
  *
  * Clears the status bit for completed voltage processor transmission
  * returned by prm_vp_check_txdone.
index d4ea56a5f75ad96da6b13ab4dba92f9cf3016774..898e7e332981c0344a285ba8d2083fad3d819ebd 100644 (file)
@@ -57,7 +57,7 @@ int omap2_wd_timer_disable(struct omap_hwmod *oh)
 }
 
 /**
- * omap2_wdtimer_reset - reset and disable the WDTIMER IP block
+ * omap2_wd_timer_reset - reset and disable the WDTIMER IP block
  * @oh: struct omap_hwmod *
  *
  * After the WDTIMER IP blocks are reset on OMAP2/3, we must also take
@@ -71,6 +71,8 @@ int omap2_wd_timer_disable(struct omap_hwmod *oh)
  * during a normal merge window.  omap_hwmod_softreset() should be
  * renamed to omap_hwmod_set_ocp_softreset(), and omap_hwmod_softreset()
  * should call the hwmod _ocp_softreset() code.
+ *
+ * Returns: %0 on success or -errno value on error.
  */
 int omap2_wd_timer_reset(struct omap_hwmod *oh)
 {
index 12a812e61c1639edbacfbe1f23550cabe15ed5e5..f4765be1b2a0965c8273585f2a27db95dc328d6c 100644 (file)
@@ -4,46 +4,21 @@ menuconfig ARCH_QCOM
        depends on ARCH_MULTI_V7
        select ARM_GIC
        select ARM_AMBA
+       select CLKSRC_QCOM
+       select HAVE_ARM_ARCH_TIMER
        select PINCTRL
        select QCOM_SCM if SMP
        help
          Support for Qualcomm's devicetree based systems.
+         This includes support for a few devices with ARM64 SoC, that have
+         ARM32 signed firmware that does not allow booting ARM64 kernels.
 
 if ARCH_QCOM
 
-config ARCH_IPQ40XX
-       bool "Enable support for IPQ40XX"
-       select CLKSRC_QCOM
-       select HAVE_ARM_ARCH_TIMER
-
-config ARCH_MSM8X60
-       bool "Enable support for MSM8X60"
-       select CLKSRC_QCOM
-
-config ARCH_MSM8909
-       bool "Enable support for MSM8909"
-       select HAVE_ARM_ARCH_TIMER
-
-config ARCH_MSM8916
-       bool "Enable support for MSM8916"
-       select HAVE_ARM_ARCH_TIMER
+config ARCH_QCOM_RESERVE_SMEM
+       bool "Reserve SMEM at the beginning of RAM"
        help
-         Enable support for the Qualcomm Snapdragon 410 (MSM8916/APQ8016).
-
-         Note that ARM64 is the main supported architecture for MSM8916.
-         The ARM32 option is intended for a few devices with signed firmware
-         that does not allow booting ARM64 kernels.
-
-config ARCH_MSM8960
-       bool "Enable support for MSM8960"
-       select CLKSRC_QCOM
-
-config ARCH_MSM8974
-       bool "Enable support for MSM8974"
-       select HAVE_ARM_ARCH_TIMER
-
-config ARCH_MDM9615
-       bool "Enable support for MDM9615"
-       select CLKSRC_QCOM
+         Reserve 2MB at the beginning of the System RAM for shared mem.
+         This is required on IPQ40xx, MSM8x60 and MSM8960 platforms.
 
 endif
index d0adc9b40e25180138efeea813f208f479d2fb70..a0187606b999a03902542d5c9862ec991cd42f5f 100644 (file)
@@ -76,6 +76,6 @@ extern void s3c24xx_init_uartdevs(char *name,
                                  struct s3c24xx_uart_resources *res,
                                  struct s3c2410_uartcfg *cfg, int no);
 
-extern struct bus_type s3c6410_subsys;
+extern const struct bus_type s3c6410_subsys;
 
 #endif
index e79f18d0ca81efb17b35399cc1407804c9cce63e..a29276a4fde53e9e934424f2eb0013462467de5b 100644 (file)
@@ -57,7 +57,7 @@ void __init s3c6410_init_irq(void)
        s3c64xx_init_irq(~0 & ~(1 << 7), ~0);
 }
 
-struct bus_type s3c6410_subsys = {
+const struct bus_type s3c6410_subsys = {
        .name           = "s3c6410-core",
        .dev_name       = "s3c6410-core",
 };
index 9f9717874d676c1bdbbc6be3c74f35b7344bb4c0..6c70ea7f2931280f38b3e21525055409bed8becd 100644 (file)
@@ -149,7 +149,7 @@ static struct map_desc s3c_iodesc[] __initdata = {
        },
 };
 
-static struct bus_type s3c64xx_subsys = {
+static const struct bus_type s3c64xx_subsys = {
        .name           = "s3c64xx-core",
        .dev_name       = "s3c64xx-core",
 };
index d59c094cdea8bad55171c2fa22af5644b4aa3453..6fa70f787df4e0e66d702a8bb0d9d47110c5673c 100644 (file)
@@ -47,7 +47,7 @@ static void s3c_pm_do_save(struct sleep_save *ptr, int count)
 }
 
 /**
- * s3c_pm_do_restore() - restore register values from the save list.
+ * s3c_pm_do_restore_core() - restore register values from the save list.
  * @ptr: Pointer to an array of registers.
  * @count: Size of the ptr array.
  *
index 9765b3f4c2fc5f7277732b202e391b8acd4e92bb..6aae14b0736ce6b594cb398b116086552cf504d1 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/mfd/syscon.h>
 #include <linux/of_address.h>
 #include <linux/regmap.h>
-#include <linux/clk/zynq.h>
 #include "common.h"
 
 /* register offsets */
@@ -146,7 +145,7 @@ void zynq_slcr_cpu_stop(int cpu)
 }
 
 /**
- * zynq_slcr_cpu_state - Read/write cpu state
+ * zynq_slcr_cpu_state_read - Read cpu state
  * @cpu:       cpu number
  *
  * SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
@@ -165,7 +164,7 @@ bool zynq_slcr_cpu_state_read(int cpu)
 }
 
 /**
- * zynq_slcr_cpu_state - Read/write cpu state
+ * zynq_slcr_cpu_state_write - Write cpu state
  * @cpu:       cpu number
  * @die:       cpu state - true if cpu is going to die
  *
index aa7c1d435139684d7b56f96f3f93945d331d64d6..29290b8cb36dce29cd8fead0a3b8ee6a63326ee8 100644 (file)
@@ -277,27 +277,21 @@ config 64BIT
 config MMU
        def_bool y
 
-config ARM64_PAGE_SHIFT
-       int
-       default 16 if ARM64_64K_PAGES
-       default 14 if ARM64_16K_PAGES
-       default 12
-
 config ARM64_CONT_PTE_SHIFT
        int
-       default 5 if ARM64_64K_PAGES
-       default 7 if ARM64_16K_PAGES
+       default 5 if PAGE_SIZE_64KB
+       default 7 if PAGE_SIZE_16KB
        default 4
 
 config ARM64_CONT_PMD_SHIFT
        int
-       default 5 if ARM64_64K_PAGES
-       default 5 if ARM64_16K_PAGES
+       default 5 if PAGE_SIZE_64KB
+       default 5 if PAGE_SIZE_16KB
        default 4
 
 config ARCH_MMAP_RND_BITS_MIN
-       default 14 if ARM64_64K_PAGES
-       default 16 if ARM64_16K_PAGES
+       default 14 if PAGE_SIZE_64KB
+       default 16 if PAGE_SIZE_16KB
        default 18
 
 # max bits determined by the following formula:
@@ -1259,11 +1253,13 @@ choice
 
 config ARM64_4K_PAGES
        bool "4KB"
+       select HAVE_PAGE_SIZE_4KB
        help
          This feature enables 4KB pages support.
 
 config ARM64_16K_PAGES
        bool "16KB"
+       select HAVE_PAGE_SIZE_16KB
        help
          The system will use 16KB pages support. AArch32 emulation
          requires applications compiled with 16K (or a multiple of 16K)
@@ -1271,6 +1267,7 @@ config ARM64_16K_PAGES
 
 config ARM64_64K_PAGES
        bool "64KB"
+       select HAVE_PAGE_SIZE_64KB
        help
          This feature enables 64KB pages support (4KB by default)
          allowing only two levels of page tables and faster TLB
@@ -1291,19 +1288,19 @@ choice
 
 config ARM64_VA_BITS_36
        bool "36-bit" if EXPERT
-       depends on ARM64_16K_PAGES
+       depends on PAGE_SIZE_16KB
 
 config ARM64_VA_BITS_39
        bool "39-bit"
-       depends on ARM64_4K_PAGES
+       depends on PAGE_SIZE_4KB
 
 config ARM64_VA_BITS_42
        bool "42-bit"
-       depends on ARM64_64K_PAGES
+       depends on PAGE_SIZE_64KB
 
 config ARM64_VA_BITS_47
        bool "47-bit"
-       depends on ARM64_16K_PAGES
+       depends on PAGE_SIZE_16KB
 
 config ARM64_VA_BITS_48
        bool "48-bit"
index 91d505b385de5a55f66b125586158c75720672a6..21149b346a60ebe4eac4eabc0980cf38d08437a2 100644 (file)
@@ -16,6 +16,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pinetab.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pinetab-early-adopter.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-sopine-baseboard.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-teres-i.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h64-remix-mini-pc.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a100-allwinner-perf1.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-bananapi-m2-plus.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-bananapi-m2-plus-v1.2.dtb
@@ -42,5 +43,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h616-bigtreetech-cb1-manta.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h616-bigtreetech-pi.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h616-orangepi-zero2.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h616-x96-mate.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h618-longanpi-3h.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h618-orangepi-zero2w.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h618-orangepi-zero3.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h618-transpeed-8k618-t.dtb
index 9ec49ac2f6fd5dbc13c8694473c66bcde10cff81..381d58cea092d9f8dadfe6f37ba2caa52d700c1c 100644 (file)
 };
 
 &spdif {
+       pinctrl-names = "default";
+       pinctrl-0 = <&spdif_tx_pin>;
        status = "okay";
 };
 
index 4903d6358112def0c27c224c9757e7505bda75be..855b7d43bc503ab3b2a042ef51f31d54a9dbaf1d 100644 (file)
 };
 
 &spdif {
+       pinctrl-names = "default";
+       pinctrl-0 = <&spdif_tx_pin>;
        status = "okay";
 };
 
index ca1d287a0a01d981f12cccf5f990303085a60462..d11e5041bae9a470242e0226ecde743dd1b72fa7 100644 (file)
                                function = "spi1";
                        };
 
+                       /omit-if-no-ref/
                        spdif_tx_pin: spdif-tx-pin {
                                pins = "PH7";
                                function = "spdif";
                        clocks = <&ccu CLK_BUS_SPDIF>, <&ccu CLK_SPDIF>;
                        clock-names = "apb", "spdif";
                        resets = <&ccu RST_BUS_SPDIF>;
-                       dmas = <&dma 2>;
-                       dma-names = "tx";
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&spdif_tx_pin>;
+                       dmas = <&dma 2>, <&dma 2>;
+                       dma-names = "rx", "tx";
                        status = "disabled";
                };
 
index dbce61b355d65e3a185cfc8ff178fc253f8f4994..4bfb52609c942ab556ebaf61b73f4bfbd2ad5f95 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2023 Martin Botka <martin.botka@somainline.org>.
  */
index 1fed2b46cfe87a205dc03cd0c481a79399f40a44..af421ba24ce0c6daae4c015ab219e3c80fbc6fa0 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2023 Martin Botka <martin.botka@somainline.org>.
  */
@@ -93,7 +93,7 @@
                interrupt-controller;
                #interrupt-cells = <1>;
 
-               regulators{
+               regulators {
                        reg_dcdc1: dcdc1 {
                                regulator-name = "vdd-gpu-sys";
                                regulator-min-microvolt = <810000>;
index 832f08b2b2608038ae1410f7be71f256898aace5..ff84a37944703683e8eec5fdd4801361331e951a 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2023 Martin Botka <martin@biqu3d.com>.
  */
index d549d277d9729f2fdb78173addb4c1335e4ece91..b2e85e52d1a12217e94cfd3b64b00b131075e76c 100644 (file)
@@ -9,6 +9,7 @@
 #include <dt-bindings/clock/sun6i-rtc.h>
 #include <dt-bindings/reset/sun50i-h616-ccu.h>
 #include <dt-bindings/reset/sun50i-h6-r-ccu.h>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
        interrupt-parent = <&gic>;
                        #reset-cells = <1>;
                };
 
+               dma: dma-controller@3002000 {
+                       compatible = "allwinner,sun50i-h616-dma",
+                                    "allwinner,sun50i-a100-dma";
+                       reg = <0x03002000 0x1000>;
+                       interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_DMA>, <&ccu CLK_MBUS_DMA>;
+                       clock-names = "bus", "mbus";
+                       dma-channels = <16>;
+                       dma-requests = <49>;
+                       resets = <&ccu RST_BUS_DMA>;
+                       #dma-cells = <1>;
+               };
+
                sid: efuse@3006000 {
                        compatible = "allwinner,sun50i-h616-sid", "allwinner,sun50i-a64-sid";
                        reg = <0x03006000 0x1000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
+
+                       ths_calibration: thermal-sensor-calibration@14 {
+                               reg = <0x14 0x8>;
+                       };
                };
 
                watchdog: watchdog@30090a0 {
                                function = "spi1";
                        };
 
+                       spdif_tx_pin: spdif-tx-pin {
+                               pins = "PH4";
+                               function = "spdif";
+                       };
+
                        uart0_ph_pins: uart0-ph-pins {
                                pins = "PH0", "PH1";
                                function = "uart0";
                                pins = "PG8", "PG9";
                                function = "uart1";
                        };
+
+                       /omit-if-no-ref/
+                       x32clk_fanout_pin: x32clk-fanout-pin {
+                               pins = "PG10";
+                               function = "clock";
+                       };
                };
 
                gic: interrupt-controller@3021000 {
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clocks = <&ccu CLK_BUS_UART0>;
+                       dmas = <&dma 14>, <&dma 14>;
+                       dma-names = "tx", "rx";
                        resets = <&ccu RST_BUS_UART0>;
                        status = "disabled";
                };
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clocks = <&ccu CLK_BUS_UART1>;
+                       dmas = <&dma 15>, <&dma 15>;
+                       dma-names = "tx", "rx";
                        resets = <&ccu RST_BUS_UART1>;
                        status = "disabled";
                };
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clocks = <&ccu CLK_BUS_UART2>;
+                       dmas = <&dma 16>, <&dma 16>;
+                       dma-names = "tx", "rx";
                        resets = <&ccu RST_BUS_UART2>;
                        status = "disabled";
                };
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clocks = <&ccu CLK_BUS_UART3>;
+                       dmas = <&dma 17>, <&dma 17>;
+                       dma-names = "tx", "rx";
                        resets = <&ccu RST_BUS_UART3>;
                        status = "disabled";
                };
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clocks = <&ccu CLK_BUS_UART4>;
+                       dmas = <&dma 18>, <&dma 18>;
+                       dma-names = "tx", "rx";
                        resets = <&ccu RST_BUS_UART4>;
                        status = "disabled";
                };
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        clocks = <&ccu CLK_BUS_UART5>;
+                       dmas = <&dma 19>, <&dma 19>;
+                       dma-names = "tx", "rx";
                        resets = <&ccu RST_BUS_UART5>;
                        status = "disabled";
                };
                        reg = <0x05002000 0x400>;
                        interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_I2C0>;
+                       dmas = <&dma 43>, <&dma 43>;
+                       dma-names = "rx", "tx";
                        resets = <&ccu RST_BUS_I2C0>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&i2c0_pins>;
                        reg = <0x05002400 0x400>;
                        interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_I2C1>;
+                       dmas = <&dma 44>, <&dma 44>;
+                       dma-names = "rx", "tx";
                        resets = <&ccu RST_BUS_I2C1>;
                        status = "disabled";
                        #address-cells = <1>;
                        reg = <0x05002800 0x400>;
                        interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_I2C2>;
+                       dmas = <&dma 45>, <&dma 45>;
+                       dma-names = "rx", "tx";
                        resets = <&ccu RST_BUS_I2C2>;
                        status = "disabled";
                        #address-cells = <1>;
                        reg = <0x05002c00 0x400>;
                        interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_I2C3>;
+                       dmas = <&dma 46>, <&dma 46>;
+                       dma-names = "rx", "tx";
                        resets = <&ccu RST_BUS_I2C3>;
                        status = "disabled";
                        #address-cells = <1>;
                        reg = <0x05003000 0x400>;
                        interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_I2C4>;
+                       dmas = <&dma 47>, <&dma 47>;
+                       dma-names = "rx", "tx";
                        resets = <&ccu RST_BUS_I2C4>;
                        status = "disabled";
                        #address-cells = <1>;
                        interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
                        clock-names = "ahb", "mod";
+                       dmas = <&dma 22>, <&dma 22>;
+                       dma-names = "rx", "tx";
                        resets = <&ccu RST_BUS_SPI0>;
                        status = "disabled";
                        #address-cells = <1>;
                        interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
                        clock-names = "ahb", "mod";
+                       dmas = <&dma 23>, <&dma 23>;
+                       dma-names = "rx", "tx";
                        resets = <&ccu RST_BUS_SPI1>;
                        status = "disabled";
                        #address-cells = <1>;
                        };
                };
 
+               spdif: spdif@5093000 {
+                       compatible = "allwinner,sun50i-h616-spdif";
+                       reg = <0x05093000 0x400>;
+                       interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_SPDIF>, <&ccu CLK_SPDIF>;
+                       clock-names = "apb", "spdif";
+                       resets = <&ccu RST_BUS_SPDIF>;
+                       dmas = <&dma 2>;
+                       dma-names = "tx";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&spdif_tx_pin>;
+                       #sound-dai-cells = <0>;
+                       status = "disabled";
+               };
+
+               ths: thermal-sensor@5070400 {
+                       compatible = "allwinner,sun50i-h616-ths";
+                       reg = <0x05070400 0x400>;
+                       interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_THS>;
+                       clock-names = "bus";
+                       resets = <&ccu RST_BUS_THS>;
+                       nvmem-cells = <&ths_calibration>;
+                       nvmem-cell-names = "calibration";
+                       allwinner,sram = <&syscon>;
+                       #thermal-sensor-cells = <1>;
+               };
+
                usbotg: usb@5100000 {
                        compatible = "allwinner,sun50i-h616-musb",
                                     "allwinner,sun8i-h3-musb";
                        reg = <0x07081400 0x400>;
                        interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&r_ccu CLK_R_APB2_I2C>;
+                       dmas = <&dma 48>, <&dma 48>;
+                       dma-names = "rx", "tx";
                        resets = <&r_ccu RST_R_APB2_I2C>;
                        status = "disabled";
                        #address-cells = <1>;
                        #size-cells = <0>;
                };
        };
+
+       thermal-zones {
+               cpu-thermal {
+                       polling-delay-passive = <500>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&ths 2>;
+                       sustainable-power = <1000>;
+
+                       trips {
+                               cpu_threshold: cpu-trip-0 {
+                                       temperature = <60000>;
+                                       type = "passive";
+                                       hysteresis = <0>;
+                               };
+                               cpu_target: cpu-trip-1 {
+                                       temperature = <70000>;
+                                       type = "passive";
+                                       hysteresis = <0>;
+                               };
+                               cpu_critical: cpu-trip-2 {
+                                       temperature = <110000>;
+                                       type = "critical";
+                                       hysteresis = <0>;
+                               };
+                       };
+               };
+
+               gpu-thermal {
+                       polling-delay-passive = <500>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&ths 0>;
+                       sustainable-power = <1100>;
+
+                       trips {
+                               gpu_temp_critical: gpu-trip-0 {
+                                       temperature = <110000>;
+                                       type = "critical";
+                                       hysteresis = <0>;
+                               };
+                       };
+               };
+
+               ve-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+                       thermal-sensors = <&ths 1>;
+
+                       trips {
+                               ve_temp_critical: ve-trip-0 {
+                                       temperature = <110000>;
+                                       type = "critical";
+                                       hysteresis = <0>;
+                               };
+                       };
+               };
+
+               ddr-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+                       thermal-sensors = <&ths 3>;
+
+                       trips {
+                               ddr_temp_critical: ddr-trip-0 {
+                                       temperature = <110000>;
+                                       type = "critical";
+                                       hysteresis = <0>;
+                               };
+                       };
+               };
+       };
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-longan-module-3h.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h618-longan-module-3h.dtsi
new file mode 100644 (file)
index 0000000..8c1263a
--- /dev/null
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) Jisheng Zhang <jszhang@kernel.org>
+ */
+
+#include "sun50i-h616.dtsi"
+
+&mmc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc2_pins>;
+       vmmc-supply = <&reg_dldo1>;
+       vqmmc-supply = <&reg_aldo1>;
+       bus-width = <8>;
+       non-removable;
+       cap-mmc-hw-reset;
+       mmc-ddr-1_8v;
+       mmc-hs200-1_8v;
+       status = "okay";
+};
+
+&r_i2c {
+       status = "okay";
+
+       axp313: pmic@36 {
+               compatible = "x-powers,axp313a";
+               reg = <0x36>;
+               #interrupt-cells = <1>;
+               interrupt-controller;
+
+               regulators {
+                       reg_aldo1: aldo1 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc-1v8-pll";
+                       };
+
+                       reg_dldo1: dldo1 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc-3v3-io";
+                       };
+
+                       reg_dcdc1: dcdc1 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <810000>;
+                               regulator-max-microvolt = <990000>;
+                               regulator-name = "vdd-gpu-sys";
+                       };
+
+                       reg_dcdc2: dcdc2 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <810000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-name = "vdd-cpu";
+                       };
+
+                       reg_dcdc3: dcdc3 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1100000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-name = "vdd-dram";
+                       };
+               };
+       };
+};
+
+&pio {
+       vcc-pc-supply = <&reg_dldo1>;
+       vcc-pf-supply = <&reg_dldo1>;
+       vcc-pg-supply = <&reg_aldo1>;
+       vcc-ph-supply = <&reg_dldo1>;
+       vcc-pi-supply = <&reg_dldo1>;
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-longanpi-3h.dts b/arch/arm64/boot/dts/allwinner/sun50i-h618-longanpi-3h.dts
new file mode 100644 (file)
index 0000000..18b29c6
--- /dev/null
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) Jisheng Zhang <jszhang@kernel.org>
+ */
+
+/dts-v1/;
+
+#include "sun50i-h618-longan-module-3h.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+       model = "Sipeed Longan Pi 3H";
+       compatible = "sipeed,longan-pi-3h", "sipeed,longan-module-3h", "allwinner,sun50i-h618";
+
+       aliases {
+               ethernet0 = &emac0;
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led-0 {
+                       color = <LED_COLOR_ID_ORANGE>;
+                       function = LED_FUNCTION_INDICATOR;
+                       function-enumerator = <0>;
+                       gpios = <&pio 6 2 GPIO_ACTIVE_LOW>; /* PG2 */
+               };
+
+               led-1 {
+                       color = <LED_COLOR_ID_ORANGE>;
+                       function = LED_FUNCTION_INDICATOR;
+                       function-enumerator = <1>;
+                       gpios = <&pio 6 4 GPIO_ACTIVE_LOW>; /* PG4 */
+               };
+       };
+
+       reg_vcc5v: regulator-vcc5v {
+               /* board wide 5V supply directly from the USB-C socket */
+               compatible = "regulator-fixed";
+               regulator-name = "vcc-5v";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+       };
+
+       reg_vcc3v3: regulator-vcc3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc-3v3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+               vin-supply = <&reg_vcc5v>;
+       };
+};
+
+&axp313 {
+       vin1-supply = <&reg_vcc5v>;
+       vin2-supply = <&reg_vcc5v>;
+       vin3-supply = <&reg_vcc5v>;
+};
+
+&ehci1 {
+       status = "okay";
+};
+
+&ohci1 {
+       status = "okay";
+};
+
+&ehci2 {
+       status = "okay";
+};
+
+&ohci2 {
+       status = "okay";
+};
+
+/* WiFi & BT combo module is connected to this Host */
+&ehci3 {
+       status = "okay";
+};
+
+&ohci3 {
+       status = "okay";
+};
+
+&emac0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&ext_rgmii_pins>;
+       phy-mode = "rgmii";
+       phy-handle = <&ext_rgmii_phy>;
+       allwinner,rx-delay-ps = <3100>;
+       allwinner,tx-delay-ps = <700>;
+       phy-supply = <&reg_vcc3v3>;
+       status = "okay";
+};
+
+&mdio0 {
+       ext_rgmii_phy: ethernet-phy@1 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <1>;
+       };
+};
+
+&mmc0 {
+       bus-width = <4>;
+       cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+       vmmc-supply = <&reg_vcc3v3>;
+       status = "okay";
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&usbotg {
+       /*
+        * PHY0 pins are connected to a USB-C socket, but a role switch
+        * is not implemented: both CC pins are pulled to GND.
+        * The VBUS pins power the device, so a fixed peripheral mode
+        * is the best choice.
+        * The board can be powered via GPIOs, in this case port0 *can*
+        * act as a host (with a cable/adapter ignoring CC), as VBUS is
+        * then provided by the GPIOs. Any user of this setup would
+        * need to adjust the DT accordingly: dr_mode set to "host",
+        * enabling OHCI0 and EHCI0.
+        */
+       dr_mode = "peripheral";
+       status = "okay";
+};
+
+&usbphy {
+       usb1_vbus-supply = <&reg_vcc5v>;
+       usb2_vbus-supply = <&reg_vcc5v>;
+       status = "okay";
+};
index 8ea1fd41aebaa0244c82dad8e83661d408e85f60..ac0a2b7ea6f31089fba1bae1d76fbffba859320f 100644 (file)
@@ -15,6 +15,7 @@
        compatible = "transpeed,8k618-t", "allwinner,sun50i-h618";
 
        aliases {
+               ethernet1 = &sdio_wifi;
                serial0 = &uart0;
        };
 
                regulator-max-microvolt = <3300000>;
                regulator-always-on;
        };
+
+       wifi_pwrseq: wifi_pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
+               clock-names = "ext_clock";
+               pinctrl-0 = <&x32clk_fanout_pin>;
+               pinctrl-names = "default";
+               reset-gpios = <&pio 6 18 GPIO_ACTIVE_LOW>; /* PG18 */
+       };
 };
 
 &ehci0 {
        status = "okay";
 };
 
+&mmc1 {
+       vmmc-supply = <&reg_dldo1>;
+       vqmmc-supply = <&reg_aldo1>;
+       mmc-pwrseq = <&wifi_pwrseq>;
+       bus-width = <4>;
+       non-removable;
+       status = "okay";
+
+       sdio_wifi: wifi@1 {
+               reg = <1>;
+       };
+};
+
 &mmc2 {
        vmmc-supply = <&reg_dldo1>;
        vqmmc-supply = <&reg_aldo1>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h64-remix-mini-pc.dts b/arch/arm64/boot/dts/allwinner/sun50i-h64-remix-mini-pc.dts
new file mode 100644 (file)
index 0000000..b6e3c16
--- /dev/null
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (c) 2023 ARM Ltd.
+
+/dts-v1/;
+
+#include "sun50i-a64.dtsi"
+#include "sun50i-a64-cpu-opp.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       model = "Remix Mini PC";
+       compatible = "jide,remix-mini-pc", "allwinner,sun50i-h64",
+                    "allwinner,sun50i-a64";
+
+       aliases {
+               ethernet1 = &rtl8723bs;
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       hdmi-connector {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_con_in: endpoint {
+                               remote-endpoint = <&hdmi_out_con>;
+                       };
+               };
+       };
+
+       reg_vcc5v: regulator-5v {
+               /* board wide 5V supply directly from the DC input */
+               compatible = "regulator-fixed";
+               regulator-name = "vcc-5v";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+       };
+
+       wifi_pwrseq: wifi_pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */
+               post-power-on-delay-ms = <200>;
+       };
+};
+
+&codec {
+       status = "okay";
+};
+
+&codec_analog {
+       cpvdd-supply = <&reg_eldo1>;
+       status = "okay";
+};
+
+&cpu0 {
+       cpu-supply = <&reg_dcdc2>;
+};
+
+&cpu1 {
+       cpu-supply = <&reg_dcdc2>;
+};
+
+&cpu2 {
+       cpu-supply = <&reg_dcdc2>;
+};
+
+&cpu3 {
+       cpu-supply = <&reg_dcdc2>;
+};
+
+&dai {
+       status = "okay";
+};
+
+&de {
+       status = "okay";
+};
+
+&ehci0 {
+       status = "okay";
+};
+
+&ehci1 {
+       status = "okay";
+};
+
+&hdmi {
+       hvcc-supply = <&reg_dldo1>;
+       status = "okay";
+};
+
+&hdmi_out {
+       hdmi_out_con: endpoint {
+               remote-endpoint = <&hdmi_con_in>;
+       };
+};
+
+/* Connects to the AC200 chip */
+&i2c0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c0_pins>;
+       status = "okay";
+};
+
+&i2c0_pins {
+       bias-pull-up;
+};
+
+&mmc0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc0_pins>;
+       vmmc-supply = <&reg_dcdc1>;
+       cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
+       disable-wp;
+       bus-width = <4>;
+       status = "okay";
+};
+
+&mmc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc1_pins>;
+       vmmc-supply = <&reg_aldo1>;
+       vqmmc-supply = <&reg_dldo4>;
+       mmc-pwrseq = <&wifi_pwrseq>;
+       bus-width = <4>;
+       non-removable;
+       status = "okay";
+
+       rtl8723bs: wifi@1 {
+               reg = <1>;
+               interrupt-parent = <&r_pio>;
+               interrupts = <0 3 IRQ_TYPE_LEVEL_LOW>; /* PL3 */
+               interrupt-names = "host-wake";
+       };
+};
+
+&mmc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc2_pins>, <&mmc2_ds_pin>;
+       vmmc-supply = <&reg_dcdc1>;
+       vqmmc-supply = <&reg_eldo1>;
+       bus-width = <8>;
+       non-removable;
+       mmc-hs200-1_8v;
+       mmc-hs400-1_8v;
+       cap-mmc-hw-reset;
+       status = "okay";
+};
+
+&ohci0 {
+       status = "okay";
+};
+
+&ohci1 {
+       status = "okay";
+};
+
+&pio {
+       vcc-pb-supply = <&reg_dcdc1>;
+       vcc-pc-supply = <&reg_dcdc1>;
+       vcc-pd-supply = <&reg_dcdc1>;
+       vcc-pe-supply = <&reg_dcdc1>;
+       vcc-pf-supply = <&reg_dcdc1>;
+       vcc-pg-supply = <&reg_dldo4>;
+       vcc-ph-supply = <&reg_dcdc1>;
+};
+
+&r_ir {
+       status = "okay";
+};
+
+&r_pio {
+       /*
+        * We cannot add that supply for now since it would create a circular
+        * dependency between pinctrl, the regulator and the RSB Bus.
+        *
+        * vcc-pl-supply = <&reg_aldo2>;
+        */
+};
+
+&r_rsb {
+       status = "okay";
+
+       axp803: pmic@3a3 {
+               compatible = "x-powers,axp803";
+               reg = <0x3a3>;
+               interrupt-parent = <&r_intc>;
+               interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_LOW>;
+               x-powers,drive-vbus-en;
+
+               vin1-supply = <&reg_vcc5v>;
+               vin2-supply = <&reg_vcc5v>;
+               vin3-supply = <&reg_vcc5v>;
+               vin5-supply = <&reg_vcc5v>;
+               vin6-supply = <&reg_vcc5v>;
+               aldoin-supply = <&reg_vcc5v>;
+               dldoin-supply = <&reg_vcc5v>;
+               eldoin-supply = <&reg_vcc5v>;
+               fldoin-supply = <&reg_vcc5v>;
+               drivevbus-supply = <&reg_vcc5v>;
+               ips-supply = <&reg_vcc5v>;
+
+               status = "okay";
+       };
+};
+
+#include "axp803.dtsi"
+
+&ac_power_supply {
+       status = "okay";
+};
+
+&reg_dcdc1 {
+       regulator-always-on;
+       regulator-min-microvolt = <3300000>;
+       regulator-max-microvolt = <3300000>;
+       regulator-name = "vcc-3v3";
+};
+
+&reg_dcdc2 {
+       regulator-always-on;
+       regulator-min-microvolt = <1040000>;
+       regulator-max-microvolt = <1300000>;
+       regulator-name = "vdd-cpux";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+&reg_dcdc5 {
+       regulator-always-on;
+       regulator-min-microvolt = <1500000>;
+       regulator-max-microvolt = <1500000>;
+       regulator-name = "vcc-dram";
+};
+
+/* Deviates from the reset default of 1.1V. */
+&reg_dcdc6 {
+       regulator-always-on;
+       regulator-min-microvolt = <1200000>;
+       regulator-max-microvolt = <1200000>;
+       regulator-name = "vdd-sys";
+};
+
+&reg_aldo1 {
+       regulator-min-microvolt = <3300000>;
+       regulator-max-microvolt = <3300000>;
+       regulator-name = "vcc-wifi";
+};
+
+&reg_aldo2 {
+       /* Specifying R_PIO consumer would create circular dependency. */
+       regulator-always-on;
+       regulator-min-microvolt = <3300000>;
+       regulator-max-microvolt = <3300000>;
+       regulator-name = "vcc-pl";
+};
+
+&reg_aldo3 {
+       regulator-always-on;
+       regulator-min-microvolt = <3000000>;
+       regulator-max-microvolt = <3000000>;
+       regulator-name = "vcc-pll-avcc";
+};
+
+/* AC200 power supply */
+&reg_dldo1 {
+       regulator-always-on;
+       regulator-min-microvolt = <3300000>;
+       regulator-max-microvolt = <3300000>;
+       regulator-name = "vcc-ave-33";
+};
+
+&reg_dldo4 {
+       regulator-min-microvolt = <3300000>;
+       regulator-max-microvolt = <3300000>;
+       regulator-name = "vcc-wifi-io";
+};
+
+&reg_drivevbus {
+       regulator-name = "usb0-vbus";
+       status = "okay";
+};
+
+&reg_eldo1 {
+       regulator-always-on;
+       regulator-min-microvolt = <1800000>;
+       regulator-max-microvolt = <1800000>;
+       regulator-name = "vcc-cpvdd-dram-emmc";
+};
+
+/* Supplies the arisc management core, needed by TF-A to power off cores. */
+&reg_fldo2 {
+       regulator-always-on;
+       regulator-min-microvolt = <1100000>;
+       regulator-max-microvolt = <1100000>;
+       regulator-name = "vdd-cpus";
+};
+
+&reg_rtc_ldo {
+       regulator-name = "vcc-rtc";
+};
+
+&simplefb_hdmi {
+       vcc-hdmi-supply = <&reg_dcdc1>;
+};
+
+&sound {
+       simple-audio-card,aux-devs = <&codec_analog>;
+       simple-audio-card,widgets = "Microphone", "Microphone Jack",
+                                   "Headphone", "Headphone Jack";
+       simple-audio-card,routing =
+                       "Left DAC", "DACL",
+                       "Right DAC", "DACR",
+                       "Headphone Jack", "HP",
+                       "ADCL", "Left ADC",
+                       "ADCR", "Right ADC",
+                       "MIC2", "Microphone Jack";
+       status = "okay";
+};
+
+/* On the (unpopulated) UART pads. */
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_pb_pins>;
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+       uart-has-rtscts;
+       status = "okay";
+
+       bluetooth {
+               compatible = "realtek,rtl8723bs-bt";
+               enable-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */
+               max-speed = <1500000>;
+       };
+};
+
+&usb_otg {
+       dr_mode = "host";
+       status = "okay";
+};
+
+&usbphy {
+       usb0_vbus-supply = <&reg_drivevbus>;
+       usb1_vbus-supply = <&reg_drivevbus>;
+       status = "okay";
+};
index dccbba6e7f98e49f572b57c86415dced108fee2d..dbf2dce8d1d68a5225311bf330704e9f6d1ead40 100644 (file)
                msix: msix@fbe00000 {
                        compatible = "al,alpine-msix";
                        reg = <0x0 0xfbe00000 0x0 0x100000>;
-                       interrupt-controller;
                        msi-controller;
                        al,msi-base-spi = <160>;
                        al,msi-num-spis = <160>;
index 39481d7fd7d4da806fe1ab1e4b2320cc732f37d5..3ea178acdddfe2072352283f47318f0f75808c4f 100644 (file)
                msix: msix@fbe00000 {
                        compatible = "al,alpine-msix";
                        reg = <0x0 0xfbe00000 0x0 0x100000>;
-                       interrupt-controller;
                        msi-controller;
                        al,msi-base-spi = <336>;
                        al,msi-num-spis = <959>;
index cc8b34bd583d84019cf6b2ad2e7460d842a80fb4..1ab160bf928ae4306768bbf1707325113d6f9bee 100644 (file)
@@ -8,6 +8,8 @@ dtb-$(CONFIG_ARCH_MESON) += meson-axg-jethome-jethub-j100.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-axg-jethome-jethub-j110-rev-2.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-axg-jethome-jethub-j110-rev-3.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-axg-s400.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-g12a-fbx8am-brcm.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-g12a-fbx8am-realtek.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-g12a-radxa-zero.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-g12a-sei510.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-g12a-u200.dtb
@@ -80,3 +82,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-sm1-odroid-hc4.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-sm1-sei610.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-sm1-x96-air-gbit.dtb
 dtb-$(CONFIG_ARCH_MESON) += meson-sm1-x96-air.dtb
+
+# Overlays
+meson-g12a-fbx8am-brcm-dtbs    := meson-g12a-fbx8am.dtb meson-g12a-fbx8am-brcm.dtbo
+meson-g12a-fbx8am-realtek-dtbs := meson-g12a-fbx8am.dtb meson-g12a-fbx8am-realtek.dtbo
index 2ad1f8eef1996ffc4806cf722433391675186c80..32a754fe7990fe7bb722b6474c27b2ca455d7f40 100644 (file)
@@ -6,6 +6,7 @@
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/reset/amlogic,c3-reset.h>
 
 / {
        cpus {
                        #size-cells = <2>;
                        ranges = <0x0 0x0 0x0 0xfe000000 0x0 0x480000>;
 
+                       reset: reset-controller@2000 {
+                               compatible = "amlogic,c3-reset";
+                               reg = <0x0 0x2000 0x0 0x98>;
+                               #reset-cells = <1>;
+                       };
+
                        watchdog@2100 {
                                compatible = "amlogic,c3-wdt", "amlogic,t7-wdt";
                                reg = <0x0 0x2100 0x0 0x10>;
index a03c7667d2b636b35abd68b26548e04f4a411f59..5248bdf824ea6004f5e2844aed47a745afa27e65 100644 (file)
@@ -54,7 +54,7 @@
                        enable-method = "psci";
                };
 
-               cpu101: cpu@101{
+               cpu101: cpu@101 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a53";
                        reg = <0x0 0x101>;
                                };
                        };
 
+                       gpio_intc: interrupt-controller@4080 {
+                               compatible = "amlogic,t7-gpio-intc",
+                                            "amlogic,meson-gpio-intc";
+                               reg = <0x0 0x4080 0x0 0x20>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                               amlogic,channel-interrupts =
+                                       <10 11 12 13 14 15 16 17 18 19 20 21>;
+                       };
+
                        uart_a: serial@78000 {
                                compatible = "amlogic,t7-uart", "amlogic,meson-s4-uart";
                                reg = <0x0 0x78000 0x0 0x18>;
index 1c20516fa653a8a0994d604258bf2db54b80b882..4bc30af0584875d8961b3ae8bde280e375e92322 100644 (file)
        pinctrl-0 = <&spifc_pins>;
        pinctrl-names = "default";
 
-       spi_nand@0 {
+       flash@0 {
                compatible = "spi-nand";
                status = "okay";
                reg = <0>;
index 648e7f49424f1037f68933dd2c8921cc9363614f..c03e207ea6c5d64abf765c42d20651633c234697 100644 (file)
                                 <&clkc_periphs CLKID_USB_BUS>,
                                 <&clkc_periphs CLKID_USB_CTRL_IN>;
                        clock-names = "usb_ctrl", "usb_bus", "xtal_usb_ctrl";
+                       assigned-clocks = <&clkc_periphs CLKID_USB_BUS>;
+                       assigned-clock-rates = <64000000>;
                        resets = <&reset RESET_USBCTRL>;
                        reset-name = "usb_ctrl";
 
index db605f3a22b4a990633de6e2528d9ed8b11134e3..9b65ae818e2f29335a551529c15fdc46be18dce7 100644 (file)
@@ -35,7 +35,7 @@
                reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
@@ -44,7 +44,7 @@
                regulator-always-on;
        };
 
-       vcc_5v: regulator-vcc_5v {
+       vcc_5v: regulator-vcc-5v {
                compatible = "regulator-fixed";
                regulator-name = "VCC5V";
                regulator-min-microvolt = <5000000>;
@@ -52,7 +52,7 @@
                regulator-always-on;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
@@ -61,7 +61,7 @@
                regulator-always-on;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
@@ -70,7 +70,7 @@
                regulator-always-on;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <3300000>;
@@ -79,7 +79,7 @@
                regulator-always-on;
        };
 
-       vccq_1v8: regulator-vccq_1v8 {
+       vccq_1v8: regulator-vccq-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VCCQ_1V8";
                regulator-min-microvolt = <1800000>;
@@ -88,7 +88,7 @@
                regulator-always-on;
        };
 
-       usb_pwr: regulator-usb_pwr {
+       usb_pwr: regulator-usb-pwr {
                compatible = "regulator-fixed";
                regulator-name = "USB_PWR";
                regulator-min-microvolt = <5000000>;
                "", "", "", "", "", // 80 - 84
                "", ""; // 85-86
 };
-
-&cpu0 {
-       #cooling-cells = <2>;
-};
-
-&cpu1 {
-       #cooling-cells = <2>;
-};
-
-&cpu2 {
-       #cooling-cells = <2>;
-};
-
-&cpu3 {
-       #cooling-cells = <2>;
-};
index c8905663bc754176c43295b3810dae81c0c9a36c..7ed526f45175f607f4fe871e3aad088c2b8218c8 100644 (file)
@@ -12,7 +12,7 @@
        compatible = "amlogic,s400", "amlogic,a113d", "amlogic,meson-axg";
        model = "Amlogic Meson AXG S400 Development Board";
 
-       adc_keys {
+       keys {
                compatible = "adc-keys";
                io-channels = <&saradc 0>;
                io-channel-names = "buttons";
                reg = <0x0 0x0 0x0 0x40000000>;
        };
 
-       main_12v: regulator-main_12v {
+       main_12v: regulator-main-12v {
                compatible = "regulator-fixed";
                regulator-name = "12V";
                regulator-min-microvolt = <12000000>;
                regulator-always-on;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       vcc_5v: regulator-vcc_5v {
+       vcc_5v: regulator-vcc-5v {
                compatible = "regulator-fixed";
                regulator-name = "VCC5V";
                regulator-min-microvolt = <5000000>;
                enable-active-high;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       usb_pwr: regulator-usb_pwr {
+       usb_pwr: regulator-usb-pwr {
                compatible = "regulator-fixed";
                regulator-name = "USB_PWR";
                regulator-min-microvolt = <5000000>;
index 7e5ac9db93f8a7dae069fc91515b3f26d0f74b9d..6d12b760b90f75c2b857460e0f0e26fec900d55e 100644 (file)
@@ -74,6 +74,8 @@
                        enable-method = "psci";
                        next-level-cache = <&l2>;
                        clocks = <&scpi_dvfs 0>;
+                       dynamic-power-coefficient = <140>;
+                       #cooling-cells = <2>;
                };
 
                cpu1: cpu@1 {
@@ -83,6 +85,8 @@
                        enable-method = "psci";
                        next-level-cache = <&l2>;
                        clocks = <&scpi_dvfs 0>;
+                       dynamic-power-coefficient = <140>;
+                       #cooling-cells = <2>;
                };
 
                cpu2: cpu@2 {
@@ -92,6 +96,8 @@
                        enable-method = "psci";
                        next-level-cache = <&l2>;
                        clocks = <&scpi_dvfs 0>;
+                       dynamic-power-coefficient = <140>;
+                       #cooling-cells = <2>;
                };
 
                cpu3: cpu@3 {
                        enable-method = "psci";
                        next-level-cache = <&l2>;
                        clocks = <&scpi_dvfs 0>;
+                       dynamic-power-coefficient = <140>;
+                       #cooling-cells = <2>;
                };
 
                l2: l2-cache0 {
index ff68b911b72971f63150da28357ab976cdb1d9c6..9d5eab6595d022647ceb77a2f48c854f213cc2ed 100644 (file)
                clocks = <&clkc CLKID_NNA_CORE_CLK>,
                         <&clkc CLKID_NNA_AXI_CLK>;
                clock-names = "core", "bus";
+               assigned-clocks = <&clkc CLKID_NNA_CORE_CLK>,
+                                 <&clkc CLKID_NNA_AXI_CLK>;
+               assigned-clock-rates = <800000000>, <800000000>;
                resets = <&reset RESET_NNA>;
                status = "disabled";
        };
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-fbx8am-brcm.dtso b/arch/arm64/boot/dts/amlogic/meson-g12a-fbx8am-brcm.dtso
new file mode 100644 (file)
index 0000000..9591fdc
--- /dev/null
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (c) 2024 Freebox SAS
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/gpio/meson-g12a-gpio.h>
+
+&uart_A {
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+               max-speed = <2000000>;
+               clocks = <&wifi32k>;
+               clock-names = "lpo";
+               vbat-supply = <&vddao_3v3>;
+               vddio-supply = <&vddio_ao1v8>;
+       };
+};
+
+&sd_emmc_a {
+       /* Per mmc-controller.yaml */
+       #address-cells = <1>;
+       #size-cells = <0>;
+       /* NB: may be either AP6398S or AP6398SR3 wifi module */
+       brcmf: wifi@1 {
+               reg = <1>;
+               compatible = "brcm,bcm4329-fmac";
+       };
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-fbx8am-realtek.dtso b/arch/arm64/boot/dts/amlogic/meson-g12a-fbx8am-realtek.dtso
new file mode 100644 (file)
index 0000000..55fff35
--- /dev/null
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (c) 2024 Freebox SAS
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/gpio/meson-g12a-gpio.h>
+
+&uart_A {
+       bluetooth {
+               compatible = "realtek,rtl8822cs-bt";
+               enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+               host-wake-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>;
+               device-wake-gpios = <&gpio GPIOX_18 GPIO_ACTIVE_HIGH>;
+       };
+};
+
+&sd_emmc_a {
+       /* No explicit compatible for rtl8822cs sdio */
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-fbx8am.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-fbx8am.dts
new file mode 100644 (file)
index 0000000..af211d8
--- /dev/null
@@ -0,0 +1,462 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (c) 2024 Freebox SAS
+
+/*
+ * SEI codename: SEI530FB (based on SEI510)
+ * Freebox codename: fbx8am
+ * Commercial names: Freebox Pop, Player TV Free 4K
+ */
+
+/dts-v1/;
+
+#include "meson-g12a.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/meson-g12a-gpio.h>
+#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
+
+/ {
+       compatible = "freebox,fbx8am", "amlogic,g12a";
+       model = "Freebox Player Pop";
+       chassis-type = "embedded";
+
+       firmware {
+               optee {
+                       compatible = "linaro,optee-tz";
+                       method = "smc";
+               };
+       };
+
+       gpio-keys-polled {
+               compatible = "gpio-keys-polled";
+               poll-interval = <100>;
+
+               /* Physical user-accessible reset button near USB port */
+               power-button {
+                       label = "Reset";
+                       linux,code = <BTN_MISC>;
+                       gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       spdif_dit: audio-codec-2 {
+               #sound-dai-cells = <0>;
+               compatible = "linux,spdif-dit";
+               status = "okay";
+               sound-name-prefix = "DIT";
+       };
+
+       aliases {
+               serial0 = &uart_AO;
+               ethernet0 = &ethmac;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       emmc_pwrseq: emmc-pwrseq {
+               compatible = "mmc-pwrseq-emmc";
+               reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>;
+       };
+
+       hdmi-connector {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&hdmi_tx_tmds_out>;
+                       };
+               };
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x80000000>;
+       };
+
+       ao_5v: regulator-ao-5v {
+               compatible = "regulator-fixed";
+               regulator-name = "AO_5V";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&dc_in>;
+               regulator-always-on;
+       };
+
+       dc_in: regulator-dc-in {
+               compatible = "regulator-fixed";
+               regulator-name = "DC_IN";
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+               regulator-always-on;
+       };
+
+       emmc_1v8: regulator-emmc-1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "EMMC_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vddao_3v3>;
+               regulator-always-on;
+       };
+
+       vddao_3v3: regulator-vddao-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDAO_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&ao_5v>;
+               regulator-always-on;
+       };
+
+       vddao_3v3_t: regulator-vddao-3v3-t {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDAO_3V3_T";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vddao_3v3>;
+               gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>;
+               enable-active-high;
+       };
+
+       vddcpu: regulator-vddcpu {
+               /*
+                * SY8120B1ABC DC/DC Regulator.
+                */
+               compatible = "pwm-regulator";
+
+               regulator-name = "VDDCPU";
+               regulator-min-microvolt = <721000>;
+               regulator-max-microvolt = <1022000>;
+
+               pwm-supply = <&ao_5v>;
+
+               pwms = <&pwm_AO_cd 1 1250 0>;
+               pwm-dutycycle-range = <100 0>;
+
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       vddio_ao1v8: regulator-vddio-ao1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDDIO_AO1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vddao_3v3>;
+               regulator-always-on;
+       };
+
+       sdio_pwrseq: sdio-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
+               post-power-on-delay-ms = <10>; /* required for 43752 */
+               clocks = <&wifi32k>;
+               clock-names = "ext_clock";
+       };
+
+       wifi32k: wifi32k {
+               compatible = "pwm-clock";
+               #clock-cells = <0>;
+               clock-frequency = <32768>;
+               pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */
+       };
+
+       sound {
+               compatible = "amlogic,axg-sound-card";
+               model = "fbx8am";
+               audio-aux-devs = <&tdmout_b>;
+               audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1",
+                               "TDMOUT_B IN 1", "FRDDR_B OUT 1",
+                               "TDMOUT_B IN 2", "FRDDR_C OUT 1",
+                               "TDM_B Playback", "TDMOUT_B OUT",
+                               "SPDIFOUT_A IN 0", "FRDDR_A OUT 3",
+                               "SPDIFOUT_A IN 1", "FRDDR_B OUT 3",
+                               "SPDIFOUT_A IN 2", "FRDDR_C OUT 3";
+
+               assigned-clocks = <&clkc CLKID_MPLL2>,
+                                 <&clkc CLKID_MPLL0>,
+                                 <&clkc CLKID_MPLL1>;
+               assigned-clock-parents = <0>, <0>, <0>;
+               assigned-clock-rates = <294912000>,
+                                      <270950400>,
+                                      <393216000>;
+
+               dai-link-0 {
+                       sound-dai = <&frddr_a>;
+               };
+
+               dai-link-1 {
+                       sound-dai = <&frddr_b>;
+               };
+
+               dai-link-2 {
+                       sound-dai = <&frddr_c>;
+               };
+
+               /* 8ch hdmi interface */
+               dai-link-3 {
+                       sound-dai = <&tdmif_b>;
+                       dai-format = "i2s";
+                       dai-tdm-slot-tx-mask-0 = <1 1>;
+                       dai-tdm-slot-tx-mask-1 = <1 1>;
+                       dai-tdm-slot-tx-mask-2 = <1 1>;
+                       dai-tdm-slot-tx-mask-3 = <1 1>;
+                       mclk-fs = <256>;
+
+                       codec {
+                               sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>;
+                       };
+               };
+
+               /* spdif hdmi or toslink interface */
+               dai-link-4 {
+                       sound-dai = <&spdifout_a>;
+
+                       codec-0 {
+                       sound-dai = <&spdif_dit>;
+                       };
+
+                       codec-1 {
+                               sound-dai = <&tohdmitx TOHDMITX_SPDIF_IN_A>;
+                       };
+               };
+
+               /* spdif hdmi interface */
+               dai-link-5 {
+                       sound-dai = <&spdifout_b>;
+
+                       codec {
+                               sound-dai = <&tohdmitx TOHDMITX_SPDIF_IN_B>;
+                       };
+               };
+
+               /* hdmi glue */
+               dai-link-6 {
+                       sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>;
+
+                       codec {
+                               sound-dai = <&hdmi_tx>;
+                       };
+               };
+       };
+};
+
+&arb {
+       status = "okay";
+};
+
+&cecb_AO {
+       pinctrl-0 = <&cec_ao_b_h_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+       hdmi-phandle = <&hdmi_tx>;
+};
+
+&clkc_audio {
+       status = "okay";
+};
+
+&cpu0 {
+       cpu-supply = <&vddcpu>;
+       operating-points-v2 = <&cpu_opp_table>;
+       clocks = <&clkc CLKID_CPU_CLK>;
+       clock-latency = <50000>;
+};
+
+&cpu1 {
+       cpu-supply = <&vddcpu>;
+       operating-points-v2 = <&cpu_opp_table>;
+       clocks = <&clkc CLKID_CPU_CLK>;
+       clock-latency = <50000>;
+};
+
+&cpu2 {
+       cpu-supply = <&vddcpu>;
+       operating-points-v2 = <&cpu_opp_table>;
+       clocks = <&clkc CLKID_CPU_CLK>;
+       clock-latency = <50000>;
+};
+
+&cpu3 {
+       cpu-supply = <&vddcpu>;
+       operating-points-v2 = <&cpu_opp_table>;
+       clocks = <&clkc CLKID_CPU_CLK>;
+       clock-latency = <50000>;
+};
+
+&ethmac {
+       status = "okay";
+       phy-handle = <&internal_ephy>;
+       phy-mode = "rmii";
+};
+
+&frddr_a {
+       status = "okay";
+};
+
+&frddr_b {
+       status = "okay";
+};
+
+&frddr_c {
+       status = "okay";
+};
+
+&spdifout_a {
+       pinctrl-0 = <&spdif_out_h_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&spdifout_b {
+       status = "okay";
+};
+
+&hdmi_tx {
+       status = "okay";
+       pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>;
+       pinctrl-names = "default";
+};
+
+&hdmi_tx_tmds_port {
+       hdmi_tx_tmds_out: endpoint {
+               remote-endpoint = <&hdmi_connector_in>;
+       };
+};
+
+&i2c3 {
+       status = "okay";
+       pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>;
+       pinctrl-names = "default";
+};
+
+&ir {
+       status = "okay";
+       pinctrl-0 = <&remote_input_ao_pins>;
+       pinctrl-names = "default";
+};
+
+&pwm_AO_cd {
+       pinctrl-0 = <&pwm_ao_d_e_pins>;
+       pinctrl-names = "default";
+       clocks = <&xtal>;
+       clock-names = "clkin1";
+       status = "okay";
+};
+
+&pwm_ef {
+       status = "okay";
+       pinctrl-0 = <&pwm_e_pins>;
+       pinctrl-names = "default";
+       clocks = <&xtal>;
+       clock-names = "clkin0";
+};
+
+&pdm {
+       pinctrl-0 = <&pdm_din0_z_pins>, <&pdm_din1_z_pins>,
+                   <&pdm_din2_z_pins>, <&pdm_din3_z_pins>,
+                   <&pdm_dclk_z_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&saradc {
+       status = "okay";
+       vref-supply = <&vddio_ao1v8>;
+};
+
+/* SDIO */
+&sd_emmc_a {
+       status = "okay";
+       pinctrl-0 = <&sdio_pins>;
+       pinctrl-1 = <&sdio_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       bus-width = <4>;
+       cap-sd-highspeed;
+       sd-uhs-sdr50;
+       max-frequency = <100000000>;
+
+       non-removable;
+       disable-wp;
+
+       /* WiFi firmware requires power to be kept while in suspend */
+       keep-power-in-suspend;
+
+       mmc-pwrseq = <&sdio_pwrseq>;
+
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&vddio_ao1v8>;
+};
+
+/* SD card */
+&sd_emmc_b {
+       status = "okay";
+       pinctrl-0 = <&sdcard_c_pins>;
+       pinctrl-1 = <&sdcard_clk_gate_c_pins>;
+       pinctrl-names = "default", "clk-gate";
+
+       bus-width = <4>;
+       cap-sd-highspeed;
+       max-frequency = <50000000>;
+       disable-wp;
+
+       cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&vddao_3v3>;
+};
+
+/* eMMC */
+&sd_emmc_c {
+       status = "okay";
+       pinctrl-0 = <&emmc_ctrl_pins>, <&emmc_data_8b_pins>, <&emmc_ds_pins>;
+       pinctrl-1 = <&emmc_clk_gate_pins>;
+       pinctrl-names = "default", "clk-gate";
+
+       bus-width = <8>;
+       cap-mmc-highspeed;
+       mmc-ddr-1_8v;
+       mmc-hs200-1_8v;
+       max-frequency = <200000000>;
+       non-removable;
+       disable-wp;
+
+       mmc-pwrseq = <&emmc_pwrseq>;
+       vmmc-supply = <&vddao_3v3>;
+       vqmmc-supply = <&emmc_1v8>;
+};
+
+&tdmif_b {
+       status = "okay";
+};
+
+&tdmout_b {
+       status = "okay";
+};
+
+&tohdmitx {
+       status = "okay";
+};
+
+&uart_A {
+       status = "okay";
+       pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
+       pinctrl-names = "default";
+       uart-has-rtscts;
+};
+
+&uart_AO {
+       status = "okay";
+       pinctrl-0 = <&uart_ao_a_pins>;
+       pinctrl-names = "default";
+};
+
+&usb {
+       status = "okay";
+       dr_mode = "host";
+};
index fcd7e1d8e16ff2bdf601da9f582d9104065b54ee..15b9bc28070617d02ae92e998d644f8c0921b817 100644 (file)
@@ -60,7 +60,7 @@
                clock-names = "ext_clock";
        };
 
-       ao_5v: regulator-ao_5v {
+       ao_5v: regulator-ao-5v {
                compatible = "regulator-fixed";
                regulator-name = "AO_5V";
                regulator-min-microvolt = <5000000>;
@@ -68,7 +68,7 @@
                regulator-always-on;
        };
 
-       vcc_1v8: regulator-vcc_1v8 {
+       vcc_1v8: regulator-vcc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_1V8";
                regulator-min-microvolt = <1800000>;
@@ -77,7 +77,7 @@
                regulator-always-on;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
@@ -86,7 +86,7 @@
                regulator-always-on;
        };
 
-       hdmi_pw: regulator-hdmi_pw {
+       hdmi_pw: regulator-hdmi-pw {
                compatible = "regulator-fixed";
                regulator-name = "HDMI_PW";
                regulator-min-microvolt = <5000000>;
@@ -95,7 +95,7 @@
                regulator-always-on;
        };
 
-       vddao_1v8: regulator-vddao_1v8 {
+       vddao_1v8: regulator-vddao-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
index 4c4550dd47112796ffe04ef6c41f928c4d797f49..61cb8135a392554169e9b6512965648fccd58270 100644 (file)
@@ -15,7 +15,7 @@
        compatible = "seirobotics,sei510", "amlogic,g12a";
        model = "SEI Robotics SEI510";
 
-       adc_keys {
+       keys {
                compatible = "adc-keys";
                io-channels = <&saradc 0>;
                io-channel-names = "buttons";
@@ -83,7 +83,7 @@
                reg = <0x0 0x0 0x0 0x40000000>;
        };
 
-       ao_5v: regulator-ao_5v {
+       ao_5v: regulator-ao-5v {
                compatible = "regulator-fixed";
                regulator-name = "AO_5V";
                regulator-min-microvolt = <5000000>;
@@ -92,7 +92,7 @@
                regulator-always-on;
        };
 
-       dc_in: regulator-dc_in {
+       dc_in: regulator-dc-in {
                compatible = "regulator-fixed";
                regulator-name = "DC_IN";
                regulator-min-microvolt = <5000000>;
                regulator-always-on;
        };
 
-       emmc_1v8: regulator-emmc_1v8 {
+       emmc_1v8: regulator-emmc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "EMMC_1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       vddao_3v3_t: regultor-vddao_3v3_t {
+       vddao_3v3_t: regulator-vddao-3v3-t {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3_T";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       vddio_ao1v8: regulator-vddio_ao1v8 {
+       vddio_ao1v8: regulator-vddio-ao1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO1V8";
                regulator-min-microvolt = <1800000>;
index 8355ddd7e9ae0f591d84735677034eb2cc26d80a..3da7922d83f1bc34d0e01ed5c2fff3bc9c77c650 100644 (file)
@@ -75,7 +75,7 @@
                reg = <0x0 0x0 0x0 0x40000000>;
        };
 
-       flash_1v8: regulator-flash_1v8 {
+       flash_1v8: regulator-flash-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "FLASH_1V8";
                regulator-min-microvolt = <1800000>;
@@ -84,7 +84,7 @@
                regulator-always-on;
        };
 
-       main_12v: regulator-main_12v {
+       main_12v: regulator-main-12v {
                compatible = "regulator-fixed";
                regulator-name = "12V";
                regulator-min-microvolt = <12000000>;
@@ -92,7 +92,7 @@
                regulator-always-on;
        };
 
-       usb_pwr_en: regulator-usb_pwr_en {
+       usb_pwr_en: regulator-usb-pwr-en {
                compatible = "regulator-fixed";
                regulator-name = "USB_PWR_EN";
                regulator-min-microvolt = <5000000>;
                enable-active-high;
        };
 
-       vcc_1v8: regulator-vcc_1v8 {
+       vcc_1v8: regulator-vcc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
                /* FIXME: actually controlled by VDDCPU_B_EN */
        };
 
-       vcc_5v: regulator-vcc_5v {
+       vcc_5v: regulator-vcc-5v {
                compatible = "regulator-fixed";
                regulator-name = "VCC_5V";
                regulator-min-microvolt = <5000000>;
                enable-active-high;
        };
 
-       vddao_1v8: regulator-vddao_1v8 {
+       vddao_1v8: regulator-vddao-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
index 9b55982b6a6bbd106978b560c38c87259297a28d..05c7a1e3f1b71afe923f1ae83ad072e2e9c4f3e4 100644 (file)
@@ -66,7 +66,7 @@
                clock-names = "ext_clock";
        };
 
-       flash_1v8: regulator-flash_1v8 {
+       flash_1v8: regulator-flash-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "FLASH_1V8";
                regulator-min-microvolt = <1800000>;
@@ -75,7 +75,7 @@
                regulator-always-on;
        };
 
-       dc_in: regulator-dc_in {
+       dc_in: regulator-dc-in {
                compatible = "regulator-fixed";
                regulator-name = "DC_IN";
                regulator-min-microvolt = <5000000>;
@@ -83,7 +83,7 @@
                regulator-always-on;
        };
 
-       vcc_1v8: regulator-vcc_1v8 {
+       vcc_1v8: regulator-vcc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_1V8";
                regulator-min-microvolt = <1800000>;
@@ -92,7 +92,7 @@
                regulator-always-on;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
                /* FIXME: actually controlled by VDDCPU_B_EN */
        };
 
-       vcc_5v: regulator-vcc_5v {
+       vcc_5v: regulator-vcc-5v {
                compatible = "regulator-fixed";
                regulator-name = "VCC_5V";
                regulator-min-microvolt = <5000000>;
                gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>;
        };
 
-       vddao_1v8: regulator-vddao_1v8 {
+       vddao_1v8: regulator-vddao-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
index 91c9769fda20108bfecf2a60ef30b2c34a9826b6..d80dd9a3da316ab083c508ae6222d181d28c2b0d 100644 (file)
@@ -19,7 +19,7 @@
                status = "okay";
        };
 
-       hub_5v: regulator-hub_5v {
+       hub_5v: regulator-hub-5v {
                compatible = "regulator-fixed";
                regulator-name = "HUB_5V";
                regulator-min-microvolt = <5000000>;
index 9e12a34b2840b8dfaada9226e718c3ccaeb89cd4..09d959aefb1843d8513881815b7127c1a5bfcfc6 100644 (file)
@@ -48,7 +48,7 @@
                };
        };
 
-       tflash_vdd: regulator-tflash_vdd {
+       tflash_vdd: regulator-tflash-vdd {
                compatible = "regulator-fixed";
 
                regulator-name = "TFLASH_VDD";
@@ -60,7 +60,7 @@
                regulator-always-on;
        };
 
-       tf_io: gpio-regulator-tf_io {
+       tf_io: gpio-regulator-tf-io {
                compatible = "regulator-gpio";
 
                regulator-name = "TF_IO";
@@ -74,7 +74,7 @@
                         <1800000 1>;
        };
 
-       flash_1v8: regulator-flash_1v8 {
+       flash_1v8: regulator-flash-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "FLASH_1V8";
                regulator-min-microvolt = <1800000>;
@@ -83,7 +83,7 @@
                regulator-always-on;
        };
 
-       main_12v: regulator-main_12v {
+       main_12v: regulator-main-12v {
                compatible = "regulator-fixed";
                regulator-name = "12V";
                regulator-min-microvolt = <12000000>;
@@ -91,7 +91,7 @@
                regulator-always-on;
        };
 
-       usb_pwr_en: regulator-usb_pwr_en {
+       usb_pwr_en: regulator-usb-pwr-en {
                compatible = "regulator-fixed";
                regulator-name = "USB_PWR_EN";
                regulator-min-microvolt = <5000000>;
                enable-active-high;
        };
 
-       vcc_5v: regulator-vcc_5v {
+       vcc_5v: regulator-vcc-5v {
                compatible = "regulator-fixed";
                regulator-name = "5V";
                regulator-min-microvolt = <5000000>;
                enable-active-high;
        };
 
-       vcc_1v8: regulator-vcc_1v8 {
+       vcc_1v8: regulator-vcc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       vddao_1v8: regulator-vddao_1v8 {
+       vddao_1v8: regulator-vddao-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
index ac8b7178257e06779bd628aa4489d77153209e4e..4cb6930ffb19620de9eef45029cfa43b08640a30 100644 (file)
@@ -39,7 +39,7 @@
                clock-names = "ext_clock";
        };
 
-       flash_1v8: regulator-flash_1v8 {
+       flash_1v8: regulator-flash-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "FLASH_1V8";
                regulator-min-microvolt = <1800000>;
@@ -48,7 +48,7 @@
                regulator-always-on;
        };
 
-       main_12v: regulator-main_12v {
+       main_12v: regulator-main-12v {
                compatible = "regulator-fixed";
                regulator-name = "12V";
                regulator-min-microvolt = <12000000>;
@@ -56,7 +56,7 @@
                regulator-always-on;
        };
 
-       vcc_5v: regulator-vcc_5v {
+       vcc_5v: regulator-vcc-5v {
                compatible = "regulator-fixed";
                regulator-name = "VCC_5V";
                regulator-min-microvolt = <5000000>;
@@ -67,7 +67,7 @@
                enable-active-high;
        };
 
-       vcc_1v8: regulator-vcc_1v8 {
+       vcc_1v8: regulator-vcc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_1V8";
                regulator-min-microvolt = <1800000>;
@@ -76,7 +76,7 @@
                regulator-always-on;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
index 5e7b9273b06243ded245bcfdea85ba65fe13ca8a..efd662a452e8812398133cf00fa6ed6a9adef459 100644 (file)
@@ -84,7 +84,7 @@
                reg = <0x0 0x0 0x0 0x80000000>;
        };
 
-       ao_5v: regulator-ao_5v {
+       ao_5v: regulator-ao-5v {
                compatible = "regulator-fixed";
                regulator-name = "AO_5V";
                regulator-min-microvolt = <5000000>;
@@ -93,7 +93,7 @@
                regulator-always-on;
        };
 
-       dc_in: regulator-dc_in {
+       dc_in: regulator-dc-in {
                compatible = "regulator-fixed";
                regulator-name = "DC_IN";
                regulator-min-microvolt = <5000000>;
                };
        };
 
-       vcc_card: regulator-vcc_card {
+       vcc_card: regulator-vcc-card {
                compatible = "regulator-fixed";
                regulator-name = "VCC_CARD";
                regulator-min-microvolt = <3300000>;
                gpio = <&gpio GPIOH_3 GPIO_OPEN_DRAIN>;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vddio_ao3v3: regulator-vddio_ao3v3 {
+       vddio_ao3v3: regulator-vddio-ao3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO3V3";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
index e59c3c92b1e7c6a660c2221954cf1277b47a69cf..08d6b69ba469183d432da40ff6cccec78f20326b 100644 (file)
                regulator-always-on;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
index 4aab1ab705b4967973f7f52f197649b8efd4065a..cca129ce2c5834af7adda219963d7a59f459df94 100644 (file)
                         <3300000 1>;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
index e6d2de7c45a9d7bd1b5ddcd0aff5921a2ad7f83f..c431986e6a3314d663473352a055a72eb692b68f 100644 (file)
@@ -67,7 +67,7 @@
                regulator-always-on;
        };
 
-       hdmi_p5v0: regulator-hdmi_p5v0 {
+       hdmi_p5v0: regulator-hdmi-p5v0 {
                compatible = "regulator-fixed";
                regulator-name = "HDMI_P5V0";
                regulator-min-microvolt = <5000000>;
@@ -76,7 +76,7 @@
                vin-supply = <&p5v0>;
        };
 
-       tflash_vdd: regulator-tflash_vdd {
+       tflash_vdd: regulator-tflash-vdd {
                compatible = "regulator-fixed";
 
                regulator-name = "TFLASH_VDD";
@@ -92,7 +92,7 @@
                vin-supply = <&vddio_ao3v3>;
        };
 
-       tf_io: gpio-regulator-tf_io {
+       tf_io: gpio-regulator-tf-io {
                compatible = "regulator-gpio";
 
                regulator-name = "TF_IO";
                vin-supply = <&p5v0>;
        };
 
-       ddr3_1v5: regulator-ddr3_1v5 {
+       ddr3_1v5: regulator-ddr3-1v5 {
                compatible = "regulator-fixed";
                regulator-name = "DDR3_1V5";
                regulator-min-microvolt = <1500000>;
index 591455c50e8866b4579cf417bc05c3d940d25626..7f94716876d39f593f2c3eb752f1bba15ea0c152 100644 (file)
                sound-name-prefix = "DIT";
        };
 
-       avdd18_usb_adc: regulator-avdd18_usb_adc {
+       avdd18_usb_adc: regulator-avdd18-usb-adc {
                compatible = "regulator-fixed";
                regulator-name = "AVDD18_USB_ADC";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       adc_keys {
+       keys {
                compatible = "adc-keys";
                io-channels = <&saradc 0>;
                io-channel-names = "buttons";
index e803a466fe4ebb15c160c480790749c46c419cbf..52d57773a77fa8f54955f45d01355cd6feea6283 100644 (file)
                regulator-settling-time-down-us = <150000>;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
index 74df32534231897f61aab3cc5ab88d96e3235573..255e93a0b36d9ea5fba47ed5b57429132134c95a 100644 (file)
                enable-active-high;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
index 94dafb955301b19b976d7c09b2dcf831489ad873..deb295227189d29c78e9bb929bbb4a94822c5fc7 100644 (file)
                enable-active-high;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
@@ -71,7 +71,7 @@
                regulator-always-on;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
index a29b49f051ae6bf2ba940cd8bb408a89f763e9db..90ef9c17d80bac172843c7de5900b69b66954e84 100644 (file)
@@ -42,7 +42,7 @@
                };
        };
 
-       dc_5v: regulator-dc_5v {
+       dc_5v: regulator-dc-5v {
                compatible = "regulator-fixed";
                regulator-name = "DC_5V";
                regulator-min-microvolt = <5000000>;
@@ -89,7 +89,7 @@
                regulator-always-on;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
@@ -98,7 +98,7 @@
                regulator-always-on;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
index c0d6eb55100af166fc2ff10ebb2de6c8353431db..08a4718219b10876a59376e6d4a902559450acf1 100644 (file)
                reg = <0x0 0x0 0x0 0x20000000>;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
index a18d6d241a5ad27646f946ed677de73778fc4111..2b94b6e5285e29934d6e29d292a3412ffbee1597 100644 (file)
                stdout-path = "serial0:115200n8";
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
index c8d74e61dec182a5b4cfa54d87dc936cd72ce70f..89fe5110f7a2e7abfdf973bb774d38010f28f091 100644 (file)
                         <3300000 1>;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
index 2825db91e46282f36398cca85d3505cd3651a993..63b20860067c0939c7b9a3a5d3def29412813dd9 100644 (file)
@@ -67,7 +67,7 @@
                reg = <0x0 0x0 0x0 0x80000000>;
        };
 
-       ao_5v: regulator-ao_5v {
+       ao_5v: regulator-ao-5v {
                compatible = "regulator-fixed";
                regulator-name = "AO_5V";
                regulator-min-microvolt = <5000000>;
@@ -76,7 +76,7 @@
                regulator-always-on;
        };
 
-       dc_in: regulator-dc_in {
+       dc_in: regulator-dc-in {
                compatible = "regulator-fixed";
                regulator-name = "DC_IN";
                regulator-min-microvolt = <5000000>;
@@ -93,7 +93,7 @@
                regulator-always-on;
        };
 
-       vcc_card: regulator-vcc_card {
+       vcc_card: regulator-vcc-card {
                compatible = "regulator-fixed";
                regulator-name = "VCC_CARD";
                regulator-min-microvolt = <3300000>;
                gpio = <&gpio GPIOH_3 GPIO_OPEN_DRAIN>;
        };
 
-       vddio_ao3v3: regulator-vddio_ao3v3 {
+       vddio_ao3v3: regulator-vddio-ao3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO3V3";
                regulator-min-microvolt = <3300000>;
                regulator-settling-time-down-us = <50000>;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vcc_1v8: regulator-vcc_1v8 {
+       vcc_1v8: regulator-vcc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VCC 1V8";
                regulator-min-microvolt = <1800000>;
index 27093e6ac9e2c7af3382fe6e6132c2bdba5b0d63..8b26c9661be1f6d00593b40b8ceb9ca4b8c8c2b6 100644 (file)
@@ -93,7 +93,7 @@
                regulator-always-on;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-settling-time-down-us = <50000>;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
        };
 
        /* This is provided by LDOs on the eMMC daugther card */
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
index f1acca5c443426544cff268c0fddb4a82c426aea..c79f9f2099bf8213102ccb0fb378cbd54dc52101 100644 (file)
                         <3300000 1>;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
index a150cc0e18ff3b28721b7a6f9614fb7e34d8770a..7e7dc87ede2d2686e3b0dd3ca24af420fb53317d 100644 (file)
                regulator-always-on;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
index 860f307494c58498cad7603959f1ac557b435c5a..07e7c3bedea0084312f7916c4e1dee52926d6570 100644 (file)
                regulator-always-on;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddio_boot: regulator-vddio_boot {
+       vddio_boot: regulator-vddio-boot {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_BOOT";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
index 4eda9f634c428d26b73b0a0d38912a8ec65097a3..a66f19851ac9a4e35c8a0a67d0228f7310685a1c 100644 (file)
@@ -14,7 +14,7 @@
                     "amlogic,meson-gxm";
        model = "Libre Computer AML-S912-PC";
 
-       typec2_vbus: regulator-typec2_vbus {
+       typec2_vbus: regulator-typec2-vbus {
                compatible = "regulator-fixed";
                regulator-name = "TYPEC2_VBUS";
                regulator-min-microvolt = <5000000>;
index 514a6dd4b12406ca2e49f37093dca305007fdd51..e78cc9b577a0551bcfb7c1fe4fe7c25a6076c3c5 100644 (file)
@@ -80,7 +80,7 @@
                clock-names = "ext_clock";
        };
 
-       dc_in: regulator-dc_in {
+       dc_in: regulator-dc-in {
                compatible = "regulator-fixed";
                regulator-name = "DC_IN";
                regulator-min-microvolt = <5000000>;
@@ -88,7 +88,7 @@
                regulator-always-on;
        };
 
-       vcc_5v: regulator-vcc_5v {
+       vcc_5v: regulator-vcc-5v {
                compatible = "regulator-fixed";
                regulator-name = "VCC_5V";
                regulator-min-microvolt = <5000000>;
@@ -99,7 +99,7 @@
                enable-active-high;
        };
 
-       vcc_1v8: regulator-vcc_1v8 {
+       vcc_1v8: regulator-vcc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
                /* FIXME: actually controlled by VDDCPU_B_EN */
        };
 
-       vddao_1v8: regulator-vddao_1v8 {
+       vddao_1v8: regulator-vddao-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       emmc_1v8: regulator-emmc_1v8 {
+       emmc_1v8: regulator-emmc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "EMMC_AO1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vsys_3v3: regulator-vsys_3v3 {
+       vsys_3v3: regulator-vsys-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VSYS_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       usb_pwr: regulator-usb_pwr {
+       usb_pwr: regulator-usb-pwr {
                compatible = "regulator-fixed";
                regulator-name = "USB_PWR";
                regulator-min-microvolt = <5000000>;
index 35e8f5bae9901af81f2b9e3096b783b583471fac..082b72703cdf952cd46de3882c02ce5bab3929f3 100644 (file)
                gpio-open-drain;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                pwm-dutycycle-range = <100 0>;
        };
 
-       vddio_ao18: regulator-vddio_ao18 {
+       vddio_ao18: regulator-vddio-ao18 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO18";
                regulator-min-microvolt = <1800000>;
                vin-supply = <&vddao_3v3>;
        };
 
-       vddio_c: regulator-vddio_c {
+       vddio_c: regulator-vddio-c {
                compatible = "regulator-gpio";
                regulator-name = "VDDIO_C";
                regulator-min-microvolt = <1800000>;
index 46a34731f7e2221822b430c885cd42e187017acf..d1fa8b8bf7959da7cdbe119ae379a90562741c9b 100644 (file)
@@ -54,7 +54,7 @@
                reg = <0x0 0x0 0x0 0x40000000>;
        };
 
-       ao_5v: regulator-ao_5v {
+       ao_5v: regulator-ao-5v {
                compatible = "regulator-fixed";
                regulator-name = "AO_5V";
                regulator-min-microvolt = <5000000>;
@@ -63,7 +63,7 @@
                regulator-always-on;
        };
 
-       dc_in: regulator-dc_in {
+       dc_in: regulator-dc-in {
                compatible = "regulator-fixed";
                regulator-name = "DC_IN";
                regulator-min-microvolt = <5000000>;
@@ -71,7 +71,7 @@
                regulator-always-on;
        };
 
-       emmc_1v8: regulator-emmc_1v8 {
+       emmc_1v8: regulator-emmc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "EMMC_1V8";
                regulator-min-microvolt = <1800000>;
@@ -80,7 +80,7 @@
                regulator-always-on;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       vddio_ao1v8: regulator-vddio_ao1v8 {
+       vddio_ao1v8: regulator-vddio-ao1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO1V8";
                regulator-min-microvolt = <1800000>;
index 62404743e62d1d1fb452d256bc951ea45f0881dd..81dce862902adeabaaf5a1007894bf9b4091eb5a 100644 (file)
@@ -82,7 +82,7 @@
                reg = <0x0 0x0 0x0 0x40000000>;
        };
 
-       emmc_1v8: regulator-emmc_1v8 {
+       emmc_1v8: regulator-emmc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "EMMC_1V8";
                regulator-min-microvolt = <1800000>;
@@ -91,7 +91,7 @@
                regulator-always-on;
        };
 
-       dc_in: regulator-dc_in {
+       dc_in: regulator-dc-in {
                compatible = "regulator-fixed";
                regulator-name = "DC_IN";
                regulator-min-microvolt = <5000000>;
@@ -99,7 +99,7 @@
                regulator-always-on;
        };
 
-       vddio_c: regulator-vddio_c {
+       vddio_c: regulator-vddio-c {
                compatible = "regulator-gpio";
                regulator-name = "VDDIO_C";
                regulator-min-microvolt = <1800000>;
                         <3300000 1>;
        };
 
-       tflash_vdd: regulator-tflash_vdd {
+       tflash_vdd: regulator-tflash-vdd {
                compatible = "regulator-fixed";
                regulator-name = "TFLASH_VDD";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       vddao_1v8: regulator-vddao_1v8 {
+       vddao_1v8: regulator-vddao-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
        };
 
        /* USB Hub Power Enable */
-       vl_pwr_en: regulator-vl_pwr_en {
+       vl_pwr_en: regulator-vl-pwr-en {
                compatible = "regulator-fixed";
                regulator-name = "VL_PWR_EN";
                regulator-min-microvolt = <5000000>;
index 846a2d6c20e53b2155afb8580b6e9f81a754d01e..0170139b8d32f4274ad991b0f3d9a0f6c67969ce 100644 (file)
@@ -43,7 +43,7 @@
        };
 
        /* Powers the SATA Disk 0 regulator, which is enabled when a disk load is detected */
-       p12v_0: regulator-p12v_0 {
+       p12v_0: regulator-p12v-0 {
                compatible = "regulator-fixed";
                regulator-name = "P12V_0";
                regulator-min-microvolt = <12000000>;
@@ -56,7 +56,7 @@
        };
 
        /* Powers the SATA Disk 1 regulator, which is enabled when a disk load is detected */
-       p12v_1: regulator-p12v_1 {
+       p12v_1: regulator-p12v-1 {
                compatible = "regulator-fixed";
                regulator-name = "P12V_1";
                regulator-min-microvolt = <12000000>;
index 1db2327bbd13e72aa33d2b2357fda06461b2aac1..951eb8e3f0c0c92633adcc686801847affd5f040 100644 (file)
@@ -28,7 +28,7 @@
                reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>;
        };
 
-       tflash_vdd: regulator-tflash_vdd {
+       tflash_vdd: regulator-tflash-vdd {
                compatible = "regulator-fixed";
 
                regulator-name = "TFLASH_VDD";
@@ -40,7 +40,7 @@
                regulator-always-on;
        };
 
-       tf_io: gpio-regulator-tf_io {
+       tf_io: gpio-regulator-tf-io {
                compatible = "regulator-gpio";
 
                regulator-name = "TF_IO";
@@ -59,7 +59,7 @@
                         <1800000 1>;
        };
 
-       flash_1v8: regulator-flash_1v8 {
+       flash_1v8: regulator-flash-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "FLASH_1V8";
                regulator-min-microvolt = <1800000>;
@@ -68,7 +68,7 @@
                regulator-always-on;
        };
 
-       main_12v: regulator-main_12v {
+       main_12v: regulator-main-12v {
                compatible = "regulator-fixed";
                regulator-name = "12V";
                regulator-min-microvolt = <12000000>;
@@ -76,7 +76,7 @@
                regulator-always-on;
        };
 
-       vcc_5v: regulator-vcc_5v {
+       vcc_5v: regulator-vcc-5v {
                compatible = "regulator-fixed";
                regulator-name = "5V";
                regulator-min-microvolt = <5000000>;
@@ -87,7 +87,7 @@
                enable-active-high;
        };
 
-       vcc_1v8: regulator-vcc_1v8 {
+       vcc_1v8: regulator-vcc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_1V8";
                regulator-min-microvolt = <1800000>;
@@ -96,7 +96,7 @@
                regulator-always-on;
        };
 
-       vcc_3v3: regulator-vcc_3v3 {
+       vcc_3v3: regulator-vcc-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       usb_pwr_en: regulator-usb_pwr_en {
+       usb_pwr_en: regulator-usb-pwr-en {
                compatible = "regulator-fixed";
                regulator-name = "USB_PWR_EN";
                regulator-min-microvolt = <5000000>;
                enable-active-high;
        };
 
-       vddao_1v8: regulator-vddao_1v8 {
+       vddao_1v8: regulator-vddao-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
index 109932068dbe6c0c7d12528ab632f1d3052e9d1b..3581e14cbf18db7dd80a99ee23ab614786ffa816 100644 (file)
                reg = <0x0 0x0 0x0 0x40000000>;
        };
 
-       ao_5v: regulator-ao_5v {
+       ao_5v: regulator-ao-5v {
                compatible = "regulator-fixed";
                regulator-name = "AO_5V";
                regulator-min-microvolt = <5000000>;
                regulator-always-on;
        };
 
-       dc_in: regulator-dc_in {
+       dc_in: regulator-dc-in {
                compatible = "regulator-fixed";
                regulator-name = "DC_IN";
                regulator-min-microvolt = <5000000>;
                regulator-always-on;
        };
 
-       emmc_1v8: regulator-emmc_1v8 {
+       emmc_1v8: regulator-emmc-1v8 {
                compatible = "regulator-fixed";
                regulator-name = "EMMC_1V8";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       vddao_3v3: regulator-vddao_3v3 {
+       vddao_3v3: regulator-vddao-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3";
                regulator-min-microvolt = <3300000>;
        };
 
        /* Used by Tuner, RGB Led & IR Emitter LED array */
-       vddao_3v3_t: regulator-vddao_3v3_t {
+       vddao_3v3_t: regulator-vddao-3v3-t {
                compatible = "regulator-fixed";
                regulator-name = "VDDAO_3V3_T";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       vddio_ao1v8: regulator-vddio_ao1v8 {
+       vddio_ao1v8: regulator-vddio-ao1v8 {
                compatible = "regulator-fixed";
                regulator-name = "VDDIO_AO1V8";
                regulator-min-microvolt = <1800000>;
index 9dcd25ec2c04183fb90f160452142c2f5a790136..896d1f33b5b6173e3b4b701d4e08f4ad277856e0 100644 (file)
                        #gpio-cells = <2>;
                        gpio-controller;
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupts = <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>;
                };
 
index f049687d6b96d23fb0383401ef9c19e50af34148..d8516ec0dae7450e2c5e81f0bddf8ffdeba2bb5e 100644 (file)
                        #gpio-cells = <2>;
                        gpio-controller;
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupts = <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>;
                        gpio-ranges = <&pinmux 0 0 16>,
                                        <&pinmux 16 71 2>,
index da3f4a791e686c70dc1050471ca9a9a29ffc62c7..2ba67c3d068116041aa74b758743bf11101fa335 100644 (file)
                        clock-names = "fin_pll", "mct";
                };
 
+               pdma0: dma-controller@120c0000 {
+                       compatible = "arm,pl330", "arm,primecell";
+                       reg = <0x120c0000 0x1000>;
+                       clocks = <&cmu_core CLK_GOUT_PDMA_CORE_ACLK>;
+                       clock-names = "apb_pclk";
+                       #dma-cells = <1>;
+                       interrupts = <GIC_SPI 479 IRQ_TYPE_LEVEL_HIGH>;
+                       arm,pl330-broken-no-flushp;
+               };
+
                gic: interrupt-controller@12a01000 {
                        compatible = "arm,gic-400";
                        #interrupt-cells = <3>;
                                 <&cmu_peri CLK_GOUT_SPI0_IPCLK>;
                        clock-names = "pclk", "ipclk";
                        status = "disabled";
+
+                       spi_0: spi@13940000 {
+                               compatible = "samsung,exynos850-spi";
+                               reg = <0x13940000 0x30>;
+                               clocks = <&cmu_peri CLK_GOUT_SPI0_PCLK>,
+                                        <&cmu_peri CLK_GOUT_SPI0_IPCLK>;
+                               clock-names = "spi", "spi_busclk0";
+                               dmas = <&pdma0 5>, <&pdma0 4>;
+                               dma-names = "tx", "rx";
+                               interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-0 = <&spi0_pins>;
+                               pinctrl-names = "default";
+                               num-cs = <1>;
+                               samsung,spi-src-clk = <0>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
                };
 
                usi_cmgp0: usi@11d000c0 {
                                clock-names = "uart", "clk_uart_baud0";
                                status = "disabled";
                        };
+
+                       spi_1: spi@11d00000 {
+                               compatible = "samsung,exynos850-spi";
+                               reg = <0x11d00000 0x30>;
+                               clocks = <&cmu_cmgp CLK_GOUT_CMGP_USI0_PCLK>,
+                                        <&cmu_cmgp CLK_GOUT_CMGP_USI0_IPCLK>;
+                               clock-names = "spi", "spi_busclk0";
+                               dmas = <&pdma0 12>, <&pdma0 13>;
+                               dma-names = "tx", "rx";
+                               interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-0 = <&spi1_pins>;
+                               pinctrl-names = "default";
+                               num-cs = <1>;
+                               samsung,spi-src-clk = <0>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
                };
 
                usi_cmgp1: usi@11d200c0 {
                                clock-names = "uart", "clk_uart_baud0";
                                status = "disabled";
                        };
+
+                       spi_2: spi@11d20000 {
+                               compatible = "samsung,exynos850-spi";
+                               reg = <0x11d20000 0x30>;
+                               clocks = <&cmu_cmgp CLK_GOUT_CMGP_USI1_PCLK>,
+                                        <&cmu_cmgp CLK_GOUT_CMGP_USI1_IPCLK>;
+                               clock-names = "spi", "spi_busclk0";
+                               dmas = <&pdma0 14>, <&pdma0 15>;
+                               dma-names = "tx", "rx";
+                               interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-0 = <&spi2_pins>;
+                               pinctrl-names = "default";
+                               num-cs = <1>;
+                               samsung,spi-src-clk = <0>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
                };
        };
 };
index 4a71f752200df1eabd2de6f69be5ddfbbbb40643..6ccade2c8cb489a347a582a77803657bb886ffb6 100644 (file)
        clock-frequency = <200000000>;
 };
 
+&hsi2c_8 {
+       status = "okay";
+
+       eeprom: eeprom@50 {
+               compatible = "atmel,24c08";
+               reg = <0x50>;
+       };
+};
+
+&hsi2c_12 {
+       status = "okay";
+       /* TODO: add the devices once drivers exist */
+};
+
 &pinctrl_far_alive {
        key_voldown: key-voldown-pins {
                samsung,pins = "gpa7-3";
        status = "okay";
 };
 
+&usi8 {
+       samsung,mode = <USI_V2_I2C>;
+       status = "okay";
+};
+
+&usi12 {
+       samsung,mode = <USI_V2_I2C>;
+       status = "okay";
+};
+
 &watchdog_cl0 {
        timeout-sec = <30>;
        status = "okay";
index e6a9776d4d62edb63f22830906fef87c3afb1005..a675f822acec524bbbb1e810ecdd64c37544880b 100644 (file)
                #interrupt-cells = <2>;
        };
 
-       pcie0_clkreq: pcie0-clkreq-pins{
+       pcie0_clkreq: pcie0-clkreq-pins {
                samsung,pins = "gph0-1";
                samsung,pin-function = <GS101_PIN_FUNC_2>;
                samsung,pin-pud = <GS101_PIN_PULL_UP>;
index d838e3a7af6e5ddda3751cc6f0bf4c73bccacc03..55e6bcb3689e93f23dc71c31f158ff9d8c203bd5 100644 (file)
@@ -73,7 +73,7 @@
                        compatible = "arm,cortex-a55";
                        reg = <0x0000>;
                        enable-method = "psci";
-                       cpu-idle-states =  <&ANANKE_CPU_SLEEP>;
+                       cpu-idle-states = <&ANANKE_CPU_SLEEP>;
                        capacity-dmips-mhz = <250>;
                        dynamic-power-coefficient = <70>;
                };
@@ -83,7 +83,7 @@
                        compatible = "arm,cortex-a55";
                        reg = <0x0100>;
                        enable-method = "psci";
-                       cpu-idle-states =  <&ANANKE_CPU_SLEEP>;
+                       cpu-idle-states = <&ANANKE_CPU_SLEEP>;
                        capacity-dmips-mhz = <250>;
                        dynamic-power-coefficient = <70>;
                };
@@ -93,7 +93,7 @@
                        compatible = "arm,cortex-a55";
                        reg = <0x0200>;
                        enable-method = "psci";
-                       cpu-idle-states =  <&ANANKE_CPU_SLEEP>;
+                       cpu-idle-states = <&ANANKE_CPU_SLEEP>;
                        capacity-dmips-mhz = <250>;
                        dynamic-power-coefficient = <70>;
                };
                        compatible = "arm,cortex-a55";
                        reg = <0x0300>;
                        enable-method = "psci";
-                       cpu-idle-states =  <&ANANKE_CPU_SLEEP>;
+                       cpu-idle-states = <&ANANKE_CPU_SLEEP>;
                        capacity-dmips-mhz = <250>;
                        dynamic-power-coefficient = <70>;
                };
                        compatible = "arm,cortex-a76";
                        reg = <0x0400>;
                        enable-method = "psci";
-                       cpu-idle-states =  <&ENYO_CPU_SLEEP>;
+                       cpu-idle-states = <&ENYO_CPU_SLEEP>;
                        capacity-dmips-mhz = <620>;
                        dynamic-power-coefficient = <284>;
                };
                        compatible = "arm,cortex-a76";
                        reg = <0x0500>;
                        enable-method = "psci";
-                       cpu-idle-states =  <&ENYO_CPU_SLEEP>;
+                       cpu-idle-states = <&ENYO_CPU_SLEEP>;
                        capacity-dmips-mhz = <620>;
                        dynamic-power-coefficient = <284>;
                };
                        compatible = "arm,cortex-x1";
                        reg = <0x0600>;
                        enable-method = "psci";
-                       cpu-idle-states =  <&HERA_CPU_SLEEP>;
+                       cpu-idle-states = <&HERA_CPU_SLEEP>;
                        capacity-dmips-mhz = <1024>;
                        dynamic-power-coefficient = <650>;
                };
                        compatible = "arm,cortex-x1";
                        reg = <0x0700>;
                        enable-method = "psci";
-                       cpu-idle-states =  <&HERA_CPU_SLEEP>;
+                       cpu-idle-states = <&HERA_CPU_SLEEP>;
                        capacity-dmips-mhz = <1024>;
                        dynamic-power-coefficient = <650>;
                };
                };
        };
 
-       /* TODO replace with CCF clock */
-       dummy_clk: clock-3 {
-               compatible = "fixed-clock";
-               #clock-cells = <0>;
-               clock-frequency = <12345>;
-               clock-output-names = "pclk";
-       };
-
        /* ect node is required to be present by bootloader */
        ect {
        };
                        clock-names = "bus", "sss";
                };
 
+               timer@10050000 {
+                       compatible = "google,gs101-mct",
+                                    "samsung,exynos4210-mct";
+                       reg = <0x10050000 0x800>;
+                       interrupts = <GIC_SPI 753 IRQ_TYPE_LEVEL_HIGH 0>,
+                                    <GIC_SPI 754 IRQ_TYPE_LEVEL_HIGH 0>,
+                                    <GIC_SPI 755 IRQ_TYPE_LEVEL_HIGH 0>,
+                                    <GIC_SPI 756 IRQ_TYPE_LEVEL_HIGH 0>,
+                                    <GIC_SPI 757 IRQ_TYPE_LEVEL_HIGH 0>,
+                                    <GIC_SPI 758 IRQ_TYPE_LEVEL_HIGH 0>,
+                                    <GIC_SPI 759 IRQ_TYPE_LEVEL_HIGH 0>,
+                                    <GIC_SPI 760 IRQ_TYPE_LEVEL_HIGH 0>,
+                                    <GIC_SPI 761 IRQ_TYPE_LEVEL_HIGH 0>,
+                                    <GIC_SPI 762 IRQ_TYPE_LEVEL_HIGH 0>,
+                                    <GIC_SPI 763 IRQ_TYPE_LEVEL_HIGH 0>,
+                                    <GIC_SPI 764 IRQ_TYPE_LEVEL_HIGH 0>;
+                       clocks = <&ext_24_5m>, <&cmu_misc CLK_GOUT_MISC_MCT_PCLK>;
+                       clock-names = "fin_pll", "mct";
+               };
+
                watchdog_cl0: watchdog@10060000 {
                        compatible = "google,gs101-wdt";
                        reg = <0x10060000 0x100>;
                        };
                };
 
+               cmu_peric0: clock-controller@10800000 {
+                       compatible = "google,gs101-cmu-peric0";
+                       reg = <0x10800000 0x4000>;
+                       #clock-cells = <1>;
+                       clocks = <&ext_24_5m>,
+                                <&cmu_top CLK_DOUT_CMU_PERIC0_BUS>,
+                                <&cmu_top CLK_DOUT_CMU_PERIC0_IP>;
+                       clock-names = "oscclk", "bus", "ip";
+               };
+
                sysreg_peric0: syscon@10820000 {
                        compatible = "google,gs101-peric0-sysreg", "syscon";
                        reg = <0x10820000 0x10000>;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_SYSREG_PERIC0_PCLK>;
                };
 
                pinctrl_peric0: pinctrl@10840000 {
                        interrupts = <GIC_SPI 625 IRQ_TYPE_LEVEL_HIGH 0>;
                };
 
+               usi8: usi@109700c0 {
+                       compatible = "google,gs101-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109700c0 0x20>;
+                       ranges;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_7>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_7>;
+                       clock-names = "pclk", "ipclk";
+                       samsung,sysreg = <&sysreg_peric0 0x101c>;
+                       status = "disabled";
+
+                       hsi2c_8: i2c@10970000 {
+                               compatible = "google,gs101-hsi2c",
+                                            "samsung,exynosautov9-hsi2c";
+                               reg = <0x10970000 0xc0>;
+                               interrupts = <GIC_SPI 642 IRQ_TYPE_LEVEL_HIGH 0>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c8_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_7>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_7>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               status = "disabled";
+                       };
+               };
+
                usi_uart: usi@10a000c0 {
                        compatible = "google,gs101-usi",
                                     "samsung,exynos850-usi";
                        ranges;
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       clocks = <&dummy_clk>, <&dummy_clk>;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PERIC0_TOP1_PCLK_0>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_PERIC0_TOP1_IPCLK_0>;
                        clock-names = "pclk", "ipclk";
                        samsung,sysreg = <&sysreg_peric0 0x1020>;
                        samsung,mode = <USI_V2_UART>;
                        serial_0: serial@10a00000 {
                                compatible = "google,gs101-uart";
                                reg = <0x10a00000 0xc0>;
-                               reg-io-width = <4>;
                                interrupts = <GIC_SPI 634
                                              IRQ_TYPE_LEVEL_HIGH 0>;
-                               clocks = <&dummy_clk 0>, <&dummy_clk 0>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PERIC0_TOP1_PCLK_0>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PERIC0_TOP1_IPCLK_0>;
                                clock-names = "uart", "clk_uart_baud0";
                                samsung,uart-fifosize = <256>;
                                status = "disabled";
                        };
                };
 
+               cmu_peric1: clock-controller@10c00000 {
+                       compatible = "google,gs101-cmu-peric1";
+                       reg = <0x10c00000 0x4000>;
+                       #clock-cells = <1>;
+                       clocks = <&ext_24_5m>,
+                                <&cmu_top CLK_DOUT_CMU_PERIC1_BUS>,
+                                <&cmu_top CLK_DOUT_CMU_PERIC1_IP>;
+                       clock-names = "oscclk", "bus", "ip";
+               };
+
                sysreg_peric1: syscon@10c20000 {
                        compatible = "google,gs101-peric1-sysreg", "syscon";
                        reg = <0x10c20000 0x10000>;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_SYSREG_PERIC1_PCLK>;
                };
 
                pinctrl_peric1: pinctrl@10c40000 {
                        interrupts = <GIC_SPI 644 IRQ_TYPE_LEVEL_HIGH 0>;
                };
 
+               usi12: usi@10d500c0 {
+                       compatible = "google,gs101-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x10d500c0 0x20>;
+                       ranges;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PERIC1_TOP0_PCLK_5>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_PERIC1_TOP0_IPCLK_5>;
+                       clock-names = "pclk", "ipclk";
+                       samsung,sysreg = <&sysreg_peric1 0x1010>;
+                       status = "disabled";
+
+                       hsi2c_12: i2c@10d50000 {
+                               compatible = "google,gs101-hsi2c",
+                                            "samsung,exynosautov9-hsi2c";
+                               reg = <0x10d50000 0xc0>;
+                               interrupts = <GIC_SPI 655 IRQ_TYPE_LEVEL_HIGH 0>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               pinctrl-0 = <&hsi2c12_bus>;
+                               pinctrl-names = "default";
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PERIC1_TOP0_IPCLK_5>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PERIC1_TOP0_PCLK_5>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               status = "disabled";
+                       };
+               };
+
                pinctrl_hsi1: pinctrl@11840000 {
                        compatible = "google,gs101-pinctrl";
                        reg = <0x11840000 0x00001000>;
index 2e027675d7bbe16300b91be4b6f5522b245dea12..045250d0a04046eb8e214278f799ce2fc1c706f3 100644 (file)
@@ -20,23 +20,41 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-frwy.dtb
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds.dtb
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb.dtb
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-tqmls1046a-mbls10xxa.dtb
+DTC_FLAGS_fsl-ls1088a-qds := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-qds.dtb
+DTC_FLAGS_fsl-ls1088a-rdb := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-rdb.dtb
+DTC_FLAGS_fsl-ls1088a-ten64 := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-ten64.dtb
+DTC_FLAGS_fsl-ls1088a-tqmls1088a-mbls10xxa := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-tqmls1088a-mbls10xxa.dtb
+DTC_FLAGS_fsl-ls2080a-qds := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-qds.dtb
+DTC_FLAGS_fsl-ls2080a-rdb := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-rdb.dtb
+DTC_FLAGS_fsl-ls2081a-rdb := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2081a-rdb.dtb
+DTC_FLAGS_fsl-ls2080a-simu := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-simu.dtb
+DTC_FLAGS_fsl-ls2088a-qds := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a-qds.dtb
+DTC_FLAGS_fsl-ls2088a-rdb := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a-rdb.dtb
+DTC_FLAGS_fsl-lx2160a-bluebox3 := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-bluebox3.dtb
+DTC_FLAGS_fsl-lx2160a-bluebox3-rev-a := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-bluebox3-rev-a.dtb
+DTC_FLAGS_fsl-lx2160a-clearfog-cx := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-clearfog-cx.dtb
+DTC_FLAGS_fsl-lx2160a-honeycomb := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-honeycomb.dtb
+DTC_FLAGS_fsl-lx2160a-qds := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-qds.dtb
+DTC_FLAGS_fsl-lx2160a-rdb := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-rdb.dtb
+DTC_FLAGS_fsl-lx2162a-clearfog := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2162a-clearfog.dtb
+DTC_FLAGS_fsl-lx2162a-qds := -Wno-interrupt_map
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2162a-qds.dtb
 
 fsl-ls1028a-qds-13bb-dtbs := fsl-ls1028a-qds.dtb fsl-ls1028a-qds-13bb.dtbo
@@ -53,6 +71,7 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-85bb.dtb
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-899b.dtb
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-9999.dtb
 
+DTC_FLAGS_fsl-lx2160a-tqmlx2160a-mblx2160a := -Wno-interrupt_map
 fsl-lx2160a-tqmlx2160a-mblx2160a-12-11-x-dtbs := fsl-lx2160a-tqmlx2160a-mblx2160a.dtb \
        fsl-lx2160a-tqmlx2160a-mblx2160a_12_x_x.dtbo \
        fsl-lx2160a-tqmlx2160a-mblx2160a_x_11_x.dtbo
@@ -80,6 +99,7 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-tqmlx2160a-mblx2160a-14-8-x.dtb
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-tqmlx2160a-mblx2160a-14-7-x.dtb
 
 dtb-$(CONFIG_ARCH_MXC) += imx8dxl-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8dxp-tqma8xdp-mba8xx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-beacon-kit.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-data-modul-edm-sbc.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-ddr4-evk.dtb
@@ -133,7 +153,9 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mn-var-som-symphony.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-venice-gw7902.dtb
 
 imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33-dtbs += imx8mn-tqma8mqnl-mba8mx.dtb imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33.dtbo
+imx8mn-tqma8mqnl-mba8mx-usbotg-dtbs += imx8mn-tqma8mqnl-mba8mx.dtb imx8mn-tqma8mqnl-mba8mx-usbotg.dtbo
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx-lvds-tm070jvhg33.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx-usbotg.dtb
 
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-beacon-kit.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-data-modul-edm-sbc.dtb
@@ -188,8 +210,10 @@ imx8mq-tqma8mq-mba8mx-lvds-tm070jvhg33-dtbs += imx8mq-tqma8mq-mba8mx.dtb imx8mq-
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-tqma8mq-mba8mx-lvds-tm070jvhg33.dtb
 
 dtb-$(CONFIG_ARCH_MXC) += imx8qm-apalis-eval.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8qm-apalis-eval-v1.2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qm-apalis-ixora-v1.1.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qm-apalis-v1.1-eval.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8qm-apalis-v1.1-eval-v1.2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qm-apalis-v1.1-ixora-v1.1.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qm-apalis-v1.1-ixora-v1.2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qm-mek.dtb
@@ -199,10 +223,13 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-colibri-eval-v3.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-colibri-iris.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-colibri-iris-v2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqp-mba8xx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx93-phyboard-segin.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-tqma9352-mba93xxca.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-tqma9352-mba93xxla.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx93-var-som-symphony.dtb
 
 imx8mm-venice-gw72xx-0x-imx219-dtbs    := imx8mm-venice-gw72xx-0x.dtb imx8mm-venice-gw72xx-0x-imx219.dtbo
 imx8mm-venice-gw72xx-0x-rpidsi-dtbs    := imx8mm-venice-gw72xx-0x.dtb imx8mm-venice-gw72xx-0x-rpidsi.dtbo
index 1e3fe3897b52cedb83656c88e4a07aa45aa89390..fe9093b3c02e2cdee19e8637b859d57122da1b65 100644 (file)
                dcfg: dcfg@1ee0000 {
                        compatible = "fsl,ls1012a-dcfg",
                                     "syscon";
-                       reg = <0x0 0x1ee0000 0x0 0x10000>;
+                       reg = <0x0 0x1ee0000 0x0 0x1000>;
                        big-endian;
                };
 
                };
 
                i2c0: i2c@2180000 {
-                       compatible = "fsl,vf610-i2c";
+                       compatible = "fsl,ls1012a-i2c", "fsl,vf610-i2c";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <0x0 0x2180000 0x0 0x10000>;
                        interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
                                            QORIQ_CLK_PLL_DIV(4)>;
+                       scl-gpios = <&gpio0 2 0>;
                        status = "disabled";
                };
 
                i2c1: i2c@2190000 {
-                       compatible = "fsl,vf610-i2c";
+                       compatible = "fsl,ls1012a-i2c", "fsl,vf610-i2c";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <0x0 0x2190000 0x0 0x10000>;
                        interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
                                            QORIQ_CLK_PLL_DIV(4)>;
+                       scl-gpios = <&gpio0 13 0>;
                        status = "disabled";
                };
 
                        snps,quirk-frame-length-adjustment = <0x20>;
                        snps,dis_rxdet_inp3_quirk;
                        snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
+                       snps,host-vbus-glitches;
                };
 
                sata: sata@3200000 {
                                        <0000 0 0 2 &gic 0 111 IRQ_TYPE_LEVEL_HIGH>,
                                        <0000 0 0 3 &gic 0 112 IRQ_TYPE_LEVEL_HIGH>,
                                        <0000 0 0 4 &gic 0 113 IRQ_TYPE_LEVEL_HIGH>;
+                       big-endian;
                        status = "disabled";
                };
 
index 1515cec231470c03fba6271d6ffb2080fa863316..754a64be739cf69bd96333a2dc014c44129acf16 100644 (file)
                                <0x00030005 0x00000042>,
                                <0x00030006 0x0000004c>,
                                <0x00030007 0x00000056>;
-                       big-endian;
                        #thermal-sensor-cells = <1>;
                };
 
index 8616d5e0c38845aafd59c067e490f0a69b3c95d7..604bf88d70b3a3b7c1ab0fd973a0fb10daca918f 100644 (file)
                        reg = <0x00 0x03400000 0x0 0x00100000>,
                              <0x20 0x00000000 0x8 0x00000000>;
                        reg-names = "regs", "addr_space";
+                       interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; /* PME interrupt */
+                       interrupt-names = "pme";
                        num-ib-windows = <24>;
                        num-ob-windows = <256>;
                        max-functions = /bits/ 8 <2>;
                        reg = <0x00 0x03500000 0x0 0x00100000>,
                              <0x28 0x00000000 0x8 0x00000000>;
                        reg-names = "regs", "addr_space";
+                       interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>; /* PME interrupt */
+                       interrupt-names = "pme";
                        num-ib-windows = <6>;
                        num-ob-windows = <6>;
                        status = "disabled";
                        reg = <0x00 0x03600000 0x0 0x00100000>,
                              <0x30 0x00000000 0x8 0x00000000>;
                        reg-names = "regs", "addr_space";
+                       interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>; /* PME interrupt */
+                       interrupt-names = "pme";
                        num-ib-windows = <6>;
                        num-ob-windows = <6>;
                        status = "disabled";
index 6640b49670ae5162841536fc0708117616f3218f..e665c629e1a1f6f6bf6d38e4711f3ad47c1da0dd 100644 (file)
                };
 
                uart0: serial@21c0000 {
-                       compatible = "arm,sbsa-uart","arm,pl011";
+                       compatible = "arm,pl011", "arm,primecell";
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(8)>,
+                                <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(8)>;
+                       clock-names = "uartclk", "apb_pclk";
                        reg = <0x0 0x21c0000 0x0 0x1000>;
                        interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
-                       current-speed = <115200>;
                        status = "disabled";
                };
 
                uart1: serial@21d0000 {
-                       compatible = "arm,sbsa-uart","arm,pl011";
+                       compatible = "arm,pl011", "arm,primecell";
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(8)>,
+                                <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(8)>;
+                       clock-names = "uartclk", "apb_pclk";
                        reg = <0x0 0x21d0000 0x0 0x1000>;
                        interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
-                       current-speed = <115200>;
                        status = "disabled";
                };
 
                uart2: serial@21e0000 {
-                       compatible = "arm,sbsa-uart","arm,pl011";
+                       compatible = "arm,pl011", "arm,primecell";
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(8)>,
+                                <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(8)>;
+                       clock-names = "uartclk", "apb_pclk";
                        reg = <0x0 0x21e0000 0x0 0x1000>;
                        interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
-                       current-speed = <115200>;
                        status = "disabled";
                };
 
                uart3: serial@21f0000 {
-                       compatible = "arm,sbsa-uart","arm,pl011";
+                       compatible = "arm,pl011", "arm,primecell";
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(8)>,
+                                <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(8)>;
+                       clock-names = "uartclk", "apb_pclk";
                        reg = <0x0 0x21f0000 0x0 0x1000>;
                        interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
-                       current-speed = <115200>;
                        status = "disabled";
                };
 
diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-eval-v1.1.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-eval-v1.1.dtsi
new file mode 100644 (file)
index 0000000..0f77f78
--- /dev/null
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2024 Toradex
+ */
+
+#include "imx8-apalis-eval.dtsi"
+
+/* Apalis CAN1 */
+&flexcan1 {
+       status = "okay";
+};
+
+/* Apalis CAN2 */
+&flexcan2 {
+       status = "okay";
+};
+
+/* Apalis MMC1 */
+&usdhc2 {
+       status = "okay";
+};
+
+/* Apalis SD1 */
+&usdhc3 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-eval-v1.2.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-eval-v1.2.dtsi
new file mode 100644 (file)
index 0000000..f5c6a01
--- /dev/null
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2024 Toradex
+ */
+
+#include "imx8-apalis-eval.dtsi"
+
+/ {
+       reg_3v3_mmc: regulator-3v3-mmc {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_enable_3v3_mmc>;
+               enable-active-high;
+               gpio = <&lsio_gpio5 19 GPIO_ACTIVE_HIGH>;
+               off-on-delay-us = <100000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "3.3V_MMC";
+               startup-delay-us = <10000>;
+       };
+
+       reg_3v3_sd: regulator-3v3-sd {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_enable_3v3_sd>;
+               enable-active-high;
+               gpio = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>;
+               off-on-delay-us = <100000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "3.3V_SD";
+               startup-delay-us = <10000>;
+       };
+
+       reg_can1: regulator-can1 {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_enable_can1_power>;
+               enable-active-high;
+               gpio = <&lsio_gpio5 22 GPIO_ACTIVE_HIGH>;
+               regulator-name = "5V_SW_CAN1";
+               startup-delay-us = <10000>;
+       };
+
+       reg_can2: regulator-can2 {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_enable_can2_power>;
+               enable-active-high;
+               gpio = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>;
+               regulator-name = "5V_SW_CAN2";
+               startup-delay-us = <10000>;
+       };
+};
+
+/* Apalis CAN1 */
+&flexcan1 {
+       xceiver-supply = <&reg_can1>;
+       status = "okay";
+};
+
+/* Apalis CAN2 */
+&flexcan2 {
+       xceiver-supply = <&reg_can2>;
+       status = "okay";
+};
+
+/* Apalis I2C1 */
+&i2c2 {
+       status = "okay";
+
+       /* Power/Current Measurement Sensor */
+       hwmon@40 {
+               compatible = "ti,ina219";
+               reg = <0x40>;
+               shunt-resistor = <5000>;
+       };
+
+       temperature-sensor@4f {
+               compatible = "ti,tmp75c";
+               reg = <0x4f>;
+       };
+
+       eeprom@57 {
+               compatible = "st,24c02", "atmel,24c02";
+               reg = <0x57>;
+       };
+};
+
+/* Apalis MMC1 */
+&usdhc2 {
+       pinctrl-0 = <&pinctrl_usdhc2_4bit>, <&pinctrl_mmc1_cd>;
+       pinctrl-1 = <&pinctrl_usdhc2_4bit_100mhz>, <&pinctrl_mmc1_cd>;
+       pinctrl-2 = <&pinctrl_usdhc2_4bit_200mhz>, <&pinctrl_mmc1_cd>;
+       pinctrl-3 = <&pinctrl_usdhc2_4bit_sleep>, <&pinctrl_mmc1_cd_sleep>;
+       bus-width = <4>;
+       vmmc-supply = <&reg_3v3_mmc>;
+       status = "okay";
+};
+
+/* Apalis SD1 */
+&usdhc3 {
+       vmmc-supply = <&reg_3v3_sd>;
+       status = "okay";
+};
+
+&iomuxc {
+
+       pinctrl_enable_3v3_mmc: enable3v3mmcgrp {
+               fsl,pins = <IMX8QM_USDHC1_DATA4_LSIO_GPIO5_IO19 0x00000021>; /* MXM3_148 */
+       };
+
+       pinctrl_enable_3v3_sd: enable3v3sdgrp {
+               fsl,pins = <IMX8QM_USDHC1_DATA5_LSIO_GPIO5_IO20 0x00000021>; /* MXM3_152 */
+       };
+
+       pinctrl_enable_can1_power: enablecan1powergrp {
+               fsl,pins = <IMX8QM_USDHC1_DATA7_LSIO_GPIO5_IO22 0x00000021>; /* MXM3_158 */
+       };
+
+       pinctrl_enable_can2_power: enablecan2powergrp {
+               fsl,pins = <IMX8QM_USDHC1_DATA6_LSIO_GPIO5_IO21 0x00000021>; /* MXM3_156 */
+       };
+};
index 685d4294f4f17d9b9d10abf0b2d7fe7a76c1bd90..deecb96a159610a2582a81e915d6cc2bbf24b139 100644 (file)
        status = "okay";
 };
 
-/* Apalis CAN1 */
-&flexcan1 {
-       status = "okay";
-};
-
-/* Apalis CAN2 */
-&flexcan2 {
-       status = "okay";
-};
-
-/* TODO: GPU */
-
 /* Apalis I2C1 */
 &i2c2 {
        status = "okay";
 };
 
 /* TODO: Apalis USBH4 SuperSpeed */
-
-/* Apalis MMC1 */
-&usdhc2 {
-       status = "okay";
-};
-
-/* Apalis SD1 */
-&usdhc3 {
-       status = "okay";
-};
index f69b0c17560aee381f5384928b3d6071f3f141bd..160153853b686223d4afd3eaad396524091c34dc 100644 (file)
                        reset-assert-us = <2>;
                        reset-deassert-us = <2>;
                        reset-gpios = <&lsio_gpio1 11 GPIO_ACTIVE_LOW>;
-                       reset-names = "phy";
                };
        };
 };
index f057c6b21b301297d6d49ebb0b5a70ca38fc5c37..07afeb78ed56483e8784f26add43f73c6b58c811 100644 (file)
@@ -4,6 +4,7 @@
  *     Dong Aisheng <aisheng.dong@nxp.com>
  */
 
+#include <dt-bindings/clock/imx8-clock.h>
 #include <dt-bindings/clock/imx8-lpcg.h>
 #include <dt-bindings/firmware/imx/rsrc.h>
 
@@ -14,12 +15,174 @@ audio_ipg_clk: clock-audio-ipg {
        clock-output-names = "audio_ipg_clk";
 };
 
+clk_ext_aud_mclk0: clock-ext-aud-mclk0 {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "ext_aud_mclk0";
+};
+
+clk_ext_aud_mclk1: clock-ext-aud-mclk1 {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "ext_aud_mclk1";
+};
+
+clk_esai0_rx_clk: clock-esai0-rx {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "esai0_rx_clk";
+};
+
+clk_esai0_rx_hf_clk: clock-esai0-rx-hf {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "esai0_rx_hf_clk";
+};
+
+clk_esai0_tx_clk: clock-esai0-tx {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "esai0_tx_clk";
+};
+
+clk_esai0_tx_hf_clk: clock-esai0-tx-hf {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "esai0_tx_hf_clk";
+};
+
+clk_spdif0_rx: clock-spdif0-rx {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "spdif0_rx";
+};
+
+clk_sai0_rx_bclk: clock-sai0-rx-bclk {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "sai0_rx_bclk";
+};
+
+clk_sai0_tx_bclk: clock-sai0-tx-bclk {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "sai0_tx_bclk";
+};
+
+clk_sai1_rx_bclk: clock-sai1-rx-bclk {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "sai1_rx_bclk";
+};
+
+clk_sai1_tx_bclk: clock-sai1-tx-bclk {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "sai1_tx_bclk";
+};
+
+clk_sai2_rx_bclk: clock-sai2-rx-bclk {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "sai2_rx_bclk";
+};
+
+clk_sai3_rx_bclk: clock-sai3-rx-bclk {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "sai3_rx_bclk";
+};
+
+clk_sai4_rx_bclk: clock-sai4-rx-bclk {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <0>;
+       clock-output-names = "sai4_rx_bclk";
+};
+
 audio_subsys: bus@59000000 {
        compatible = "simple-bus";
        #address-cells = <1>;
        #size-cells = <1>;
        ranges = <0x59000000 0x0 0x59000000 0x1000000>;
 
+       sai0: sai@59040000 {
+               compatible = "fsl,imx8qm-sai";
+               reg = <0x59040000 0x10000>;
+               interrupts = <GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&sai0_lpcg 1>,
+                        <&clk_dummy>,
+                        <&sai0_lpcg 0>,
+                        <&clk_dummy>,
+                        <&clk_dummy>;
+               clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+               dma-names = "rx", "tx";
+               dmas = <&edma0 12 0 1>, <&edma0 13 0 0>;
+               power-domains = <&pd IMX_SC_R_SAI_0>;
+               status = "disabled";
+       };
+
+       sai1: sai@59050000 {
+               compatible = "fsl,imx8qm-sai";
+               reg = <0x59050000 0x10000>;
+               interrupts = <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&sai1_lpcg 1>,
+                        <&clk_dummy>,
+                        <&sai1_lpcg 0>,
+                        <&clk_dummy>,
+                        <&clk_dummy>;
+               clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+               dma-names = "rx", "tx";
+               dmas = <&edma0 14 0 1>, <&edma0 15 0 0>;
+               power-domains = <&pd IMX_SC_R_SAI_1>;
+               status = "disabled";
+       };
+
+       sai2: sai@59060000 {
+               compatible = "fsl,imx8qm-sai";
+               reg = <0x59060000 0x10000>;
+               interrupts = <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&sai2_lpcg 1>,
+                        <&clk_dummy>,
+                        <&sai2_lpcg 0>,
+                        <&clk_dummy>,
+                        <&clk_dummy>;
+               clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+               dma-names = "rx";
+               dmas = <&edma0 16 0 1>;
+               power-domains = <&pd IMX_SC_R_SAI_2>;
+               status = "disabled";
+       };
+
+       sai3: sai@59070000 {
+               compatible = "fsl,imx8qm-sai";
+               reg = <0x59070000 0x10000>;
+               interrupts = <GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&sai3_lpcg 1>,
+                        <&clk_dummy>,
+                        <&sai3_lpcg 0>,
+                        <&clk_dummy>,
+                        <&clk_dummy>;
+               clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
+               dma-names = "rx";
+               dmas = <&edma0 17 0 1>;
+               power-domains = <&pd IMX_SC_R_SAI_3>;
+               status = "disabled";
+       };
+
        edma0: dma-controller@591f0000 {
                compatible = "fsl,imx8qm-edma";
                reg = <0x591f0000 0x190000>;
@@ -76,6 +239,54 @@ audio_subsys: bus@59000000 {
                                <&pd IMX_SC_R_DMA_0_CH23>;
        };
 
+       sai0_lpcg: clock-controller@59440000 {
+               compatible = "fsl,imx8qxp-lpcg";
+               reg = <0x59440000 0x10000>;
+               #clock-cells = <1>;
+               clocks = <&acm IMX_ADMA_ACM_SAI0_MCLK_SEL>,
+                        <&audio_ipg_clk>;
+               clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>;
+               clock-output-names = "sai0_lpcg_mclk",
+                                    "sai0_lpcg_ipg_clk";
+               power-domains = <&pd IMX_SC_R_SAI_0>;
+       };
+
+       sai1_lpcg: clock-controller@59450000 {
+               compatible = "fsl,imx8qxp-lpcg";
+               reg = <0x59450000 0x10000>;
+               #clock-cells = <1>;
+               clocks = <&acm IMX_ADMA_ACM_SAI1_MCLK_SEL>,
+                        <&audio_ipg_clk>;
+               clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>;
+               clock-output-names = "sai1_lpcg_mclk",
+                                    "sai1_lpcg_ipg_clk";
+               power-domains = <&pd IMX_SC_R_SAI_1>;
+       };
+
+       sai2_lpcg: clock-controller@59460000 {
+               compatible = "fsl,imx8qxp-lpcg";
+               reg = <0x59460000 0x10000>;
+               #clock-cells = <1>;
+               clocks = <&acm IMX_ADMA_ACM_SAI2_MCLK_SEL>,
+                        <&audio_ipg_clk>;
+               clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>;
+               clock-output-names = "sai2_lpcg_mclk",
+                                    "sai2_lpcg_ipg_clk";
+               power-domains = <&pd IMX_SC_R_SAI_2>;
+       };
+
+       sai3_lpcg: clock-controller@59470000 {
+               compatible = "fsl,imx8qxp-lpcg";
+               reg = <0x59470000 0x10000>;
+               #clock-cells = <1>;
+               clocks = <&acm IMX_ADMA_ACM_SAI3_MCLK_SEL>,
+                        <&audio_ipg_clk>;
+               clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>;
+               clock-output-names = "sai3_lpcg_mclk",
+                                    "sai3_lpcg_ipg_clk";
+               power-domains = <&pd IMX_SC_R_SAI_3>;
+       };
+
        dsp_lpcg: clock-controller@59580000 {
                compatible = "fsl,imx8qxp-lpcg";
                reg = <0x59580000 0x10000>;
@@ -151,4 +362,123 @@ audio_subsys: bus@59000000 {
                                <&pd IMX_SC_R_DMA_1_CH9>,
                                <&pd IMX_SC_R_DMA_1_CH10>;
        };
+
+       aud_rec0_lpcg: clock-controller@59d00000 {
+               compatible = "fsl,imx8qxp-lpcg";
+               reg = <0x59d00000 0x10000>;
+               #clock-cells = <1>;
+               clocks = <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_MST_BUS>;
+               clock-indices = <IMX_LPCG_CLK_0>;
+               clock-output-names = "aud_rec_clk0_lpcg_clk";
+               power-domains = <&pd IMX_SC_R_AUDIO_PLL_0>;
+       };
+
+       aud_rec1_lpcg: clock-controller@59d10000 {
+               compatible = "fsl,imx8qxp-lpcg";
+               reg = <0x59d10000 0x10000>;
+               #clock-cells = <1>;
+               clocks = <&clk IMX_SC_R_AUDIO_PLL_1 IMX_SC_PM_CLK_MST_BUS>;
+               clock-indices = <IMX_LPCG_CLK_0>;
+               clock-output-names = "aud_rec_clk1_lpcg_clk";
+               power-domains = <&pd IMX_SC_R_AUDIO_PLL_1>;
+       };
+
+       aud_pll_div0_lpcg: clock-controller@59d20000 {
+               compatible = "fsl,imx8qxp-lpcg";
+               reg = <0x59d20000 0x10000>;
+               #clock-cells = <1>;
+               clocks = <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_SLV_BUS>;
+               clock-indices = <IMX_LPCG_CLK_0>;
+               clock-output-names = "aud_pll_div_clk0_lpcg_clk";
+               power-domains = <&pd IMX_SC_R_AUDIO_PLL_0>;
+       };
+
+       aud_pll_div1_lpcg: clock-controller@59d30000 {
+               compatible = "fsl,imx8qxp-lpcg";
+               reg = <0x59d30000 0x10000>;
+               #clock-cells = <1>;
+               clocks = <&clk IMX_SC_R_AUDIO_PLL_1 IMX_SC_PM_CLK_SLV_BUS>;
+               clock-indices = <IMX_LPCG_CLK_0>;
+               clock-output-names = "aud_pll_div_clk1_lpcg_clk";
+               power-domains = <&pd IMX_SC_R_AUDIO_PLL_1>;
+       };
+
+       mclkout0_lpcg: clock-controller@59d50000 {
+               compatible = "fsl,imx8qxp-lpcg";
+               reg = <0x59d50000 0x10000>;
+               #clock-cells = <1>;
+               clocks = <&acm IMX_ADMA_ACM_MCLKOUT0_SEL>;
+               clock-indices = <IMX_LPCG_CLK_0>;
+               clock-output-names = "mclkout0_lpcg_clk";
+               power-domains = <&pd IMX_SC_R_MCLK_OUT_0>;
+       };
+
+       mclkout1_lpcg: clock-controller@59d60000 {
+               compatible = "fsl,imx8qxp-lpcg";
+               reg = <0x59d60000 0x10000>;
+               #clock-cells = <1>;
+               clocks = <&acm IMX_ADMA_ACM_MCLKOUT1_SEL>;
+               clock-indices = <IMX_LPCG_CLK_0>;
+               clock-output-names = "mclkout1_lpcg_clk";
+               power-domains = <&pd IMX_SC_R_MCLK_OUT_1>;
+       };
+
+       acm: acm@59e00000 {
+               compatible = "fsl,imx8qxp-acm";
+               reg = <0x59e00000 0x1d0000>;
+               #clock-cells = <1>;
+               power-domains = <&pd IMX_SC_R_AUDIO_CLK_0>,
+                               <&pd IMX_SC_R_AUDIO_CLK_1>,
+                               <&pd IMX_SC_R_MCLK_OUT_0>,
+                               <&pd IMX_SC_R_MCLK_OUT_1>,
+                               <&pd IMX_SC_R_AUDIO_PLL_0>,
+                               <&pd IMX_SC_R_AUDIO_PLL_1>,
+                               <&pd IMX_SC_R_ASRC_0>,
+                               <&pd IMX_SC_R_ASRC_1>,
+                               <&pd IMX_SC_R_ESAI_0>,
+                               <&pd IMX_SC_R_SAI_0>,
+                               <&pd IMX_SC_R_SAI_1>,
+                               <&pd IMX_SC_R_SAI_2>,
+                               <&pd IMX_SC_R_SAI_3>,
+                               <&pd IMX_SC_R_SAI_4>,
+                               <&pd IMX_SC_R_SAI_5>,
+                               <&pd IMX_SC_R_SPDIF_0>,
+                               <&pd IMX_SC_R_MQS_0>;
+               clocks = <&aud_rec0_lpcg IMX_LPCG_CLK_0>,
+                        <&aud_rec1_lpcg IMX_LPCG_CLK_0>,
+                        <&aud_pll_div0_lpcg IMX_LPCG_CLK_0>,
+                        <&aud_pll_div1_lpcg IMX_LPCG_CLK_0>,
+                        <&clk_ext_aud_mclk0>,
+                        <&clk_ext_aud_mclk1>,
+                        <&clk_esai0_rx_clk>,
+                        <&clk_esai0_rx_hf_clk>,
+                        <&clk_esai0_tx_clk>,
+                        <&clk_esai0_tx_hf_clk>,
+                        <&clk_spdif0_rx>,
+                        <&clk_sai0_rx_bclk>,
+                        <&clk_sai0_tx_bclk>,
+                        <&clk_sai1_rx_bclk>,
+                        <&clk_sai1_tx_bclk>,
+                        <&clk_sai2_rx_bclk>,
+                        <&clk_sai3_rx_bclk>,
+                        <&clk_sai4_rx_bclk>;
+               clock-names = "aud_rec_clk0_lpcg_clk",
+                             "aud_rec_clk1_lpcg_clk",
+                             "aud_pll_div_clk0_lpcg_clk",
+                             "aud_pll_div_clk1_lpcg_clk",
+                             "ext_aud_mclk0",
+                             "ext_aud_mclk1",
+                             "esai0_rx_clk",
+                             "esai0_rx_hf_clk",
+                             "esai0_tx_clk",
+                             "esai0_tx_hf_clk",
+                             "spdif0_rx",
+                             "sai0_rx_bclk",
+                             "sai0_tx_bclk",
+                             "sai1_rx_bclk",
+                             "sai1_tx_bclk",
+                             "sai2_rx_bclk",
+                             "sai3_rx_bclk",
+                             "sai4_rx_bclk";
+       };
 };
index b0bb77150adccb6c9610c1b0dcf510100495a772..cab3468b1875ee885f32a842f92d56cc0b744998 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/imx8-lpcg.h>
+#include <dt-bindings/dma/fsl-edma.h>
 #include <dt-bindings/firmware/imx/rsrc.h>
 
 dma_ipg_clk: clock-dma-ipg {
@@ -93,8 +94,8 @@ dma_subsys: bus@5a000000 {
                assigned-clocks = <&clk IMX_SC_R_UART_0 IMX_SC_PM_CLK_PER>;
                assigned-clock-rates = <80000000>;
                power-domains = <&pd IMX_SC_R_UART_0>;
-               dma-names = "tx","rx";
-               dmas = <&edma2 9 0 0>, <&edma2 8 0 1>;
+               dma-names = "rx", "tx";
+               dmas = <&edma2 8 0 FSL_EDMA_RX>, <&edma2 9 0 0>;
                status = "disabled";
        };
 
@@ -107,8 +108,8 @@ dma_subsys: bus@5a000000 {
                assigned-clocks = <&clk IMX_SC_R_UART_1 IMX_SC_PM_CLK_PER>;
                assigned-clock-rates = <80000000>;
                power-domains = <&pd IMX_SC_R_UART_1>;
-               dma-names = "tx","rx";
-               dmas = <&edma2 11 0 0>, <&edma2 10 0 1>;
+               dma-names = "rx", "tx";
+               dmas = <&edma2 10 0 FSL_EDMA_RX>, <&edma2 11 0 0>;
                status = "disabled";
        };
 
@@ -121,8 +122,8 @@ dma_subsys: bus@5a000000 {
                assigned-clocks = <&clk IMX_SC_R_UART_2 IMX_SC_PM_CLK_PER>;
                assigned-clock-rates = <80000000>;
                power-domains = <&pd IMX_SC_R_UART_2>;
-               dma-names = "tx","rx";
-               dmas = <&edma2 13 0 0>, <&edma2 12 0 1>;
+               dma-names = "rx", "tx";
+               dmas = <&edma2 12 0 FSL_EDMA_RX>, <&edma2 13 0 0>;
                status = "disabled";
        };
 
@@ -135,8 +136,8 @@ dma_subsys: bus@5a000000 {
                assigned-clocks = <&clk IMX_SC_R_UART_3 IMX_SC_PM_CLK_PER>;
                assigned-clock-rates = <80000000>;
                power-domains = <&pd IMX_SC_R_UART_3>;
-               dma-names = "tx","rx";
-               dmas = <&edma2 15 0 0>, <&edma2 14 0 1>;
+               dma-names = "rx", "tx";
+               dmas = <&edma2 14 0 FSL_EDMA_RX>, <&edma2 15 0 0>;
                status = "disabled";
        };
 
@@ -192,29 +193,6 @@ dma_subsys: bus@5a000000 {
                                <&pd IMX_SC_R_DMA_2_CH15>;
        };
 
-       edma3: dma-controller@5a9f0000 {
-               compatible = "fsl,imx8qm-edma";
-               reg = <0x5a9f0000 0x90000>;
-               #dma-cells = <3>;
-               dma-channels = <8>;
-               interrupts = <GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 426 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 427 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 428 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 429 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 430 IRQ_TYPE_LEVEL_HIGH>,
-                            <GIC_SPI 431 IRQ_TYPE_LEVEL_HIGH>;
-               power-domains = <&pd IMX_SC_R_DMA_3_CH0>,
-                               <&pd IMX_SC_R_DMA_3_CH1>,
-                               <&pd IMX_SC_R_DMA_3_CH2>,
-                               <&pd IMX_SC_R_DMA_3_CH3>,
-                               <&pd IMX_SC_R_DMA_3_CH4>,
-                               <&pd IMX_SC_R_DMA_3_CH5>,
-                               <&pd IMX_SC_R_DMA_3_CH6>,
-                               <&pd IMX_SC_R_DMA_3_CH7>;
-       };
-
        spi0_lpcg: clock-controller@5a400000 {
                compatible = "fsl,imx8qxp-lpcg";
                reg = <0x5a400000 0x10000>;
@@ -460,6 +438,29 @@ dma_subsys: bus@5a000000 {
                status = "disabled";
        };
 
+       edma3: dma-controller@5a9f0000 {
+               compatible = "fsl,imx8qm-edma";
+               reg = <0x5a9f0000 0x90000>;
+               #dma-cells = <3>;
+               dma-channels = <8>;
+               interrupts = <GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 426 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 427 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 428 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 429 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 430 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 431 IRQ_TYPE_LEVEL_HIGH>;
+               power-domains = <&pd IMX_SC_R_DMA_3_CH0>,
+                               <&pd IMX_SC_R_DMA_3_CH1>,
+                               <&pd IMX_SC_R_DMA_3_CH2>,
+                               <&pd IMX_SC_R_DMA_3_CH3>,
+                               <&pd IMX_SC_R_DMA_3_CH4>,
+                               <&pd IMX_SC_R_DMA_3_CH5>,
+                               <&pd IMX_SC_R_DMA_3_CH6>,
+                               <&pd IMX_SC_R_DMA_3_CH7>;
+       };
+
        i2c0_lpcg: clock-controller@5ac00000 {
                compatible = "fsl,imx8qxp-lpcg";
                reg = <0x5ac00000 0x10000>;
diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-gpu0.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-gpu0.dtsi
new file mode 100644 (file)
index 0000000..9b8a44a
--- /dev/null
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ *     Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+
+gpu0_subsys: bus@53000000 {
+       compatible = "simple-bus";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       ranges = <0x53000000 0x0 0x53000000 0x1000000>;
+
+       gpu_3d0: gpu@53100000 {
+               compatible = "vivante,gc";
+               reg = <0x53100000 0x40000>;
+               interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk IMX_SC_R_GPU_0_PID0 IMX_SC_PM_CLK_PER>,
+                        <&clk IMX_SC_R_GPU_0_PID0 IMX_SC_PM_CLK_MISC>;
+               clock-names = "core", "shader";
+               assigned-clocks = <&clk IMX_SC_R_GPU_0_PID0 IMX_SC_PM_CLK_PER>,
+                                 <&clk IMX_SC_R_GPU_0_PID0 IMX_SC_PM_CLK_MISC>;
+               assigned-clock-rates = <700000000>, <850000000>;
+               power-domains = <&pd IMX_SC_R_GPU_0_PID0>;
+       };
+};
index b972658efb1769777f7436d38e54d770cc4f9674..2123d431e061374fa7ee154c279b101b5c404433 100644 (file)
                status = "disabled";
        };
 
+       reg_can0_stby: regulator-4 {
+               compatible = "regulator-fixed";
+               regulator-name = "can0-stby";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&pca6416_3 0 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_can1_stby: regulator-5 {
+               compatible = "regulator-fixed";
+               regulator-name = "can1-stby";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&pca6416_3 1 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
        reg_usdhc2_vmmc: regulator-3 {
                compatible = "regulator-fixed";
                regulator-name = "SD1_SPWR";
        };
 };
 
+&i2c3 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       clock-frequency = <100000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       status = "okay";
+
+       pca6416_3: gpio@20 {
+               compatible = "ti,tca6416";
+               reg = <0x20>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-parent = <&lsio_gpio2>;
+               interrupts = <5 IRQ_TYPE_EDGE_RISING>;
+       };
+
+       pca9548_2: i2c-mux@70 {
+               compatible = "nxp,pca9548";
+               reg = <0x70>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0>;
+               };
+
+               i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x1>;
+               };
+
+               i2c@2 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x2>;
+               };
+
+               i2c@3 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x3>;
+               };
+
+               i2c@4 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x4>;
+               };
+       };
+};
+
 &lpuart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_lpuart0>;
        status = "okay";
 };
 
+&flexcan2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan2>;
+       xceiver-supply = <&reg_can0_stby>;
+       status = "okay";
+};
+
+&flexcan3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan3>;
+       xceiver-supply = <&reg_can1_stby>;
+       status = "okay";
+};
+
 &lsio_gpio4 {
        status = "okay";
 };
                >;
        };
 
+       pinctrl_flexcan2: flexcan2grp {
+               fsl,pins = <
+                       IMX8DXL_UART2_TX_ADMA_FLEXCAN1_TX       0x00000021
+                       IMX8DXL_UART2_RX_ADMA_FLEXCAN1_RX       0x00000021
+               >;
+       };
+
+       pinctrl_flexcan3: flexcan3grp {
+               fsl,pins = <
+                       IMX8DXL_FLEXCAN2_TX_ADMA_FLEXCAN2_TX    0x00000021
+                       IMX8DXL_FLEXCAN2_RX_ADMA_FLEXCAN2_RX    0x00000021
+               >;
+       };
+
        pinctrl_fec1: fec1grp {
                fsl,pins = <
                        IMX8DXL_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB0_PAD           0x000014a0
index 0a477f6318f1523f00340d83b573685598f6f16b..5d012c95222f52fd59be9ad70bf8d23e82a54383 100644 (file)
        interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
 };
 
+&edma0 {
+       reg = <0x591f0000 0x1a0000>;
+       #dma-cells = <3>;
+       dma-channels = <25>;
+       dma-channel-mask = <0x1c0cc0>;
+       interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>, /* asrc 0 */
+               <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 0   IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 0   IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>, /* spdif0 */
+               <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 0   IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 0   IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>, /* sai0 */
+               <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>, /* sai1 */
+               <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>, /* sai2 */
+               <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>, /* sai3 */
+               <GIC_SPI 0   IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 0   IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 0   IRQ_TYPE_LEVEL_HIGH>,
+               <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>, /* gpt0 */
+               <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>, /* gpt1 */
+               <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>, /* gpt2 */
+               <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>; /* gpt3 */
+       power-domains = <&pd IMX_SC_R_DMA_0_CH0>,
+                       <&pd IMX_SC_R_DMA_0_CH1>,
+                       <&pd IMX_SC_R_DMA_0_CH2>,
+                       <&pd IMX_SC_R_DMA_0_CH3>,
+                       <&pd IMX_SC_R_DMA_0_CH4>,
+                       <&pd IMX_SC_R_DMA_0_CH5>,
+                       <&pd IMX_SC_R_DMA_0_CH6>,
+                       <&pd IMX_SC_R_DMA_0_CH7>,
+                       <&pd IMX_SC_R_DMA_0_CH8>,
+                       <&pd IMX_SC_R_DMA_0_CH9>,
+                       <&pd IMX_SC_R_DMA_0_CH10>,
+                       <&pd IMX_SC_R_DMA_0_CH11>,
+                       <&pd IMX_SC_R_DMA_0_CH12>,
+                       <&pd IMX_SC_R_DMA_0_CH13>,
+                       <&pd IMX_SC_R_DMA_0_CH14>,
+                       <&pd IMX_SC_R_DMA_0_CH15>,
+                       <&pd IMX_SC_R_DMA_0_CH16>,
+                       <&pd IMX_SC_R_DMA_0_CH17>,
+                       <&pd IMX_SC_R_DMA_0_CH18>,
+                       <&pd IMX_SC_R_DMA_0_CH19>,
+                       <&pd IMX_SC_R_DMA_0_CH20>,
+                       <&pd IMX_SC_R_DMA_0_CH21>,
+                       <&pd IMX_SC_R_DMA_0_CH22>,
+                       <&pd IMX_SC_R_DMA_0_CH23>,
+                       <&pd IMX_SC_R_DMA_0_CH24>;
+};
+
 &edma2 {
        interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
                     <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>;
 };
 
+&flexcan1 {
+       interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&flexcan2 {
+       interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&flexcan3 {
+       interrupts = <GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>;
+};
+
 &i2c0 {
        compatible = "fsl,imx8dxl-lpi2c", "fsl,imx7ulp-lpi2c";
        interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
+       dma-names = "tx","rx";
+       dmas = <&edma3 1 0 0>, <&edma3 0 0 FSL_EDMA_RX>;
 };
 
 &i2c1 {
        compatible = "fsl,imx8dxl-lpi2c", "fsl,imx7ulp-lpi2c";
        interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
+       dma-names = "tx","rx";
+       dmas = <&edma3 3 0 0>, <&edma3 2 0 FSL_EDMA_RX>;
 };
 
 &i2c2 {
        compatible = "fsl,imx8dxl-lpi2c", "fsl,imx7ulp-lpi2c";
        interrupts = <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
+       dma-names = "tx","rx";
+       dmas = <&edma3 5 0 0>, <&edma3 4 0 FSL_EDMA_RX>;
 };
 
 &i2c3 {
        compatible = "fsl,imx8dxl-lpi2c", "fsl,imx7ulp-lpi2c";
        interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+       dma-names = "tx","rx";
+       dmas = <&edma3 7 0 0>, <&edma3 6 0 FSL_EDMA_RX>;
 };
 
 &lpuart0 {
index f580eb6db9a61327b8db1ec411e8da7a1ec2c01f..a0674c5c55766dd3971ceea33d2514a72d13c169 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/imx8-clock.h>
+#include <dt-bindings/dma/fsl-edma.h>
 #include <dt-bindings/firmware/imx/rsrc.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/arch/arm64/boot/dts/freescale/imx8dxp-tqma8xdp-mba8xx.dts b/arch/arm64/boot/dts/freescale/imx8dxp-tqma8xdp-mba8xx.dts
new file mode 100644 (file)
index 0000000..f35514b
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR X11)
+/*
+ * Copyright 2018-2023 TQ-Systems GmbH <linux@ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Alexander Stein
+ */
+
+/dts-v1/;
+
+#include "imx8dxp-tqma8xdp.dtsi"
+#include "mba8xx.dtsi"
+
+/ {
+       model = "TQ-Systems i.MX8DXP TQMa8XDP on MBa8Xx";
+       compatible = "tq,imx8dxp-tqma8xdp-mba8xx", "tq,imx8dxp-tqma8xdp", "fsl,imx8dxp";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8dxp-tqma8xdp.dtsi b/arch/arm64/boot/dts/freescale/imx8dxp-tqma8xdp.dtsi
new file mode 100644 (file)
index 0000000..e2de851
--- /dev/null
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR X11)
+/*
+ * Copyright 2018-2023 TQ-Systems GmbH <linux@ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Alexander Stein
+ */
+
+#include "imx8dxp.dtsi"
+#include "tqma8xx.dtsi"
+
+/ {
+       model = "TQ-Systems i.MX8DXP TQMa8XDP";
+       compatible = "tq,imx8dxp-tqma8xdp", "fsl,imx8dxp";
+};
+
+&pmic_thermal {
+       cooling-maps {
+               map0 {
+                       cooling-device =
+                               <&A35_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                               <&A35_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8dxp.dtsi b/arch/arm64/boot/dts/freescale/imx8dxp.dtsi
new file mode 100644 (file)
index 0000000..a8f7352
--- /dev/null
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ */
+
+/dts-v1/;
+
+#include "imx8qxp.dtsi"
+
+/delete-node/ &A35_2;
+/delete-node/ &A35_3;
+
+&thermal_zones {
+       cpu0-thermal {
+               cooling-maps {
+                       map0 {
+                               cooling-device =
+                               <&A35_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                               <&A35_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                       };
+               };
+       };
+};
index b53104ed89199339b67535fc6b9741e0177a2a2d..bd5b365867fda26d130462cccdf9fda8ee2b6293 100644 (file)
                        clocks = <&clk IMX8MM_CLK_SAI3_ROOT>;
                };
        };
+
+       sound-micfil {
+               compatible = "fsl,imx-audio-card";
+               model = "micfil-audio";
+
+               pri-dai-link {
+                       link-name = "micfil hifi";
+                       format = "i2s";
+
+                       cpu {
+                               sound-dai = <&micfil>;
+                       };
+               };
+       };
+
+       sound-spdif {
+               compatible = "fsl,imx-audio-spdif";
+               model = "imx-spdif";
+               spdif-controller = <&spdif1>;
+               spdif-out;
+               spdif-in;
+       };
 };
 
 &A53_0 {
        status = "okay";
 };
 
+&micfil {
+       #sound-dai-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pdm>;
+       assigned-clocks = <&clk IMX8MM_CLK_PDM>;
+       assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
+       assigned-clock-rates = <196608000>;
+       status = "okay";
+};
+
 &mipi_csi {
        status = "okay";
 
        status = "okay";
 };
 
+&spdif1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spdif1>;
+       assigned-clocks = <&clk IMX8MM_CLK_SPDIF1>;
+       assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
+       assigned-clock-rates = <24576000>;
+       clocks = <&clk IMX8MM_CLK_AUDIO_AHB>, <&clk IMX8MM_CLK_24M>,
+                <&clk IMX8MM_CLK_SPDIF1>, <&clk IMX8MM_CLK_DUMMY>,
+                <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>,
+                <&clk IMX8MM_CLK_AUDIO_AHB>, <&clk IMX8MM_CLK_DUMMY>,
+                <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>,
+                <&clk IMX8MM_AUDIO_PLL1_OUT>, <&clk IMX8MM_AUDIO_PLL2_OUT>;
+       clock-names = "core", "rxtx0", "rxtx1", "rxtx2", "rxtx3",
+                     "rxtx4", "rxtx5", "rxtx6", "rxtx7", "spba",
+                     "pll8k", "pll11k";
+       status = "okay";
+};
+
 &uart2 { /* console */
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart2>;
                >;
        };
 
+       pinctrl_pdm: pdmgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI5_MCLK_SAI5_MCLK        0xd6
+                       MX8MM_IOMUXC_SAI5_RXC_PDM_CLK           0xd6
+                       MX8MM_IOMUXC_SAI5_RXFS_SAI5_RX_SYNC     0xd6
+                       MX8MM_IOMUXC_SAI5_RXD0_PDM_DATA0        0xd6
+                       MX8MM_IOMUXC_SAI5_RXD1_PDM_DATA1        0xd6
+                       MX8MM_IOMUXC_SAI5_RXD2_PDM_DATA2        0xd6
+                       MX8MM_IOMUXC_SAI5_RXD3_PDM_DATA3        0xd6
+               >;
+       };
+
        pinctrl_pmic: pmicirqgrp {
                fsl,pins = <
                        MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3               0x141
                >;
        };
 
+       pinctrl_spdif1: spdif1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SPDIF_TX_SPDIF1_OUT        0xd6
+                       MX8MM_IOMUXC_SPDIF_RX_SPDIF1_IN         0xd6
+               >;
+       };
+
        pinctrl_typec1: typec1grp {
                fsl,pins = <
                        MX8MM_IOMUXC_SD1_STROBE_GPIO2_IO11      0x159
index 8b16bd68576c0b51d67320ab4a015068834d881b..33f8d7d1970e0b165c159a788fa0a96cbefb0d82 100644 (file)
 
        leds {
                compatible = "gpio-leds";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_gpio_led>;
 
                led1 {
                        label = "led1";
-                       gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
                        linux,default-trigger = "heartbeat";
                };
 
                led2 {
                        label = "led2";
-                       gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio3 8 GPIO_ACTIVE_LOW>;
                };
 
                led3 {
                        label = "led3";
-                       gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio3 7 GPIO_ACTIVE_LOW>;
                };
        };
 
 
        reg_rst_eth2: regulator-rst-eth2 {
                compatible = "regulator-fixed";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_usb_eth2>;
-               gpio = <&gpio3 2 GPIO_ACTIVE_HIGH>;
+               gpio = <&gpio1 1 GPIO_ACTIVE_HIGH>;
                enable-active-high;
                regulator-always-on;
                regulator-name = "rst-usb-eth2";
        };
 
-       reg_usb1_vbus: regulator-usb1-vbus {
-               compatible = "regulator-fixed";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_reg_usb1_vbus>;
-               gpio = <&gpio3 25 GPIO_ACTIVE_LOW>;
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-               regulator-name = "usb1-vbus";
-       };
-
        reg_vdd_5v: regulator-5v {
                compatible = "regulator-fixed";
                regulator-always-on;
@@ -80,9 +66,6 @@
 };
 
 &ecspi2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_ecspi2>;
-       cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
        status = "okay";
 
        can@0 {
@@ -91,7 +74,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_can>;
                clocks = <&osc_can>;
-               interrupts-extended = <&gpio4 28 IRQ_TYPE_LEVEL_LOW>;
+               interrupts-extended = <&gpio5 1 IRQ_TYPE_LEVEL_LOW>;
                /*
                 * Limit the SPI clock to 15 MHz to prevent issues
                 * with corrupted data due to chip errata.
 };
 
 &ecspi3 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_ecspi3>;
-       cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>;
        status = "okay";
 
        eeram@0 {
 
 &fec1 {
        pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_enet>;
-       phy-connection-type = "rgmii-rxid";
+       pinctrl-0 = <&pinctrl_enet_rgmii>;
+       phy-connection-type = "rgmii-id";
        phy-handle = <&ethphy>;
        status = "okay";
 
                #size-cells = <0>;
 
                ethphy: ethernet-phy@0 {
+                       compatible = "ethernet-phy-id4f51.e91b";
                        reg = <0>;
-                       reset-assert-us = <1>;
-                       reset-deassert-us = <15000>;
-                       reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
+                       reset-assert-us = <10000>;
+                       reset-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
                };
        };
 };
 
+/*
+ * Rename SoM signals according to board usage:
+ *   GPIO_B_0      -> DIO1_OUT
+ *   GPIO_B_1      -> DIO2_OUT
+ */
 &gpio1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_gpio1>;
-       gpio-line-names = "", "", "", "dio1-out", "", "", "dio1-in", "dio2-out",
-                         "dio2-in", "dio3-out", "dio3-in", "dio4-out", "", "", "", "",
-                         "", "", "", "", "", "", "", "",
-                         "", "", "", "", "", "", "", "";
+       gpio-line-names = "", "GPIO_A_0", "", "GPIO_A_1",
+                         "", "GPIO_A_2", "GPIO_A_3", "GPIO_A_4",
+                         "GPIO_A_5", "GPIO_A_6", "GPIO_A_7", "DIO1_OUT",
+                         "DIO2_OUT", "USB_A_OC#", "CAM_MCK", "USB_B_OC#",
+                         "ETH_MDC", "ETH_MDIO", "ETH_A_(S)(R)(G)MII_TXD3",
+                         "ETH_A_(S)(R)(G)MII_TXD2", "ETH_A_(S)(R)(G)MII_TXD1",
+                         "ETH_A_(S)(R)(G)MII_TXD0", "ETH_A_(R)(G)MII_TX_EN(_ER)",
+                         "ETH_A_(R)(G)MII_TX_CLK", "ETH_A_(R)(G)MII_RX_DV(_ER)",
+                         "ETH_A_(R)(G)MII_RX_CLK", "ETH_A_(S)(R)(G)MII_RXD0",
+                         "ETH_A_(S)(R)(G)MII_RXD1", "ETH_A_(R)(G)MII_RXD2",
+                         "ETH_A_(R)(G)MII_RXD3";
 };
 
-&gpio5 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_gpio5>;
-       gpio-line-names = "", "", "dio4-in", "", "", "", "", "",
-                         "", "", "", "", "", "", "", "",
-                         "", "", "", "", "", "", "", "",
-                         "", "", "", "", "", "", "", "";
+/*
+ * Rename SoM signals according to board usage:
+ *   GPIO_B_2      -> DIO3_OUT
+ *   GPIO_B_3      -> DIO4_OUT
+ */
+&gpio3 {
+       gpio-line-names = "GPIO_C_5", "GPIO_C_4", "SDIO_B_CD#", "SDIO_B_D5",
+                         "SDIO_B_D6", "SDIO_B_D7", "GPIO_C_0", "GPIO_C_1",
+                         "GPIO_C_2", "GPIO_C_3", "SDIO_B_D0", "SDIO_B_D1",
+                         "SDIO_B_D2", "SDIO_B_D3", "", "SDIO_B_D4",
+                         "CARRIER_PWR_EN", "SDIO_B_CLK", "SDIO_B_CMD", "DIO3_OUT",
+                         "USB_B_EN", "DIO4_OUT", "PCIe_CLKREQ#", "PCIe_A_PERST#",
+                         "PCIe_WAKE#", "USB_A_EN";
 };
 
-&i2c4 {
-       clock-frequency = <100000>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_i2c4>;
+/*
+ * Rename SoM signals according to board usage:
+ *   GPIO_B_4      -> DIO1_IN
+ *   GPIO_B_5      -> DIO2_IN
+ *   GPIO_B_6      -> DIO3_IN
+ *   GPIO_B_7      -> DIO4_IN
+ */
+&gpio4 {
+       gpio-line-names = "GPIO_C_7", "", "I2S_A_DATA_IN", "I2S_B_DATA_IN",
+                         "DIO1_IN", "BOOT_SEL0#", "BOOT_SEL1#", "",
+                         "", "", "I2S_LRCLK", "I2S_BITCLK",
+                         "I2S_A_DATA_OUT", "I2S_B_DATA_OUT", "DIO2_IN", "DIO3_IN",
+                         "DIO4_IN", "SPI_A_/WP_(IO2)", "SPI_A_/HOLD_(IO3)", "GPIO_C_6",
+                         "I2S_MCLK", "UART_A_TX", "UART_A_RX", "UART_A_CTS",
+                         "UART_A_RTS", "", "", "",
+                         "PCIe_SM_ALERT", "UART_B_RTS", "UART_B_CTS", "UART_B_RX";
+};
+
+&i2c3 {
        status = "okay";
+
+       usb-hub@2c {
+               compatible = "microchip,usb2514b";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usb_hub>;
+               reg = <0x2c>;
+               non-removable-ports = <0>, <3>;
+               reset-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
+       };
 };
 
 &pwm2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_pwm2>;
        status = "okay";
 };
 
+&reg_usb2_vbus {
+       status = "disabled";
+};
+
+&reg_usdhc2_vcc {
+       status = "disabled";
+};
+
+&reg_usdhc3_vcc {
+       status = "disabled";
+};
+
 &uart1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart1>;
        uart-has-rtscts;
        status = "okay";
 };
 
 &uart2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart2>;
        linux,rs485-enabled-at-boot-time;
        uart-has-rtscts;
        status = "okay";
 
 &usbotg1 {
        dr_mode = "otg";
-       disable-over-current;
-       vbus-supply = <&reg_usb1_vbus>;
        status = "okay";
 };
 
        #size-cells = <0>;
        status = "okay";
 
+       /* VBUS is controlled by the hub */
+       /delete-property/ vbus-supply;
+
        usb1@1 {
-               compatible = "usb424,9514";
+               compatible = "usb424,2514";
                reg = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
 
                usbnet: ethernet@1 {
-                       compatible = "usb424,ec00";
+                       compatible = "usbb95,772b";
                        reg = <1>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                };
 };
 
 &usdhc2 {
-       pinctrl-names = "default", "state_100mhz", "state_200mhz";
-       pinctrl-0 = <&pinctrl_usdhc2>;
-       pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
-       pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
        vmmc-supply = <&reg_vdd_3v3>;
-       vqmmc-supply = <&reg_nvcc_sd>;
-       cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
 &iomuxc {
        pinctrl_can: cangrp {
                fsl,pins = <
-                       MX8MM_IOMUXC_SAI3_RXFS_GPIO4_IO28               0x19
-               >;
-       };
-
-       pinctrl_ecspi2: ecspi2grp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_ECSPI2_MISO_ECSPI2_MISO            0x82
-                       MX8MM_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI            0x82
-                       MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK            0x82
-                       MX8MM_IOMUXC_ECSPI2_SS0_GPIO5_IO13              0x19
-               >;
-       };
-
-       pinctrl_ecspi3: ecspi3grp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_UART2_RXD_ECSPI3_MISO              0x82
-                       MX8MM_IOMUXC_UART1_TXD_ECSPI3_MOSI              0x82
-                       MX8MM_IOMUXC_UART1_RXD_ECSPI3_SCLK              0x82
-                       MX8MM_IOMUXC_UART2_TXD_GPIO5_IO25               0x19
-               >;
-       };
-
-       pinctrl_enet: enetgrp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_ENET_MDC_ENET1_MDC                 0x3
-                       MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO               0x3
-                       MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3           0x1f
-                       MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2           0x1f
-                       MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1           0x1f
-                       MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0           0x1f
-                       MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3           0x91
-                       MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2           0x91
-                       MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1           0x91
-                       MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0           0x91
-                       MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC           0x1f
-                       MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC           0x91
-                       MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL     0x91
-                       MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL     0x1f
-                       MX8MM_IOMUXC_GPIO1_IO01_GPIO1_IO1               0x19 /* PHY RST */
-                       MX8MM_IOMUXC_GPIO1_IO05_GPIO1_IO5               0x19 /* ETH IRQ */
-               >;
-       };
-
-       pinctrl_gpio_led: gpioledgrp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12              0x19
-                       MX8MM_IOMUXC_GPIO1_IO13_GPIO1_IO13              0x19
-                       MX8MM_IOMUXC_GPIO1_IO14_GPIO1_IO14              0x19
-               >;
-       };
-
-       pinctrl_gpio1: gpio1grp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3               0x19
-                       MX8MM_IOMUXC_GPIO1_IO07_GPIO1_IO7               0x19
-                       MX8MM_IOMUXC_GPIO1_IO09_GPIO1_IO9               0x19
-                       MX8MM_IOMUXC_GPIO1_IO11_GPIO1_IO11              0x19
-                       MX8MM_IOMUXC_GPIO1_IO06_GPIO1_IO6               0x19
-                       MX8MM_IOMUXC_GPIO1_IO08_GPIO1_IO8               0x19
-                       MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10              0x19
-               >;
-       };
-
-       pinctrl_gpio5: gpio5grp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_SAI3_MCLK_GPIO5_IO2                0x19
-               >;
-       };
-
-       pinctrl_i2c4: i2c4grp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL                  0x400001c3
-                       MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA                  0x400001c3
-               >;
-       };
-
-       pinctrl_pwm2: pwm2grp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_SPDIF_RX_PWM2_OUT                  0x19
-               >;
-       };
-
-       pinctrl_reg_usb1_vbus: regusb1vbusgrp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_SAI5_MCLK_GPIO3_IO25               0x19
-               >;
-       };
-
-       pinctrl_uart1: uart1grp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX              0x140
-                       MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX             0x140
-                       MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B          0x140
-                       MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B          0x140
-               >;
-       };
-
-       pinctrl_uart2: uart2grp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX             0x140
-                       MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX              0x140
-                       MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B           0x140
-                       MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B           0x140
-               >;
-       };
-
-       pinctrl_usb_eth2: usbeth2grp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_NAND_CE1_B_GPIO3_IO2               0x19
-               >;
-       };
-
-       pinctrl_usdhc2: usdhc2grp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK                 0x190
-                       MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD                 0x1d0
-                       MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0             0x1d0
-                       MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1             0x1d0
-                       MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2             0x1d0
-                       MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3             0x1d0
-                       MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12                0x019
-                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0x1d0
-               >;
-       };
-
-       pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK                 0x194
-                       MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD                 0x1d4
-                       MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0             0x1d4
-                       MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1             0x1d4
-                       MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2             0x1d4
-                       MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3             0x1d4
-                       MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12                0x019
-                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0x1d0
+                       MX8MM_IOMUXC_SAI3_TXD_GPIO5_IO1                 0x19  /* SDIO_B_PWR_EN */
                >;
        };
 
-       pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+       pinctrl_usb_hub: usbhubgrp {
                fsl,pins = <
-                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK                 0x196
-                       MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD                 0x1d6
-                       MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0             0x1d6
-                       MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1             0x1d6
-                       MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2             0x1d6
-                       MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3             0x1d6
-                       MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12                0x019
-                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0x1d0
+                       MX8MM_IOMUXC_SAI3_MCLK_GPIO5_IO2                0x19 /* SDIO_B_WP */
                >;
        };
 };
index dcec57c20399edf6e457b5fbf4fbc2b9dd0370b1..aab8e24216501e154ea521abf83a2b2fbd8d9219 100644 (file)
 
        pinctrl_i2c4: i2c4grp {
                fsl,pins = <
-                       MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL                  0x400001c3
-                       MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA                  0x400001c3
+                       MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL                  0x40000083
+                       MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA                  0x40000083
                >;
        };
 
 
        pinctrl_uart1: uart1grp {
                fsl,pins = <
-                       MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX              0x140
-                       MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX             0x140
-                       MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B          0x140
-                       MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B          0x140
+                       MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX              0x0
+                       MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX             0x0
+                       MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B          0x0
+                       MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B          0x0
                >;
        };
 
        pinctrl_uart2: uart2grp {
                fsl,pins = <
-                       MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX             0x140
-                       MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX              0x140
-                       MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B           0x140
-                       MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B           0x140
+                       MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX             0x0
+                       MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX              0x0
+                       MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B           0x0
+                       MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B           0x0
                >;
        };
 
 
        pinctrl_usdhc2: usdhc2grp {
                fsl,pins = <
-                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK                 0x190
+                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK                 0x90
                        MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD                 0x1d0
                        MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0             0x1d0
                        MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1             0x1d0
                        MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2             0x1d0
                        MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3             0x1d0
-                       MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12                0x019
-                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0x1d0
+                       MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12                0x19
+                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0xd0
                >;
        };
 
        pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
                fsl,pins = <
-                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK                 0x194
+                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK                 0x94
                        MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD                 0x1d4
                        MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0             0x1d4
                        MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1             0x1d4
                        MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2             0x1d4
                        MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3             0x1d4
-                       MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12                0x019
-                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0x1d0
+                       MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12                0x19
+                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0xd0
                >;
        };
 
        pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
                fsl,pins = <
-                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK                 0x196
+                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK                 0x96
                        MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD                 0x1d6
                        MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0             0x1d6
                        MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1             0x1d6
                        MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2             0x1d6
                        MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3             0x1d6
-                       MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12                0x019
-                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0x1d0
+                       MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12                0x19
+                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0xd0
                >;
        };
 };
index 6e75ab879bf59c4a69ca7c4dccb0da98158d4f78..663ae52b48526e88dd71c8ca6081af6a97bcf462 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (C) 2022 Kontron Electronics GmbH
  */
 
+#include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include "imx8mm.dtsi"
 
        chosen {
                stdout-path = &uart3;
        };
+
+       reg_vdd_carrier: regulator-vdd-carrier {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_vdd_carrier>;
+               gpio = <&gpio3 16 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-name = "VDD_CARRIER";
+
+               regulator-state-standby {
+                       regulator-on-in-suspend;
+               };
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+
+               regulator-state-disk {
+                       regulator-off-in-suspend;
+               };
+       };
+
+       reg_usb1_vbus: regulator-usb1-vbus {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_usb1_vbus>;
+               enable-active-high;
+               gpio = <&gpio3 25 GPIO_ACTIVE_HIGH>;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-name = "VBUS_USB1";
+       };
+
+       reg_usb2_vbus: regulator-usb2-vbus {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_usb2_vbus>;
+               enable-active-high;
+               gpio = <&gpio3 20 GPIO_ACTIVE_HIGH>;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-name = "VBUS_USB2";
+       };
+
+       reg_usdhc2_vcc: regulator-usdhc2-vcc {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_usdhc2_vcc>;
+               enable-active-high;
+               gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-name = "VCC_SDIO_A";
+       };
+
+       reg_usdhc3_vcc: regulator-usdhc3-vcc {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_usdhc3_vcc>;
+               enable-active-high;
+               gpio = <&gpio5 1 GPIO_ACTIVE_HIGH>;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-name = "VCC_SDIO_B";
+       };
 };
 
 &A53_0 {
        };
 };
 
+&ecspi2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi2>, <&pinctrl_ecspi2_gpio>;
+       cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+};
+
+&ecspi3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi3>;
+       cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>;
+};
+
+&gpio1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpio1>;
+       gpio-line-names = "", "GPIO_A_0", "", "GPIO_A_1",
+                         "", "GPIO_A_2", "GPIO_A_3", "GPIO_A_4",
+                         "GPIO_A_5", "GPIO_A_6", "GPIO_A_7", "GPIO_B_0",
+                         "GPIO_B_1", "USB_A_OC#", "CAM_MCK", "USB_B_OC#",
+                         "ETH_MDC", "ETH_MDIO", "ETH_A_(S)(R)(G)MII_TXD3",
+                         "ETH_A_(S)(R)(G)MII_TXD2", "ETH_A_(S)(R)(G)MII_TXD1",
+                         "ETH_A_(S)(R)(G)MII_TXD0", "ETH_A_(R)(G)MII_TX_EN(_ER)",
+                         "ETH_A_(R)(G)MII_TX_CLK", "ETH_A_(R)(G)MII_RX_DV(_ER)",
+                         "ETH_A_(R)(G)MII_RX_CLK", "ETH_A_(S)(R)(G)MII_RXD0",
+                         "ETH_A_(S)(R)(G)MII_RXD1", "ETH_A_(R)(G)MII_RXD2",
+                         "ETH_A_(R)(G)MII_RXD3";
+};
+
+&gpio2 {
+       gpio-line-names = "", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "",
+                         "SDIO_A_CD#", "SDIO_A_CLK", "SDIO_A_CMD", "SDIO_A_D0",
+                         "SDIO_A_D1", "SDIO_A_D2", "SDIO_A_D3", "SDIO_A_PWR_EN",
+                         "SDIO_A_WP";
+};
+
+&gpio3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpio3>;
+       gpio-line-names = "GPIO_C_5", "GPIO_C_4", "SDIO_B_CD#", "SDIO_B_D5",
+                         "SDIO_B_D6", "SDIO_B_D7", "GPIO_C_0", "GPIO_C_1",
+                         "GPIO_C_2", "GPIO_C_3", "SDIO_B_D0", "SDIO_B_D1",
+                         "SDIO_B_D2", "SDIO_B_D3", "", "SDIO_B_D4",
+                         "CARRIER_PWR_EN", "SDIO_B_CLK", "SDIO_B_CMD", "GPIO_B_2",
+                         "USB_B_EN", "GPIO_B_3", "PCIe_CLKREQ#", "PCIe_A_PERST#",
+                         "PCIe_WAKE#", "USB_A_EN";
+};
+
+&gpio4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpio4>;
+       gpio-line-names = "GPIO_C_7", "", "I2S_A_DATA_IN", "I2S_B_DATA_IN",
+                         "GPIO_B_4", "BOOT_SEL0#", "BOOT_SEL1#", "",
+                         "", "", "I2S_LRCLK", "I2S_BITCLK",
+                         "I2S_A_DATA_OUT", "I2S_B_DATA_OUT", "GPIO_B_5", "GPIO_B_6",
+                         "GPIO_B_7", "SPI_A_/WP_(IO2)", "SPI_A_/HOLD_(IO3)", "GPIO_C_6",
+                         "I2S_MCLK", "UART_A_TX", "UART_A_RX", "UART_A_CTS",
+                         "UART_A_RTS", "", "", "",
+                         "PCIe_SM_ALERT", "UART_B_RTS", "UART_B_CTS", "UART_B_RX";
+};
+
+&gpio5 {
+       gpio-line-names = "UART_B_TX", "SDIO_B_PWR_EN", "SDIO_B_WP", "PWM_2",
+                         "PWM_1", "PWM_0", "", "",
+                         "", "", "SPI_A_SCK", "SPI_A_SDO_(IO1)",
+                         "SPI_A_SCK", "SPI_A_CS0#", "", "",
+                         "I2C_A_SCL", "I2C_A_SDA", "I2C_B_SCL", "I2C_B_SDA",
+                         "PCIe_SMCLK", "PCIe_SMDAT", "SPI_B_SCK", "SPI_B_SDO",
+                         "SPI_B_SDI", "SPI_B_CS0#", "UART_CON_RX", "UART_CON_TX",
+                         "UART_C_RX", "UART_C_TX";
+};
+
 &i2c1 {
        clock-frequency = <400000>;
        pinctrl-names = "default";
                };
        };
 
+       eeprom: eeprom@50 {
+               compatible = "atmel,24c64";
+               reg = <0x50>;
+               address-width = <16>;
+               pagesize = <32>;
+               size = <8192>;
+       };
+
        rv3028: rtc@52 {
                compatible = "microcrystal,rv3028";
                reg = <0x52>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_rtc>;
-               interrupts-extended = <&gpio4 1 IRQ_TYPE_LEVEL_HIGH>;
-               trickle-diode-disable;
+               interrupts-extended = <&gpio4 1 IRQ_TYPE_LEVEL_LOW>;
        };
 };
 
+&i2c2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c2>;
+};
+
+&i2c3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c3>;
+};
+
+&i2c4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_i2c4>;
+};
+
+&pwm1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm1>;
+};
+
+&pwm2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm2>;
+};
+
+&pwm3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm3>;
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+};
+
 &uart3 { /* console */
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart3>;
        status = "okay";
 };
 
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4>;
+};
+
+&usbotg1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usb1>;
+       vbus-supply = <&reg_usb1_vbus>;
+};
+
+&usbotg2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usb2>;
+       vbus-supply = <&reg_usb2_vbus>;
+};
+
 &usdhc1 {
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc1>;
        status = "okay";
 };
 
+&usdhc2 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+       pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+       pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+       vmmc-supply = <&reg_usdhc2_vcc>;
+       vqmmc-supply = <&reg_nvcc_sd>;
+       cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+};
+
+&usdhc3 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_gpio>;
+       pinctrl-1 = <&pinctrl_usdhc3_100mhz>, <&pinctrl_usdhc3_gpio>;
+       pinctrl-2 = <&pinctrl_usdhc3_200mhz>, <&pinctrl_usdhc3_gpio>;
+       vmmc-supply = <&reg_usdhc3_vcc>;
+       vqmmc-supply = <&reg_nvcc_sd>;
+       cd-gpios = <&gpio3 2 GPIO_ACTIVE_LOW>;
+};
+
 &wdog1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_wdog>;
 };
 
 &iomuxc {
+       pinctrl_csi_mck: csimckgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO14_CCMSRCGPCMIX_CLKO1      0x59 /* CAM_MCK */
+               >;
+       };
+
        pinctrl_ecspi1: ecspi1grp {
                fsl,pins = <
                        MX8MM_IOMUXC_ECSPI1_MISO_ECSPI1_MISO            0x82
                >;
        };
 
+       pinctrl_ecspi2: ecspi2grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_ECSPI2_MISO_ECSPI2_MISO            0x82 /* SPI_A_SDI_(IO0) */
+                       MX8MM_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI            0x82 /* SPI_A_SDO_(IO1) */
+                       MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK            0x82 /* SPI_A_SCK */
+                       MX8MM_IOMUXC_ECSPI2_SS0_GPIO5_IO13              0x19 /* SPI_A_CS0# */
+               >;
+       };
+
+       pinctrl_ecspi2_gpio: ecspi2gpiogrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI1_TXD5_GPIO4_IO17               0x19 /* SPI_A_/WP_(IO2) */
+                       MX8MM_IOMUXC_SAI1_TXD6_GPIO4_IO18               0x19 /* SPI_A_/HOLD_(IO3) */
+               >;
+       };
+
+       pinctrl_ecspi3: ecspi3grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_UART2_RXD_ECSPI3_MISO              0x82 /* SPI_B_SDI */
+                       MX8MM_IOMUXC_UART1_TXD_ECSPI3_MOSI              0x82 /* SPI_B_SDO */
+                       MX8MM_IOMUXC_UART1_RXD_ECSPI3_SCLK              0x82 /* SPI_B_SCK */
+                       MX8MM_IOMUXC_UART2_TXD_GPIO5_IO25               0x19 /* SPI_B_CS0# */
+               >;
+       };
+
+       pinctrl_enet_rgmii: enetrgmiigrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_ENET_MDC_ENET1_MDC                 0x03 /* ETH_MDC */
+                       MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO               0x03 /* ETH_MDIO */
+                       MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3           0x1f /* ETH_A_(S)(R)(G)MII_TXD3 */
+                       MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2           0x1f /* ETH_A_(S)(R)(G)MII_TXD2 */
+                       MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1           0x1f /* ETH_A_(S)(R)(G)MII_TXD1 */
+                       MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0           0x1f /* ETH_A_(S)(R)(G)MII_TXD0 */
+                       MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3           0x91 /* ETH_A_(R)(G)MII_RXD3 */
+                       MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2           0x91 /* ETH_A_(R)(G)MII_RXD2 */
+                       MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1           0x91 /* ETH_A_(S)(R)(G)MII_RXD1 */
+                       MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0           0x91 /* ETH_A_(S)(R)(G)MII_RXD0 */
+                       MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC           0x1f /* ETH_A_(R)(G)MII_TX_CLK */
+                       MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC           0x91 /* ETH_A_(R)(G)MII_RX_CLK */
+                       MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL     0x91 /* ETH_A_(R)(G)MII_RX_DV(_ER) */
+                       MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL     0x1f /* ETH_A_(R)(G)MII_TX_EN(_ER) */
+               >;
+       };
+
+       pinctrl_enet_rmii: enetrmiigrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_ENET_MDC_ENET1_MDC                 0x03 /* ETH_MDC */
+                       MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO               0x03 /* ETH_MDIO */
+                       MX8MM_IOMUXC_ENET_TD2_ENET1_TX_CLK              0x4000001f /* ETH_A_(S)(R)(G)MII_TXD2 */
+                       MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1           0x56 /* ETH_A_(S)(R)(G)MII_TXD1 */
+                       MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0           0x56 /* ETH_A_(S)(R)(G)MII_TXD0 */
+                       MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1           0x56 /* ETH_A_(S)(R)(G)MII_RXD1 */
+                       MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0           0x56 /* ETH_A_(S)(R)(G)MII_RXD0 */
+                       MX8MM_IOMUXC_ENET_RXC_ENET1_RX_ER               0x56 /* ETH_A_(R)(G)MII_RX_CLK */
+                       MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL     0x56 /* ETH_A_(R)(G)MII_RX_DV(_ER) */
+                       MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL     0x56 /* ETH_A_(R)(G)MII_TX_EN(_ER) */
+               >;
+       };
+
+       pinctrl_gpio1: gpio1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO01_GPIO1_IO1               0x19 /* GPIO_A_0 */
+                       MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3               0x19 /* GPIO_A_1 */
+                       MX8MM_IOMUXC_GPIO1_IO05_GPIO1_IO5               0x19 /* GPIO_A_2 */
+                       MX8MM_IOMUXC_GPIO1_IO06_GPIO1_IO6               0x19 /* GPIO_A_3 */
+                       MX8MM_IOMUXC_GPIO1_IO07_GPIO1_IO7               0x19 /* GPIO_A_4 */
+                       MX8MM_IOMUXC_GPIO1_IO08_GPIO1_IO8               0x19 /* GPIO_A_5 */
+                       MX8MM_IOMUXC_GPIO1_IO09_GPIO1_IO9               0x19 /* GPIO_A_6 */
+                       MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10              0x19 /* GPIO_A_7 */
+                       MX8MM_IOMUXC_GPIO1_IO11_GPIO1_IO11              0x19 /* GPIO_B_0 */
+                       MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12              0x19 /* GPIO_B_1 */
+               >;
+       };
+
+       pinctrl_gpio3: gpio3grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_ALE_GPIO3_IO0                 0x19 /* GPIO_C_5 */
+                       MX8MM_IOMUXC_NAND_CE0_B_GPIO3_IO1               0x19 /* GPIO_C_4 */
+                       MX8MM_IOMUXC_NAND_DATA00_GPIO3_IO6              0x19 /* GPIO_C_0 */
+                       MX8MM_IOMUXC_NAND_DATA01_GPIO3_IO7              0x19 /* GPIO_C_1 */
+                       MX8MM_IOMUXC_NAND_DATA02_GPIO3_IO8              0x19 /* GPIO_C_2 */
+                       MX8MM_IOMUXC_NAND_DATA03_GPIO3_IO9              0x19 /* GPIO_C_3 */
+                       MX8MM_IOMUXC_SAI5_RXFS_GPIO3_IO19               0x19 /* GPIO_B_2 */
+                       MX8MM_IOMUXC_SAI5_RXD0_GPIO3_IO21               0x19 /* GPIO_B_3 */
+               >;
+       };
+
+       pinctrl_gpio4: gpio4grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI1_RXFS_GPIO4_IO0                0x19 /* GPIO_C_7 */
+                       MX8MM_IOMUXC_SAI1_RXD2_GPIO4_IO4                0x19 /* GPIO_B_4 */
+                       MX8MM_IOMUXC_SAI1_RXD3_GPIO4_IO5                0x19 /* BOOT_SEL0# */
+                       MX8MM_IOMUXC_SAI1_RXD4_GPIO4_IO6                0x19 /* BOOT_SEL1# */
+                       MX8MM_IOMUXC_SAI1_TXD2_GPIO4_IO14               0x19 /* GPIO_B_5 */
+                       MX8MM_IOMUXC_SAI1_TXD3_GPIO4_IO15               0x19 /* GPIO_B_6 */
+                       MX8MM_IOMUXC_SAI1_TXD4_GPIO4_IO16               0x19 /* GPIO_B_7 */
+                       MX8MM_IOMUXC_SAI1_TXD7_GPIO4_IO19               0x19 /* GPIO_C_6 */
+               >;
+       };
+
        pinctrl_i2c1: i2c1grp {
                fsl,pins = <
-                       MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL                  0x400001c3
-                       MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA                  0x400001c3
+                       MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL                  0x40000083
+                       MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA                  0x40000083
+               >;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL                  0x40000083 /* I2C_A_SCL */
+                       MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA                  0x40000083 /* I2C_A_SDA */
+               >;
+       };
+
+       pinctrl_i2c3: i2c3grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL                  0x40000083 /* I2C_B_SCL */
+                       MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA                  0x40000083 /* I2C_B_SDA */
+               >;
+       };
+
+       pinctrl_i2c4: i2c4grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL                  0x40000083 /* PCIe_SMCLK and I2C_CAM_SCL/CSI_TX_P */
+                       MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA                  0x40000083 /* PCIe_SMDAT and I2C_CAM_SDA/CSI_TX_N */
+               >;
+       };
+
+       pinctrl_pcie: pciegrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI5_RXD1_GPIO3_IO22               0x19 /* PCIe_CLKREQ# */
+                       MX8MM_IOMUXC_SAI5_RXD2_GPIO3_IO23               0x19 /* PCIe_A_PERST# */
+                       MX8MM_IOMUXC_SAI5_RXD3_GPIO3_IO24               0x19 /* PCIe_WAKE# */
+                       MX8MM_IOMUXC_SAI3_RXFS_GPIO4_IO28               0x19 /* PCIe_SM_ALERT */
                >;
        };
 
                >;
        };
 
+       pinctrl_pwm1: pwm1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SPDIF_EXT_CLK_PWM1_OUT             0x19 /* PWM_0 */
+               >;
+       };
+
+       pinctrl_pwm2: pwm2grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SPDIF_RX_PWM2_OUT                  0x19 /* PWM_1 */
+               >;
+       };
+
+       pinctrl_pwm3: pwm3grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SPDIF_TX_PWM3_OUT                  0x19 /* PWM_2 */
+               >;
+       };
+
+       pinctrl_reg_usb1_vbus: regusb1vbusgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI5_MCLK_GPIO3_IO25               0x19 /* USB_A_EN */
+               >;
+       };
+
+       pinctrl_reg_usb2_vbus: regusb2vbusgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI5_RXC_GPIO3_IO20                0x19 /* USB_B_EN */
+               >;
+       };
+
+       pinctrl_reg_usdhc2_vcc: regusdhc2vccgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19             0x19 /* SDIO_A_PWR_EN */
+               >;
+       };
+
+       pinctrl_reg_usdhc3_vcc: regusdhc3vccgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI3_TXD_GPIO5_IO1                 0x19 /* SDIO_B_PWR_EN */
+               >;
+       };
+
+       pinctrl_reg_vdd_carrier: regvddcarriergrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_READY_B_GPIO3_IO16            0x19 /* CARRIER_PWR_EN */
+               >;
+       };
+
        pinctrl_rtc: rtcgrp {
                fsl,pins = <
                        MX8MM_IOMUXC_SAI1_RXC_GPIO4_IO1                 0x19
                >;
        };
 
+       pinctrl_sai1: sai1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI1_RXD0_SAI1_RX_DATA0            0xd6 /* I2S_A_DATA_IN */
+                       MX8MM_IOMUXC_SAI1_TXD0_SAI1_TX_DATA0            0xd6 /* I2S_A_DATA_OUT */
+                       MX8MM_IOMUXC_SAI1_RXD1_SAI1_RX_DATA1            0xd6 /* I2S_B_DATA_IN */
+                       MX8MM_IOMUXC_SAI1_TXD1_SAI1_TX_DATA1            0xd6 /* I2S_B_DATA_OUT */
+                       MX8MM_IOMUXC_SAI1_MCLK_SAI1_MCLK                0xd6 /* I2S_MCLK */
+                       MX8MM_IOMUXC_SAI1_TXFS_SAI1_TX_SYNC             0xd6 /* I2S_LRCLK */
+                       MX8MM_IOMUXC_SAI1_TXC_SAI1_TX_BCLK              0xd6 /* I2S_BITCLK */
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX              0x0 /* UART_A_RX */
+                       MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX             0x0 /* UART_A_TX */
+                       MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B          0x0 /* UART_A_CTS */
+                       MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B          0x0 /* UART_A_RTS */
+               >;
+       };
+
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX             0x0 /* UART_B_RX */
+                       MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX              0x0 /* UART_B_TX */
+                       MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B           0x0 /* UART_B_CTS */
+                       MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B           0x0 /* UART_B_RTS */
+               >;
+       };
+
        pinctrl_uart3: uart3grp {
                fsl,pins = <
-                       MX8MM_IOMUXC_UART3_RXD_UART3_DCE_RX             0x140
-                       MX8MM_IOMUXC_UART3_TXD_UART3_DCE_TX             0x140
+                       MX8MM_IOMUXC_UART3_RXD_UART3_DCE_RX             0x140 /* UART_CON_RX */
+                       MX8MM_IOMUXC_UART3_TXD_UART3_DCE_TX             0x140 /* UART_CON_TX */
+               >;
+       };
+
+       pinctrl_uart4: uart4grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_UART4_RXD_UART4_DCE_RX             0x0 /* UART_C_RX */
+                       MX8MM_IOMUXC_UART4_TXD_UART4_DCE_TX             0x0 /* UART_C_TX */
+               >;
+       };
+
+       pinctrl_usb1: usb1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO13_USB1_OTG_OC             0x19 /* USB_A_OC# */
+               >;
+       };
+
+       pinctrl_usb2: usb2grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO15_USB2_OTG_OC             0x19 /* USB_B_OC# */
                >;
        };
 
                >;
        };
 
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK                 0x90 /* SDIO_A_CLK */
+                       MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD                 0x1d0 /* SDIO_A_CMD */
+                       MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0             0x1d0 /* SDIO_A_D0 */
+                       MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1             0x1d0 /* SDIO_A_D1 */
+                       MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2             0x1d0 /* SDIO_A_D2 */
+                       MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3             0x1d0 /* SDIO_A_D3 */
+                       MX8MM_IOMUXC_SD2_WP_USDHC2_WP                   0x400000d6 /* SDIO_A_WP */
+                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0x90
+               >;
+       };
+
+       pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK                 0x94 /* SDIO_A_CLK */
+                       MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD                 0x1d4 /* SDIO_A_CMD */
+                       MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0             0x1d4 /* SDIO_A_D0 */
+                       MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1             0x1d4 /* SDIO_A_D1 */
+                       MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2             0x1d4 /* SDIO_A_D2 */
+                       MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3             0x1d4 /* SDIO_A_D3 */
+                       MX8MM_IOMUXC_SD2_WP_USDHC2_WP                   0x400000d6 /* SDIO_A_WP */
+                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0x90
+               >;
+       };
+
+       pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK                 0x96 /* SDIO_A_CLK */
+                       MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD                 0x1d6 /* SDIO_A_CMD */
+                       MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0             0x1d6 /* SDIO_A_D0 */
+                       MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1             0x1d6 /* SDIO_A_D1 */
+                       MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2             0x1d6 /* SDIO_A_D2 */
+                       MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3             0x1d6 /* SDIO_A_D3 */
+                       MX8MM_IOMUXC_SD2_WP_USDHC2_WP                   0x400000d6 /* SDIO_A_WP */
+                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT          0x90
+               >;
+       };
+
+       pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12                0x19 /* SDIO_A_CD# */
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK               0x90 /* SDIO_B_CLK */
+                       MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD               0x90 /* SDIO_B_CMD */
+                       MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x90 /* SDIO_B_D0 */
+                       MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x90 /* SDIO_B_D1 */
+                       MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x90 /* SDIO_B_D2 */
+                       MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x90 /* SDIO_B_D3 */
+                       MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x90 /* SDIO_B_D4 */
+                       MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x90 /* SDIO_B_D5 */
+                       MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x90 /* SDIO_B_D6 */
+                       MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7              0x90 /* SDIO_B_D7 */
+               >;
+       };
+
+       pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK               0x94 /* SDIO_B_CLK */
+                       MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD               0x94 /* SDIO_B_CMD */
+                       MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x94 /* SDIO_B_D0 */
+                       MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x94 /* SDIO_B_D1 */
+                       MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x94 /* SDIO_B_D2 */
+                       MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x94 /* SDIO_B_D3 */
+                       MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x94 /* SDIO_B_D4 */
+                       MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x94 /* SDIO_B_D5 */
+                       MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x94 /* SDIO_B_D6 */
+                       MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7              0x94 /* SDIO_B_D7 */
+               >;
+       };
+
+       pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK               0x96 /* SDIO_B_CLK */
+                       MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD               0x96 /* SDIO_B_CMD */
+                       MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x96 /* SDIO_B_D0 */
+                       MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x96 /* SDIO_B_D1 */
+                       MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x96 /* SDIO_B_D2 */
+                       MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x96 /* SDIO_B_D3 */
+                       MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x96 /* SDIO_B_D4 */
+                       MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x96 /* SDIO_B_D5 */
+                       MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x96 /* SDIO_B_D6 */
+                       MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7              0x96 /* SDIO_B_D7 */
+               >;
+       };
+
+       pinctrl_usdhc3_gpio: usdhc3gpiogrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_CE1_B_GPIO3_IO2               0x19 /* SDIO_B_CD# */
+                       MX8MM_IOMUXC_SAI3_MCLK_GPIO5_IO2                0x19 /* SDIO_B_WP */
+               >;
+       };
+
        pinctrl_wdog: wdoggrp {
                fsl,pins = <
                        MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B            0xc6
index 1f8326613ee9e35fb3532c07b9b922585be3aad4..2076148e08627a167b3b34d886ec5456bb5e18eb 100644 (file)
 
        pinctrl_i2c1: i2c1grp {
                fsl,pins = <
-                       MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL                  0x400001c3
-                       MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA                  0x400001c3
+                       MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL                  0x40000083
+                       MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA                  0x40000083
                >;
        };
 
index ea6e8b85169f75c3dfefb45956976a1a713610de..01b632b220dc7411d300bc5a44e922da9802affc 100644 (file)
@@ -5,6 +5,8 @@
 
 /dts-v1/;
 
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+
 #include "imx8mm-tqma8mqml.dtsi"
 #include "mba8mx.dtsi"
 
 };
 
 &pcie_phy {
-       clocks = <&pcie0_refclk>;
+       fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_INPUT>;
+       fsl,clkreq-unsupported;
+       clocks = <&pcieclk 2>;
+       clock-names = "ref";
        status = "okay";
 };
 
+/* PCIe slot on X36 */
 &pcie0 {
        reset-gpio = <&expander0 14 GPIO_ACTIVE_LOW>;
-       clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>, <&pcie0_refclk>,
+       clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>, <&pcieclk 3>,
                 <&clk IMX8MM_CLK_PCIE1_AUX>;
        assigned-clocks = <&clk IMX8MM_CLK_PCIE1_AUX>,
-                               <&clk IMX8MM_CLK_PCIE1_CTRL>;
+                         <&clk IMX8MM_CLK_PCIE1_CTRL>;
        assigned-clock-rates = <10000000>, <250000000>;
        assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_50M>,
-                               <&clk IMX8MM_SYS_PLL2_250M>;
+                                <&clk IMX8MM_SYS_PLL2_250M>;
        status = "okay";
 };
 
index 6425773f68e0a2344e98c62c1b75f215f9f32775..41c966147b9454d49502c351978b1992af2affbf 100644 (file)
                gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
                status = "okay";
        };
-
-       reg_usb_otg1_vbus: regulator-usb-otg1 {
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_reg_usb1_en>;
-               compatible = "regulator-fixed";
-               regulator-name = "usb_otg1_vbus";
-               gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>;
-               enable-active-high;
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-       };
 };
 
-/* off-board header */
 &ecspi2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_spi2>;
-       cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+       cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>,
+                  <&gpio1 10 GPIO_ACTIVE_LOW>;
        status = "okay";
+
+       tpm@1 {
+               compatible = "tcg,tpm_tis-spi";
+               reg = <0x1>;
+               spi-max-frequency = <36000000>;
+       };
 };
 
 &gpio1 {
 };
 
 &usbotg1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg1>;
        dr_mode = "otg";
        over-current-active-low;
-       vbus-supply = <&reg_usb_otg1_vbus>;
        status = "okay";
 };
 
                >;
        };
 
-       pinctrl_reg_usb1_en: regusb1grp {
-               fsl,pins = <
-                       MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10      0x41
-                       MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12      0x141
-                       MX8MM_IOMUXC_GPIO1_IO13_USB1_OTG_OC     0x41
-               >;
-       };
-
        pinctrl_spi2: spi2grp {
                fsl,pins = <
                        MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK    0xd6
                        MX8MM_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI    0xd6
                        MX8MM_IOMUXC_ECSPI2_MISO_ECSPI2_MISO    0xd6
                        MX8MM_IOMUXC_ECSPI2_SS0_GPIO5_IO13      0xd6
+                       MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10      0xd6
                >;
        };
 
                        MX8MM_IOMUXC_UART3_TXD_UART3_DCE_TX     0x140
                >;
        };
+
+       pinctrl_usbotg1: usbotg1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12      0x141
+                       MX8MM_IOMUXC_GPIO1_IO13_USB1_OTG_OC     0x41
+               >;
+       };
 };
index 87b80e2412cb4f960540394994f219409331f620..5e2cbaf27e0fc8dd44351e9426fb9df56ee52354 100644 (file)
 &ecspi1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_spi1>;
-       cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+       cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>,
+                  <&gpio4 24 GPIO_ACTIVE_LOW>;
        status = "okay";
 
        flash@0 {
                spi-max-frequency = <40000000>;
                status = "okay";
        };
+
+       tpm@1 {
+               compatible = "tcg,tpm_tis-spi";
+               reg = <0x1>;
+               spi-max-frequency = <36000000>;
+       };
 };
 
 &fec1 {
 
 &gpio4 {
        gpio-line-names = "", "", "", "",
-               "", "", "uart3_rs232#", "uart3_rs422#",
+               "dig1_ctl", "dig2_ctl", "uart3_rs232#", "uart3_rs422#",
                "uart3_rs485#", "", "", "", "", "", "", "",
                "", "", "", "", "", "", "", "",
                "", "", "", "uart4_rs485#", "", "sim1det#", "sim2det#", "";
 
        pinctrl_hog: hoggrp {
                fsl,pins = <
+                       MX8MM_IOMUXC_SAI1_RXD2_GPIO4_IO4        0x40000041 /* DIG1_CTL */
+                       MX8MM_IOMUXC_SAI1_RXD3_GPIO4_IO5        0x40000041 /* DIG2_CTL */
                        MX8MM_IOMUXC_SPDIF_TX_GPIO5_IO3         0x40000041 /* DIG2_OUT */
                        MX8MM_IOMUXC_SPDIF_RX_GPIO5_IO4         0x40000041 /* DIG2_IN */
                        MX8MM_IOMUXC_GPIO1_IO06_GPIO1_IO6       0x40000041 /* DIG1_IN */
                        MX8MM_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI    0x82
                        MX8MM_IOMUXC_ECSPI1_MISO_ECSPI1_MISO    0x82
                        MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9       0x140
+                       MX8MM_IOMUXC_SAI2_TXFS_GPIO4_IO24       0x140
                >;
        };
 
index 35b8d2060cd99aa95ef9dd13c0eca5eb3ebc159b..bbd80896db9648bfdeb56a9e502b9c8d20c4e0b7 100644 (file)
@@ -99,8 +99,6 @@
 };
 
 &lcdif {
-       assigned-clocks = <&clk IMX8MN_VIDEO_PLL1>;
-       assigned-clock-rates = <594000000>;
        status = "okay";
 };
 
index a0e13d3324ed1211720a2bae9a8b9bd242bd1727..269e70f66a1331da780422dd6d3eb1402560d3c8 100644 (file)
                spdif-out;
                spdif-in;
        };
+
+       sound-micfil {
+               compatible = "fsl,imx-audio-card";
+               model = "micfil-audio";
+
+               pri-dai-link {
+                       link-name = "micfil hifi";
+                       format = "i2s";
+
+                       cpu {
+                               sound-dai = <&micfil>;
+                       };
+               };
+       };
 };
 
 &easrc {
        status = "okay";
 };
 
+&micfil {
+       #sound-dai-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pdm>;
+       assigned-clocks = <&clk IMX8MN_CLK_PDM>;
+       assigned-clock-parents = <&clk IMX8MN_AUDIO_PLL1_OUT>;
+       assigned-clock-rates = <196608000>;
+       status = "okay";
+};
+
 &mipi_csi {
        status = "okay";
 
                >;
        };
 
+       pinctrl_pdm: pdmgrp {
+               fsl,pins = <
+                       MX8MN_IOMUXC_SAI5_MCLK_SAI5_MCLK        0xd6
+                       MX8MN_IOMUXC_SAI5_RXC_PDM_CLK           0xd6
+                       MX8MN_IOMUXC_SAI5_RXFS_SAI5_RX_SYNC     0xd6
+                       MX8MN_IOMUXC_SAI5_RXD0_PDM_BIT_STREAM0  0xd6
+                       MX8MN_IOMUXC_SAI5_RXD1_PDM_BIT_STREAM1  0xd6
+                       MX8MN_IOMUXC_SAI5_RXD2_PDM_BIT_STREAM2  0xd6
+                       MX8MN_IOMUXC_SAI5_RXD3_PDM_BIT_STREAM3  0xd6
+               >;
+       };
+
        pinctrl_pmic: pmicirqgrp {
                fsl,pins = <
                        MX8MN_IOMUXC_GPIO1_IO03_GPIO1_IO3       0x141
index 1b633bd1ebb6695388a0406269d0d2e876383643..ea1855171fb03c23a4b60ca2c23682f37cf471d9 100644 (file)
@@ -10,7 +10,7 @@
 
 / {
        model = "RVE gateway";
-       compatible = "rve,rve-gateway", "variscite,var-som-mx8mn", "fsl,imx8mn";
+       compatible = "rve,gateway", "variscite,var-som-mx8mn", "fsl,imx8mn";
 
        crystal_duart_24m: crystal-duart-24m {
                compatible = "fixed-clock";
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx-usbotg.dtso b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx-usbotg.dtso
new file mode 100644 (file)
index 0000000..96db07f
--- /dev/null
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2022-2024 TQ-Systems GmbH <linux@ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Alexander Stein
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "imx8mn-pinfunc.h"
+
+&{/} {
+       connector {
+               compatible = "gpio-usb-b-connector", "usb-b-connector";
+               type = "micro";
+               label = "X19";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usb1_connector>;
+               id-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
+
+               port {
+                       usb_dr_connector: endpoint {
+                               remote-endpoint = <&usb1_drd_sw>;
+                       };
+               };
+       };
+};
+
+&rst_usb_hub_hog {
+       output-low;
+};
+
+&sel_usb_hub_hog {
+       output-low;
+};
+
+&usbotg1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg>;
+       dr_mode = "otg";
+       srp-disable;
+       hnp-disable;
+       adp-disable;
+       power-active-high;
+       /delete-property/ disable-over-current;
+       over-current-active-low;
+       usb-role-switch;
+       status = "okay";
+
+       port {
+               usb1_drd_sw: endpoint {
+                       remote-endpoint = <&usb_dr_connector>;
+               };
+       };
+};
+
+&iomuxc {
+       pinctrl_usb1_connector: usb1-connectorgrp {
+               fsl,pins = <MX8MN_IOMUXC_GPIO1_IO10_GPIO1_IO10          0x1c0>;
+       };
+};
index c07d59147ab55956267c2572d4a49b853c1f3990..433d8bba44255e3c87384416a1533d3f15650c9e 100644 (file)
@@ -41,7 +41,7 @@
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usb0hub_sel>;
 
-       sel-usb-hub-hog {
+       sel_usb_hub_hog: sel-usb-hub-hog {
                gpio-hog;
                gpios = <1 GPIO_ACTIVE_HIGH>;
                output-high;
 
        pinctrl_usbotg: usbotggrp {
                fsl,pins = <MX8MN_IOMUXC_GPIO1_IO12_USB1_OTG_PWR        0x84>,
-                          <MX8MN_IOMUXC_GPIO1_IO13_USB1_OTG_OC         0x84>,
-                          <MX8MN_IOMUXC_GPIO1_IO10_USB1_OTG_ID         0x1C4>;
+                          <MX8MN_IOMUXC_GPIO1_IO13_USB1_OTG_OC         0x84>;
        };
 
        pinctrl_usdhc2: usdhc2grp {
index f38ee2266b25dd811e1a8f29c7380aed337a1337..a6b94d1957c92ac6bcc18667b477ca05eda8b1bc 100644 (file)
                pinctrl-0 = <&pinctrl_ptn5150>;
                status = "okay";
 
-               connector {
-                       compatible = "usb-c-connector";
-                       label = "USB-C";
-
-                       port {
-                               typec1_dr_sw: endpoint {
-                                       remote-endpoint = <&usb1_drd_sw>;
-                               };
+               port {
+                       typec1_dr_sw: endpoint {
+                               remote-endpoint = <&usb1_drd_sw>;
                        };
                };
        };
index 136e75c51251a60c7a7f831d7e987ea27241f6a4..932c8b05c75fc06ea394bcdc0f8fbe049dade17d 100644 (file)
                                                         <&clk IMX8MN_SYS_PLL1_800M>;
                                assigned-clock-rates = <266000000>,
                                                       <24000000>,
-                                                      <594000000>,
+                                                      <24000000>,
                                                       <500000000>,
                                                       <200000000>;
                                #power-domain-cells = <1>;
index e5da9080478084da704a76198fa50b0feeeab79b..8be251b6937891bfbd38ebdb14f38f4bbdb87b26 100644 (file)
@@ -50,6 +50,8 @@
        phy-mode = "rgmii-id";
        phy-handle = <&ethphy0>;
        snps,force_thresh_dma_mode;
+       snps,mtl-rx-config = <&mtl_rx_setup>;
+       snps,mtl-tx-config = <&mtl_tx_setup>;
        status = "okay";
 
        mdio {
                        interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
                };
        };
+
+       mtl_rx_setup: rx-queues-config {
+               snps,rx-queues-to-use = <5>;
+               snps,rx-sched-sp;
+
+               queue0 {
+                       snps,dcb-algorithm;
+                       snps,priority = <0x1>;
+                       snps,map-to-dma-channel = <0>;
+               };
+
+               queue1 {
+                       snps,dcb-algorithm;
+                       snps,priority = <0x2>;
+                       snps,map-to-dma-channel = <1>;
+               };
+
+               queue2 {
+                       snps,dcb-algorithm;
+                       snps,priority = <0x4>;
+                       snps,map-to-dma-channel = <2>;
+               };
+
+               queue3 {
+                       snps,dcb-algorithm;
+                       snps,priority = <0x8>;
+                       snps,map-to-dma-channel = <3>;
+               };
+
+               queue4 {
+                       snps,dcb-algorithm;
+                       snps,priority = <0xf0>;
+                       snps,map-to-dma-channel = <4>;
+               };
+       };
+
+       mtl_tx_setup: tx-queues-config {
+               snps,tx-queues-to-use = <5>;
+               snps,tx-sched-sp;
+
+               queue0 {
+                       snps,dcb-algorithm;
+                       snps,priority = <0x1>;
+               };
+
+               queue1 {
+                       snps,dcb-algorithm;
+                       snps,priority = <0x2>;
+               };
+
+               queue2 {
+                       snps,dcb-algorithm;
+                       snps,priority = <0x4>;
+               };
+
+               queue3 {
+                       snps,dcb-algorithm;
+                       snps,priority = <0x8>;
+               };
+
+               queue4 {
+                       snps,dcb-algorithm;
+                       snps,priority = <0xf0>;
+               };
+       };
 };
 
 &flexspi {
        assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
        uart-has-rtscts;
        status = "okay";
+
+       bluetooth {
+               compatible = "nxp,88w8997-bt";
+       };
 };
 
 &usdhc1 {
index d98a040860a48a3ff2c6592420853a0dacc9b48a..7e1b58dbe23a7f2d1e17dfb32a9ce4650356e959 100644 (file)
@@ -6,6 +6,7 @@
 /dts-v1/;
 
 #include <dt-bindings/net/qca-ar803x.h>
+#include <dt-bindings/phy/phy-imx8-pcie.h>
 #include "imx8mp.dtsi"
 
 / {
                clock-frequency = <25000000>;
        };
 
+       clk_pwm4: clock-pwm4 {
+               compatible = "pwm-clock";
+               #clock-cells = <0>;
+               clock-frequency = <12000000>;
+               clock-output-names = "codec-pwm4";
+               /*
+                * 1 / 83 ns ~= 12 MHz , but since the PWM input clock is 24 MHz
+                * and the calculated PWM period is 1 and duty cycle is 50%, the
+                * result is exactly 12 MHz, which is fine for SGTL5000 MCLK.
+                */
+               pwms = <&pwm4 0 83 0>;
+       };
+
        panel: panel {
                /* Compatible string is filled in by panel board DT Overlay. */
                backlight = <&backlight>;
                vin-supply = <&buck4>;
        };
 
+       sound {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "SGTL5000-Card";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,bitclock-master = <&codec_dai>;
+               simple-audio-card,frame-master = <&codec_dai>;
+               simple-audio-card,widgets = "Headphone", "Headphone Jack";
+               simple-audio-card,routing = "Headphone Jack", "HP_OUT";
+
+               cpu_dai: simple-audio-card,cpu {
+                       sound-dai = <&sai3>;
+               };
+
+               codec_dai: simple-audio-card,codec {
+                       sound-dai = <&sgtl5000>;
+               };
+       };
+
        watchdog { /* TPS3813 */
                compatible = "linux,wdt-gpio";
                pinctrl-names = "default";
        flash@0 {       /* W25Q128JVEI */
                compatible = "jedec,spi-nor";
                reg = <0>;
-               spi-max-frequency = <100000000>;        /* Up to 133 MHz */
+               spi-max-frequency = <40000000>;
                spi-tx-bus-width = <1>;
                spi-rx-bus-width = <1>;
        };
        sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        status = "okay";
 
+       sgtl5000: audio-codec@a {
+               compatible = "fsl,sgtl5000";
+               reg = <0x0a>;
+               #sound-dai-cells = <0>;
+               clocks = <&clk_pwm4>;
+               VDDA-supply = <&buck4>;
+               VDDIO-supply = <&buck4>;
+       };
+
        usb-hub@2c {
                compatible = "microchip,usb2514bi";
                reg = <0x2c>;
        status = "okay";
 };
 
+&pcie_phy {
+       clocks = <&pcieclk 0>;
+       clock-names = "ref";
+       fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_INPUT>;
+       status = "okay";
+};
+
+&pcie {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie0>;
+       fsl,max-link-speed = <3>;
+       reset-gpio = <&gpio1 5 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
 &pwm1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_panel_pwm>;
        status = "disabled";
 };
 
+&pwm4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm4>;
+       status = "okay";
+};
+
+&sai3 {
+       #clock-cells = <0>;
+       #sound-dai-cells = <0>;
+       assigned-clocks = <&clk IMX8MP_CLK_SAI3>;
+       assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>;
+       assigned-clock-rates = <12288000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sai3>;
+       status = "okay";
+};
+
 /* SD slot */
 &usdhc2 {
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
 &uart4 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart4>;
-       status = "okay";
+       status = "disabled";
 };
 
 &usb3_phy0 {
                >;
        };
 
+       pinctrl_pwm4: pwm4-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SAI3_MCLK__PWM4_OUT                0xd6
+               >;
+       };
+
        pinctrl_rtc: rtc-grp {
                fsl,pins = <
                        /* RTC_IRQ# */
                        MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC   0xd6
                        MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SAI3_TX_DATA00  0xd6
                        MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_SAI3_TX_BCLK    0xd6
-                       MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SAI3_MCLK      0xd6
                        MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_SAI3_RX_DATA00  0xd6
                >;
        };
index fea67a9282f033121323ef2c86e200deac9463d4..b749e28e5ede5cf85f309f2f7903ebee44b41f98 100644 (file)
                                pinctrl-names = "default";
                                pinctrl-0 = <&pinctrl_ptn5150>;
 
-                               connector {
-                                       compatible = "usb-c-connector";
-                                       label = "USB-C";
-
-                                       port {
-                                               ptn5150_out_ep: endpoint {
-                                                       remote-endpoint = <&dwc3_0_ep>;
-                                               };
+                               port {
+
+                                       ptn5150_out_ep: endpoint {
+                                               remote-endpoint = <&dwc3_0_ep>;
                                        };
                                };
                        };
index 4ae4fdab461e008d4816816eedb90f91e7d32561..43f1d45ccc96f01686534d228de9b69630db3ebb 100644 (file)
                                  <&clk IMX8MP_AUDIO_PLL2_OUT>;
                assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL2_OUT>;
                assigned-clock-rates = <13000000>, <13000000>, <156000000>;
-               reset-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&gpio1 GPIO_ACTIVE_HIGH>;
                status = "disabled";
 
                ports {
index f87fa5a948ccc380c473778e9f0b61c68a0b7e7c..9beba8d6a0dfe4b1ec51015e0f1c12ebca2d8f1c 100644 (file)
@@ -23,7 +23,7 @@
 
                port {
                        hdmi_connector_in: endpoint {
-                               remote-endpoint = <&adv7533_out>;
+                               remote-endpoint = <&adv7535_out>;
                        };
                };
        };
                enable-active-high;
        };
 
+       reg_vext_3v3: regulator-vext-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VEXT_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
        sound {
                compatible = "simple-audio-card";
                simple-audio-card,name = "wm8960-audio";
                                regulator-always-on;
                        };
 
-                       BUCK5 {
+                       reg_buck5: BUCK5 {
                                regulator-name = "BUCK5";
                                regulator-min-microvolt = <1650000>;
                                regulator-max-microvolt = <1950000>;
 
        hdmi@3d {
                compatible = "adi,adv7535";
-               reg = <0x3d>, <0x3c>, <0x3e>, <0x3f>;
-               reg-names = "main", "cec", "edid", "packet";
+               reg = <0x3d>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
                adi,dsi-lanes = <4>;
-               adi,input-depth = <8>;
-               adi,input-colorspace = "rgb";
-               adi,input-clock = "1x";
-               adi,input-style = <1>;
-               adi,input-justification = "evenly";
+               avdd-supply = <&reg_buck5>;
+               dvdd-supply = <&reg_buck5>;
+               pvdd-supply = <&reg_buck5>;
+               a2vdd-supply = <&reg_buck5>;
+               v3p3-supply = <&reg_vext_3v3>;
+               v1p2-supply = <&reg_buck5>;
 
                ports {
                        #address-cells = <1>;
                        port@0 {
                                reg = <0>;
 
-                               adv7533_in: endpoint {
+                               adv7535_in: endpoint {
                                        remote-endpoint = <&dsi_out>;
                                };
                        };
                        port@1 {
                                reg = <1>;
 
-                               adv7533_out: endpoint {
+                               adv7535_out: endpoint {
                                        remote-endpoint = <&hdmi_connector_in>;
                                };
                        };
                        reg = <1>;
 
                        dsi_out: endpoint {
-                               remote-endpoint = <&adv7533_in>;
+                               remote-endpoint = <&adv7535_in>;
                                data-lanes = <1 2 3 4>;
                        };
                };
index c8640cac3edceb15b6531bf2ad33aee4c150171b..00a240484c254e02707463da6b89cb5aed60018f 100644 (file)
                stdout-path = &uart1;
        };
 
+       backlight_lvds: backlight {
+               compatible = "pwm-backlight";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_lvds1>;
+               brightness-levels = <0 4 8 16 32 64 128 255>;
+               default-brightness-level = <11>;
+               enable-gpios = <&gpio2 20 GPIO_ACTIVE_LOW>;
+               num-interpolated-steps = <2>;
+               power-supply = <&reg_lvds1_reg_en>;
+               pwms = <&pwm3 0 50000 0>;
+       };
+
+       panel1_lvds: panel-lvds {
+               compatible = "edt,etml1010g3dra";
+               backlight = <&backlight_lvds>;
+               power-supply = <&reg_vcc_3v3_sw>;
+
+               port {
+                       panel1_in: endpoint {
+                               remote-endpoint = <&ldb_lvds_ch1>;
+                       };
+               };
+       };
+
        reg_can1_stby: regulator-can1-stby {
                compatible = "regulator-fixed";
                pinctrl-names = "default";
                regulator-name = "can2-stby";
        };
 
+       reg_lvds1_reg_en: regulator-lvds1 {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+               regulator-max-microvolt = <1200000>;
+               regulator-min-microvolt = <1200000>;
+               regulator-name = "lvds1_reg_en";
+       };
+
        reg_usb1_vbus: regulator-usb1-vbus {
                compatible = "regulator-fixed";
                pinctrl-names = "default";
                startup-delay-us = <100>;
                off-on-delay-us = <12000>;
        };
+
+       reg_vcc_3v3_sw: regulator-vcc-3v3-sw {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC_3V3_SW";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
 };
 
 &eqos {
        };
 };
 
+&lcdif2 {
+       status = "okay";
+};
+
+&lvds_bridge {
+       status = "okay";
+
+       ports {
+               port@2 {
+                       ldb_lvds_ch1: endpoint {
+                               remote-endpoint = <&panel1_in>;
+                       };
+               };
+       };
+};
+
 &snvs_pwrkey {
        status = "okay";
 };
 
+&pwm3 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm3>;
+};
+
+&rv3028 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_rtc>;
+       interrupt-parent = <&gpio4>;
+       interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+       wakeup-source;
+       trickle-resistor-ohms = <3000>;
+};
+
 /* debug console */
 &uart1 {
        pinctrl-names = "default";
                        MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3               0x90
                        MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x90
                        MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL         0x90
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0               0x16
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1               0x16
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2               0x16
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3               0x16
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL         0x16
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x16
+                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0               0x12
+                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1               0x12
+                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2               0x12
+                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3               0x12
+                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL         0x12
+                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x12
                        MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20                      0x10
                >;
        };
                >;
        };
 
+       pinctrl_lvds1: lvds1grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SD2_WP__GPIO2_IO20         0x12
+               >;
+       };
+
+       pinctrl_pwm3: pwm3grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SPDIF_TX__PWM3_OUT         0x12
+               >;
+       };
+
        pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
                fsl,pins = <
                        MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x40
                >;
        };
 
+       pinctrl_rtc: rtcgrp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19      0x1C0
+               >;
+       };
+
        pinctrl_uart1: uart1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX    0x40
-                       MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX    0x40
+                       MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX    0x140
+                       MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX    0x140
                >;
        };
 
 
        pinctrl_usdhc2_pins: usdhc2-gpiogrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12       0x1c4
+                       MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12       0x40
                >;
        };
 
index c976c3b6cbc650aae74d299db8020eb1a8bb1ec3..e6ffa6a6b68bb4c022c39d830b6acbaae0720d53 100644 (file)
        rv3028: rtc@52 {
                compatible = "microcrystal,rv3028";
                reg = <0x52>;
-               trickle-resistor-ohms = <3000>;
        };
 };
 
index a2d5d19b2de0cb8b69a8ce55fbaeb0c6ba410907..86d3da36e4f3eecf64c0168c825baee86dfdab3f 100644 (file)
                enable-active-high;
        };
 
+       reg_vcc_1v8: regulator-1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+       };
+
        reg_vcc_3v3: regulator-3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                clock-names = "mclk";
                clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>;
                reset-gpios = <&gpio4 29 GPIO_ACTIVE_LOW>;
-               iov-supply = <&reg_vcc_3v3>;
+               iov-supply = <&reg_vcc_1v8>;
                ldoin-supply = <&reg_vcc_3v3>;
        };
 
index 0e8d0f3c7ea87194187f127975256657b4f6221b..e7bf032265e010eecb031e8c9dabe958077a31f1 100644 (file)
 &ecspi2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_spi2>;
-       cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+       cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>,
+                  <&gpio1 10 GPIO_ACTIVE_LOW>;
        status = "okay";
+
+       tpm@1 {
+               compatible = "tcg,tpm_tis-spi";
+               reg = <0x1>;
+               spi-max-frequency = <36000000>;
+       };
 };
 
 &gpio4 {
                        MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI   0x140
                        MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO   0x140
                        MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13     0x140
+                       MX8MP_IOMUXC_GPIO1_IO10__GPIO1_IO10     0x140
                >;
        };
 
index c3305f0d40010041a89b855a5f19b8f2d62a521f..faa17cbbe2fdae53945194e2861a4dbfec8d1838 100644 (file)
                                regulator-name = "On-module +V3.3_ADC (LDO4)";
                        };
 
-                       LDO5 {
+                       reg_vdd_sdio: LDO5 {
                                regulator-max-microvolt = <3300000>;
                                regulator-min-microvolt = <1800000>;
                                regulator-name = "On-module +V3.3_1.8_SD (LDO5)";
        pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_cd>;
        pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_cd_sleep>;
        vmmc-supply = <&reg_usdhc2_vmmc>;
+       vqmmc-supply = <&reg_vdd_sdio>;
 };
 
 /* On-module eMMC */
index 76c73daf546bd0f64bc22e5e1176d814ad677e18..bfc5c81a5bd4eb44b2fb4cdf57ded83ccf8cb6e8 100644 (file)
                                         <&clk IMX8MP_CLK_MEDIA_MIPI_PHY1_REF_ROOT>,
                                         <&clk IMX8MP_CLK_MEDIA_AXI_ROOT>;
                                clock-names = "pclk", "wrap", "phy", "axi";
-                               assigned-clocks = <&clk IMX8MP_CLK_MEDIA_CAM1_PIX>;
-                               assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>;
+                               assigned-clocks = <&clk IMX8MP_CLK_MEDIA_CAM1_PIX>,
+                                                 <&clk IMX8MP_CLK_MEDIA_MIPI_PHY1_REF>;
+                               assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>,
+                                                        <&clk IMX8MP_CLK_24M>;
                                assigned-clock-rates = <500000000>;
                                power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_MIPI_CSI2_1>;
                                status = "disabled";
                                         <&clk IMX8MP_CLK_MEDIA_MIPI_PHY1_REF_ROOT>,
                                         <&clk IMX8MP_CLK_MEDIA_AXI_ROOT>;
                                clock-names = "pclk", "wrap", "phy", "axi";
-                               assigned-clocks = <&clk IMX8MP_CLK_MEDIA_CAM2_PIX>;
-                               assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>;
+                               assigned-clocks = <&clk IMX8MP_CLK_MEDIA_CAM1_PIX>,
+                                                 <&clk IMX8MP_CLK_MEDIA_MIPI_PHY1_REF>;
+                               assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>,
+                                                        <&clk IMX8MP_CLK_24M>;
                                assigned-clock-rates = <266000000>;
                                power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_MIPI_CSI2_2>;
                                status = "disabled";
                                        compatible = "fsl,imx8mp-ldb";
                                        reg = <0x5c 0x4>, <0x128 0x4>;
                                        reg-names = "ldb", "lvds";
-                                       clocks = <&clk IMX8MP_CLK_MEDIA_LDB>;
+                                       clocks = <&clk IMX8MP_CLK_MEDIA_LDB_ROOT>;
                                        clock-names = "ldb";
                                        assigned-clocks = <&clk IMX8MP_CLK_MEDIA_LDB>;
                                        assigned-clock-parents = <&clk IMX8MP_VIDEO_PLL1_OUT>;
index b302daca4ce64e17f7fab22eaac666bd7229127a..0165f3a259853cf545bbba41247526cd200f8f7c 100644 (file)
                id-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
        };
 
-       pcie0_refclk: pcie0-refclk {
-               compatible = "fixed-clock";
-               #clock-cells = <0>;
-               clock-frequency = <100000000>;
-       };
-
-       pcie1_refclk: pcie1-refclk {
-               compatible = "fixed-clock";
-               #clock-cells = <0>;
-               clock-frequency = <100000000>;
-       };
-
        reg_otg_vbus: regulator-otg-vbus {
                compatible = "regulator-fixed";
                pinctrl-names = "default";
        gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;
 };
 
+/* PCIe slot on X36 */
 &pcie0 {
        reset-gpio = <&expander0 14 GPIO_ACTIVE_LOW>;
        clocks = <&clk IMX8MQ_CLK_PCIE1_ROOT>,
-                <&pcie0_refclk>,
-                <&clk IMX8MQ_CLK_PCIE1_PHY>,
+                <&pcieclk 3>,
+                <&pcieclk 2>,
                 <&clk IMX8MQ_CLK_PCIE1_AUX>;
        status = "okay";
 };
 
 /*
- * miniPCIe, also usable for cards with USB. Therefore configure the reset as
+ * miniPCIe on X28, also usable for cards with USB. Therefore configure the reset as
  * static gpio hog.
  */
 &pcie1 {
        clocks = <&clk IMX8MQ_CLK_PCIE2_ROOT>,
-                <&pcie1_refclk>,
-                <&clk IMX8MQ_CLK_PCIE2_PHY>,
+                <&pcieclk 1>,
+                <&pcieclk 0>,
                 <&clk IMX8MQ_CLK_PCIE2_AUX>;
        status = "okay";
 };
 };
 
 &usb3_phy1 {
+       vbus-supply = <&reg_hub_vbus>;
        status = "okay";
 };
 
diff --git a/arch/arm64/boot/dts/freescale/imx8qm-apalis-eval-v1.2.dts b/arch/arm64/boot/dts/freescale/imx8qm-apalis-eval-v1.2.dts
new file mode 100644 (file)
index 0000000..8466a82
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2024 Toradex
+ */
+
+/dts-v1/;
+
+#include "imx8qm-apalis.dtsi"
+#include "imx8-apalis-eval-v1.2.dtsi"
+
+/ {
+       model = "Toradex Apalis iMX8QM/QP on Apalis Evaluation Board V1.2";
+       compatible = "toradex,apalis-imx8-eval-v1.2",
+                    "toradex,apalis-imx8",
+                    "fsl,imx8qm";
+};
index 5ab0921eb599bcff9b1b78716cf6929b540cb834..b0ebf6d05450b4af1b39eecd68ea7a7189ffc05f 100644 (file)
@@ -6,7 +6,7 @@
 /dts-v1/;
 
 #include "imx8qm-apalis.dtsi"
-#include "imx8-apalis-eval.dtsi"
+#include "imx8-apalis-eval-v1.1.dtsi"
 
 / {
        model = "Toradex Apalis iMX8QM/QP on Apalis Evaluation Board";
diff --git a/arch/arm64/boot/dts/freescale/imx8qm-apalis-v1.1-eval-v1.2.dts b/arch/arm64/boot/dts/freescale/imx8qm-apalis-v1.1-eval-v1.2.dts
new file mode 100644 (file)
index 0000000..92c0ae0
--- /dev/null
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2024 Toradex
+ */
+
+/dts-v1/;
+
+#include "imx8qm-apalis-v1.1.dtsi"
+#include "imx8-apalis-eval-v1.2.dtsi"
+
+/ {
+       model = "Toradex Apalis iMX8QM V1.1 on Apalis Evaluation Board V1.2";
+       compatible = "toradex,apalis-imx8-v1.1-eval-v1.2",
+                    "toradex,apalis-imx8-v1.1",
+                    "fsl,imx8qm";
+};
+
+/* Apalis MMC1 */
+&usdhc2 {
+       /delete-property/ no-1-8-v;
+};
+
+/* Apalis SD1 */
+&usdhc3 {
+       /delete-property/ no-1-8-v;
+};
index c8ff75831556d1439a8e52d98a5807c21c2ba24f..c998e542f93c064a7283fa4502158f98ff2f3645 100644 (file)
@@ -6,7 +6,7 @@
 /dts-v1/;
 
 #include "imx8qm-apalis-v1.1.dtsi"
-#include "imx8-apalis-eval.dtsi"
+#include "imx8-apalis-eval-v1.1.dtsi"
 
 / {
        model = "Toradex Apalis iMX8QM V1.1 on Apalis Evaluation Board";
index 6d50838ad17ded0c09a870c261e74504bf9707e0..77ac0efdfaadaec7b5edc1c83bbe8393e67ef6dc 100644 (file)
        };
 };
 
+&i2c1 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       clock-frequency = <100000>;
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       pinctrl-1 = <&pinctrl_i2c1_gpio>;
+       scl-gpios = <&lsio_gpio0 14 GPIO_ACTIVE_HIGH>;
+       sda-gpios = <&lsio_gpio0 15 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
 &lpuart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_lpuart0>;
 };
 
 &iomuxc {
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       IMX8QM_GPT0_CLK_DMA_I2C1_SCL 0x0600004c
+                       IMX8QM_GPT0_CAPTURE_DMA_I2C1_SDA 0x0600004c
+               >;
+       };
+
+       pinctrl_i2c1_gpio: i2c1gpio-grp {
+               fsl,pins = <
+                       IMX8QM_GPT0_CLK_LSIO_GPIO0_IO14         0xc600004c
+                       IMX8QM_GPT0_CAPTURE_LSIO_GPIO0_IO15     0xc600004c
+               >;
+       };
+
        pinctrl_fec1: fec1grp {
                fsl,pins = <
                        IMX8QM_ENET0_MDC_CONN_ENET0_MDC                         0x06000020
index ec1639174e2e5105d49920650a944d62c1a6787f..545e175c88b3e2cada8d14f9170ba14fddfb91ea 100644 (file)
@@ -6,20 +6,25 @@
 
 &fec1 {
        compatible = "fsl,imx8qm-fec", "fsl,imx6sx-fec";
+       iommus = <&smmu 0x12 0x7f80>;
 };
 
 &fec2 {
        compatible = "fsl,imx8qm-fec", "fsl,imx6sx-fec";
+       iommus = <&smmu 0x12 0x7f80>;
 };
 
 &usdhc1 {
        compatible = "fsl,imx8qm-usdhc", "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc";
+       iommus = <&smmu 0x11 0x7f80>;
 };
 
 &usdhc2 {
        compatible = "fsl,imx8qm-usdhc", "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc";
+       iommus = <&smmu 0x11 0x7f80>;
 };
 
 &usdhc3 {
        compatible = "fsl,imx8qm-usdhc", "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc";
+       iommus = <&smmu 0x11 0x7f80>;
 };
index 69cb8676732ea5dc1f7bb204cdd029b022899f63..11626fae5f97f3a9b2c94528d1957fdc73f9aac8 100644 (file)
                power-domains = <&pd IMX_SC_R_UART_4>;
        };
 
+       i2c4: i2c@5a840000 {
+               compatible = "fsl,imx8qm-lpi2c", "fsl,imx7ulp-lpi2c";
+               reg = <0x5a840000 0x4000>;
+               interrupts = <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-parent = <&gic>;
+               clocks = <&i2c4_lpcg 0>,
+                        <&i2c4_lpcg 1>;
+               clock-names = "per", "ipg";
+               assigned-clocks = <&clk IMX_SC_R_I2C_4 IMX_SC_PM_CLK_PER>;
+               assigned-clock-rates = <24000000>;
+               power-domains = <&pd IMX_SC_R_I2C_4>;
+               status = "disabled";
+       };
+
+       i2c4_lpcg: clock-controller@5ac40000 {
+               compatible = "fsl,imx8qxp-lpcg";
+               reg = <0x5ac40000 0x10000>;
+               #clock-cells = <1>;
+               clocks = <&clk IMX_SC_R_I2C_4 IMX_SC_PM_CLK_PER>,
+                        <&dma_ipg_clk>;
+               clock-indices = <IMX_LPCG_CLK_0>, <IMX_LPCG_CLK_4>;
+               clock-output-names = "i2c4_lpcg_clk",
+                                    "i2c4_lpcg_ipg_clk";
+               power-domains = <&pd IMX_SC_R_I2C_4>;
+       };
+
        can1_lpcg: clock-controller@5ace0000 {
                compatible = "fsl,imx8qxp-lpcg";
                reg = <0x5ace0000 0x10000>;
        status = "okay";
 };
 
+/* It is eDMA1 in 8QM RM, but 8QXP it is eDMA3 */
 &edma3 {
+       reg = <0x5a9f0000 0x210000>;
+       dma-channels = <10>;
+       interrupts = <GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 426 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 427 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 428 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 429 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 430 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 431 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 432 IRQ_TYPE_LEVEL_HIGH>,
+                    <GIC_SPI 433 IRQ_TYPE_LEVEL_HIGH>;
        power-domains = <&pd IMX_SC_R_DMA_1_CH0>,
-                    <&pd IMX_SC_R_DMA_1_CH1>,
-                    <&pd IMX_SC_R_DMA_1_CH2>,
-                    <&pd IMX_SC_R_DMA_1_CH3>,
-                    <&pd IMX_SC_R_DMA_1_CH4>,
-                    <&pd IMX_SC_R_DMA_1_CH5>,
-                    <&pd IMX_SC_R_DMA_1_CH6>,
-                    <&pd IMX_SC_R_DMA_1_CH7>;
+                       <&pd IMX_SC_R_DMA_1_CH1>,
+                       <&pd IMX_SC_R_DMA_1_CH2>,
+                       <&pd IMX_SC_R_DMA_1_CH3>,
+                       <&pd IMX_SC_R_DMA_1_CH4>,
+                       <&pd IMX_SC_R_DMA_1_CH5>,
+                       <&pd IMX_SC_R_DMA_1_CH6>,
+                       <&pd IMX_SC_R_DMA_1_CH7>,
+                       <&pd IMX_SC_R_DMA_1_CH8>,
+                       <&pd IMX_SC_R_DMA_1_CH9>;
 };
 
 &flexcan1 {
index 31744fc1ab085d9d67ad7f02fd09cecc145a1ff5..b3d01677b70c48702b316d7395112a1d4e189858 100644 (file)
                             <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* Hypervisor */
        };
 
+       smmu: iommu@51400000 {
+               compatible = "arm,mmu-500";
+               interrupt-parent = <&gic>;
+               reg = <0 0x51400000 0 0x40000>;
+               #global-interrupts = <1>;
+               #iommu-cells = <2>;
+               interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+       };
+
        system-controller {
                compatible = "fsl,imx-scu";
                mbox-names = "tx0",
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-tqma8xqp-mba8xx.dts b/arch/arm64/boot/dts/freescale/imx8qxp-tqma8xqp-mba8xx.dts
new file mode 100644 (file)
index 0000000..7d2e98b
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR X11)
+/*
+ * Copyright 2018-2023 TQ-Systems GmbH <linux@ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Alexander Stein
+ */
+
+/dts-v1/;
+
+#include "imx8qxp-tqma8xqp.dtsi"
+#include "mba8xx.dtsi"
+
+/ {
+       model = "TQ-Systems i.MX8QXP TQMa8XQP on MBa8Xx";
+       compatible = "tq,imx8qxp-tqma8xqp-mba8xx", "tq,imx8qxp-tqma8xqp", "fsl,imx8qxp";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-tqma8xqp.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-tqma8xqp.dtsi
new file mode 100644 (file)
index 0000000..b14040b
--- /dev/null
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR X11)
+/*
+ * Copyright 2018-2023 TQ-Systems GmbH <linux@ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Alexander Stein
+ */
+
+#include "imx8qxp.dtsi"
+#include "tqma8xx.dtsi"
+
+/ {
+       model = "TQ-Systems i.MX8QXP TQMa8XQP";
+       compatible = "tq,imx8qxp-tqma8xqp", "fsl,imx8qxp";
+};
index 958267b3334031c0a01e27294f7c202a213e18f5..10e16d84c0c3b7caa9a3c43d0483a3459cca4a44 100644 (file)
                             <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* Hypervisor */
        };
 
+       clk_dummy: clock-dummy {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+               clock-output-names = "clk_dummy";
+       };
+
        xtal32k: clock-xtal32k {
                compatible = "fixed-clock";
                #clock-cells = <0>;
        /* sorted in register address */
        #include "imx8-ss-img.dtsi"
        #include "imx8-ss-vpu.dtsi"
+       #include "imx8-ss-gpu0.dtsi"
        #include "imx8-ss-adma.dtsi"
        #include "imx8-ss-conn.dtsi"
        #include "imx8-ss-ddr.dtsi"
index 69dd8e31027c8a2069be761a22f0b4eef1d7748f..24bb253b938de54d658cba31918a468e8a5ee155 100644 (file)
@@ -37,7 +37,7 @@
                        no-map;
                };
 
-               rsc_table: rsc-table@1fff8000{
+               rsc_table: rsc-table@1fff8000 {
                        reg = <0 0x1fff8000 0 0x1000>;
                        no-map;
                };
diff --git a/arch/arm64/boot/dts/freescale/imx93-phyboard-segin.dts b/arch/arm64/boot/dts/freescale/imx93-phyboard-segin.dts
new file mode 100644 (file)
index 0000000..85fb188
--- /dev/null
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2023 PHYTEC Messtechnik GmbH
+ * Author: Wadim Egorov <w.egorov@phytec.de>, Christoph Stoidner <c.stoidner@phytec.de>
+ * Copyright (C) 2024 Mathieu Othacehe <m.othacehe@gmail.com>
+ *
+ * Product homepage:
+ * phyBOARD-Segin carrier board is reused for the i.MX93 design.
+ * https://www.phytec.eu/en/produkte/single-board-computer/phyboard-segin-imx6ul/
+ */
+/dts-v1/;
+
+#include "imx93-phycore-som.dtsi"
+
+/{
+       model = "PHYTEC phyBOARD-Segin-i.MX93";
+       compatible = "phytec,imx93-phyboard-segin", "phytec,imx93-phycore-som",
+                    "fsl,imx93";
+
+       chosen {
+               stdout-path = &lpuart1;
+       };
+
+       reg_usdhc2_vmmc: regulator-usdhc2 {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-name = "VCC_SD";
+       };
+};
+
+/* Console */
+&lpuart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+/* eMMC */
+&usdhc1 {
+       no-1-8-v;
+};
+
+/* SD-Card */
+&usdhc2 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc2_default>, <&pinctrl_usdhc2_cd>;
+       pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_cd>;
+       pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_cd>;
+       bus-width = <4>;
+       cd-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>;
+       no-mmc;
+       no-sdio;
+       vmmc-supply = <&reg_usdhc2_vmmc>;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX93_PAD_UART1_RXD__LPUART1_RX          0x31e
+                       MX93_PAD_UART1_TXD__LPUART1_TX          0x30e
+               >;
+       };
+
+       pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+               fsl,pins = <
+                       MX93_PAD_SD2_RESET_B__GPIO3_IO07        0x31e
+               >;
+       };
+
+       pinctrl_usdhc2_cd: usdhc2cdgrp {
+               fsl,pins = <
+                       MX93_PAD_SD2_CD_B__GPIO3_IO00           0x31e
+               >;
+       };
+
+       pinctrl_usdhc2_default: usdhc2grp {
+               fsl,pins = <
+                       MX93_PAD_SD2_CLK__USDHC2_CLK            0x179e
+                       MX93_PAD_SD2_CMD__USDHC2_CMD            0x139e
+                       MX93_PAD_SD2_DATA0__USDHC2_DATA0        0x138e
+                       MX93_PAD_SD2_DATA1__USDHC2_DATA1        0x138e
+                       MX93_PAD_SD2_DATA2__USDHC2_DATA2        0x138e
+                       MX93_PAD_SD2_DATA3__USDHC2_DATA3        0x139e
+                       MX93_PAD_SD2_VSELECT__USDHC2_VSELECT    0x51e
+               >;
+       };
+
+       pinctrl_usdhc2_100mhz: usdhc2grp {
+               fsl,pins = <
+                       MX93_PAD_SD2_CLK__USDHC2_CLK            0x179e
+                       MX93_PAD_SD2_CMD__USDHC2_CMD            0x139e
+                       MX93_PAD_SD2_DATA0__USDHC2_DATA0        0x138e
+                       MX93_PAD_SD2_DATA1__USDHC2_DATA1        0x138e
+                       MX93_PAD_SD2_DATA2__USDHC2_DATA2        0x139e
+                       MX93_PAD_SD2_DATA3__USDHC2_DATA3        0x139e
+                       MX93_PAD_SD2_VSELECT__USDHC2_VSELECT    0x51e
+               >;
+       };
+
+       pinctrl_usdhc2_200mhz: usdhc2grp {
+               fsl,pins = <
+                       MX93_PAD_SD2_CLK__USDHC2_CLK            0x178e
+                       MX93_PAD_SD2_CMD__USDHC2_CMD            0x139e
+                       MX93_PAD_SD2_DATA0__USDHC2_DATA0        0x139e
+                       MX93_PAD_SD2_DATA1__USDHC2_DATA1        0x139e
+                       MX93_PAD_SD2_DATA2__USDHC2_DATA2        0x139e
+                       MX93_PAD_SD2_DATA3__USDHC2_DATA3        0x139e
+                       MX93_PAD_SD2_VSELECT__USDHC2_VSELECT    0x51e
+               >;
+       };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi b/arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi
new file mode 100644 (file)
index 0000000..88c2657
--- /dev/null
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2023 PHYTEC Messtechnik GmbH
+ * Author: Wadim Egorov <w.egorov@phytec.de>, Christoph Stoidner <c.stoidner@phytec.de>
+ * Copyright (C) 2024 Mathieu Othacehe <m.othacehe@gmail.com>
+ *
+ * Product homepage:
+ * https://www.phytec.eu/en/produkte/system-on-modules/phycore-imx-91-93/
+ */
+
+#include <dt-bindings/leds/common.h>
+
+#include "imx93.dtsi"
+
+/{
+       model = "PHYTEC phyCORE-i.MX93";
+       compatible = "phytec,imx93-phycore-som", "fsl,imx93";
+
+       reserved-memory {
+               ranges;
+               #address-cells = <2>;
+               #size-cells = <2>;
+
+               linux,cma {
+                       compatible = "shared-dma-pool";
+                       reusable;
+                       alloc-ranges = <0 0x80000000 0 0x40000000>;
+                       size = <0 0x10000000>;
+                       linux,cma-default;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_leds>;
+
+               led-0 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_HEARTBEAT;
+                       gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+};
+
+/* Ethernet */
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec>;
+       phy-mode = "rmii";
+       phy-handle = <&ethphy1>;
+       fsl,magic-packet;
+       assigned-clocks = <&clk IMX93_CLK_ENET_TIMER1>,
+                         <&clk IMX93_CLK_ENET_REF>,
+                         <&clk IMX93_CLK_ENET_REF_PHY>;
+       assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>,
+                                <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>,
+                                <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
+       assigned-clock-rates = <100000000>, <50000000>, <50000000>;
+       status = "okay";
+
+       mdio: mdio {
+               clock-frequency = <5000000>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy1: ethernet-phy@1 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <1>;
+               };
+       };
+};
+
+/* eMMC */
+&usdhc1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       bus-width = <8>;
+       non-removable;
+       status = "okay";
+};
+
+/* Watchdog */
+&wdog3 {
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_fec: fecgrp {
+               fsl,pins = <
+                       MX93_PAD_ENET2_MDC__ENET1_MDC                   0x50e
+                       MX93_PAD_ENET2_MDIO__ENET1_MDIO                 0x502
+                       MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0             0x57e
+                       MX93_PAD_ENET2_RD1__ENET1_RGMII_RD1             0x57e
+                       MX93_PAD_ENET2_RXC__ENET1_RX_ER                 0x5fe
+                       MX93_PAD_ENET2_RX_CTL__ENET1_RGMII_RX_CTL       0x57e
+                       MX93_PAD_ENET2_TD0__ENET1_RGMII_TD0             0x50e
+                       MX93_PAD_ENET2_TD1__ENET1_RGMII_TD1             0x50e
+                       MX93_PAD_ENET2_TX_CTL__ENET1_RGMII_TX_CTL       0x50e
+                       MX93_PAD_ENET2_TD2__ENET1_TX_CLK                0x4000050e
+               >;
+       };
+
+       pinctrl_leds: ledsgrp {
+               fsl,pins = <
+                       MX93_PAD_I2C1_SDA__GPIO1_IO01           0x31e
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX93_PAD_SD1_CLK__USDHC1_CLK            0x179e
+                       MX93_PAD_SD1_CMD__USDHC1_CMD            0x1386
+                       MX93_PAD_SD1_DATA0__USDHC1_DATA0        0x138e
+                       MX93_PAD_SD1_DATA1__USDHC1_DATA1        0x1386
+                       MX93_PAD_SD1_DATA2__USDHC1_DATA2        0x138e
+                       MX93_PAD_SD1_DATA3__USDHC1_DATA3        0x1386
+                       MX93_PAD_SD1_DATA4__USDHC1_DATA4        0x1386
+                       MX93_PAD_SD1_DATA5__USDHC1_DATA5        0x1386
+                       MX93_PAD_SD1_DATA6__USDHC1_DATA6        0x1386
+                       MX93_PAD_SD1_DATA7__USDHC1_DATA7        0x1386
+                       MX93_PAD_SD1_STROBE__USDHC1_STROBE      0x179e
+               >;
+       };
+};
index f6e422dc2663e99702e3a305d7213e6547aa79e5..9d2328c185c90ed1629872b1dca87142260ff5ed 100644 (file)
 
        /* protectable identification memory (part of M24C64-D @57) */
        eeprom@5f {
-               compatible = "st,24c64", "atmel,24c64";
+               compatible = "atmel,24c64d-wl";
                reg = <0x5f>;
-               size = <32>;
-               pagesize = <32>;
                vcc-supply = <&reg_v3v3>;
        };
 
diff --git a/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx93-var-som-symphony.dts
new file mode 100644 (file)
index 0000000..576d698
--- /dev/null
@@ -0,0 +1,351 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2021 NXP
+ * Copyright 2023 Variscite Ltd.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+#include "imx93-var-som.dtsi"
+
+/{
+       model = "Variscite VAR-SOM-MX93 on Symphony evaluation board";
+       compatible = "variscite,var-som-mx93-symphony",
+                    "variscite,var-som-mx93", "fsl,imx93";
+
+       aliases {
+               ethernet0 = &eqos;
+               ethernet1 = &fec;
+       };
+
+       chosen {
+               stdout-path = &lpuart1;
+       };
+
+       /*
+        * Needed only for Symphony <= v1.5
+        */
+       reg_fec_phy: regulator-fec-phy {
+               compatible = "regulator-fixed";
+               regulator-name = "fec-phy";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-enable-ramp-delay = <20000>;
+               gpio = <&pca9534 7 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+       };
+
+       reg_usdhc2_vmmc: regulator-usdhc2 {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+               regulator-name = "VSD_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&gpio2 18 GPIO_ACTIVE_HIGH>;
+               off-on-delay-us = <20000>;
+               enable-active-high;
+       };
+
+       reg_vref_1v8: regulator-adc-vref {
+               compatible = "regulator-fixed";
+               regulator-name = "vref_1v8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+       };
+
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               ethosu_mem: ethosu-region@88000000 {
+                       compatible = "shared-dma-pool";
+                       reusable;
+                       reg = <0x0 0x88000000 0x0 0x8000000>;
+               };
+
+               vdev0vring0: vdev0vring0@87ee0000 {
+                       reg = <0 0x87ee0000 0 0x8000>;
+                       no-map;
+               };
+
+               vdev0vring1: vdev0vring1@87ee8000 {
+                       reg = <0 0x87ee8000 0 0x8000>;
+                       no-map;
+               };
+
+               vdev1vring0: vdev1vring0@87ef0000 {
+                       reg = <0 0x87ef0000 0 0x8000>;
+                       no-map;
+               };
+
+               vdev1vring1: vdev1vring1@87ef8000 {
+                       reg = <0 0x87ef8000 0 0x8000>;
+                       no-map;
+               };
+
+               rsc_table: rsc-table@2021f000 {
+                       reg = <0 0x2021f000 0 0x1000>;
+                       no-map;
+               };
+
+               vdevbuffer: vdevbuffer@87f00000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x87f00000 0 0x100000>;
+                       no-map;
+               };
+
+               ele_reserved: ele-reserved@87de0000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x87de0000 0 0x100000>;
+                       no-map;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               key-back {
+                       label = "Back";
+                       gpios = <&pca9534 1 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_BACK>;
+               };
+
+               key-home {
+                       label = "Home";
+                       gpios = <&pca9534 2 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_HOME>;
+               };
+
+               key-menu {
+                       label = "Menu";
+                       gpios = <&pca9534 3 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_MENU>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led-0 {
+                       function = LED_FUNCTION_STATUS;
+                       color = <LED_COLOR_ID_GREEN>;
+                       gpios = <&pca9534 0 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+};
+
+/* Use external instead of internal RTC*/
+&bbnsm_rtc {
+       status = "disabled";
+};
+
+&eqos {
+       mdio {
+               ethphy1: ethernet-phy@5 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <5>;
+                       qca,disable-smarteee;
+                       eee-broken-1000t;
+                       reset-gpios = <&pca9534 5 GPIO_ACTIVE_LOW>;
+                       reset-assert-us = <10000>;
+                       reset-deassert-us = <20000>;
+                       vddio-supply = <&vddio1>;
+
+                       vddio1: vddio-regulator {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                       };
+               };
+       };
+};
+
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec>;
+       phy-mode = "rgmii";
+       phy-handle = <&ethphy1>;
+       phy-supply = <&reg_fec_phy>;
+       status = "okay";
+};
+
+&flexcan1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan1>;
+       status = "okay";
+};
+
+&lpi2c1 {
+       clock-frequency = <400000>;
+       pinctrl-names = "default", "sleep", "gpio";
+       pinctrl-0 = <&pinctrl_lpi2c1>;
+       pinctrl-1 = <&pinctrl_lpi2c1_gpio>;
+       pinctrl-2 = <&pinctrl_lpi2c1_gpio>;
+       scl-gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>;
+       sda-gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+
+       /* DS1337 RTC module */
+       rtc@68 {
+               compatible = "dallas,ds1337";
+               reg = <0x68>;
+       };
+};
+
+&lpi2c5 {
+       clock-frequency = <400000>;
+       pinctrl-names = "default", "sleep", "gpio";
+       pinctrl-0 = <&pinctrl_lpi2c5>;
+       pinctrl-1 = <&pinctrl_lpi2c5_gpio>;
+       pinctrl-2 = <&pinctrl_lpi2c5_gpio>;
+       scl-gpios = <&gpio2 23 GPIO_ACTIVE_HIGH>;
+       sda-gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+
+       pca9534: gpio@20 {
+               compatible = "nxp,pca9534";
+               reg = <0x20>;
+               gpio-controller;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pca9534>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
+               #gpio-cells = <2>;
+               wakeup-source;
+       };
+};
+
+/* Console */
+&lpuart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+/* J18.7, J18.9 */
+&lpuart6 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart6>;
+       status = "okay";
+};
+
+/* SD */
+&usdhc2 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+       pinctrl-1 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+       pinctrl-2 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+       cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&reg_usdhc2_vmmc>;
+       bus-width = <4>;
+       status = "okay";
+       no-sdio;
+       no-mmc;
+};
+
+/* Watchdog */
+&wdog3 {
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_fec: fecgrp {
+               fsl,pins = <
+                       MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0             0x57e
+                       MX93_PAD_ENET2_RD1__ENET1_RGMII_RD1             0x57e
+                       MX93_PAD_ENET2_RD2__ENET1_RGMII_RD2             0x57e
+                       MX93_PAD_ENET2_RD3__ENET1_RGMII_RD3             0x57e
+                       MX93_PAD_ENET2_RXC__ENET1_RGMII_RXC             0x5fe
+                       MX93_PAD_ENET2_RX_CTL__ENET1_RGMII_RX_CTL       0x57e
+                       MX93_PAD_ENET2_TD0__ENET1_RGMII_TD0             0x57e
+                       MX93_PAD_ENET2_TD1__ENET1_RGMII_TD1             0x57e
+                       MX93_PAD_ENET2_TD2__ENET1_RGMII_TD2             0x57e
+                       MX93_PAD_ENET2_TD3__ENET1_RGMII_TD3             0x57e
+                       MX93_PAD_ENET2_TXC__ENET1_RGMII_TXC             0x5fe
+                       MX93_PAD_ENET2_TX_CTL__ENET1_RGMII_TX_CTL       0x57e
+               >;
+       };
+
+       pinctrl_flexcan1: flexcan1grp {
+               fsl,pins = <
+                       MX93_PAD_PDM_CLK__CAN1_TX                       0x139e
+                       MX93_PAD_PDM_BIT_STREAM0__CAN1_RX               0x139e
+               >;
+       };
+
+       pinctrl_lpi2c1: lpi2c1grp {
+               fsl,pins = <
+                       MX93_PAD_I2C1_SCL__LPI2C1_SCL                   0x40000b9e
+                       MX93_PAD_I2C1_SDA__LPI2C1_SDA                   0x40000b9e
+               >;
+       };
+
+       pinctrl_lpi2c1_gpio: lpi2c1gpiogrp {
+               fsl,pins = <
+                       MX93_PAD_I2C1_SCL__GPIO1_IO00                   0x31e
+                       MX93_PAD_I2C1_SDA__GPIO1_IO01                   0x31e
+               >;
+       };
+
+       pinctrl_lpi2c5: lpi2c5grp {
+               fsl,pins = <
+                       MX93_PAD_GPIO_IO23__LPI2C5_SCL                  0x40000b9e
+                       MX93_PAD_GPIO_IO22__LPI2C5_SDA                  0x40000b9e
+               >;
+       };
+
+       pinctrl_lpi2c5_gpio: lpi2c5gpiogrp {
+               fsl,pins = <
+                       MX93_PAD_GPIO_IO23__GPIO2_IO23                  0x31e
+                       MX93_PAD_GPIO_IO22__GPIO2_IO22                  0x31e
+               >;
+       };
+
+       pinctrl_pca9534: pca9534grp {
+               fsl,pins = <
+                       MX93_PAD_CCM_CLKO1__GPIO3_IO26          0x31e
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX93_PAD_UART1_RXD__LPUART1_RX                  0x31e
+                       MX93_PAD_UART1_TXD__LPUART1_TX                  0x31e
+               >;
+       };
+
+       pinctrl_uart6: uart6grp {
+               fsl,pins = <
+                       MX93_PAD_GPIO_IO05__LPUART6_RX                  0x31e
+                       MX93_PAD_GPIO_IO04__LPUART6_TX                  0x31e
+               >;
+       };
+
+       pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+               fsl,pins = <
+                       MX93_PAD_GPIO_IO18__GPIO2_IO18          0x31e
+               >;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX93_PAD_SD2_CLK__USDHC2_CLK            0x15fe
+                       MX93_PAD_SD2_CMD__USDHC2_CMD            0x13fe
+                       MX93_PAD_SD2_DATA0__USDHC2_DATA0        0x13fe
+                       MX93_PAD_SD2_DATA1__USDHC2_DATA1        0x13fe
+                       MX93_PAD_SD2_DATA2__USDHC2_DATA2        0x13fe
+                       MX93_PAD_SD2_DATA3__USDHC2_DATA3        0x13fe
+                       MX93_PAD_SD2_VSELECT__USDHC2_VSELECT    0x51e
+               >;
+       };
+
+       pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+               fsl,pins = <
+                       MX93_PAD_SD2_CD_B__GPIO3_IO00           0x31e
+               >;
+       };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx93-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx93-var-som.dtsi
new file mode 100644 (file)
index 0000000..7839382
--- /dev/null
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 NXP
+ * Copyright 2023 Variscite Ltd.
+ */
+
+/dts-v1/;
+
+#include "imx93.dtsi"
+
+/{
+       model = "Variscite VAR-SOM-MX93 module";
+       compatible = "variscite,var-som-mx93", "fsl,imx93";
+
+       mmc_pwrseq: mmc-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               post-power-on-delay-ms = <100>;
+               power-off-delay-us = <10000>;
+               reset-gpios = <&gpio4 14 GPIO_ACTIVE_LOW>,      /* WIFI_RESET */
+                             <&gpio3 7 GPIO_ACTIVE_LOW>;       /* WIFI_PWR_EN */
+       };
+
+       reg_eqos_phy: regulator-eqos-phy {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_eqos_phy>;
+               regulator-name = "eth_phy_pwr";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               startup-delay-us = <100000>;
+               regulator-always-on;
+       };
+};
+
+&eqos {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_eqos>;
+       phy-mode = "rgmii";
+       phy-handle = <&ethphy0>;
+       status = "okay";
+
+       mdio {
+               compatible = "snps,dwmac-mdio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               clock-frequency = <1000000>;
+
+               ethphy0: ethernet-phy@0 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <0>;
+                       eee-broken-1000t;
+               };
+       };
+};
+
+/* eMMC */
+&usdhc1 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       pinctrl-1 = <&pinctrl_usdhc1>;
+       pinctrl-2 = <&pinctrl_usdhc1>;
+       bus-width = <8>;
+       non-removable;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_eqos: eqosgrp {
+               fsl,pins = <
+                       MX93_PAD_ENET1_MDC__ENET_QOS_MDC                        0x57e
+                       MX93_PAD_ENET1_MDIO__ENET_QOS_MDIO                      0x57e
+                       MX93_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0                  0x57e
+                       MX93_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1                  0x57e
+                       MX93_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2                  0x57e
+                       MX93_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3                  0x57e
+                       MX93_PAD_ENET1_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK  0x5fe
+                       MX93_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL            0x57e
+                       MX93_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0                  0x57e
+                       MX93_PAD_ENET1_TD1__ENET_QOS_RGMII_TD1                  0x57e
+                       MX93_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2                  0x57e
+                       MX93_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3                  0x57e
+                       MX93_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK  0x5fe
+                       MX93_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL            0x57e
+               >;
+       };
+
+       pinctrl_reg_eqos_phy: regeqosgrp {
+               fsl,pins = <
+                       MX93_PAD_UART2_TXD__GPIO1_IO07                  0x51e
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX93_PAD_SD1_CLK__USDHC1_CLK            0x15fe
+                       MX93_PAD_SD1_CMD__USDHC1_CMD            0x13fe
+                       MX93_PAD_SD1_DATA0__USDHC1_DATA0        0x13fe
+                       MX93_PAD_SD1_DATA1__USDHC1_DATA1        0x13fe
+                       MX93_PAD_SD1_DATA2__USDHC1_DATA2        0x13fe
+                       MX93_PAD_SD1_DATA3__USDHC1_DATA3        0x13fe
+                       MX93_PAD_SD1_DATA4__USDHC1_DATA4        0x13fe
+                       MX93_PAD_SD1_DATA5__USDHC1_DATA5        0x13fe
+                       MX93_PAD_SD1_DATA6__USDHC1_DATA6        0x13fe
+                       MX93_PAD_SD1_DATA7__USDHC1_DATA7        0x13fe
+                       MX93_PAD_SD1_STROBE__USDHC1_STROBE      0x15fe
+               >;
+       };
+};
index 8f2e7c42ad6e8321a321b17ae2773c3de1aba5c7..601c94e1fac8ea222e1f59a48a1b1b6318eecfa4 100644 (file)
                                status = "disabled";
                        };
 
-                       i3c1: i3c-master@44330000 {
+                       i3c1: i3c@44330000 {
                                compatible = "silvaco,i3c-master-v1";
                                reg = <0x44330000 0x10000>;
                                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
                                status = "disabled";
                        };
 
-                       i3c2: i3c-master@42520000 {
+                       i3c2: i3c@42520000 {
                                compatible = "silvaco,i3c-master-v1";
                                reg = <0x42520000 0x10000>;
                                interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
index e2bc53b8d39a8914c0caa9cbad8bbee90a249056..427467df42bfa66ba5ed7eedd11be752d3820b18 100644 (file)
                stdout-path = &uart3;
        };
 
+       clk_xtal25: clk-xtal25 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <25000000>;
+       };
+
        gpio-keys {
                compatible = "gpio-keys";
                pinctrl-names = "default";
                };
        };
 
-       pcie0_refclk: pcie0-refclk {
-               compatible = "fixed-clock";
-               #clock-cells = <0>;
-               clock-frequency = <100000000>;
-       };
-
        reg_12v: regulator-12v {
                compatible = "regulator-fixed";
                regulator-name = "MBA8MX_12V";
                        line-name = "BOOT_CFG_OE#";
                };
 
-               rst-usb-hub-hog {
+               rst_usb_hub_hog: rst-usb-hub-hog {
                        gpio-hog;
                        gpios = <13 0>;
                        output-high;
                pagesize = <16>;
                vcc-supply = <&reg_vcc_3v3>;
        };
+
+       pcieclk: clk@68 {
+               compatible = "renesas,9fgv0441";
+               reg = <0x68>;
+               clocks = <&clk_xtal25>;
+               #clock-cells = <1>;
+       };
 };
 
 &i2c3 {
diff --git a/arch/arm64/boot/dts/freescale/mba8xx.dtsi b/arch/arm64/boot/dts/freescale/mba8xx.dtsi
new file mode 100644 (file)
index 0000000..276d168
--- /dev/null
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR X11)
+/*
+ * Copyright 2018-2023 TQ-Systems GmbH <linux@ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Alexander Stein
+ */
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/net/ti-dp83867.h>
+
+/ {
+       adc {
+               compatible = "iio-hwmon";
+               io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>;
+       };
+
+       aliases {
+               rtc0 = &pcf85063;
+               rtc1 = &rtc;
+       };
+
+       backlight_lvds: backlight-lvds {
+               compatible = "pwm-backlight";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_bl_lvds>;
+               pwms = <&adma_pwm 0 5000000 0>;
+               brightness-levels = <0 4 8 16 32 64 128 255>;
+               default-brightness-level = <7>;
+               power-supply = <&reg_12v0>;
+               enable-gpios = <&lsio_gpio1 30 GPIO_ACTIVE_HIGH>;
+               status = "disabled";
+       };
+
+       chosen {
+               stdout-path = &lpuart1;
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpiobuttons>;
+               autorepeat;
+
+               switch-a {
+                       label = "switcha";
+                       linux,code = <BTN_0>;
+                       gpios = <&lsio_gpio1 13 GPIO_ACTIVE_LOW>;
+               };
+
+               switch-b {
+                       label = "switchb";
+                       linux,code = <BTN_1>;
+                       gpios = <&lsio_gpio1 14 GPIO_ACTIVE_LOW>;
+               };
+       };
+
+       gpio-leds {
+               compatible = "gpio-leds";
+
+               led1 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_STATUS;
+                       gpios = <&expander 1 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "default-on";
+               };
+
+               led2 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_HEARTBEAT;
+                       gpios = <&expander 2 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       /* TODO LVDS panels */
+
+       reg_12v0: regulator-12v0 {
+               compatible = "regulator-fixed";
+               regulator-name = "V_12V";
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+               gpio = <&expander 6 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_pcie_1v5: regulator-pcie-1v5 {
+               compatible = "regulator-fixed";
+               regulator-name = "MBA8XX_PCIE_1V5";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_pcie_1v5>;
+               regulator-min-microvolt = <1500000>;
+               regulator-max-microvolt = <1500000>;
+               gpio = <&lsio_gpio0 30 GPIO_ACTIVE_HIGH>;
+               startup-delay-us = <1000>;
+               enable-active-high;
+       };
+
+       reg_pcie_3v3: regulator-pcie-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "MBA8XX_PCIE_3V3";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_pcie_3v3>;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&lsio_gpio0 31 GPIO_ACTIVE_HIGH>;
+               startup-delay-us = <1000>;
+               enable-active-high;
+               regulator-always-on;
+       };
+
+       reg_3v3_mb: regulator-usdhc2-vmmc {
+               compatible = "regulator-fixed";
+               regulator-name = "V_3V3_MB";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       sound {
+               compatible = "fsl,imx-audio-tlv320aic32x4";
+               model = "tqm-tlv320aic32";
+               audio-codec = <&tlv320aic3x04>;
+               ssi-controller = <&sai1>;
+       };
+};
+
+&adc0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_adc0>;
+       vref-supply = <&reg_1v8>;
+       #io-channel-cells = <1>;
+       status = "okay";
+};
+
+&adma_pwm {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_admapwm>;
+};
+
+&fec1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec1>;
+       phy-mode = "rgmii-id";
+       phy-handle = <&ethphy0>;
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy0: ethernet-phy@0 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_ethphy0>;
+                       ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+                       ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+                       ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+                       ti,dp83867-rxctrl-strap-quirk;
+                       ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
+                       reset-gpios = <&lsio_gpio3 2 GPIO_ACTIVE_LOW>;
+                       reset-assert-us = <500000>;
+                       reset-deassert-us = <50000>;
+                       enet-phy-lane-no-swap;
+                       interrupt-parent = <&lsio_gpio3>;
+                       interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
+               };
+
+               ethphy3: ethernet-phy@3 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <3>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_ethphy3>;
+                       ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+                       ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+                       ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+                       ti,dp83867-rxctrl-strap-quirk;
+                       ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
+                       reset-gpios = <&lsio_gpio3 3 GPIO_ACTIVE_LOW>;
+                       reset-assert-us = <500000>;
+                       reset-deassert-us = <50000>;
+                       enet-phy-lane-no-swap;
+                       interrupt-parent = <&lsio_gpio3>;
+                       interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+               };
+       };
+};
+
+&fec2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec2>;
+       phy-mode = "rgmii-id";
+       phy-handle = <&ethphy3>;
+       status = "okay";
+};
+
+&flexcan1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_can0>;
+       xceiver-supply = <&reg_3v3>;
+       status = "okay";
+};
+
+&flexcan2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_can1>;
+       xceiver-supply = <&reg_3v3>;
+       status = "okay";
+};
+
+&i2c1 {
+       tlv320aic3x04: audio-codec@18 {
+               compatible = "ti,tlv320aic32x4";
+               reg = <0x18>;
+               clocks = <&mclkout0_lpcg 0>;
+               clock-names = "mclk";
+               iov-supply = <&reg_1v8>;
+               ldoin-supply = <&reg_3v3>;
+       };
+
+       se97b_1c: temperature-sensor@1c {
+               compatible = "nxp,se97b", "jedec,jc-42.4-temp";
+               reg = <0x1c>;
+       };
+
+       at24c02_54: eeprom@54 {
+               compatible = "nxp,se97b", "atmel,24c02";
+               reg = <0x54>;
+               pagesize = <16>;
+               vcc-supply = <&reg_3v3>;
+       };
+
+       expander: gpio@70 {
+               compatible = "nxp,pca9538";
+               reg = <0x70>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pca9538>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-parent = <&lsio_gpio4>;
+               interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               vcc-supply = <&reg_1v8>;
+
+               gpio-line-names = "", "LED_A",
+                                 "LED_B", "",
+                                 "DSI_EN", "USB_RESET#",
+                                 "V_12V_EN", "PCIE_DIS#";
+       };
+};
+
+&i2c2 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&pinctrl_lpi2c2>;
+       pinctrl-1 = <&pinctrl_lpi2c2gpio>;
+       scl-gpios = <&lsio_gpio1 31 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&lsio_gpio2 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       status = "okay";
+};
+
+/* TODO LDB */
+
+&lpspi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi1>;
+       cs-gpios = <&lsio_gpio0 27 GPIO_ACTIVE_LOW>, <&lsio_gpio0 29 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&lpspi2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi2>;
+       cs-gpios = <&lsio_gpio1 0 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&lpspi3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi3>;
+       num-cs = <2>;
+       cs-gpios = <&lsio_gpio0 16 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&lpuart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_lpuart1>;
+       status = "okay";
+};
+
+&lpuart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_lpuart3>;
+       status = "okay";
+};
+
+&lsio_gpio3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_lsgpio3>;
+       gpio-line-names = "", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "X4_15",
+                         "", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "";
+};
+
+/* TODO: Mini-PCIe */
+
+&sai1 {
+       assigned-clocks = <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>,
+                         <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_SLV_BUS>,
+                         <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_MST_BUS>,
+                         <&sai1_lpcg 0>;
+       assigned-clock-rates = <786432000>, <49152000>, <12288000>, <49152000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sai1>;
+       status = "okay";
+};
+
+&usbotg1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usbotg1>;
+       srp-disable;
+       hnp-disable;
+       adp-disable;
+       power-active-high;
+       over-current-active-low;
+       dr_mode = "otg";
+       status = "okay";
+};
+
+&usbotg3 {
+       status = "okay";
+};
+
+&usbotg3_cdns3 {
+       dr_mode = "host";
+       status = "okay";
+};
+
+&usbphy1 {
+       status = "okay";
+};
+
+&usb3_phy {
+       status = "okay";
+};
+
+&usdhc2 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+       pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+       pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+       bus-width = <4>;
+       cd-gpios = <&lsio_gpio4 22 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&lsio_gpio4 21 GPIO_ACTIVE_HIGH>;
+       vmmc-supply = <&reg_3v3_mb>;
+       no-1-8-v;
+       no-sdio;
+       no-mmc;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_adc0: adc0grp {
+               fsl,pins = <IMX8QXP_ADC_IN0_ADMA_ADC_IN0        0x02000060>,
+                          <IMX8QXP_ADC_IN1_ADMA_ADC_IN1        0x02000060>,
+                          <IMX8QXP_ADC_IN2_ADMA_ADC_IN2        0x02000060>,
+                          <IMX8QXP_ADC_IN3_ADMA_ADC_IN3        0x02000060>;
+       };
+
+       pinctrl_admapwm: admapwmgrp {
+               fsl,pins = <IMX8QXP_SPI0_CS1_ADMA_LCD_PWM0_OUT  0x00000021>;
+       };
+
+       pinctrl_bl_lvds: bllvdsgrp {
+               fsl,pins = <IMX8QXP_MIPI_DSI1_I2C0_SDA_LSIO_GPIO1_IO30  0x00000021>;
+       };
+
+       pinctrl_can0: can0grp {
+               fsl,pins = <IMX8QXP_UART0_RX_ADMA_FLEXCAN0_RX           0x00000021>,
+                          <IMX8QXP_UART0_TX_ADMA_FLEXCAN0_TX           0x00000021>;
+       };
+
+       pinctrl_can1: can1grp {
+               fsl,pins = <IMX8QXP_UART2_RX_ADMA_FLEXCAN1_RX           0x00000021>,
+                          <IMX8QXP_UART2_TX_ADMA_FLEXCAN1_TX           0x00000021>;
+       };
+
+       pinctrl_ethphy0: ethphy0grp {
+               fsl,pins = <IMX8QXP_CSI_EN_LSIO_GPIO3_IO02              0x00000040>,
+                          <IMX8QXP_CSI_PCLK_LSIO_GPIO3_IO00            0x00000040>;
+       };
+
+       pinctrl_ethphy3: ethphy3grp {
+               fsl,pins = <IMX8QXP_CSI_RESET_LSIO_GPIO3_IO03           0x00000040>,
+                          <IMX8QXP_CSI_MCLK_LSIO_GPIO3_IO01            0x00000040>;
+       };
+
+       pinctrl_fec1: fec1grp {
+               fsl,pins = <IMX8QXP_ENET0_MDC_CONN_ENET0_MDC                    0x06000041>,
+                          <IMX8QXP_ENET0_MDIO_CONN_ENET0_MDIO                  0x06000041>,
+                          <IMX8QXP_ENET0_RGMII_TX_CTL_CONN_ENET0_RGMII_TX_CTL  0x00000040>,
+                          <IMX8QXP_ENET0_RGMII_TXC_CONN_ENET0_RGMII_TXC        0x00000040>,
+                          <IMX8QXP_ENET0_RGMII_TXD0_CONN_ENET0_RGMII_TXD0      0x00000040>,
+                          <IMX8QXP_ENET0_RGMII_TXD1_CONN_ENET0_RGMII_TXD1      0x00000040>,
+                          <IMX8QXP_ENET0_RGMII_TXD2_CONN_ENET0_RGMII_TXD2      0x00000040>,
+                          <IMX8QXP_ENET0_RGMII_TXD3_CONN_ENET0_RGMII_TXD3      0x00000040>,
+                          <IMX8QXP_ENET0_RGMII_RX_CTL_CONN_ENET0_RGMII_RX_CTL  0x00000040>,
+                          <IMX8QXP_ENET0_RGMII_RXC_CONN_ENET0_RGMII_RXC        0x00000040>,
+                          <IMX8QXP_ENET0_RGMII_RXD0_CONN_ENET0_RGMII_RXD0      0x00000040>,
+                          <IMX8QXP_ENET0_RGMII_RXD1_CONN_ENET0_RGMII_RXD1      0x00000040>,
+                          <IMX8QXP_ENET0_RGMII_RXD2_CONN_ENET0_RGMII_RXD2      0x00000040>,
+                          <IMX8QXP_ENET0_RGMII_RXD3_CONN_ENET0_RGMII_RXD3      0x00000040>;
+       };
+
+       pinctrl_fec2: fec2grp {
+               fsl,pins = <IMX8QXP_ESAI0_SCKR_CONN_ENET1_RGMII_TX_CTL          0x00000040>,
+                          <IMX8QXP_ESAI0_FSR_CONN_ENET1_RGMII_TXC              0x00000040>,
+                          <IMX8QXP_ESAI0_TX4_RX1_CONN_ENET1_RGMII_TXD0         0x00000040>,
+                          <IMX8QXP_ESAI0_TX5_RX0_CONN_ENET1_RGMII_TXD1         0x00000040>,
+                          <IMX8QXP_ESAI0_FST_CONN_ENET1_RGMII_TXD2             0x00000040>,
+                          <IMX8QXP_ESAI0_SCKT_CONN_ENET1_RGMII_TXD3            0x00000040>,
+                          <IMX8QXP_ESAI0_TX0_CONN_ENET1_RGMII_RXC              0x00000040>,
+                          <IMX8QXP_SPDIF0_TX_CONN_ENET1_RGMII_RX_CTL           0x00000040>,
+                          <IMX8QXP_SPDIF0_RX_CONN_ENET1_RGMII_RXD0             0x00000040>,
+                          <IMX8QXP_ESAI0_TX3_RX2_CONN_ENET1_RGMII_RXD1         0x00000040>,
+                          <IMX8QXP_ESAI0_TX2_RX3_CONN_ENET1_RGMII_RXD2         0x00000040>,
+                          <IMX8QXP_ESAI0_TX1_CONN_ENET1_RGMII_RXD3             0x00000040>;
+       };
+
+       pinctrl_gpiobuttons: gpiobuttonsgrp {
+               fsl,pins = <IMX8QXP_ADC_IN5_LSIO_GPIO1_IO13     0x00000020>,
+                          <IMX8QXP_ADC_IN4_LSIO_GPIO1_IO14     0x00000020>;
+       };
+
+       pinctrl_lpi2c2: lpi2c2grp {
+               fsl,pins = <IMX8QXP_MIPI_DSI1_GPIO0_00_ADMA_I2C2_SCL    0x06000021>,
+                          <IMX8QXP_MIPI_DSI1_GPIO0_01_ADMA_I2C2_SDA    0x06000021>;
+       };
+
+       pinctrl_lpi2c2gpio: lpi2c2gpiogrp {
+               fsl,pins = <IMX8QXP_MIPI_DSI1_GPIO0_00_LSIO_GPIO1_IO31  0x06000021>,
+                          <IMX8QXP_MIPI_DSI1_GPIO0_01_LSIO_GPIO2_IO00  0x06000021>;
+       };
+
+       pinctrl_lpuart1: lpuart1grp {
+               fsl,pins = <IMX8QXP_UART1_RX_ADMA_UART1_RX      0x06000020>,
+                          <IMX8QXP_UART1_TX_ADMA_UART1_TX      0x06000020>;
+       };
+
+       pinctrl_lpuart3: lpuart3grp {
+               fsl,pins = <IMX8QXP_FLEXCAN2_RX_ADMA_UART3_RX   0x06000020>,
+                          <IMX8QXP_FLEXCAN2_TX_ADMA_UART3_TX   0x06000020>;
+       };
+
+       pinctrl_lsgpio3: lsgpio3grp {
+               fsl,pins = <IMX8QXP_QSPI0A_SS1_B_LSIO_GPIO3_IO15        0x00000021>;
+       };
+
+       pinctrl_pca9538: pca9538grp {
+               fsl,pins = <IMX8QXP_USDHC1_RESET_B_LSIO_GPIO4_IO19      0x00000020>;
+       };
+
+       pinctrl_pcieb: pcieagrp {
+               fsl,pins = <IMX8QXP_PCIE_CTRL0_PERST_B_LSIO_GPIO4_IO00  0x06000041>,
+                          <IMX8QXP_PCIE_CTRL0_CLKREQ_B_LSIO_GPIO4_IO01 0x06000041>,
+                          <IMX8QXP_PCIE_CTRL0_WAKE_B_LSIO_GPIO4_IO02   0x04000041>;
+       };
+
+       pinctrl_reg_pcie_1v5: regpcie1v5grp {
+               fsl,pins = <IMX8QXP_SAI1_RXC_LSIO_GPIO0_IO30    0x00000021>;
+       };
+
+       pinctrl_reg_pcie_3v3: regpcie3v3grp {
+               fsl,pins = <IMX8QXP_SAI1_RXFS_LSIO_GPIO0_IO31   0x00000021>;
+       };
+
+       pinctrl_sai1: sai1grp {
+               fsl,pins = <IMX8QXP_MCLK_OUT0_ADMA_ACM_MCLK_OUT0        0x06000041>,
+                          <IMX8QXP_FLEXCAN0_RX_ADMA_SAI1_TXC           0x06000041>,
+                          <IMX8QXP_FLEXCAN0_TX_ADMA_SAI1_TXFS          0x06000041>,
+                          <IMX8QXP_FLEXCAN1_RX_ADMA_SAI1_TXD           0x06000041>,
+                          <IMX8QXP_FLEXCAN1_TX_ADMA_SAI1_RXD           0x06000041>;
+       };
+
+       pinctrl_spi1: spi1grp {
+               fsl,pins = <IMX8QXP_SAI0_TXC_ADMA_SPI1_SDI      0x00000041>,
+                          <IMX8QXP_SAI0_TXD_ADMA_SPI1_SDO      0x00000041>,
+                          <IMX8QXP_SAI0_TXFS_ADMA_SPI1_SCK     0x00000041>,
+                          <IMX8QXP_SAI0_RXD_LSIO_GPIO0_IO27    0x00000021>,
+                          <IMX8QXP_SAI1_RXD_LSIO_GPIO0_IO29    0x00000021>;
+       };
+
+       pinctrl_spi2: spi2grp {
+               fsl,pins = <IMX8QXP_SPI2_SCK_ADMA_SPI2_SCK      0x00000041>,
+                          <IMX8QXP_SPI2_SDI_ADMA_SPI2_SDI      0x00000041>,
+                          <IMX8QXP_SPI2_SDO_ADMA_SPI2_SDO      0x00000041>,
+                          <IMX8QXP_SPI2_CS0_LSIO_GPIO1_IO00    0x00000021>;
+       };
+
+       pinctrl_spi3: spi3grp {
+               fsl,pins = <IMX8QXP_SPI3_SCK_ADMA_SPI3_SCK      0x00000041>,
+                          <IMX8QXP_SPI3_SDI_ADMA_SPI3_SDI      0x00000041>,
+                          <IMX8QXP_SPI3_SDO_ADMA_SPI3_SDO      0x00000041>,
+                          <IMX8QXP_SPI3_CS0_LSIO_GPIO0_IO16    0x00000021>,
+                          <IMX8QXP_SPI3_CS1_ADMA_SPI3_CS1      0x00000021>;
+       };
+
+       pinctrl_usbotg1: usbotg1grp {
+               fsl,pins = <IMX8QXP_USB_SS3_TC0_CONN_USB_OTG1_PWR       0x00000021>,
+                          <IMX8QXP_USB_SS3_TC2_CONN_USB_OTG1_OC        0x00000021>;
+       };
+
+       pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+               fsl,pins = <IMX8QXP_USDHC1_WP_LSIO_GPIO4_IO21           0x00000021>,
+                          <IMX8QXP_USDHC1_CD_B_LSIO_GPIO4_IO22         0x00000021>;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <IMX8QXP_USDHC1_CLK_CONN_USDHC1_CLK          0x06000041>,
+                          <IMX8QXP_USDHC1_CMD_CONN_USDHC1_CMD          0x00000021>,
+                          <IMX8QXP_USDHC1_DATA0_CONN_USDHC1_DATA0      0x00000021>,
+                          <IMX8QXP_USDHC1_DATA1_CONN_USDHC1_DATA1      0x00000021>,
+                          <IMX8QXP_USDHC1_DATA2_CONN_USDHC1_DATA2      0x00000021>,
+                          <IMX8QXP_USDHC1_DATA3_CONN_USDHC1_DATA3      0x00000021>,
+                          <IMX8QXP_USDHC1_VSELECT_CONN_USDHC1_VSELECT  0x00000021>;
+       };
+
+       pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+               fsl,pins = <IMX8QXP_USDHC1_CLK_CONN_USDHC1_CLK          0x06000040>,
+                          <IMX8QXP_USDHC1_CMD_CONN_USDHC1_CMD          0x00000020>,
+                          <IMX8QXP_USDHC1_DATA0_CONN_USDHC1_DATA0      0x00000020>,
+                          <IMX8QXP_USDHC1_DATA1_CONN_USDHC1_DATA1      0x00000020>,
+                          <IMX8QXP_USDHC1_DATA2_CONN_USDHC1_DATA2      0x00000020>,
+                          <IMX8QXP_USDHC1_DATA3_CONN_USDHC1_DATA3      0x00000020>,
+                          <IMX8QXP_USDHC1_VSELECT_CONN_USDHC1_VSELECT  0x00000020>;
+       };
+
+       pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+               fsl,pins = <IMX8QXP_USDHC1_CLK_CONN_USDHC1_CLK          0x06000040>,
+                          <IMX8QXP_USDHC1_CMD_CONN_USDHC1_CMD          0x00000020>,
+                          <IMX8QXP_USDHC1_DATA0_CONN_USDHC1_DATA0      0x00000020>,
+                          <IMX8QXP_USDHC1_DATA1_CONN_USDHC1_DATA1      0x00000020>,
+                          <IMX8QXP_USDHC1_DATA2_CONN_USDHC1_DATA2      0x00000020>,
+                          <IMX8QXP_USDHC1_DATA3_CONN_USDHC1_DATA3      0x00000020>,
+                          <IMX8QXP_USDHC1_VSELECT_CONN_USDHC1_VSELECT  0x00000020>;
+       };
+};
diff --git a/arch/arm64/boot/dts/freescale/tqma8xx.dtsi b/arch/arm64/boot/dts/freescale/tqma8xx.dtsi
new file mode 100644 (file)
index 0000000..d98469a
--- /dev/null
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR X11)
+/*
+ * Copyright 2018-2023 TQ-Systems GmbH <linux@ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Alexander Stein
+ */
+
+/ {
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0x00000000 0x80000000 0 0x40000000>;
+       };
+
+       reg_1v8: regulator-1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "V_1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+       };
+
+       reg_3v3: regulator-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "V_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               /*
+                * global autoconfigured region for contiguous allocations
+                * must not exceed memory size and region
+                */
+               linux,cma {
+                       compatible = "shared-dma-pool";
+                       reusable;
+                       size = <0 0x20000000>;
+                       alloc-ranges = <0 0x96000000 0 0x30000000>;
+                       linux,cma-default;
+               };
+       };
+};
+
+/* TQMa8Xx only uses industrial grade, reduce trip points accordingly */
+&cpu_alert0 {
+       temperature = <95000>;
+};
+
+&cpu_crit0 {
+       temperature = <100000>;
+};
+/* end of temperature grade adjustments */
+
+&flexspi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexspi0>;
+       status = "okay";
+
+       flash0: flash@0 {
+               reg = <0>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "jedec,spi-nor";
+               spi-max-frequency = <66000000>;
+               spi-tx-bus-width = <1>;
+               spi-rx-bus-width = <4>;
+       };
+};
+
+/* TODO GPU */
+
+&i2c1 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       clock-frequency = <100000>;
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&pinctrl_lpi2c1>;
+       pinctrl-1 = <&pinctrl_lpi2c1gpio>;
+       scl-gpios = <&lsio_gpio1 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&lsio_gpio1 28 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       status = "okay";
+
+       se97: temperature-sensor@1b {
+               compatible = "nxp,se97b", "jedec,jc-42.4-temp";
+               reg = <0x1b>;
+       };
+
+       pcf85063: rtc@51 {
+               compatible = "nxp,pcf85063a";
+               reg = <0x51>;
+               quartz-load-femtofarads = <7000>;
+       };
+
+       at24c02: eeprom@53 {
+               compatible = "nxp,se97b", "atmel,24c02";
+               reg = <0x53>;
+               pagesize = <16>;
+               read-only;
+               vcc-supply = <&reg_3v3>;
+       };
+
+       m24c64: eeprom@57 {
+               compatible = "atmel,24c64";
+               reg = <0x57>;
+               pagesize = <32>;
+               vcc-supply = <&reg_3v3>;
+       };
+};
+
+&mu_m0 {
+       status = "okay";
+};
+
+&mu1_m0 {
+       status = "okay";
+};
+
+&thermal_zones {
+       pmic_thermal: pmic-thermal {
+               polling-delay-passive = <250>;
+               polling-delay = <2000>;
+               thermal-sensors = <&tsens IMX_SC_R_PMIC_0>;
+
+               trips {
+                       pmic_alert0: trip0 {
+                               temperature = <110000>;
+                               hysteresis = <2000>;
+                               type = "passive";
+                       };
+
+                       pmic_crit0: trip1 {
+                               temperature = <125000>;
+                               hysteresis = <2000>;
+                               type = "critical";
+                       };
+               };
+
+               cooling-maps {
+                       map0 {
+                               trip = <&pmic_alert0>;
+                               cooling-device =
+                                       <&A35_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                       <&A35_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                       <&A35_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                       <&A35_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                       };
+               };
+       };
+};
+
+&usdhc1 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+       vqmmc-supply = <&reg_1v8>;
+       vmmc-supply = <&reg_3v3>;
+       bus-width = <8>;
+       non-removable;
+       no-sdio;
+       no-sd;
+       status = "okay";
+};
+
+&vpu {
+       compatible = "nxp,imx8qxp-vpu";
+       status = "okay";
+};
+
+&vpu_core0 {
+       memory-region = <&decoder_boot>, <&decoder_rpc>;
+       status = "okay";
+};
+
+&vpu_core1 {
+       memory-region = <&encoder_boot>, <&encoder_rpc>;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_flexspi0: flexspi0grp {
+               fsl,pins = <
+                       IMX8QXP_QSPI0A_DATA0_LSIO_QSPI0A_DATA0  0x0600004d
+                       IMX8QXP_QSPI0A_DATA1_LSIO_QSPI0A_DATA1  0x0600004d
+                       IMX8QXP_QSPI0A_DATA2_LSIO_QSPI0A_DATA2  0x0600004d
+                       IMX8QXP_QSPI0A_DATA3_LSIO_QSPI0A_DATA3  0x0600004d
+                       IMX8QXP_QSPI0A_DQS_LSIO_QSPI0A_DQS      0x0600004d
+                       IMX8QXP_QSPI0A_SS0_B_LSIO_QSPI0A_SS0_B  0x0600004d
+                       IMX8QXP_QSPI0A_SCLK_LSIO_QSPI0A_SCLK    0x0600004d
+                       IMX8QXP_QSPI0B_SCLK_LSIO_QSPI0B_SCLK    0x0600004d
+                       IMX8QXP_QSPI0B_DATA0_LSIO_QSPI0B_DATA0  0x0600004d
+                       IMX8QXP_QSPI0B_DATA1_LSIO_QSPI0B_DATA1  0x0600004d
+                       IMX8QXP_QSPI0B_DATA2_LSIO_QSPI0B_DATA2  0x0600004d
+                       IMX8QXP_QSPI0B_DATA3_LSIO_QSPI0B_DATA3  0x0600004d
+                       IMX8QXP_QSPI0B_DQS_LSIO_QSPI0B_DQS      0x0600004d
+                       IMX8QXP_QSPI0B_SS0_B_LSIO_QSPI0B_SS0_B  0x0600004d
+                       IMX8QXP_QSPI0B_SS1_B_LSIO_QSPI0B_SS1_B  0x0600004d
+               >;
+       };
+
+       pinctrl_lpi2c1: lpi2c1grp {
+               fsl,pins = <
+                       IMX8QXP_MIPI_DSI0_GPIO0_00_ADMA_I2C1_SCL        0x06000021
+                       IMX8QXP_MIPI_DSI0_GPIO0_01_ADMA_I2C1_SDA        0x06000021
+               >;
+       };
+
+       pinctrl_lpi2c1gpio: lpi2c1gpiogrp {
+               fsl,pins = <
+                       IMX8QXP_MIPI_DSI0_GPIO0_00_LSIO_GPIO1_IO27      0x06000021
+                       IMX8QXP_MIPI_DSI0_GPIO0_01_LSIO_GPIO1_IO28      0x06000021
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       IMX8QXP_EMMC0_CLK_CONN_EMMC0_CLK        0x06000041
+                       IMX8QXP_EMMC0_CMD_CONN_EMMC0_CMD        0x00000021
+                       IMX8QXP_EMMC0_DATA0_CONN_EMMC0_DATA0    0x00000021
+                       IMX8QXP_EMMC0_DATA1_CONN_EMMC0_DATA1    0x00000021
+                       IMX8QXP_EMMC0_DATA2_CONN_EMMC0_DATA2    0x00000021
+                       IMX8QXP_EMMC0_DATA3_CONN_EMMC0_DATA3    0x00000021
+                       IMX8QXP_EMMC0_DATA4_CONN_EMMC0_DATA4    0x00000021
+                       IMX8QXP_EMMC0_DATA5_CONN_EMMC0_DATA5    0x00000021
+                       IMX8QXP_EMMC0_DATA6_CONN_EMMC0_DATA6    0x00000021
+                       IMX8QXP_EMMC0_DATA7_CONN_EMMC0_DATA7    0x00000021
+                       IMX8QXP_EMMC0_STROBE_CONN_EMMC0_STROBE  0x00000041
+               >;
+       };
+
+       pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+               fsl,pins = <
+                       IMX8QXP_EMMC0_CLK_CONN_EMMC0_CLK        0x06000040
+                       IMX8QXP_EMMC0_CMD_CONN_EMMC0_CMD        0x00000020
+                       IMX8QXP_EMMC0_DATA0_CONN_EMMC0_DATA0    0x00000020
+                       IMX8QXP_EMMC0_DATA1_CONN_EMMC0_DATA1    0x00000020
+                       IMX8QXP_EMMC0_DATA2_CONN_EMMC0_DATA2    0x00000020
+                       IMX8QXP_EMMC0_DATA3_CONN_EMMC0_DATA3    0x00000020
+                       IMX8QXP_EMMC0_DATA4_CONN_EMMC0_DATA4    0x00000020
+                       IMX8QXP_EMMC0_DATA5_CONN_EMMC0_DATA5    0x00000020
+                       IMX8QXP_EMMC0_DATA6_CONN_EMMC0_DATA6    0x00000020
+                       IMX8QXP_EMMC0_DATA7_CONN_EMMC0_DATA7    0x00000020
+                       IMX8QXP_EMMC0_STROBE_CONN_EMMC0_STROBE  0x00000040
+               >;
+       };
+
+       pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+               fsl,pins = <
+                       IMX8QXP_EMMC0_CLK_CONN_EMMC0_CLK        0x06000040
+                       IMX8QXP_EMMC0_CMD_CONN_EMMC0_CMD        0x00000020
+                       IMX8QXP_EMMC0_DATA0_CONN_EMMC0_DATA0    0x00000020
+                       IMX8QXP_EMMC0_DATA1_CONN_EMMC0_DATA1    0x00000020
+                       IMX8QXP_EMMC0_DATA2_CONN_EMMC0_DATA2    0x00000020
+                       IMX8QXP_EMMC0_DATA3_CONN_EMMC0_DATA3    0x00000020
+                       IMX8QXP_EMMC0_DATA4_CONN_EMMC0_DATA4    0x00000020
+                       IMX8QXP_EMMC0_DATA5_CONN_EMMC0_DATA5    0x00000020
+                       IMX8QXP_EMMC0_DATA6_CONN_EMMC0_DATA6    0x00000020
+                       IMX8QXP_EMMC0_DATA7_CONN_EMMC0_DATA7    0x00000020
+                       IMX8QXP_EMMC0_STROBE_CONN_EMMC0_STROBE  0x00000040
+               >;
+       };
+};
index d66d425e45b7d9f7035115c74ea829c53640502c..1162978329c1637aa0fd9a4adef16a9ae5017ac3 100644 (file)
                        status = "disabled";
                };
 
-               i3c0: i3c-master@10da0000 {
+               i3c0: i3c@10da0000 {
                        compatible = "snps,dw-i3c-master-1.00a";
                        reg = <0x10da0000 0x1000>;
                        #address-cells = <3>;
                        status = "disabled";
                };
 
-               i3c1: i3c-master@10da1000 {
+               i3c1: i3c@10da1000 {
                        compatible = "snps,dw-i3c-master-1.00a";
                        reg = <0x10da1000 0x1000>;
                        #address-cells = <3>;
index 48ec4ebec0a83e65bb4978e2f2ffa9cb7aba873c..b864ffa74ea8b6ff72afbd698eab4d30ad990a37 100644 (file)
        amba {
                #address-cells = <2>;
                #size-cells = <1>;
-               #interrupt-cells = <3>;
 
                compatible = "simple-bus";
                interrupt-parent = <&gic>;
index 3869460aa5dcb5da3a3fb32f8e0df6903b88862c..996fb39bb50c1f2074ddd5ac03f191091920c96b 100644 (file)
        amba {
                #address-cells = <2>;
                #size-cells = <1>;
-               #interrupt-cells = <3>;
 
                compatible = "simple-bus";
                interrupt-parent = <&gic>;
index b5e042b8e9290ebbcc2dbdc3c66bd7d10d3bca13..5591939e057b8bd1d628223f20e986fe2f3df237 100644 (file)
@@ -77,7 +77,6 @@
                #address-cells = <2>;
                #size-cells = <2>;
                ranges;
-               dma-ranges;
 
                internal-regs@7f000000 {
                        #address-cells = <1>;
                        };
                };
 
+               mmc_dma: bus@80500000 {
+                               compatible = "simple-bus";
+                               ranges;
+                               #address-cells = <0x2>;
+                               #size-cells = <0x2>;
+                               reg = <0x0 0x80500000 0x0 0x100000>;
+                               dma-ranges = <0x0 0x0 0x2 0x0 0x0 0x80000000>;
+                               dma-coherent;
+
+                               sdhci: mmc@805c0000 {
+                                       compatible = "marvell,ac5-sdhci",
+                                                    "marvell,armada-ap806-sdhci";
+                                       reg = <0x0 0x805c0000 0x0 0x1000>;
+                                       interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+                                       clocks = <&emmc_clock>, <&cnm_clock>;
+                                       clock-names = "core", "axi";
+                                       bus-width = <8>;
+                                       non-removable;
+                                       mmc-ddr-1_8v;
+                                       mmc-hs200-1_8v;
+                                       mmc-hs400-1_8v;
+                               };
+               };
+
                /*
                 * Dedicated section for devices behind 32bit controllers so we
                 * can configure specific DMA mapping for them
                        #clock-cells = <0>;
                        clock-frequency = <400000000>;
                };
+
+               emmc_clock: emmc-clock {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <400000000>;
+               };
        };
 };
index f0ebdb84eec9e18dceeb46541d77fb5a4dcd3a06..0c973d7a215a25091fa92041c5f7993a6a23f2fe 100644 (file)
@@ -99,3 +99,7 @@
                };
        };
 };
+
+&sdhci {
+       status = "okay";
+};
index e300145ad1a6f5ae347a819cf0451410346bac76..1cc3fa1c354de81ca9f6eaa4257b9b561a0deb2a 100644 (file)
                        crypto: crypto@90000 {
                                compatible = "inside-secure,safexcel-eip97ies";
                                reg = <0x90000 0x20000>;
-                               interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
-                                            <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
+                               interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
-                                            <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "mem", "ring0", "ring1",
-                                                 "ring2", "ring3", "eip";
+                                            <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "ring0", "ring1", "ring2",
+                                                 "ring3", "eip", "mem";
                                clocks = <&nb_periph_clk 15>;
                        };
 
index 4a23f65d475fc07de61173da6cc21777ab0635a1..a3328d05fc94c10968e7d96f22e94375ca89faf6 100644 (file)
@@ -33,3 +33,6 @@
                     "marvell,armada-ap806-sdhci"; /* Backward compatibility */
 };
 
+&ap_thermal {
+       compatible = "marvell,armada-ap807-thermal";
+};
index 2c920e22cec2b52dd983f2d20812e7fe80a0c379..7ec7c789d87eff436c4f7362e417c71e2033a5b1 100644 (file)
 
                        odmi: odmi@300000 {
                                compatible = "marvell,odmi-controller";
-                               interrupt-controller;
                                msi-controller;
                                marvell,odmi-frames = <4>;
                                reg = <0x300000 0x4000>,
index 4ec1aae0a3a9c397b3985b8f45176764f6592e4d..7e595ac80043aa18ed742a13c97f5e74aa0e05b2 100644 (file)
                CP11X_LABEL(crypto): crypto@800000 {
                        compatible = "inside-secure,safexcel-eip197b";
                        reg = <0x800000 0x200000>;
-                       interrupts = <87 IRQ_TYPE_LEVEL_HIGH>,
-                               <88 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts = <88 IRQ_TYPE_LEVEL_HIGH>,
                                <89 IRQ_TYPE_LEVEL_HIGH>,
                                <90 IRQ_TYPE_LEVEL_HIGH>,
                                <91 IRQ_TYPE_LEVEL_HIGH>,
-                               <92 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "mem", "ring0", "ring1",
-                               "ring2", "ring3", "eip";
+                               <92 IRQ_TYPE_LEVEL_HIGH>,
+                               <87 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "ring0", "ring1", "ring2", "ring3",
+                                         "eip", "mem";
                        clock-names = "core", "reg";
                        clocks = <&CP11X_LABEL(clk) 1 26>,
                                 <&CP11X_LABEL(clk) 1 17>;
index 1e6f91731e9279cb3f434beab99c4a554f153261..37b4ca3a87c96cb9a8d4be86e446cd51be0d997f 100644 (file)
@@ -8,6 +8,8 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt6797-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt6797-x20-dev.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt7622-rfb1.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt7622-bananapi-bpi-r64.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt7981b-xiaomi-ax3000t.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-acelink-ew-7886cax.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-emmc.dtbo
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-nand.dtbo
@@ -15,6 +17,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-nor.dtbo
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-sd.dtbo
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-rfb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986b-rfb.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8167-pumpkin.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm-hana.dtb
@@ -49,6 +52,16 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kodama-sku32.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-krane-sku0.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-krane-sku176.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-pumpkin.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-corsola-magneton-sku393216.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-corsola-magneton-sku393217.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-corsola-magneton-sku393218.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-corsola-rusty-sku196608.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-corsola-steelix-sku131072.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-corsola-steelix-sku131073.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-corsola-tentacool-sku327681.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-corsola-tentacool-sku327683.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-corsola-tentacruel-sku262144.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-corsola-tentacruel-sku262148.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8188-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8192-asurada-hayato-r1.dtb
@@ -63,4 +76,5 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-demo.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8365-evk.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-genio-1200-evk.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8395-radxa-nio-12l.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8516-pumpkin.dtb
index fffdb7bbf889e48a675e1e7efe10b2d7023d01ed..0c38f7b51763776cda640ab73f8513f4cce9f1e5 100644 (file)
 
        extcon_usb: extcon_iddig {
                compatible = "linux,extcon-usb-gpio";
-               id-gpio = <&pio 12 GPIO_ACTIVE_HIGH>;
+               id-gpios = <&pio 12 GPIO_ACTIVE_HIGH>;
        };
 
        extcon_usb1: extcon_iddig1 {
                compatible = "linux,extcon-usb-gpio";
-               id-gpio = <&pio 14 GPIO_ACTIVE_HIGH>;
+               id-gpios = <&pio 14 GPIO_ACTIVE_HIGH>;
        };
 
        usb_p0_vbus: regulator-usb-p0-vbus {
index ed1a9d319415302a3704b967d578521665803287..6d218caa198cfd304eb546988737b1dc261c34ed 100644 (file)
                #clock-cells = <1>;
        };
 
-       syscfg_pctl_a: syscfg_pctl_a@10005000 {
+       syscfg_pctl_a: syscon@10005000 {
                compatible = "mediatek,mt2712-pctl-a-syscfg", "syscon";
                reg = <0 0x10005000 0 0x1000>;
        };
index c3677d77e0a45a78daaac27ea73ce99a7bdedc01..0e9d11b4585be2c40d817569b3ac5f9e763ad7b8 100644 (file)
                #clock-cells = <1>;
        };
 
-       infrasys: infracfg_ao@10001000 {
+       infrasys: syscon@10001000 {
                compatible = "mediatek,mt6797-infracfg", "syscon";
                reg = <0 0x10001000 0 0x1000>;
                #clock-cells = <1>;
                #clock-cells = <1>;
        };
 
-       imgsys: imgsys_config@15000000  {
+       imgsys: syscon@15000000  {
                compatible = "mediatek,mt6797-imgsys", "syscon";
                reg = <0 0x15000000 0 0x1000>;
                #clock-cells = <1>;
        };
 
-       vdecsys: vdec_gcon@16000000 {
+       vdecsys: syscon@16000000 {
                compatible = "mediatek,mt6797-vdecsys", "syscon";
                reg = <0 0x16000000 0 0x10000>;
                #clock-cells = <1>;
        };
 
-       vencsys: venc_gcon@17000000 {
+       vencsys: syscon@17000000 {
                compatible = "mediatek,mt6797-vencsys", "syscon";
                reg = <0 0x17000000 0 0x1000>;
                #clock-cells = <1>;
index a1f42048dcc70396fa416055c49f368d27d1c070..224bb289660c0869782d1d57589d817525359452 100644 (file)
@@ -75,6 +75,7 @@
 
        memory@40000000 {
                reg = <0 0x40000000 0 0x40000000>;
+               device_type = "memory";
        };
 
        reg_1p8v: regulator-1p8v {
                                        label = "lan3";
                                };
 
+                               port@5 {
+                                       reg = <5>;
+                                       ethernet = <&gmac1>;
+                                       phy-mode = "rgmii";
+
+                                       fixed-link {
+                                               speed = <1000>;
+                                               full-duplex;
+                                               pause;
+                                       };
+                               };
+
                                port@6 {
                                        reg = <6>;
                                        label = "cpu";
index 2dc1bdc74e2124224d5810b4f255453605bd4999..41629769bdc8578cd484f463d94c7cb8b7bb9b5b 100644 (file)
@@ -57,6 +57,7 @@
 
        memory@40000000 {
                reg = <0 0x40000000 0 0x20000000>;
+               device_type = "memory";
        };
 
        reg_1p8v: regulator-1p8v {
                };
        };
 
+       gmac1: mac@1 {
+               compatible = "mediatek,eth-mac";
+               reg = <1>;
+               phy-mode = "rgmii";
+
+               fixed-link {
+                       speed = <1000>;
+                       full-duplex;
+                       pause;
+               };
+       };
+
        mdio-bus {
                #address-cells = <1>;
                #size-cells = <0>;
                                        label = "wan";
                                };
 
+                               port@5 {
+                                       reg = <5>;
+                                       ethernet = <&gmac1>;
+                                       phy-mode = "rgmii";
+
+                                       fixed-link {
+                                               speed = <1000>;
+                                               full-duplex;
+                                               pause;
+                                       };
+                               };
+
                                port@6 {
                                        reg = <6>;
                                        label = "cpu";
diff --git a/arch/arm64/boot/dts/mediatek/mt7981b-xiaomi-ax3000t.dts b/arch/arm64/boot/dts/mediatek/mt7981b-xiaomi-ax3000t.dts
new file mode 100644 (file)
index 0000000..a314c3e
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+
+/dts-v1/;
+
+#include "mt7981b.dtsi"
+
+/ {
+       compatible = "xiaomi,ax3000t", "mediatek,mt7981b";
+       model = "Xiaomi AX3000T";
+
+       memory@40000000 {
+               reg = <0 0x40000000 0 0x10000000>;
+               device_type = "memory";
+       };
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi
new file mode 100644 (file)
index 0000000..4feff3d
--- /dev/null
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+
+#include <dt-bindings/clock/mediatek,mt7981-clk.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       compatible = "mediatek,mt7981b";
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       compatible = "arm,cortex-a53";
+                       reg = <0x0>;
+                       device_type = "cpu";
+                       enable-method = "psci";
+               };
+
+               cpu@1 {
+                       compatible = "arm,cortex-a53";
+                       reg = <0x1>;
+                       device_type = "cpu";
+                       enable-method = "psci";
+               };
+       };
+
+       oscillator-40m {
+               compatible = "fixed-clock";
+               clock-frequency = <40000000>;
+               clock-output-names = "clkxtal";
+               #clock-cells = <0>;
+       };
+
+       psci {
+               compatible = "arm,psci-1.0";
+               method = "smc";
+       };
+
+       soc {
+               compatible = "simple-bus";
+               ranges;
+               #address-cells = <2>;
+               #size-cells = <2>;
+
+               gic: interrupt-controller@c000000 {
+                       compatible = "arm,gic-v3";
+                       reg = <0 0x0c000000 0 0x40000>,  /* GICD */
+                             <0 0x0c080000 0 0x200000>; /* GICR */
+                       interrupt-parent = <&gic>;
+                       interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+               };
+
+               infracfg: clock-controller@10001000 {
+                       compatible = "mediatek,mt7981-infracfg", "syscon";
+                       reg = <0 0x10001000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               clock-controller@1001b000 {
+                       compatible = "mediatek,mt7981-topckgen", "syscon";
+                       reg = <0 0x1001b000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               clock-controller@1001e000 {
+                       compatible = "mediatek,mt7981-apmixedsys";
+                       reg = <0 0x1001e000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               pwm@10048000 {
+                       compatible = "mediatek,mt7981-pwm";
+                       reg = <0 0x10048000 0 0x1000>;
+                       clocks = <&infracfg CLK_INFRA_PWM_STA>,
+                               <&infracfg CLK_INFRA_PWM_HCK>,
+                               <&infracfg CLK_INFRA_PWM1_CK>,
+                               <&infracfg CLK_INFRA_PWM2_CK>,
+                               <&infracfg CLK_INFRA_PWM3_CK>;
+                       clock-names = "top", "main", "pwm1", "pwm2", "pwm3";
+                       #pwm-cells = <2>;
+               };
+
+               clock-controller@15000000 {
+                       compatible = "mediatek,mt7981-ethsys", "syscon";
+                       reg = <0 0x15000000 0 0x1000>;
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+       };
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-acelink-ew-7886cax.dts b/arch/arm64/boot/dts/mediatek/mt7986a-acelink-ew-7886cax.dts
new file mode 100644 (file)
index 0000000..08b3b08
--- /dev/null
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+
+#include "mt7986a.dtsi"
+
+/ {
+       compatible = "acelink,ew-7886cax", "mediatek,mt7986a";
+       model = "Acelink EW-7886CAX";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@40000000 {
+               reg = <0 0x40000000 0 0x20000000>;
+               device_type = "memory";
+       };
+
+       keys {
+               compatible = "gpio-keys";
+
+               key-restart {
+                       label = "Reset";
+                       gpios = <&pio 7 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led-0 {
+                       function = LED_FUNCTION_STATUS;
+                       color = <LED_COLOR_ID_RED>;
+                       gpios = <&pio 18 GPIO_ACTIVE_HIGH>;
+               };
+
+               led-1 {
+                       function = LED_FUNCTION_STATUS;
+                       color = <LED_COLOR_ID_GREEN>;
+                       gpios = <&pio 19 GPIO_ACTIVE_HIGH>;
+               };
+
+               led-2 {
+                       function = LED_FUNCTION_STATUS;
+                       color = <LED_COLOR_ID_BLUE>;
+                       gpios = <&pio 20 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
+
+&crypto {
+       status = "okay";
+};
+
+&eth {
+       status = "okay";
+
+       mac@1 {
+               compatible = "mediatek,eth-mac";
+               reg = <1>;
+               phy-mode = "2500base-x";
+               phy-handle = <&phy6>;
+               nvmem-cells = <&macaddr>;
+               nvmem-cell-names = "mac-address";
+       };
+
+       mdio-bus {
+               reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>;
+               reset-delay-us = <50000>;
+               reset-post-delay-us = <20000>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               phy6: phy@6 {
+                       compatible = "ethernet-phy-ieee802.3-c45";
+                       reg = <6>;
+               };
+       };
+};
+
+&pcie_phy {
+       status = "okay";
+};
+
+&spi0 {
+       status = "okay";
+
+       flash@0 {
+               compatible = "spi-nand";
+               reg = <0>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               spi-max-frequency = <52000000>;
+               spi-rx-bus-width = <4>;
+               spi-tx-bus-width = <4>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               reg = <0x0 0x100000>;
+                               label = "bootloader";
+                               read-only;
+                       };
+
+                       partition@100000 {
+                               reg = <0x100000 0x80000>;
+                               label = "u-boot-env";
+                       };
+
+                       partition@180000 {
+                               compatible = "nvmem-cells";
+                               reg = <0x180000 0x200000>;
+                               label = "factory";
+                               read-only;
+
+                               nvmem-layout {
+                                       compatible = "fixed-layout";
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+
+                                       eeprom: eeprom@0 {
+                                               reg = <0x0 0x1000>;
+                                       };
+
+                                       macaddr: macaddr@4 {
+                                               reg = <0x4 0x6>;
+                                       };
+                               };
+                       };
+
+                       partition@380000 {
+                               reg = <0x380000 0x200000>;
+                               label = "fip";
+                       };
+
+                       partition@580000 {
+                               reg = <0x580000 0x4000000>;
+                               label = "ubi";
+                       };
+               };
+       };
+};
+
+&trng {
+       status = "okay";
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&watchdog {
+       status = "okay";
+};
+
+&wifi {
+       nvmem-cells = <&eeprom>;
+       nvmem-cell-names = "eeprom";
+       status = "okay";
+};
index 543c13385d6e3f82f013b2e6261e4d51c8b39f06..7b97c5c91bd0264df6655b8a3de5ec7aba168896 100644 (file)
@@ -15,7 +15,7 @@
                __overlay__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       spi_nand: spi_nand@0 {
+                       spi_nand: flash@0 {
                                compatible = "spi-nand";
                                reg = <0>;
                                spi-max-frequency = <10000000>;
index d06d4af43cbffba96f5702a133734994a5201120..e04b1c0c0ebbfb59e6e75318ebfaef1dfbe02997 100644 (file)
@@ -43,7 +43,7 @@
                #cooling-cells = <2>;
                /* cooling level (0, 1, 2) - pwm inverted */
                cooling-levels = <255 96 0>;
-               pwms = <&pwm 0 10000 0>;
+               pwms = <&pwm 0 10000>;
                status = "okay";
        };
 
index 3ef371ca254e816c9c4be836e0c04b4bca20f584..5d8e3d3f6c200e0c56b0bdbf494951c1c40fa54c 100644 (file)
                };
        };
 
+       gmac1: mac@1 {
+               compatible = "mediatek,eth-mac";
+               reg = <1>;
+               phy-mode = "rgmii";
+
+               fixed-link {
+                       speed = <1000>;
+                       full-duplex;
+                       pause;
+               };
+       };
+
        mdio: mdio-bus {
                #address-cells = <1>;
                #size-cells = <0>;
        pinctrl-0 = <&spi_flash_pins>;
        cs-gpios = <0>, <0>;
        status = "okay";
-       spi_nand: spi_nand@0 {
+
+       spi_nand: flash@0 {
                compatible = "spi-nand";
                reg = <0>;
                spi-max-frequency = <10000000>;
-               spi-tx-buswidth = <4>;
-               spi-rx-buswidth = <4>;
+               spi-tx-bus-width = <4>;
+               spi-rx-bus-width = <4>;
        };
 };
 
                        label = "lan4";
                };
 
+               port@5 {
+                       reg = <5>;
+                       ethernet = <&gmac1>;
+                       phy-mode = "rgmii";
+
+                       fixed-link {
+                               speed = <1000>;
+                               full-duplex;
+                               pause;
+                       };
+               };
+
                port@6 {
                        reg = <6>;
                        label = "cpu";
index fc751e049953c27ff9df7787642d0bd6016ad458..b3f416b9a7a4da6c15c040c160ee6d6203979aeb 100644 (file)
        #address-cells = <2>;
        #size-cells = <2>;
 
-       clk40m: oscillator-40m {
-               compatible = "fixed-clock";
-               clock-frequency = <40000000>;
-               #clock-cells = <0>;
-               clock-output-names = "clkxtal";
-       };
-
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
                cpu0: cpu@0 {
-                       device_type = "cpu";
                        compatible = "arm,cortex-a53";
-                       enable-method = "psci";
                        reg = <0x0>;
+                       device_type = "cpu";
+                       enable-method = "psci";
                        #cooling-cells = <2>;
                };
 
                cpu1: cpu@1 {
-                       device_type = "cpu";
                        compatible = "arm,cortex-a53";
-                       enable-method = "psci";
                        reg = <0x1>;
+                       device_type = "cpu";
+                       enable-method = "psci";
                        #cooling-cells = <2>;
                };
 
                cpu2: cpu@2 {
-                       device_type = "cpu";
                        compatible = "arm,cortex-a53";
-                       enable-method = "psci";
                        reg = <0x2>;
+                       device_type = "cpu";
+                       enable-method = "psci";
                        #cooling-cells = <2>;
                };
 
                cpu3: cpu@3 {
-                       device_type = "cpu";
-                       enable-method = "psci";
                        compatible = "arm,cortex-a53";
                        reg = <0x3>;
+                       device_type = "cpu";
+                       enable-method = "psci";
                        #cooling-cells = <2>;
                };
        };
 
+       clk40m: oscillator-40m {
+               compatible = "fixed-clock";
+               clock-frequency = <40000000>;
+               #clock-cells = <0>;
+               clock-output-names = "clkxtal";
+       };
+
        psci {
                compatible = "arm,psci-0.2";
                method = "smc";
 
        };
 
-       timer {
-               compatible = "arm,armv8-timer";
-               interrupt-parent = <&gic>;
-               interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
-                            <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
-                            <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
-                            <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
-       };
-
        soc {
-               #address-cells = <2>;
-               #size-cells = <2>;
                compatible = "simple-bus";
                ranges;
+               #address-cells = <2>;
+               #size-cells = <2>;
 
                gic: interrupt-controller@c000000 {
                        compatible = "arm,gic-v3";
-                       #interrupt-cells = <3>;
-                       interrupt-parent = <&gic>;
-                       interrupt-controller;
                        reg = <0 0x0c000000 0 0x10000>,  /* GICD */
                              <0 0x0c080000 0 0x80000>,  /* GICR */
                              <0 0x0c400000 0 0x2000>,   /* GICC */
                              <0 0x0c410000 0 0x1000>,   /* GICH */
                              <0 0x0c420000 0 0x2000>;   /* GICV */
+                       interrupt-parent = <&gic>;
                        interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
                };
 
                infracfg: infracfg@10001000 {
                        compatible = "mediatek,mt7986-infracfg", "syscon";
                        reg = <0 0x10001000 0 0x1000>;
                        #clock-cells = <1>;
+                       #reset-cells = <1>;
                };
 
                wed_pcie: wed-pcie@10003000 {
                        #interrupt-cells = <2>;
                };
 
+               pwm: pwm@10048000 {
+                       compatible = "mediatek,mt7986-pwm";
+                       reg = <0 0x10048000 0 0x1000>;
+                       #pwm-cells = <2>;
+                       interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&topckgen CLK_TOP_PWM_SEL>,
+                                <&infracfg CLK_INFRA_PWM_STA>,
+                                <&infracfg CLK_INFRA_PWM1_CK>,
+                                <&infracfg CLK_INFRA_PWM2_CK>;
+                       clock-names = "top", "main", "pwm1", "pwm2";
+                       status = "disabled";
+               };
+
                sgmiisys0: syscon@10060000 {
                        compatible = "mediatek,mt7986-sgmiisys_0",
                                     "syscon";
                                     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "ring0", "ring1", "ring2", "ring3";
                        clocks = <&infracfg CLK_INFRA_EIP97_CK>;
-                       clock-names = "infra_eip97_ck";
                        assigned-clocks = <&topckgen CLK_TOP_EIP_B_SEL>;
                        assigned-clock-parents = <&apmixedsys CLK_APMIXED_NET2PLL>;
                        status = "disabled";
                };
 
-               pwm: pwm@10048000 {
-                       compatible = "mediatek,mt7986-pwm";
-                       reg = <0 0x10048000 0 0x1000>;
-                       #clock-cells = <1>;
-                       #pwm-cells = <2>;
-                       interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&topckgen CLK_TOP_PWM_SEL>,
-                                <&infracfg CLK_INFRA_PWM_STA>,
-                                <&infracfg CLK_INFRA_PWM1_CK>,
-                                <&infracfg CLK_INFRA_PWM2_CK>;
-                       clock-names = "top", "main", "pwm1", "pwm2";
-                       status = "disabled";
-               };
-
                uart0: serial@11002000 {
                        compatible = "mediatek,mt7986-uart",
                                     "mediatek,mt6577-uart";
 
                spi0: spi@1100a000 {
                        compatible = "mediatek,mt7986-spi-ipm", "mediatek,spi-ipm";
+                       reg = <0 0x1100a000 0 0x100>;
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       reg = <0 0x1100a000 0 0x100>;
                        interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&topckgen CLK_TOP_MPLL_D2>,
                                 <&topckgen CLK_TOP_SPI_SEL>,
 
                spi1: spi@1100b000 {
                        compatible = "mediatek,mt7986-spi-ipm", "mediatek,spi-ipm";
+                       reg = <0 0x1100b000 0 0x100>;
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       reg = <0 0x1100b000 0 0x100>;
                        interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&topckgen CLK_TOP_MPLL_D2>,
                                 <&topckgen CLK_TOP_SPIM_MST_SEL>,
                        status = "disabled";
                };
 
+               thermal: thermal@1100c800 {
+                       compatible = "mediatek,mt7986-thermal";
+                       reg = <0 0x1100c800 0 0x800>;
+                       interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&infracfg CLK_INFRA_THERM_CK>,
+                                <&infracfg CLK_INFRA_ADC_26M_CK>,
+                                <&infracfg CLK_INFRA_ADC_FRC_CK>;
+                       clock-names = "therm", "auxadc", "adc_32k";
+                       nvmem-cells = <&thermal_calibration>;
+                       nvmem-cell-names = "calibration-data";
+                       #thermal-sensor-cells = <1>;
+                       mediatek,auxadc = <&auxadc>;
+                       mediatek,apmixedsys = <&apmixedsys>;
+               };
+
                auxadc: adc@1100d000 {
                        compatible = "mediatek,mt7986-auxadc";
                        reg = <0 0x1100d000 0 0x1000>;
                        status = "disabled";
                };
 
-               thermal: thermal@1100c800 {
-                       #thermal-sensor-cells = <1>;
-                       compatible = "mediatek,mt7986-thermal";
-                       reg = <0 0x1100c800 0 0x800>;
-                       interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&infracfg CLK_INFRA_THERM_CK>,
-                                <&infracfg CLK_INFRA_ADC_26M_CK>,
-                                <&infracfg CLK_INFRA_ADC_FRC_CK>;
-                       clock-names = "therm", "auxadc", "adc_32k";
-                       mediatek,auxadc = <&auxadc>;
-                       mediatek,apmixedsys = <&apmixedsys>;
-                       nvmem-cells = <&thermal_calibration>;
-                       nvmem-cell-names = "calibration-data";
-               };
-
                pcie: pcie@11280000 {
                        compatible = "mediatek,mt7986-pcie",
                                     "mediatek,mt8192-pcie";
+                       reg = <0x00 0x11280000 0x00 0x4000>;
+                       reg-names = "pcie-mac";
+                       ranges = <0x82000000 0x00 0x20000000 0x00
+                                 0x20000000 0x00 0x10000000>;
                        device_type = "pci";
                        #address-cells = <3>;
                        #size-cells = <2>;
-                       reg = <0x00 0x11280000 0x00 0x4000>;
-                       reg-names = "pcie-mac";
                        interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
                        bus-range = <0x00 0xff>;
-                       ranges = <0x82000000 0x00 0x20000000 0x00
-                                 0x20000000 0x00 0x10000000>;
                        clocks = <&infracfg CLK_INFRA_IPCIE_PIPE_CK>,
                                 <&infracfg CLK_INFRA_IPCIE_CK>,
                                 <&infracfg CLK_INFRA_IPCIER_CK>,
                                 <&infracfg CLK_INFRA_IPCIEB_CK>;
                        clock-names = "pl_250m", "tl_26m", "peri_26m", "top_133m";
-                       status = "disabled";
 
                        phys = <&pcie_port PHY_TYPE_PCIE>;
                        phy-names = "pcie-phy";
                                        <0 0 0 2 &pcie_intc 1>,
                                        <0 0 0 3 &pcie_intc 2>,
                                        <0 0 0 4 &pcie_intc 3>;
+                       status = "disabled";
+
                        pcie_intc: interrupt-controller {
                                #address-cells = <0>;
                                #interrupt-cells = <1>;
                pcie_phy: t-phy {
                        compatible = "mediatek,mt7986-tphy",
                                     "mediatek,generic-tphy-v2";
+                       ranges;
                        #address-cells = <2>;
                        #size-cells = <2>;
-                       ranges;
                        status = "disabled";
 
                        pcie_port: pcie-phy@11c00000 {
                usb_phy: t-phy@11e10000 {
                        compatible = "mediatek,mt7986-tphy",
                                     "mediatek,generic-tphy-v2";
+                       ranges = <0 0 0x11e10000 0x1700>;
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       ranges = <0 0 0x11e10000 0x1700>;
                        status = "disabled";
 
                        u2port0: usb-phy@0 {
                };
 
                ethsys: syscon@15000000 {
-                        #address-cells = <1>;
-                        #size-cells = <1>;
                         compatible = "mediatek,mt7986-ethsys",
                                      "syscon";
                         reg = <0 0x15000000 0 0x1000>;
+                        #address-cells = <1>;
+                        #size-cells = <1>;
                         #clock-cells = <1>;
                         #reset-cells = <1>;
                };
                        mediatek,wo-ccif = <&wo_ccif1>;
                };
 
-               wo_ccif0: syscon@151a5000 {
-                       compatible = "mediatek,mt7986-wo-ccif", "syscon";
-                       reg = <0 0x151a5000 0 0x1000>;
-                       interrupt-parent = <&gic>;
-                       interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>;
-               };
-
-               wo_ccif1: syscon@151ad000 {
-                       compatible = "mediatek,mt7986-wo-ccif", "syscon";
-                       reg = <0 0x151ad000 0 0x1000>;
-                       interrupt-parent = <&gic>;
-                       interrupts = <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
-               };
-
                eth: ethernet@15100000 {
                        compatible = "mediatek,mt7986-eth";
                        reg = <0 0x15100000 0 0x80000>;
                                          <&topckgen CLK_TOP_SGM_325M_SEL>;
                        assigned-clock-parents = <&apmixedsys CLK_APMIXED_NET2PLL>,
                                                 <&apmixedsys CLK_APMIXED_SGMPLL>;
+                       #reset-cells = <1>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                        mediatek,ethsys = <&ethsys>;
                        mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
                        mediatek,wed-pcie = <&wed_pcie>;
                        mediatek,wed = <&wed0>, <&wed1>;
-                       #reset-cells = <1>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
                        status = "disabled";
                };
 
+               wo_ccif0: syscon@151a5000 {
+                       compatible = "mediatek,mt7986-wo-ccif", "syscon";
+                       reg = <0 0x151a5000 0 0x1000>;
+                       interrupt-parent = <&gic>;
+                       interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               wo_ccif1: syscon@151ad000 {
+                       compatible = "mediatek,mt7986-wo-ccif", "syscon";
+                       reg = <0 0x151ad000 0 0x1000>;
+                       interrupt-parent = <&gic>;
+                       interrupts = <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
                wifi: wifi@18000000 {
                        compatible = "mediatek,mt7986-wmac";
+                       reg = <0 0x18000000 0 0x1000000>,
+                             <0 0x10003000 0 0x1000>,
+                             <0 0x11d10000 0 0x1000>;
                        resets = <&watchdog MT7986_TOPRGU_CONSYS_SW_RST>;
                        reset-names = "consys";
                        clocks = <&topckgen CLK_TOP_CONN_MCUSYS_SEL>,
                                 <&topckgen CLK_TOP_AP2CNN_HOST_SEL>;
                        clock-names = "mcu", "ap2conn";
-                       reg = <0 0x18000000 0 0x1000000>,
-                             <0 0x10003000 0 0x1000>,
-                             <0 0x11d10000 0 0x1000>;
                        interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
                        };
                };
        };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+       };
 };
index dde190442e3866ce5cfee5be7846028e96be966c..58f77d932429f832c9945c613d0dac928dc56002 100644 (file)
                };
        };
 
+       gmac1: mac@1 {
+               compatible = "mediatek,eth-mac";
+               reg = <1>;
+               phy-mode = "rgmii";
+
+               fixed-link {
+                       speed = <1000>;
+                       full-duplex;
+                       pause;
+               };
+       };
+
        mdio: mdio-bus {
                #address-cells = <1>;
                #size-cells = <0>;
                                        label = "lan4";
                                };
 
+                               port@5 {
+                                       reg = <5>;
+                                       ethernet = <&gmac1>;
+                                       phy-mode = "rgmii";
+
+                                       fixed-link {
+                                               speed = <1000>;
+                                               full-duplex;
+                                               pause;
+                                       };
+                               };
+
                                port@6 {
                                        reg = <6>;
                                        label = "cpu";
        pinctrl-0 = <&spi_flash_pins>;
        cs-gpios = <0>, <0>;
        status = "okay";
-       spi_nand: spi_nand@0 {
+
+       spi_nand: flash@0 {
                compatible = "spi-nand";
                reg = <0>;
                spi-max-frequency = <10000000>;
-               spi-tx-buswidth = <4>;
-               spi-rx-buswidth = <4>;
+               spi-tx-bus-width = <4>;
+               spi-rx-bus-width = <4>;
        };
 };
 
diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts
new file mode 100644 (file)
index 0000000..efc4ad0
--- /dev/null
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+
+/dts-v1/;
+
+#include "mt7988a.dtsi"
+
+/ {
+       compatible = "bananapi,bpi-r4", "mediatek,mt7988a";
+       model = "Banana Pi BPI-R4";
+       chassis-type = "embedded";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi
new file mode 100644 (file)
index 0000000..bba97de
--- /dev/null
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       compatible = "mediatek,mt7988a";
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       compatible = "arm,cortex-a73";
+                       reg = <0x0>;
+                       device_type = "cpu";
+                       enable-method = "psci";
+               };
+
+               cpu@1 {
+                       compatible = "arm,cortex-a73";
+                       reg = <0x1>;
+                       device_type = "cpu";
+                       enable-method = "psci";
+               };
+
+               cpu@2 {
+                       compatible = "arm,cortex-a73";
+                       reg = <0x2>;
+                       device_type = "cpu";
+                       enable-method = "psci";
+               };
+
+               cpu@3 {
+                       compatible = "arm,cortex-a73";
+                       reg = <0x3>;
+                       device_type = "cpu";
+                       enable-method = "psci";
+               };
+       };
+
+       oscillator-40m {
+               compatible = "fixed-clock";
+               clock-frequency = <40000000>;
+               #clock-cells = <0>;
+               clock-output-names = "clkxtal";
+       };
+
+       pmu {
+               compatible = "arm,cortex-a73-pmu";
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>;
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       soc {
+               compatible = "simple-bus";
+               ranges;
+               #address-cells = <2>;
+               #size-cells = <2>;
+
+               gic: interrupt-controller@c000000 {
+                       compatible = "arm,gic-v3";
+                       reg = <0 0x0c000000 0 0x40000>,  /* GICD */
+                             <0 0x0c080000 0 0x200000>, /* GICR */
+                             <0 0x0c400000 0 0x2000>,   /* GICC */
+                             <0 0x0c410000 0 0x1000>,   /* GICH */
+                             <0 0x0c420000 0 0x2000>;   /* GICV */
+                       interrupt-parent = <&gic>;
+                       interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+               };
+
+               clock-controller@10001000 {
+                       compatible = "mediatek,mt7988-infracfg", "syscon";
+                       reg = <0 0x10001000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               clock-controller@1001b000 {
+                       compatible = "mediatek,mt7988-topckgen", "syscon";
+                       reg = <0 0x1001b000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               watchdog: watchdog@1001c000 {
+                       compatible = "mediatek,mt7988-wdt";
+                       reg = <0 0x1001c000 0 0x1000>;
+                       interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+                       #reset-cells = <1>;
+               };
+
+               clock-controller@1001e000 {
+                       compatible = "mediatek,mt7988-apmixedsys";
+                       reg = <0 0x1001e000 0 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               clock-controller@11f40000 {
+                       compatible = "mediatek,mt7988-xfi-pll";
+                       reg = <0 0x11f40000 0 0x1000>;
+                       resets = <&watchdog 16>;
+                       #clock-cells = <1>;
+               };
+
+               clock-controller@15000000 {
+                       compatible = "mediatek,mt7988-ethsys", "syscon";
+                       reg = <0 0x15000000 0 0x1000>;
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+               };
+
+               clock-controller@15031000 {
+                       compatible = "mediatek,mt7988-ethwarp";
+                       reg = <0 0x15031000 0 0x1000>;
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupt-parent = <&gic>;
+               interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+       };
+};
index 256f245ac01d879254b3a1e3e51fc1e010abf483..1c9fc791bdfc56d4740d24a1ce68d5598017dfba 100644 (file)
@@ -14,7 +14,7 @@
 
 &cpu_thermal {
        trips {
-               cpu_crit: cpu_crit0 {
+               cpu_crit: cpu-crit0 {
                        temperature = <100000>;
                        type = "critical";
                };
index 8d614ac2c58ed8262e468a9239b5692f767c6ac2..6d962d437e0231288290806c1d4060c311d9bf19 100644 (file)
                        compatible = "mediatek,mt6397-rtc";
                };
 
-               syscfg_pctl_pmic: syscfg_pctl_pmic@c000 {
+               syscfg_pctl_pmic: syscon@c000 {
                        compatible = "mediatek,mt6397-pctl-pmic-syscfg",
                                     "syscon";
                        reg = <0 0x0000c000 0 0x0108>;
                spi-max-frequency = <12000000>;
                interrupts-extended = <&pio 0 IRQ_TYPE_LEVEL_LOW>;
                google,cros-ec-spi-msg-delay = <500>;
+               wakeup-source;
 
                i2c_tunnel: i2c-tunnel0 {
                        compatible = "google,cros-ec-i2c-tunnel";
index 0e5c628d1ec3e00062f3dafc815e0384614fc753..3fab21f59d1834e8c02a94436b0a8c24b392d4cf 100644 (file)
@@ -41,7 +41,7 @@
 
        extcon_usb: extcon_iddig {
                compatible = "linux,extcon-usb-gpio";
-               id-gpio = <&pio 16 GPIO_ACTIVE_HIGH>;
+               id-gpios = <&pio 16 GPIO_ACTIVE_HIGH>;
        };
 
        usb_p1_vbus: regulator-usb-p1 {
index cac4cd0a032012be0e004eb83baa6515f0f961c0..3458be7f7f61140f94d5e47ea87b6551a59bf48d 100644 (file)
                };
        };
 
-       pmu_a53 {
+       pmu-a53 {
                compatible = "arm,cortex-a53-pmu";
                interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_LOW>,
                             <GIC_SPI 9 IRQ_TYPE_LEVEL_LOW>;
                interrupt-affinity = <&cpu0>, <&cpu1>;
        };
 
-       pmu_a72 {
+       pmu-a72 {
                compatible = "arm,cortex-a72-pmu";
                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_LOW>,
                             <GIC_SPI 13 IRQ_TYPE_LEVEL_LOW>;
                                        type = "passive";
                                };
 
-                               cpu_crit: cpu_crit0 {
+                               cpu_crit: cpu-crit0 {
                                        temperature = <115000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                #address-cells = <2>;
                #size-cells = <2>;
                ranges;
-               vpu_dma_reserved: vpu_dma_mem_region@b7000000 {
+               vpu_dma_reserved: vpu-dma-mem@b7000000 {
                        compatible = "shared-dma-pool";
                        reg = <0 0xb7000000 0 0x500000>;
                        alignment = <0x1000>;
                        #reset-cells = <1>;
                };
 
-               syscfg_pctl_a: syscfg_pctl_a@10005000 {
+               syscfg_pctl_a: syscon@10005000 {
                        compatible = "mediatek,mt8173-pctl-a-syscfg", "syscon";
                        reg = <0 0x10005000 0 0x1000>;
                };
                        reg = <0 0x10206000 0 0x1000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
+
+                       socinfo-data1@40 {
+                               reg = <0x040 0x4>;
+                       };
+
+                       socinfo-data2@44 {
+                               reg = <0x044 0x4>;
+                       };
+
                        thermal_calibration: calib@528 {
                                reg = <0x528 0xc>;
                        };
index b6a9830af2696f55a9e013b462d96f6164d20ef8..bfb9e42c8acaa7c2e5515888a77fe97258a1b78a 100644 (file)
 };
 
 &cros_ec {
+       cbas {
+               compatible = "google,cros-cbas";
+       };
+
        keyboard-controller {
                compatible = "google,cros-ec-keyb-switches";
        };
index 306c95166f3fecb83d88e4c8585ad4c33315d201..5c1bf6a1e475865fc0f6187e9733d7d98908797e 100644 (file)
 };
 
 &cros_ec {
+       cbas {
+               compatible = "google,cros-cbas";
+       };
+
        keyboard-controller {
                compatible = "google,cros-ec-keyb-switches";
        };
index 382e4c6d7191c0325c666b966dca197f8b871b0a..0f5fa893a77426d50c293f780b75cacfe988d866 100644 (file)
 };
 
 &cros_ec {
+       cbas {
+               compatible = "google,cros-cbas";
+       };
+
        keyboard-controller {
                compatible = "google,cros-ec-keyb-switches";
        };
index 1b3396b1cee394659d0a77c104f05e1e7762569f..6bd7424ef66c53b48d89d07ca14d25e913fd1c98 100644 (file)
                interrupts-extended = <&pio 151 IRQ_TYPE_LEVEL_LOW>;
                pinctrl-names = "default";
                pinctrl-0 = <&ec_ap_int_odl>;
+               wakeup-source;
 
                i2c_tunnel: i2c-tunnel {
                        compatible = "google,cros-ec-i2c-tunnel";
                        google,usb-port-id = <0>;
                };
 
-               cbas {
-                       compatible = "google,cros-cbas";
-               };
-
                typec {
                        compatible = "google,cros-ec-typec";
                        #address-cells = <1>;
index 76449b4cf23606e257858d23b1dc2e983f9f0a12..333c516af4908d58439fa4b70342b4d61d84a723 100644 (file)
@@ -33,7 +33,7 @@
                #size-cells = <2>;
                ranges;
 
-               scp_mem_reserved: scp_mem_region@50000000 {
+               scp_mem_reserved: scp-mem@50000000 {
                        compatible = "shared-dma-pool";
                        reg = <0 0x50000000 0 0x2900000>;
                        no-map;
index 920ee415ef5fbd225f4d8e7babe39c609597e0e0..93dfbf1302315d83c2a4c556694c4193ed56e8a3 100644 (file)
                        reg = <0 0x11f10000 0 0x1000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
+
+                       socinfo-data1@4c {
+                               reg = <0x04c 0x4>;
+                       };
+
+                       socinfo-data2@60 {
+                               reg = <0x060 0x4>;
+                       };
+
                        thermal_calibration: calib@180 {
                                reg = <0x180 0xc>;
                        };
                        power-domains = <&spm MT8183_POWER_DOMAIN_VENC>;
                };
 
-               venc_jpg: venc_jpg@17030000 {
+               venc_jpg: jpeg-encoder@17030000 {
                        compatible = "mediatek,mt8183-jpgenc", "mediatek,mtk-jpgenc";
                        reg = <0 0x17030000 0 0x1000>;
                        interrupts = <GIC_SPI 249 IRQ_TYPE_LEVEL_LOW>;
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-krabby.dtsi b/arch/arm64/boot/dts/mediatek/mt8186-corsola-krabby.dtsi
new file mode 100644 (file)
index 0000000..7c97119
--- /dev/null
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2022 Google LLC
+ */
+
+/dts-v1/;
+#include "mt8186-corsola.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       aliases {
+               i2c4 = &i2c4;
+       };
+};
+
+&dsi_out {
+       remote-endpoint = <&ps8640_in>;
+};
+
+&i2c0 {
+       clock-frequency = <400000>;
+
+       edp-bridge@8 {
+               compatible = "parade,ps8640";
+               reg = <0x8>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ps8640_pins>;
+               powerdown-gpios = <&pio 96 GPIO_ACTIVE_LOW>;
+               reset-gpios = <&pio 98 GPIO_ACTIVE_LOW>;
+               vdd12-supply = <&mt6366_vrf12_reg>;
+               vdd33-supply = <&mt6366_vcn33_reg>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               ps8640_in: endpoint {
+                                       remote-endpoint = <&dsi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               ps8640_out: endpoint {
+                                       remote-endpoint = <&panel_in>;
+                               };
+                       };
+               };
+
+               aux-bus {
+                       panel {
+                               compatible = "edp-panel";
+                               power-supply = <&pp3300_disp_x>;
+                               backlight = <&backlight_lcd0>;
+
+                               port {
+                                       panel_in: endpoint {
+                                               remote-endpoint = <&ps8640_out>;
+                                       };
+                               };
+                       };
+               };
+       };
+};
+
+&i2c1 {
+       i2c-scl-internal-delay-ns = <10000>;
+
+       touchscreen: touchscreen@10 {
+               compatible = "hid-over-i2c";
+               reg = <0x10>;
+               interrupts-extended = <&pio 12 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&touchscreen_pins>;
+               post-power-on-delay-ms = <10>;
+               hid-descr-addr = <0x0001>;
+               vdd-supply = <&pp3300_s3>;
+       };
+};
+
+&i2c4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c4_pins>;
+       clock-frequency = <400000>;
+       status = "okay";
+
+       proximity@28 {
+               compatible = "semtech,sx9324";
+               reg = <0x28>;
+               #io-channel-cells = <1>;
+               interrupts-extended = <&pio 5 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&sar_sensor_pins>;
+               vdd-supply = <&mt6366_vio18_reg>;
+               svdd-supply = <&mt6366_vio18_reg>;
+       };
+};
+
+&pio {
+       i2c4_pins: i2c4-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO136__FUNC_SDA4>,
+                                <PINMUX_GPIO135__FUNC_SCL4>;
+                       bias-disable;
+                       drive-strength = <4>;
+                       input-enable;
+               };
+       };
+
+       ps8640_pins: ps8640-pins {
+               pins-pwrdn-rst {
+                       pinmux = <PINMUX_GPIO96__FUNC_GPIO96>,
+                                <PINMUX_GPIO98__FUNC_GPIO98>;
+                       output-low;
+               };
+       };
+
+       sar_sensor_pins: sar-sensor-pins {
+               pins-irq {
+                       pinmux = <PINMUX_GPIO5__FUNC_GPIO5>;
+                       input-enable;
+                       bias-pull-up;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-magneton-sku393216.dts b/arch/arm64/boot/dts/mediatek/mt8186-corsola-magneton-sku393216.dts
new file mode 100644 (file)
index 0000000..c967338
--- /dev/null
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2022 Google LLC
+ */
+
+/dts-v1/;
+#include "mt8186-corsola-steelix.dtsi"
+
+/ {
+       model = "Google Magneton board";
+       compatible = "google,steelix-sku393219", "google,steelix-sku393216",
+                    "google,steelix", "mediatek,mt8186";
+       chassis-type = "laptop";
+};
+
+&gpio_keys {
+       status = "disabled";
+};
+
+&i2c1 {
+       touchscreen@10 {
+               compatible = "hid-over-i2c";
+               reg = <0x10>;
+               interrupts-extended = <&pio 12 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&touchscreen_pins>;
+               vdd-supply = <&pp3300_s3>;
+               post-power-on-delay-ms = <350>;
+               hid-descr-addr = <0x0001>;
+       };
+};
+
+&touchscreen {
+       status = "disabled";
+};
+
+&usb_c1 {
+       status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-magneton-sku393217.dts b/arch/arm64/boot/dts/mediatek/mt8186-corsola-magneton-sku393217.dts
new file mode 100644 (file)
index 0000000..28e3bbe
--- /dev/null
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2022 Google LLC
+ */
+
+/dts-v1/;
+#include "mt8186-corsola-steelix.dtsi"
+
+/ {
+       model = "Google Magneton board";
+       compatible = "google,steelix-sku393220", "google,steelix-sku393217",
+                    "google,steelix", "mediatek,mt8186";
+       chassis-type = "laptop";
+};
+
+&gpio_keys {
+       status = "disabled";
+};
+
+&i2c1 {
+       touchscreen@40 {
+               compatible = "hid-over-i2c";
+               reg = <0x40>;
+               interrupts-extended = <&pio 12 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&touchscreen_pins>;
+               vdd-supply = <&pp3300_s3>;
+               post-power-on-delay-ms = <450>;
+               hid-descr-addr = <0x0001>;
+       };
+};
+
+&touchscreen {
+       status = "disabled";
+};
+
+&usb_c1 {
+       status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-magneton-sku393218.dts b/arch/arm64/boot/dts/mediatek/mt8186-corsola-magneton-sku393218.dts
new file mode 100644 (file)
index 0000000..3328942
--- /dev/null
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2022 Google LLC
+ */
+
+/dts-v1/;
+#include "mt8186-corsola-steelix.dtsi"
+
+/ {
+       model = "Google Magneton board";
+       compatible = "google,steelix-sku393221", "google,steelix-sku393218",
+                    "google,steelix", "mediatek,mt8186";
+       chassis-type = "laptop";
+};
+
+&gpio_keys {
+       status = "disabled";
+};
+
+&touchscreen {
+       status = "disabled";
+};
+
+&usb_c1 {
+       status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-rusty-sku196608.dts b/arch/arm64/boot/dts/mediatek/mt8186-corsola-rusty-sku196608.dts
new file mode 100644 (file)
index 0000000..731b0d6
--- /dev/null
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2022 Google LLC
+ */
+
+/dts-v1/;
+#include "mt8186-corsola-steelix.dtsi"
+
+/ {
+       model = "Google Rusty board";
+       compatible = "google,steelix-sku196609", "google,steelix-sku196608",
+                    "google,steelix", "mediatek,mt8186";
+       chassis-type = "laptop";
+};
+
+&gpio_keys {
+       status = "disabled";
+};
+
+&i2c1 {
+       status = "disabled";
+};
+
+&touchscreen {
+       status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-steelix-sku131072.dts b/arch/arm64/boot/dts/mediatek/mt8186-corsola-steelix-sku131072.dts
new file mode 100644 (file)
index 0000000..eae17bc
--- /dev/null
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2022 Google LLC
+ */
+
+/dts-v1/;
+#include "mt8186-corsola-steelix.dtsi"
+
+/ {
+       model = "Google Steelix board";
+       compatible = "google,steelix-sku131072", "google,steelix",
+                    "mediatek,mt8186";
+       chassis-type = "convertible";
+};
+
+&mt6366codec {
+       mediatek,dmic-mode = <0>; /* two-wire */
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-steelix-sku131073.dts b/arch/arm64/boot/dts/mediatek/mt8186-corsola-steelix-sku131073.dts
new file mode 100644 (file)
index 0000000..a55375b
--- /dev/null
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2022 Google LLC
+ */
+
+/dts-v1/;
+#include "mt8186-corsola-steelix.dtsi"
+
+/ {
+       model = "Google Steelix board";
+       compatible = "google,steelix-sku131073", "google,steelix",
+                    "mediatek,mt8186";
+       chassis-type = "convertible";
+};
+
+&mt6366codec {
+       mediatek,dmic-mode = <1>; /* one-wire */
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-steelix.dtsi b/arch/arm64/boot/dts/mediatek/mt8186-corsola-steelix.dtsi
new file mode 100644 (file)
index 0000000..e74e886
--- /dev/null
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2022 Google LLC
+ */
+
+/dts-v1/;
+#include "mt8186-corsola.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/{
+       pp1000_edpbrdg: regulator-pp1000-edpbrdg {
+               compatible = "regulator-fixed";
+               regulator-name = "pp1000_edpbrdg";
+               pinctrl-names = "default";
+               pinctrl-0 = <&en_pp1000_edpbrdg>;
+               enable-active-high;
+               regulator-boot-on;
+               gpio = <&pio 29 GPIO_ACTIVE_HIGH>;
+               vin-supply = <&pp3300_z2>;
+       };
+
+       pp1800_edpbrdg_dx: regulator-pp1800-edpbrdg-dx {
+               compatible = "regulator-fixed";
+               regulator-name = "pp1800_edpbrdg_dx";
+               pinctrl-names = "default";
+               pinctrl-0 = <&en_pp1800_edpbrdg>;
+               enable-active-high;
+               regulator-boot-on;
+               gpio = <&pio 30 GPIO_ACTIVE_HIGH>;
+               vin-supply = <&mt6366_vio18_reg>;
+       };
+
+       pp3300_edp_dx: regulator-pp3300-edp-dx {
+               compatible = "regulator-fixed";
+               regulator-name = "pp3300_edp_dx";
+               pinctrl-names = "default";
+               pinctrl-0 = <&en_pp3300_edpbrdg>;
+               enable-active-high;
+               regulator-boot-on;
+               gpio = <&pio 31 GPIO_ACTIVE_HIGH>;
+               vin-supply = <&pp3300_z2>;
+       };
+};
+
+&dsi_out {
+       remote-endpoint = <&anx7625_in>;
+};
+
+&i2c0 {
+       clock-frequency = <400000>;
+
+       anx_bridge: anx7625@58 {
+               compatible = "analogix,anx7625";
+               reg = <0x58>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&anx7625_pins>;
+               enable-gpios = <&pio 96 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&pio 98 GPIO_ACTIVE_HIGH>;
+               vdd10-supply = <&pp1000_edpbrdg>;
+               vdd18-supply = <&pp1800_edpbrdg_dx>;
+               vdd33-supply = <&pp3300_edp_dx>;
+               analogix,lane0-swing = /bits/ 8 <0x70 0x30>;
+               analogix,lane1-swing = /bits/ 8 <0x70 0x30>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               anx7625_in: endpoint {
+                                       remote-endpoint = <&dsi_out>;
+                                       data-lanes = <0 1 2 3>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               anx7625_out: endpoint {
+                                       remote-endpoint = <&panel_in>;
+                               };
+                       };
+               };
+
+               aux-bus {
+                       panel: panel {
+                               compatible = "edp-panel";
+                               power-supply = <&pp3300_disp_x>;
+                               backlight = <&backlight_lcd0>;
+
+                               port {
+                                       panel_in: endpoint {
+                                               remote-endpoint = <&anx7625_out>;
+                                       };
+                               };
+                       };
+               };
+       };
+};
+
+&i2c1 {
+       touchscreen: touchscreen@5d {
+               compatible = "goodix,gt7375p";
+               reg = <0x5d>;
+               interrupts-extended = <&pio 12 IRQ_TYPE_EDGE_FALLING>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&touchscreen_pins>;
+               reset-gpios = <&pio 60 GPIO_ACTIVE_LOW>;
+               vdd-supply = <&pp3300_s3>;
+               goodix,no-reset-during-suspend;
+       };
+};
+
+&i2c2 {
+       i2c-scl-internal-delay-ns = <22000>;
+
+       /* second source component */
+       trackpad@2c {
+               compatible = "hid-over-i2c";
+               reg = <0x2c>;
+               hid-descr-addr = <0x20>;
+               interrupts-extended = <&pio 11 IRQ_TYPE_LEVEL_LOW>;
+               vdd-supply = <&pp3300_s3>;
+               wakeup-source;
+       };
+};
+
+&keyboard_controller {
+       function-row-physmap = <
+               MATRIX_KEY(0x00, 0x02, 0)       /* T1 */
+               MATRIX_KEY(0x03, 0x02, 0)       /* T2 */
+               MATRIX_KEY(0x02, 0x02, 0)       /* T3 */
+               MATRIX_KEY(0x01, 0x02, 0)       /* T4 */
+               MATRIX_KEY(0x03, 0x04, 0)       /* T5 */
+               MATRIX_KEY(0x02, 0x04, 0)       /* T6 */
+               MATRIX_KEY(0x01, 0x04, 0)       /* T7 */
+               MATRIX_KEY(0x02, 0x09, 0)       /* T8 */
+               MATRIX_KEY(0x01, 0x09, 0)       /* T9 */
+               MATRIX_KEY(0x00, 0x04, 0)       /* T10 */
+       >;
+
+       linux,keymap = <
+               MATRIX_KEY(0x00, 0x02, KEY_BACK)
+               MATRIX_KEY(0x03, 0x02, KEY_REFRESH)
+               MATRIX_KEY(0x02, 0x02, KEY_ZOOM)
+               MATRIX_KEY(0x01, 0x02, KEY_SCALE)
+               MATRIX_KEY(0x03, 0x04, KEY_BRIGHTNESSDOWN)
+               MATRIX_KEY(0x02, 0x04, KEY_BRIGHTNESSUP)
+               MATRIX_KEY(0x01, 0x04, KEY_MICMUTE)
+               MATRIX_KEY(0x02, 0x09, KEY_MUTE)
+               MATRIX_KEY(0x01, 0x09, KEY_VOLUMEDOWN)
+               MATRIX_KEY(0x00, 0x04, KEY_VOLUMEUP)
+               CROS_STD_MAIN_KEYMAP
+       >;
+};
+
+&pio {
+       anx7625_pins: anx7625-pins {
+               pins-int {
+                       pinmux = <PINMUX_GPIO9__FUNC_GPIO9>;
+                       input-enable;
+                       bias-disable;
+               };
+
+               pins-reset {
+                       pinmux = <PINMUX_GPIO98__FUNC_GPIO98>;
+                       output-low;
+               };
+
+               pins-power-en {
+                       pinmux = <PINMUX_GPIO96__FUNC_GPIO96>;
+                       output-low;
+               };
+       };
+
+       en_pp1000_edpbrdg: pp1000-edpbrdg-en-pins {
+               pins-vreg-en {
+                       pinmux = <PINMUX_GPIO29__FUNC_GPIO29>;
+                       output-low;
+               };
+       };
+
+       en_pp1800_edpbrdg: pp1800-edpbrdg-en-pins {
+               pins-vreg-en {
+                       pinmux = <PINMUX_GPIO30__FUNC_GPIO30>;
+                       output-low;
+               };
+       };
+
+       en_pp3300_edpbrdg: pp3300-edpbrdg-en-pins {
+               pins-vreg-en {
+                       pinmux = <PINMUX_GPIO31__FUNC_GPIO31>;
+                       output-low;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-tentacool-sku327681.dts b/arch/arm64/boot/dts/mediatek/mt8186-corsola-tentacool-sku327681.dts
new file mode 100644 (file)
index 0000000..9bb6435
--- /dev/null
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2022 Google LLC
+ */
+
+/dts-v1/;
+#include "mt8186-corsola-krabby.dtsi"
+
+/ {
+       model = "Google Tentacool board";
+       compatible = "google,tentacruel-sku327681", "google,tentacruel", "mediatek,mt8186";
+       chassis-type = "laptop";
+};
+
+/* Tentacool omits the pen. */
+&gpio_keys {
+       status = "disabled";
+};
+
+/* Tentacool omits the touchscreen; nothing else is on i2c1. */
+&i2c1 {
+       status = "disabled";
+};
+
+&keyboard_controller {
+       function-row-physmap = <
+               MATRIX_KEY(0x00, 0x02, 0)       /* T1 */
+               MATRIX_KEY(0x03, 0x02, 0)       /* T2 */
+               MATRIX_KEY(0x02, 0x02, 0)       /* T3 */
+               MATRIX_KEY(0x01, 0x02, 0)       /* T4 */
+               MATRIX_KEY(0x03, 0x04, 0)       /* T5 */
+               MATRIX_KEY(0x02, 0x04, 0)       /* T6 */
+               MATRIX_KEY(0x01, 0x04, 0)       /* T7 */
+               MATRIX_KEY(0x02, 0x09, 0)       /* T8 */
+               MATRIX_KEY(0x01, 0x09, 0)       /* T9 */
+               MATRIX_KEY(0x00, 0x04, 0)       /* T10 */
+       >;
+
+       linux,keymap = <
+               MATRIX_KEY(0x00, 0x02, KEY_BACK)
+               MATRIX_KEY(0x03, 0x02, KEY_REFRESH)
+               MATRIX_KEY(0x02, 0x02, KEY_ZOOM)
+               MATRIX_KEY(0x01, 0x02, KEY_SCALE)
+               MATRIX_KEY(0x03, 0x04, KEY_SYSRQ)
+               MATRIX_KEY(0x02, 0x04, KEY_BRIGHTNESSDOWN)
+               MATRIX_KEY(0x01, 0x04, KEY_BRIGHTNESSUP)
+               MATRIX_KEY(0x02, 0x09, KEY_MUTE)
+               MATRIX_KEY(0x01, 0x09, KEY_VOLUMEDOWN)
+               MATRIX_KEY(0x00, 0x04, KEY_VOLUMEUP)
+               CROS_STD_MAIN_KEYMAP
+       >;
+};
+
+/* Tentacool omits the touchscreen. */
+&touchscreen {
+       status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-tentacool-sku327683.dts b/arch/arm64/boot/dts/mediatek/mt8186-corsola-tentacool-sku327683.dts
new file mode 100644 (file)
index 0000000..c3ae6f9
--- /dev/null
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2023 Google LLC
+ */
+
+#include "mt8186-corsola-tentacool-sku327681.dts"
+
+/ {
+       compatible = "google,tentacruel-sku327683", "google,tentacruel", "mediatek,mt8186";
+};
+
+/* This variant replaces only the trackpad controller. */
+&i2c2 {
+       /delete-node/ trackpad@15;
+
+       trackpad@15 {
+               compatible = "hid-over-i2c";
+               reg = <0x15>;
+               interrupts-extended = <&pio 11 IRQ_TYPE_LEVEL_LOW>;
+               hid-descr-addr = <0x0001>;
+               vdd-supply = <&pp3300_s3>;
+               wakeup-source;
+       };
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-tentacruel-sku262144.dts b/arch/arm64/boot/dts/mediatek/mt8186-corsola-tentacruel-sku262144.dts
new file mode 100644 (file)
index 0000000..26d3451
--- /dev/null
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2022 Google LLC
+ */
+
+/dts-v1/;
+#include "mt8186-corsola-krabby.dtsi"
+
+/ {
+       model = "Google Tentacruel board";
+       compatible = "google,tentacruel-sku262147", "google,tentacruel-sku262146",
+                    "google,tentacruel-sku262145", "google,tentacruel-sku262144",
+                    "google,tentacruel", "mediatek,mt8186";
+       chassis-type = "convertible";
+};
+
+&keyboard_controller {
+       function-row-physmap = <
+               MATRIX_KEY(0x00, 0x02, 0)       /* T1 */
+               MATRIX_KEY(0x03, 0x02, 0)       /* T2 */
+               MATRIX_KEY(0x02, 0x02, 0)       /* T3 */
+               MATRIX_KEY(0x01, 0x02, 0)       /* T4 */
+               MATRIX_KEY(0x03, 0x04, 0)       /* T5 */
+               MATRIX_KEY(0x02, 0x04, 0)       /* T6 */
+               MATRIX_KEY(0x01, 0x04, 0)       /* T7 */
+               MATRIX_KEY(0x02, 0x09, 0)       /* T8 */
+               MATRIX_KEY(0x01, 0x09, 0)       /* T9 */
+               MATRIX_KEY(0x00, 0x04, 0)       /* T10 */
+       >;
+
+       linux,keymap = <
+               MATRIX_KEY(0x00, 0x02, KEY_BACK)
+               MATRIX_KEY(0x03, 0x02, KEY_REFRESH)
+               MATRIX_KEY(0x02, 0x02, KEY_ZOOM)
+               MATRIX_KEY(0x01, 0x02, KEY_SCALE)
+               MATRIX_KEY(0x03, 0x04, KEY_SYSRQ)
+               MATRIX_KEY(0x02, 0x04, KEY_BRIGHTNESSDOWN)
+               MATRIX_KEY(0x01, 0x04, KEY_BRIGHTNESSUP)
+               MATRIX_KEY(0x02, 0x09, KEY_MUTE)
+               MATRIX_KEY(0x01, 0x09, KEY_VOLUMEDOWN)
+               MATRIX_KEY(0x00, 0x04, KEY_VOLUMEUP)
+               CROS_STD_MAIN_KEYMAP
+       >;
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-tentacruel-sku262148.dts b/arch/arm64/boot/dts/mediatek/mt8186-corsola-tentacruel-sku262148.dts
new file mode 100644 (file)
index 0000000..447b57b
--- /dev/null
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2023 Google LLC
+ */
+
+#include "mt8186-corsola-tentacruel-sku262144.dts"
+
+/ {
+       compatible = "google,tentacruel-sku262151", "google,tentacruel-sku262150",
+                    "google,tentacruel-sku262149", "google,tentacruel-sku262148",
+                    "google,tentacruel", "mediatek,mt8186";
+};
+
+/* This variant replaces only the trackpad controller. */
+&i2c2 {
+       /delete-node/ trackpad@15;
+
+       trackpad@15 {
+               compatible = "hid-over-i2c";
+               reg = <0x15>;
+               interrupts-extended = <&pio 11 IRQ_TYPE_LEVEL_LOW>;
+               hid-descr-addr = <0x0001>;
+               vdd-supply = <&pp3300_s3>;
+               wakeup-source;
+       };
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola.dtsi b/arch/arm64/boot/dts/mediatek/mt8186-corsola.dtsi
new file mode 100644 (file)
index 0000000..3dea28f
--- /dev/null
@@ -0,0 +1,1681 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ */
+/dts-v1/;
+#include "mt8186.dtsi"
+#include <dt-bindings/pinctrl/mt8186-pinfunc.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/input/gpio-keys.h>
+#include <dt-bindings/regulator/mediatek,mt6397-regulator.h>
+
+/ {
+       aliases {
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
+               i2c2 = &i2c2;
+               i2c3 = &i2c3;
+               i2c5 = &i2c5;
+               mmc0 = &mmc0;
+               mmc1 = &mmc1;
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@40000000 {
+               device_type = "memory";
+               /* The size should be filled in by the bootloader. */
+               reg = <0 0x40000000 0 0>;
+       };
+
+       backlight_lcd0: backlight-lcd0 {
+               compatible = "pwm-backlight";
+               pwms = <&pwm0 0 500000>;
+               power-supply = <&ppvar_sys>;
+               enable-gpios = <&pio 152 0>;
+               brightness-levels = <0 1023>;
+               num-interpolated-steps = <1023>;
+               default-brightness-level = <576>;
+       };
+
+       bt-sco-codec {
+               compatible = "linux,bt-sco";
+               #sound-dai-cells = <0>;
+       };
+
+       dmic-codec {
+               compatible = "dmic-codec";
+               #sound-dai-cells = <0>;
+               num-channels = <2>;
+               wakeup-delay-ms = <50>;
+       };
+
+       gpio_keys: gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pen_eject>;
+
+               pen_insert: pen-insert-switch {
+                       label = "Pen Insert";
+                       /* Insert = low, eject = high */
+                       gpios = <&pio 18 GPIO_ACTIVE_LOW>;
+                       wakeup-event-action = <EV_ACT_DEASSERTED>;
+                       wakeup-source;
+                       linux,code = <SW_PEN_INSERTED>;
+                       linux,input-type = <EV_SW>;
+               };
+       };
+
+       pp1800_dpbrdg_dx: regulator-pp1800-dpbrdg-dx {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&en_pp1800_dpbrdg>;
+               gpios = <&pio 39 GPIO_ACTIVE_HIGH>;
+               regulator-name = "pp1800_dpbrdg_dx";
+               enable-active-high;
+               vin-supply = <&mt6366_vio18_reg>;
+       };
+
+       pp3300_disp_x: regulator-pp3300-disp-x {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&edp_panel_fixed_pins>;
+               gpios = <&pio 153 GPIO_ACTIVE_HIGH>;
+               regulator-name = "pp3300_disp_x";
+               enable-active-high;
+               regulator-boot-on;
+               vin-supply = <&pp3300_z2>;
+       };
+
+       /* system wide LDO 3.3V power rail */
+       pp3300_z5: regulator-pp3300-ldo-z5 {
+               compatible = "regulator-fixed";
+               regulator-name = "pp3300_ldo_z5";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&ppvar_sys>;
+       };
+
+       /* separately switched 3.3V power rail */
+       pp3300_s3: regulator-pp3300-s3 {
+               compatible = "regulator-fixed";
+               regulator-name = "pp3300_s3";
+               /* automatically sequenced by PMIC EXT_PMIC_EN2 */
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&pp3300_z2>;
+       };
+
+       /* system wide 3.3V power rail */
+       pp3300_z2: regulator-pp3300-z2 {
+               compatible = "regulator-fixed";
+               regulator-name = "pp3300_z2";
+               /* EN pin tied to pp4200_z2, which is controlled by EC */
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&ppvar_sys>;
+       };
+
+       /* system wide 4.2V power rail */
+       pp4200_z2: regulator-pp4200-z2 {
+               compatible = "regulator-fixed";
+               regulator-name = "pp4200_z2";
+               /* controlled by EC */
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <4200000>;
+               regulator-max-microvolt = <4200000>;
+               vin-supply = <&ppvar_sys>;
+       };
+
+       /* system wide switching 5.0V power rail */
+       pp5000_z2: regulator-pp5000-z2 {
+               compatible = "regulator-fixed";
+               regulator-name = "pp5000_z2";
+               /* controlled by EC */
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&ppvar_sys>;
+       };
+
+       /* system wide semi-regulated power rail from battery or USB */
+       ppvar_sys: regulator-ppvar-sys {
+               compatible = "regulator-fixed";
+               regulator-name = "ppvar_sys";
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       reserved_memory: reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               adsp_dma_mem: memory@61000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x61000000 0 0x100000>;
+                       no-map;
+               };
+
+               adsp_mem: memory@60000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x60000000 0 0xA00000>;
+                       no-map;
+               };
+
+               scp_mem: memory@50000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x50000000 0 0x10a0000>;
+                       no-map;
+               };
+       };
+
+       sound: sound {
+               compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound";
+               pinctrl-names = "aud_clk_mosi_off",
+                               "aud_clk_mosi_on",
+                               "aud_clk_miso_off",
+                               "aud_clk_miso_on",
+                               "aud_dat_miso_off",
+                               "aud_dat_miso_on",
+                               "aud_dat_mosi_off",
+                               "aud_dat_mosi_on",
+                               "aud_gpio_i2s0_off",
+                               "aud_gpio_i2s0_on",
+                               "aud_gpio_i2s1_off",
+                               "aud_gpio_i2s1_on",
+                               "aud_gpio_i2s2_off",
+                               "aud_gpio_i2s2_on",
+                               "aud_gpio_i2s3_off",
+                               "aud_gpio_i2s3_on",
+                               "aud_gpio_pcm_off",
+                               "aud_gpio_pcm_on",
+                               "aud_gpio_dmic_sec";
+               pinctrl-0 = <&aud_clk_mosi_off>;
+               pinctrl-1 = <&aud_clk_mosi_on>;
+               pinctrl-2 = <&aud_clk_miso_off>;
+               pinctrl-3 = <&aud_clk_miso_on>;
+               pinctrl-4 = <&aud_dat_miso_off>;
+               pinctrl-5 = <&aud_dat_miso_on>;
+               pinctrl-6 = <&aud_dat_mosi_off>;
+               pinctrl-7 = <&aud_dat_mosi_on>;
+               pinctrl-8 = <&aud_gpio_i2s0_off>;
+               pinctrl-9 = <&aud_gpio_i2s0_on>;
+               pinctrl-10 = <&aud_gpio_i2s1_off>;
+               pinctrl-11 = <&aud_gpio_i2s1_on>;
+               pinctrl-12 = <&aud_gpio_i2s2_off>;
+               pinctrl-13 = <&aud_gpio_i2s2_on>;
+               pinctrl-14 = <&aud_gpio_i2s3_off>;
+               pinctrl-15 = <&aud_gpio_i2s3_on>;
+               pinctrl-16 = <&aud_gpio_pcm_off>;
+               pinctrl-17 = <&aud_gpio_pcm_on>;
+               pinctrl-18 = <&aud_gpio_dmic_sec>;
+               mediatek,adsp = <&adsp>;
+               mediatek,platform = <&afe>;
+
+               playback-codecs {
+                       sound-dai = <&it6505dptx>, <&rt1019p>;
+               };
+
+               headset-codec {
+                       sound-dai = <&rt5682s 0>;
+               };
+       };
+
+       rt1019p: speaker-codec {
+               compatible = "realtek,rt1019p";
+               pinctrl-names = "default";
+               pinctrl-0 = <&rt1019p_pins_default>;
+               #sound-dai-cells = <0>;
+               sdb-gpios = <&pio 150 GPIO_ACTIVE_HIGH>;
+       };
+
+       usb_p1_vbus: regulator-usb-p1-vbus {
+               compatible = "regulator-fixed";
+               gpio = <&pio 148 GPIO_ACTIVE_HIGH>;
+               regulator-name = "vbus1";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               enable-active-high;
+               vin-supply = <&pp5000_z2>;
+       };
+
+       wifi_pwrseq: wifi-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_enable_pin>;
+               post-power-on-delay-ms = <50>;
+               reset-gpios = <&pio 54 GPIO_ACTIVE_LOW>;
+       };
+
+       wifi_wakeup: wifi-wakeup {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_wakeup_pin>;
+
+               wowlan-event {
+                       label = "Wake on WiFi";
+                       gpios = <&pio 7 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_WAKEUP>;
+                       wakeup-source;
+               };
+       };
+};
+
+&adsp {
+       memory-region = <&adsp_dma_mem>, <&adsp_mem>;
+       status = "okay";
+};
+
+&afe {
+       status = "okay";
+};
+
+&cci {
+       proc-supply = <&mt6366_vproc12_reg>;
+};
+
+&cpu0 {
+       proc-supply = <&mt6366_vproc12_reg>;
+};
+
+&cpu1 {
+       proc-supply = <&mt6366_vproc12_reg>;
+};
+
+&cpu2 {
+       proc-supply = <&mt6366_vproc12_reg>;
+};
+
+&cpu3 {
+       proc-supply = <&mt6366_vproc12_reg>;
+};
+
+&cpu4 {
+       proc-supply = <&mt6366_vproc12_reg>;
+};
+
+&cpu5 {
+       proc-supply = <&mt6366_vproc12_reg>;
+};
+
+&cpu6 {
+       proc-supply = <&mt6366_vproc11_reg>;
+};
+
+&cpu7 {
+       proc-supply = <&mt6366_vproc11_reg>;
+};
+
+&dpi {
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&dpi_pins_default>;
+       pinctrl-1 = <&dpi_pins_sleep>;
+       status = "okay";
+};
+
+&dpi_out {
+       remote-endpoint = <&it6505_in>;
+};
+
+&dsi0 {
+       status = "okay";
+};
+
+&gic {
+       mediatek,broken-save-restore-fw;
+};
+
+&gpu {
+       mali-supply = <&mt6366_vgpu_reg>;
+       status = "okay";
+};
+
+&i2c0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c0_pins>;
+       status = "okay";
+};
+
+&i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c1_pins>;
+       clock-frequency = <400000>;
+       i2c-scl-internal-delay-ns = <8000>;
+       status = "okay";
+};
+
+&i2c2 {
+       pinctrl-names = "default";
+       /*
+        * Trackpad pin put here to work around second source components
+        * sharing the pinmux in steelix designs.
+        */
+       pinctrl-0 = <&i2c2_pins>, <&trackpad_pin>;
+       clock-frequency = <400000>;
+       i2c-scl-internal-delay-ns = <10000>;
+       status = "okay";
+
+       trackpad@15 {
+               compatible = "elan,ekth3000";
+               reg = <0x15>;
+               interrupts-extended = <&pio 11 IRQ_TYPE_LEVEL_LOW>;
+               vcc-supply = <&pp3300_s3>;
+               wakeup-source;
+       };
+};
+
+&i2c3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c3_pins>;
+       clock-frequency = <100000>;
+       status = "okay";
+
+       it6505dptx: dp-bridge@5c {
+               compatible = "ite,it6505";
+               reg = <0x5c>;
+               interrupts-extended = <&pio 8 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&it6505_pins>;
+               #sound-dai-cells = <0>;
+               ovdd-supply = <&mt6366_vsim2_reg>;
+               pwr18-supply = <&pp1800_dpbrdg_dx>;
+               reset-gpios = <&pio 177 GPIO_ACTIVE_HIGH>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               it6505_in: endpoint {
+                                       link-frequencies = /bits/ 64 <150000000>;
+                                       remote-endpoint = <&dpi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+                       };
+               };
+       };
+};
+
+&i2c5 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c5_pins>;
+       status = "okay";
+
+       rt5682s: codec@1a {
+               compatible = "realtek,rt5682s";
+               reg = <0x1a>;
+               interrupts-extended = <&pio 17 IRQ_TYPE_EDGE_BOTH>;
+               #sound-dai-cells = <1>;
+               AVDD-supply = <&mt6366_vio18_reg>;
+               DBVDD-supply = <&mt6366_vio18_reg>;
+               LDO1-IN-supply = <&mt6366_vio18_reg>;
+               MICVDD-supply = <&pp3300_z2>;
+               realtek,jd-src = <1>;
+       };
+};
+
+&mfg0 {
+       domain-supply = <&mt6366_vsram_gpu_reg>;
+};
+
+&mfg1 {
+       domain-supply = <&mt6366_vgpu_reg>;
+};
+
+&mipi_tx0 {
+       status = "okay";
+};
+
+&mmc0 {
+       pinctrl-names = "default", "state_uhs";
+       pinctrl-0 = <&mmc0_pins_default>;
+       pinctrl-1 = <&mmc0_pins_uhs>;
+       bus-width = <8>;
+       max-frequency = <200000000>;
+       non-removable;
+       cap-mmc-highspeed;
+       mmc-hs200-1_8v;
+       mmc-hs400-1_8v;
+       supports-cqe;
+       no-sd;
+       no-sdio;
+       cap-mmc-hw-reset;
+       hs400-ds-delay = <0x11814>;
+       mediatek,hs400-ds-dly3 = <0x14>;
+       vmmc-supply = <&mt6366_vemc_reg>;
+       vqmmc-supply = <&mt6366_vio18_reg>;
+       status = "okay";
+};
+
+&mmc1 {
+       pinctrl-names = "default", "state_uhs", "state_eint";
+       pinctrl-0 = <&mmc1_pins_default>;
+       pinctrl-1 = <&mmc1_pins_uhs>;
+       pinctrl-2 = <&mmc1_pins_eint>;
+       /delete-property/ interrupts;
+       interrupt-names = "msdc", "sdio_wakeup";
+       interrupts-extended = <&gic GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH 0>,
+                             <&pio 87 IRQ_TYPE_LEVEL_LOW>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       bus-width = <4>;
+       max-frequency = <200000000>;
+       cap-sd-highspeed;
+       sd-uhs-sdr104;
+       sd-uhs-sdr50;
+       keep-power-in-suspend;
+       wakeup-source;
+       cap-sdio-irq;
+       no-mmc;
+       no-sd;
+       non-removable;
+       vmmc-supply = <&pp3300_s3>;
+       vqmmc-supply = <&mt6366_vio18_reg>;
+       mmc-pwrseq = <&wifi_pwrseq>;
+       status = "okay";
+
+       bluetooth@2 {
+               compatible = "mediatek,mt7921s-bluetooth";
+               reg = <2>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&bt_pins_reset>;
+               reset-gpios = <&pio 155 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&nor_flash {
+       assigned-clock-parents = <&topckgen CLK_TOP_MAINPLL_D7_D4>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&nor_pins_default>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "okay";
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <39000000>;
+       };
+};
+
+&pio {
+       /* 185 lines */
+       gpio-line-names = "TP",
+                         "TP",
+                         "TP",
+                         "I2S0_HP_DI",
+                         "I2S3_DP_SPKR_DO",
+                         "SAR_INT_ODL",
+                         "BT_WAKE_AP_ODL",
+                         "WIFI_INT_ODL",
+                         "DPBRDG_INT_ODL",
+                         "EDPBRDG_INT_ODL",
+                         "EC_AP_HPD_OD",
+                         "TCHPAD_INT_ODL",
+                         "TCHSCR_INT_1V8_ODL",
+                         "EC_AP_INT_ODL",
+                         "EC_IN_RW_ODL",
+                         "GSC_AP_INT_ODL",
+                         /* AP_FLASH_WP_L is crossystem ABI. Rev1 schematics call it AP_WP_ODL. */
+                         "AP_FLASH_WP_L",
+                         "HP_INT_ODL",
+                         "PEN_EJECT_OD",
+                         "WCAM_PWDN_L",
+                         "WCAM_RST_L",
+                         "UCAM_SEN_EN",
+                         "UCAM_RST_L",
+                         "LTE_RESET_L",
+                         "LTE_SAR_DETECT_L",
+                         "I2S2_DP_SPK_MCK",
+                         "I2S2_DP_SPKR_BCK",
+                         "I2S2_DP_SPKR_LRCK",
+                         "I2S2_DP_SPKR_DI (TP)",
+                         "EN_PP1000_EDPBRDG",
+                         "EN_PP1800_EDPBRDG",
+                         "EN_PP3300_EDPBRDG",
+                         "UART_GSC_TX_AP_RX",
+                         "UART_AP_TX_GSC_RX",
+                         "UART_DBGCON_TX_ADSP_RX",
+                         "UART_ADSP_TX_DBGCON_RX",
+                         "EN_PP1000_DPBRDG",
+                         "TCHSCR_REPORT_DISABLE",
+                         "EN_PP3300_DPBRDG",
+                         "EN_PP1800_DPBRDG",
+                         "SPI_AP_CLK_EC",
+                         "SPI_AP_CS_EC_L",
+                         "SPI_AP_DO_EC_DI",
+                         "SPI_AP_DI_EC_DO",
+                         "SPI_AP_CLK_GSC",
+                         "SPI_AP_CS_GSC_L",
+                         "SPI_AP_DO_GSC_DI",
+                         "SPI_AP_DI_GSC_DO",
+                         "UART_DBGCON_TX_SCP_RX",
+                         "UART_SCP_TX_DBGCON_RX",
+                         "EN_PP1200_CAM_X",
+                         "EN_PP2800A_VCM_X",
+                         "EN_PP2800A_UCAM_X",
+                         "EN_PP2800A_WCAM_X",
+                         "WLAN_MODULE_RST_L",
+                         "EN_PP1200_UCAM_X",
+                         "I2S1_HP_DO",
+                         "I2S1_HP_BCK",
+                         "I2S1_HP_LRCK",
+                         "I2S1_HP_MCK",
+                         "TCHSCR_RST_1V8_L",
+                         "SPI_AP_CLK_ROM",
+                         "SPI_AP_CS_ROM_L",
+                         "SPI_AP_DO_ROM_DI",
+                         "SPI_AP_DI_ROM_DO",
+                         "NC",
+                         "NC",
+                         "EMMC_STRB",
+                         "EMMC_CLK",
+                         "EMMC_CMD",
+                         "EMMC_RST_L",
+                         "EMMC_DATA0",
+                         "EMMC_DATA1",
+                         "EMMC_DATA2",
+                         "EMMC_DATA3",
+                         "EMMC_DATA4",
+                         "EMMC_DATA5",
+                         "EMMC_DATA6",
+                         "EMMC_DATA7",
+                         "AP_KPCOL0",
+                         "NC",
+                         "NC",
+                         "NC",
+                         "TP",
+                         "SDIO_CLK",
+                         "SDIO_CMD",
+                         "SDIO_DATA0",
+                         "SDIO_DATA1",
+                         "SDIO_DATA2",
+                         "SDIO_DATA3",
+                         "NC",
+                         "NC",
+                         "NC",
+                         "NC",
+                         "NC",
+                         "NC",
+                         "EDPBRDG_PWREN",
+                         "BL_PWM_1V8",
+                         "EDPBRDG_RST_L",
+                         "MIPI_DPI_CLK",
+                         "MIPI_DPI_VSYNC",
+                         "MIPI_DPI_HSYNC",
+                         "MIPI_DPI_DE",
+                         "MIPI_DPI_D0",
+                         "MIPI_DPI_D1",
+                         "MIPI_DPI_D2",
+                         "MIPI_DPI_D3",
+                         "MIPI_DPI_D4",
+                         "MIPI_DPI_D5",
+                         "MIPI_DPI_D6",
+                         "MIPI_DPI_DA7",
+                         "MIPI_DPI_D8",
+                         "MIPI_DPI_D9",
+                         "MIPI_DPI_D10",
+                         "MIPI_DPI_D11",
+                         "PCM_BT_CLK",
+                         "PCM_BT_SYNC",
+                         "PCM_BT_DI",
+                         "PCM_BT_DO",
+                         "JTAG_TMS_TP",
+                         "JTAG_TCK_TP",
+                         "JTAG_TDI_TP",
+                         "JTAG_TDO_TP",
+                         "JTAG_TRSTN_TP",
+                         "CLK_24M_WCAM",
+                         "CLK_24M_UCAM",
+                         "UCAM_DET_ODL",
+                         "AP_I2C_EDPBRDG_SCL_1V8",
+                         "AP_I2C_EDPBRDG_SDA_1V8",
+                         "AP_I2C_TCHSCR_SCL_1V8",
+                         "AP_I2C_TCHSCR_SDA_1V8",
+                         "AP_I2C_TCHPAD_SCL_1V8",
+                         "AP_I2C_TCHPAD_SDA_1V8",
+                         "AP_I2C_DPBRDG_SCL_1V8",
+                         "AP_I2C_DPBRDG_SDA_1V8",
+                         "AP_I2C_WLAN_SCL_1V8",
+                         "AP_I2C_WLAN_SDA_1V8",
+                         "AP_I2C_AUD_SCL_1V8",
+                         "AP_I2C_AUD_SDA_1V8",
+                         "AP_I2C_TPM_SCL_1V8",
+                         "AP_I2C_UCAM_SDA_1V8",
+                         "AP_I2C_UCAM_SCL_1V8",
+                         "AP_I2C_UCAM_SDA_1V8",
+                         "AP_I2C_WCAM_SCL_1V8",
+                         "AP_I2C_WCAM_SDA_1V8",
+                         "SCP_I2C_SENSOR_SCL_1V8",
+                         "SCP_I2C_SENSOR_SDA_1V8",
+                         "AP_EC_WARM_RST_REQ",
+                         "AP_XHCI_INIT_DONE",
+                         "USB3_HUB_RST_L",
+                         "EN_SPKR",
+                         "BEEP_ON",
+                         "AP_EDP_BKLTEN",
+                         "EN_PP3300_DISP_X",
+                         "EN_PP3300_SDBRDG_X",
+                         "BT_KILL_1V8_L",
+                         "WIFI_KILL_1V8_L",
+                         "PWRAP_SPI0_CSN",
+                         "PWRAP_SPI0_CK",
+                         "PWRAP_SPI0_MO",
+                         "PWRAP_SPI0_MI",
+                         "SRCLKENA0",
+                         "SRCLKENA1",
+                         "SCP_VREQ_VAO",
+                         "AP_RTC_CLK32K",
+                         "AP_PMIC_WDTRST_L",
+                         "AUD_CLK_MOSI",
+                         "AUD_SYNC_MOSI",
+                         "AUD_DAT_MOSI0",
+                         "AUD_DAT_MOSI1",
+                         "AUD_CLK_MISO",
+                         "AUD_SYNC_MISO",
+                         "AUD_DAT_MISO0",
+                         "AUD_DAT_MISO1",
+                         "NC",
+                         "NC",
+                         "DPBRDG_PWREN",
+                         "DPBRDG_RST_L",
+                         "LTE_W_DISABLE_L",
+                         "LTE_SAR_DETECT_L",
+                         "EN_PP3300_LTE_X",
+                         "LTE_PWR_OFF_L",
+                         "LTE_RESET_L",
+                         "TP",
+                         "TP";
+
+       aud_clk_mosi_off: aud-clk-mosi-off-pins {
+               pins-clk-sync {
+                       pinmux = <PINMUX_GPIO166__FUNC_GPIO166>,
+                                <PINMUX_GPIO167__FUNC_GPIO167>;
+                       input-enable;
+                       bias-pull-down;
+               };
+       };
+
+       aud_clk_mosi_on: aud-clk-mosi-on-pins {
+               pins-clk-sync {
+                       pinmux = <PINMUX_GPIO166__FUNC_AUD_CLK_MOSI>,
+                                <PINMUX_GPIO167__FUNC_AUD_SYNC_MOSI>;
+               };
+       };
+
+       aud_clk_miso_off: aud-clk-miso-off-pins {
+               pins-clk-sync {
+                       pinmux = <PINMUX_GPIO170__FUNC_GPIO170>,
+                                <PINMUX_GPIO171__FUNC_GPIO171>;
+                       input-enable;
+                       bias-pull-down;
+               };
+       };
+
+       aud_clk_miso_on: aud-clk-miso-on-pins {
+               pins-clk-sync {
+                       pinmux = <PINMUX_GPIO170__FUNC_AUD_CLK_MISO>,
+                                <PINMUX_GPIO171__FUNC_AUD_SYNC_MISO>;
+               };
+       };
+
+       aud_dat_mosi_off: aud-dat-mosi-off-pins {
+               pins-dat {
+                       pinmux = <PINMUX_GPIO168__FUNC_GPIO168>,
+                                <PINMUX_GPIO169__FUNC_GPIO169>;
+                       input-enable;
+                       bias-pull-down;
+               };
+       };
+
+       aud_dat_mosi_on: aud-dat-mosi-on-pins {
+               pins-dat {
+                       pinmux = <PINMUX_GPIO168__FUNC_AUD_DAT_MOSI0>,
+                                <PINMUX_GPIO169__FUNC_AUD_DAT_MOSI1>;
+               };
+       };
+
+       aud_dat_miso_off: aud-dat-miso-off-pins {
+               pins-dat {
+                       pinmux = <PINMUX_GPIO172__FUNC_GPIO172>,
+                                <PINMUX_GPIO173__FUNC_GPIO173>;
+                       input-enable;
+                       bias-pull-down;
+               };
+       };
+
+       aud_dat_miso_on: aud-dat-miso-on-pins {
+               pins-dat {
+                       pinmux = <PINMUX_GPIO172__FUNC_AUD_DAT_MISO0>,
+                                <PINMUX_GPIO173__FUNC_AUD_DAT_MISO1>;
+                       input-schmitt-enable;
+                       bias-disable;
+               };
+       };
+
+       aud_gpio_i2s0_off: aud-gpio-i2s0-off-pins {
+               pins-sdata {
+                       pinmux = <PINMUX_GPIO3__FUNC_GPIO3>;
+               };
+       };
+
+       aud_gpio_i2s0_on: aud-gpio-i2s0-on-pins {
+               pins-sdata {
+                       pinmux = <PINMUX_GPIO3__FUNC_I2S0_DI>;
+               };
+       };
+
+       aud_gpio_i2s1_off: aud-gpio-i2s-off-pins {
+               pins-clk-sdata {
+                       pinmux = <PINMUX_GPIO56__FUNC_GPIO56>,
+                                <PINMUX_GPIO57__FUNC_GPIO57>,
+                                <PINMUX_GPIO58__FUNC_GPIO58>,
+                                <PINMUX_GPIO59__FUNC_GPIO59>;
+                       output-low;
+               };
+       };
+
+       aud_gpio_i2s1_on: aud-gpio-i2s1-on-pins {
+               pins-clk-sdata {
+                       pinmux = <PINMUX_GPIO56__FUNC_I2S1_DO>,
+                                <PINMUX_GPIO57__FUNC_I2S1_BCK>,
+                                <PINMUX_GPIO58__FUNC_I2S1_LRCK>,
+                                <PINMUX_GPIO59__FUNC_I2S1_MCK>;
+               };
+       };
+
+       aud_gpio_i2s2_off: aud-gpio-i2s2-off-pins {
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO26__FUNC_GPIO26>,
+                                <PINMUX_GPIO27__FUNC_GPIO27>;
+                       output-low;
+               };
+       };
+
+       aud_gpio_i2s2_on: aud-gpio-i2s2-on-pins {
+               pins-clk {
+                       pinmux = <PINMUX_GPIO26__FUNC_I2S2_BCK>,
+                                <PINMUX_GPIO27__FUNC_I2S2_LRCK>;
+                       drive-strength = <4>;
+               };
+       };
+
+       aud_gpio_i2s3_off: aud-gpio-i2s3-off-pins {
+               pins-sdata {
+                       pinmux = <PINMUX_GPIO4__FUNC_GPIO4>;
+                       output-low;
+               };
+       };
+
+       aud_gpio_i2s3_on: aud-gpio-i2s3-on-pins {
+               pins-sdata {
+                       pinmux = <PINMUX_GPIO4__FUNC_I2S3_DO>;
+                       drive-strength = <4>;
+               };
+       };
+
+       aud_gpio_pcm_off: aud-gpio-pcm-off-pins {
+               pins-clk-sdata {
+                       pinmux = <PINMUX_GPIO115__FUNC_GPIO115>,
+                                <PINMUX_GPIO116__FUNC_GPIO116>,
+                                <PINMUX_GPIO117__FUNC_GPIO117>,
+                                <PINMUX_GPIO118__FUNC_GPIO118>;
+                       output-low;
+               };
+       };
+
+       aud_gpio_pcm_on: aud-gpio-pcm-on-pins {
+               pins-clk-sdata {
+                       pinmux = <PINMUX_GPIO115__FUNC_PCM_CLK>,
+                                <PINMUX_GPIO116__FUNC_PCM_SYNC>,
+                                <PINMUX_GPIO117__FUNC_PCM_DI>,
+                                <PINMUX_GPIO118__FUNC_PCM_DO>;
+               };
+       };
+
+       aud_gpio_dmic_sec: aud-gpio-dmic-sec-pins {
+               pins {
+                       pinmux = <PINMUX_GPIO23__FUNC_GPIO23>;
+                       output-low;
+               };
+       };
+
+       bt_pins_reset: bt-reset-pins {
+               pins-bt-reset {
+                       pinmux = <PINMUX_GPIO155__FUNC_GPIO155>;
+                       output-high;
+               };
+       };
+
+       dpi_pins_sleep: dpi-sleep-pins {
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO103__FUNC_GPIO103>,
+                                <PINMUX_GPIO104__FUNC_GPIO104>,
+                                <PINMUX_GPIO105__FUNC_GPIO105>,
+                                <PINMUX_GPIO106__FUNC_GPIO106>,
+                                <PINMUX_GPIO107__FUNC_GPIO107>,
+                                <PINMUX_GPIO108__FUNC_GPIO108>,
+                                <PINMUX_GPIO109__FUNC_GPIO109>,
+                                <PINMUX_GPIO110__FUNC_GPIO110>,
+                                <PINMUX_GPIO111__FUNC_GPIO111>,
+                                <PINMUX_GPIO112__FUNC_GPIO112>,
+                                <PINMUX_GPIO113__FUNC_GPIO113>,
+                                <PINMUX_GPIO114__FUNC_GPIO114>,
+                                <PINMUX_GPIO101__FUNC_GPIO101>,
+                                <PINMUX_GPIO100__FUNC_GPIO100>,
+                                <PINMUX_GPIO102__FUNC_GPIO102>,
+                                <PINMUX_GPIO99__FUNC_GPIO99>;
+                       drive-strength = <10>;
+                       output-low;
+               };
+       };
+
+       dpi_pins_default: dpi-default-pins {
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO103__FUNC_DPI_DATA0>,
+                                <PINMUX_GPIO104__FUNC_DPI_DATA1>,
+                                <PINMUX_GPIO105__FUNC_DPI_DATA2>,
+                                <PINMUX_GPIO106__FUNC_DPI_DATA3>,
+                                <PINMUX_GPIO107__FUNC_DPI_DATA4>,
+                                <PINMUX_GPIO108__FUNC_DPI_DATA5>,
+                                <PINMUX_GPIO109__FUNC_DPI_DATA6>,
+                                <PINMUX_GPIO110__FUNC_DPI_DATA7>,
+                                <PINMUX_GPIO111__FUNC_DPI_DATA8>,
+                                <PINMUX_GPIO112__FUNC_DPI_DATA9>,
+                                <PINMUX_GPIO113__FUNC_DPI_DATA10>,
+                                <PINMUX_GPIO114__FUNC_DPI_DATA11>,
+                                <PINMUX_GPIO101__FUNC_DPI_HSYNC>,
+                                <PINMUX_GPIO100__FUNC_DPI_VSYNC>,
+                                <PINMUX_GPIO102__FUNC_DPI_DE>,
+                                <PINMUX_GPIO99__FUNC_DPI_PCLK>;
+                       drive-strength = <10>;
+               };
+       };
+
+       ec_ap_int: cros-ec-int-pins {
+               pins-ec-ap-int-odl {
+                       pinmux = <PINMUX_GPIO13__FUNC_GPIO13>;
+                       input-enable;
+               };
+       };
+
+       edp_panel_fixed_pins: edp-panel-fixed-pins {
+               pins-vreg-en {
+                       pinmux = <PINMUX_GPIO153__FUNC_GPIO153>;
+                       output-high;
+               };
+       };
+
+       en_pp1800_dpbrdg: en-pp1800-dpbrdg-pins {
+               pins-vreg-en {
+                       pinmux = <PINMUX_GPIO39__FUNC_GPIO39>;
+                       output-low;
+               };
+       };
+
+       gsc_int: gsc-int-pins {
+               pins-gsc-ap-int-odl {
+                       pinmux = <PINMUX_GPIO15__FUNC_GPIO15>;
+                       input-enable;
+               };
+       };
+
+       i2c0_pins: i2c0-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO128__FUNC_SDA0>,
+                                <PINMUX_GPIO127__FUNC_SCL0>;
+                       bias-disable;
+                       drive-strength = <4>;
+                       input-enable;
+               };
+       };
+
+       i2c1_pins: i2c1-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO130__FUNC_SDA1>,
+                                <PINMUX_GPIO129__FUNC_SCL1>;
+                       bias-disable;
+                       drive-strength = <4>;
+                       input-enable;
+               };
+       };
+
+       i2c2_pins: i2c2-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO132__FUNC_SDA2>,
+                                <PINMUX_GPIO131__FUNC_SCL2>;
+                       bias-disable;
+                       drive-strength = <4>;
+                       input-enable;
+               };
+       };
+
+       i2c3_pins: i2c3-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO134__FUNC_SDA3>,
+                                <PINMUX_GPIO133__FUNC_SCL3>;
+                       bias-disable;
+                       drive-strength = <4>;
+                       input-enable;
+               };
+       };
+
+       i2c5_pins: i2c5-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO138__FUNC_SDA5>,
+                                <PINMUX_GPIO137__FUNC_SCL5>;
+                       bias-disable;
+                       drive-strength = <4>;
+                       input-enable;
+               };
+       };
+
+       it6505_pins: it6505-pins {
+               pins-hpd {
+                       pinmux = <PINMUX_GPIO10__FUNC_GPIO10>;
+                       input-enable;
+                       bias-pull-up;
+               };
+
+               pins-int {
+                       pinmux = <PINMUX_GPIO8__FUNC_GPIO8>;
+                       input-enable;
+                       bias-pull-up;
+               };
+
+               pins-reset {
+                       pinmux = <PINMUX_GPIO177__FUNC_GPIO177>;
+                       output-low;
+                       bias-pull-up;
+               };
+       };
+
+       mmc0_pins_default: mmc0-default-pins {
+               pins-clk {
+                       pinmux = <PINMUX_GPIO68__FUNC_MSDC0_CLK>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO71__FUNC_MSDC0_DAT0>,
+                                <PINMUX_GPIO72__FUNC_MSDC0_DAT1>,
+                                <PINMUX_GPIO73__FUNC_MSDC0_DAT2>,
+                                <PINMUX_GPIO74__FUNC_MSDC0_DAT3>,
+                                <PINMUX_GPIO75__FUNC_MSDC0_DAT4>,
+                                <PINMUX_GPIO76__FUNC_MSDC0_DAT5>,
+                                <PINMUX_GPIO77__FUNC_MSDC0_DAT6>,
+                                <PINMUX_GPIO78__FUNC_MSDC0_DAT7>,
+                                <PINMUX_GPIO69__FUNC_MSDC0_CMD>;
+                       input-enable;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+
+               pins-rst {
+                       pinmux = <PINMUX_GPIO70__FUNC_MSDC0_RSTB>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+       };
+
+       mmc0_pins_uhs: mmc0-uhs-pins {
+               pins-clk {
+                       pinmux = <PINMUX_GPIO68__FUNC_MSDC0_CLK>;
+                       drive-strength = <6>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO71__FUNC_MSDC0_DAT0>,
+                                <PINMUX_GPIO72__FUNC_MSDC0_DAT1>,
+                                <PINMUX_GPIO73__FUNC_MSDC0_DAT2>,
+                                <PINMUX_GPIO74__FUNC_MSDC0_DAT3>,
+                                <PINMUX_GPIO75__FUNC_MSDC0_DAT4>,
+                                <PINMUX_GPIO76__FUNC_MSDC0_DAT5>,
+                                <PINMUX_GPIO77__FUNC_MSDC0_DAT6>,
+                                <PINMUX_GPIO78__FUNC_MSDC0_DAT7>,
+                                <PINMUX_GPIO69__FUNC_MSDC0_CMD>;
+                       input-enable;
+                       drive-strength = <6>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+
+               pins-ds {
+                       pinmux = <PINMUX_GPIO67__FUNC_MSDC0_DSL>;
+                       drive-strength = <6>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+
+               pins-rst {
+                       pinmux = <PINMUX_GPIO70__FUNC_MSDC0_RSTB>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+       };
+
+       mmc1_pins_default: mmc1-default-pins {
+               pins-clk {
+                       pinmux = <PINMUX_GPIO84__FUNC_MSDC1_CLK>;
+                       drive-strength = <6>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO86__FUNC_MSDC1_DAT0>,
+                                <PINMUX_GPIO87__FUNC_MSDC1_DAT1>,
+                                <PINMUX_GPIO88__FUNC_MSDC1_DAT2>,
+                                <PINMUX_GPIO89__FUNC_MSDC1_DAT3>,
+                                <PINMUX_GPIO85__FUNC_MSDC1_CMD>;
+                       input-enable;
+                       drive-strength = <6>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+       };
+
+       mmc1_pins_uhs: mmc1-uhs-pins {
+               pins-clk {
+                       pinmux = <PINMUX_GPIO84__FUNC_MSDC1_CLK>;
+                       drive-strength = <6>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO86__FUNC_MSDC1_DAT0>,
+                                <PINMUX_GPIO87__FUNC_MSDC1_DAT1>,
+                                <PINMUX_GPIO88__FUNC_MSDC1_DAT2>,
+                                <PINMUX_GPIO89__FUNC_MSDC1_DAT3>,
+                                <PINMUX_GPIO85__FUNC_MSDC1_CMD>;
+                       input-enable;
+                       drive-strength = <8>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+       };
+
+       mmc1_pins_eint: mmc1-eint-pins {
+               pins-dat1 {
+                       pinmux = <PINMUX_GPIO87__FUNC_GPIO87>;
+                       input-enable;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+       };
+
+       nor_pins_default: nor-default-pins {
+               pins-clk-dat {
+                       pinmux = <PINMUX_GPIO63__FUNC_SPINOR_IO0>,
+                                <PINMUX_GPIO61__FUNC_SPINOR_CK>,
+                                <PINMUX_GPIO64__FUNC_SPINOR_IO1>;
+                       drive-strength = <6>;
+                       bias-pull-down;
+               };
+
+               pins-cs-dat {
+                       pinmux = <PINMUX_GPIO62__FUNC_SPINOR_CS>,
+                                <PINMUX_GPIO65__FUNC_SPINOR_IO2>,
+                                <PINMUX_GPIO66__FUNC_SPINOR_IO3>;
+                       drive-strength = <6>;
+                       bias-pull-up;
+               };
+       };
+
+       pen_eject: pen-eject-pins {
+               pins {
+                       pinmux = <PINMUX_GPIO18__FUNC_GPIO18>;
+                       input-enable;
+                       /* External pull-up. */
+                       bias-disable;
+               };
+       };
+
+       pwm0_pin: disp-pwm-pins {
+               pins {
+                       pinmux = <PINMUX_GPIO97__FUNC_DISP_PWM>;
+                       output-high;
+               };
+       };
+
+       rt1019p_pins_default: rt1019p-default-pins {
+               pins-sdb {
+                       pinmux = <PINMUX_GPIO150__FUNC_GPIO150>;
+                       output-low;
+               };
+       };
+
+       scp_pins: scp-default-pins {
+               pins-scp-uart {
+                       pinmux = <PINMUX_GPIO48__FUNC_TP_URXD2_AO>,
+                                <PINMUX_GPIO49__FUNC_TP_UTXD2_AO>;
+               };
+       };
+
+       spi1_pins: spi1-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO40__FUNC_SPI1_CLK_A>,
+                                <PINMUX_GPIO41__FUNC_SPI1_CSB_A>,
+                                <PINMUX_GPIO42__FUNC_SPI1_MO_A>,
+                                <PINMUX_GPIO43__FUNC_SPI1_MI_A>;
+                       bias-disable;
+                       input-enable;
+               };
+       };
+
+       spi2_pins: spi2-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO44__FUNC_SPI2_CLK_A>,
+                                <PINMUX_GPIO45__FUNC_GPIO45>,
+                                <PINMUX_GPIO46__FUNC_SPI2_MO_A>,
+                                <PINMUX_GPIO47__FUNC_SPI2_MI_A>;
+                       bias-disable;
+                       input-enable;
+               };
+       };
+
+       spmi_pins: spmi-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO183__FUNC_SPMI_SCL>,
+                                <PINMUX_GPIO184__FUNC_SPMI_SDA>;
+               };
+       };
+
+       touchscreen_pins: touchscreen-pins {
+               pins-irq {
+                       pinmux = <PINMUX_GPIO12__FUNC_GPIO12>;
+                       input-enable;
+                       bias-pull-up;
+               };
+
+               pins-reset {
+                       pinmux = <PINMUX_GPIO60__FUNC_GPIO60>;
+                       output-high;
+               };
+
+               pins-report-sw {
+                       pinmux = <PINMUX_GPIO37__FUNC_GPIO37>;
+                       output-low;
+               };
+       };
+
+       trackpad_pin: trackpad-default-pins {
+               pins-int-n {
+                       pinmux = <PINMUX_GPIO11__FUNC_GPIO11>;
+                       input-enable;
+                       bias-disable; /* pulled externally */
+               };
+       };
+
+       wifi_enable_pin: wifi-enable-pins {
+               pins-wifi-enable {
+                       pinmux = <PINMUX_GPIO54__FUNC_GPIO54>;
+               };
+       };
+
+       wifi_wakeup_pin: wifi-wakeup-pins {
+               pins-wifi-wakeup {
+                       pinmux = <PINMUX_GPIO7__FUNC_GPIO7>;
+                       input-enable;
+               };
+       };
+};
+
+&pwm0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pwm0_pin>;
+       status = "okay";
+};
+
+&pwrap {
+       pmic {
+               compatible = "mediatek,mt6366", "mediatek,mt6358";
+               interrupt-controller;
+               interrupts-extended = <&pio 201 IRQ_TYPE_LEVEL_HIGH>;
+               #interrupt-cells = <2>;
+
+               mt6366codec: codec {
+                       compatible = "mediatek,mt6366-sound", "mediatek,mt6358-sound";
+                       Avdd-supply = <&mt6366_vaud28_reg>;
+                       mediatek,dmic-mode = <1>; /* one-wire */
+               };
+
+               mt6366_regulators: regulators {
+                       compatible = "mediatek,mt6366-regulator", "mediatek,mt6358-regulator";
+                       vsys-ldo1-supply = <&pp4200_z2>;
+                       vsys-ldo2-supply = <&pp4200_z2>;
+                       vsys-ldo3-supply = <&pp4200_z2>;
+                       vsys-vcore-supply = <&pp4200_z2>;
+                       vsys-vdram1-supply = <&pp4200_z2>;
+                       vsys-vgpu-supply = <&pp4200_z2>;
+                       vsys-vmodem-supply = <&pp4200_z2>;
+                       vsys-vpa-supply = <&pp4200_z2>;
+                       vsys-vproc11-supply = <&pp4200_z2>;
+                       vsys-vproc12-supply = <&pp4200_z2>;
+                       vsys-vs1-supply = <&pp4200_z2>;
+                       vsys-vs2-supply = <&pp4200_z2>;
+                       vs1-ldo1-supply = <&mt6366_vs1_reg>;
+                       vs2-ldo1-supply = <&mt6366_vdram1_reg>;
+                       vs2-ldo2-supply = <&mt6366_vs2_reg>;
+                       vs2-ldo3-supply = <&mt6366_vs2_reg>;
+
+                       vcore {
+                               regulator-name = "pp0750_dvdd_core";
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <800000>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <200>;
+                               regulator-allowed-modes = <MT6397_BUCK_MODE_AUTO
+                                                          MT6397_BUCK_MODE_FORCE_PWM>;
+                               regulator-always-on;
+                       };
+
+                       mt6366_vdram1_reg: vdram1 {
+                               regulator-name = "pp1125_emi_vdd2";
+                               regulator-min-microvolt = <1125000>;
+                               regulator-max-microvolt = <1125000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <0>;
+                               regulator-allowed-modes = <MT6397_BUCK_MODE_AUTO
+                                                          MT6397_BUCK_MODE_FORCE_PWM>;
+                               regulator-always-on;
+                       };
+
+                       mt6366_vgpu_reg: vgpu {
+                               /*
+                                * Called "ppvar_dvdd_gpu" in the schematic.
+                                * Called "ppvar_dvdd_vgpu" here to match
+                                * regulator coupling requirements.
+                                */
+                               regulator-name = "ppvar_dvdd_vgpu";
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <200>;
+                               regulator-allowed-modes = <MT6397_BUCK_MODE_AUTO
+                                                          MT6397_BUCK_MODE_FORCE_PWM>;
+                               regulator-coupled-with = <&mt6366_vsram_gpu_reg>;
+                               regulator-coupled-max-spread = <10000>;
+                       };
+
+                       mt6366_vproc11_reg: vproc11 {
+                               regulator-name = "ppvar_dvdd_proc_bc_mt6366";
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <200>;
+                               regulator-allowed-modes = <MT6397_BUCK_MODE_AUTO
+                                                          MT6397_BUCK_MODE_FORCE_PWM>;
+                               regulator-always-on;
+                       };
+
+                       mt6366_vproc12_reg: vproc12 {
+                               regulator-name = "ppvar_dvdd_proc_lc";
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <200>;
+                               regulator-allowed-modes = <MT6397_BUCK_MODE_AUTO
+                                                          MT6397_BUCK_MODE_FORCE_PWM>;
+                               regulator-always-on;
+                       };
+
+                       mt6366_vs1_reg: vs1 {
+                               regulator-name = "pp2000_vs1";
+                               regulator-min-microvolt = <2000000>;
+                               regulator-max-microvolt = <2000000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <0>;
+                               regulator-always-on;
+                       };
+
+                       mt6366_vs2_reg: vs2 {
+                               regulator-name = "pp1350_vs2";
+                               regulator-min-microvolt = <1350000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <0>;
+                               regulator-always-on;
+                       };
+
+                       va12 {
+                               regulator-name = "pp1200_va12";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-enable-ramp-delay = <270>;
+                               regulator-always-on;
+                       };
+
+                       mt6366_vaud28_reg: vaud28 {
+                               regulator-name = "pp2800_vaud28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6366_vaux18_reg: vaux18 {
+                               regulator-name = "pp1840_vaux18";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1840000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6366_vbif28_reg: vbif28 {
+                               regulator-name = "pp2800_vbif28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6366_vcn18_reg: vcn18 {
+                               regulator-name = "pp1800_vcn18_x";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6366_vcn28_reg: vcn28 {
+                               regulator-name = "pp2800_vcn28_x";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6366_vefuse_reg: vefuse {
+                               regulator-name = "pp1800_vefuse";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6366_vfe28_reg: vfe28 {
+                               regulator-name = "pp2800_vfe28_x";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6366_vemc_reg: vemc {
+                               regulator-name = "pp3000_vemc";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-enable-ramp-delay = <60>;
+                       };
+
+                       mt6366_vibr_reg: vibr {
+                               regulator-name = "pp2800_vibr_x";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <60>;
+                       };
+
+                       mt6366_vio18_reg: vio18 {
+                               regulator-name = "pp1800_vio18_s3";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <2700>;
+                               regulator-always-on;
+                       };
+
+                       mt6366_vio28_reg: vio28 {
+                               regulator-name = "pp2800_vio28_x";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6366_vm18_reg: vm18 {
+                               regulator-name = "pp1800_emi_vdd1";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1840000>;
+                               regulator-enable-ramp-delay = <325>;
+                               regulator-always-on;
+                       };
+
+                       mt6366_vmc_reg: vmc {
+                               regulator-name = "pp3000_vmc";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-enable-ramp-delay = <60>;
+                       };
+
+                       mt6366_vmddr_reg: vmddr {
+                               regulator-name = "pm0750_emi_vmddr";
+                               regulator-min-microvolt = <700000>;
+                               regulator-max-microvolt = <750000>;
+                               regulator-enable-ramp-delay = <325>;
+                               regulator-always-on;
+                       };
+
+                       mt6366_vmch_reg: vmch {
+                               regulator-name = "pp3000_vmch";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-enable-ramp-delay = <60>;
+                       };
+
+                       mt6366_vcn33_reg: vcn33 {
+                               regulator-name = "pp3300_vcn33_x";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       vdram2 {
+                               regulator-name = "pp0600_emi_vddq";
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <600000>;
+                               regulator-enable-ramp-delay = <3300>;
+                               regulator-always-on;
+                       };
+
+                       mt6366_vrf12_reg: vrf12 {
+                               regulator-name = "pp1200_vrf12_x";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-enable-ramp-delay = <120>;
+                       };
+
+                       mt6366_vrf18_reg: vrf18 {
+                               regulator-name = "pp1800_vrf18_x";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <120>;
+                       };
+
+                       vsim1 {
+                               regulator-name = "pp1860_vsim1_x";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1860000>;
+                               regulator-enable-ramp-delay = <540>;
+                       };
+
+                       mt6366_vsim2_reg: vsim2 {
+                               regulator-name = "pp2760_vsim2_x";
+                               regulator-min-microvolt = <2700000>;
+                               regulator-max-microvolt = <2760000>;
+                               regulator-enable-ramp-delay = <540>;
+                       };
+
+                       mt6366_vsram_gpu_reg: vsram-gpu {
+                               regulator-name = "pp0900_dvdd_sram_gpu";
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <1050000>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <240>;
+                               regulator-coupled-with = <&mt6366_vgpu_reg>;
+                               regulator-coupled-max-spread = <10000>;
+                       };
+
+                       mt6366_vsram_others_reg: vsram-others {
+                               regulator-name = "pp0900_dvdd_sram_core";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <900000>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <240>;
+                               regulator-always-on;
+                       };
+
+                       mt6366_vsram_proc11_reg: vsram-proc11 {
+                               regulator-name = "pp0900_dvdd_sram_bc";
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <1120000>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <240>;
+                               regulator-always-on;
+                       };
+
+                       mt6366_vsram_proc12_reg: vsram-proc12 {
+                               regulator-name = "pp0900_dvdd_sram_lc";
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <1120000>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <240>;
+                               regulator-always-on;
+                       };
+
+                       vusb {
+                               regulator-name = "pp3070_vusb";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3070000>;
+                               regulator-enable-ramp-delay = <270>;
+                               regulator-always-on;
+                       };
+
+                       vxo22 {
+                               regulator-name = "pp2240_vxo22";
+                               regulator-min-microvolt = <2200000>;
+                               regulator-max-microvolt = <2240000>;
+                               regulator-enable-ramp-delay = <120>;
+                               /* Feeds DCXO internally */
+                               regulator-always-on;
+                       };
+               };
+
+               rtc {
+                       compatible = "mediatek,mt6366-rtc", "mediatek,mt6358-rtc";
+               };
+       };
+};
+
+&scp {
+       pinctrl-names = "default";
+       pinctrl-0 = <&scp_pins>;
+       firmware-name = "mediatek/mt8186/scp.img";
+       memory-region = <&scp_mem>;
+       status = "okay";
+
+       cros-ec-rpmsg {
+               compatible = "google,cros-ec-rpmsg";
+               mediatek,rpmsg-name = "cros-ec-rpmsg";
+       };
+};
+
+&spi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi1_pins>;
+       mediatek,pad-select = <0>;
+       status = "okay";
+
+       cros_ec: ec@0 {
+               compatible = "google,cros-ec-spi";
+               reg = <0>;
+               interrupts-extended = <&pio 13 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ec_ap_int>;
+               spi-max-frequency = <1000000>;
+
+               i2c_tunnel: i2c-tunnel {
+                       compatible = "google,cros-ec-i2c-tunnel";
+                       google,remote-bus = <1>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               typec {
+                       compatible = "google,cros-ec-typec";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       usb_c0: connector@0 {
+                               compatible = "usb-c-connector";
+                               reg = <0>;
+                               label = "left";
+                               power-role = "dual";
+                               data-role = "host";
+                               try-power-role = "source";
+                       };
+
+                       usb_c1: connector@1 {
+                               compatible = "usb-c-connector";
+                               reg = <1>;
+                               label = "right";
+                               power-role = "dual";
+                               data-role = "host";
+                               try-power-role = "source";
+                       };
+               };
+       };
+};
+
+&spi2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi2_pins>;
+       cs-gpios = <&pio 45 GPIO_ACTIVE_LOW>;
+       mediatek,pad-select = <0>;
+       status = "okay";
+
+       tpm@0 {
+               compatible = "google,cr50";
+               reg = <0>;
+               interrupts-extended = <&pio 15 IRQ_TYPE_EDGE_RISING>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&gsc_int>;
+               spi-max-frequency = <1000000>;
+       };
+};
+
+&ssusb0 {
+       status = "okay";
+};
+
+&ssusb1 {
+       status = "okay";
+};
+
+&u3phy0 {
+       status = "okay";
+};
+
+&u3phy1 {
+       status = "okay";
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&usb_host0 {
+       vbus-supply = <&pp3300_s3>;
+       status = "okay";
+};
+
+&usb_host1 {
+       vbus-supply = <&usb_p1_vbus>;
+       status = "okay";
+};
+
+&watchdog {
+       mediatek,reset-by-toprgu;
+};
+
+#include <arm/cros-ec-keyboard.dtsi>
+#include <arm/cros-ec-sbs.dtsi>
index 2fec6fd1c1a71db7477f4d211ff7be8750761264..4763ed5dc86cfb5ab8c0a9eafa5a766554f6240e 100644 (file)
 
                                power-domain@MT8186_POWER_DOMAIN_SSUSB {
                                        reg = <MT8186_POWER_DOMAIN_SSUSB>;
+                                       clocks = <&topckgen CLK_TOP_USB_TOP>,
+                                                <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_REF>;
+                                       clock-names = "sys_ck", "ref_ck";
                                        #power-domain-cells = <0>;
                                };
 
                                power-domain@MT8186_POWER_DOMAIN_SSUSB_P1 {
                                        reg = <MT8186_POWER_DOMAIN_SSUSB_P1>;
+                                       clocks = <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_SYS>,
+                                                <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_REF>;
+                                       clock-names = "sys_ck", "ref_ck";
                                        #power-domain-cells = <0>;
                                };
 
                                                reg = <MT8186_POWER_DOMAIN_VENC>;
                                                clocks = <&topckgen CLK_TOP_VENC>,
                                                         <&vencsys CLK_VENC_CKE1_VENC>;
-                                               clock-names = "venc0", "larb";
+                                               clock-names = "venc0", "subsys-larb";
                                                mediatek,infracfg = <&infracfg_ao>;
                                                #power-domain-cells = <0>;
                                        };
                        clocks = <&topckgen CLK_TOP_USB_TOP>,
                                 <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_REF>,
                                 <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_HCLK>,
-                                <&infracfg_ao CLK_INFRA_AO_ICUSB>;
-                       clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck";
+                                <&infracfg_ao CLK_INFRA_AO_ICUSB>,
+                                <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_XHCI>;
+                       clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck";
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH 0>;
                        phys = <&u2port0 PHY_TYPE_USB2>;
                        power-domains = <&spm MT8186_POWER_DOMAIN_SSUSB>;
                        clocks = <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_SYS>,
                                 <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_REF>,
                                 <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_HCLK>,
-                                <&clk26m>;
-                       clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck";
+                                <&clk26m>,
+                                <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_XHCI>;
+                       clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck";
                        interrupts = <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH 0>;
                        phys = <&u2port1 PHY_TYPE_USB2>, <&u3port1 PHY_TYPE_USB3>;
                        power-domains = <&spm MT8186_POWER_DOMAIN_SSUSB_P1>;
                                reg = <0x59c 0x4>;
                                bits = <0 3>;
                        };
+
+                       socinfo-data1@7a0 {
+                               reg = <0x7a0 0x4>;
+                       };
                };
 
                mipi_tx0: dsi-phy@11cc0000 {
                        power-domains = <&spm MT8186_POWER_DOMAIN_IMG2>;
                };
 
+               video_decoder: video-decoder@16000000 {
+                       compatible = "mediatek,mt8186-vcodec-dec";
+                       reg = <0 0x16000000 0 0x1000>;
+                       ranges;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>;
+                       iommus = <&iommu_mm IOMMU_PORT_L4_HW_VDEC_MC_EXT>;
+                       mediatek,scp = <&scp>;
+
+                       vcodec_core: video-codec@16025000 {
+                               compatible = "mediatek,mtk-vcodec-core";
+                               reg = <0 0x16025000 0 0x1000>;
+                               interrupts = <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH 0>;
+                               iommus = <&iommu_mm IOMMU_PORT_L4_HW_VDEC_MC_EXT>,
+                                        <&iommu_mm IOMMU_PORT_L4_HW_VDEC_UFO_EXT>,
+                                        <&iommu_mm IOMMU_PORT_L4_HW_VDEC_PP_EXT>,
+                                        <&iommu_mm IOMMU_PORT_L4_HW_VDEC_PRED_RD_EXT>,
+                                        <&iommu_mm IOMMU_PORT_L4_HW_VDEC_PRED_WR_EXT>,
+                                        <&iommu_mm IOMMU_PORT_L4_HW_VDEC_PPWRAP_EXT>,
+                                        <&iommu_mm IOMMU_PORT_L4_HW_VDEC_TILE_EXT>,
+                                        <&iommu_mm IOMMU_PORT_L4_HW_VDEC_VLD_EXT>,
+                                        <&iommu_mm IOMMU_PORT_L4_HW_VDEC_VLD2_EXT>,
+                                        <&iommu_mm IOMMU_PORT_L4_HW_VDEC_AVC_MV_EXT>,
+                                        <&iommu_mm IOMMU_PORT_L4_HW_VDEC_UFO_ENC_EXT>,
+                                        <&iommu_mm IOMMU_PORT_L4_HW_VDEC_RG_CTRL_DMA_EXT>;
+                               clocks = <&topckgen CLK_TOP_VDEC>,
+                                        <&vdecsys CLK_VDEC_CKEN>,
+                                        <&vdecsys CLK_VDEC_LARB1_CKEN>,
+                                        <&topckgen CLK_TOP_UNIVPLL_D3>;
+                               clock-names = "vdec-sel", "vdec-soc-vdec", "vdec", "vdec-top";
+                               assigned-clocks = <&topckgen CLK_TOP_VDEC>;
+                               assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D3>;
+                               power-domains = <&spm MT8186_POWER_DOMAIN_VDEC>;
+                       };
+               };
+
                larb4: smi@1602e000 {
                        compatible = "mediatek,mt8186-smi-larb";
                        reg = <0 0x1602e000 0 0x1000>;
                        power-domains = <&spm MT8186_POWER_DOMAIN_VENC>;
                };
 
+               venc: video-encoder@17020000 {
+                       compatible = "mediatek,mt8186-vcodec-enc", "mediatek,mt8183-vcodec-enc";
+                       reg = <0 0x17020000 0 0x2000>;
+                       interrupts = <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH 0>;
+                       iommus = <&iommu_mm IOMMU_PORT_L7_VENC_RCPU>,
+                                <&iommu_mm IOMMU_PORT_L7_VENC_REC>,
+                                <&iommu_mm IOMMU_PORT_L7_VENC_BSDMA>,
+                                <&iommu_mm IOMMU_PORT_L7_VENC_SV_COMV>,
+                                <&iommu_mm IOMMU_PORT_L7_VENC_RD_COMV>,
+                                <&iommu_mm IOMMU_PORT_L7_VENC_CUR_LUMA>,
+                                <&iommu_mm IOMMU_PORT_L7_VENC_CUR_CHROMA>,
+                                <&iommu_mm IOMMU_PORT_L7_VENC_REF_LUMA>,
+                                <&iommu_mm IOMMU_PORT_L7_VENC_REF_CHROMA>;
+                       clocks = <&vencsys CLK_VENC_CKE1_VENC>;
+                       clock-names = "venc_sel";
+                       assigned-clocks = <&topckgen CLK_TOP_VENC>;
+                       assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D3>;
+                       power-domains = <&spm MT8186_POWER_DOMAIN_VENC>;
+                       mediatek,scp = <&scp>;
+               };
+
+               jpgenc: jpeg-encoder@17030000 {
+                       compatible = "mediatek,mt8186-jpgenc", "mediatek,mtk-jpgenc";
+                       reg = <0 0x17030000 0 0x10000>;
+                       interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH 0>;
+                       clocks = <&vencsys CLK_VENC_CKE2_JPGENC>;
+                       clock-names = "jpgenc";
+                       iommus = <&iommu_mm IOMMU_PORT_L7_JPGENC_Y_RDMA>,
+                                <&iommu_mm IOMMU_PORT_L7_JPGENC_C_RDMA>,
+                                <&iommu_mm IOMMU_PORT_L7_JPGENC_Q_TABLE>,
+                                <&iommu_mm IOMMU_PORT_L7_JPGENC_BSDMA>;
+                       power-domains = <&spm MT8186_POWER_DOMAIN_VENC>;
+               };
+
                camsys: clock-controller@1a000000 {
                        compatible = "mediatek,mt8186-camsys";
                        reg = <0 0x1a000000 0 0x1000>;
index d87aab8d7a79ed4ac8365b951f16c370b2efcc91..9b738f6a5d213ada21fb98eef5ff223caa4dfdc7 100644 (file)
                spi-max-frequency = <3000000>;
                pinctrl-names = "default";
                pinctrl-0 = <&cros_ec_int>;
+               wakeup-source;
 
                #address-cells = <1>;
                #size-cells = <0>;
 
-               base_detection: cbas {
-                       compatible = "google,cros-cbas";
-               };
-
                cros_ec_pwm: pwm {
                        compatible = "google,cros-ec-pwm";
                        #pwm-cells = <1>;
index 6dd32dbfb832e7d8cdbb7c8a1c8098c6834329de..05e401670bced3abf9eed4117739f2e4f24e99ee 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
 
+                       socinfo-data1@44 {
+                               reg = <0x044 0x4>;
+                       };
+
+                       socinfo-data2@50 {
+                               reg = <0x050 0x4>;
+                       };
+
                        lvts_e_data1: data1@1c0 {
                                reg = <0x1c0 0x58>;
                        };
                        mediatek,scp = <&scp>;
                        power-domains = <&spm MT8192_POWER_DOMAIN_VENC>;
                        clocks = <&vencsys CLK_VENC_SET1_VENC>;
-                       clock-names = "venc-set1";
+                       clock-names = "venc_sel";
                        assigned-clocks = <&topckgen CLK_TOP_VENC_SEL>;
                        assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D4>;
                };
index 2d5e8f371b6def2c2881e48d8737e235d34bf599..a82d716f10d449a7f3e8737f356ce9b75af9a6f6 100644 (file)
@@ -23,3 +23,7 @@
 &ts_10 {
        status = "okay";
 };
+
+&watchdog {
+       /delete-property/ mediatek,disable-extrst;
+};
index 2586c32ce6e6fe6ee2ffef68e67944c4ff67c079..2fe20e0dad836d8b191d3f1e8b997d4e864cde19 100644 (file)
@@ -43,3 +43,7 @@
 &ts_10 {
        status = "okay";
 };
+
+&watchdog {
+       /delete-property/ mediatek,disable-extrst;
+};
index f54f9477b99dadcefbe6ee3a3a8cf4da65094c93..dd294ca98194ccfb2853f8f4a0b2e175618983b6 100644 (file)
@@ -44,3 +44,7 @@
 &ts_10 {
        status = "okay";
 };
+
+&watchdog {
+       /delete-property/ mediatek,disable-extrst;
+};
index 3c6079edda190d3606ff5f1f36bc3ad10ff99019..f94c07f8b9334e817041a21e83515cb3dc274c40 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&cros_ec_int>;
                spi-max-frequency = <3000000>;
+               wakeup-source;
 
                keyboard-backlight {
                        compatible = "google,cros-kbd-led-backlight";
        status = "okay";
 };
 
+/*
+ * For the USB Type-C ports the role and alternate modes switching is
+ * done by the EC so we set dr_mode to host to avoid interfering.
+ */
+&ssusb0 {
+       dr_mode = "host";
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       status = "okay";
+};
+
+&ssusb2 {
+       dr_mode = "host";
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       status = "okay";
+};
+
+&ssusb3 {
+       dr_mode = "host";
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       status = "okay";
+};
+
 &xhci0 {
        status = "okay";
 
        rx-fifo-depth = <3072>;
-       vusb33-supply = <&mt6359_vusb_ldo_reg>;
        vbus-supply = <&usb_vbus>;
 };
 
 
 &xhci2 {
        status = "okay";
-
-       vusb33-supply = <&mt6359_vusb_ldo_reg>;
        vbus-supply = <&usb_vbus>;
 };
 
 
        /* MT7921's USB Bluetooth has issues with USB2 LPM */
        usb2-lpm-disable;
-       vusb33-supply = <&mt6359_vusb_ldo_reg>;
        vbus-supply = <&usb_vbus>;
 };
 
index 69c7f3954ae59a8008a257807d31f227ba1cd2a8..b82f7176b4a1c62ec63f2d7686e1ce25088d6683 100644 (file)
                compatible = "mediatek,mt6360";
                reg = <0x34>;
                interrupt-controller;
+               #interrupt-cells = <1>;
                interrupts-extended = <&pio 101 IRQ_TYPE_EDGE_FALLING>;
                interrupt-names = "IRQB";
 
        status = "okay";
 };
 
-&xhci0 {
+&ssusb0 {
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       status = "okay";
+};
+
+&ssusb2 {
        vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       status = "okay";
+};
+
+&ssusb3 {
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       status = "okay";
+};
+
+&xhci0 {
        vbus-supply = <&otg_vbus_regulator>;
        status = "okay";
 };
 };
 
 &xhci2 {
-       vusb33-supply = <&mt6359_vusb_ldo_reg>;
        status = "okay";
 };
 
 &xhci3 {
-       vusb33-supply = <&mt6359_vusb_ldo_reg>;
        status = "okay";
 };
index 690dc7717f2c9d087af9c20931e18c2feeddfcd1..341b6e074139699792f22c097e9c009ab5e036a2 100644 (file)
        status = "okay";
 };
 
+&ssusb0 {
+       status = "okay";
+};
+
+&ssusb2 {
+       status = "okay";
+};
+
+&ssusb3 {
+       status = "okay";
+};
+
 &xhci0 {
        status = "okay";
 };
index b9101662ce40d056295b799120a34c26f04e910d..ea6dc220e1cce2181422fd33b9081ad1082e64b6 100644 (file)
                        };
                };
 
-               xhci0: usb@11200000 {
-                       compatible = "mediatek,mt8195-xhci",
-                                    "mediatek,mtk-xhci";
-                       reg = <0 0x11200000 0 0x1000>,
-                             <0 0x11203e00 0 0x0100>;
+               ssusb0: usb@11201000 {
+                       compatible = "mediatek,mt8195-mtu3", "mediatek,mtu3";
+                       reg = <0 0x11201000 0 0x2dff>, <0 0x11203e00 0 0x0100>;
                        reg-names = "mac", "ippc";
-                       interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH 0>;
-                       phys = <&u2port0 PHY_TYPE_USB2>,
-                              <&u3port0 PHY_TYPE_USB3>;
-                       assigned-clocks = <&topckgen CLK_TOP_USB_TOP>,
-                                         <&topckgen CLK_TOP_SSUSB_XHCI>;
-                       assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5_D4>,
-                                                <&topckgen CLK_TOP_UNIVPLL_D5_D4>;
+                       ranges = <0 0 0 0x11200000 0 0x3f00>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH 0>;
                        clocks = <&infracfg_ao CLK_INFRA_AO_SSUSB>,
                                 <&topckgen CLK_TOP_SSUSB_REF>,
-                                <&apmixedsys CLK_APMIXED_USB1PLL>,
-                                <&clk26m>,
                                 <&infracfg_ao CLK_INFRA_AO_SSUSB_XHCI>;
-                       clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck",
-                                     "xhci_ck";
-                       mediatek,syscon-wakeup = <&pericfg 0x400 103>;
+                       clock-names = "sys_ck", "ref_ck", "mcu_ck";
+                       phys = <&u2port0 PHY_TYPE_USB2>, <&u3port0 PHY_TYPE_USB3>;
                        wakeup-source;
+                       mediatek,syscon-wakeup = <&pericfg 0x400 103>;
                        status = "disabled";
+
+                       xhci0: usb@0 {
+                               compatible = "mediatek,mt8195-xhci", "mediatek,mtk-xhci";
+                               reg = <0 0 0 0x1000>;
+                               reg-names = "mac";
+                               interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH 0>;
+                               assigned-clocks = <&topckgen CLK_TOP_USB_TOP>,
+                                                 <&topckgen CLK_TOP_SSUSB_XHCI>;
+                               assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5_D4>,
+                                                        <&topckgen CLK_TOP_UNIVPLL_D5_D4>;
+                               clocks = <&infracfg_ao CLK_INFRA_AO_SSUSB>,
+                                        <&topckgen CLK_TOP_SSUSB_REF>,
+                                        <&apmixedsys CLK_APMIXED_USB1PLL>,
+                                        <&clk26m>,
+                                        <&infracfg_ao CLK_INFRA_AO_SSUSB_XHCI>;
+                               clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck";
+                               status = "disabled";
+                       };
                };
 
                mmc0: mmc@11230000 {
                        status = "disabled";
                };
 
-               xhci2: usb@112a0000 {
-                       compatible = "mediatek,mt8195-xhci",
-                                    "mediatek,mtk-xhci";
-                       reg = <0 0x112a0000 0 0x1000>,
-                             <0 0x112a3e00 0 0x0100>;
+               ssusb2: usb@112a1000 {
+                       compatible = "mediatek,mt8195-mtu3", "mediatek,mtu3";
+                       reg = <0 0x112a1000 0 0x2dff>, <0 0x112a3e00 0 0x0100>;
                        reg-names = "mac", "ippc";
-                       interrupts = <GIC_SPI 533 IRQ_TYPE_LEVEL_HIGH 0>;
-                       phys = <&u2port2 PHY_TYPE_USB2>;
-                       assigned-clocks = <&topckgen CLK_TOP_USB_TOP_2P>,
-                                         <&topckgen CLK_TOP_SSUSB_XHCI_2P>;
-                       assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5_D4>,
-                                                <&topckgen CLK_TOP_UNIVPLL_D5_D4>;
+                       ranges = <0 0 0 0x112a0000 0 0x3f00>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       interrupts = <GIC_SPI 532 IRQ_TYPE_LEVEL_HIGH 0>;
+                       assigned-clocks = <&topckgen CLK_TOP_USB_TOP_2P>;
+                       assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5_D4>;
                        clocks = <&pericfg_ao CLK_PERI_AO_SSUSB_2P_BUS>,
                                 <&topckgen CLK_TOP_SSUSB_P2_REF>,
-                                <&clk26m>,
-                                <&clk26m>,
                                 <&pericfg_ao CLK_PERI_AO_SSUSB_2P_XHCI>;
-                       clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck",
-                                     "xhci_ck";
-                       mediatek,syscon-wakeup = <&pericfg 0x400 105>;
+                       clock-names = "sys_ck", "ref_ck", "mcu_ck";
+                       phys = <&u2port2 PHY_TYPE_USB2>;
                        wakeup-source;
+                       mediatek,syscon-wakeup = <&pericfg 0x400 105>;
                        status = "disabled";
+
+                       xhci2: usb@0 {
+                               compatible = "mediatek,mt8195-xhci", "mediatek,mtk-xhci";
+                               reg = <0 0 0 0x1000>;
+                               reg-names = "mac";
+                               interrupts = <GIC_SPI 533 IRQ_TYPE_LEVEL_HIGH 0>;
+                               assigned-clocks = <&topckgen CLK_TOP_SSUSB_XHCI_2P>;
+                               assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5_D4>;
+                               clocks = <&pericfg_ao CLK_PERI_AO_SSUSB_2P_XHCI>;
+                               clock-names = "sys_ck";
+                               status = "disabled";
+                       };
                };
 
-               xhci3: usb@112b0000 {
-                       compatible = "mediatek,mt8195-xhci",
-                                    "mediatek,mtk-xhci";
-                       reg = <0 0x112b0000 0 0x1000>,
-                             <0 0x112b3e00 0 0x0100>;
+               ssusb3: usb@112b1000 {
+                       compatible = "mediatek,mt8195-mtu3", "mediatek,mtu3";
+                       reg = <0 0x112b1000 0 0x2dff>, <0 0x112b3e00 0 0x0100>;
                        reg-names = "mac", "ippc";
-                       interrupts = <GIC_SPI 536 IRQ_TYPE_LEVEL_HIGH 0>;
-                       phys = <&u2port3 PHY_TYPE_USB2>;
-                       assigned-clocks = <&topckgen CLK_TOP_USB_TOP_3P>,
-                                         <&topckgen CLK_TOP_SSUSB_XHCI_3P>;
-                       assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5_D4>,
-                                                <&topckgen CLK_TOP_UNIVPLL_D5_D4>;
+                       ranges = <0 0 0 0x112b0000 0 0x3f00>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       interrupts = <GIC_SPI 535 IRQ_TYPE_LEVEL_HIGH 0>;
+                       assigned-clocks = <&topckgen CLK_TOP_USB_TOP_3P>;
+                       assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5_D4>;
                        clocks = <&pericfg_ao CLK_PERI_AO_SSUSB_3P_BUS>,
                                 <&topckgen CLK_TOP_SSUSB_P3_REF>,
-                                <&clk26m>,
-                                <&clk26m>,
                                 <&pericfg_ao CLK_PERI_AO_SSUSB_3P_XHCI>;
-                       clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck",
-                                     "xhci_ck";
-                       mediatek,syscon-wakeup = <&pericfg 0x400 106>;
+                       clock-names = "sys_ck", "ref_ck", "mcu_ck";
+                       phys = <&u2port3 PHY_TYPE_USB2>;
                        wakeup-source;
+                       mediatek,syscon-wakeup = <&pericfg 0x400 106>;
                        status = "disabled";
+
+                       xhci3: usb@0 {
+                               compatible = "mediatek,mt8195-xhci", "mediatek,mtk-xhci";
+                               reg = <0 0 0 0x1000>;
+                               reg-names = "mac";
+                               interrupts = <GIC_SPI 536 IRQ_TYPE_LEVEL_HIGH 0>;
+                               assigned-clocks = <&topckgen CLK_TOP_SSUSB_XHCI_3P>;
+                               assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5_D4>;
+                               clocks = <&pericfg_ao CLK_PERI_AO_SSUSB_3P_XHCI>;
+                               clock-names = "sys_ck";
+                               status = "disabled";
+                       };
                };
 
                pcie0: pcie@112f0000 {
                        svs_calib_data: svs-calib@580 {
                                reg = <0x580 0x64>;
                        };
+                       socinfo-data1@7a0 {
+                               reg = <0x7a0 0x4>;
+                       };
                };
 
                u3phy2: t-phy@11c40000 {
index 7fc515a07c65d1d3047c7d92cca2310f8877d3fa..1558649f633c0b1ce24a8ba520e576a0df774bf7 100644 (file)
        status = "disabled";
 };
 
+&ssusb0 {
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       status = "okay";
+};
+
+&ssusb2 {
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       status = "okay";
+};
+
+&ssusb3 {
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       status = "okay";
+};
+
 &xhci0 {
        status = "okay";
 };
 };
 
 &xhci2 {
-       vusb33-supply = <&mt6359_vusb_ldo_reg>;
        status = "okay";
 };
 
 &xhci3 {
-       vusb33-supply = <&mt6359_vusb_ldo_reg>;
        status = "okay";
 };
diff --git a/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts b/arch/arm64/boot/dts/mediatek/mt8395-radxa-nio-12l.dts
new file mode 100644 (file)
index 0000000..e5d9b67
--- /dev/null
@@ -0,0 +1,825 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2023 Radxa Limited
+ * Copyright (C) 2024 Collabora Ltd.
+ *                    AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include "mt8195.dtsi"
+#include "mt6359.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/mt8195-pinfunc.h>
+#include <dt-bindings/regulator/mediatek,mt6360-regulator.h>
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/usb/pd.h>
+
+/ {
+       model = "Radxa NIO 12L";
+       chassis-type = "embedded";
+       compatible = "radxa,nio-12l", "mediatek,mt8395", "mediatek,mt8195";
+
+       aliases {
+               i2c0 = &i2c2;
+               i2c1 = &i2c3;
+               i2c2 = &i2c4;
+               i2c3 = &i2c0;
+               i2c4 = &i2c1;
+               ethernet0 = &eth;
+               serial0 = &uart0;
+               serial1 = &uart1;
+               spi0 = &spi1;
+               spi1 = &spi2;
+       };
+
+       chosen {
+               stdout-path = "serial0:921600n8";
+       };
+
+       firmware {
+               optee {
+                       compatible = "linaro,optee-tz";
+                       method = "smc";
+               };
+       };
+
+       memory@40000000 {
+               device_type = "memory";
+               reg = <0 0x40000000 0x1 0x0>;
+       };
+
+       wifi_vreg: regulator-wifi-3v3-en {
+               compatible = "regulator-fixed";
+               regulator-name = "wifi_3v3_en";
+               regulator-always-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               enable-active-high;
+               gpio = <&pio 67 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&wifi_vreg_pins>;
+               vin-supply = <&vsys>;
+       };
+
+       /* system wide switching 5.0V power rail */
+       vsys: regulator-vsys {
+               compatible = "regulator-fixed";
+               regulator-name = "vsys";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc5v0_vsys>;
+       };
+
+       vsys_buck: regulator-vsys-buck {
+               compatible = "regulator-fixed";
+               regulator-name = "vsys_buck";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc5v0_vsys>;
+       };
+
+       /* Rail from power-only "TYPE C DC" port */
+       vcc5v0_vsys: regulator-vcc5v0-sys {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_sys";
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               /*
+                * 12 MiB reserved for OP-TEE (BL32)
+                * +-----------------------+ 0x43e0_0000
+                * |      SHMEM 2MiB       |
+                * +-----------------------+ 0x43c0_0000
+                * |        | TA_RAM  8MiB |
+                * + TZDRAM +--------------+ 0x4340_0000
+                * |        | TEE_RAM 2MiB |
+                * +-----------------------+ 0x4320_0000
+                */
+               optee_reserved: optee@43200000 {
+                       reg = <0 0x43200000 0 0xc00000>;
+                       no-map;
+               };
+
+               scp_mem: memory@50000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x50000000 0 0x2900000>;
+                       no-map;
+               };
+
+               vpu_mem: memory@53000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x53000000 0 0x1400000>; /* 20 MB */
+               };
+
+               /* 2 MiB reserved for ARM Trusted Firmware (BL31) */
+               bl31_secmon_mem: memory@54600000 {
+                       reg = <0 0x54600000 0x0 0x200000>;
+                       no-map;
+               };
+
+               afe_mem: memory@60000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x60000000 0 0x1100000>;
+                       no-map;
+               };
+
+               apu_mem: memory@62000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x62000000 0 0x1400000>; /* 20 MB */
+               };
+       };
+};
+
+&eth {
+       phy-mode = "rgmii-rxid";
+       phy-handle = <&rgmii_phy>;
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&eth_default_pins>;
+       pinctrl-1 = <&eth_sleep_pins>;
+       mediatek,tx-delay-ps = <2030>;
+       mediatek,mac-wol;
+       snps,reset-gpio = <&pio 93 GPIO_ACTIVE_HIGH>;
+       snps,reset-delays-us = <0 20000 100000>;
+       status = "okay";
+
+       mdio {
+               rgmii_phy: ethernet-phy@1 {
+                       compatible = "ethernet-phy-id001c.c916";
+                       reg = <0x1>;
+               };
+       };
+};
+
+&gpu {
+       mali-supply = <&mt6315_7_vbuck1>;
+       status = "okay";
+};
+
+&i2c2 {
+       clock-frequency = <400000>;
+       pinctrl-0 = <&i2c2_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       typec-mux@48 {
+               compatible = "ite,it5205";
+               reg = <0x48>;
+
+               mode-switch;
+               orientation-switch;
+
+               vcc-supply = <&mt6359_vibr_ldo_reg>;
+
+               port {
+                       it5205_sbu_mux: endpoint {
+                               remote-endpoint = <&typec_con_mux>;
+                       };
+               };
+       };
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+       pinctrl-0 = <&i2c4_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       /* I2C4 exposed at 39-pins MIPI-LCD connector */
+};
+
+&i2c6 {
+       clock-frequency = <400000>;
+       pinctrl-0 = <&i2c6_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       mt6360: pmic@34 {
+               compatible = "mediatek,mt6360";
+               reg = <0x34>;
+               interrupts-extended = <&pio 101 IRQ_TYPE_EDGE_FALLING>;
+               interrupt-names = "IRQB";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               pinctrl-0 = <&mt6360_pins>;
+
+               charger {
+                       compatible = "mediatek,mt6360-chg";
+                       richtek,vinovp-microvolt = <14500000>;
+
+                       otg_vbus_regulator: usb-otg-vbus-regulator {
+                               regulator-name = "usb-otg-vbus";
+                               regulator-min-microvolt = <4425000>;
+                               regulator-max-microvolt = <5825000>;
+                       };
+               };
+
+               regulator {
+                       compatible = "mediatek,mt6360-regulator";
+                       LDO_VIN1-supply = <&vsys_buck>;
+                       LDO_VIN3-supply = <&mt6360_buck2>;
+
+                       mt6360_buck1: buck1 {
+                               regulator-name = "emi_vdd2";
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1300000>;
+                               regulator-allowed-modes = <MT6360_OPMODE_NORMAL
+                                                          MT6360_OPMODE_LP
+                                                          MT6360_OPMODE_ULP>;
+                               regulator-always-on;
+                       };
+
+                       mt6360_buck2: buck2 {
+                               regulator-name = "emi_vddq";
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1300000>;
+                               regulator-allowed-modes = <MT6360_OPMODE_NORMAL
+                                                          MT6360_OPMODE_LP
+                                                          MT6360_OPMODE_ULP>;
+                               regulator-always-on;
+                       };
+
+                       mt6360_ldo1: ldo1 {
+                               regulator-name = "ext_lcd_3v3";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-allowed-modes = <MT6360_OPMODE_NORMAL
+                                                          MT6360_OPMODE_LP>;
+                               regulator-always-on;
+                       };
+
+                       mt6360_ldo2: ldo2 {
+                               regulator-name = "panel1_p1v8";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-allowed-modes = <MT6360_OPMODE_NORMAL
+                                                          MT6360_OPMODE_LP>;
+                       };
+
+                       mt6360_ldo3: ldo3 {
+                               regulator-name = "vmc_pmu";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3600000>;
+                               regulator-allowed-modes = <MT6360_OPMODE_NORMAL
+                                                          MT6360_OPMODE_LP>;
+                       };
+
+                       mt6360_ldo5: ldo5 {
+                               regulator-name = "vmch_pmu";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-allowed-modes = <MT6360_OPMODE_NORMAL
+                                                          MT6360_OPMODE_LP>;
+                               regulator-always-on;
+                       };
+
+                       mt6360_ldo6: ldo6 {
+                               regulator-name = "mt6360_ldo6"; /* Test point */
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <2100000>;
+                               regulator-allowed-modes = <MT6360_OPMODE_NORMAL
+                                                          MT6360_OPMODE_LP>;
+                       };
+
+                       mt6360_ldo7: ldo7 {
+                               regulator-name = "emi_vmddr_en";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <2100000>;
+                               regulator-allowed-modes = <MT6360_OPMODE_NORMAL
+                                                          MT6360_OPMODE_LP>;
+                               regulator-always-on;
+                       };
+               };
+
+               typec {
+                       compatible = "mediatek,mt6360-tcpc";
+                       interrupts-extended = <&pio 100 IRQ_TYPE_LEVEL_LOW>;
+                       interrupt-names = "PD_IRQB";
+
+                       connector {
+                               compatible = "usb-c-connector";
+                               label = "USB-C";
+                               data-role = "dual";
+                               op-sink-microwatt = <10000000>;
+                               power-role = "dual";
+                               try-power-role = "sink";
+
+                               source-pdos = <PDO_FIXED(5000, 1000,
+                                                        PDO_FIXED_DUAL_ROLE |
+                                                        PDO_FIXED_DATA_SWAP)>;
+                               sink-pdos = <PDO_FIXED(5000, 3000,
+                                                      PDO_FIXED_DUAL_ROLE |
+                                                      PDO_FIXED_DATA_SWAP)>;
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+                                               typec_con_hs: endpoint {
+                                                       remote-endpoint = <&mtu3_hs0_role_sw>;
+                                               };
+                                       };
+
+                                       port@2 {
+                                               reg = <2>;
+                                               typec_con_mux: endpoint {
+                                                       remote-endpoint = <&it5205_sbu_mux>;
+                                               };
+                                       };
+                               };
+                       };
+               };
+       };
+};
+
+/* MMC0 Controller: eMMC (HS400). Power lines are shared with UFS! */
+&mmc0 {
+       pinctrl-names = "default", "state_uhs";
+       pinctrl-0 = <&mmc0_default_pins>;
+       pinctrl-1 = <&mmc0_uhs_pins>;
+       bus-width = <8>;
+       max-frequency = <200000000>;
+       hs400-ds-delay = <0x14c11>;
+       cap-mmc-highspeed;
+       cap-mmc-hw-reset;
+       mmc-hs200-1_8v;
+       mmc-hs400-1_8v;
+       no-sdio;
+       no-sd;
+       non-removable;
+       vmmc-supply = <&mt6359_vemc_1_ldo_reg>;
+       vqmmc-supply = <&mt6359_vufs_ldo_reg>;
+       status = "okay";
+};
+
+/* MMC1 Controller: MicroSD card slot */
+&mmc1 {
+       pinctrl-names = "default", "state_uhs";
+       pinctrl-0 = <&mmc1_default_pins>, <&mmc1_pins_detect>;
+       pinctrl-1 = <&mmc1_default_pins>;
+       bus-width = <4>;
+       max-frequency = <200000000>;
+       cap-sd-highspeed;
+       cd-gpios = <&pio 129 GPIO_ACTIVE_LOW>;
+       no-mmc;
+       no-sdio;
+       sd-uhs-sdr50;
+       sd-uhs-sdr104;
+       vmmc-supply = <&mt6360_ldo5>;
+       vqmmc-supply = <&mt6360_ldo3>;
+       status = "okay";
+};
+
+&mt6359_vaud18_ldo_reg {
+       regulator-always-on;
+};
+
+&mt6359_vbbck_ldo_reg {
+       regulator-always-on;
+};
+
+/* For USB Hub */
+&mt6359_vcamio_ldo_reg {
+       regulator-always-on;
+};
+
+&mt6359_vcn33_2_bt_ldo_reg {
+       regulator-min-microvolt = <3300000>;
+       regulator-max-microvolt = <3300000>;
+};
+
+&mt6359_vcore_buck_reg {
+       regulator-always-on;
+};
+
+&mt6359_vgpu11_buck_reg {
+       regulator-always-on;
+};
+
+&mt6359_vproc1_buck_reg {
+       regulator-always-on;
+};
+
+&mt6359_vproc2_buck_reg {
+       regulator-always-on;
+};
+
+&mt6359_vpu_buck_reg {
+       regulator-always-on;
+};
+
+&mt6359_vrf12_ldo_reg {
+       regulator-always-on;
+};
+
+&mt6359_vsram_md_ldo_reg {
+       regulator-always-on;
+};
+
+/* for GPU SRAM */
+&mt6359_vsram_others_ldo_reg {
+       regulator-min-microvolt = <750000>;
+       regulator-max-microvolt = <750000>;
+};
+
+&pio {
+       eth_default_pins: eth-default-pins {
+               pins-cc {
+                       pinmux = <PINMUX_GPIO85__FUNC_GBE_TXC>,
+                                <PINMUX_GPIO86__FUNC_GBE_RXC>,
+                                <PINMUX_GPIO87__FUNC_GBE_RXDV>,
+                                <PINMUX_GPIO88__FUNC_GBE_TXEN>;
+                       drive-strength = <8>;
+               };
+
+               pins-mdio {
+                       pinmux = <PINMUX_GPIO89__FUNC_GBE_MDC>,
+                                <PINMUX_GPIO90__FUNC_GBE_MDIO>;
+                       input-enable;
+               };
+
+               pins-power {
+                       pinmux = <PINMUX_GPIO91__FUNC_GPIO91>,
+                                <PINMUX_GPIO92__FUNC_GPIO92>;
+                       output-high;
+               };
+
+               pins-rst {
+                       pinmux = <PINMUX_GPIO93__FUNC_GPIO93>;
+               };
+
+               pins-rxd {
+                       pinmux = <PINMUX_GPIO81__FUNC_GBE_RXD3>,
+                                <PINMUX_GPIO82__FUNC_GBE_RXD2>,
+                                <PINMUX_GPIO83__FUNC_GBE_RXD1>,
+                                <PINMUX_GPIO84__FUNC_GBE_RXD0>;
+               };
+
+               pins-txd {
+                       pinmux = <PINMUX_GPIO77__FUNC_GBE_TXD3>,
+                                <PINMUX_GPIO78__FUNC_GBE_TXD2>,
+                                <PINMUX_GPIO79__FUNC_GBE_TXD1>,
+                                <PINMUX_GPIO80__FUNC_GBE_TXD0>;
+                       drive-strength = <8>;
+               };
+       };
+
+       eth_sleep_pins: eth-sleep-pins {
+               pins-cc {
+                       pinmux = <PINMUX_GPIO85__FUNC_GPIO85>,
+                                <PINMUX_GPIO86__FUNC_GPIO86>,
+                                <PINMUX_GPIO87__FUNC_GPIO87>,
+                                <PINMUX_GPIO88__FUNC_GPIO88>;
+               };
+
+               pins-mdio {
+                       pinmux = <PINMUX_GPIO89__FUNC_GPIO89>,
+                                <PINMUX_GPIO90__FUNC_GPIO90>;
+                       bias-disable;
+                       input-disable;
+               };
+
+               pins-rxd {
+                       pinmux = <PINMUX_GPIO81__FUNC_GPIO81>,
+                                <PINMUX_GPIO82__FUNC_GPIO82>,
+                                <PINMUX_GPIO83__FUNC_GPIO83>,
+                                <PINMUX_GPIO84__FUNC_GPIO84>;
+               };
+
+               pins-txd {
+                       pinmux = <PINMUX_GPIO77__FUNC_GPIO77>,
+                                <PINMUX_GPIO78__FUNC_GPIO78>,
+                                <PINMUX_GPIO79__FUNC_GPIO79>,
+                                <PINMUX_GPIO80__FUNC_GPIO80>;
+               };
+       };
+
+       i2c2_pins: i2c2-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO12__FUNC_SDA2>,
+                                <PINMUX_GPIO13__FUNC_SCL2>;
+                       bias-pull-up = <MTK_PULL_SET_RSEL_111>;
+                       drive-strength = <6>;
+                       drive-strength-microamp = <1000>;
+               };
+       };
+
+       i2c4_pins: i2c4-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO16__FUNC_SDA4>,
+                                <PINMUX_GPIO17__FUNC_SCL4>;
+                       bias-pull-up = <MTK_PULL_SET_RSEL_111>;
+                       drive-strength-microamp = <1000>;
+               };
+       };
+
+       i2c6_pins: i2c6-pins {
+               pins {
+                       pinmux = <PINMUX_GPIO25__FUNC_SDA6>,
+                                <PINMUX_GPIO26__FUNC_SCL6>;
+                       bias-pull-up = <MTK_PULL_SET_RSEL_111>;
+               };
+       };
+
+       mmc0_default_pins: mmc0-default-pins {
+               pins-clk {
+                       pinmux = <PINMUX_GPIO122__FUNC_MSDC0_CLK>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+                       drive-strength = <6>;
+               };
+
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO126__FUNC_MSDC0_DAT0>,
+                                <PINMUX_GPIO125__FUNC_MSDC0_DAT1>,
+                                <PINMUX_GPIO124__FUNC_MSDC0_DAT2>,
+                                <PINMUX_GPIO123__FUNC_MSDC0_DAT3>,
+                                <PINMUX_GPIO119__FUNC_MSDC0_DAT4>,
+                                <PINMUX_GPIO118__FUNC_MSDC0_DAT5>,
+                                <PINMUX_GPIO117__FUNC_MSDC0_DAT6>,
+                                <PINMUX_GPIO116__FUNC_MSDC0_DAT7>,
+                                <PINMUX_GPIO121__FUNC_MSDC0_CMD>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+                       drive-strength = <6>;
+                       input-enable;
+               };
+
+               pins-rst {
+                       pinmux = <PINMUX_GPIO120__FUNC_MSDC0_RSTB>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+                       drive-strength = <6>;
+               };
+       };
+
+       mmc0_uhs_pins: mmc0-uhs-pins {
+               pins-clk {
+                       pinmux = <PINMUX_GPIO122__FUNC_MSDC0_CLK>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+                       drive-strength = <8>;
+               };
+
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO126__FUNC_MSDC0_DAT0>,
+                                <PINMUX_GPIO125__FUNC_MSDC0_DAT1>,
+                                <PINMUX_GPIO124__FUNC_MSDC0_DAT2>,
+                                <PINMUX_GPIO123__FUNC_MSDC0_DAT3>,
+                                <PINMUX_GPIO119__FUNC_MSDC0_DAT4>,
+                                <PINMUX_GPIO118__FUNC_MSDC0_DAT5>,
+                                <PINMUX_GPIO117__FUNC_MSDC0_DAT6>,
+                                <PINMUX_GPIO116__FUNC_MSDC0_DAT7>,
+                                <PINMUX_GPIO121__FUNC_MSDC0_CMD>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+                       drive-strength = <8>;
+                       input-enable;
+               };
+
+               pins-ds {
+                       pinmux = <PINMUX_GPIO127__FUNC_MSDC0_DSL>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+                       drive-strength = <8>;
+               };
+
+               pins-rst {
+                       pinmux = <PINMUX_GPIO120__FUNC_MSDC0_RSTB>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+                       drive-strength = <8>;
+               };
+       };
+
+       mmc1_default_pins: mmc1-default-pins {
+               pins-clk {
+                       pinmux = <PINMUX_GPIO111__FUNC_MSDC1_CLK>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+                       drive-strength = <8>;
+               };
+
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO110__FUNC_MSDC1_CMD>,
+                                <PINMUX_GPIO112__FUNC_MSDC1_DAT0>,
+                                <PINMUX_GPIO113__FUNC_MSDC1_DAT1>,
+                                <PINMUX_GPIO114__FUNC_MSDC1_DAT2>,
+                                <PINMUX_GPIO115__FUNC_MSDC1_DAT3>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+                       drive-strength = <8>;
+                       input-enable;
+               };
+       };
+
+       mmc1_pins_detect: mmc1-detect-pins {
+               pins-insert {
+                       pinmux = <PINMUX_GPIO129__FUNC_GPIO129>;
+                       bias-pull-up;
+               };
+       };
+
+       mt6360_pins: mt6360-pins {
+               pins-irq {
+                       pinmux = <PINMUX_GPIO100__FUNC_GPIO100>,
+                                <PINMUX_GPIO101__FUNC_GPIO101>;
+                       input-enable;
+                       bias-pull-up;
+               };
+       };
+
+       pcie0_default_pins: pcie0-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO19__FUNC_WAKEN>,
+                                <PINMUX_GPIO20__FUNC_PERSTN>,
+                                <PINMUX_GPIO21__FUNC_CLKREQN>;
+                       bias-pull-up;
+               };
+       };
+
+       pcie1_default_pins: pcie1-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO0__FUNC_PERSTN_1>,
+                                <PINMUX_GPIO1__FUNC_CLKREQN_1>,
+                                <PINMUX_GPIO2__FUNC_WAKEN_1>;
+                       bias-disable;
+               };
+       };
+
+       spi1_pins: spi1-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO136__FUNC_SPIM1_CSB>,
+                                <PINMUX_GPIO137__FUNC_SPIM1_CLK>,
+                                <PINMUX_GPIO138__FUNC_SPIM1_MO>,
+                                <PINMUX_GPIO139__FUNC_SPIM1_MI>;
+                       bias-disable;
+               };
+       };
+
+       spi2_pins: spi2-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO140__FUNC_SPIM2_CSB>,
+                                <PINMUX_GPIO141__FUNC_SPIM2_CLK>,
+                                <PINMUX_GPIO142__FUNC_SPIM2_MO>,
+                                <PINMUX_GPIO143__FUNC_SPIM2_MI>;
+                       bias-disable;
+               };
+       };
+
+       uart0_pins: uart0-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO98__FUNC_UTXD0>,
+                                <PINMUX_GPIO99__FUNC_URXD0>;
+               };
+       };
+
+       uart1_pins: uart1-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO102__FUNC_UTXD1>,
+                                <PINMUX_GPIO103__FUNC_URXD1>;
+               };
+       };
+
+       wifi_vreg_pins: wifi-vreg-pins {
+               pins-wifi-pmu-en {
+                       pinmux = <PINMUX_GPIO65__FUNC_GPIO65>;
+                       output-high;
+               };
+
+               pins-wifi-vreg-en {
+                       pinmux = <PINMUX_GPIO67__FUNC_GPIO67>;
+               };
+       };
+};
+
+&pcie0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie0_default_pins>;
+       status = "okay";
+};
+
+&pcie1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie1_default_pins>;
+       status = "okay";
+};
+
+&pmic {
+       interrupts-extended = <&pio 222 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&scp {
+       memory-region = <&scp_mem>;
+       status = "okay";
+};
+
+&spi1 {
+       /* Exposed at 40 pin connector */
+       pinctrl-0 = <&spi1_pins>;
+       pinctrl-names = "default";
+       mediatek,pad-select = <0>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "okay";
+};
+
+&spi2 {
+       /* Exposed at 40 pin connector */
+       pinctrl-0 = <&spi2_pins>;
+       pinctrl-names = "default";
+       mediatek,pad-select = <0>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "okay";
+};
+
+&spmi {
+       #address-cells = <2>;
+       #size-cells = <0>;
+
+       mt6315_6: pmic@6 {
+               compatible = "mediatek,mt6315-regulator";
+               reg = <0x6 SPMI_USID>;
+
+               regulators {
+                       mt6315_6_vbuck1: vbuck1 {
+                               regulator-compatible = "vbuck1";
+                               regulator-name = "Vbcpu";
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1193750>;
+                               regulator-enable-ramp-delay = <256>;
+                               regulator-allowed-modes = <0 1 2>;
+                               regulator-always-on;
+                       };
+               };
+       };
+
+       mt6315_7: pmic@7 {
+               compatible = "mediatek,mt6315-regulator";
+               reg = <0x7 SPMI_USID>;
+
+               regulators {
+                       mt6315_7_vbuck1: vbuck1 {
+                               regulator-compatible = "vbuck1";
+                               regulator-name = "Vgpu";
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1193750>;
+                               regulator-enable-ramp-delay = <256>;
+                               regulator-allowed-modes = <0 1 2>;
+                       };
+               };
+       };
+};
+
+&uart0 {
+       /* Exposed at 40 pin connector */
+       pinctrl-0 = <&uart0_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&uart1 {
+       /* Exposed at 40 pin connector */
+       pinctrl-0 = <&uart1_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&ssusb0 {
+       role-switch-default-mode = "host";
+       usb-role-switch;
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       status = "okay";
+
+       port {
+               mtu3_hs0_role_sw: endpoint {
+                       remote-endpoint = <&typec_con_hs>;
+               };
+       };
+};
+
+&ssusb2 {
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       status = "okay";
+};
+
+&xhci0 {
+       vbus-supply = <&otg_vbus_regulator>;
+       status = "okay";
+};
+
+&xhci1 {
+       /* MT7921's USB Bluetooth has issues with USB2 LPM */
+       usb2-lpm-disable;
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       vbus-supply = <&vsys>;
+       status = "okay";
+};
+
+&xhci2 {
+       vbus-supply = <&vsys>;
+       status = "okay";
+};
index bbc2e9bef08da55d464837ddaef64b12f04a8469..14d58859bb55c99c756d2d4c6f4fc49b0ea84096 100644 (file)
                        interrupt-parent = <&gpio>;
                        interrupts = <TEGRA_GPIO(C, 7) IRQ_TYPE_LEVEL_LOW>;
                        reg = <0>;
+                       wakeup-source;
 
                        google,cros-ec-spi-msg-delay = <2000>;
 
index 5b59c1986e9b5fe886ba3e6fb8541044a2842f7d..e8b296d9e0d3e66a6739ad085ee38cc73f86e0fe 100644 (file)
                        status = "okay";
                };
 
+               i2c@c240000 {
+                       status = "okay";
+
+                       power-sensor@40 {
+                               compatible = "ti,ina3221";
+                               reg = <0x40>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               input@0 {
+                                       reg = <0x0>;
+                                       label = "GPU";
+                                       shunt-resistor-micro-ohms = <5000>;
+                               };
+                               input@1 {
+                                       reg = <0x1>;
+                                       label = "CPU";
+                                       shunt-resistor-micro-ohms = <5000>;
+                               };
+                               input@2 {
+                                       reg = <0x2>;
+                                       label = "SOC";
+                                       shunt-resistor-micro-ohms = <5000>;
+                               };
+                       };
+
+                       power-sensor@41 {
+                               compatible = "ti,ina3221";
+                               reg = <0x41>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               input@0 {
+                                       reg = <0x0>;
+                                       label = "CV";
+                                       shunt-resistor-micro-ohms = <5000>;
+                               };
+                               input@1 {
+                                       reg = <0x1>;
+                                       label = "VDDRQ";
+                                       shunt-resistor-micro-ohms = <5000>;
+                               };
+                               input@2 {
+                                       reg = <0x2>;
+                                       label = "SYS5V";
+                                       shunt-resistor-micro-ohms = <5000>;
+                               };
+                       };
+               };
+
                serial@3110000 {
                        status = "okay";
                };
index 64a3398fe7a6d3c82449bbe622099b87a11baafe..c32876699a43e9f57b3888c5bc0f5da73c5b95b5 100644 (file)
 
                        ports {
                                usb2-0 {
-                                       mode = "host";
+                                       mode = "otg";
+                                       usb-role-switch;
                                        status = "okay";
+
+                                       port {
+                                               hs_typec_p0: endpoint {
+                                                       remote-endpoint = <&hs_ucsi_ccg_p0>;
+                                               };
+                                       };
                                };
 
                                usb2-1 {
                        };
                };
 
+               usb@3550000 {
+                       status = "okay";
+
+                       phys = <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-0}>,
+                              <&{/bus@0/padctl@3520000/pads/usb3/lanes/usb3-2}>;
+                       phy-names = "usb2-0", "usb3-0";
+               };
+
                usb@3610000 {
                        status = "okay";
 
                        phy-names = "usb2-0", "usb2-1", "usb2-3", "usb3-0", "usb3-2", "usb3-3";
                };
 
+               i2c@c240000 {
+                       typec@8 {
+                               compatible = "cypress,cypd4226";
+                               reg = <0x08>;
+                               interrupt-parent = <&gpio_aon>;
+                               interrupts = <TEGRA194_AON_GPIO(BB, 2) IRQ_TYPE_LEVEL_LOW>;
+                               firmware-name = "nvidia,jetson-agx-xavier";
+                               status = "okay";
+
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               ccg_typec_con0: connector@0 {
+                                       compatible = "usb-c-connector";
+                                       reg = <0>;
+                                       label = "USB-C";
+                                       data-role = "dual";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       hs_ucsi_ccg_p0: endpoint {
+                                                               remote-endpoint = <&hs_typec_p0>;
+                                                       };
+                                               };
+                                       };
+                               };
+                       };
+               };
+
                i2c@c250000 {
                        status = "okay";
 
index 58f190b0f868724176ccb3a1b27551aaf8a7c9f2..59860d19f0f6a5a32719dcdb7f868b60c2551a1f 100644 (file)
                        status = "okay";
                };
 
+               i2c@c250000 {
+                       status = "okay";
+
+                       power-sensor@40 {
+                               compatible = "ti,ina3221";
+                               reg = <0x40>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               input@0 {
+                                       reg = <0x0>;
+                                       label = "VDD_IN";
+                                       shunt-resistor-micro-ohms = <5000>;
+                               };
+                               input@1 {
+                                       reg = <0x1>;
+                                       label = "VDD_CPU_GPU_CV";
+                                       shunt-resistor-micro-ohms = <5000>;
+                               };
+                               input@2 {
+                                       reg = <0x2>;
+                                       label = "VDD_SOC";
+                                       shunt-resistor-micro-ohms = <5000>;
+                               };
+                       };
+               };
+
                serial@3100000 {
                        status = "okay";
                };
index db6ef711674ab50ed58e97fb18e2facd0bdfce38..320c8e9b06b46d743ca958fd0f2cc663021042e8 100644 (file)
@@ -3,6 +3,11 @@
 / {
        compatible = "nvidia,p3701", "nvidia,tegra234";
 
+       aliases {
+               mmc0 = "/bus@0/mmc@3460000";
+               mmc1 = "/bus@0/mmc@3400000";
+       };
+
        bus@0 {
                aconnect@2900000 {
                        status = "okay";
 
                                i2s@2901000 {
                                        status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       i2s1_cif: endpoint {
-                                                               remote-endpoint = <&xbar_i2s1>;
-                                                       };
-                                               };
-
-                                               i2s1_port: port@1 {
-                                                       reg = <1>;
-
-                                                       i2s1_dap: endpoint {
-                                                               dai-format = "i2s";
-                                                               /* placeholder for external codec */
-                                                       };
-                                               };
-                                       };
                                };
 
                                i2s@2901100 {
                                        status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       i2s2_cif: endpoint {
-                                                               remote-endpoint = <&xbar_i2s2>;
-                                                       };
-                                               };
-
-                                               i2s2_port: port@1 {
-                                                       reg = <1>;
-
-                                                       i2s2_dap: endpoint {
-                                                               dai-format = "i2s";
-                                                               /* placeholder for external codec */
-                                                       };
-                                               };
-                                       };
                                };
 
                                i2s@2901300 {
                                        status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       i2s4_cif: endpoint {
-                                                               remote-endpoint = <&xbar_i2s4>;
-                                                       };
-                                               };
-
-                                               i2s4_port: port@1 {
-                                                       reg = <1>;
-
-                                                       i2s4_dap: endpoint {
-                                                               dai-format = "i2s";
-                                                               /* placeholder for external codec */
-                                                       };
-                                               };
-                                       };
                                };
 
                                i2s@2901500 {
                                        status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       i2s6_cif: endpoint {
-                                                               remote-endpoint = <&xbar_i2s6>;
-                                                       };
-                                               };
-
-                                               i2s6_port: port@1 {
-                                                       reg = <1>;
-
-                                                       i2s6_dap: endpoint {
-                                                               dai-format = "i2s";
-                                                               /* placeholder for external codec */
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               sfc@2902000 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       sfc1_cif_in: endpoint {
-                                                               remote-endpoint = <&xbar_sfc1_in>;
-                                                       };
-                                               };
-
-                                               sfc1_out_port: port@1 {
-                                                       reg = <1>;
-
-                                                       sfc1_cif_out: endpoint {
-                                                               remote-endpoint = <&xbar_sfc1_out>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               sfc@2902200 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       sfc2_cif_in: endpoint {
-                                                               remote-endpoint = <&xbar_sfc2_in>;
-                                                       };
-                                               };
-
-                                               sfc2_out_port: port@1 {
-                                                       reg = <1>;
-
-                                                       sfc2_cif_out: endpoint {
-                                                               remote-endpoint = <&xbar_sfc2_out>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               sfc@2902400 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       sfc3_cif_in: endpoint {
-                                                               remote-endpoint = <&xbar_sfc3_in>;
-                                                       };
-                                               };
-
-                                               sfc3_out_port: port@1 {
-                                                       reg = <1>;
-
-                                                       sfc3_cif_out: endpoint {
-                                                               remote-endpoint = <&xbar_sfc3_out>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               sfc@2902600 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       sfc4_cif_in: endpoint {
-                                                               remote-endpoint = <&xbar_sfc4_in>;
-                                                       };
-                                               };
-
-                                               sfc4_out_port: port@1 {
-                                                       reg = <1>;
-
-                                                       sfc4_cif_out: endpoint {
-                                                               remote-endpoint = <&xbar_sfc4_out>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               amx@2903000 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       amx1_in1: endpoint {
-                                                               remote-endpoint = <&xbar_amx1_in1>;
-                                                       };
-                                               };
-
-                                               port@1 {
-                                                       reg = <1>;
-
-                                                       amx1_in2: endpoint {
-                                                               remote-endpoint = <&xbar_amx1_in2>;
-                                                       };
-                                               };
-
-                                               port@2 {
-                                                       reg = <2>;
-
-                                                       amx1_in3: endpoint {
-                                                               remote-endpoint = <&xbar_amx1_in3>;
-                                                       };
-                                               };
-
-                                               port@3 {
-                                                       reg = <3>;
-
-                                                       amx1_in4: endpoint {
-                                                               remote-endpoint = <&xbar_amx1_in4>;
-                                                       };
-                                               };
-
-                                               amx1_out_port: port@4 {
-                                                       reg = <4>;
-
-                                                       amx1_out: endpoint {
-                                                               remote-endpoint = <&xbar_amx1_out>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               amx@2903100 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       amx2_in1: endpoint {
-                                                               remote-endpoint = <&xbar_amx2_in1>;
-                                                       };
-                                               };
-
-                                               port@1 {
-                                                       reg = <1>;
-
-                                                       amx2_in2: endpoint {
-                                                               remote-endpoint = <&xbar_amx2_in2>;
-                                                       };
-                                               };
-
-                                               port@2 {
-                                                       reg = <2>;
-
-                                                       amx2_in3: endpoint {
-                                                               remote-endpoint = <&xbar_amx2_in3>;
-                                                       };
-                                               };
-
-                                               port@3 {
-                                                       reg = <3>;
-
-                                                       amx2_in4: endpoint {
-                                                               remote-endpoint = <&xbar_amx2_in4>;
-                                                       };
-                                               };
-
-                                               amx2_out_port: port@4 {
-                                                       reg = <4>;
-
-                                                       amx2_out: endpoint {
-                                                               remote-endpoint = <&xbar_amx2_out>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               amx@2903200 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       amx3_in1: endpoint {
-                                                               remote-endpoint = <&xbar_amx3_in1>;
-                                                       };
-                                               };
-
-                                               port@1 {
-                                                       reg = <1>;
-
-                                                       amx3_in2: endpoint {
-                                                               remote-endpoint = <&xbar_amx3_in2>;
-                                                       };
-                                               };
-
-                                               port@2 {
-                                                       reg = <2>;
-
-                                                       amx3_in3: endpoint {
-                                                               remote-endpoint = <&xbar_amx3_in3>;
-                                                       };
-                                               };
-
-                                               port@3 {
-                                                       reg = <3>;
-
-                                                       amx3_in4: endpoint {
-                                                               remote-endpoint = <&xbar_amx3_in4>;
-                                                       };
-                                               };
-
-                                               amx3_out_port: port@4 {
-                                                       reg = <4>;
-
-                                                       amx3_out: endpoint {
-                                                               remote-endpoint = <&xbar_amx3_out>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               amx@2903300 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       amx4_in1: endpoint {
-                                                               remote-endpoint = <&xbar_amx4_in1>;
-                                                       };
-                                               };
-
-                                               port@1 {
-                                                       reg = <1>;
-
-                                                       amx4_in2: endpoint {
-                                                               remote-endpoint = <&xbar_amx4_in2>;
-                                                       };
-                                               };
-
-                                               port@2 {
-                                                       reg = <2>;
-
-                                                       amx4_in3: endpoint {
-                                                               remote-endpoint = <&xbar_amx4_in3>;
-                                                       };
-                                               };
-
-                                               port@3 {
-                                                       reg = <3>;
-
-                                                       amx4_in4: endpoint {
-                                                               remote-endpoint = <&xbar_amx4_in4>;
-                                                       };
-                                               };
-
-                                               amx4_out_port: port@4 {
-                                                       reg = <4>;
-
-                                                       amx4_out: endpoint {
-                                                               remote-endpoint = <&xbar_amx4_out>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               adx@2903800 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       adx1_in: endpoint {
-                                                               remote-endpoint = <&xbar_adx1_in>;
-                                                       };
-                                               };
-
-                                               adx1_out1_port: port@1 {
-                                                       reg = <1>;
-
-                                                       adx1_out1: endpoint {
-                                                               remote-endpoint = <&xbar_adx1_out1>;
-                                                       };
-                                               };
-
-                                               adx1_out2_port: port@2 {
-                                                       reg = <2>;
-
-                                                       adx1_out2: endpoint {
-                                                               remote-endpoint = <&xbar_adx1_out2>;
-                                                       };
-                                               };
-
-                                               adx1_out3_port: port@3 {
-                                                       reg = <3>;
-
-                                                       adx1_out3: endpoint {
-                                                               remote-endpoint = <&xbar_adx1_out3>;
-                                                       };
-                                               };
-
-                                               adx1_out4_port: port@4 {
-                                                       reg = <4>;
-
-                                                       adx1_out4: endpoint {
-                                                               remote-endpoint = <&xbar_adx1_out4>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               adx@2903900 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       adx2_in: endpoint {
-                                                               remote-endpoint = <&xbar_adx2_in>;
-                                                       };
-                                               };
-
-                                               adx2_out1_port: port@1 {
-                                                       reg = <1>;
-
-                                                       adx2_out1: endpoint {
-                                                               remote-endpoint = <&xbar_adx2_out1>;
-                                                       };
-                                               };
-
-                                               adx2_out2_port: port@2 {
-                                                       reg = <2>;
-
-                                                       adx2_out2: endpoint {
-                                                               remote-endpoint = <&xbar_adx2_out2>;
-                                                       };
-                                               };
-
-                                               adx2_out3_port: port@3 {
-                                                       reg = <3>;
-
-                                                       adx2_out3: endpoint {
-                                                               remote-endpoint = <&xbar_adx2_out3>;
-                                                       };
-                                               };
-
-                                               adx2_out4_port: port@4 {
-                                                       reg = <4>;
-
-                                                       adx2_out4: endpoint {
-                                                               remote-endpoint = <&xbar_adx2_out4>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               adx@2903a00 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       adx3_in: endpoint {
-                                                               remote-endpoint = <&xbar_adx3_in>;
-                                                       };
-                                               };
-
-                                               adx3_out1_port: port@1 {
-                                                       reg = <1>;
-
-                                                       adx3_out1: endpoint {
-                                                               remote-endpoint = <&xbar_adx3_out1>;
-                                                       };
-                                               };
-
-                                               adx3_out2_port: port@2 {
-                                                       reg = <2>;
-
-                                                       adx3_out2: endpoint {
-                                                               remote-endpoint = <&xbar_adx3_out2>;
-                                                       };
-                                               };
-
-                                               adx3_out3_port: port@3 {
-                                                       reg = <3>;
-
-                                                       adx3_out3: endpoint {
-                                                               remote-endpoint = <&xbar_adx3_out3>;
-                                                       };
-                                               };
-
-                                               adx3_out4_port: port@4 {
-                                                       reg = <4>;
-
-                                                       adx3_out4: endpoint {
-                                                               remote-endpoint = <&xbar_adx3_out4>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               adx@2903b00 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       adx4_in: endpoint {
-                                                               remote-endpoint = <&xbar_adx4_in>;
-                                                       };
-                                               };
-
-                                               adx4_out1_port: port@1 {
-                                                       reg = <1>;
-
-                                                       adx4_out1: endpoint {
-                                                               remote-endpoint = <&xbar_adx4_out1>;
-                                                       };
-                                               };
-
-                                               adx4_out2_port: port@2 {
-                                                       reg = <2>;
-
-                                                       adx4_out2: endpoint {
-                                                               remote-endpoint = <&xbar_adx4_out2>;
-                                                       };
-                                               };
-
-                                               adx4_out3_port: port@3 {
-                                                       reg = <3>;
-
-                                                       adx4_out3: endpoint {
-                                                               remote-endpoint = <&xbar_adx4_out3>;
-                                                       };
-                                               };
-
-                                               adx4_out4_port: port@4 {
-                                                       reg = <4>;
-
-                                                       adx4_out4: endpoint {
-                                                               remote-endpoint = <&xbar_adx4_out4>;
-                                                       };
-                                               };
-                                       };
                                };
 
                                dmic@2904200 {
                                        status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       dmic3_cif: endpoint {
-                                                               remote-endpoint = <&xbar_dmic3>;
-                                                       };
-                                               };
-
-                                               dmic3_port: port@1 {
-                                                       reg = <1>;
-
-                                                       dmic3_dap: endpoint {
-                                                               /* placeholder for external codec */
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               processing-engine@2908000 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0x0>;
-
-                                                       ope1_cif_in_ep: endpoint {
-                                                               remote-endpoint = <&xbar_ope1_in_ep>;
-                                                       };
-                                               };
-
-                                               ope1_out_port: port@1 {
-                                                       reg = <0x1>;
-
-                                                       ope1_cif_out_ep: endpoint {
-                                                               remote-endpoint = <&xbar_ope1_out_ep>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               mvc@290a000 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       mvc1_cif_in: endpoint {
-                                                               remote-endpoint = <&xbar_mvc1_in>;
-                                                       };
-                                               };
-
-                                               mvc1_out_port: port@1 {
-                                                       reg = <1>;
-
-                                                       mvc1_cif_out: endpoint {
-                                                               remote-endpoint = <&xbar_mvc1_out>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               mvc@290a200 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0>;
-
-                                                       mvc2_cif_in: endpoint {
-                                                               remote-endpoint = <&xbar_mvc2_in>;
-                                                       };
-                                               };
-
-                                               mvc2_out_port: port@1 {
-                                                       reg = <1>;
-
-                                                       mvc2_cif_out: endpoint {
-                                                               remote-endpoint = <&xbar_mvc2_out>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               amixer@290bb00 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0x0>;
-
-                                                       mix_in1: endpoint {
-                                                               remote-endpoint = <&xbar_mix_in1>;
-                                                       };
-                                               };
-
-                                               port@1 {
-                                                       reg = <0x1>;
-
-                                                       mix_in2: endpoint {
-                                                               remote-endpoint = <&xbar_mix_in2>;
-                                                       };
-                                               };
-
-                                               port@2 {
-                                                       reg = <0x2>;
-
-                                                       mix_in3: endpoint {
-                                                               remote-endpoint = <&xbar_mix_in3>;
-                                                       };
-                                               };
-
-                                               port@3 {
-                                                       reg = <0x3>;
-
-                                                       mix_in4: endpoint {
-                                                               remote-endpoint = <&xbar_mix_in4>;
-                                                       };
-                                               };
-
-                                               port@4 {
-                                                       reg = <0x4>;
-
-                                                       mix_in5: endpoint {
-                                                               remote-endpoint = <&xbar_mix_in5>;
-                                                       };
-                                               };
-
-                                               port@5 {
-                                                       reg = <0x5>;
-
-                                                       mix_in6: endpoint {
-                                                               remote-endpoint = <&xbar_mix_in6>;
-                                                       };
-                                               };
-
-                                               port@6 {
-                                                       reg = <0x6>;
-
-                                                       mix_in7: endpoint {
-                                                               remote-endpoint = <&xbar_mix_in7>;
-                                                       };
-                                               };
-
-                                               port@7 {
-                                                       reg = <0x7>;
-
-                                                       mix_in8: endpoint {
-                                                               remote-endpoint = <&xbar_mix_in8>;
-                                                       };
-                                               };
-
-                                               port@8 {
-                                                       reg = <0x8>;
-
-                                                       mix_in9: endpoint {
-                                                               remote-endpoint = <&xbar_mix_in9>;
-                                                       };
-                                               };
-
-                                               port@9 {
-                                                       reg = <0x9>;
-
-                                                       mix_in10: endpoint {
-                                                               remote-endpoint = <&xbar_mix_in10>;
-                                                       };
-                                               };
-
-                                               mix_out1_port: port@a {
-                                                       reg = <0xa>;
-
-                                                       mix_out1: endpoint {
-                                                               remote-endpoint = <&xbar_mix_out1>;
-                                                       };
-                                               };
-
-                                               mix_out2_port: port@b {
-                                                       reg = <0xb>;
-
-                                                       mix_out2: endpoint {
-                                                               remote-endpoint = <&xbar_mix_out2>;
-                                                       };
-                                               };
-
-                                               mix_out3_port: port@c {
-                                                       reg = <0xc>;
-
-                                                       mix_out3: endpoint {
-                                                               remote-endpoint = <&xbar_mix_out3>;
-                                                       };
-                                               };
-
-                                               mix_out4_port: port@d {
-                                                       reg = <0xd>;
-
-                                                       mix_out4: endpoint {
-                                                               remote-endpoint = <&xbar_mix_out4>;
-                                                       };
-                                               };
-
-                                               mix_out5_port: port@e {
-                                                       reg = <0xe>;
-
-                                                       mix_out5: endpoint {
-                                                               remote-endpoint = <&xbar_mix_out5>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               admaif@290f000 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               admaif0_port: port@0 {
-                                                       reg = <0x0>;
-
-                                                       admaif0: endpoint {
-                                                               remote-endpoint = <&xbar_admaif0>;
-                                                       };
-                                               };
-
-                                               admaif1_port: port@1 {
-                                                       reg = <0x1>;
-
-                                                       admaif1: endpoint {
-                                                               remote-endpoint = <&xbar_admaif1>;
-                                                       };
-                                               };
-
-                                               admaif2_port: port@2 {
-                                                       reg = <0x2>;
-
-                                                       admaif2: endpoint {
-                                                               remote-endpoint = <&xbar_admaif2>;
-                                                       };
-                                               };
-
-                                               admaif3_port: port@3 {
-                                                       reg = <0x3>;
-
-                                                       admaif3: endpoint {
-                                                               remote-endpoint = <&xbar_admaif3>;
-                                                       };
-                                               };
-
-                                               admaif4_port: port@4 {
-                                                       reg = <0x4>;
-
-                                                       admaif4: endpoint {
-                                                               remote-endpoint = <&xbar_admaif4>;
-                                                       };
-                                               };
-
-                                               admaif5_port: port@5 {
-                                                       reg = <0x5>;
-
-                                                       admaif5: endpoint {
-                                                               remote-endpoint = <&xbar_admaif5>;
-                                                       };
-                                               };
-
-                                               admaif6_port: port@6 {
-                                                       reg = <0x6>;
-
-                                                       admaif6: endpoint {
-                                                               remote-endpoint = <&xbar_admaif6>;
-                                                       };
-                                               };
-
-                                               admaif7_port: port@7 {
-                                                       reg = <0x7>;
-
-                                                       admaif7: endpoint {
-                                                               remote-endpoint = <&xbar_admaif7>;
-                                                       };
-                                               };
-
-                                               admaif8_port: port@8 {
-                                                       reg = <0x8>;
-
-                                                       admaif8: endpoint {
-                                                               remote-endpoint = <&xbar_admaif8>;
-                                                       };
-                                               };
-
-                                               admaif9_port: port@9 {
-                                                       reg = <0x9>;
-
-                                                       admaif9: endpoint {
-                                                               remote-endpoint = <&xbar_admaif9>;
-                                                       };
-                                               };
-
-                                               admaif10_port: port@a {
-                                                       reg = <0xa>;
-
-                                                       admaif10: endpoint {
-                                                               remote-endpoint = <&xbar_admaif10>;
-                                                       };
-                                               };
-
-                                               admaif11_port: port@b {
-                                                       reg = <0xb>;
-
-                                                       admaif11: endpoint {
-                                                               remote-endpoint = <&xbar_admaif11>;
-                                                       };
-                                               };
-
-                                               admaif12_port: port@c {
-                                                       reg = <0xc>;
-
-                                                       admaif12: endpoint {
-                                                               remote-endpoint = <&xbar_admaif12>;
-                                                       };
-                                               };
-
-                                               admaif13_port: port@d {
-                                                       reg = <0xd>;
-
-                                                       admaif13: endpoint {
-                                                               remote-endpoint = <&xbar_admaif13>;
-                                                       };
-                                               };
-
-                                               admaif14_port: port@e {
-                                                       reg = <0xe>;
-
-                                                       admaif14: endpoint {
-                                                               remote-endpoint = <&xbar_admaif14>;
-                                                       };
-                                               };
-
-                                               admaif15_port: port@f {
-                                                       reg = <0xf>;
-
-                                                       admaif15: endpoint {
-                                                               remote-endpoint = <&xbar_admaif15>;
-                                                       };
-                                               };
-
-                                               admaif16_port: port@10 {
-                                                       reg = <0x10>;
-
-                                                       admaif16: endpoint {
-                                                               remote-endpoint = <&xbar_admaif16>;
-                                                       };
-                                               };
-
-                                               admaif17_port: port@11 {
-                                                       reg = <0x11>;
-
-                                                       admaif17: endpoint {
-                                                               remote-endpoint = <&xbar_admaif17>;
-                                                       };
-                                               };
-
-                                               admaif18_port: port@12 {
-                                                       reg = <0x12>;
-
-                                                       admaif18: endpoint {
-                                                               remote-endpoint = <&xbar_admaif18>;
-                                                       };
-                                               };
-
-                                               admaif19_port: port@13 {
-                                                       reg = <0x13>;
-
-                                                       admaif19: endpoint {
-                                                               remote-endpoint = <&xbar_admaif19>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               asrc@2910000 {
-                                       status = "okay";
-
-                                       ports {
-                                               #address-cells = <1>;
-                                               #size-cells = <0>;
-
-                                               port@0 {
-                                                       reg = <0x0>;
-
-                                                       asrc_in1_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_in1_ep>;
-                                                       };
-                                               };
-
-                                               port@1 {
-                                                       reg = <0x1>;
-
-                                                       asrc_in2_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_in2_ep>;
-                                                       };
-                                               };
-
-                                               port@2 {
-                                                       reg = <0x2>;
-
-                                                       asrc_in3_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_in3_ep>;
-                                                       };
-                                               };
-
-                                               port@3 {
-                                                       reg = <0x3>;
-
-                                                       asrc_in4_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_in4_ep>;
-                                                       };
-                                               };
-
-                                               port@4 {
-                                                       reg = <0x4>;
-
-                                                       asrc_in5_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_in5_ep>;
-                                                       };
-                                               };
-
-                                               port@5 {
-                                                       reg = <0x5>;
-
-                                                       asrc_in6_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_in6_ep>;
-                                                       };
-                                               };
-
-                                               port@6 {
-                                                       reg = <0x6>;
-
-                                                       asrc_in7_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_in7_ep>;
-                                                       };
-                                               };
-
-                                               asrc_out1_port: port@7 {
-                                                       reg = <0x7>;
-
-                                                       asrc_out1_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_out1_ep>;
-                                                       };
-                                               };
-
-                                               asrc_out2_port: port@8 {
-                                                       reg = <0x8>;
-
-                                                       asrc_out2_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_out2_ep>;
-                                                       };
-                                               };
-
-                                               asrc_out3_port: port@9 {
-                                                       reg = <0x9>;
-
-                                                       asrc_out3_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_out3_ep>;
-                                                       };
-                                               };
-
-                                               asrc_out4_port: port@a {
-                                                       reg = <0xa>;
-
-                                                       asrc_out4_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_out4_ep>;
-                                                       };
-                                               };
-
-                                               asrc_out5_port: port@b {
-                                                       reg = <0xb>;
-
-                                                       asrc_out5_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_out5_ep>;
-                                                       };
-                                               };
-
-                                               asrc_out6_port: port@c {
-                                                       reg = <0xc>;
-
-                                                       asrc_out6_ep: endpoint {
-                                                               remote-endpoint = <&xbar_asrc_out6_ep>;
-                                                       };
-                                               };
-                                       };
-                               };
-
-                               ports {
-                                       #address-cells = <1>;
-                                       #size-cells = <0>;
-
-                                       port@0 {
-                                               reg = <0x0>;
-
-                                               xbar_admaif0: endpoint {
-                                                       remote-endpoint = <&admaif0>;
-                                               };
-                                       };
-
-                                       port@1 {
-                                               reg = <0x1>;
-
-                                               xbar_admaif1: endpoint {
-                                                       remote-endpoint = <&admaif1>;
-                                               };
-                                       };
-
-                                       port@2 {
-                                               reg = <0x2>;
-
-                                               xbar_admaif2: endpoint {
-                                                       remote-endpoint = <&admaif2>;
-                                               };
-                                       };
-
-                                       port@3 {
-                                               reg = <0x3>;
-
-                                               xbar_admaif3: endpoint {
-                                                       remote-endpoint = <&admaif3>;
-                                               };
-                                       };
-
-                                       port@4 {
-                                               reg = <0x4>;
-
-                                               xbar_admaif4: endpoint {
-                                                       remote-endpoint = <&admaif4>;
-                                               };
-                                       };
-
-                                       port@5 {
-                                               reg = <0x5>;
-
-                                               xbar_admaif5: endpoint {
-                                                       remote-endpoint = <&admaif5>;
-                                               };
-                                       };
-
-                                       port@6 {
-                                               reg = <0x6>;
-
-                                               xbar_admaif6: endpoint {
-                                                       remote-endpoint = <&admaif6>;
-                                               };
-                                       };
-
-                                       port@7 {
-                                               reg = <0x7>;
-
-                                               xbar_admaif7: endpoint {
-                                                       remote-endpoint = <&admaif7>;
-                                               };
-                                       };
-
-                                       port@8 {
-                                               reg = <0x8>;
-
-                                               xbar_admaif8: endpoint {
-                                                       remote-endpoint = <&admaif8>;
-                                               };
-                                       };
-
-                                       port@9 {
-                                               reg = <0x9>;
-
-                                               xbar_admaif9: endpoint {
-                                                       remote-endpoint = <&admaif9>;
-                                               };
-                                       };
-
-                                       port@a {
-                                               reg = <0xa>;
-
-                                               xbar_admaif10: endpoint {
-                                                       remote-endpoint = <&admaif10>;
-                                               };
-                                       };
-
-                                       port@b {
-                                               reg = <0xb>;
-
-                                               xbar_admaif11: endpoint {
-                                                       remote-endpoint = <&admaif11>;
-                                               };
-                                       };
-
-                                       port@c {
-                                               reg = <0xc>;
-
-                                               xbar_admaif12: endpoint {
-                                                       remote-endpoint = <&admaif12>;
-                                               };
-                                       };
-
-                                       port@d {
-                                               reg = <0xd>;
-
-                                               xbar_admaif13: endpoint {
-                                                       remote-endpoint = <&admaif13>;
-                                               };
-                                       };
-
-                                       port@e {
-                                               reg = <0xe>;
-
-                                               xbar_admaif14: endpoint {
-                                                       remote-endpoint = <&admaif14>;
-                                               };
-                                       };
-
-                                       port@f {
-                                               reg = <0xf>;
-
-                                               xbar_admaif15: endpoint {
-                                                       remote-endpoint = <&admaif15>;
-                                               };
-                                       };
-
-                                       port@10 {
-                                               reg = <0x10>;
-
-                                               xbar_admaif16: endpoint {
-                                                       remote-endpoint = <&admaif16>;
-                                               };
-                                       };
-
-                                       port@11 {
-                                               reg = <0x11>;
-
-                                               xbar_admaif17: endpoint {
-                                                       remote-endpoint = <&admaif17>;
-                                               };
-                                       };
-
-                                       port@12 {
-                                               reg = <0x12>;
-
-                                               xbar_admaif18: endpoint {
-                                                       remote-endpoint = <&admaif18>;
-                                               };
-                                       };
-
-                                       port@13 {
-                                               reg = <0x13>;
-
-                                               xbar_admaif19: endpoint {
-                                                       remote-endpoint = <&admaif19>;
-                                               };
-                                       };
-
-                                       xbar_i2s1_port: port@14 {
-                                               reg = <0x14>;
-
-                                               xbar_i2s1: endpoint {
-                                                       remote-endpoint = <&i2s1_cif>;
-                                               };
-                                       };
-
-                                       xbar_i2s2_port: port@15 {
-                                               reg = <0x15>;
-
-                                               xbar_i2s2: endpoint {
-                                                       remote-endpoint = <&i2s2_cif>;
-                                               };
-                                       };
-
-                                       xbar_i2s4_port: port@17 {
-                                               reg = <0x17>;
-
-                                               xbar_i2s4: endpoint {
-                                                       remote-endpoint = <&i2s4_cif>;
-                                               };
-                                       };
-
-                                       xbar_i2s6_port: port@19 {
-                                               reg = <0x19>;
-
-                                               xbar_i2s6: endpoint {
-                                                       remote-endpoint = <&i2s6_cif>;
-                                               };
-                                       };
-
-                                       xbar_dmic3_port: port@1c {
-                                               reg = <0x1c>;
-
-                                               xbar_dmic3: endpoint {
-                                                       remote-endpoint = <&dmic3_cif>;
-                                               };
-                                       };
-
-                                       xbar_sfc1_in_port: port@20 {
-                                               reg = <0x20>;
-
-                                               xbar_sfc1_in: endpoint {
-                                                       remote-endpoint = <&sfc1_cif_in>;
-                                               };
-                                       };
-
-                                       port@21 {
-                                               reg = <0x21>;
-
-                                               xbar_sfc1_out: endpoint {
-                                                       remote-endpoint = <&sfc1_cif_out>;
-                                               };
-                                       };
-
-                                       xbar_sfc2_in_port: port@22 {
-                                               reg = <0x22>;
-
-                                               xbar_sfc2_in: endpoint {
-                                                       remote-endpoint = <&sfc2_cif_in>;
-                                               };
-                                       };
-
-                                       port@23 {
-                                               reg = <0x23>;
-
-                                               xbar_sfc2_out: endpoint {
-                                                       remote-endpoint = <&sfc2_cif_out>;
-                                               };
-                                       };
-
-                                       xbar_sfc3_in_port: port@24 {
-                                               reg = <0x24>;
-
-                                               xbar_sfc3_in: endpoint {
-                                                       remote-endpoint = <&sfc3_cif_in>;
-                                               };
-                                       };
-
-                                       port@25 {
-                                               reg = <0x25>;
-
-                                               xbar_sfc3_out: endpoint {
-                                                       remote-endpoint = <&sfc3_cif_out>;
-                                               };
-                                       };
-
-                                       xbar_sfc4_in_port: port@26 {
-                                               reg = <0x26>;
-
-                                               xbar_sfc4_in: endpoint {
-                                                       remote-endpoint = <&sfc4_cif_in>;
-                                               };
-                                       };
-
-                                       port@27 {
-                                               reg = <0x27>;
-
-                                               xbar_sfc4_out: endpoint {
-                                                       remote-endpoint = <&sfc4_cif_out>;
-                                               };
-                                       };
-
-                                       xbar_mvc1_in_port: port@28 {
-                                               reg = <0x28>;
-
-                                               xbar_mvc1_in: endpoint {
-                                                       remote-endpoint = <&mvc1_cif_in>;
-                                               };
-                                       };
-
-                                       port@29 {
-                                               reg = <0x29>;
-
-                                               xbar_mvc1_out: endpoint {
-                                                       remote-endpoint = <&mvc1_cif_out>;
-                                               };
-                                       };
-
-                                       xbar_mvc2_in_port: port@2a {
-                                               reg = <0x2a>;
-
-                                               xbar_mvc2_in: endpoint {
-                                                       remote-endpoint = <&mvc2_cif_in>;
-                                               };
-                                       };
-
-                                       port@2b {
-                                               reg = <0x2b>;
-
-                                               xbar_mvc2_out: endpoint {
-                                                       remote-endpoint = <&mvc2_cif_out>;
-                                               };
-                                       };
-
-                                       xbar_amx1_in1_port: port@2c {
-                                               reg = <0x2c>;
-
-                                               xbar_amx1_in1: endpoint {
-                                                       remote-endpoint = <&amx1_in1>;
-                                               };
-                                       };
-
-                                       xbar_amx1_in2_port: port@2d {
-                                               reg = <0x2d>;
-
-                                               xbar_amx1_in2: endpoint {
-                                                       remote-endpoint = <&amx1_in2>;
-                                               };
-                                       };
-
-                                       xbar_amx1_in3_port: port@2e {
-                                               reg = <0x2e>;
-
-                                               xbar_amx1_in3: endpoint {
-                                                       remote-endpoint = <&amx1_in3>;
-                                               };
-                                       };
-
-                                       xbar_amx1_in4_port: port@2f {
-                                               reg = <0x2f>;
-
-                                               xbar_amx1_in4: endpoint {
-                                                       remote-endpoint = <&amx1_in4>;
-                                               };
-                                       };
-
-                                       port@30 {
-                                               reg = <0x30>;
-
-                                               xbar_amx1_out: endpoint {
-                                                       remote-endpoint = <&amx1_out>;
-                                               };
-                                       };
-
-                                       xbar_amx2_in1_port: port@31 {
-                                               reg = <0x31>;
-
-                                               xbar_amx2_in1: endpoint {
-                                                       remote-endpoint = <&amx2_in1>;
-                                               };
-                                       };
-
-                                       xbar_amx2_in2_port: port@32 {
-                                               reg = <0x32>;
-
-                                               xbar_amx2_in2: endpoint {
-                                                       remote-endpoint = <&amx2_in2>;
-                                               };
-                                       };
-
-                                       xbar_amx2_in3_port: port@33 {
-                                               reg = <0x33>;
-
-                                               xbar_amx2_in3: endpoint {
-                                                       remote-endpoint = <&amx2_in3>;
-                                               };
-                                       };
-
-                                       xbar_amx2_in4_port: port@34 {
-                                               reg = <0x34>;
-
-                                               xbar_amx2_in4: endpoint {
-                                                       remote-endpoint = <&amx2_in4>;
-                                               };
-                                       };
-
-                                       port@35 {
-                                               reg = <0x35>;
-
-                                               xbar_amx2_out: endpoint {
-                                                       remote-endpoint = <&amx2_out>;
-                                               };
-                                       };
-
-                                       xbar_amx3_in1_port: port@36 {
-                                               reg = <0x36>;
-
-                                               xbar_amx3_in1: endpoint {
-                                                       remote-endpoint = <&amx3_in1>;
-                                               };
-                                       };
-
-                                       xbar_amx3_in2_port: port@37 {
-                                               reg = <0x37>;
-
-                                               xbar_amx3_in2: endpoint {
-                                                       remote-endpoint = <&amx3_in2>;
-                                               };
-                                       };
-
-                                       xbar_amx3_in3_port: port@38 {
-                                               reg = <0x38>;
-
-                                               xbar_amx3_in3: endpoint {
-                                                       remote-endpoint = <&amx3_in3>;
-                                               };
-                                       };
-
-                                       xbar_amx3_in4_port: port@39 {
-                                               reg = <0x39>;
-
-                                               xbar_amx3_in4: endpoint {
-                                                       remote-endpoint = <&amx3_in4>;
-                                               };
-                                       };
-
-                                       port@3a {
-                                               reg = <0x3a>;
-
-                                               xbar_amx3_out: endpoint {
-                                                       remote-endpoint = <&amx3_out>;
-                                               };
-                                       };
-
-                                       xbar_amx4_in1_port: port@3b {
-                                               reg = <0x3b>;
-
-                                               xbar_amx4_in1: endpoint {
-                                                       remote-endpoint = <&amx4_in1>;
-                                               };
-                                       };
-
-                                       xbar_amx4_in2_port: port@3c {
-                                               reg = <0x3c>;
-
-                                               xbar_amx4_in2: endpoint {
-                                                       remote-endpoint = <&amx4_in2>;
-                                               };
-                                       };
-
-                                       xbar_amx4_in3_port: port@3d {
-                                               reg = <0x3d>;
-
-                                               xbar_amx4_in3: endpoint {
-                                                       remote-endpoint = <&amx4_in3>;
-                                               };
-                                       };
-
-                                       xbar_amx4_in4_port: port@3e {
-                                               reg = <0x3e>;
-
-                                               xbar_amx4_in4: endpoint {
-                                                       remote-endpoint = <&amx4_in4>;
-                                               };
-                                       };
-
-                                       port@3f {
-                                               reg = <0x3f>;
-
-                                               xbar_amx4_out: endpoint {
-                                                       remote-endpoint = <&amx4_out>;
-                                               };
-                                       };
-
-                                       xbar_adx1_in_port: port@40 {
-                                               reg = <0x40>;
-
-                                               xbar_adx1_in: endpoint {
-                                                       remote-endpoint = <&adx1_in>;
-                                               };
-                                       };
-
-                                       port@41 {
-                                               reg = <0x41>;
-
-                                               xbar_adx1_out1: endpoint {
-                                                       remote-endpoint = <&adx1_out1>;
-                                               };
-                                       };
-
-                                       port@42 {
-                                               reg = <0x42>;
-
-                                               xbar_adx1_out2: endpoint {
-                                                       remote-endpoint = <&adx1_out2>;
-                                               };
-                                       };
-
-                                       port@43 {
-                                               reg = <0x43>;
-
-                                               xbar_adx1_out3: endpoint {
-                                                       remote-endpoint = <&adx1_out3>;
-                                               };
-                                       };
-
-                                       port@44 {
-                                               reg = <0x44>;
-
-                                               xbar_adx1_out4: endpoint {
-                                                       remote-endpoint = <&adx1_out4>;
-                                               };
-                                       };
-
-                                       xbar_adx2_in_port: port@45 {
-                                               reg = <0x45>;
-
-                                               xbar_adx2_in: endpoint {
-                                                       remote-endpoint = <&adx2_in>;
-                                               };
-                                       };
-
-                                       port@46 {
-                                               reg = <0x46>;
-
-                                               xbar_adx2_out1: endpoint {
-                                                       remote-endpoint = <&adx2_out1>;
-                                               };
-                                       };
-
-                                       port@47 {
-                                               reg = <0x47>;
-
-                                               xbar_adx2_out2: endpoint {
-                                                       remote-endpoint = <&adx2_out2>;
-                                               };
-                                       };
-
-                                       port@48 {
-                                               reg = <0x48>;
-
-                                               xbar_adx2_out3: endpoint {
-                                                       remote-endpoint = <&adx2_out3>;
-                                               };
-                                       };
-
-                                       port@49 {
-                                               reg = <0x49>;
-
-                                               xbar_adx2_out4: endpoint {
-                                                       remote-endpoint = <&adx2_out4>;
-                                               };
-                                       };
-
-                                       xbar_adx3_in_port: port@4a {
-                                               reg = <0x4a>;
-
-                                               xbar_adx3_in: endpoint {
-                                                       remote-endpoint = <&adx3_in>;
-                                               };
-                                       };
-
-                                       port@4b {
-                                               reg = <0x4b>;
-
-                                               xbar_adx3_out1: endpoint {
-                                                       remote-endpoint = <&adx3_out1>;
-                                               };
-                                       };
-
-                                       port@4c {
-                                               reg = <0x4c>;
-
-                                               xbar_adx3_out2: endpoint {
-                                                       remote-endpoint = <&adx3_out2>;
-                                               };
-                                       };
-
-                                       port@4d {
-                                               reg = <0x4d>;
-
-                                               xbar_adx3_out3: endpoint {
-                                                       remote-endpoint = <&adx3_out3>;
-                                               };
-                                       };
-
-                                       port@4e {
-                                               reg = <0x4e>;
-
-                                               xbar_adx3_out4: endpoint {
-                                                       remote-endpoint = <&adx3_out4>;
-                                               };
-                                       };
-
-                                       xbar_adx4_in_port: port@4f {
-                                               reg = <0x4f>;
-
-                                               xbar_adx4_in: endpoint {
-                                                       remote-endpoint = <&adx4_in>;
-                                               };
-                                       };
-
-                                       port@50 {
-                                               reg = <0x50>;
-
-                                               xbar_adx4_out1: endpoint {
-                                                       remote-endpoint = <&adx4_out1>;
-                                               };
-                                       };
-
-                                       port@51 {
-                                               reg = <0x51>;
-
-                                               xbar_adx4_out2: endpoint {
-                                                       remote-endpoint = <&adx4_out2>;
-                                               };
-                                       };
-
-                                       port@52 {
-                                               reg = <0x52>;
-
-                                               xbar_adx4_out3: endpoint {
-                                                       remote-endpoint = <&adx4_out3>;
-                                               };
-                                       };
-
-                                       port@53 {
-                                               reg = <0x53>;
-
-                                               xbar_adx4_out4: endpoint {
-                                                       remote-endpoint = <&adx4_out4>;
-                                               };
-                                       };
-
-                                       xbar_mix_in1_port: port@54 {
-                                               reg = <0x54>;
-
-                                               xbar_mix_in1: endpoint {
-                                                       remote-endpoint = <&mix_in1>;
-                                               };
-                                       };
-
-                                       xbar_mix_in2_port: port@55 {
-                                               reg = <0x55>;
-
-                                               xbar_mix_in2: endpoint {
-                                                       remote-endpoint = <&mix_in2>;
-                                               };
-                                       };
-
-                                       xbar_mix_in3_port: port@56 {
-                                               reg = <0x56>;
-
-                                               xbar_mix_in3: endpoint {
-                                                       remote-endpoint = <&mix_in3>;
-                                               };
-                                       };
-
-                                       xbar_mix_in4_port: port@57 {
-                                               reg = <0x57>;
-
-                                               xbar_mix_in4: endpoint {
-                                                       remote-endpoint = <&mix_in4>;
-                                               };
-                                       };
-
-                                       xbar_mix_in5_port: port@58 {
-                                               reg = <0x58>;
-
-                                               xbar_mix_in5: endpoint {
-                                                       remote-endpoint = <&mix_in5>;
-                                               };
-                                       };
-
-                                       xbar_mix_in6_port: port@59 {
-                                               reg = <0x59>;
-
-                                               xbar_mix_in6: endpoint {
-                                                       remote-endpoint = <&mix_in6>;
-                                               };
-                                       };
-
-                                       xbar_mix_in7_port: port@5a {
-                                               reg = <0x5a>;
-
-                                               xbar_mix_in7: endpoint {
-                                                       remote-endpoint = <&mix_in7>;
-                                               };
-                                       };
-
-                                       xbar_mix_in8_port: port@5b {
-                                               reg = <0x5b>;
-
-                                               xbar_mix_in8: endpoint {
-                                                       remote-endpoint = <&mix_in8>;
-                                               };
-                                       };
-
-                                       xbar_mix_in9_port: port@5c {
-                                               reg = <0x5c>;
-
-                                               xbar_mix_in9: endpoint {
-                                                       remote-endpoint = <&mix_in9>;
-                                               };
-                                       };
-
-                                       xbar_mix_in10_port: port@5d {
-                                               reg = <0x5d>;
-
-                                               xbar_mix_in10: endpoint {
-                                                       remote-endpoint = <&mix_in10>;
-                                               };
-                                       };
-
-                                       port@5e {
-                                               reg = <0x5e>;
-
-                                               xbar_mix_out1: endpoint {
-                                                       remote-endpoint = <&mix_out1>;
-                                               };
-                                       };
-
-                                       port@5f {
-                                               reg = <0x5f>;
-
-                                               xbar_mix_out2: endpoint {
-                                                       remote-endpoint = <&mix_out2>;
-                                               };
-                                       };
-
-                                       port@60 {
-                                               reg = <0x60>;
-
-                                               xbar_mix_out3: endpoint {
-                                                       remote-endpoint = <&mix_out3>;
-                                               };
-                                       };
-
-                                       port@61 {
-                                               reg = <0x61>;
-
-                                               xbar_mix_out4: endpoint {
-                                                       remote-endpoint = <&mix_out4>;
-                                               };
-                                       };
-
-                                       port@62 {
-                                               reg = <0x62>;
-
-                                               xbar_mix_out5: endpoint {
-                                                       remote-endpoint = <&mix_out5>;
-                                               };
-                                       };
-
-                                       xbar_asrc_in1_port: port@63 {
-                                               reg = <0x63>;
-
-                                               xbar_asrc_in1_ep: endpoint {
-                                                       remote-endpoint = <&asrc_in1_ep>;
-                                               };
-                                       };
-
-                                       port@64 {
-                                               reg = <0x64>;
-
-                                               xbar_asrc_out1_ep: endpoint {
-                                                       remote-endpoint = <&asrc_out1_ep>;
-                                               };
-                                       };
-
-                                       xbar_asrc_in2_port: port@65 {
-                                               reg = <0x65>;
-
-                                               xbar_asrc_in2_ep: endpoint {
-                                                       remote-endpoint = <&asrc_in2_ep>;
-                                               };
-                                       };
-
-                                       port@66 {
-                                               reg = <0x66>;
-
-                                               xbar_asrc_out2_ep: endpoint {
-                                                       remote-endpoint = <&asrc_out2_ep>;
-                                               };
-                                       };
-
-                                       xbar_asrc_in3_port: port@67 {
-                                               reg = <0x67>;
-
-                                               xbar_asrc_in3_ep: endpoint {
-                                                       remote-endpoint = <&asrc_in3_ep>;
-                                               };
-                                       };
-
-                                       port@68 {
-                                               reg = <0x68>;
-
-                                               xbar_asrc_out3_ep: endpoint {
-                                                       remote-endpoint = <&asrc_out3_ep>;
-                                               };
-                                       };
-
-                                       xbar_asrc_in4_port: port@69 {
-                                               reg = <0x69>;
-
-                                               xbar_asrc_in4_ep: endpoint {
-                                                       remote-endpoint = <&asrc_in4_ep>;
-                                               };
-                                       };
-
-                                       port@6a {
-                                               reg = <0x6a>;
-
-                                               xbar_asrc_out4_ep: endpoint {
-                                                       remote-endpoint = <&asrc_out4_ep>;
-                                               };
-                                       };
-
-                                       xbar_asrc_in5_port: port@6b {
-                                               reg = <0x6b>;
-
-                                               xbar_asrc_in5_ep: endpoint {
-                                                       remote-endpoint = <&asrc_in5_ep>;
-                                               };
-                                       };
-
-                                       port@6c {
-                                               reg = <0x6c>;
-
-                                               xbar_asrc_out5_ep: endpoint {
-                                                       remote-endpoint = <&asrc_out5_ep>;
-                                               };
-                                       };
-
-                                       xbar_asrc_in6_port: port@6d {
-                                               reg = <0x6d>;
-
-                                               xbar_asrc_in6_ep: endpoint {
-                                                       remote-endpoint = <&asrc_in6_ep>;
-                                               };
-                                       };
-
-                                       port@6e {
-                                               reg = <0x6e>;
-
-                                               xbar_asrc_out6_ep: endpoint {
-                                                       remote-endpoint = <&asrc_out6_ep>;
-                                               };
-                                       };
-
-                                       xbar_asrc_in7_port: port@6f {
-                                               reg = <0x6f>;
-
-                                               xbar_asrc_in7_ep: endpoint {
-                                                       remote-endpoint = <&asrc_in7_ep>;
-                                               };
-                                       };
-
-                                       xbar_ope1_in_port: port@70 {
-                                               reg = <0x70>;
-
-                                               xbar_ope1_in_ep: endpoint {
-                                                       remote-endpoint = <&ope1_cif_in_ep>;
-                                               };
-                                       };
-
-                                       port@71 {
-                                               reg = <0x71>;
-
-                                               xbar_ope1_out_ep: endpoint {
-                                                       remote-endpoint = <&ope1_cif_out_ep>;
-                                               };
-                                       };
                                };
                        };
 
index ea13c4a7027c46ba5f5151947537b5376bcbad20..69db584253dae88b5d0d80f6530ad2fc9897e2ad 100644 (file)
@@ -12,7 +12,6 @@
        compatible = "nvidia,p3737-0000+p3701-0000", "nvidia,p3701-0000", "nvidia,tegra234";
 
        aliases {
-               mmc3 = "/bus@0/mmc@3460000";
                serial0 = &tcu;
                serial1 = &uarta;
        };
                        status = "okay";
 
                        phy-handle = <&mgbe0_phy>;
-                       phy-mode = "usxgmii";
+                       phy-mode = "10gbase-r";
 
                        mdio {
                                #address-cells = <1>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3767-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3767-0000.dtsi
deleted file mode 100644 (file)
index baf4f69..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include "tegra234-p3767.dtsi"
-
-/ {
-       compatible = "nvidia,p3767-0000", "nvidia,tegra234";
-       model = "NVIDIA Jetson Orin NX";
-
-       bus@0 {
-               hda@3510000 {
-                       nvidia,model = "NVIDIA Jetson Orin NX HDA";
-               };
-       };
-};
diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3767-0005.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3767-0005.dtsi
deleted file mode 100644 (file)
index 232fa95..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include "tegra234-p3767.dtsi"
-
-/ {
-       compatible = "nvidia,p3767-0005", "nvidia,tegra234";
-       model = "NVIDIA Jetson Orin Nano";
-
-       bus@0 {
-               hda@3510000 {
-                       nvidia,model = "NVIDIA Jetson Orin Nano HDA";
-               };
-       };
-};
index 59c14ded5e9fac10023e76078d99efec25e00b24..84db7132e8fc8367e78ff7539b3f58c6444d7d7e 100644 (file)
@@ -5,7 +5,35 @@
 / {
        compatible = "nvidia,p3767", "nvidia,tegra234";
 
+       aliases {
+               mmc0 = "/bus@0/mmc@3400000";
+       };
+
        bus@0 {
+               aconnect@2900000 {
+                       status = "okay";
+
+                       ahub@2900800 {
+                               status = "okay";
+
+                               i2s@2901100 {
+                                       status = "okay";
+                               };
+
+                               i2s@2901300 {
+                                       status = "okay";
+                               };
+                       };
+
+                       dma-controller@2930000 {
+                               status = "okay";
+                       };
+
+                       interrupt-controller@2a40000 {
+                               status = "okay";
+                       };
+               };
+
                i2c@3160000 {
                        status = "okay";
 
                vin-supply = <&vdd_5v0_sys>;
        };
 
+       sound {
+               compatible = "nvidia,tegra186-audio-graph-card";
+               status = "okay";
+
+               dais = /* ADMAIF (FE) Ports */
+                      <&admaif0_port>, <&admaif1_port>, <&admaif2_port>, <&admaif3_port>,
+                      <&admaif4_port>, <&admaif5_port>, <&admaif6_port>, <&admaif7_port>,
+                      <&admaif8_port>, <&admaif9_port>, <&admaif10_port>, <&admaif11_port>,
+                      <&admaif12_port>, <&admaif13_port>, <&admaif14_port>, <&admaif15_port>,
+                      <&admaif16_port>, <&admaif17_port>, <&admaif18_port>, <&admaif19_port>,
+                      /* XBAR Ports */
+                      <&xbar_i2s2_port>, <&xbar_i2s4_port>,
+                      <&xbar_sfc1_in_port>, <&xbar_sfc2_in_port>,
+                      <&xbar_sfc3_in_port>, <&xbar_sfc4_in_port>,
+                      <&xbar_mvc1_in_port>, <&xbar_mvc2_in_port>,
+                      <&xbar_amx1_in1_port>, <&xbar_amx1_in2_port>,
+                      <&xbar_amx1_in3_port>, <&xbar_amx1_in4_port>,
+                      <&xbar_amx2_in1_port>, <&xbar_amx2_in2_port>,
+                      <&xbar_amx2_in3_port>, <&xbar_amx2_in4_port>,
+                      <&xbar_amx3_in1_port>, <&xbar_amx3_in2_port>,
+                      <&xbar_amx3_in3_port>, <&xbar_amx3_in4_port>,
+                      <&xbar_amx4_in1_port>, <&xbar_amx4_in2_port>,
+                      <&xbar_amx4_in3_port>, <&xbar_amx4_in4_port>,
+                      <&xbar_adx1_in_port>, <&xbar_adx2_in_port>,
+                      <&xbar_adx3_in_port>, <&xbar_adx4_in_port>,
+                      <&xbar_mix_in1_port>, <&xbar_mix_in2_port>,
+                      <&xbar_mix_in3_port>, <&xbar_mix_in4_port>,
+                      <&xbar_mix_in5_port>, <&xbar_mix_in6_port>,
+                      <&xbar_mix_in7_port>, <&xbar_mix_in8_port>,
+                      <&xbar_mix_in9_port>, <&xbar_mix_in10_port>,
+                      <&xbar_asrc_in1_port>, <&xbar_asrc_in2_port>,
+                      <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
+                      <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
+                      <&xbar_asrc_in7_port>,
+                      <&xbar_ope1_in_port>,
+                      /* HW accelerators */
+                      <&sfc1_out_port>, <&sfc2_out_port>,
+                      <&sfc3_out_port>, <&sfc4_out_port>,
+                      <&mvc1_out_port>, <&mvc2_out_port>,
+                      <&amx1_out_port>, <&amx2_out_port>,
+                      <&amx3_out_port>, <&amx4_out_port>,
+                      <&adx1_out1_port>, <&adx1_out2_port>,
+                      <&adx1_out3_port>, <&adx1_out4_port>,
+                      <&adx2_out1_port>, <&adx2_out2_port>,
+                      <&adx2_out3_port>, <&adx2_out4_port>,
+                      <&adx3_out1_port>, <&adx3_out2_port>,
+                      <&adx3_out3_port>, <&adx3_out4_port>,
+                      <&adx4_out1_port>, <&adx4_out2_port>,
+                      <&adx4_out3_port>, <&adx4_out4_port>,
+                      <&mix_out1_port>, <&mix_out2_port>, <&mix_out3_port>,
+                      <&mix_out4_port>, <&mix_out5_port>,
+                      <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
+                      <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+                      <&ope1_out_port>,
+                      /* BE I/O Ports */
+                      <&i2s2_port>, <&i2s4_port>;
+       };
+
        thermal-zones {
                tj-thermal {
                        polling-delay = <1000>;
index 61b0e69d3d205373ecc18e16ca647f2452973346..1607ee14216fbc00c9a1d17a9173dd1137170c12 100644 (file)
@@ -4,7 +4,7 @@
 #include <dt-bindings/input/linux-event-codes.h>
 #include <dt-bindings/input/gpio-keys.h>
 
-#include "tegra234-p3767-0000.dtsi"
+#include "tegra234-p3767.dtsi"
 #include "tegra234-p3768-0000.dtsi"
 
 / {
@@ -37,7 +37,6 @@
 
                hda@3510000 {
                        nvidia,model = "NVIDIA Jetson Orin NX HDA";
-                       status = "okay";
                };
 
                padctl@3520000 {
                enable-active-high;
        };
 
+       sound {
+               label = "NVIDIA Jetson Orin NX APE";
+       };
+
        thermal-zones {
                tj-thermal {
                        cooling-maps {
index 9e9bb9ca8be40547d129842477e77a745cb3bf9d..dc2d4bef1e839907f2f5b99ab93a4e6eb90e58ce 100644 (file)
@@ -4,17 +4,27 @@
 #include <dt-bindings/input/linux-event-codes.h>
 #include <dt-bindings/input/gpio-keys.h>
 
-#include "tegra234-p3767-0005.dtsi"
+#include "tegra234-p3767.dtsi"
 #include "tegra234-p3768-0000.dtsi"
 
 / {
        compatible = "nvidia,p3768-0000+p3767-0005", "nvidia,p3767-0005", "nvidia,tegra234";
        model = "NVIDIA Jetson Orin Nano Developer Kit";
 
+       bus@0 {
+               hda@3510000 {
+                       nvidia,model = "NVIDIA Jetson Orin Nano HDA";
+               };
+       };
+
        pwm-fan {
                cooling-levels = <0 88 187 255>;
        };
 
+       sound {
+               label = "NVIDIA Jetson Orin Nano APE";
+       };
+
        thermal-zones {
                tj-thermal {
                        cooling-maps {
index 9f3e9f30c3f7073d73bcb0481821843d2aed2efd..292e28376eec7f882301236dfb5acb2fddba3cfb 100644 (file)
@@ -8,7 +8,6 @@
        compatible = "nvidia,tegra234-vdk", "nvidia,tegra234";
 
        aliases {
-               mmc3 = "/bus@0/mmc@3460000";
                serial0 = &uarta;
        };
 
index 3f16595d099c5620b0d2dde77f0e2c6491c4a576..78cbfdd98dd12c8bfe3216bf30a6d8d77ce378d2 100644 (file)
                                        assigned-clock-rates = <1536000>;
                                        sound-name-prefix = "I2S1";
                                        status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       i2s1_cif: endpoint {
+                                                               remote-endpoint = <&xbar_i2s1>;
+                                                       };
+                                               };
+
+                                               i2s1_port: port@1 {
+                                                       reg = <1>;
+
+                                                       i2s1_dap: endpoint {
+                                                               dai-format = "i2s";
+                                                               /* placeholder for external codec */
+                                                       };
+                                               };
+                                       };
                                };
 
                                tegra_i2s2: i2s@2901100 {
                                        assigned-clock-rates = <1536000>;
                                        sound-name-prefix = "I2S2";
                                        status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       i2s2_cif: endpoint {
+                                                               remote-endpoint = <&xbar_i2s2>;
+                                                       };
+                                               };
+
+                                               i2s2_port: port@1 {
+                                                       reg = <1>;
+
+                                                       i2s2_dap: endpoint {
+                                                               dai-format = "i2s";
+                                                               /* placeholder for external codec */
+                                                       };
+                                               };
+                                       };
                                };
 
                                tegra_i2s3: i2s@2901200 {
                                        assigned-clock-rates = <1536000>;
                                        sound-name-prefix = "I2S3";
                                        status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       i2s3_cif: endpoint {
+                                                               remote-endpoint = <&xbar_i2s3>;
+                                                       };
+                                               };
+
+                                               i2s3_port: port@1 {
+                                                       reg = <1>;
+
+                                                       i2s3_dap: endpoint {
+                                                               dai-format = "i2s";
+                                                               /* placeholder for external codec */
+                                                       };
+                                               };
+                                       };
                                };
 
                                tegra_i2s4: i2s@2901300 {
                                        assigned-clock-rates = <1536000>;
                                        sound-name-prefix = "I2S4";
                                        status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       i2s4_cif: endpoint {
+                                                               remote-endpoint = <&xbar_i2s4>;
+                                                       };
+                                               };
+
+                                               i2s4_port: port@1 {
+                                                       reg = <1>;
+
+                                                       i2s4_dap: endpoint {
+                                                               dai-format = "i2s";
+                                                               /* placeholder for external codec */
+                                                       };
+                                               };
+                                       };
                                };
 
                                tegra_i2s5: i2s@2901400 {
                                        assigned-clock-rates = <1536000>;
                                        sound-name-prefix = "I2S5";
                                        status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       i2s5_cif: endpoint {
+                                                               remote-endpoint = <&xbar_i2s5>;
+                                                       };
+                                               };
+
+                                               i2s5_port: port@1 {
+                                                       reg = <1>;
+
+                                                       i2s5_dap: endpoint {
+                                                               dai-format = "i2s";
+                                                               /* placeholder for external codec */
+                                                       };
+                                               };
+                                       };
                                };
 
                                tegra_i2s6: i2s@2901500 {
                                        assigned-clock-rates = <1536000>;
                                        sound-name-prefix = "I2S6";
                                        status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       i2s6_cif: endpoint {
+                                                               remote-endpoint = <&xbar_i2s6>;
+                                                       };
+                                               };
+
+                                               i2s6_port: port@1 {
+                                                       reg = <1>;
+
+                                                       i2s6_dap: endpoint {
+                                                               dai-format = "i2s";
+                                                               /* placeholder for external codec */
+                                                       };
+                                               };
+                                       };
                                };
 
                                tegra_sfc1: sfc@2902000 {
                                                     "nvidia,tegra210-sfc";
                                        reg = <0x0 0x2902000 0x0 0x200>;
                                        sound-name-prefix = "SFC1";
-                                       status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       sfc1_cif_in: endpoint {
+                                                               remote-endpoint = <&xbar_sfc1_in>;
+                                                       };
+                                               };
+
+                                               sfc1_out_port: port@1 {
+                                                       reg = <1>;
+
+                                                       sfc1_cif_out: endpoint {
+                                                               remote-endpoint = <&xbar_sfc1_out>;
+                                                       };
+                                               };
+                                       };
                                };
 
                                tegra_sfc2: sfc@2902200 {
                                                     "nvidia,tegra210-sfc";
                                        reg = <0x0 0x2902200 0x0 0x200>;
                                        sound-name-prefix = "SFC2";
-                                       status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       sfc2_cif_in: endpoint {
+                                                               remote-endpoint = <&xbar_sfc2_in>;
+                                                       };
+                                               };
+
+                                               sfc2_out_port: port@1 {
+                                                       reg = <1>;
+
+                                                       sfc2_cif_out: endpoint {
+                                                               remote-endpoint = <&xbar_sfc2_out>;
+                                                       };
+                                               };
+                                       };
                                };
 
                                tegra_sfc3: sfc@2902400 {
                                                     "nvidia,tegra210-sfc";
                                        reg = <0x0 0x2902400 0x0 0x200>;
                                        sound-name-prefix = "SFC3";
-                                       status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       sfc3_cif_in: endpoint {
+                                                               remote-endpoint = <&xbar_sfc3_in>;
+                                                       };
+                                               };
+
+                                               sfc3_out_port: port@1 {
+                                                       reg = <1>;
+
+                                                       sfc3_cif_out: endpoint {
+                                                               remote-endpoint = <&xbar_sfc3_out>;
+                                                       };
+                                               };
+                                       };
                                };
 
                                tegra_sfc4: sfc@2902600 {
                                                     "nvidia,tegra210-sfc";
                                        reg = <0x0 0x2902600 0x0 0x200>;
                                        sound-name-prefix = "SFC4";
-                                       status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       sfc4_cif_in: endpoint {
+                                                               remote-endpoint = <&xbar_sfc4_in>;
+                                                       };
+                                               };
+
+                                               sfc4_out_port: port@1 {
+                                                       reg = <1>;
+
+                                                       sfc4_cif_out: endpoint {
+                                                               remote-endpoint = <&xbar_sfc4_out>;
+                                                       };
+                                               };
+                                       };
                                };
 
                                tegra_amx1: amx@2903000 {
                                                     "nvidia,tegra194-amx";
                                        reg = <0x0 0x2903000 0x0 0x100>;
                                        sound-name-prefix = "AMX1";
-                                       status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       amx1_in1: endpoint {
+                                                               remote-endpoint = <&xbar_amx1_in1>;
+                                                       };
+                                               };
+
+                                               port@1 {
+                                                       reg = <1>;
+
+                                                       amx1_in2: endpoint {
+                                                               remote-endpoint = <&xbar_amx1_in2>;
+                                                       };
+                                               };
+
+                                               port@2 {
+                                                       reg = <2>;
+
+                                                       amx1_in3: endpoint {
+                                                               remote-endpoint = <&xbar_amx1_in3>;
+                                                       };
+                                               };
+
+                                               port@3 {
+                                                       reg = <3>;
+
+                                                       amx1_in4: endpoint {
+                                                               remote-endpoint = <&xbar_amx1_in4>;
+                                                       };
+                                               };
+
+                                               amx1_out_port: port@4 {
+                                                       reg = <4>;
+
+                                                       amx1_out: endpoint {
+                                                               remote-endpoint = <&xbar_amx1_out>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_amx2: amx@2903100 {
+                                       compatible = "nvidia,tegra234-amx",
+                                                    "nvidia,tegra194-amx";
+                                       reg = <0x0 0x2903100 0x0 0x100>;
+                                       sound-name-prefix = "AMX2";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       amx2_in1: endpoint {
+                                                               remote-endpoint = <&xbar_amx2_in1>;
+                                                       };
+                                               };
+
+                                               port@1 {
+                                                       reg = <1>;
+
+                                                       amx2_in2: endpoint {
+                                                               remote-endpoint = <&xbar_amx2_in2>;
+                                                       };
+                                               };
+
+                                               port@2 {
+                                                       reg = <2>;
+
+                                                       amx2_in3: endpoint {
+                                                               remote-endpoint = <&xbar_amx2_in3>;
+                                                       };
+                                               };
+
+                                               port@3 {
+                                                       reg = <3>;
+
+                                                       amx2_in4: endpoint {
+                                                               remote-endpoint = <&xbar_amx2_in4>;
+                                                       };
+                                               };
+
+                                               amx2_out_port: port@4 {
+                                                       reg = <4>;
+
+                                                       amx2_out: endpoint {
+                                                               remote-endpoint = <&xbar_amx2_out>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_amx3: amx@2903200 {
+                                       compatible = "nvidia,tegra234-amx",
+                                                    "nvidia,tegra194-amx";
+                                       reg = <0x0 0x2903200 0x0 0x100>;
+                                       sound-name-prefix = "AMX3";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       amx3_in1: endpoint {
+                                                               remote-endpoint = <&xbar_amx3_in1>;
+                                                       };
+                                               };
+
+                                               port@1 {
+                                                       reg = <1>;
+
+                                                       amx3_in2: endpoint {
+                                                               remote-endpoint = <&xbar_amx3_in2>;
+                                                       };
+                                               };
+
+                                               port@2 {
+                                                       reg = <2>;
+
+                                                       amx3_in3: endpoint {
+                                                               remote-endpoint = <&xbar_amx3_in3>;
+                                                       };
+                                               };
+
+                                               port@3 {
+                                                       reg = <3>;
+
+                                                       amx3_in4: endpoint {
+                                                               remote-endpoint = <&xbar_amx3_in4>;
+                                                       };
+                                               };
+
+                                               amx3_out_port: port@4 {
+                                                       reg = <4>;
+
+                                                       amx3_out: endpoint {
+                                                               remote-endpoint = <&xbar_amx3_out>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_amx4: amx@2903300 {
+                                       compatible = "nvidia,tegra234-amx",
+                                                    "nvidia,tegra194-amx";
+                                       reg = <0x0 0x2903300 0x0 0x100>;
+                                       sound-name-prefix = "AMX4";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       amx4_in1: endpoint {
+                                                               remote-endpoint = <&xbar_amx4_in1>;
+                                                       };
+                                               };
+
+                                               port@1 {
+                                                       reg = <1>;
+
+                                                       amx4_in2: endpoint {
+                                                               remote-endpoint = <&xbar_amx4_in2>;
+                                                       };
+                                               };
+
+                                               port@2 {
+                                                       reg = <2>;
+
+                                                       amx4_in3: endpoint {
+                                                               remote-endpoint = <&xbar_amx4_in3>;
+                                                       };
+                                               };
+
+                                               port@3 {
+                                                       reg = <3>;
+
+                                                       amx4_in4: endpoint {
+                                                               remote-endpoint = <&xbar_amx4_in4>;
+                                                       };
+                                               };
+
+                                               amx4_out_port: port@4 {
+                                                       reg = <4>;
+
+                                                       amx4_out: endpoint {
+                                                               remote-endpoint = <&xbar_amx4_out>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_adx1: adx@2903800 {
+                                       compatible = "nvidia,tegra234-adx",
+                                                    "nvidia,tegra210-adx";
+                                       reg = <0x0 0x2903800 0x0 0x100>;
+                                       sound-name-prefix = "ADX1";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       adx1_in: endpoint {
+                                                               remote-endpoint = <&xbar_adx1_in>;
+                                                       };
+                                               };
+
+                                               adx1_out1_port: port@1 {
+                                                       reg = <1>;
+
+                                                       adx1_out1: endpoint {
+                                                               remote-endpoint = <&xbar_adx1_out1>;
+                                                       };
+                                               };
+
+                                               adx1_out2_port: port@2 {
+                                                       reg = <2>;
+
+                                                       adx1_out2: endpoint {
+                                                               remote-endpoint = <&xbar_adx1_out2>;
+                                                       };
+                                               };
+
+                                               adx1_out3_port: port@3 {
+                                                       reg = <3>;
+
+                                                       adx1_out3: endpoint {
+                                                               remote-endpoint = <&xbar_adx1_out3>;
+                                                       };
+                                               };
+
+                                               adx1_out4_port: port@4 {
+                                                       reg = <4>;
+
+                                                       adx1_out4: endpoint {
+                                                               remote-endpoint = <&xbar_adx1_out4>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_adx2: adx@2903900 {
+                                       compatible = "nvidia,tegra234-adx",
+                                                    "nvidia,tegra210-adx";
+                                       reg = <0x0 0x2903900 0x0 0x100>;
+                                       sound-name-prefix = "ADX2";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       adx2_in: endpoint {
+                                                               remote-endpoint = <&xbar_adx2_in>;
+                                                       };
+                                               };
+
+                                               adx2_out1_port: port@1 {
+                                                       reg = <1>;
+
+                                                       adx2_out1: endpoint {
+                                                               remote-endpoint = <&xbar_adx2_out1>;
+                                                       };
+                                               };
+
+                                               adx2_out2_port: port@2 {
+                                                       reg = <2>;
+
+                                                       adx2_out2: endpoint {
+                                                               remote-endpoint = <&xbar_adx2_out2>;
+                                                       };
+                                               };
+
+                                               adx2_out3_port: port@3 {
+                                                       reg = <3>;
+
+                                                       adx2_out3: endpoint {
+                                                               remote-endpoint = <&xbar_adx2_out3>;
+                                                       };
+                                               };
+
+                                               adx2_out4_port: port@4 {
+                                                       reg = <4>;
+
+                                                       adx2_out4: endpoint {
+                                                               remote-endpoint = <&xbar_adx2_out4>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_adx3: adx@2903a00 {
+                                       compatible = "nvidia,tegra234-adx",
+                                                    "nvidia,tegra210-adx";
+                                       reg = <0x0 0x2903a00 0x0 0x100>;
+                                       sound-name-prefix = "ADX3";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       adx3_in: endpoint {
+                                                               remote-endpoint = <&xbar_adx3_in>;
+                                                       };
+                                               };
+
+                                               adx3_out1_port: port@1 {
+                                                       reg = <1>;
+
+                                                       adx3_out1: endpoint {
+                                                               remote-endpoint = <&xbar_adx3_out1>;
+                                                       };
+                                               };
+
+                                               adx3_out2_port: port@2 {
+                                                       reg = <2>;
+
+                                                       adx3_out2: endpoint {
+                                                               remote-endpoint = <&xbar_adx3_out2>;
+                                                       };
+                                               };
+
+                                               adx3_out3_port: port@3 {
+                                                       reg = <3>;
+
+                                                       adx3_out3: endpoint {
+                                                               remote-endpoint = <&xbar_adx3_out3>;
+                                                       };
+                                               };
+
+                                               adx3_out4_port: port@4 {
+                                                       reg = <4>;
+
+                                                       adx3_out4: endpoint {
+                                                               remote-endpoint = <&xbar_adx3_out4>;
+                                                       };
+                                               };
+                                       };
                                };
 
-                               tegra_amx2: amx@2903100 {
-                                       compatible = "nvidia,tegra234-amx",
-                                                    "nvidia,tegra194-amx";
-                                       reg = <0x0 0x2903100 0x0 0x100>;
-                                       sound-name-prefix = "AMX2";
-                                       status = "disabled";
-                               };
+                               tegra_adx4: adx@2903b00 {
+                                       compatible = "nvidia,tegra234-adx",
+                                                    "nvidia,tegra210-adx";
+                                       reg = <0x0 0x2903b00 0x0 0x100>;
+                                       sound-name-prefix = "ADX4";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       adx4_in: endpoint {
+                                                               remote-endpoint = <&xbar_adx4_in>;
+                                                       };
+                                               };
+
+                                               adx4_out1_port: port@1 {
+                                                       reg = <1>;
+
+                                                       adx4_out1: endpoint {
+                                                               remote-endpoint = <&xbar_adx4_out1>;
+                                                       };
+                                               };
+
+                                               adx4_out2_port: port@2 {
+                                                       reg = <2>;
+
+                                                       adx4_out2: endpoint {
+                                                               remote-endpoint = <&xbar_adx4_out2>;
+                                                       };
+                                               };
+
+                                               adx4_out3_port: port@3 {
+                                                       reg = <3>;
+
+                                                       adx4_out3: endpoint {
+                                                               remote-endpoint = <&xbar_adx4_out3>;
+                                                       };
+                                               };
+
+                                               adx4_out4_port: port@4 {
+                                                       reg = <4>;
+
+                                                       adx4_out4: endpoint {
+                                                               remote-endpoint = <&xbar_adx4_out4>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+
+                               tegra_dmic1: dmic@2904000 {
+                                       compatible = "nvidia,tegra234-dmic",
+                                                    "nvidia,tegra210-dmic";
+                                       reg = <0x0 0x2904000 0x0 0x100>;
+                                       clocks = <&bpmp TEGRA234_CLK_DMIC1>;
+                                       clock-names = "dmic";
+                                       assigned-clocks = <&bpmp TEGRA234_CLK_DMIC1>;
+                                       assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA_OUT0>;
+                                       assigned-clock-rates = <3072000>;
+                                       sound-name-prefix = "DMIC1";
+                                       status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       dmic1_cif: endpoint {
+                                                               remote-endpoint = <&xbar_dmic1>;
+                                                       };
+                                               };
+
+                                               dmic1_port: port@1 {
+                                                       reg = <1>;
+
+                                                       dmic1_dap: endpoint {
+                                                               /* placeholder for external codec */
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_dmic2: dmic@2904100 {
+                                       compatible = "nvidia,tegra234-dmic",
+                                                    "nvidia,tegra210-dmic";
+                                       reg = <0x0 0x2904100 0x0 0x100>;
+                                       clocks = <&bpmp TEGRA234_CLK_DMIC2>;
+                                       clock-names = "dmic";
+                                       assigned-clocks = <&bpmp TEGRA234_CLK_DMIC2>;
+                                       assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA_OUT0>;
+                                       assigned-clock-rates = <3072000>;
+                                       sound-name-prefix = "DMIC2";
+                                       status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       dmic2_cif: endpoint {
+                                                               remote-endpoint = <&xbar_dmic2>;
+                                                       };
+                                               };
+
+                                               dmic2_port: port@1 {
+                                                       reg = <1>;
+
+                                                       dmic2_dap: endpoint {
+                                                               /* placeholder for external codec */
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_dmic3: dmic@2904200 {
+                                       compatible = "nvidia,tegra234-dmic",
+                                                    "nvidia,tegra210-dmic";
+                                       reg = <0x0 0x2904200 0x0 0x100>;
+                                       clocks = <&bpmp TEGRA234_CLK_DMIC3>;
+                                       clock-names = "dmic";
+                                       assigned-clocks = <&bpmp TEGRA234_CLK_DMIC3>;
+                                       assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA_OUT0>;
+                                       assigned-clock-rates = <3072000>;
+                                       sound-name-prefix = "DMIC3";
+                                       status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       dmic3_cif: endpoint {
+                                                               remote-endpoint = <&xbar_dmic3>;
+                                                       };
+                                               };
+
+                                               dmic3_port: port@1 {
+                                                       reg = <1>;
+
+                                                       dmic3_dap: endpoint {
+                                                               /* placeholder for external codec */
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_dmic4: dmic@2904300 {
+                                       compatible = "nvidia,tegra234-dmic",
+                                                    "nvidia,tegra210-dmic";
+                                       reg = <0x0 0x2904300 0x0 0x100>;
+                                       clocks = <&bpmp TEGRA234_CLK_DMIC4>;
+                                       clock-names = "dmic";
+                                       assigned-clocks = <&bpmp TEGRA234_CLK_DMIC4>;
+                                       assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA_OUT0>;
+                                       assigned-clock-rates = <3072000>;
+                                       sound-name-prefix = "DMIC4";
+                                       status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       dmic4_cif: endpoint {
+                                                               remote-endpoint = <&xbar_dmic4>;
+                                                       };
+                                               };
+
+                                               dmic4_port: port@1 {
+                                                       reg = <1>;
+
+                                                       dmic4_dap: endpoint {
+                                                               /* placeholder for external codec */
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_dspk1: dspk@2905000 {
+                                       compatible = "nvidia,tegra234-dspk",
+                                                    "nvidia,tegra186-dspk";
+                                       reg = <0x0 0x2905000 0x0 0x100>;
+                                       clocks = <&bpmp TEGRA234_CLK_DSPK1>;
+                                       clock-names = "dspk";
+                                       assigned-clocks = <&bpmp TEGRA234_CLK_DSPK1>;
+                                       assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA_OUT0>;
+                                       assigned-clock-rates = <12288000>;
+                                       sound-name-prefix = "DSPK1";
+                                       status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       dspk1_cif: endpoint {
+                                                               remote-endpoint = <&xbar_dspk1>;
+                                                       };
+                                               };
+
+                                               dspk1_port: port@1 {
+                                                       reg = <1>;
+
+                                                       dspk1_dap: endpoint {
+                                                               /* placeholder for external codec */
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_dspk2: dspk@2905100 {
+                                       compatible = "nvidia,tegra234-dspk",
+                                                    "nvidia,tegra186-dspk";
+                                       reg = <0x0 0x2905100 0x0 0x100>;
+                                       clocks = <&bpmp TEGRA234_CLK_DSPK2>;
+                                       clock-names = "dspk";
+                                       assigned-clocks = <&bpmp TEGRA234_CLK_DSPK2>;
+                                       assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA_OUT0>;
+                                       assigned-clock-rates = <12288000>;
+                                       sound-name-prefix = "DSPK2";
+                                       status = "disabled";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       dspk2_cif: endpoint {
+                                                               remote-endpoint = <&xbar_dspk2>;
+                                                       };
+                                               };
+
+                                               dspk2_port: port@1 {
+                                                       reg = <1>;
+
+                                                       dspk2_dap: endpoint {
+                                                               /* placeholder for external codec */
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_ope1: processing-engine@2908000 {
+                                       compatible = "nvidia,tegra234-ope",
+                                                    "nvidia,tegra210-ope";
+                                       reg = <0x0 0x2908000 0x0 0x100>;
+                                       sound-name-prefix = "OPE1";
+
+                                       #address-cells = <2>;
+                                       #size-cells = <2>;
+                                       ranges;
+
+                                       equalizer@2908100 {
+                                               compatible = "nvidia,tegra234-peq",
+                                                            "nvidia,tegra210-peq";
+                                               reg = <0x0 0x2908100 0x0 0x100>;
+                                       };
+
+                                       dynamic-range-compressor@2908200 {
+                                               compatible = "nvidia,tegra234-mbdrc",
+                                                            "nvidia,tegra210-mbdrc";
+                                               reg = <0x0 0x2908200 0x0 0x200>;
+                                       };
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0x0>;
+
+                                                       ope1_cif_in_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_ope1_in_ep>;
+                                                       };
+                                               };
+
+                                               ope1_out_port: port@1 {
+                                                       reg = <0x1>;
+
+                                                       ope1_cif_out_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_ope1_out_ep>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_mvc1: mvc@290a000 {
+                                       compatible = "nvidia,tegra234-mvc",
+                                                    "nvidia,tegra210-mvc";
+                                       reg = <0x0 0x290a000 0x0 0x200>;
+                                       sound-name-prefix = "MVC1";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       mvc1_cif_in: endpoint {
+                                                               remote-endpoint = <&xbar_mvc1_in>;
+                                                       };
+                                               };
+
+                                               mvc1_out_port: port@1 {
+                                                       reg = <1>;
+
+                                                       mvc1_cif_out: endpoint {
+                                                               remote-endpoint = <&xbar_mvc1_out>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_mvc2: mvc@290a200 {
+                                       compatible = "nvidia,tegra234-mvc",
+                                                    "nvidia,tegra210-mvc";
+                                       reg = <0x0 0x290a200 0x0 0x200>;
+                                       sound-name-prefix = "MVC2";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0>;
+
+                                                       mvc2_cif_in: endpoint {
+                                                               remote-endpoint = <&xbar_mvc2_in>;
+                                                       };
+                                               };
+
+                                               mvc2_out_port: port@1 {
+                                                       reg = <1>;
+
+                                                       mvc2_cif_out: endpoint {
+                                                               remote-endpoint = <&xbar_mvc2_out>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_amixer: amixer@290bb00 {
+                                       compatible = "nvidia,tegra234-amixer",
+                                                    "nvidia,tegra210-amixer";
+                                       reg = <0x0 0x290bb00 0x0 0x800>;
+                                       sound-name-prefix = "MIXER1";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0x0>;
+
+                                                       mix_in1: endpoint {
+                                                               remote-endpoint = <&xbar_mix_in1>;
+                                                       };
+                                               };
+
+                                               port@1 {
+                                                       reg = <0x1>;
+
+                                                       mix_in2: endpoint {
+                                                               remote-endpoint = <&xbar_mix_in2>;
+                                                       };
+                                               };
+
+                                               port@2 {
+                                                       reg = <0x2>;
+
+                                                       mix_in3: endpoint {
+                                                               remote-endpoint = <&xbar_mix_in3>;
+                                                       };
+                                               };
+
+                                               port@3 {
+                                                       reg = <0x3>;
+
+                                                       mix_in4: endpoint {
+                                                               remote-endpoint = <&xbar_mix_in4>;
+                                                       };
+                                               };
+
+                                               port@4 {
+                                                       reg = <0x4>;
+
+                                                       mix_in5: endpoint {
+                                                               remote-endpoint = <&xbar_mix_in5>;
+                                                       };
+                                               };
+
+                                               port@5 {
+                                                       reg = <0x5>;
+
+                                                       mix_in6: endpoint {
+                                                               remote-endpoint = <&xbar_mix_in6>;
+                                                       };
+                                               };
+
+                                               port@6 {
+                                                       reg = <0x6>;
+
+                                                       mix_in7: endpoint {
+                                                               remote-endpoint = <&xbar_mix_in7>;
+                                                       };
+                                               };
+
+                                               port@7 {
+                                                       reg = <0x7>;
+
+                                                       mix_in8: endpoint {
+                                                               remote-endpoint = <&xbar_mix_in8>;
+                                                       };
+                                               };
+
+                                               port@8 {
+                                                       reg = <0x8>;
+
+                                                       mix_in9: endpoint {
+                                                               remote-endpoint = <&xbar_mix_in9>;
+                                                       };
+                                               };
+
+                                               port@9 {
+                                                       reg = <0x9>;
+
+                                                       mix_in10: endpoint {
+                                                               remote-endpoint = <&xbar_mix_in10>;
+                                                       };
+                                               };
+
+                                               mix_out1_port: port@a {
+                                                       reg = <0xa>;
+
+                                                       mix_out1: endpoint {
+                                                               remote-endpoint = <&xbar_mix_out1>;
+                                                       };
+                                               };
+
+                                               mix_out2_port: port@b {
+                                                       reg = <0xb>;
+
+                                                       mix_out2: endpoint {
+                                                               remote-endpoint = <&xbar_mix_out2>;
+                                                       };
+                                               };
+
+                                               mix_out3_port: port@c {
+                                                       reg = <0xc>;
+
+                                                       mix_out3: endpoint {
+                                                               remote-endpoint = <&xbar_mix_out3>;
+                                                       };
+                                               };
+
+                                               mix_out4_port: port@d {
+                                                       reg = <0xd>;
+
+                                                       mix_out4: endpoint {
+                                                               remote-endpoint = <&xbar_mix_out4>;
+                                                       };
+                                               };
+
+                                               mix_out5_port: port@e {
+                                                       reg = <0xe>;
+
+                                                       mix_out5: endpoint {
+                                                               remote-endpoint = <&xbar_mix_out5>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_admaif: admaif@290f000 {
+                                       compatible = "nvidia,tegra234-admaif",
+                                                    "nvidia,tegra186-admaif";
+                                       reg = <0x0 0x0290f000 0x0 0x1000>;
+                                       dmas = <&adma 1>, <&adma 1>,
+                                              <&adma 2>, <&adma 2>,
+                                              <&adma 3>, <&adma 3>,
+                                              <&adma 4>, <&adma 4>,
+                                              <&adma 5>, <&adma 5>,
+                                              <&adma 6>, <&adma 6>,
+                                              <&adma 7>, <&adma 7>,
+                                              <&adma 8>, <&adma 8>,
+                                              <&adma 9>, <&adma 9>,
+                                              <&adma 10>, <&adma 10>,
+                                              <&adma 11>, <&adma 11>,
+                                              <&adma 12>, <&adma 12>,
+                                              <&adma 13>, <&adma 13>,
+                                              <&adma 14>, <&adma 14>,
+                                              <&adma 15>, <&adma 15>,
+                                              <&adma 16>, <&adma 16>,
+                                              <&adma 17>, <&adma 17>,
+                                              <&adma 18>, <&adma 18>,
+                                              <&adma 19>, <&adma 19>,
+                                              <&adma 20>, <&adma 20>;
+                                       dma-names = "rx1", "tx1",
+                                                   "rx2", "tx2",
+                                                   "rx3", "tx3",
+                                                   "rx4", "tx4",
+                                                   "rx5", "tx5",
+                                                   "rx6", "tx6",
+                                                   "rx7", "tx7",
+                                                   "rx8", "tx8",
+                                                   "rx9", "tx9",
+                                                   "rx10", "tx10",
+                                                   "rx11", "tx11",
+                                                   "rx12", "tx12",
+                                                   "rx13", "tx13",
+                                                   "rx14", "tx14",
+                                                   "rx15", "tx15",
+                                                   "rx16", "tx16",
+                                                   "rx17", "tx17",
+                                                   "rx18", "tx18",
+                                                   "rx19", "tx19",
+                                                   "rx20", "tx20";
+                                       interconnects = <&mc TEGRA234_MEMORY_CLIENT_APEDMAR &emc>,
+                                                       <&mc TEGRA234_MEMORY_CLIENT_APEDMAW &emc>;
+                                       interconnect-names = "dma-mem", "write";
+                                       iommus = <&smmu_niso0 TEGRA234_SID_APE>;
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               admaif0_port: port@0 {
+                                                       reg = <0x0>;
+
+                                                       admaif0: endpoint {
+                                                               remote-endpoint = <&xbar_admaif0>;
+                                                       };
+                                               };
+
+                                               admaif1_port: port@1 {
+                                                       reg = <0x1>;
+
+                                                       admaif1: endpoint {
+                                                               remote-endpoint = <&xbar_admaif1>;
+                                                       };
+                                               };
+
+                                               admaif2_port: port@2 {
+                                                       reg = <0x2>;
+
+                                                       admaif2: endpoint {
+                                                               remote-endpoint = <&xbar_admaif2>;
+                                                       };
+                                               };
+
+                                               admaif3_port: port@3 {
+                                                       reg = <0x3>;
+
+                                                       admaif3: endpoint {
+                                                               remote-endpoint = <&xbar_admaif3>;
+                                                       };
+                                               };
+
+                                               admaif4_port: port@4 {
+                                                       reg = <0x4>;
+
+                                                       admaif4: endpoint {
+                                                               remote-endpoint = <&xbar_admaif4>;
+                                                       };
+                                               };
+
+                                               admaif5_port: port@5 {
+                                                       reg = <0x5>;
+
+                                                       admaif5: endpoint {
+                                                               remote-endpoint = <&xbar_admaif5>;
+                                                       };
+                                               };
+
+                                               admaif6_port: port@6 {
+                                                       reg = <0x6>;
+
+                                                       admaif6: endpoint {
+                                                               remote-endpoint = <&xbar_admaif6>;
+                                                       };
+                                               };
+
+                                               admaif7_port: port@7 {
+                                                       reg = <0x7>;
+
+                                                       admaif7: endpoint {
+                                                               remote-endpoint = <&xbar_admaif7>;
+                                                       };
+                                               };
+
+                                               admaif8_port: port@8 {
+                                                       reg = <0x8>;
+
+                                                       admaif8: endpoint {
+                                                               remote-endpoint = <&xbar_admaif8>;
+                                                       };
+                                               };
+
+                                               admaif9_port: port@9 {
+                                                       reg = <0x9>;
+
+                                                       admaif9: endpoint {
+                                                               remote-endpoint = <&xbar_admaif9>;
+                                                       };
+                                               };
+
+                                               admaif10_port: port@a {
+                                                       reg = <0xa>;
+
+                                                       admaif10: endpoint {
+                                                               remote-endpoint = <&xbar_admaif10>;
+                                                       };
+                                               };
+
+                                               admaif11_port: port@b {
+                                                       reg = <0xb>;
+
+                                                       admaif11: endpoint {
+                                                               remote-endpoint = <&xbar_admaif11>;
+                                                       };
+                                               };
+
+                                               admaif12_port: port@c {
+                                                       reg = <0xc>;
+
+                                                       admaif12: endpoint {
+                                                               remote-endpoint = <&xbar_admaif12>;
+                                                       };
+                                               };
+
+                                               admaif13_port: port@d {
+                                                       reg = <0xd>;
+
+                                                       admaif13: endpoint {
+                                                               remote-endpoint = <&xbar_admaif13>;
+                                                       };
+                                               };
+
+                                               admaif14_port: port@e {
+                                                       reg = <0xe>;
+
+                                                       admaif14: endpoint {
+                                                               remote-endpoint = <&xbar_admaif14>;
+                                                       };
+                                               };
+
+                                               admaif15_port: port@f {
+                                                       reg = <0xf>;
+
+                                                       admaif15: endpoint {
+                                                               remote-endpoint = <&xbar_admaif15>;
+                                                       };
+                                               };
+
+                                               admaif16_port: port@10 {
+                                                       reg = <0x10>;
+
+                                                       admaif16: endpoint {
+                                                               remote-endpoint = <&xbar_admaif16>;
+                                                       };
+                                               };
+
+                                               admaif17_port: port@11 {
+                                                       reg = <0x11>;
+
+                                                       admaif17: endpoint {
+                                                               remote-endpoint = <&xbar_admaif17>;
+                                                       };
+                                               };
+
+                                               admaif18_port: port@12 {
+                                                       reg = <0x12>;
+
+                                                       admaif18: endpoint {
+                                                               remote-endpoint = <&xbar_admaif18>;
+                                                       };
+                                               };
+
+                                               admaif19_port: port@13 {
+                                                       reg = <0x13>;
+
+                                                       admaif19: endpoint {
+                                                               remote-endpoint = <&xbar_admaif19>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               tegra_asrc: asrc@2910000 {
+                                       compatible = "nvidia,tegra234-asrc",
+                                                    "nvidia,tegra186-asrc";
+                                       reg = <0x0 0x2910000 0x0 0x2000>;
+                                       sound-name-prefix = "ASRC1";
+
+                                       ports {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               port@0 {
+                                                       reg = <0x0>;
+
+                                                       asrc_in1_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_in1_ep>;
+                                                       };
+                                               };
+
+                                               port@1 {
+                                                       reg = <0x1>;
+
+                                                       asrc_in2_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_in2_ep>;
+                                                       };
+                                               };
+
+                                               port@2 {
+                                                       reg = <0x2>;
+
+                                                       asrc_in3_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_in3_ep>;
+                                                       };
+                                               };
+
+                                               port@3 {
+                                                       reg = <0x3>;
+
+                                                       asrc_in4_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_in4_ep>;
+                                                       };
+                                               };
+
+                                               port@4 {
+                                                       reg = <0x4>;
+
+                                                       asrc_in5_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_in5_ep>;
+                                                       };
+                                               };
+
+                                               port@5 {
+                                                       reg = <0x5>;
+
+                                                       asrc_in6_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_in6_ep>;
+                                                       };
+                                               };
+
+                                               port@6 {
+                                                       reg = <0x6>;
+
+                                                       asrc_in7_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_in7_ep>;
+                                                       };
+                                               };
+
+                                               asrc_out1_port: port@7 {
+                                                       reg = <0x7>;
+
+                                                       asrc_out1_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_out1_ep>;
+                                                       };
+                                               };
+
+                                               asrc_out2_port: port@8 {
+                                                       reg = <0x8>;
+
+                                                       asrc_out2_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_out2_ep>;
+                                                       };
+                                               };
+
+                                               asrc_out3_port: port@9 {
+                                                       reg = <0x9>;
+
+                                                       asrc_out3_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_out3_ep>;
+                                                       };
+                                               };
+
+                                               asrc_out4_port: port@a {
+                                                       reg = <0xa>;
+
+                                                       asrc_out4_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_out4_ep>;
+                                                       };
+                                               };
+
+                                               asrc_out5_port: port@b {
+                                                       reg = <0xb>;
+
+                                                       asrc_out5_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_out5_ep>;
+                                                       };
+                                               };
+
+                                               asrc_out6_port: port@c {
+                                                       reg = <0xc>;
+
+                                                       asrc_out6_ep: endpoint {
+                                                               remote-endpoint =
+                                                                       <&xbar_asrc_out6_ep>;
+                                                       };
+                                               };
+                                       };
+                               };
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0x0>;
+
+                                               xbar_admaif0: endpoint {
+                                                       remote-endpoint = <&admaif0>;
+                                               };
+                                       };
+
+                                       port@1 {
+                                               reg = <0x1>;
+
+                                               xbar_admaif1: endpoint {
+                                                       remote-endpoint = <&admaif1>;
+                                               };
+                                       };
+
+                                       port@2 {
+                                               reg = <0x2>;
+
+                                               xbar_admaif2: endpoint {
+                                                       remote-endpoint = <&admaif2>;
+                                               };
+                                       };
+
+                                       port@3 {
+                                               reg = <0x3>;
+
+                                               xbar_admaif3: endpoint {
+                                                       remote-endpoint = <&admaif3>;
+                                               };
+                                       };
+
+                                       port@4 {
+                                               reg = <0x4>;
+
+                                               xbar_admaif4: endpoint {
+                                                       remote-endpoint = <&admaif4>;
+                                               };
+                                       };
+
+                                       port@5 {
+                                               reg = <0x5>;
+
+                                               xbar_admaif5: endpoint {
+                                                       remote-endpoint = <&admaif5>;
+                                               };
+                                       };
+
+                                       port@6 {
+                                               reg = <0x6>;
+
+                                               xbar_admaif6: endpoint {
+                                                       remote-endpoint = <&admaif6>;
+                                               };
+                                       };
+
+                                       port@7 {
+                                               reg = <0x7>;
+
+                                               xbar_admaif7: endpoint {
+                                                       remote-endpoint = <&admaif7>;
+                                               };
+                                       };
+
+                                       port@8 {
+                                               reg = <0x8>;
+
+                                               xbar_admaif8: endpoint {
+                                                       remote-endpoint = <&admaif8>;
+                                               };
+                                       };
+
+                                       port@9 {
+                                               reg = <0x9>;
+
+                                               xbar_admaif9: endpoint {
+                                                       remote-endpoint = <&admaif9>;
+                                               };
+                                       };
+
+                                       port@a {
+                                               reg = <0xa>;
+
+                                               xbar_admaif10: endpoint {
+                                                       remote-endpoint = <&admaif10>;
+                                               };
+                                       };
+
+                                       port@b {
+                                               reg = <0xb>;
+
+                                               xbar_admaif11: endpoint {
+                                                       remote-endpoint = <&admaif11>;
+                                               };
+                                       };
+
+                                       port@c {
+                                               reg = <0xc>;
+
+                                               xbar_admaif12: endpoint {
+                                                       remote-endpoint = <&admaif12>;
+                                               };
+                                       };
+
+                                       port@d {
+                                               reg = <0xd>;
+
+                                               xbar_admaif13: endpoint {
+                                                       remote-endpoint = <&admaif13>;
+                                               };
+                                       };
+
+                                       port@e {
+                                               reg = <0xe>;
+
+                                               xbar_admaif14: endpoint {
+                                                       remote-endpoint = <&admaif14>;
+                                               };
+                                       };
+
+                                       port@f {
+                                               reg = <0xf>;
+
+                                               xbar_admaif15: endpoint {
+                                                       remote-endpoint = <&admaif15>;
+                                               };
+                                       };
+
+                                       port@10 {
+                                               reg = <0x10>;
+
+                                               xbar_admaif16: endpoint {
+                                                       remote-endpoint = <&admaif16>;
+                                               };
+                                       };
+
+                                       port@11 {
+                                               reg = <0x11>;
+
+                                               xbar_admaif17: endpoint {
+                                                       remote-endpoint = <&admaif17>;
+                                               };
+                                       };
+
+                                       port@12 {
+                                               reg = <0x12>;
+
+                                               xbar_admaif18: endpoint {
+                                                       remote-endpoint = <&admaif18>;
+                                               };
+                                       };
+
+                                       port@13 {
+                                               reg = <0x13>;
+
+                                               xbar_admaif19: endpoint {
+                                                       remote-endpoint = <&admaif19>;
+                                               };
+                                       };
+
+                                       xbar_i2s1_port: port@14 {
+                                               reg = <0x14>;
+
+                                               xbar_i2s1: endpoint {
+                                                       remote-endpoint = <&i2s1_cif>;
+                                               };
+                                       };
+
+                                       xbar_i2s2_port: port@15 {
+                                               reg = <0x15>;
+
+                                               xbar_i2s2: endpoint {
+                                                       remote-endpoint = <&i2s2_cif>;
+                                               };
+                                       };
+
+                                       xbar_i2s3_port: port@16 {
+                                               reg = <0x16>;
+
+                                               xbar_i2s3: endpoint {
+                                                       remote-endpoint = <&i2s3_cif>;
+                                               };
+                                       };
+
+                                       xbar_i2s4_port: port@17 {
+                                               reg = <0x17>;
+
+                                               xbar_i2s4: endpoint {
+                                                       remote-endpoint = <&i2s4_cif>;
+                                               };
+                                       };
+
+                                       xbar_i2s5_port: port@18 {
+                                               reg = <0x18>;
+
+                                               xbar_i2s5: endpoint {
+                                                       remote-endpoint = <&i2s5_cif>;
+                                               };
+                                       };
+
+                                       xbar_i2s6_port: port@19 {
+                                               reg = <0x19>;
+
+                                               xbar_i2s6: endpoint {
+                                                       remote-endpoint = <&i2s6_cif>;
+                                               };
+                                       };
+
+                                       xbar_dmic1_port: port@1a {
+                                               reg = <0x1a>;
+
+                                               xbar_dmic1: endpoint {
+                                                       remote-endpoint = <&dmic1_cif>;
+                                               };
+                                       };
+
+                                       xbar_dmic2_port: port@1b {
+                                               reg = <0x1b>;
+
+                                               xbar_dmic2: endpoint {
+                                                       remote-endpoint = <&dmic2_cif>;
+                                               };
+                                       };
+
+                                       xbar_dmic3_port: port@1c {
+                                               reg = <0x1c>;
+
+                                               xbar_dmic3: endpoint {
+                                                       remote-endpoint = <&dmic3_cif>;
+                                               };
+                                       };
+
+                                       xbar_dmic4_port: port@1d {
+                                               reg = <0x1d>;
+
+                                               xbar_dmic4: endpoint {
+                                                       remote-endpoint = <&dmic4_cif>;
+                                               };
+                                       };
+
+                                       xbar_dspk1_port: port@1e {
+                                               reg = <0x1e>;
+
+                                               xbar_dspk1: endpoint {
+                                                       remote-endpoint = <&dspk1_cif>;
+                                               };
+                                       };
+
+                                       xbar_dspk2_port: port@1f {
+                                               reg = <0x1f>;
+
+                                               xbar_dspk2: endpoint {
+                                                       remote-endpoint = <&dspk2_cif>;
+                                               };
+                                       };
+
+                                       xbar_sfc1_in_port: port@20 {
+                                               reg = <0x20>;
+
+                                               xbar_sfc1_in: endpoint {
+                                                       remote-endpoint = <&sfc1_cif_in>;
+                                               };
+                                       };
+
+                                       port@21 {
+                                               reg = <0x21>;
+
+                                               xbar_sfc1_out: endpoint {
+                                                       remote-endpoint = <&sfc1_cif_out>;
+                                               };
+                                       };
+
+                                       xbar_sfc2_in_port: port@22 {
+                                               reg = <0x22>;
+
+                                               xbar_sfc2_in: endpoint {
+                                                       remote-endpoint = <&sfc2_cif_in>;
+                                               };
+                                       };
+
+                                       port@23 {
+                                               reg = <0x23>;
+
+                                               xbar_sfc2_out: endpoint {
+                                                       remote-endpoint = <&sfc2_cif_out>;
+                                               };
+                                       };
+
+                                       xbar_sfc3_in_port: port@24 {
+                                               reg = <0x24>;
+
+                                               xbar_sfc3_in: endpoint {
+                                                       remote-endpoint = <&sfc3_cif_in>;
+                                               };
+                                       };
+
+                                       port@25 {
+                                               reg = <0x25>;
+
+                                               xbar_sfc3_out: endpoint {
+                                                       remote-endpoint = <&sfc3_cif_out>;
+                                               };
+                                       };
+
+                                       xbar_sfc4_in_port: port@26 {
+                                               reg = <0x26>;
+
+                                               xbar_sfc4_in: endpoint {
+                                                       remote-endpoint = <&sfc4_cif_in>;
+                                               };
+                                       };
+
+                                       port@27 {
+                                               reg = <0x27>;
+
+                                               xbar_sfc4_out: endpoint {
+                                                       remote-endpoint = <&sfc4_cif_out>;
+                                               };
+                                       };
+
+                                       xbar_mvc1_in_port: port@28 {
+                                               reg = <0x28>;
+
+                                               xbar_mvc1_in: endpoint {
+                                                       remote-endpoint = <&mvc1_cif_in>;
+                                               };
+                                       };
+
+                                       port@29 {
+                                               reg = <0x29>;
+
+                                               xbar_mvc1_out: endpoint {
+                                                       remote-endpoint = <&mvc1_cif_out>;
+                                               };
+                                       };
+
+                                       xbar_mvc2_in_port: port@2a {
+                                               reg = <0x2a>;
+
+                                               xbar_mvc2_in: endpoint {
+                                                       remote-endpoint = <&mvc2_cif_in>;
+                                               };
+                                       };
+
+                                       port@2b {
+                                               reg = <0x2b>;
+
+                                               xbar_mvc2_out: endpoint {
+                                                       remote-endpoint = <&mvc2_cif_out>;
+                                               };
+                                       };
+
+                                       xbar_amx1_in1_port: port@2c {
+                                               reg = <0x2c>;
+
+                                               xbar_amx1_in1: endpoint {
+                                                       remote-endpoint = <&amx1_in1>;
+                                               };
+                                       };
+
+                                       xbar_amx1_in2_port: port@2d {
+                                               reg = <0x2d>;
+
+                                               xbar_amx1_in2: endpoint {
+                                                       remote-endpoint = <&amx1_in2>;
+                                               };
+                                       };
+
+                                       xbar_amx1_in3_port: port@2e {
+                                               reg = <0x2e>;
+
+                                               xbar_amx1_in3: endpoint {
+                                                       remote-endpoint = <&amx1_in3>;
+                                               };
+                                       };
+
+                                       xbar_amx1_in4_port: port@2f {
+                                               reg = <0x2f>;
+
+                                               xbar_amx1_in4: endpoint {
+                                                       remote-endpoint = <&amx1_in4>;
+                                               };
+                                       };
+
+                                       port@30 {
+                                               reg = <0x30>;
+
+                                               xbar_amx1_out: endpoint {
+                                                       remote-endpoint = <&amx1_out>;
+                                               };
+                                       };
+
+                                       xbar_amx2_in1_port: port@31 {
+                                               reg = <0x31>;
+
+                                               xbar_amx2_in1: endpoint {
+                                                       remote-endpoint = <&amx2_in1>;
+                                               };
+                                       };
+
+                                       xbar_amx2_in2_port: port@32 {
+                                               reg = <0x32>;
+
+                                               xbar_amx2_in2: endpoint {
+                                                       remote-endpoint = <&amx2_in2>;
+                                               };
+                                       };
+
+                                       xbar_amx2_in3_port: port@33 {
+                                               reg = <0x33>;
+
+                                               xbar_amx2_in3: endpoint {
+                                                       remote-endpoint = <&amx2_in3>;
+                                               };
+                                       };
+
+                                       xbar_amx2_in4_port: port@34 {
+                                               reg = <0x34>;
+
+                                               xbar_amx2_in4: endpoint {
+                                                       remote-endpoint = <&amx2_in4>;
+                                               };
+                                       };
+
+                                       port@35 {
+                                               reg = <0x35>;
+
+                                               xbar_amx2_out: endpoint {
+                                                       remote-endpoint = <&amx2_out>;
+                                               };
+                                       };
+
+                                       xbar_amx3_in1_port: port@36 {
+                                               reg = <0x36>;
+
+                                               xbar_amx3_in1: endpoint {
+                                                       remote-endpoint = <&amx3_in1>;
+                                               };
+                                       };
+
+                                       xbar_amx3_in2_port: port@37 {
+                                               reg = <0x37>;
+
+                                               xbar_amx3_in2: endpoint {
+                                                       remote-endpoint = <&amx3_in2>;
+                                               };
+                                       };
+
+                                       xbar_amx3_in3_port: port@38 {
+                                               reg = <0x38>;
+
+                                               xbar_amx3_in3: endpoint {
+                                                       remote-endpoint = <&amx3_in3>;
+                                               };
+                                       };
+
+                                       xbar_amx3_in4_port: port@39 {
+                                               reg = <0x39>;
+
+                                               xbar_amx3_in4: endpoint {
+                                                       remote-endpoint = <&amx3_in4>;
+                                               };
+                                       };
+
+                                       port@3a {
+                                               reg = <0x3a>;
+
+                                               xbar_amx3_out: endpoint {
+                                                       remote-endpoint = <&amx3_out>;
+                                               };
+                                       };
+
+                                       xbar_amx4_in1_port: port@3b {
+                                               reg = <0x3b>;
+
+                                               xbar_amx4_in1: endpoint {
+                                                       remote-endpoint = <&amx4_in1>;
+                                               };
+                                       };
+
+                                       xbar_amx4_in2_port: port@3c {
+                                               reg = <0x3c>;
+
+                                               xbar_amx4_in2: endpoint {
+                                                       remote-endpoint = <&amx4_in2>;
+                                               };
+                                       };
+
+                                       xbar_amx4_in3_port: port@3d {
+                                               reg = <0x3d>;
+
+                                               xbar_amx4_in3: endpoint {
+                                                       remote-endpoint = <&amx4_in3>;
+                                               };
+                                       };
+
+                                       xbar_amx4_in4_port: port@3e {
+                                               reg = <0x3e>;
+
+                                               xbar_amx4_in4: endpoint {
+                                                       remote-endpoint = <&amx4_in4>;
+                                               };
+                                       };
+
+                                       port@3f {
+                                               reg = <0x3f>;
+
+                                               xbar_amx4_out: endpoint {
+                                                       remote-endpoint = <&amx4_out>;
+                                               };
+                                       };
+
+                                       xbar_adx1_in_port: port@40 {
+                                               reg = <0x40>;
+
+                                               xbar_adx1_in: endpoint {
+                                                       remote-endpoint = <&adx1_in>;
+                                               };
+                                       };
+
+                                       port@41 {
+                                               reg = <0x41>;
+
+                                               xbar_adx1_out1: endpoint {
+                                                       remote-endpoint = <&adx1_out1>;
+                                               };
+                                       };
+
+                                       port@42 {
+                                               reg = <0x42>;
+
+                                               xbar_adx1_out2: endpoint {
+                                                       remote-endpoint = <&adx1_out2>;
+                                               };
+                                       };
+
+                                       port@43 {
+                                               reg = <0x43>;
+
+                                               xbar_adx1_out3: endpoint {
+                                                       remote-endpoint = <&adx1_out3>;
+                                               };
+                                       };
+
+                                       port@44 {
+                                               reg = <0x44>;
+
+                                               xbar_adx1_out4: endpoint {
+                                                       remote-endpoint = <&adx1_out4>;
+                                               };
+                                       };
+
+                                       xbar_adx2_in_port: port@45 {
+                                               reg = <0x45>;
+
+                                               xbar_adx2_in: endpoint {
+                                                       remote-endpoint = <&adx2_in>;
+                                               };
+                                       };
+
+                                       port@46 {
+                                               reg = <0x46>;
+
+                                               xbar_adx2_out1: endpoint {
+                                                       remote-endpoint = <&adx2_out1>;
+                                               };
+                                       };
+
+                                       port@47 {
+                                               reg = <0x47>;
+
+                                               xbar_adx2_out2: endpoint {
+                                                       remote-endpoint = <&adx2_out2>;
+                                               };
+                                       };
+
+                                       port@48 {
+                                               reg = <0x48>;
+
+                                               xbar_adx2_out3: endpoint {
+                                                       remote-endpoint = <&adx2_out3>;
+                                               };
+                                       };
+
+                                       port@49 {
+                                               reg = <0x49>;
+
+                                               xbar_adx2_out4: endpoint {
+                                                       remote-endpoint = <&adx2_out4>;
+                                               };
+                                       };
+
+                                       xbar_adx3_in_port: port@4a {
+                                               reg = <0x4a>;
+
+                                               xbar_adx3_in: endpoint {
+                                                       remote-endpoint = <&adx3_in>;
+                                               };
+                                       };
+
+                                       port@4b {
+                                               reg = <0x4b>;
+
+                                               xbar_adx3_out1: endpoint {
+                                                       remote-endpoint = <&adx3_out1>;
+                                               };
+                                       };
+
+                                       port@4c {
+                                               reg = <0x4c>;
+
+                                               xbar_adx3_out2: endpoint {
+                                                       remote-endpoint = <&adx3_out2>;
+                                               };
+                                       };
+
+                                       port@4d {
+                                               reg = <0x4d>;
+
+                                               xbar_adx3_out3: endpoint {
+                                                       remote-endpoint = <&adx3_out3>;
+                                               };
+                                       };
+
+                                       port@4e {
+                                               reg = <0x4e>;
+
+                                               xbar_adx3_out4: endpoint {
+                                                       remote-endpoint = <&adx3_out4>;
+                                               };
+                                       };
+
+                                       xbar_adx4_in_port: port@4f {
+                                               reg = <0x4f>;
+
+                                               xbar_adx4_in: endpoint {
+                                                       remote-endpoint = <&adx4_in>;
+                                               };
+                                       };
+
+                                       port@50 {
+                                               reg = <0x50>;
+
+                                               xbar_adx4_out1: endpoint {
+                                                       remote-endpoint = <&adx4_out1>;
+                                               };
+                                       };
+
+                                       port@51 {
+                                               reg = <0x51>;
+
+                                               xbar_adx4_out2: endpoint {
+                                                       remote-endpoint = <&adx4_out2>;
+                                               };
+                                       };
+
+                                       port@52 {
+                                               reg = <0x52>;
+
+                                               xbar_adx4_out3: endpoint {
+                                                       remote-endpoint = <&adx4_out3>;
+                                               };
+                                       };
+
+                                       port@53 {
+                                               reg = <0x53>;
+
+                                               xbar_adx4_out4: endpoint {
+                                                       remote-endpoint = <&adx4_out4>;
+                                               };
+                                       };
+
+                                       xbar_mix_in1_port: port@54 {
+                                               reg = <0x54>;
+
+                                               xbar_mix_in1: endpoint {
+                                                       remote-endpoint = <&mix_in1>;
+                                               };
+                                       };
+
+                                       xbar_mix_in2_port: port@55 {
+                                               reg = <0x55>;
+
+                                               xbar_mix_in2: endpoint {
+                                                       remote-endpoint = <&mix_in2>;
+                                               };
+                                       };
+
+                                       xbar_mix_in3_port: port@56 {
+                                               reg = <0x56>;
+
+                                               xbar_mix_in3: endpoint {
+                                                       remote-endpoint = <&mix_in3>;
+                                               };
+                                       };
+
+                                       xbar_mix_in4_port: port@57 {
+                                               reg = <0x57>;
+
+                                               xbar_mix_in4: endpoint {
+                                                       remote-endpoint = <&mix_in4>;
+                                               };
+                                       };
+
+                                       xbar_mix_in5_port: port@58 {
+                                               reg = <0x58>;
+
+                                               xbar_mix_in5: endpoint {
+                                                       remote-endpoint = <&mix_in5>;
+                                               };
+                                       };
+
+                                       xbar_mix_in6_port: port@59 {
+                                               reg = <0x59>;
+
+                                               xbar_mix_in6: endpoint {
+                                                       remote-endpoint = <&mix_in6>;
+                                               };
+                                       };
+
+                                       xbar_mix_in7_port: port@5a {
+                                               reg = <0x5a>;
+
+                                               xbar_mix_in7: endpoint {
+                                                       remote-endpoint = <&mix_in7>;
+                                               };
+                                       };
+
+                                       xbar_mix_in8_port: port@5b {
+                                               reg = <0x5b>;
+
+                                               xbar_mix_in8: endpoint {
+                                                       remote-endpoint = <&mix_in8>;
+                                               };
+                                       };
+
+                                       xbar_mix_in9_port: port@5c {
+                                               reg = <0x5c>;
+
+                                               xbar_mix_in9: endpoint {
+                                                       remote-endpoint = <&mix_in9>;
+                                               };
+                                       };
+
+                                       xbar_mix_in10_port: port@5d {
+                                               reg = <0x5d>;
+
+                                               xbar_mix_in10: endpoint {
+                                                       remote-endpoint = <&mix_in10>;
+                                               };
+                                       };
+
+                                       port@5e {
+                                               reg = <0x5e>;
+
+                                               xbar_mix_out1: endpoint {
+                                                       remote-endpoint = <&mix_out1>;
+                                               };
+                                       };
+
+                                       port@5f {
+                                               reg = <0x5f>;
+
+                                               xbar_mix_out2: endpoint {
+                                                       remote-endpoint = <&mix_out2>;
+                                               };
+                                       };
+
+                                       port@60 {
+                                               reg = <0x60>;
+
+                                               xbar_mix_out3: endpoint {
+                                                       remote-endpoint = <&mix_out3>;
+                                               };
+                                       };
+
+                                       port@61 {
+                                               reg = <0x61>;
+
+                                               xbar_mix_out4: endpoint {
+                                                       remote-endpoint = <&mix_out4>;
+                                               };
+                                       };
+
+                                       port@62 {
+                                               reg = <0x62>;
+
+                                               xbar_mix_out5: endpoint {
+                                                       remote-endpoint = <&mix_out5>;
+                                               };
+                                       };
+
+                                       xbar_asrc_in1_port: port@63 {
+                                               reg = <0x63>;
+
+                                               xbar_asrc_in1_ep: endpoint {
+                                                       remote-endpoint = <&asrc_in1_ep>;
+                                               };
+                                       };
+
+                                       port@64 {
+                                               reg = <0x64>;
+
+                                               xbar_asrc_out1_ep: endpoint {
+                                                       remote-endpoint = <&asrc_out1_ep>;
+                                               };
+                                       };
+
+                                       xbar_asrc_in2_port: port@65 {
+                                               reg = <0x65>;
+
+                                               xbar_asrc_in2_ep: endpoint {
+                                                       remote-endpoint = <&asrc_in2_ep>;
+                                               };
+                                       };
 
-                               tegra_amx3: amx@2903200 {
-                                       compatible = "nvidia,tegra234-amx",
-                                                    "nvidia,tegra194-amx";
-                                       reg = <0x0 0x2903200 0x0 0x100>;
-                                       sound-name-prefix = "AMX3";
-                                       status = "disabled";
-                               };
+                                       port@66 {
+                                               reg = <0x66>;
 
-                               tegra_amx4: amx@2903300 {
-                                       compatible = "nvidia,tegra234-amx",
-                                                    "nvidia,tegra194-amx";
-                                       reg = <0x0 0x2903300 0x0 0x100>;
-                                       sound-name-prefix = "AMX4";
-                                       status = "disabled";
-                               };
+                                               xbar_asrc_out2_ep: endpoint {
+                                                       remote-endpoint = <&asrc_out2_ep>;
+                                               };
+                                       };
 
-                               tegra_adx1: adx@2903800 {
-                                       compatible = "nvidia,tegra234-adx",
-                                                    "nvidia,tegra210-adx";
-                                       reg = <0x0 0x2903800 0x0 0x100>;
-                                       sound-name-prefix = "ADX1";
-                                       status = "disabled";
-                               };
+                                       xbar_asrc_in3_port: port@67 {
+                                               reg = <0x67>;
 
-                               tegra_adx2: adx@2903900 {
-                                       compatible = "nvidia,tegra234-adx",
-                                                    "nvidia,tegra210-adx";
-                                       reg = <0x0 0x2903900 0x0 0x100>;
-                                       sound-name-prefix = "ADX2";
-                                       status = "disabled";
-                               };
+                                               xbar_asrc_in3_ep: endpoint {
+                                                       remote-endpoint = <&asrc_in3_ep>;
+                                               };
+                                       };
 
-                               tegra_adx3: adx@2903a00 {
-                                       compatible = "nvidia,tegra234-adx",
-                                                    "nvidia,tegra210-adx";
-                                       reg = <0x0 0x2903a00 0x0 0x100>;
-                                       sound-name-prefix = "ADX3";
-                                       status = "disabled";
-                               };
+                                       port@68 {
+                                               reg = <0x68>;
 
-                               tegra_adx4: adx@2903b00 {
-                                       compatible = "nvidia,tegra234-adx",
-                                                    "nvidia,tegra210-adx";
-                                       reg = <0x0 0x2903b00 0x0 0x100>;
-                                       sound-name-prefix = "ADX4";
-                                       status = "disabled";
-                               };
+                                               xbar_asrc_out3_ep: endpoint {
+                                                       remote-endpoint = <&asrc_out3_ep>;
+                                               };
+                                       };
 
+                                       xbar_asrc_in4_port: port@69 {
+                                               reg = <0x69>;
 
-                               tegra_dmic1: dmic@2904000 {
-                                       compatible = "nvidia,tegra234-dmic",
-                                                    "nvidia,tegra210-dmic";
-                                       reg = <0x0 0x2904000 0x0 0x100>;
-                                       clocks = <&bpmp TEGRA234_CLK_DMIC1>;
-                                       clock-names = "dmic";
-                                       assigned-clocks = <&bpmp TEGRA234_CLK_DMIC1>;
-                                       assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA_OUT0>;
-                                       assigned-clock-rates = <3072000>;
-                                       sound-name-prefix = "DMIC1";
-                                       status = "disabled";
-                               };
+                                               xbar_asrc_in4_ep: endpoint {
+                                                       remote-endpoint = <&asrc_in4_ep>;
+                                               };
+                                       };
 
-                               tegra_dmic2: dmic@2904100 {
-                                       compatible = "nvidia,tegra234-dmic",
-                                                    "nvidia,tegra210-dmic";
-                                       reg = <0x0 0x2904100 0x0 0x100>;
-                                       clocks = <&bpmp TEGRA234_CLK_DMIC2>;
-                                       clock-names = "dmic";
-                                       assigned-clocks = <&bpmp TEGRA234_CLK_DMIC2>;
-                                       assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA_OUT0>;
-                                       assigned-clock-rates = <3072000>;
-                                       sound-name-prefix = "DMIC2";
-                                       status = "disabled";
-                               };
+                                       port@6a {
+                                               reg = <0x6a>;
 
-                               tegra_dmic3: dmic@2904200 {
-                                       compatible = "nvidia,tegra234-dmic",
-                                                    "nvidia,tegra210-dmic";
-                                       reg = <0x0 0x2904200 0x0 0x100>;
-                                       clocks = <&bpmp TEGRA234_CLK_DMIC3>;
-                                       clock-names = "dmic";
-                                       assigned-clocks = <&bpmp TEGRA234_CLK_DMIC3>;
-                                       assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA_OUT0>;
-                                       assigned-clock-rates = <3072000>;
-                                       sound-name-prefix = "DMIC3";
-                                       status = "disabled";
-                               };
+                                               xbar_asrc_out4_ep: endpoint {
+                                                       remote-endpoint = <&asrc_out4_ep>;
+                                               };
+                                       };
 
-                               tegra_dmic4: dmic@2904300 {
-                                       compatible = "nvidia,tegra234-dmic",
-                                                    "nvidia,tegra210-dmic";
-                                       reg = <0x0 0x2904300 0x0 0x100>;
-                                       clocks = <&bpmp TEGRA234_CLK_DMIC4>;
-                                       clock-names = "dmic";
-                                       assigned-clocks = <&bpmp TEGRA234_CLK_DMIC4>;
-                                       assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA_OUT0>;
-                                       assigned-clock-rates = <3072000>;
-                                       sound-name-prefix = "DMIC4";
-                                       status = "disabled";
-                               };
+                                       xbar_asrc_in5_port: port@6b {
+                                               reg = <0x6b>;
 
-                               tegra_dspk1: dspk@2905000 {
-                                       compatible = "nvidia,tegra234-dspk",
-                                                    "nvidia,tegra186-dspk";
-                                       reg = <0x0 0x2905000 0x0 0x100>;
-                                       clocks = <&bpmp TEGRA234_CLK_DSPK1>;
-                                       clock-names = "dspk";
-                                       assigned-clocks = <&bpmp TEGRA234_CLK_DSPK1>;
-                                       assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA_OUT0>;
-                                       assigned-clock-rates = <12288000>;
-                                       sound-name-prefix = "DSPK1";
-                                       status = "disabled";
-                               };
+                                               xbar_asrc_in5_ep: endpoint {
+                                                       remote-endpoint = <&asrc_in5_ep>;
+                                               };
+                                       };
 
-                               tegra_dspk2: dspk@2905100 {
-                                       compatible = "nvidia,tegra234-dspk",
-                                                    "nvidia,tegra186-dspk";
-                                       reg = <0x0 0x2905100 0x0 0x100>;
-                                       clocks = <&bpmp TEGRA234_CLK_DSPK2>;
-                                       clock-names = "dspk";
-                                       assigned-clocks = <&bpmp TEGRA234_CLK_DSPK2>;
-                                       assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA_OUT0>;
-                                       assigned-clock-rates = <12288000>;
-                                       sound-name-prefix = "DSPK2";
-                                       status = "disabled";
-                               };
+                                       port@6c {
+                                               reg = <0x6c>;
 
-                               tegra_ope1: processing-engine@2908000 {
-                                       compatible = "nvidia,tegra234-ope",
-                                                    "nvidia,tegra210-ope";
-                                       reg = <0x0 0x2908000 0x0 0x100>;
-                                       sound-name-prefix = "OPE1";
-                                       status = "disabled";
+                                               xbar_asrc_out5_ep: endpoint {
+                                                       remote-endpoint = <&asrc_out5_ep>;
+                                               };
+                                       };
 
-                                       #address-cells = <2>;
-                                       #size-cells = <2>;
-                                       ranges;
+                                       xbar_asrc_in6_port: port@6d {
+                                               reg = <0x6d>;
 
-                                       equalizer@2908100 {
-                                               compatible = "nvidia,tegra234-peq",
-                                                            "nvidia,tegra210-peq";
-                                               reg = <0x0 0x2908100 0x0 0x100>;
+                                               xbar_asrc_in6_ep: endpoint {
+                                                       remote-endpoint = <&asrc_in6_ep>;
+                                               };
                                        };
 
-                                       dynamic-range-compressor@2908200 {
-                                               compatible = "nvidia,tegra234-mbdrc",
-                                                            "nvidia,tegra210-mbdrc";
-                                               reg = <0x0 0x2908200 0x0 0x200>;
+                                       port@6e {
+                                               reg = <0x6e>;
+
+                                               xbar_asrc_out6_ep: endpoint {
+                                                       remote-endpoint = <&asrc_out6_ep>;
+                                               };
                                        };
-                               };
 
-                               tegra_mvc1: mvc@290a000 {
-                                       compatible = "nvidia,tegra234-mvc",
-                                                    "nvidia,tegra210-mvc";
-                                       reg = <0x0 0x290a000 0x0 0x200>;
-                                       sound-name-prefix = "MVC1";
-                                       status = "disabled";
-                               };
+                                       xbar_asrc_in7_port: port@6f {
+                                               reg = <0x6f>;
 
-                               tegra_mvc2: mvc@290a200 {
-                                       compatible = "nvidia,tegra234-mvc",
-                                                    "nvidia,tegra210-mvc";
-                                       reg = <0x0 0x290a200 0x0 0x200>;
-                                       sound-name-prefix = "MVC2";
-                                       status = "disabled";
-                               };
+                                               xbar_asrc_in7_ep: endpoint {
+                                                       remote-endpoint = <&asrc_in7_ep>;
+                                               };
+                                       };
 
-                               tegra_amixer: amixer@290bb00 {
-                                       compatible = "nvidia,tegra234-amixer",
-                                                    "nvidia,tegra210-amixer";
-                                       reg = <0x0 0x290bb00 0x0 0x800>;
-                                       sound-name-prefix = "MIXER1";
-                                       status = "disabled";
-                               };
+                                       xbar_ope1_in_port: port@70 {
+                                               reg = <0x70>;
 
-                               tegra_admaif: admaif@290f000 {
-                                       compatible = "nvidia,tegra234-admaif",
-                                                    "nvidia,tegra186-admaif";
-                                       reg = <0x0 0x0290f000 0x0 0x1000>;
-                                       dmas = <&adma 1>, <&adma 1>,
-                                              <&adma 2>, <&adma 2>,
-                                              <&adma 3>, <&adma 3>,
-                                              <&adma 4>, <&adma 4>,
-                                              <&adma 5>, <&adma 5>,
-                                              <&adma 6>, <&adma 6>,
-                                              <&adma 7>, <&adma 7>,
-                                              <&adma 8>, <&adma 8>,
-                                              <&adma 9>, <&adma 9>,
-                                              <&adma 10>, <&adma 10>,
-                                              <&adma 11>, <&adma 11>,
-                                              <&adma 12>, <&adma 12>,
-                                              <&adma 13>, <&adma 13>,
-                                              <&adma 14>, <&adma 14>,
-                                              <&adma 15>, <&adma 15>,
-                                              <&adma 16>, <&adma 16>,
-                                              <&adma 17>, <&adma 17>,
-                                              <&adma 18>, <&adma 18>,
-                                              <&adma 19>, <&adma 19>,
-                                              <&adma 20>, <&adma 20>;
-                                       dma-names = "rx1", "tx1",
-                                                   "rx2", "tx2",
-                                                   "rx3", "tx3",
-                                                   "rx4", "tx4",
-                                                   "rx5", "tx5",
-                                                   "rx6", "tx6",
-                                                   "rx7", "tx7",
-                                                   "rx8", "tx8",
-                                                   "rx9", "tx9",
-                                                   "rx10", "tx10",
-                                                   "rx11", "tx11",
-                                                   "rx12", "tx12",
-                                                   "rx13", "tx13",
-                                                   "rx14", "tx14",
-                                                   "rx15", "tx15",
-                                                   "rx16", "tx16",
-                                                   "rx17", "tx17",
-                                                   "rx18", "tx18",
-                                                   "rx19", "tx19",
-                                                   "rx20", "tx20";
-                                       interconnects = <&mc TEGRA234_MEMORY_CLIENT_APEDMAR &emc>,
-                                                       <&mc TEGRA234_MEMORY_CLIENT_APEDMAW &emc>;
-                                       interconnect-names = "dma-mem", "write";
-                                       iommus = <&smmu_niso0 TEGRA234_SID_APE>;
-                                       status = "disabled";
-                               };
+                                               xbar_ope1_in_ep: endpoint {
+                                                       remote-endpoint = <&ope1_cif_in_ep>;
+                                               };
+                                       };
 
-                               tegra_asrc: asrc@2910000 {
-                                       compatible = "nvidia,tegra234-asrc",
-                                                    "nvidia,tegra186-asrc";
-                                       reg = <0x0 0x2910000 0x0 0x2000>;
-                                       sound-name-prefix = "ASRC1";
-                                       status = "disabled";
+                                       port@71 {
+                                               reg = <0x71>;
+
+                                               xbar_ope1_out_ep: endpoint {
+                                                       remote-endpoint = <&ope1_cif_out_ep>;
+                                               };
+                                       };
                                };
                        };
 
                                        <&mc TEGRA234_MEMORY_CLIENT_MGBEAWR &emc>;
                        interconnect-names = "dma-mem", "write";
                        iommus = <&smmu_niso0 TEGRA234_SID_MGBE>;
-                       power-domains = <&bpmp TEGRA234_POWER_DOMAIN_MGBEA>;
+                       power-domains = <&bpmp TEGRA234_POWER_DOMAIN_MGBEB>;
                        status = "disabled";
+
+                       snps,axi-config = <&mgbe0_axi_setup>;
+
+                       mgbe0_axi_setup: stmmac-axi-config {
+                               snps,blen = <256 128 64 32>;
+                               snps,rd_osr_lmt = <63>;
+                               snps,wr_osr_lmt = <63>;
+                       };
                };
 
                ethernet@6900000 {
                                        <&mc TEGRA234_MEMORY_CLIENT_MGBEBWR &emc>;
                        interconnect-names = "dma-mem", "write";
                        iommus = <&smmu_niso0 TEGRA234_SID_MGBE_VF1>;
-                       power-domains = <&bpmp TEGRA234_POWER_DOMAIN_MGBEB>;
+                       power-domains = <&bpmp TEGRA234_POWER_DOMAIN_MGBEC>;
                        status = "disabled";
+
+                       snps,axi-config = <&mgbe1_axi_setup>;
+
+                       mgbe1_axi_setup: stmmac-axi-config {
+                               snps,blen = <256 128 64 32>;
+                               snps,rd_osr_lmt = <63>;
+                               snps,wr_osr_lmt = <63>;
+                       };
                };
 
                ethernet@6a00000 {
                                        <&mc TEGRA234_MEMORY_CLIENT_MGBECWR &emc>;
                        interconnect-names = "dma-mem", "write";
                        iommus = <&smmu_niso0 TEGRA234_SID_MGBE_VF2>;
-                       power-domains = <&bpmp TEGRA234_POWER_DOMAIN_MGBEC>;
+                       power-domains = <&bpmp TEGRA234_POWER_DOMAIN_MGBED>;
                        status = "disabled";
+
+                       snps,axi-config = <&mgbe2_axi_setup>;
+
+                       mgbe2_axi_setup: stmmac-axi-config {
+                               snps,blen = <256 128 64 32>;
+                               snps,rd_osr_lmt = <63>;
+                               snps,wr_osr_lmt = <63>;
+                       };
                };
 
                ethernet@6b00000 {
index 39889d5f8e1238cf7b86601106e0bc3ae4c95295..7d40ec5e7d214c5c72df95e8b83f16b57d4c53ce 100644 (file)
@@ -23,6 +23,7 @@ dtb-$(CONFIG_ARCH_QCOM)       += ipq9574-rdp433.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += ipq9574-rdp449.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += ipq9574-rdp453.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += ipq9574-rdp454.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += msm8216-samsung-fortuna3g.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-acer-a1-724.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-alcatel-idol347.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-asus-z00l.dtb
@@ -35,11 +36,14 @@ dtb-$(CONFIG_ARCH_QCOM)     += msm8916-samsung-a3u-eur.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-samsung-a5u-eur.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-samsung-e5.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-samsung-e7.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += msm8916-samsung-gprimeltecan.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-samsung-grandmax.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += msm8916-samsung-grandprimelte.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-samsung-gt510.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-samsung-gt58.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-samsung-j5.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-samsung-j5x.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += msm8916-samsung-rossa.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-samsung-serranove.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-thwc-uf896.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8916-thwc-ufi001c.dtb
@@ -210,6 +214,7 @@ dtb-$(CONFIG_ARCH_QCOM)     += sm6125-sony-xperia-seine-pdx201.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sm6125-xiaomi-laurel-sprout.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sm6350-sony-xperia-lena-pdx213.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sm6375-sony-xperia-murray-pdx225.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sm7125-xiaomi-curtana.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sm7125-xiaomi-joyeuse.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sm7225-fairphone-fp4.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sm8150-hdk.dtb
@@ -233,6 +238,7 @@ dtb-$(CONFIG_ARCH_QCOM)     += sm8450-hdk.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sm8450-qrd.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sm8450-sony-xperia-nagara-pdx223.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sm8450-sony-xperia-nagara-pdx224.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sm8550-hdk.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sm8550-mtp.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sm8550-qrd.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sm8650-mtp.dtb
index c08b4be5cc7ee175d944bd9020cf73a0f6aee60e..f9cbf8c1d6891108e208f4626aa7667c74ee413b 100644 (file)
@@ -9,7 +9,7 @@
 #include "apq8016-sbc.dts"
 
 / {
-       camera_vdddo_1v8: camera-vdddo-1v8 {
+       camera_vdddo_1v8: regulator-camera-vdddo {
                compatible = "regulator-fixed";
                regulator-name = "camera_vdddo";
                regulator-min-microvolt = <1800000>;
@@ -17,7 +17,7 @@
                regulator-always-on;
        };
 
-       camera_vdda_2v8: camera-vdda-2v8 {
+       camera_vdda_2v8: regulator-camera-vdda {
                compatible = "regulator-fixed";
                regulator-name = "camera_vdda";
                regulator-min-microvolt = <2800000>;
@@ -25,7 +25,7 @@
                regulator-always-on;
        };
 
-       camera_vddd_1v5: camera-vddd-1v5 {
+       camera_vddd_1v5: regulator-camera-vddd {
                compatible = "regulator-fixed";
                regulator-name = "camera_vddd";
                regulator-min-microvolt = <1500000>;
@@ -53,7 +53,7 @@
 };
 
 &cci_i2c0 {
-       camera_rear@3b {
+       camera@3b {
                compatible = "ovti,ov5640";
                reg = <0x3b>;
 
index 42e2e48b2bc3d10591eed3b4dbe43cecb6ce22be..770d9c2fb4562b1daab13a45945020bdcc7d9b93 100644 (file)
                        compatible = "qcom,ipq5332-dwc3", "qcom,dwc3";
                        reg = <0x08af8800 0x400>;
 
-                       interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq";
+                       interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 53 IRQ_TYPE_EDGE_BOTH>,
+                                    <GIC_SPI 52 IRQ_TYPE_EDGE_BOTH>;
+                       interrupt-names = "pwr_event",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq";
 
                        clocks = <&gcc GCC_USB0_MASTER_CLK>,
                                 <&gcc GCC_SNOC_USB_CLK>,
index 5e1277fea7250b4132039efb18f1cfaafdc5257e..4e29adea570a063fdd18c31da210d00176ace875 100644 (file)
@@ -9,6 +9,7 @@
 #include <dt-bindings/clock/qcom,gcc-ipq6018.h>
 #include <dt-bindings/reset/qcom,gcc-ipq6018.h>
 #include <dt-bindings/clock/qcom,apss-ipq.h>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
        #address-cells = <2>;
@@ -43,6 +44,7 @@
                        clock-names = "cpu";
                        operating-points-v2 = <&cpu_opp_table>;
                        cpu-supply = <&ipq6018_s2>;
+                       #cooling-cells = <2>;
                };
 
                CPU1: cpu@1 {
@@ -55,6 +57,7 @@
                        clock-names = "cpu";
                        operating-points-v2 = <&cpu_opp_table>;
                        cpu-supply = <&ipq6018_s2>;
+                       #cooling-cells = <2>;
                };
 
                CPU2: cpu@2 {
@@ -67,6 +70,7 @@
                        clock-names = "cpu";
                        operating-points-v2 = <&cpu_opp_table>;
                        cpu-supply = <&ipq6018_s2>;
+                       #cooling-cells = <2>;
                };
 
                CPU3: cpu@3 {
@@ -79,6 +83,7 @@
                        clock-names = "cpu";
                        operating-points-v2 = <&cpu_opp_table>;
                        cpu-supply = <&ipq6018_s2>;
+                       #cooling-cells = <2>;
                };
 
                L2_0: l2-cache {
                        clock-names = "core";
                };
 
+               tsens: thermal-sensor@4a9000 {
+                       compatible = "qcom,ipq6018-tsens", "qcom,ipq8074-tsens";
+                       reg = <0x0 0x004a9000 0x0 0x1000>,
+                             <0x0 0x004a8000 0x0 0x1000>;
+                       interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "combined";
+                       #qcom,sensors = <16>;
+                       #thermal-sensor-cells = <1>;
+               };
+
                cryptobam: dma-controller@704000 {
                        compatible = "qcom,bam-v1.7.0";
                        reg = <0x0 0x00704000 0x0 0x20000>;
                                          <&gcc GCC_USB1_MOCK_UTMI_CLK>;
                        assigned-clock-rates = <133330000>,
                                               <24000000>;
+
+                       interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "qusb2_phy";
+
                        resets = <&gcc GCC_USB1_BCR>;
                        status = "disabled";
 
                        status = "disabled";
                };
 
+               blsp1_i2c6: i2c@78ba000 {
+                       compatible = "qcom,i2c-qup-v2.2.1";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x0 0x078ba000 0x0 0x600>;
+                       interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&gcc GCC_BLSP1_QUP6_I2C_APPS_CLK>,
+                              <&gcc GCC_BLSP1_AHB_CLK>;
+                       clock-names = "core", "iface";
+                       clock-frequency = <400000>;
+                       dmas = <&blsp_dma 22>, <&blsp_dma 23>;
+                       dma-names = "tx", "rx";
+                       status = "disabled";
+               };
+
                qpic_bam: dma-controller@7984000 {
                        compatible = "qcom,bam-v1.7.0";
                        reg = <0x0 0x07984000 0x0 0x1a000>;
                                               <133330000>,
                                               <24000000>;
 
+                       interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "qusb2_phy",
+                                         "ss_phy_irq";
+
                        resets = <&gcc GCC_USB0_BCR>;
                        status = "disabled";
 
 
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
-                       interrupt-map = <0 0 0 1 &intc 0 75 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
-                                       <0 0 0 2 &intc 0 78 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
-                                       <0 0 0 3 &intc 0 79 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
-                                       <0 0 0 4 &intc 0 83 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
+                       interrupt-map = <0 0 0 1 &intc 0 0 0 75 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
+                                       <0 0 0 2 &intc 0 0 0 78 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
+                                       <0 0 0 3 &intc 0 0 0 79 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
+                                       <0 0 0 4 &intc 0 0 0 83 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
 
                        clocks = <&gcc GCC_SYS_NOC_PCIE0_AXI_CLK>,
                                 <&gcc GCC_PCIE0_AXI_M_CLK>,
                };
        };
 
+       thermal-zones {
+               nss-top-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 4>;
+
+                       trips {
+                               nss-top-critical {
+                                       temperature = <125000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               nss-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 5>;
+
+                       trips {
+                               nss-critical {
+                                       temperature = <125000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               wcss-phya0-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 7>;
+
+                       trips {
+                               wcss-phya0-critical {
+                                       temperature = <125000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               wcss-phya1-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 8>;
+
+                       trips {
+                               wcss-phya1-critical {
+                                       temperature = <125000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpu-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 13>;
+
+                       trips {
+                               cpu-critical {
+                                       temperature = <125000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+
+                               cpu_alert: cpu-passive {
+                                       temperature = <110000>;
+                                       hysteresis = <1000>;
+                                       type = "passive";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu_alert>;
+                                       cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               lpass-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 14>;
+
+                       trips {
+                               lpass-critical {
+                                       temperature = <125000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               ddrss-top-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens 15>;
+
+                       trips {
+                               ddrss-top-critical {
+                                       temperature = <125000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+       };
+
        timer {
                compatible = "arm,armv8-timer";
                interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
index cf295bed32998087cee60bd0ce61d0cf587d2c0a..e5b89753aa5c12ca1d9e9165c88f5044a2af2924 100644 (file)
                        clocks = <&gcc GCC_MDIO_AHB_CLK>;
                        clock-names = "gcc_mdio_ahb_clk";
 
+                       clock-frequency = <6250000>;
+
                        status = "disabled";
                };
 
                                                <133330000>,
                                                <19200000>;
 
+                       interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "qusb2_phy",
+                                         "ss_phy_irq";
+
                        power-domains = <&gcc USB0_GDSC>;
 
                        resets = <&gcc GCC_USB0_BCR>;
                                                <133330000>,
                                                <19200000>;
 
+                       interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "qusb2_phy",
+                                         "ss_phy_irq";
+
                        power-domains = <&gcc USB1_GDSC>;
 
                        resets = <&gcc GCC_USB1_BCR>;
                        interrupt-names = "msi";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
-                       interrupt-map = <0 0 0 1 &intc 0 142
+                       interrupt-map = <0 0 0 1 &intc 0 142
                                         IRQ_TYPE_LEVEL_HIGH>, /* int_a */
-                                       <0 0 0 2 &intc 0 143
+                                       <0 0 0 2 &intc 0 143
                                         IRQ_TYPE_LEVEL_HIGH>, /* int_b */
-                                       <0 0 0 3 &intc 0 144
+                                       <0 0 0 3 &intc 0 144
                                         IRQ_TYPE_LEVEL_HIGH>, /* int_c */
-                                       <0 0 0 4 &intc 0 145
+                                       <0 0 0 4 &intc 0 145
                                         IRQ_TYPE_LEVEL_HIGH>; /* int_d */
 
                        clocks = <&gcc GCC_SYS_NOC_PCIE1_AXI_CLK>,
                        interrupt-names = "msi";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
-                       interrupt-map = <0 0 0 1 &intc 0 75
+                       interrupt-map = <0 0 0 1 &intc 0 75
                                         IRQ_TYPE_LEVEL_HIGH>, /* int_a */
-                                       <0 0 0 2 &intc 0 78
+                                       <0 0 0 2 &intc 0 78
                                         IRQ_TYPE_LEVEL_HIGH>, /* int_b */
-                                       <0 0 0 3 &intc 0 79
+                                       <0 0 0 3 &intc 0 79
                                         IRQ_TYPE_LEVEL_HIGH>, /* int_c */
-                                       <0 0 0 4 &intc 0 83
+                                       <0 0 0 4 &intc 0 83
                                         IRQ_TYPE_LEVEL_HIGH>; /* int_d */
 
                        clocks = <&gcc GCC_SYS_NOC_PCIE0_AXI_CLK>,
index 5f83ee42a71942c9089e56781c9d839fcc542b2b..7f2e5cbf3bbb711afb8a9ae11402804f6613a18f 100644 (file)
 
                sdhc_1: mmc@7804000 {
                        compatible = "qcom,ipq9574-sdhci", "qcom,sdhci-msm-v5";
-                       reg = <0x07804000 0x1000>, <0x07805000 0x1000>;
-                       reg-names = "hc", "cqhci";
+                       reg = <0x07804000 0x1000>,
+                             <0x07805000 0x1000>,
+                             <0x07808000 0x2000>;
+                       reg-names = "hc", "cqhci", "ice";
 
                        interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
 
                        clocks = <&gcc GCC_SDCC1_AHB_CLK>,
                                 <&gcc GCC_SDCC1_APPS_CLK>,
-                                <&xo_board_clk>;
-                       clock-names = "iface", "core", "xo";
+                                <&xo_board_clk>,
+                                <&gcc GCC_SDCC1_ICE_CORE_CLK>;
+                       clock-names = "iface", "core", "xo", "ice";
                        non-removable;
+                       supports-cqe;
                        status = "disabled";
                };
 
diff --git a/arch/arm64/boot/dts/qcom/msm8216-samsung-fortuna3g.dts b/arch/arm64/boot/dts/qcom/msm8216-samsung-fortuna3g.dts
new file mode 100644 (file)
index 0000000..366914b
--- /dev/null
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/dts-v1/;
+
+#include "msm8916-samsung-fortuna-common.dtsi"
+
+/ {
+       model = "Samsung Galaxy Grand Prime (SM-G530H)";
+       compatible = "samsung,fortuna3g", "qcom,msm8916";
+       chassis-type = "handset";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-fortuna-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-fortuna-common.dtsi
new file mode 100644 (file)
index 0000000..c2800ad
--- /dev/null
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "msm8916-pm8916.dtsi"
+#include "msm8916-modem-qdsp6.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+       aliases {
+               mmc0 = &sdhc_1; /* eMMC */
+               mmc1 = &sdhc_2; /* SD card */
+               serial0 = &blsp_uart2;
+       };
+
+       chosen {
+               stdout-path = "serial0";
+       };
+
+       reserved-memory {
+               /* Additional memory used by Samsung firmware modifications */
+               tz-apps@85a00000 {
+                       reg = <0x0 0x85a00000 0x0 0x600000>;
+                       no-map;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               pinctrl-0 = <&gpio_keys_default>;
+               pinctrl-names = "default";
+
+               label = "GPIO Buttons";
+
+               button-volume-up {
+                       label = "Volume Up";
+                       gpios = <&tlmm 107 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEUP>;
+               };
+
+               button-home {
+                       label = "Home";
+                       gpios = <&tlmm 109 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_HOMEPAGE>;
+               };
+       };
+
+       haptic {
+               compatible = "regulator-haptic";
+               haptic-supply = <&reg_motor_vdd>;
+               min-microvolt = <3300000>;
+               max-microvolt = <3300000>;
+       };
+
+       reg_motor_vdd: regulator-motor-vdd {
+               compatible = "regulator-fixed";
+               regulator-name = "motor_vdd";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               gpio = <&tlmm 72 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+
+               pinctrl-0 = <&motor_en_default>;
+               pinctrl-names = "default";
+       };
+};
+
+&blsp_i2c1 {
+       status = "okay";
+
+       muic: extcon@25 {
+               compatible = "siliconmitus,sm5502-muic";
+               reg = <0x25>;
+               interrupts-extended = <&tlmm 12 IRQ_TYPE_EDGE_FALLING>;
+               pinctrl-0 = <&muic_int_default>;
+               pinctrl-names = "default";
+       };
+};
+
+&blsp_i2c4 {
+       status = "okay";
+
+       fuel-gauge@35 {
+               compatible = "richtek,rt5033-battery";
+               reg = <0x35>;
+
+               interrupts-extended = <&tlmm 121 IRQ_TYPE_EDGE_FALLING>;
+
+               pinctrl-0 = <&fg_alert_default>;
+               pinctrl-names = "default";
+       };
+};
+
+&blsp_uart2 {
+       status = "okay";
+};
+
+&mpss_mem {
+       reg = <0x0 0x86800000 0x0 0x5000000>;
+};
+
+&pm8916_resin {
+       linux,code = <KEY_VOLUMEDOWN>;
+       status = "okay";
+};
+
+&pm8916_rpm_regulators {
+       pm8916_l17: l17 {
+               regulator-min-microvolt = <2850000>;
+               regulator-max-microvolt = <2850000>;
+       };
+};
+
+&sdhc_1 {
+       status = "okay";
+};
+
+&sdhc_2 {
+       pinctrl-0 = <&sdc2_default &sdc2_cd_default>;
+       pinctrl-1 = <&sdc2_sleep &sdc2_cd_default>;
+       pinctrl-names = "default", "sleep";
+
+       cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
+
+       status = "okay";
+};
+
+&sound {
+       model = "msm8916-1mic";
+       audio-routing =
+               "AMIC1", "MIC BIAS External1",
+               "AMIC2", "MIC BIAS Internal2",
+               "AMIC3", "MIC BIAS External1";
+};
+
+&usb {
+       extcon = <&muic>, <&muic>;
+       status = "okay";
+};
+
+&usb_hs_phy {
+       extcon = <&muic>;
+};
+
+&venus {
+       status = "okay";
+};
+
+&venus_mem {
+       status = "okay";
+};
+
+&wcnss {
+       status = "okay";
+};
+
+&wcnss_iris {
+       compatible = "qcom,wcn3620";
+};
+
+&wcnss_mem {
+       status = "okay";
+};
+
+&tlmm {
+       fg_alert_default: fg-alert-default-state {
+               pins = "gpio121";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       gpio_keys_default: gpio-keys-default-state {
+               pins = "gpio107", "gpio109";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-pull-up;
+       };
+
+       motor_en_default: motor-en-default-state {
+               pins = "gpio72";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       muic_int_default: muic-int-default-state {
+               pins = "gpio12";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       sdc2_cd_default: sdc2-cd-default-state {
+               pins = "gpio38";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-disable;
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gprimeltecan.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-gprimeltecan.dts
new file mode 100644 (file)
index 0000000..9d65fa5
--- /dev/null
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/dts-v1/;
+
+#include "msm8916-samsung-fortuna-common.dtsi"
+
+/ {
+       model = "Samsung Galaxy Grand Prime (SM-G530W)";
+       compatible = "samsung,gprimeltecan", "qcom,msm8916";
+       chassis-type = "handset";
+
+       reserved-memory {
+               /* Firmware for gprimeltecan needs more space */
+               /delete-node/ tz-apps@85a00000;
+
+               /* Additional memory used by Samsung firmware modifications */
+               tz-apps@85500000 {
+                       reg = <0x0 0x85500000 0x0 0xb00000>;
+                       no-map;
+               };
+       };
+};
+
+&mpss_mem {
+       /* Firmware for gprimeltecan needs more space */
+       reg = <0x0 0x86800000 0x0 0x5400000>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-grandprimelte.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-grandprimelte.dts
new file mode 100644 (file)
index 0000000..a66ce4b
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/dts-v1/;
+
+#include "msm8916-samsung-fortuna-common.dtsi"
+
+/ {
+       model = "Samsung Galaxy Grand Prime (SM-G530FZ)";
+       compatible = "samsung,grandprimelte", "qcom,msm8916";
+       chassis-type = "handset";
+};
+
+&mpss_mem {
+       /* Firmware for grandprimelte needs more space */
+       reg = <0x0 0x86800000 0x0 0x5400000>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-rossa-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-rossa-common.dtsi
new file mode 100644 (file)
index 0000000..4284377
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "msm8916-samsung-fortuna-common.dtsi"
+
+/* SM5504 MUIC instead of SM5502 */
+/delete-node/ &muic;
+
+&blsp_i2c1 {
+       muic: extcon@14 {
+               compatible = "siliconmitus,sm5504-muic";
+               reg = <0x14>;
+               interrupts-extended = <&tlmm 12 IRQ_TYPE_EDGE_FALLING>;
+               pinctrl-0 = <&muic_int_default>;
+               pinctrl-names = "default";
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-rossa.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-rossa.dts
new file mode 100644 (file)
index 0000000..ebaa13c
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/dts-v1/;
+
+#include "msm8916-samsung-rossa-common.dtsi"
+
+/ {
+       model = "Samsung Galaxy Core Prime LTE";
+       compatible = "samsung,rossa", "qcom,msm8916";
+       chassis-type = "handset";
+};
+
+&mpss_mem {
+       /* Firmware for rossa needs more space */
+       reg = <0x0 0x86800000 0x0 0x5800000>;
+};
index e423c57ddd41eceefaea483aaa343aa9b9bd1ee7..cedff4166bfb9f1f3af68404cad606425d56ce2b 100644 (file)
                        power-domains = <&gcc OXILI_GDSC>;
                        operating-points-v2 = <&gpu_opp_table>;
                        iommus = <&gpu_iommu 1>, <&gpu_iommu 2>;
+                       #cooling-cells = <2>;
+
                        status = "disabled";
 
                        gpu_opp_table: opp-table {
 
                        thermal-sensors = <&tsens 2>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                gpu_alert0: trip-point0 {
                                        temperature = <75000>;
index 82d85ff61045d31c13b6b5874acd315399a8886e..dd45975682b247d5d3a9c14b6c319ecd1f97d878 100644 (file)
                        power-domains = <&gcc OXILI_GDSC>;
                        operating-points-v2 = <&opp_table>;
                        iommus = <&gpu_iommu 1>, <&gpu_iommu 2>;
+                       #cooling-cells = <2>;
+
                        status = "disabled";
 
                        opp_table: opp-table {
 
                        thermal-sensors = <&tsens 3>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                gpu_alert0: trip-point0 {
                                        temperature = <75000>;
                                        type = "passive";
                                };
 
-                               gpu_crit: gpu_crit {
+                               gpu_crit: gpu-crit {
                                        temperature = <95000>;
                                        hysteresis = <2000>;
                                        type = "critical";
index ad2f8cf9c966c568cdc517b1ccd7939ded23e57c..f1011bb641c619c2331fcca2b920151241ead05b 100644 (file)
                                      "vsync",
                                      "core";
 
+                       resets = <&gcc GCC_MDSS_BCR>;
+
                        #address-cells = <1>;
                        #size-cells = <1>;
                        ranges;
                        };
                };
 
+               gpu: gpu@1c00000 {
+                       compatible = "qcom,adreno-506.0", "qcom,adreno";
+                       reg = <0x01c00000 0x40000>;
+                       reg-names = "kgsl_3d0_reg_memory";
+                       interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+
+                       clocks = <&gcc GCC_OXILI_GFX3D_CLK>,
+                                <&gcc GCC_OXILI_AHB_CLK>,
+                                <&gcc GCC_BIMC_GFX_CLK>,
+                                <&gcc GCC_BIMC_GPU_CLK>,
+                                <&gcc GCC_OXILI_TIMER_CLK>,
+                                <&gcc GCC_OXILI_AON_CLK>;
+                       clock-names = "core",
+                                     "iface",
+                                     "mem_iface",
+                                     "alt_mem_iface",
+                                     "rbbmtimer",
+                                     "alwayson";
+                       power-domains = <&gcc OXILI_GX_GDSC>;
+
+                       iommus = <&gpu_iommu 0>;
+                       operating-points-v2 = <&gpu_opp_table>;
+
+                       #cooling-cells = <2>;
+
+                       status = "disabled";
+
+                       zap-shader {
+                               memory-region = <&zap_shader_region>;
+                       };
+
+                       gpu_opp_table: opp-table {
+                               compatible = "operating-points-v2";
+
+                               opp-19200000 {
+                                       opp-hz = /bits/ 64 <19200000>;
+                                       opp-supported-hw = <0xff>;
+                                       required-opps = <&rpmpd_opp_min_svs>;
+                               };
+
+                               opp-133300000 {
+                                       opp-hz = /bits/ 64 <133300000>;
+                                       opp-supported-hw = <0xff>;
+                                       required-opps = <&rpmpd_opp_min_svs>;
+                               };
+
+                               opp-216000000 {
+                                       opp-hz = /bits/ 64 <216000000>;
+                                       opp-supported-hw = <0xff>;
+                                       required-opps = <&rpmpd_opp_low_svs>;
+                               };
+
+                               opp-320000000 {
+                                       opp-hz = /bits/ 64 <320000000>;
+                                       opp-supported-hw = <0xff>;
+                                       required-opps = <&rpmpd_opp_svs>;
+                               };
+
+                               opp-400000000 {
+                                       opp-hz = /bits/ 64 <400000000>;
+                                       opp-supported-hw = <0xff>;
+                                       required-opps = <&rpmpd_opp_svs_plus>;
+                               };
+
+                               opp-510000000 {
+                                       opp-hz = /bits/ 64 <510000000>;
+                                       opp-supported-hw = <0xff>;
+                                       required-opps = <&rpmpd_opp_nom>;
+                               };
+
+                               opp-560000000 {
+                                       opp-hz = /bits/ 64 <560000000>;
+                                       opp-supported-hw = <0xff>;
+                                       required-opps = <&rpmpd_opp_nom_plus>;
+                               };
+
+                               /*
+                                * This opp is only available on msm8953 and
+                                * sdm632, the max for sdm450 is 600MHz.
+                                */
+                               opp-650000000 {
+                                       opp-hz = /bits/ 64 <650000000>;
+                                       opp-supported-hw = <0xff>;
+                                       required-opps = <&rpmpd_opp_turbo>;
+                               };
+                       };
+               };
+
+               gpu_iommu: iommu@1c48000 {
+                       compatible = "qcom,msm8953-iommu", "qcom,msm-iommu-v2";
+                       ranges = <0 0x01c48000 0x8000>;
+
+                       clocks = <&gcc GCC_OXILI_AHB_CLK>,
+                                <&gcc GCC_BIMC_GFX_CLK>;
+                       clock-names = "iface", "bus";
+
+                       power-domains = <&gcc OXILI_CX_GDSC>;
+
+                       qcom,iommu-secure-id = <18>;
+
+                       #address-cells = <1>;
+                       #iommu-cells = <1>;
+                       #size-cells = <1>;
+
+                       /* gfx3d_user */
+                       iommu-ctx@0 {
+                               compatible = "qcom,msm-iommu-v2-ns";
+                               reg = <0x0000 0x1000>;
+                               interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+
+                       /* gfx3d_secure */
+                       iommu-ctx@2000 {
+                               compatible = "qcom,msm-iommu-v2-sec";
+                               reg = <0x2000 0x1000>;
+                               interrupts = <GIC_SPI 233 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+               };
+
                apps_iommu: iommu@1e20000 {
                        compatible = "qcom,msm8953-iommu", "qcom,msm-iommu-v1";
                        ranges = <0 0x01e20000 0x20000>;
                        #size-cells = <1>;
                        ranges;
 
-                       interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq";
+                       interrupt-names = "pwr_event",
+                                         "qusb2_phy",
+                                         "ss_phy_irq";
 
                        clocks = <&gcc GCC_USB_PHY_CFG_AHB_CLK>,
                                 <&gcc GCC_USB30_MASTER_CLK>,
                                };
                        };
                };
+
+               gpu-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsens0 15>;
+
+                       trips {
+                               gpu_alert: trip-point0 {
+                                       temperature = <70000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               gpu_crit: crit {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_alert>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
        };
 
        timer {
index cbc84459a5ae3da995b5006adecfd0668fdb7274..10cd244dea4f7202b3b7aed42fb8ddae16a87315 100644 (file)
 &blsp2_i2c1 {
        status = "okay";
 
-       sideinteraction: ad7147_captouch@2c {
+       sideinteraction: touch@2c {
                compatible = "ad,ad7147_captouch";
                reg = <0x2c>;
 
index 9dbde79f26a28d3fe8b555c3bfb8f0c7048a343d..0163d41f95f865d0154eb3a551a5ff3c9fd033bb 100644 (file)
@@ -79,7 +79,7 @@
                        pmsg-size = <0x80000>;
                };
 
-               fb_region: fb_region@40000000 {
+               fb_region: fb@40000000 {
                        reg = <0 0x40000000 0 0x1000000>;
                        no-map;
                };
index 8295bf1b219d89704a0f0558d576d40551f6bc34..695e541832ad51fb19637253c7f6b67e58eea106 100644 (file)
                #size-cells = <2>;
                ranges;
 
-               dfps_data_mem: dfps_data_mem@3400000 {
+               dfps_data_mem: dfps-data@3400000 {
                        reg = <0 0x03400000 0 0x1000>;
                        no-map;
                };
                        no-map;
                };
 
-               smem_mem: smem_region@6a00000 {
+               smem_mem: smem@6a00000 {
                        reg = <0 0x06a00000 0 0x200000>;
                        no-map;
                };
index 8d41ed261adfbfc99e15c07755f54d8f4cf5cc80..1601e46549e77990dafbd63894b9c078ffec60af 100644 (file)
                };
        };
 
-       mpm: interrupt-controller {
-               compatible = "qcom,mpm";
-               qcom,rpm-msg-ram = <&apss_mpm>;
-               interrupts = <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>;
-               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 184>,  /* TSENS1 upper_lower_int */
-                                  <52 243>, /* DWC3_PRI ss_phy_irq */
-                                  <79 347>, /* DWC3_PRI hs_phy_irq */
-                                  <80 352>, /* DWC3_SEC hs_phy_irq */
-                                  <81 347>, /* QUSB2_PHY_PRI DP+DM */
-                                  <82 352>, /* QUSB2_PHY_SEC DP+DM */
-                                  <87 326>; /* SPMI */
-       };
-
        psci {
                compatible = "arm,psci-1.0";
                method = "smc";
                };
 
                rpm_msg_ram: sram@68000 {
-                       compatible = "qcom,rpm-msg-ram", "mmio-sram";
+                       compatible = "qcom,rpm-msg-ram";
                        reg = <0x00068000 0x6000>;
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges = <0 0x00068000 0x7000>;
-
-                       apss_mpm: sram@1b8 {
-                               reg = <0x1b8 0x48>;
-                       };
                };
 
                qfprom@74000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
 
-                       qusb2p_hstx_trim: hstx_trim@24e {
+                       qusb2p_hstx_trim: hstx-trim@24e {
                                reg = <0x24e 0x2>;
                                bits = <5 4>;
                        };
 
-                       qusb2s_hstx_trim: hstx_trim@24f {
+                       qusb2s_hstx_trim: hstx-trim@24f {
                                reg = <0x24f 0x1>;
                                bits = <1 4>;
                        };
                        reg = <0x004ad000 0x1000>, /* TM */
                              <0x004ac000 0x1000>; /* SROT */
                        #qcom,sensors = <8>;
-                       interrupts-extended = <&mpm 2 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&intc GIC_SPI 430 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 430 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "uplow", "critical";
                        #thermal-sensor-cells = <1>;
                };
                        interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
                        gpio-controller;
                        gpio-ranges = <&tlmm 0 0 150>;
-                       wakeup-parent = <&mpm>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
                              <0x0400a000 0x002100>;
                        reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
                        interrupt-names = "periph_irq";
-                       interrupts-extended = <&mpm 87 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>;
                        qcom,ee = <0>;
                        qcom,channel = <0>;
                        #address-cells = <2>;
                                <0 0>,
                                <0 0>,
                                <150000000 300000000>,
-                               <0>,
+                               <75000000 150000000>,
                                <0 0>,
                                <0 0>,
                                <0 0>,
                        compatible = "qcom,msm8996-qmp-ufs-phy";
                        reg = <0x00627000 0x1000>;
 
-                       clocks = <&gcc GCC_UFS_CLKREF_CLK>;
-                       clock-names = "ref";
+                       clocks = <&rpmcc RPM_SMD_LN_BB_CLK>, <&gcc GCC_UFS_CLKREF_CLK>;
+                       clock-names = "ref", "qref";
 
                        resets = <&ufshc 0>;
                        reset-names = "ufsphy";
                        #size-cells = <1>;
                        ranges;
 
-                       interrupts-extended = <&mpm 79 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&mpm 52 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hs_phy_irq", "ss_phy_irq";
 
                        clocks = <&gcc GCC_SYS_NOC_USB3_AXI_CLK>,
                        #size-cells = <1>;
                        ranges;
 
-                       interrupts = <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq";
+                       interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "qusb2_phy",
+                                         "hs_phy_irq";
 
                        clocks = <&gcc GCC_PERIPH_NOC_USB20_AHB_CLK>,
                                <&gcc GCC_USB20_MASTER_CLK>,
index 2793cc22d381af990a80018b96e16da4400d0fd1..4dfe2d09ac2859d1da4341954fc42450696f92ef 100644 (file)
                        compatible = "qcom,msm8998-qmp-ufs-phy";
                        reg = <0x01da7000 0x1000>;
 
-                       clock-names =
-                               "ref",
-                               "ref_aux";
-                       clocks =
-                               <&gcc GCC_UFS_CLKREF_CLK>,
-                               <&gcc GCC_UFS_PHY_AUX_CLK>;
+                       clocks = <&rpmcc RPM_SMD_LN_BB_CLK1>,
+                                <&gcc GCC_UFS_PHY_AUX_CLK>,
+                                <&gcc GCC_UFS_CLKREF_CLK>;
+                       clock-names = "ref",
+                                     "ref_aux",
+                                     "qref";
 
                        reset-names = "ufsphy";
                        resets = <&ufshc 0>;
                        reg = <0x01f60000 0x20000>;
                };
 
+               tcsr_regs_2: syscon@1fc0000 {
+                       compatible = "qcom,msm8998-tcsr", "syscon";
+                       reg = <0x01fc0000 0x26000>;
+               };
+
                tlmm: pinctrl@3400000 {
                        compatible = "qcom,msm8998-pinctrl";
                        reg = <0x03400000 0xc00000>;
                                          <&gcc GCC_USB30_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <120000000>;
 
-                       interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq";
+                       interrupt-names = "pwr_event",
+                                         "qusb2_phy",
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB_30_GDSC>;
 
                        reset-names = "phy",
                                      "phy_phy";
 
+                       qcom,tcsr-reg = <&tcsr_regs_2 0xb244>;
+
                        status = "disabled";
                };
 
similarity index 56%
rename from arch/arm64/boot/dts/qcom/pm2250.dtsi
rename to arch/arm64/boot/dts/qcom/pm4125.dtsi
index 5f1d15db5c9934b58d7e1bdf043e61ae0141df33..cf8c822e80ce87c332b1b3f378c362686f908441 100644 (file)
@@ -19,7 +19,7 @@
                        compatible = "qcom,pm8916-pon";
                        reg = <0x800>;
 
-                       pm2250_pwrkey: pwrkey {
+                       pm4125_pwrkey: pwrkey {
                                compatible = "qcom,pm8941-pwrkey";
                                interrupts-extended = <&spmi_bus 0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>;
                                linux,code = <KEY_POWER>;
@@ -27,7 +27,7 @@
                                bias-pull-up;
                        };
 
-                       pm2250_resin: resin {
+                       pm4125_resin: resin {
                                compatible = "qcom,pm8941-resin";
                                interrupts-extended = <&spmi_bus 0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>;
                                debounce = <15625>;
                        };
                };
 
+               pm4125_vbus: usb-vbus-regulator@1100 {
+                       compatible = "qcom,pm4125-vbus-reg", "qcom,pm8150b-vbus-reg";
+                       reg = <0x1100>;
+                       status = "disabled";
+               };
+
+               pm4125_typec: typec@1500 {
+                       compatible = "qcom,pm4125-typec", "qcom,pmi632-typec";
+                       reg = <0x1500>;
+                       interrupts = <0x0 0x15 0x00 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x15 0x01 IRQ_TYPE_EDGE_BOTH>,
+                                    <0x0 0x15 0x02 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x15 0x03 IRQ_TYPE_EDGE_BOTH>,
+                                    <0x0 0x15 0x04 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x15 0x05 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x15 0x06 IRQ_TYPE_EDGE_BOTH>,
+                                    <0x0 0x15 0x07 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "or-rid-detect-change",
+                                         "vpd-detect",
+                                         "cc-state-change",
+                                         "vconn-oc",
+                                         "vbus-change",
+                                         "attach-detach",
+                                         "legacy-cable-detect",
+                                         "try-snk-src-detect";
+                       vdd-vbus-supply = <&pm4125_vbus>;
+
+                       status = "disabled";
+               };
+
                rtc@6000 {
                        compatible = "qcom,pm8941-rtc";
                        reg = <0x6000>, <0x6100>;
                        interrupts-extended = <&spmi_bus 0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>;
                };
 
-               pm2250_gpios: gpio@c000 {
+               pm4125_gpios: gpio@c000 {
                        compatible = "qcom,pm2250-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
-                       gpio-ranges = <&pm2250_gpios 0 0 10>;
+                       gpio-ranges = <&pm4125_gpios 0 0 10>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index 4eb79e0ce40a5e9715d15d5dfadecac7dbe0fbab..94d53b1cf6c8f15267d1a02c6d1c00b9c3d27d84 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
+               pmi632_vbus: usb-vbus-regulator@1100 {
+                       compatible = "qcom,pmi632-vbus-reg", "qcom,pm8150b-vbus-reg";
+                       reg = <0x1100>;
+                       status = "disabled";
+               };
+
+               pmi632_typec: typec@1500 {
+                       compatible = "qcom,pmi632-typec";
+                       reg = <0x1500>;
+                       interrupts = <0x2 0x15 0x00 IRQ_TYPE_EDGE_RISING>,
+                                    <0x2 0x15 0x01 IRQ_TYPE_EDGE_BOTH>,
+                                    <0x2 0x15 0x02 IRQ_TYPE_EDGE_RISING>,
+                                    <0x2 0x15 0x03 IRQ_TYPE_EDGE_BOTH>,
+                                    <0x2 0x15 0x04 IRQ_TYPE_EDGE_RISING>,
+                                    <0x2 0x15 0x05 IRQ_TYPE_EDGE_RISING>,
+                                    <0x2 0x15 0x06 IRQ_TYPE_EDGE_BOTH>,
+                                    <0x2 0x15 0x07 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "or-rid-detect-change",
+                                         "vpd-detect",
+                                         "cc-state-change",
+                                         "vconn-oc",
+                                         "vbus-change",
+                                         "attach-detach",
+                                         "legacy-cable-detect",
+                                         "try-snk-src-detect";
+                       vdd-vbus-supply = <&pmi632_vbus>;
+
+                       status = "disabled";
+               };
+
                pmi632_temp: temp-alarm@2400 {
                        compatible = "qcom,spmi-temp-alarm";
                        reg = <0x2400>;
                        status = "disabled";
                };
 
+               pmi632_pbs_client3: pbs@7400 {
+                       compatible = "qcom,pmi632-pbs", "qcom,pbs";
+                       reg = <0x7400>;
+               };
+
                pmi632_sdam_7: nvram@b600 {
                        compatible = "qcom,spmi-sdam";
                        reg = <0xb600>;
                pmi632_lpg: pwm {
                        compatible = "qcom,pmi632-lpg";
 
+                       nvmem = <&pmi632_sdam_7>;
+                       nvmem-names = "lpg_chan_sdam";
+                       qcom,pbs = <&pmi632_pbs_client3>;
+
                        #address-cells = <1>;
                        #size-cells = <0>;
                        #pwm-cells = <2>;
index 0911fb08ed6327f75d6e2d627324bffef24dec22..89beac833d43552197b88ac5b9d57c239a6bbb39 100644 (file)
                        #hwlock-cells = <1>;
                };
 
+               tcsr_regs: syscon@3c0000 {
+                       compatible = "qcom,qcm2290-tcsr", "syscon";
+                       reg = <0x0 0x003c0000 0x0 0x40000>;
+               };
+
                tlmm: pinctrl@500000 {
                        compatible = "qcom,qcm2290-tlmm";
                        reg = <0x0 0x00500000 0x0 0x300000>;
 
                        #phy-cells = <0>;
 
+                       qcom,tcsr-reg = <&tcsr_regs 0xb244>;
+
                        status = "disabled";
                };
 
index 176898c9dbbd72672dce448f4b747aef022820e3..4ff9fc24e50e120f51e840191881d22c59aed874 100644 (file)
                };
        };
 
+       pmic-glink {
+               compatible = "qcom,qcm6490-pmic-glink", "qcom,pmic-glink";
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               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@1 {
+                                       reg = <1>;
+
+                                       pmic_glink_ss_in: endpoint {
+                                               remote-endpoint = <&usb_1_dwc3_ss>;
+                                       };
+                               };
+                       };
+               };
+       };
+
        reserved-memory {
                cont_splash_mem: cont-splash@e1000000 {
                        reg = <0x0 0xe1000000 0x0 0x2300000>;
                        no-map;
                };
 
+               removed_mem: removed@c0000000 {
+                       reg = <0x0 0xc0000000 0x0 0x5100000>;
+                       no-map;
+               };
+
                rmtfs_mem: memory@f8500000 {
                        compatible = "qcom,rmtfs-mem";
                        reg = <0x0 0xf8500000 0x0 0x600000>;
 };
 
 &usb_1_dwc3 {
-       dr_mode = "peripheral";
+       dr_mode = "otg";
+       usb-role-switch;
+};
+
+&usb_1_dwc3_hs {
+       remote-endpoint = <&pmic_glink_hs_in>;
+};
+
+&usb_1_dwc3_ss {
+       remote-endpoint = <&pmic_glink_ss_in>;
 };
 
 &usb_1_hsphy {
        status = "okay";
 };
 
+&venus {
+       firmware-name = "qcom/qcm6490/fairphone5/venus.mbn";
+       status = "okay";
+};
+
 &wifi {
        qcom,ath11k-calibration-variant = "Fairphone_5";
        status = "okay";
index 03e97e27d16d4abb521e5fb152d0a743d702809a..e4bfad50a669b18edb60cf0bd9011f61fbf20919 100644 (file)
@@ -5,8 +5,14 @@
 
 /dts-v1/;
 
+/* PM7250B is configured to use SID8/9 */
+#define PM7250B_SID 8
+#define PM7250B_SID1 9
+
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 #include "sc7280.dtsi"
+#include "pm7250b.dtsi"
 #include "pm7325.dtsi"
 #include "pm8350c.dtsi"
 #include "pmk8350.dtsi"
                        no-map;
                };
 
-               trusted_apps_mem: trusted_apps@c1800000 {
+               trusted_apps_mem: trusted-apps@c1800000 {
                        reg = <0x0 0xc1800000 0x0 0x1c00000>;
                        no-map;
                };
        vph_pwr: vph-pwr-regulator {
                compatible = "regulator-fixed";
                regulator-name = "vph_pwr";
-               regulator-min-microvolt = <2500000>;
-               regulator-max-microvolt = <4350000>;
+               regulator-min-microvolt = <3700000>;
+               regulator-max-microvolt = <3700000>;
        };
 };
 
        };
 };
 
+&pm8350c_pwm {
+       status = "okay";
+
+       multi-led {
+               color = <LED_COLOR_ID_RGB>;
+               function = LED_FUNCTION_STATUS;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               led@1 {
+                       reg = <1>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+
+               led@2 {
+                       reg = <2>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led@3 {
+                       reg = <3>;
+                       color = <LED_COLOR_ID_BLUE>;
+               };
+       };
+};
+
 &qupv3_id_0 {
        status = "okay";
 };
index 2f2eeaf2e945781056add9a0d5c5fce3541471c9..a05d0234f7fc0af276824fa5aba82d2abddb5f9c 100644 (file)
                        assigned-clocks = <&gcc GCC_USB20_MOCK_UTMI_CLK>,
                                          <&gcc GCC_USB30_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <200000000>;
+
+                       interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "qusb2_phy";
+
                        status = "disabled";
 
                        usb3_dwc3: usb@7580000 {
                        assigned-clocks = <&gcc GCC_USB20_MOCK_UTMI_CLK>,
                                          <&gcc GCC_USB_HS_SYSTEM_CLK>;
                        assigned-clock-rates = <19200000>, <133333333>;
+
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "qusb2_phy";
+
                        status = "disabled";
 
                        usb@78c0000 {
index 8bb7d13d85f663dfb38ed75a54614fa486dbe83b..97824c769ba34203b569e79dbe20143284e74e48 100644 (file)
                        no-map;
                };
 
-               trusted_apps_mem: trusted_apps@c1800000 {
+               trusted_apps_mem: trusted-apps@c1800000 {
                        reg = <0x0 0xc1800000 0x0 0x1c00000>;
                        no-map;
                };
        vph_pwr: vph-pwr-regulator {
                compatible = "regulator-fixed";
                regulator-name = "vph_pwr";
-               regulator-min-microvolt = <2500000>;
-               regulator-max-microvolt = <4350000>;
+               regulator-min-microvolt = <3700000>;
+               regulator-max-microvolt = <3700000>;
        };
 };
 
        };
 };
 
+&gcc {
+       protected-clocks = <GCC_CFG_NOC_LPASS_CLK>,
+                          <GCC_MSS_CFG_AHB_CLK>,
+                          <GCC_MSS_GPLL0_MAIN_DIV_CLK_SRC>,
+                          <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>;
+};
+
 &qupv3_id_0 {
        status = "okay";
 };
index aa53b6af6d9cbd1c1331f0ddf06a7aab70336eb3..6e9dd0312adc5d369136fedbbd6166f7a6f7390c 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <dt-bindings/leds/common.h>
 #include "qcm2290.dtsi"
-#include "pm2250.dtsi"
+#include "pm4125.dtsi"
 
 / {
        model = "Qualcomm Technologies, Inc. Robotics RB1";
        };
 };
 
+&CPU_PD0 {
+       /delete-property/ power-domains;
+};
+
+&CPU_PD1 {
+       /delete-property/ power-domains;
+};
+
+&CPU_PD2 {
+       /delete-property/ power-domains;
+};
+
+&CPU_PD3 {
+       /delete-property/ power-domains;
+};
+
+/delete-node/ &CLUSTER_PD;
+
 &gpi_dma0 {
        status = "okay";
 };
 };
 
 &mdss_dsi0 {
-       vdda-supply = <&pm2250_l5>;
+       vdda-supply = <&pm4125_l5>;
        status = "okay";
 };
 
        status = "okay";
 };
 
-&pm2250_resin {
+&pm4125_resin {
        linux,code = <KEY_VOLUMEDOWN>;
        status = "okay";
 };
                compatible = "qcom,rpm-pm2250-regulators";
                vdd_s3-supply = <&vph_pwr>;
                vdd_s4-supply = <&vph_pwr>;
-               vdd_l1_l2_l3_l5_l6_l7_l8_l9_l10_l11_l12-supply = <&pm2250_s3>;
+               vdd_l1_l2_l3_l5_l6_l7_l8_l9_l10_l11_l12-supply = <&pm4125_s3>;
                vdd_l4_l17_l18_l19_l20_l21_l22-supply = <&vph_pwr>;
-               vdd_l13_l14_l15_l16-supply = <&pm2250_s4>;
+               vdd_l13_l14_l15_l16-supply = <&pm4125_s4>;
 
                /*
                 * S1 - VDD_APC
                 * S2 - VDD_CX
                 */
 
-               pm2250_s3: s3 {
+               pm4125_s3: s3 {
                        /* 0.4V-1.6625V -> 1.3V (Power tree requirements) */
                        regulator-min-microvolt = <1352000>;
                        regulator-max-microvolt = <1352000>;
                        regulator-boot-on;
                };
 
-               pm2250_s4: s4 {
+               pm4125_s4: s4 {
                        /* 1.2V-2.35V -> 2.05V (Power tree requirements) */
                        regulator-min-microvolt = <2072000>;
                        regulator-max-microvolt = <2072000>;
 
                /* L1 - VDD_MX */
 
-               pm2250_l2: l2 {
+               pm4125_l2: l2 {
                        /* LPDDR4X VDD2 */
                        regulator-min-microvolt = <1136000>;
                        regulator-max-microvolt = <1136000>;
                        regulator-boot-on;
                };
 
-               pm2250_l3: l3 {
+               pm4125_l3: l3 {
                        /* LPDDR4X VDDQ */
                        regulator-min-microvolt = <616000>;
                        regulator-max-microvolt = <616000>;
                        regulator-boot-on;
                };
 
-               pm2250_l4: l4 {
+               pm4125_l4: l4 {
                        /* max = 3.05V -> max = 2.7 to disable 3V signaling (SDHCI2) */
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <2700000>;
                        regulator-allow-set-load;
                };
 
-               pm2250_l5: l5 {
+               pm4125_l5: l5 {
                        /* CSI/DSI */
                        regulator-min-microvolt = <1232000>;
                        regulator-max-microvolt = <1232000>;
                        regulator-boot-on;
                };
 
-               pm2250_l6: l6 {
+               pm4125_l6: l6 {
                        /* DRAM PLL */
                        regulator-min-microvolt = <928000>;
                        regulator-max-microvolt = <928000>;
                        regulator-boot-on;
                };
 
-               pm2250_l7: l7 {
+               pm4125_l7: l7 {
                        /* Wi-Fi CX/MX */
                        regulator-min-microvolt = <664000>;
                        regulator-max-microvolt = <664000>;
                 * L9 - VDD_LPI_MX
                 */
 
-               pm2250_l10: l10 {
+               pm4125_l10: l10 {
                        /* Wi-Fi RFA */
                        regulator-min-microvolt = <1304000>;
                        regulator-max-microvolt = <1304000>;
                };
 
-               pm2250_l11: l11 {
+               pm4125_l11: l11 {
                        /* GPS RF1 */
                        regulator-min-microvolt = <1000000>;
                        regulator-max-microvolt = <1000000>;
                        regulator-boot-on;
                };
 
-               pm2250_l12: l12 {
+               pm4125_l12: l12 {
                        /* USB PHYs */
                        regulator-min-microvolt = <928000>;
                        regulator-max-microvolt = <928000>;
                        regulator-boot-on;
                };
 
-               pm2250_l13: l13 {
+               pm4125_l13: l13 {
                        /* USB/QFPROM/PLLs */
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                        regulator-boot-on;
                };
 
-               pm2250_l14: l14 {
+               pm4125_l14: l14 {
                        /* SDHCI1 VQMMC */
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                        regulator-always-on;
                };
 
-               pm2250_l15: l15 {
+               pm4125_l15: l15 {
                        /* WCD/DSI/BT VDDIO */
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                        regulator-boot-on;
                };
 
-               pm2250_l16: l16 {
+               pm4125_l16: l16 {
                        /* GPS RF2 */
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                        regulator-boot-on;
                };
 
-               pm2250_l17: l17 {
+               pm4125_l17: l17 {
                        regulator-min-microvolt = <3000000>;
                        regulator-max-microvolt = <3000000>;
                };
 
-               pm2250_l18: l18 {
+               pm4125_l18: l18 {
                        /* VDD_PXn */
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                };
 
-               pm2250_l19: l19 {
+               pm4125_l19: l19 {
                        /* VDD_PXn */
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                };
 
-               pm2250_l20: l20 {
+               pm4125_l20: l20 {
                        /* SDHCI1 VMMC */
                        regulator-min-microvolt = <2400000>;
                        regulator-max-microvolt = <3600000>;
                        regulator-allow-set-load;
                };
 
-               pm2250_l21: l21 {
+               pm4125_l21: l21 {
                        /* SDHCI2 VMMC */
                        regulator-min-microvolt = <2960000>;
                        regulator-max-microvolt = <3300000>;
                        regulator-boot-on;
                };
 
-               pm2250_l22: l22 {
+               pm4125_l22: l22 {
                        /* Wi-Fi */
                        regulator-min-microvolt = <3312000>;
                        regulator-max-microvolt = <3312000>;
 };
 
 &sdhc_1 {
-       vmmc-supply = <&pm2250_l20>;
-       vqmmc-supply = <&pm2250_l14>;
+       vmmc-supply = <&pm4125_l20>;
+       vqmmc-supply = <&pm4125_l14>;
        pinctrl-0 = <&sdc1_state_on>;
        pinctrl-1 = <&sdc1_state_off>;
        pinctrl-names = "default", "sleep";
 };
 
 &sdhc_2 {
-       vmmc-supply = <&pm2250_l21>;
-       vqmmc-supply = <&pm2250_l4>;
+       vmmc-supply = <&pm4125_l21>;
+       vqmmc-supply = <&pm4125_l4>;
        cd-gpios = <&tlmm 88 GPIO_ACTIVE_LOW>;
        pinctrl-0 = <&sdc2_state_on &sd_det_in_on>;
        pinctrl-1 = <&sdc2_state_off &sd_det_in_off>;
 };
 
 &usb_qmpphy {
-       vdda-phy-supply = <&pm2250_l12>;
-       vdda-pll-supply = <&pm2250_l13>;
+       vdda-phy-supply = <&pm4125_l12>;
+       vdda-pll-supply = <&pm4125_l13>;
        status = "okay";
 };
 
 };
 
 &usb_hsphy {
-       vdd-supply = <&pm2250_l12>;
-       vdda-pll-supply = <&pm2250_l13>;
-       vdda-phy-dpdm-supply = <&pm2250_l21>;
+       vdd-supply = <&pm4125_l12>;
+       vdda-pll-supply = <&pm4125_l13>;
+       vdda-phy-dpdm-supply = <&pm4125_l21>;
        status = "okay";
 };
 
 &wifi {
-       vdd-0.8-cx-mx-supply = <&pm2250_l7>;
-       vdd-1.8-xo-supply = <&pm2250_l13>;
-       vdd-1.3-rfa-supply = <&pm2250_l10>;
-       vdd-3.3-ch0-supply = <&pm2250_l22>;
+       vdd-0.8-cx-mx-supply = <&pm4125_l7>;
+       vdd-1.8-xo-supply = <&pm4125_l13>;
+       vdd-1.3-rfa-supply = <&pm4125_l10>;
+       vdd-3.3-ch0-supply = <&pm4125_l22>;
        qcom,ath10k-calibration-variant = "Thundercomm_RB1";
        status = "okay";
 };
index 7c19f874fa716d1ca616deaf5537001204e7f9f0..696d6d43c56b326f5eff21b57cc28daad94c70c1 100644 (file)
@@ -6,8 +6,10 @@
 /dts-v1/;
 
 #include <dt-bindings/leds/common.h>
+#include <dt-bindings/usb/pd.h>
 #include "sm4250.dtsi"
 #include "pm6125.dtsi"
+#include "pmi632.dtsi"
 
 / {
        model = "Qualcomm Technologies, Inc. QRB4210 RB2";
        };
 };
 
+&pmi632_typec {
+       status = "okay";
+
+       connector {
+               compatible = "usb-c-connector";
+
+               power-role = "dual";
+               data-role = "dual";
+               self-powered;
+
+               typec-power-opmode = "default";
+               pd-disable;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               pmi632_hs_in: endpoint {
+                                       remote-endpoint = <&usb_dwc3_hs>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+                               pmi632_ss_in: endpoint {
+                                       remote-endpoint = <&usb_qmpphy_out>;
+                               };
+                       };
+               };
+       };
+};
+
+&pmi632_vbus {
+       regulator-min-microamp = <500000>;
+       regulator-max-microamp = <3000000>;
+       status = "okay";
+};
+
 &pon_pwrkey {
        status = "okay";
 };
        status = "okay";
 };
 
-&usb_dwc3 {
-       maximum-speed = "super-speed";
+&usb_dwc3_hs {
+       remote-endpoint = <&pmi632_hs_in>;
 };
 
 &usb_hsphy {
        status = "okay";
 };
 
+&usb_qmpphy_out {
+       remote-endpoint = <&pmi632_ss_in>;
+};
+
 &wifi {
        vdd-0.8-cx-mx-supply = <&vreg_l8a_0p664>;
        vdd-1.8-xo-supply = <&vreg_l16a_1p3>;
index fd253942e5e5cdc42f713459a4344081ca049841..78e933c42c3144324da581687fd712f39fb796ec 100644 (file)
                        };
                };
        };
+
+       reserved-memory {
+               gpu_mem: gpu-mem@8bf00000 {
+                       reg = <0 0x8bf00000 0 0x2000>;
+                       no-map;
+               };
+       };
 };
 
 &apps_rsc {
        status = "okay";
 };
 
+&i2c12 {
+       pinctrl-0 = <&qup1_i2c4_state>;
+       pinctrl-names = "default";
+
+       status = "okay";
+
+       vdd_gfx: regulator@39 {
+               compatible = "maxim,max20411";
+               reg = <0x39>;
+
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <800000>;
+
+               enable-gpios = <&pmm8540a_gpios 2 GPIO_ACTIVE_HIGH>;
+
+               pinctrl-0 = <&max20411_en>;
+               pinctrl-names = "default";
+       };
+};
+
+&gpucc {
+       vdd-gfx-supply = <&vdd_gfx>;
+       status = "okay";
+};
+
+&gmu {
+       status = "okay";
+};
+
+&gpu {
+       status = "okay";
+
+       zap-shader {
+               memory-region = <&gpu_mem>;
+               firmware-name = "qcom/sa8295p/a690_zap.mbn";
+       };
+};
+
+&gpu_smmu {
+       status = "okay";
+};
+
 &mdss0 {
        status = "okay";
 };
        status = "okay";
 };
 
+&qup1 {
+       status = "okay";
+};
+
 &qup2 {
        status = "okay";
 };
 
 /* PINCTRL */
 
+&pmm8540a_gpios {
+       max20411_en: max20411-en-state {
+               pins = "gpio2";
+               function = "normal";
+               output-enable;
+       };
+};
+
 &tlmm {
        pcie2a_default: pcie2a-default-state {
                clkreq-n-pins {
                        bias-pull-up;
                };
        };
+
+       qup1_i2c4_state: qup1-i2c4-state {
+               pins = "gpio0", "gpio1";
+               function = "qup12";
+               drive-strength = <2>;
+               bias-pull-up;
+       };
 };
index b04f72ec097ca509846a007b387004a4a69cc2dc..177b9dad6ff703467ea4d10e0f5a651d11569275 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pcie2a_default>;
 
-       status = "okay";
+       status = "disabled";
 };
 
 &pcie2a_phy {
        vdda-phy-supply = <&vreg_l11a>;
        vdda-pll-supply = <&vreg_l3a>;
 
-       status = "okay";
+       status = "disabled";
 };
 
 &pcie3a {
index 96b2c59ad02b4dfe690227e70660b1b0ac0fb786..23888029cc117956d8531c423c3249e897ede0d9 100644 (file)
 };
 
 &gpucc {
+       /* SA8295P and SA8540P doesn't provide gfx.lvl */
+       /delete-property/ power-domains;
+
        status = "disabled";
 };
 
index a7eaca33d326441d64df943bc72258b6d2d29707..231cea1f0fa8f46d890146ed8d7f469bbf40d210 100644 (file)
                        no-map;
                };
 
+               ddr_training_checksum: ddr-training-checksum@908c0000 {
+                       reg = <0x0 0x908c0000 0x0 0x1000>;
+                       no-map;
+               };
+
                reserved_mem: reserved@908f0000 {
-                       reg = <0x0 0x908f0000 0x0 0xf000>;
+                       reg = <0x0 0x908f0000 0x0 0xe000>;
                        no-map;
                };
 
-               secdata_apss_mem: secdata-apss@908ff000 {
-                       reg = <0x0 0x908ff000 0x0 0x1000>;
+               secdata_apss_mem: secdata-apss@908fe000 {
+                       reg = <0x0 0x908fe000 0x0 0x2000>;
                        no-map;
                };
 
                        hwlocks = <&tcsr_mutex 3>;
                };
 
-               cpucp_fw_mem: cpucp-fw@90b00000 {
-                       reg = <0x0 0x90b00000 0x0 0x100000>;
+               tz_sail_mailbox_mem: tz-sail-mailbox@90c00000 {
+                       reg = <0x0 0x90c00000 0x0 0x100000>;
+                       no-map;
+               };
+
+               sail_mailbox_mem: sail-ss@90d00000 {
+                       reg = <0x0 0x90d00000 0x0 0x100000>;
+                       no-map;
+               };
+
+               sail_ota_mem: sail-ss@90e00000 {
+                       reg = <0x0 0x90e00000 0x0 0x300000>;
+                       no-map;
+               };
+
+               aoss_backup_mem: aoss-backup@91b00000 {
+                       reg = <0x0 0x91b00000 0x0 0x40000>;
+                       no-map;
+               };
+
+               cpucp_backup_mem: cpucp-backup@91b40000 {
+                       reg = <0x0 0x91b40000 0x0 0x40000>;
+                       no-map;
+               };
+
+               tz_config_backup_mem: tz-config-backup@91b80000 {
+                       reg = <0x0 0x91b80000 0x0 0x10000>;
+                       no-map;
+               };
+
+               ddr_training_data_mem: ddr-training-data@91b90000 {
+                       reg = <0x0 0x91b90000 0x0 0x10000>;
+                       no-map;
+               };
+
+               cdt_data_backup_mem: cdt-data-backup@91ba0000 {
+                       reg = <0x0 0x91ba0000 0x0 0x1000>;
                        no-map;
                };
 
                        no-map;
                };
 
+               audio_mdf_mem: audio-mdf-region@ae000000 {
+                       reg = <0x0 0xae000000 0x0 0x1000000>;
+                       no-map;
+               };
+
+               firmware_mem: firmware-region@b0000000 {
+                       reg = <0x0 0xb0000000 0x0 0x800000>;
+                       no-map;
+               };
+
                hyptz_reserved_mem: hyptz-reserved@beb00000 {
                        reg = <0x0 0xbeb00000 0x0 0x11500000>;
                        no-map;
                };
 
-               tz_stat_mem: tz-stat@d0000000 {
-                       reg = <0x0 0xd0000000 0x0 0x100000>;
+               scmi_mem: scmi-region@d0000000 {
+                       reg = <0x0 0xd0000000 0x0 0x40000>;
+                       no-map;
+               };
+
+               firmware_logs_mem: firmware-logs@d0040000 {
+                       reg = <0x0 0xd0040000 0x0 0x10000>;
+                       no-map;
+               };
+
+               firmware_audio_mem: firmware-audio@d0050000 {
+                       reg = <0x0 0xd0050000 0x0 0x4000>;
+                       no-map;
+               };
+
+               firmware_reserved_mem: firmware-reserved@d0054000 {
+                       reg = <0x0 0xd0054000 0x0 0x9c000>;
+                       no-map;
+               };
+
+               firmware_quantum_test_mem: firmware-quantum-test@d00f0000 {
+                       reg = <0x0 0xd00f0000 0x0 0x10000>;
                        no-map;
                };
 
                        no-map;
                };
 
-               trusted_apps_mem: trusted-apps@d1800000 {
-                       reg = <0x0 0xd1800000 0x0 0x3900000>;
+               deepsleep_backup_mem: deepsleep-backup@d1800000 {
+                       reg = <0x0 0xd1800000 0x0 0x100000>;
+                       no-map;
+               };
+
+               trusted_apps_mem: trusted-apps@d1900000 {
+                       reg = <0x0 0xd1900000 0x0 0x3800000>;
+                       no-map;
+               };
+
+               tz_stat_mem: tz-stat@db100000 {
+                       reg = <0x0 0xdb100000 0x0 0x100000>;
+                       no-map;
+               };
+
+               cpucp_fw_mem: cpucp-fw@db200000 {
+                       reg = <0x0 0xdb200000 0x0 0x100000>;
                        no-map;
                };
        };
                        assigned-clock-rates = <19200000>, <200000000>;
 
                        interrupts-extended = <&intc GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>,
                                              <&pdc 14 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 15 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 12 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
                                          "dp_hs_phy_irq",
                                          "dm_hs_phy_irq",
                                          "ss_phy_irq";
                        assigned-clock-rates = <19200000>, <200000000>;
 
                        interrupts-extended = <&intc GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH>,
                                              <&pdc 8 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 7 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 13 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
                                          "dp_hs_phy_irq",
                                          "dm_hs_phy_irq",
                                          "ss_phy_irq";
                        assigned-clock-rates = <19200000>, <200000000>;
 
                        interrupts-extended = <&intc GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 443 IRQ_TYPE_LEVEL_HIGH>,
                                              <&pdc 10 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 9 IRQ_TYPE_EDGE_BOTH>;
                        interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
                                          "dp_hs_phy_irq",
                                          "dm_hs_phy_irq";
 
                              <0x0 0x23016000 0x0 0x100>;
                        reg-names = "stmmaceth", "rgmii";
 
-                       interrupts = <GIC_SPI 929 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "macirq";
+                       interrupts = <GIC_SPI 929 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 781 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "macirq", "sfty";
 
                        clocks = <&gcc GCC_EMAC1_AXI_CLK>,
                                 <&gcc GCC_EMAC1_SLV_AHB_CLK>,
                              <0x0 0x23056000 0x0 0x100>;
                        reg-names = "stmmaceth", "rgmii";
 
-                       interrupts = <GIC_SPI 946 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "macirq";
+                       interrupts = <GIC_SPI 946 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 782 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "macirq", "sfty";
 
                        clocks = <&gcc GCC_EMAC0_AXI_CLK>,
                                 <&gcc GCC_EMAC0_SLV_AHB_CLK>,
index 46aaeba286047a074fe79db418254a2e382591f3..f3a6da8b28901907d0fbc533b2d63c498ecb5afc 100644 (file)
@@ -649,6 +649,7 @@ ap_ec_spi: &spi6 {
                pinctrl-names = "default";
                pinctrl-0 = <&ap_ec_int_l>;
                spi-max-frequency = <3000000>;
+               wakeup-source;
 
                cros_ec_pwm: pwm {
                        compatible = "google,cros-ec-pwm";
index 4dcaa15caef263d9917ca62b01c1b0b82bf547ab..2b481e20ae38f74000f8bbf7dd2a26f103465f0b 100644 (file)
                                bits = <1 3>;
                        };
 
-                       gpu_speed_bin: gpu_speed_bin@1d2 {
+                       gpu_speed_bin: gpu-speed-bin@1d2 {
                                reg = <0x1d2 0x2>;
                                bits = <5 8>;
                        };
                        qcom,bcm-voters = <&apps_bcm_voter>;
                };
 
+               ufs_mem_hc: ufshc@1d84000 {
+                       compatible = "qcom,sc7180-ufshc", "qcom,ufshc",
+                                    "jedec,ufs-2.0";
+                       reg = <0 0x01d84000 0 0x3000>;
+                       interrupts = <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>;
+                       phys = <&ufs_mem_phy>;
+                       phy-names = "ufsphy";
+                       lanes-per-direction = <1>;
+                       #reset-cells = <1>;
+                       resets = <&gcc GCC_UFS_PHY_BCR>;
+                       reset-names = "rst";
+
+                       power-domains = <&gcc UFS_PHY_GDSC>;
+
+                       iommus = <&apps_smmu 0xa0 0x0>;
+
+                       clock-names = "core_clk",
+                                     "bus_aggr_clk",
+                                     "iface_clk",
+                                     "core_clk_unipro",
+                                     "ref_clk",
+                                     "tx_lane0_sync_clk",
+                                     "rx_lane0_sync_clk";
+                       clocks = <&gcc GCC_UFS_PHY_AXI_CLK>,
+                                <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>,
+                                <&gcc GCC_UFS_PHY_AHB_CLK>,
+                                <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>,
+                                <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>;
+                       freq-table-hz = <50000000 200000000>,
+                                       <0 0>,
+                                       <0 0>,
+                                       <37500000 150000000>,
+                                       <0 0>,
+                                       <0 0>,
+                                       <0 0>;
+
+                       interconnects = <&aggre1_noc MASTER_UFS_MEM QCOM_ICC_TAG_ALWAYS
+                                        &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+                                       <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
+                                        &config_noc SLAVE_UFS_MEM_CFG QCOM_ICC_TAG_ALWAYS>;
+                       interconnect-names = "ufs-ddr", "cpu-ufs";
+
+                       qcom,ice = <&ice>;
+
+                       status = "disabled";
+               };
+
+               ufs_mem_phy: phy@1d87000 {
+                       compatible = "qcom,sc7180-qmp-ufs-phy",
+                                    "qcom,sm7150-qmp-ufs-phy";
+                       reg = <0 0x01d87000 0 0x1000>;
+                       clocks = <&gcc GCC_UFS_MEM_CLKREF_CLK>,
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+                       clock-names = "ref", "ref_aux";
+                       power-domains = <&gcc UFS_PHY_GDSC>;
+                       resets = <&ufs_mem_hc 0>;
+                       reset-names = "ufsphy";
+                       #phy-cells = <0>;
+                       status = "disabled";
+               };
+
+               ice: crypto@1d90000 {
+                       compatible = "qcom,sc7180-inline-crypto-engine",
+                                    "qcom,inline-crypto-engine";
+                       reg = <0 0x01d90000 0 0x8000>;
+                       clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>;
+               };
+
                ipa: ipa@1e40000 {
                        compatible = "qcom,sc7180-ipa";
 
                                          <&gcc GCC_USB30_PRIM_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <150000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 6 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 9 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 8 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 9 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq",
-                                         "dm_hs_phy_irq", "dp_hs_phy_irq";
+                                             <&pdc 6 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
                        required-opps = <&rpmhpd_opp_nom>;
index c4d00a81da394e54650ae87adb136545cdd38cdf..cecb3e89f7f7b24a4ce2a00419bb808a4afca44d 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 /delete-node/ &cdsp_mem;
+/delete-node/ &domain_idle_states;
 /delete-node/ &gpu_zap_mem;
 /delete-node/ &gpu_zap_shader;
 /delete-node/ &hyp_mem;
 /delete-node/ &sec_apps_mem;
 
 / {
+       cpus {
+               domain_idle_states: domain-idle-states {
+                       CLUSTER_SLEEP_0: cluster-sleep-0 {
+                               compatible = "domain-idle-state";
+                               arm,psci-suspend-param = <0x40003444>;
+                               entry-latency-us = <2752>;
+                               exit-latency-us = <6562>;
+                               min-residency-us = <9926>;
+                       };
+               };
+       };
+
        reserved-memory {
                camera_mem: memory@8ad00000 {
                        reg = <0x0 0x8ad00000 0x0 0x500000>;
        };
 };
 
+&CLUSTER_PD {
+       domain-idle-states = <&CLUSTER_SLEEP_0>;
+};
+
 &lpass_aon {
        status = "okay";
 };
        dma-coherent;
 };
 
+&venus {
+       iommus = <&apps_smmu 0x2180 0x20>,
+                <&apps_smmu 0x2184 0x20>;
+
+       status = "okay";
+
+       video-firmware {
+               iommus = <&apps_smmu 0x21a2 0x0>;
+       };
+};
+
 &watchdog {
        status = "okay";
 };
index 9ea6636125ad9026dd5e8be174989a32fbb3796d..2ba4ea60cb14736c9cfbf9f4a9048f20a4c921f2 100644 (file)
@@ -548,6 +548,7 @@ ap_ec_spi: &spi10 {
                pinctrl-names = "default";
                pinctrl-0 = <&ap_ec_int_l>;
                spi-max-frequency = <3000000>;
+               wakeup-source;
 
                cros_ec_pwm: pwm {
                        compatible = "google,cros-ec-pwm";
index ebae545c587c44d9a7cf213eab5cdc4d8570c5e5..fbfac7534d3c6775e559f07a2c6b2f09bffde271 100644 (file)
@@ -19,6 +19,7 @@ ap_ec_spi: &spi10 {
                pinctrl-names = "default";
                pinctrl-0 = <&ap_ec_int_l>;
                spi-max-frequency = <3000000>;
+               wakeup-source;
 
                cros_ec_pwm: pwm {
                        compatible = "google,cros-ec-pwm";
index 83b5b76ba17940e4582a680b039cdb8c17acc19e..7e7f0f0fb41ba03fe39095c7d1b5e2e24ac3136d 100644 (file)
                        power-domain-names = "psci";
                        next-level-cache = <&L2_0>;
                        operating-points-v2 = <&cpu0_opp_table>;
+                       capacity-dmips-mhz = <1024>;
+                       dynamic-power-coefficient = <100>;
                        interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
                                        <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        power-domain-names = "psci";
                        next-level-cache = <&L2_100>;
                        operating-points-v2 = <&cpu0_opp_table>;
+                       capacity-dmips-mhz = <1024>;
+                       dynamic-power-coefficient = <100>;
                        interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
                                        <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        power-domain-names = "psci";
                        next-level-cache = <&L2_200>;
                        operating-points-v2 = <&cpu0_opp_table>;
+                       capacity-dmips-mhz = <1024>;
+                       dynamic-power-coefficient = <100>;
                        interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
                                        <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        power-domain-names = "psci";
                        next-level-cache = <&L2_300>;
                        operating-points-v2 = <&cpu0_opp_table>;
+                       capacity-dmips-mhz = <1024>;
+                       dynamic-power-coefficient = <100>;
                        interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
                                        <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        power-domain-names = "psci";
                        next-level-cache = <&L2_400>;
                        operating-points-v2 = <&cpu4_opp_table>;
+                       capacity-dmips-mhz = <1946>;
+                       dynamic-power-coefficient = <520>;
                        interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
                                        <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        power-domain-names = "psci";
                        next-level-cache = <&L2_500>;
                        operating-points-v2 = <&cpu4_opp_table>;
+                       capacity-dmips-mhz = <1946>;
+                       dynamic-power-coefficient = <520>;
                        interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
                                        <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        power-domain-names = "psci";
                        next-level-cache = <&L2_600>;
                        operating-points-v2 = <&cpu4_opp_table>;
+                       capacity-dmips-mhz = <1946>;
+                       dynamic-power-coefficient = <520>;
                        interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
                                        <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        power-domain-names = "psci";
                        next-level-cache = <&L2_700>;
                        operating-points-v2 = <&cpu7_opp_table>;
+                       capacity-dmips-mhz = <1985>;
+                       dynamic-power-coefficient = <552>;
                        interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>,
                                        <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>;
                        qcom,freq-domain = <&cpufreq_hw 2>;
                        };
                };
 
-               domain-idle-states {
-                       CLUSTER_SLEEP_0: cluster-sleep-0 {
+               domain_idle_states: domain-idle-states {
+                       CLUSTER_SLEEP_APSS_OFF: cluster-sleep-0 {
                                compatible = "domain-idle-state";
-                               idle-state-name = "cluster-power-down";
-                               arm,psci-suspend-param = <0x40003444>;
+                               arm,psci-suspend-param = <0x41000044>;
+                               entry-latency-us = <2752>;
+                               exit-latency-us = <3048>;
+                               min-residency-us = <6118>;
+                       };
+
+                       CLUSTER_SLEEP_CX_RET: cluster-sleep-1 {
+                               compatible = "domain-idle-state";
+                               arm,psci-suspend-param = <0x41001344>;
                                entry-latency-us = <3263>;
+                               exit-latency-us = <4562>;
+                               min-residency-us = <8467>;
+                       };
+
+                       CLUSTER_SLEEP_LLCC_OFF: cluster-sleep-2 {
+                               compatible = "domain-idle-state";
+                               arm,psci-suspend-param = <0x4100b344>;
+                               entry-latency-us = <3638>;
                                exit-latency-us = <6562>;
-                               min-residency-us = <9926>;
-                               local-timer-stop;
+                               min-residency-us = <9826>;
                        };
                };
        };
 
                CLUSTER_PD: power-domain-cluster {
                        #power-domain-cells = <0>;
-                       domain-idle-states = <&CLUSTER_SLEEP_0>;
+                       domain-idle-states = <&CLUSTER_SLEEP_APSS_OFF &CLUSTER_SLEEP_CX_RET &CLUSTER_SLEEP_LLCC_OFF>;
                };
        };
 
                        #address-cells = <1>;
                        #size-cells = <1>;
 
-                       gpu_speed_bin: gpu_speed_bin@1e9 {
+                       gpu_speed_bin: gpu-speed-bin@1e9 {
                                reg = <0x1e9 0x2>;
                                bits = <5 8>;
                        };
                        ranges = <0x01000000 0x0 0x00000000 0x0 0x40200000 0x0 0x100000>,
                                 <0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1fd00000>;
 
-                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0", "msi1", "msi2", "msi3",
+                                         "msi4", "msi5", "msi6", "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 0 0 434 IRQ_TYPE_LEVEL_HIGH>,
                                 <&apps_smmu 0x4e6 0x0011>;
                        qcom,ee = <0>;
                        qcom,controlled-remotely;
+                       num-channels = <16>;
+                       qcom,num-ees = <4>;
                };
 
                crypto: crypto@1dfa000 {
                        status = "disabled";
                };
 
+               slimbam: dma-controller@3a84000 {
+                       compatible = "qcom,bam-v1.7.0";
+                       reg = <0 0x03a84000 0 0x20000>;
+                       interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+                       #dma-cells = <1>;
+                       qcom,controlled-remotely;
+                       num-channels  = <31>;
+                       qcom,ee = <1>;
+                       qcom,num-ees = <2>;
+                       iommus = <&apps_smmu 0x1826 0x0>;
+                       status = "disabled";
+               };
+
+               slim: slim-ngd@3ac0000 {
+                       compatible = "qcom,slim-ngd-v1.5.0";
+                       reg = <0 0x03ac0000 0 0x2c000>;
+                       interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+                       dmas = <&slimbam 3>, <&slimbam 4>;
+                       dma-names = "rx", "tx";
+                       iommus = <&apps_smmu 0x1826 0x0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
                lpass_hm: clock-controller@3c00000 {
                        compatible = "qcom,sc7280-lpasshm";
                        reg = <0 0x03c00000 0 0x28>;
                                          <&gcc GCC_USB30_SEC_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <200000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>,
                                              <&pdc 12 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 13 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq",
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
                                          "dp_hs_phy_irq",
                                          "dm_hs_phy_irq";
 
                                          <&gcc GCC_USB30_PRIM_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <200000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                              <&pdc 14 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 15 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq",
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
                                          "dp_hs_phy_irq",
                                          "dm_hs_phy_irq",
                                          "ss_phy_irq";
                                phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>;
                                phy-names = "usb2-phy", "usb3-phy";
                                maximum-speed = "super-speed";
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+
+                                               usb_1_dwc3_hs: endpoint {
+                                               };
+                                       };
+
+                                       port@1 {
+                                               reg = <1>;
+
+                                               usb_1_dwc3_ss: endpoint {
+                                               };
+                                       };
+                               };
                        };
                };
 
                                        <&mmss_noc MASTER_VIDEO_P0 0 &mc_virt SLAVE_EBI1 0>;
                        interconnect-names = "cpu-cfg", "video-mem";
 
-                       iommus = <&apps_smmu 0x2180 0x20>,
-                                <&apps_smmu 0x2184 0x20>;
+                       iommus = <&apps_smmu 0x2180 0x20>;
                        memory-region = <&video_mem>;
 
+                       status = "disabled";
+
                        video-decoder {
                                compatible = "venus-decoder";
                        };
                                compatible = "venus-encoder";
                        };
 
-                       video-firmware {
-                               iommus = <&apps_smmu 0x21a2 0x0>;
-                       };
-
                        venus_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
index 0430d99091e30ac48a9feef53856ad7fdb0b6ff9..32afc78d5b769d56d6f316b2bbd34343a2497b56 100644 (file)
                        BIG_CPU_SLEEP_0: cpu-sleep-1-0 {
                                compatible = "arm,idle-state";
                                arm,psci-suspend-param = <0x40000004>;
-                               entry-latency-us = <241>;
+                               entry-latency-us = <2411>;
                                exit-latency-us = <1461>;
                                min-residency-us = <4488>;
                                local-timer-stop;
                };
 
                domain-idle-states {
-                       CLUSTER_SLEEP_0: cluster-sleep-0 {
+                       CLUSTER_SLEEP_APSS_OFF: cluster-sleep-0 {
+                               compatible = "domain-idle-state";
+                               arm,psci-suspend-param = <0x41000044>;
+                               entry-latency-us = <3300>;
+                               exit-latency-us = <3300>;
+                               min-residency-us = <6000>;
+                       };
+
+                       CLUSTER_SLEEP_AOSS_SLEEP: cluster-sleep-1 {
                                compatible = "domain-idle-state";
                                arm,psci-suspend-param = <0x4100a344>;
                                entry-latency-us = <3263>;
 
                CLUSTER_PD: power-domain-cpu-cluster0 {
                        #power-domain-cells = <0>;
-                       domain-idle-states = <&CLUSTER_SLEEP_0>;
+                       domain-idle-states = <&CLUSTER_SLEEP_APSS_OFF &CLUSTER_SLEEP_AOSS_SLEEP>;
                };
        };
 
                        clock-names = "bi_tcxo",
                                      "bi_tcxo_ao",
                                      "sleep_clk";
+                       power-domains = <&rpmhpd SC8180X_CX>;
                };
 
                qupv3_id_0: geniqup@8c0000 {
                        ranges = <0x01000000 0x0 0x60200000 0x0 0x60200000 0x0 0x100000>,
                                 <0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x3d00000>;
 
-                       interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                        ranges = <0x01000000 0x0 0x40200000 0x0 0x40200000 0x0 0x100000>,
                                 <0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1fd00000>;
 
-                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 434 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                        ranges = <0x01000000 0x0 0x68200000 0x0 0x68200000 0x0 0x100000>,
                                 <0x02000000 0x0 0x68300000 0x0 0x68300000 0x0 0x3d00000>;
 
-                       interrupts = <GIC_SPI 755 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 756 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 755 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 754 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 753 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 752 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 751 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 750 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 749 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 747 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                        ranges = <0x01000000 0x0 0x70200000 0x0 0x70200000 0x0 0x100000>,
                                 <0x02000000 0x0 0x70300000 0x0 0x70300000 0x0 0x3d00000>;
 
-                       interrupts = <GIC_SPI 671 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 672 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 671 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 670 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 669 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 668 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 667 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 666 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 665 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 663 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                        reg = <0 0x01d87000 0 0x1000>;
 
                        clocks = <&rpmhcc RPMH_CXO_CLK>,
-                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>,
+                                <&gcc GCC_UFS_MEM_CLKREF_EN>;
                        clock-names = "ref",
-                                     "ref_aux";
+                                     "ref_aux",
+                                     "qref";
 
                        resets = <&ufs_mem_hc 0>;
                        reset-names = "ufsphy";
                        interconnect-names = "gfx-mem";
 
                        qcom,gmu = <&gmu>;
+                       #cooling-cells = <2>;
+
                        status = "disabled";
 
                        gpu_opp_table: opp-table {
                        interrupt-controller;
                        #interrupt-cells = <1>;
 
-                       interconnects = <&mmss_noc MASTER_MDP_PORT0 0 &mc_virt SLAVE_EBI_CH0 0>,
-                                       <&mmss_noc MASTER_MDP_PORT1 0 &mc_virt SLAVE_EBI_CH0 0>;
-                       interconnect-names = "mdp0-mem", "mdp1-mem";
+                       interconnects = <&mmss_noc MASTER_MDP_PORT0 QCOM_ICC_TAG_ALWAYS
+                                        &mc_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ALWAYS>,
+                                       <&mmss_noc MASTER_MDP_PORT1 QCOM_ICC_TAG_ALWAYS
+                                        &mc_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ALWAYS>,
+                                       <&gem_noc MASTER_AMPSS_M0 QCOM_ICC_TAG_ALWAYS
+                                        &config_noc SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ALWAYS>;
+                       interconnect-names = "mdp0-mem",
+                                            "mdp1-mem",
+                                            "cpu-cfg";
 
                        iommus = <&apps_smmu 0x800 0x420>;
 
                                              "rot",
                                              "lut";
 
-                               assigned-clocks = <&dispcc DISP_CC_MDSS_MDP_CLK>,
-                                                 <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
-                               assigned-clock-rates = <460000000>,
-                                                      <19200000>;
+                               assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+                               assigned-clock-rates = <19200000>;
 
                                operating-points-v2 = <&mdp_opp_table>;
                                power-domains = <&rpmhpd SC8180X_MMCX>;
                                 <&dispcc DISP_CC_MDSS_AHB_CLK>;
                        clock-names = "aux", "cfg_ahb";
 
-                       power-domains = <&dispcc MDSS_GDSC>;
+                       power-domains = <&rpmhpd SC8180X_MX>;
 
                        #clock-cells = <1>;
                        #phy-cells = <0>;
                                      "edp_phy_pll_link_clk",
                                      "edp_phy_pll_vco_div_clk";
                        power-domains = <&rpmhpd SC8180X_MMCX>;
+                       required-opps = <&rpmhpd_opp_low_svs>;
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                        #power-domain-cells = <1>;
 
                aoss_qmp: power-controller@c300000 {
                        compatible = "qcom,sc8180x-aoss-qmp", "qcom,aoss-qmp";
-                       reg = <0x0 0x0c300000 0x0 0x100000>;
+                       reg = <0x0 0x0c300000 0x0 0x400>;
                        interrupts = <GIC_SPI 389 IRQ_TYPE_EDGE_RISING>;
                        mboxes = <&apss_shared 0>;
 
                        #power-domain-cells = <1>;
                };
 
+               sram@c3f0000 {
+                       compatible = "qcom,rpmh-stats";
+                       reg = <0x0 0x0c3f0000 0x0 0x400>;
+               };
+
                spmi_bus: spmi@c440000 {
                        compatible = "qcom,spmi-pmic-arb";
                        reg = <0x0 0x0c440000 0x0 0x0001100>,
 
                        thermal-sensors = <&tsens0 15>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_top_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
-                               trip-point0 {
+                               gpu_top_alert0: trip-point0 {
                                        temperature = <90000>;
                                        hysteresis = <2000>;
                                        type = "hot";
 
                        thermal-sensors = <&tsens1 11>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_bottom_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
-                               trip-point0 {
+                               gpu_bottom_alert0: trip-point0 {
                                        temperature = <90000>;
                                        hysteresis = <2000>;
                                        type = "hot";
index ffc4406422ae2f82c9636e0fb521f34a1d28c1eb..41215567b3aed7d4211a8a4c5ab94042d205b422 100644 (file)
 };
 
 &pcie4 {
+       max-link-speed = <2>;
+
        perst-gpios = <&tlmm 141 GPIO_ACTIVE_LOW>;
        wake-gpios = <&tlmm 139 GPIO_ACTIVE_LOW>;
 
index def3976bd5bb154d27228831de14e9463239bdf8..15ae94c1602d59ba2b3aa5fd954fabca95b667f4 100644 (file)
@@ -6,10 +6,8 @@
 
 /dts-v1/;
 
-#include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/iio/qcom,spmi-adc7-pm8350.h>
-#include <dt-bindings/iio/qcom,spmi-adc7-pmk8350.h>
-#include <dt-bindings/iio/qcom,spmi-adc7-pmr735a.h>
+#include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/gpio-keys.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/leds/common.h>
 };
 
 &pcie4 {
+       max-link-speed = <2>;
+
        perst-gpios = <&tlmm 141 GPIO_ACTIVE_LOW>;
        wake-gpios = <&tlmm 139 GPIO_ACTIVE_LOW>;
 
 };
 
 &pmk8280_vadc {
-       status = "okay";
-
-       channel@3 {
-               reg = <PMK8350_ADC7_DIE_TEMP>;
-               qcom,pre-scaling = <1 1>;
-               label = "pmk8350_die_temp";
-       };
-
-       channel@44 {
-               reg = <PMK8350_ADC7_AMUX_THM1_100K_PU>;
-               qcom,hw-settle-time = <200>;
-               qcom,ratiometric;
-               label = "pmk8350_xo_therm";
-       };
-
-       channel@103 {
-               reg = <PM8350_ADC7_DIE_TEMP(1)>;
-               qcom,pre-scaling = <1 1>;
-               label = "pmc8280_1_die_temp";
-       };
-
        channel@144 {
                reg = <PM8350_ADC7_AMUX_THM1_100K_PU(1)>;
                qcom,hw-settle-time = <200>;
                label = "sys_therm4";
        };
 
-       channel@303 {
-               reg = <PM8350_ADC7_DIE_TEMP(3)>;
-               qcom,pre-scaling = <1 1>;
-               label = "pmc8280_2_die_temp";
-       };
-
        channel@344 {
                reg = <PM8350_ADC7_AMUX_THM1_100K_PU(3)>;
                qcom,hw-settle-time = <200>;
                qcom,ratiometric;
                label = "sys_therm8";
        };
-
-       channel@403 {
-               reg = <PMR735A_ADC7_DIE_TEMP>;
-               qcom,pre-scaling = <1 1>;
-               label = "pmr735a_die_temp";
-       };
 };
 
 &qup0 {
 };
 
 &vamacro {
-       pinctrl-0 = <&dmic01_default>, <&dmic02_default>;
+       pinctrl-0 = <&dmic01_default>, <&dmic23_default>;
        pinctrl-names = "default";
 
        vdd-micb-supply = <&vreg_s10b>;
index 80ee12ded4f42da1e511ba5f1f0339c1dbfda963..945de77911de1ce558c500a94de8f80b7ee05d20 100644 (file)
@@ -3,6 +3,9 @@
  * Copyright (c) 2022, Linaro Limited
  */
 
+#include <dt-bindings/iio/qcom,spmi-adc7-pm8350.h>
+#include <dt-bindings/iio/qcom,spmi-adc7-pmk8350.h>
+#include <dt-bindings/iio/qcom,spmi-adc7-pmr735a.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/spmi/spmi.h>
                        #address-cells = <1>;
                        #size-cells = <0>;
                        #io-channel-cells = <1>;
-                       status = "disabled";
+
+                       channel@3 {
+                               reg = <PMK8350_ADC7_DIE_TEMP>;
+                               qcom,pre-scaling = <1 1>;
+                               label = "pmk8350_die_temp";
+                       };
+
+                       channel@44 {
+                               reg = <PMK8350_ADC7_AMUX_THM1_100K_PU>;
+                               qcom,hw-settle-time = <200>;
+                               qcom,ratiometric;
+                               label = "pmk8350_xo_therm";
+                       };
+
+                       channel@103 {
+                               reg = <PM8350_ADC7_DIE_TEMP(1)>;
+                               qcom,pre-scaling = <1 1>;
+                               label = "pmc8280_1_die_temp";
+                       };
+
+                       channel@303 {
+                               reg = <PM8350_ADC7_DIE_TEMP(3)>;
+                               qcom,pre-scaling = <1 1>;
+                               label = "pmc8280_2_die_temp";
+                       };
+
+                       channel@403 {
+                               reg = <PMR735A_ADC7_DIE_TEMP>;
+                               qcom,pre-scaling = <1 1>;
+                               label = "pmr735a_die_temp";
+                       };
                };
 
                pmk8280_adc_tm: adc-tm@3400 {
                        compatible = "qcom,spmi-temp-alarm";
                        reg = <0xa00>;
                        interrupts-extended = <&spmi_bus 0x1 0xa 0x0 IRQ_TYPE_EDGE_BOTH>;
+                       io-channels = <&pmk8280_vadc PM8350_ADC7_DIE_TEMP(1)>;
+                       io-channel-names = "thermal";
                        #thermal-sensor-cells = <0>;
                };
 
                        compatible = "qcom,spmi-temp-alarm";
                        reg = <0xa00>;
                        interrupts-extended = <&spmi_bus 0x2 0xa 0x0 IRQ_TYPE_EDGE_BOTH>;
+                       io-channels = <&pmk8280_vadc PM8350_ADC7_DIE_TEMP(3)>;
+                       io-channel-names = "thermal";
                        #thermal-sensor-cells = <0>;
                };
 
index febf28356ff8b0a4a52de16ceda2ab1bdb1eca4d..a5b194813079e9779e7913a4054a413af3a14750 100644 (file)
                        compatible = "qcom,sc8280xp-qmp-ufs-phy";
                        reg = <0 0x01d87000 0 0x1000>;
 
-                       clocks = <&gcc GCC_UFS_CARD_CLKREF_CLK>,
-                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
-                       clock-names = "ref", "ref_aux";
+                       clocks = <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>,
+                                <&gcc GCC_UFS_CARD_CLKREF_CLK>;
+                       clock-names = "ref",
+                                     "ref_aux",
+                                     "qref";
 
                        power-domains = <&gcc UFS_PHY_GDSC>;
 
                        compatible = "qcom,sc8280xp-qmp-ufs-phy";
                        reg = <0 0x01da7000 0 0x1000>;
 
-                       clocks = <&gcc GCC_UFS_1_CARD_CLKREF_CLK>,
-                                <&gcc GCC_UFS_CARD_PHY_AUX_CLK>;
-                       clock-names = "ref", "ref_aux";
+                       clocks = <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_UFS_CARD_PHY_AUX_CLK>,
+                                <&gcc GCC_UFS_1_CARD_CLKREF_CLK>;
+                       clock-names = "ref",
+                                     "ref_aux",
+                                     "qref";
 
                        power-domains = <&gcc UFS_CARD_GDSC>;
 
                                };
                        };
 
-                       dmic02_default: dmic02-default-state {
+                       dmic23_default: dmic23-default-state {
                                clk-pins {
                                        pins = "gpio8";
                                        function = "dmic2_clk";
                                };
                        };
 
-                       dmic02_sleep: dmic02-sleep-state {
+                       dmic23_sleep: dmic23-sleep-state {
                                clk-pins {
                                        pins = "gpio8";
                                        function = "dmic2_clk";
                        };
                };
 
+               cci0: cci@ac4a000 {
+                       compatible = "qcom,sc8280xp-cci", "qcom,msm8996-cci";
+                       reg = <0 0x0ac4a000 0 0x1000>;
+
+                       interrupts = <GIC_SPI 460 IRQ_TYPE_EDGE_RISING>;
+
+                       clocks = <&camcc CAMCC_CAMNOC_AXI_CLK>,
+                                <&camcc CAMCC_SLOW_AHB_CLK_SRC>,
+                                <&camcc CAMCC_CPAS_AHB_CLK>,
+                                <&camcc CAMCC_CCI_0_CLK>;
+                       clock-names = "camnoc_axi",
+                                     "slow_ahb_src",
+                                     "cpas_ahb",
+                                     "cci";
+
+                       power-domains = <&camcc TITAN_TOP_GDSC>;
+
+                       pinctrl-0 = <&cci0_default>;
+                       pinctrl-1 = <&cci0_sleep>;
+                       pinctrl-names = "default", "sleep";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       status = "disabled";
+
+                       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@ac4b000 {
+                       compatible = "qcom,sc8280xp-cci", "qcom,msm8996-cci";
+                       reg = <0 0x0ac4b000 0 0x1000>;
+
+                       interrupts = <GIC_SPI 271 IRQ_TYPE_EDGE_RISING>;
+
+                       clocks = <&camcc CAMCC_CAMNOC_AXI_CLK>,
+                                <&camcc CAMCC_SLOW_AHB_CLK_SRC>,
+                                <&camcc CAMCC_CPAS_AHB_CLK>,
+                                <&camcc CAMCC_CCI_1_CLK>;
+                       clock-names = "camnoc_axi",
+                                     "slow_ahb_src",
+                                     "cpas_ahb",
+                                     "cci";
+
+                       power-domains = <&camcc TITAN_TOP_GDSC>;
+
+                       pinctrl-0 = <&cci1_default>;
+                       pinctrl-1 = <&cci1_sleep>;
+                       pinctrl-names = "default", "sleep";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       status = "disabled";
+
+                       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@ac4c000 {
+                       compatible = "qcom,sc8280xp-cci", "qcom,msm8996-cci";
+                       reg = <0 0x0ac4c000 0 0x1000>;
+
+                       interrupts = <GIC_SPI 651 IRQ_TYPE_EDGE_RISING>;
+
+                       clocks = <&camcc CAMCC_CAMNOC_AXI_CLK>,
+                                <&camcc CAMCC_SLOW_AHB_CLK_SRC>,
+                                <&camcc CAMCC_CPAS_AHB_CLK>,
+                                <&camcc CAMCC_CCI_2_CLK>;
+                       clock-names = "camnoc_axi",
+                                     "slow_ahb_src",
+                                     "cpas_ahb",
+                                     "cci";
+                       power-domains = <&camcc TITAN_TOP_GDSC>;
+
+                       pinctrl-0 = <&cci2_default>;
+                       pinctrl-1 = <&cci2_sleep>;
+                       pinctrl-names = "default", "sleep";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       status = "disabled";
+
+                       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>;
+                       };
+               };
+
+               cci3: cci@ac4d000 {
+                       compatible = "qcom,sc8280xp-cci", "qcom,msm8996-cci";
+                       reg = <0 0x0ac4d000 0 0x1000>;
+
+                       interrupts = <GIC_SPI 650 IRQ_TYPE_EDGE_RISING>;
+
+                       clocks = <&camcc CAMCC_CAMNOC_AXI_CLK>,
+                                <&camcc CAMCC_SLOW_AHB_CLK_SRC>,
+                                <&camcc CAMCC_CPAS_AHB_CLK>,
+                                <&camcc CAMCC_CCI_3_CLK>;
+                       clock-names = "camnoc_axi",
+                                     "slow_ahb_src",
+                                     "cpas_ahb",
+                                     "cci";
+
+                       power-domains = <&camcc TITAN_TOP_GDSC>;
+
+                       pinctrl-0 = <&cci3_default>;
+                       pinctrl-1 = <&cci3_sleep>;
+                       pinctrl-names = "default", "sleep";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       status = "disabled";
+
+                       cci3_i2c0: i2c-bus@0 {
+                               reg = <0>;
+                               clock-frequency = <1000000>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       cci3_i2c1: i2c-bus@1 {
+                               reg = <1>;
+                               clock-frequency = <1000000>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+               };
+
+               camss: camss@ac5a000 {
+                       compatible = "qcom,sc8280xp-camss";
+
+                       reg = <0 0x0ac5a000 0 0x2000>,
+                             <0 0x0ac5c000 0 0x2000>,
+                             <0 0x0ac65000 0 0x2000>,
+                             <0 0x0ac67000 0 0x2000>,
+                             <0 0x0acaf000 0 0x4000>,
+                             <0 0x0acb3000 0 0x1000>,
+                             <0 0x0acb6000 0 0x4000>,
+                             <0 0x0acba000 0 0x1000>,
+                             <0 0x0acbd000 0 0x4000>,
+                             <0 0x0acc1000 0 0x1000>,
+                             <0 0x0acc4000 0 0x4000>,
+                             <0 0x0acc8000 0 0x1000>,
+                             <0 0x0accb000 0 0x4000>,
+                             <0 0x0accf000 0 0x1000>,
+                             <0 0x0acd2000 0 0x4000>,
+                             <0 0x0acd6000 0 0x1000>,
+                             <0 0x0acd9000 0 0x4000>,
+                             <0 0x0acdd000 0 0x1000>,
+                             <0 0x0ace0000 0 0x4000>,
+                             <0 0x0ace4000 0 0x1000>;
+                       reg-names = "csiphy2",
+                                   "csiphy3",
+                                   "csiphy0",
+                                   "csiphy1",
+                                   "vfe0",
+                                   "csid0",
+                                   "vfe1",
+                                   "csid1",
+                                   "vfe2",
+                                   "csid2",
+                                   "vfe_lite0",
+                                   "csid0_lite",
+                                   "vfe_lite1",
+                                   "csid1_lite",
+                                   "vfe_lite2",
+                                   "csid2_lite",
+                                   "vfe_lite3",
+                                   "csid3_lite",
+                                   "vfe3",
+                                   "csid3";
+
+                       interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 464 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 478 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 479 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 640 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 641 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 758 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 759 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 760 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 761 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 762 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 764 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "csid1_lite",
+                                         "vfe_lite1",
+                                         "csiphy3",
+                                         "csid0",
+                                         "vfe0",
+                                         "csid1",
+                                         "vfe1",
+                                         "csid0_lite",
+                                         "vfe_lite0",
+                                         "csiphy0",
+                                         "csiphy1",
+                                         "csiphy2",
+                                         "csid2",
+                                         "vfe2",
+                                         "csid3_lite",
+                                         "csid2_lite",
+                                         "vfe_lite3",
+                                         "vfe_lite2",
+                                         "csid3",
+                                         "vfe3";
+
+                       power-domains = <&camcc IFE_0_GDSC>,
+                                       <&camcc IFE_1_GDSC>,
+                                       <&camcc IFE_2_GDSC>,
+                                       <&camcc IFE_3_GDSC>,
+                                       <&camcc TITAN_TOP_GDSC>;
+                       power-domain-names = "ife0",
+                                            "ife1",
+                                            "ife2",
+                                            "ife3",
+                                            "top";
+
+                       clocks = <&camcc CAMCC_CAMNOC_AXI_CLK>,
+                                <&camcc CAMCC_CPAS_AHB_CLK>,
+                                <&camcc CAMCC_CSIPHY0_CLK>,
+                                <&camcc CAMCC_CSI0PHYTIMER_CLK>,
+                                <&camcc CAMCC_CSIPHY1_CLK>,
+                                <&camcc CAMCC_CSI1PHYTIMER_CLK>,
+                                <&camcc CAMCC_CSIPHY2_CLK>,
+                                <&camcc CAMCC_CSI2PHYTIMER_CLK>,
+                                <&camcc CAMCC_CSIPHY3_CLK>,
+                                <&camcc CAMCC_CSI3PHYTIMER_CLK>,
+                                <&camcc CAMCC_IFE_0_AXI_CLK>,
+                                <&camcc CAMCC_IFE_0_CLK>,
+                                <&camcc CAMCC_IFE_0_CPHY_RX_CLK>,
+                                <&camcc CAMCC_IFE_0_CSID_CLK>,
+                                <&camcc CAMCC_IFE_1_AXI_CLK>,
+                                <&camcc CAMCC_IFE_1_CLK>,
+                                <&camcc CAMCC_IFE_1_CPHY_RX_CLK>,
+                                <&camcc CAMCC_IFE_1_CSID_CLK>,
+                                <&camcc CAMCC_IFE_2_AXI_CLK>,
+                                <&camcc CAMCC_IFE_2_CLK>,
+                                <&camcc CAMCC_IFE_2_CPHY_RX_CLK>,
+                                <&camcc CAMCC_IFE_2_CSID_CLK>,
+                                <&camcc CAMCC_IFE_3_AXI_CLK>,
+                                <&camcc CAMCC_IFE_3_CLK>,
+                                <&camcc CAMCC_IFE_3_CPHY_RX_CLK>,
+                                <&camcc CAMCC_IFE_3_CSID_CLK>,
+                                <&camcc CAMCC_IFE_LITE_0_CLK>,
+                                <&camcc CAMCC_IFE_LITE_0_CPHY_RX_CLK>,
+                                <&camcc CAMCC_IFE_LITE_0_CSID_CLK>,
+                                <&camcc CAMCC_IFE_LITE_1_CLK>,
+                                <&camcc CAMCC_IFE_LITE_1_CPHY_RX_CLK>,
+                                <&camcc CAMCC_IFE_LITE_1_CSID_CLK>,
+                                <&camcc CAMCC_IFE_LITE_2_CLK>,
+                                <&camcc CAMCC_IFE_LITE_2_CPHY_RX_CLK>,
+                                <&camcc CAMCC_IFE_LITE_2_CSID_CLK>,
+                                <&camcc CAMCC_IFE_LITE_3_CLK>,
+                                <&camcc CAMCC_IFE_LITE_3_CPHY_RX_CLK>,
+                                <&camcc CAMCC_IFE_LITE_3_CSID_CLK>,
+                                <&gcc GCC_CAMERA_HF_AXI_CLK>,
+                                <&gcc GCC_CAMERA_SF_AXI_CLK>;
+                       clock-names = "camnoc_axi",
+                                     "cpas_ahb",
+                                     "csiphy0",
+                                     "csiphy0_timer",
+                                     "csiphy1",
+                                     "csiphy1_timer",
+                                     "csiphy2",
+                                     "csiphy2_timer",
+                                     "csiphy3",
+                                     "csiphy3_timer",
+                                     "vfe0_axi",
+                                     "vfe0",
+                                     "vfe0_cphy_rx",
+                                     "vfe0_csid",
+                                     "vfe1_axi",
+                                     "vfe1",
+                                     "vfe1_cphy_rx",
+                                     "vfe1_csid",
+                                     "vfe2_axi",
+                                     "vfe2",
+                                     "vfe2_cphy_rx",
+                                     "vfe2_csid",
+                                     "vfe3_axi",
+                                     "vfe3",
+                                     "vfe3_cphy_rx",
+                                     "vfe3_csid",
+                                     "vfe_lite0",
+                                     "vfe_lite0_cphy_rx",
+                                     "vfe_lite0_csid",
+                                     "vfe_lite1",
+                                     "vfe_lite1_cphy_rx",
+                                     "vfe_lite1_csid",
+                                     "vfe_lite2",
+                                     "vfe_lite2_cphy_rx",
+                                     "vfe_lite2_csid",
+                                     "vfe_lite3",
+                                     "vfe_lite3_cphy_rx",
+                                     "vfe_lite3_csid",
+                                     "gcc_axi_hf",
+                                     "gcc_axi_sf";
+
+                       iommus = <&apps_smmu 0x2000 0x4e0>,
+                                <&apps_smmu 0x2020 0x4e0>,
+                                <&apps_smmu 0x2040 0x4e0>,
+                                <&apps_smmu 0x2060 0x4e0>,
+                                <&apps_smmu 0x2080 0x4e0>,
+                                <&apps_smmu 0x20e0 0x4e0>,
+                                <&apps_smmu 0x20c0 0x4e0>,
+                                <&apps_smmu 0x20a0 0x4e0>,
+                                <&apps_smmu 0x2400 0x4e0>,
+                                <&apps_smmu 0x2420 0x4e0>,
+                                <&apps_smmu 0x2440 0x4e0>,
+                                <&apps_smmu 0x2460 0x4e0>,
+                                <&apps_smmu 0x2480 0x4e0>,
+                                <&apps_smmu 0x24e0 0x4e0>,
+                                <&apps_smmu 0x24c0 0x4e0>,
+                                <&apps_smmu 0x24a0 0x4e0>;
+
+                       interconnects = <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_CAMERA_CFG 0>,
+                                       <&mmss_noc MASTER_CAMNOC_HF 0 &mc_virt SLAVE_EBI1 0>,
+                                       <&mmss_noc MASTER_CAMNOC_SF 0 &mc_virt SLAVE_EBI1 0>,
+                                       <&mmss_noc MASTER_CAMNOC_ICP 0 &mc_virt SLAVE_EBI1 0>;
+                       interconnect-names = "cam_ahb",
+                                            "cam_hf_mnoc",
+                                            "cam_sf_mnoc",
+                                            "cam_sf_icp_mnoc";
+
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                               };
+
+                               port@2 {
+                                       reg = <2>;
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                               };
+
+                               port@3 {
+                                       reg = <3>;
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                               };
+                       };
+               };
+
                camcc: clock-controller@ad00000 {
                        compatible = "qcom,sc8280xp-camcc";
                        reg = <0 0x0ad00000 0 0x20000>;
                        interrupt-controller;
                };
 
+               tsens2: thermal-sensor@c251000 {
+                       compatible = "qcom,sc8280xp-tsens", "qcom,tsens-v2";
+                       reg = <0 0x0c251000 0 0x1ff>,
+                             <0 0x0c224000 0 0x8>;
+                       #qcom,sensors = <11>;
+                       interrupts-extended = <&pdc 122 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 124 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "uplow", "critical";
+                       #thermal-sensor-cells = <1>;
+               };
+
+               tsens3: thermal-sensor@c252000 {
+                       compatible = "qcom,sc8280xp-tsens", "qcom,tsens-v2";
+                       reg = <0 0x0c252000 0 0x1ff>,
+                             <0 0x0c225000 0 0x8>;
+                       #qcom,sensors = <5>;
+                       interrupts-extended = <&pdc 123 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 125 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "uplow", "critical";
+                       #thermal-sensor-cells = <1>;
+               };
+
                tsens0: thermal-sensor@c263000 {
                        compatible = "qcom,sc8280xp-tsens", "qcom,tsens-v2";
                        reg = <0 0x0c263000 0 0x1ff>, /* TM */
                        #interrupt-cells = <2>;
                        gpio-ranges = <&tlmm 0 0 230>;
                        wakeup-parent = <&pdc>;
+
+                       cci0_default: cci0-default-state {
+                               cci0_i2c0_default: cci0-i2c0-default-pins {
+                                       /* cci_i2c_sda0, cci_i2c_scl0 */
+                                       pins = "gpio113", "gpio114";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-up;
+                               };
+
+                               cci0_i2c1_default: cci0-i2c1-default-pins {
+                                       /* cci_i2c_sda1, cci_i2c_scl1 */
+                                       pins = "gpio115", "gpio116";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-up;
+                               };
+                       };
+
+                       cci0_sleep: cci0-sleep-state {
+                               cci0_i2c0_sleep: cci0-i2c0-sleep-pins {
+                                       /* cci_i2c_sda0, cci_i2c_scl0 */
+                                       pins = "gpio113", "gpio114";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-down;
+                               };
+
+                               cci0_i2c1_sleep: cci0-i2c1-sleep-pins {
+                                       /* cci_i2c_sda1, cci_i2c_scl1 */
+                                       pins = "gpio115", "gpio116";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-down;
+                               };
+                       };
+
+                       cci1_default: cci1-default-state {
+                               cci1_i2c0_default: cci1-i2c0-default-pins {
+                                       /* cci_i2c_sda2, cci_i2c_scl2 */
+                                       pins = "gpio10","gpio11";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-up;
+                               };
+
+                               cci1_i2c1_default: cci1-i2c1-default-pins {
+                                       /* cci_i2c_sda3, cci_i2c_scl3 */
+                                       pins = "gpio123","gpio124";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-up;
+                               };
+                       };
+
+                       cci1_sleep: cci1-sleep-state {
+                               cci1_i2c0_sleep: cci1-i2c0-sleep-pins {
+                                       /* cci_i2c_sda2, cci_i2c_scl2 */
+                                       pins = "gpio10","gpio11";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-down;
+                               };
+
+                               cci1_i2c1_sleep: cci1-i2c1-sleep-pins {
+                                       /* cci_i2c_sda3, cci_i2c_scl3 */
+                                       pins = "gpio123","gpio124";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-down;
+                               };
+                       };
+
+                       cci2_default: cci2-default-state {
+                               cci2_i2c0_default: cci2-i2c0-default-pins {
+                                       /* cci_i2c_sda4, cci_i2c_scl4 */
+                                       pins = "gpio117","gpio118";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-up;
+                               };
+
+                               cci2_i2c1_default: cci2-i2c1-default-pins {
+                                       /* cci_i2c_sda5, cci_i2c_scl5 */
+                                       pins = "gpio12","gpio13";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-up;
+                               };
+                       };
+
+                       cci2_sleep: cci2-sleep-state {
+                               cci2_i2c0_sleep: cci2-i2c0-sleep-pins {
+                                       /* cci_i2c_sda4, cci_i2c_scl4 */
+                                       pins = "gpio117","gpio118";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-down;
+                               };
+
+                               cci2_i2c1_sleep: cci2-i2c1-sleep-pins {
+                                       /* cci_i2c_sda5, cci_i2c_scl5 */
+                                       pins = "gpio12","gpio13";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-down;
+                               };
+                       };
+
+                       cci3_default: cci3-default-state {
+                               cci3_i2c0_default: cci3-i2c0-default-pins {
+                                       /* cci_i2c_sda6, cci_i2c_scl6 */
+                                       pins = "gpio145","gpio146";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-up;
+                               };
+
+                               cci3_i2c1_default: cci3-i2c1-default-pins {
+                                       /* cci_i2c_sda7, cci_i2c_scl7 */
+                                       pins = "gpio164","gpio165";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-up;
+                               };
+                       };
+
+                       cci3_sleep: cci3-sleep-state {
+                               cci3_i2c0_sleep: cci3-i2c0-sleep-pins {
+                                       /* cci_i2c_sda6, cci_i2c_scl6 */
+                                       pins = "gpio145","gpio146";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-down;
+                               };
+
+                               cci3_i2c1_sleep: cci3-i2c1-sleep-pins {
+                                       /* cci_i2c_sda7, cci_i2c_scl7 */
+                                       pins = "gpio164","gpio165";
+                                       function = "cci_i2c";
+                                       drive-strength = <2>;
+                                       bias-pull-down;
+                               };
+                       };
                };
 
                apps_smmu: iommu@15000000 {
                        };
                };
 
+               gpu-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens2 2>;
+
+                       trips {
+                               gpu-crit {
+                                       temperature = <110000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
                mem-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
index 2ed39d402d3f6aeef2529ec997ccea7d373066ca..702ab49bbc5949aa072f4cdec6c63f95e6eff9e9 100644 (file)
        dr_mode = "peripheral";
        extcon = <&extcon_usb>;
 };
+
+&usb3_qmpphy {
+       vdda-phy-supply = <&vreg_l1b_0p925>;
+       status = "okay";
+};
index 362be5719dd25c2bcba63a7ef18bae2aa95f720b..e27f3c5d5bba9a620156e2ae3137310c72920f11 100644 (file)
@@ -4,7 +4,7 @@
  */
 /dts-v1/;
 
-#include "msm8953.dtsi"
+#include "sdm450.dtsi"
 #include "pm8953.dtsi"
 #include "pmi8950.dtsi"
 
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dtsi b/arch/arm64/boot/dts/qcom/sdm450.dtsi
new file mode 100644 (file)
index 0000000..b222aeb
--- /dev/null
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/* Copyright (c) 2023, Luca Weiss <luca@z3ntu.xyz> */
+
+#include "msm8953.dtsi"
+
+&gpu_opp_table {
+       /delete-node/ opp-650000000;
+
+       opp-600000000 {
+               opp-hz = /bits/ 64 <600000000>;
+               opp-supported-hw = <0xff>;
+               required-opps = <&rpmpd_opp_turbo>;
+       };
+};
index 87d0293c728d8dcddaac55011e0ec497a21466a5..819a5f8825e783daef1a64d4e460cb3bd7e5aa1a 100644 (file)
        };
 };
 
+&pm660l_wled {
+       status = "okay";
+
+       qcom,switching-freq = <800>;
+       qcom,ovp-millivolt = <29600>;
+       qcom,current-boost-limit = <970>;
+       qcom,current-limit-microamp = <17500>;
+       qcom,num-strings = <2>;
+};
+
 &pon_pwrkey {
        status = "okay";
 };
 };
 
 &usb3 {
+       qcom,select-utmi-as-pipe-clk;
+
        status = "okay";
 };
 
 &usb3_dwc3 {
+       maximum-speed = "high-speed";
+       phys = <&qusb2phy0>;
+       phy-names = "usb2-phy";
+
        dr_mode = "peripheral";
        extcon = <&extcon_usb>;
 };
index 513fe5e76b688ed0ace12b3804169fdb7e2c8841..f5921b80ef943d3bab4a174e9e4250e2d66a807a 100644 (file)
@@ -13,6 +13,7 @@
 #include <dt-bindings/power/qcom-rpmpd.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/thermal.h>
 #include <dt-bindings/soc/qcom,apr.h>
 
 / {
                        interconnect-names = "gfx-mem";
 
                        operating-points-v2 = <&gpu_sdm630_opp_table>;
+                       #cooling-cells = <2>;
 
                        status = "disabled";
 
                                          <&gcc GCC_USB30_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <120000000>;
 
-                       interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq";
+                       interrupt-names = "pwr_event",
+                                         "qusb2_phy",
+                                         "hs_phy_irq",
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB_30_GDSC>;
-                       qcom,select-utmi-as-pipe-clk;
 
                        resets = <&gcc GCC_USB_30_BCR>;
 
                                snps,dis_u2_susphy_quirk;
                                snps,dis_enblslpm_quirk;
 
-                               /*
-                                * SDM630 technically supports USB3 but I
-                                * haven't seen any devices making use of it.
-                                */
-                               maximum-speed = "high-speed";
-                               phys = <&qusb2phy0>;
-                               phy-names = "usb2-phy";
+                               phys = <&qusb2phy0>, <&usb3_qmpphy>;
+                               phy-names = "usb2-phy", "usb3-phy";
                                snps,hird-threshold = /bits/ 8 <0>;
                        };
                };
 
+               usb3_qmpphy: phy@c010000 {
+                       compatible = "qcom,sdm660-qmp-usb3-phy";
+                       reg = <0x0c010000 0x1000>;
+
+                       clocks = <&gcc GCC_USB3_PHY_AUX_CLK>,
+                                <&gcc GCC_USB3_CLKREF_CLK>,
+                                <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+                                <&gcc GCC_USB3_PHY_PIPE_CLK>;
+                       clock-names = "aux",
+                                     "ref",
+                                     "cfg_ahb",
+                                     "pipe";
+                       clock-output-names = "usb3_phy_pipe_clk_src";
+                       #clock-cells = <0>;
+                       #phy-cells = <0>;
+
+                       resets = <&gcc GCC_USB3_PHY_BCR>,
+                                <&gcc GCC_USB3PHY_PHY_BCR>;
+                       reset-names = "phy",
+                                     "phy_phy";
+
+                       qcom,tcsr-reg = <&tcsr_regs_1 0x6b244>;
+
+                       status = "disabled";
+               };
+
                qusb2phy0: phy@c012000 {
                        compatible = "qcom,sdm660-qusb2-phy";
                        reg = <0x0c012000 0x180>;
                                          <&gcc GCC_USB20_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <60000000>;
 
-                       interrupts = <GIC_SPI 348 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq";
+                       interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 348 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "qusb2_phy",
+                                         "hs_phy_irq";
 
                        qcom,select-utmi-as-pipe-clk;
 
 
                        thermal-sensors = <&tsens 8>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_alert0>;
+                                       cooling-device = <&adreno_gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                gpu_alert0: trip-point0 {
                                        temperature = <90000>;
index 645b9f6a801f44a407e84674249fe8cdc01ec4b8..95b025ea260bdbc48e15496dda34cdd5a7f0a448 100644 (file)
        compatible = "qcom,kryo250";
        capacity-dmips-mhz = <1980>;
 };
+
+&gpu_opp_table {
+       opp-725000000 {
+               opp-hz = /bits/ 64 <725000000>;
+               opp-supported-hw = <0xff>;
+               required-opps = <&rpmpd_opp_turbo>;
+       };
+};
index 3c47410ba94c0b4df66d77f1e646270e8ba7b44f..7167f75bced3fdee2bf34b74f1396a2bda5a944f 100644 (file)
 };
 
 &usb3 {
+       qcom,select-utmi-as-pipe-clk;
+
        status = "okay";
 };
 
 &usb3_dwc3 {
+       maximum-speed = "high-speed";
+       phys = <&qusb2phy0>;
+       phy-names = "usb2-phy";
+
        dr_mode = "peripheral";
        extcon = <&extcon_usb>;
 };
index 4d7b77a231598e8a7f593d6fece320f17c9ef76c..80e81c4233b3899955cf9fc8e60684ebd9fa1018 100644 (file)
                                          <&gcc GCC_USB30_PRIM_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <150000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 6 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 9 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 8 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 9 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq",
-                                         "dm_hs_phy_irq", "dp_hs_phy_irq";
+                                             <&pdc 6 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
 
index 0ab5e8f53ac9f8fdee1c962d3e568c8ca06a9d5f..e8276db9eabb29b8a6021fcdf33e959d2450af5d 100644 (file)
@@ -852,6 +852,7 @@ ap_ts_i2c: &i2c14 {
                pinctrl-names = "default";
                pinctrl-0 = <&ec_ap_int_l>;
                spi-max-frequency = <3000000>;
+               wakeup-source;
 
                cros_ec_pwm: pwm {
                        compatible = "google,cros-ec-pwm";
index ab6220456513cf8ec86a836d6ac5a163d205c47a..1f517328199b908655a5eed5c350641edd06ae1a 100644 (file)
 &pcie0 {
        status = "okay";
        perst-gpios = <&tlmm 35 GPIO_ACTIVE_LOW>;
-       enable-gpio = <&tlmm 134 GPIO_ACTIVE_HIGH>;
+       wake-gpios = <&tlmm 134 GPIO_ACTIVE_HIGH>;
 
        vddpe-3v3-supply = <&pcie0_3p3v_dual>;
 
index e821103d49c0ad38d17f69c1be1bd624e1c82918..46e25c53829ad2cc3572198af6e4abd084bb0bbc 100644 (file)
 };
 
 &q6afedai {
-       qi2s@22 {
-               reg = <22>;
+       dai@22 {
+               reg = <QUATERNARY_MI2S_RX>;
                qcom,sd-lines = <1>;
        };
 
-       qi2s@23 {
-               reg = <23>;
+       dai@23 {
+               reg = <QUATERNARY_MI2S_TX>;
                qcom,sd-lines = <0>;
        };
 };
index fbb8655653fb386acb97fcb8cc4d1a9fed2ca5b0..486ce175e6bcb24f31da48ab99993598e4509d98 100644 (file)
@@ -60,7 +60,7 @@
        };
 
        reserved-memory {
-               framebuffer_region@9d400000 {
+               framebuffer@9d400000 {
                        reg = <0x0 0x9d400000 0x0 (1080 * 2160 * 4)>;
                        no-map;
                };
index c2244824355a20e6a3a8b8d35b63526e3f1d4ace..2f20be99ee7e13dd18802c31d8302f4f5fbc3cff 100644 (file)
                        compatible = "qcom,sdm845-qmp-ufs-phy";
                        reg = <0 0x01d87000 0 0x1000>;
 
+                       clocks = <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>,
+                                <&gcc GCC_UFS_MEM_CLKREF_CLK>;
                        clock-names = "ref",
-                                     "ref_aux";
-                       clocks = <&gcc GCC_UFS_MEM_CLKREF_CLK>,
-                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+                                     "ref_aux",
+                                     "qref";
 
                        resets = <&ufs_mem_hc 0>;
                        reset-names = "ufsphy";
 
                        qcom,qmp = <&aoss_qmp>;
 
-                       power-domains = <&rpmhpd SDM845_CX>,
-                                       <&rpmhpd SDM845_MX>;
+                       power-domains = <&rpmhpd SDM845_LCX>,
+                                       <&rpmhpd SDM845_LMX>;
                        power-domain-names = "lcx", "lmx";
 
                        memory-region = <&slpi_mem>;
                                          <&gcc GCC_USB30_PRIM_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <150000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc_intc 6 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc_intc 9 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc_intc 8 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc_intc 9 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq",
-                                         "dm_hs_phy_irq", "dp_hs_phy_irq";
+                                             <&pdc_intc 6 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
 
                                          <&gcc GCC_USB30_SEC_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <150000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc_intc 7 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc_intc 11 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc_intc 10 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc_intc 11 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq",
-                                         "dm_hs_phy_irq", "dp_hs_phy_irq";
+                                             <&pdc_intc 7 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_SEC_GDSC>;
 
                        operating-points-v2 = <&gpu_opp_table>;
 
                        qcom,gmu = <&gmu>;
+                       #cooling-cells = <2>;
 
                        interconnects = <&mem_noc MASTER_GFX3D 0 &mem_noc SLAVE_EBI1 0>;
                        interconnect-names = "gfx-mem";
                                        hysteresis = <2000>;
                                        type = "hot";
                                };
-                               cluster0_crit: cluster0_crit {
+                               cluster0_crit: cluster0-crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                                        hysteresis = <2000>;
                                        type = "hot";
                                };
-                               cluster1_crit: cluster1_crit {
+                               cluster1_crit: cluster1-crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
 
                        thermal-sensors = <&tsens0 11>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_top_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
-                               gpu1_alert0: trip-point0 {
+                               gpu_top_alert0: trip-point0 {
                                        temperature = <90000>;
                                        hysteresis = <2000>;
                                        type = "hot";
 
                        thermal-sensors = <&tsens0 12>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_bottom_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
-                               gpu2_alert0: trip-point0 {
+                               gpu_bottom_alert0: trip-point0 {
                                        temperature = <90000>;
                                        hysteresis = <2000>;
                                        type = "hot";
index 3e7ae3bebbe081d992ebffec7edb9f6fb113bd5f..603c962661ccfc86551504fa7b4b59e27ab7125f 100644 (file)
@@ -17,7 +17,7 @@
 
        chosen { };
 
-       clocks{
+       clocks {
                xo_board: xo-board {
                        compatible = "fixed-clock";
                        clock-frequency = <76800000>;
index 160e098f10757e5f4e9c68e82ecc45f1ce27aa14..aca0a87092e453951a889008a1f7640606af75bd 100644 (file)
@@ -14,6 +14,7 @@
 #include <dt-bindings/interconnect/qcom,sm6115.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/power/qcom-rpmpd.h>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
        interrupt-parent = <&intc>;
                        #hwlock-cells = <1>;
                };
 
+               tcsr_regs: syscon@3c0000 {
+                       compatible = "qcom,sm6115-tcsr", "syscon";
+                       reg = <0x0 0x003c0000 0x0 0x40000>;
+               };
+
                tlmm: pinctrl@500000 {
                        compatible = "qcom,sm6115-tlmm";
                        reg = <0x0 0x00500000 0x0 0x400000>,
                        clock-output-names = "usb3_phy_pipe_clk_src";
 
                        #phy-cells = <0>;
+                       orientation-switch;
+
+                       qcom,tcsr-reg = <&tcsr_regs 0xb244>;
 
                        status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+
+                                       usb_qmpphy_out: endpoint {
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+
+                                       usb_qmpphy_usb_ss_in: endpoint {
+                                               remote-endpoint = <&usb_dwc3_ss>;
+                                       };
+                               };
+                       };
                };
 
                system_noc: interconnect@1880000 {
                        compatible = "qcom,sm6115-qmp-ufs-phy";
                        reg = <0x0 0x04807000 0x0 0x1000>;
 
-                       clocks = <&gcc GCC_UFS_CLKREF_CLK>, <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
-                       clock-names = "ref", "ref_aux";
+                       clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>,
+                                <&gcc GCC_UFS_CLKREF_CLK>;
+                       clock-names = "ref",
+                                     "ref_aux",
+                                     "qref";
 
                        resets = <&ufs_mem_hc 0>;
                        reset-names = "ufsphy";
                                                 &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>,
                                                <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG
                                                 &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>;
+                               interconnect-names = "qup-core",
+                                                    "qup-config",
+                                                    "qup-memory";
                                #address-cells = <1>;
                                #size-cells = <0>;
                                status = "disabled";
                                          <&gcc GCC_USB30_PRIM_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <66666667>;
 
-                       interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts = <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq";
+                       interrupt-names = "pwr_event",
+                                         "qusb2_phy",
+                                         "hs_phy_irq",
+                                         "ss_phy_irq";
 
                        resets = <&gcc GCC_USB30_PRIM_BCR>;
                        power-domains = <&gcc GCC_USB30_PRIM_GDSC>;
                        interconnect-names = "usb-ddr",
                                             "apps-usb";
 
-                       qcom,select-utmi-as-pipe-clk;
                        status = "disabled";
 
                        usb_dwc3: usb@4e00000 {
                                snps,has-lpm-erratum;
                                snps,hird-threshold = /bits/ 8 <0x10>;
                                snps,usb3_lpm_capable;
+
+                               usb-role-switch;
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+
+                                               usb_dwc3_hs: endpoint {
+                                               };
+                                       };
+
+                                       port@1 {
+                                               reg = <1>;
+
+                                               usb_dwc3_ss: endpoint {
+                                                       remote-endpoint = <&usb_qmpphy_usb_ss_in>;
+                                               };
+                                       };
+                               };
                        };
                };
 
 
                        nvmem-cells = <&gpu_speed_bin>;
                        nvmem-cell-names = "speed_bin";
+                       #cooling-cells = <2>;
 
                        status = "disabled";
 
                                        type = "passive";
                                };
 
-                               cpu4_crit: cpu_crit {
+                               cpu4_crit: cpu-crit {
                                        temperature = <110000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                        type = "passive";
                                };
 
-                               cpu5_crit: cpu_crit {
+                               cpu5_crit: cpu-crit {
                                        temperature = <110000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                        type = "passive";
                                };
 
-                               cpu6_crit: cpu_crit {
+                               cpu6_crit: cpu-crit {
                                        temperature = <110000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                        type = "passive";
                                };
 
-                               cpu7_crit: cpu_crit {
+                               cpu7_crit: cpu-crit {
                                        temperature = <110000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                        type = "passive";
                                };
 
-                               cpu45_crit: cpu_crit {
+                               cpu45_crit: cpu-crit {
                                        temperature = <110000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                        type = "passive";
                                };
 
-                               cpu67_crit: cpu_crit {
+                               cpu67_crit: cpu-crit {
                                        temperature = <110000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                                        type = "passive";
                                };
 
-                               cpu0123_crit: cpu_crit {
+                               cpu0123_crit: cpu-crit {
                                        temperature = <110000>;
                                        hysteresis = <1000>;
                                        type = "critical";
                        polling-delay = <0>;
                        thermal-sensors = <&tsens0 15>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
-                               trip-point0 {
+                               gpu_alert0: trip-point0 {
                                        temperature = <115000>;
                                        hysteresis = <5000>;
                                        type = "passive";
                                trip-point1 {
                                        temperature = <125000>;
                                        hysteresis = <1000>;
-                                       type = "passive";
+                                       type = "critical";
                                };
                        };
                };
index 1dd3a4056e26f3888dcc95e300f44f289f99d8bb..98ab083560887ce2c89ca7e4cc63a134ae42a790 100644 (file)
                        compatible = "qcom,sm6125-qmp-ufs-phy";
                        reg = <0x04807000 0xdb8>;
 
-                       clocks = <&gcc GCC_UFS_MEM_CLKREF_CLK>,
-                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+                       clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>,
+                                <&gcc GCC_UFS_MEM_CLKREF_CLK>;
                        clock-names = "ref",
-                                     "ref_aux";
+                                     "ref_aux",
+                                     "qref";
 
                        resets = <&ufs_mem_hc 0>;
                        reset-names = "ufsphy";
                                          <&gcc GCC_USB30_PRIM_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <66666667>;
 
-                       interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts = <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq";
+                       interrupt-names = "pwr_event",
+                                         "qusb2_phy",
+                                         "hs_phy_irq",
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
                        qcom,select-utmi-as-pipe-clk;
index 43cffe8e1247e35d65bfb4b01aec4861e04f396c..24bcec3366efd58671cbcd6fa27cd0d807ab2d4f 100644 (file)
@@ -19,6 +19,7 @@
 #include <dt-bindings/phy/phy-qcom-qmp.h>
 #include <dt-bindings/power/qcom-rpmpd.h>
 #include <dt-bindings/soc/qcom,rpmh-rsc.h>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
        interrupt-parent = <&intc>;
                        compatible = "qcom,sm6350-qmp-ufs-phy";
                        reg = <0 0x01d87000 0 0x1000>;
 
+                       clocks = <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>,
+                                <&gcc GCC_UFS_MEM_CLKREF_CLK>;
                        clock-names = "ref",
-                                     "ref_aux";
-                       clocks = <&gcc GCC_UFS_MEM_CLKREF_CLK>,
-                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+                                     "ref_aux",
+                                     "qref";
 
                        resets = <&ufs_mem_hc 0>;
                        reset-names = "ufsphy";
                        qcom,gmu = <&gmu>;
                        nvmem-cells = <&gpu_speed_bin>;
                        nvmem-cell-names = "speed_bin";
+                       #cooling-cells = <2>;
 
                        status = "disabled";
 
-                       zap-shader {
+                       gpu_zap_shader: zap-shader {
                                memory-region = <&pil_gpu_mem>;
                        };
 
 
                        operating-points-v2 = <&gmu_opp_table>;
 
-                       status = "disabled";
-
                        gmu_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                      "mock_utmi";
 
                        interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 15 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>;
-
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq",
-                                         "dm_hs_phy_irq", "dp_hs_phy_irq";
+                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
 
                        interrupt-controller;
                        #interrupt-cells = <1>;
 
+                       interconnects = <&mmss_noc MASTER_MDP_PORT0 QCOM_ICC_TAG_ALWAYS
+                                        &clk_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ALWAYS>,
+                                       <&gem_noc MASTER_AMPSS_M0 QCOM_ICC_TAG_ACTIVE_ONLY
+                                        &config_noc SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ACTIVE_ONLY>;
+                       interconnect-names = "mdp0-mem",
+                                            "cpu-cfg";
+
                        clocks = <&gcc GCC_DISP_AHB_CLK>,
                                 <&gcc GCC_DISP_AXI_CLK>,
                                 <&dispcc DISP_CC_MDSS_MDP_CLK>;
                };
        };
 
+       thermal-zones {
+               aoss0-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 0>;
+
+                       trips {
+                               aoss0-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               aoss1-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens1 0>;
+
+                       trips {
+                               aoss1-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               audio-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens1 2>;
+
+                       trips {
+                               audio-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               camera-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens1 5>;
+
+                       trips {
+                               camera-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpu0-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 1>;
+
+                       trips {
+                               cpu0_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               cpu0-crit {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu0_alert0>;
+                                       cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu1-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 2>;
+
+                       trips {
+                               cpu1_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               cpu1-crit {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu1_alert0>;
+                                       cooling-device = <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu2-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 3>;
+
+                       trips {
+                               cpu2_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               cpu2-crit {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu2_alert0>;
+                                       cooling-device = <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu3-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 4>;
+
+                       trips {
+                               cpu3_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               cpu3-crit {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu3_alert0>;
+                                       cooling-device = <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu4-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 5>;
+
+                       trips {
+                               cpu4_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               cpu4-crit {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu4_alert0>;
+                                       cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu5-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 6>;
+
+                       trips {
+                               cpu5_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               cpu5-crit {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu5_alert0>;
+                                       cooling-device = <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu6-left-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 9>;
+
+                       trips {
+                               cpu6_left_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               cpu6-left-crit {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu6_left_alert0>;
+                                       cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu6-right-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 10>;
+
+                       trips {
+                               cpu6_right_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               cpu6-right-crit {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu6_right_alert0>;
+                                       cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu7-left-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 11>;
+
+                       trips {
+                               cpu7_left_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               cpu7-left-crit {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu7_left_alert0>;
+                                       cooling-device = <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpu7-right-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 12>;
+
+                       trips {
+                               cpu7_right_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               cpu7-right-crit {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&cpu7_right_alert0>;
+                                       cooling-device = <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               cpuss0-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 7>;
+
+                       trips {
+                               cpuss0-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpuss1-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 8>;
+
+                       trips {
+                               cpuss1-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cwlan-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens1 1>;
+
+                       trips {
+                               cwlan-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               ddr-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens1 3>;
+
+                       trips {
+                               ddr-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               gpuss0-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 13>;
+
+                       trips {
+                               gpuss0_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               gpuss0-crit {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpuss0_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               gpuss1-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens0 14>;
+
+                       trips {
+                               gpuss1_alert0: trip-point0 {
+                                       temperature = <95000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               gpuss1-crit {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpuss1_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+
+               modem-core0-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens1 6>;
+
+                       trips {
+                               modem-core0-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               modem-core1-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens1 7>;
+
+                       trips {
+                               modem-core1-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               modem-scl-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens1 9>;
+
+                       trips {
+                               modem-scl-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               modem-vec-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens1 8>;
+
+                       trips {
+                               modem-vec-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               npu-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens1 10>;
+
+                       trips {
+                               npu-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               q6-hvx-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens1 4>;
+
+                       trips {
+                               q6-hvx-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               video-thermal {
+                       polling-delay-passive = <0>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&tsens1 11>;
+
+                       trips {
+                               video-crit {
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+               };
+       };
+
        timer {
                compatible = "arm,armv8-timer";
                clock-frequency = <19200000>;
index 7ac8bf26dda3a28c40ce996705fb42c0ddf545f2..4386f8a9c636c1dd58a21ed8002d385c3d716c5c 100644 (file)
                        assigned-clock-rates = <19200000>, <133333333>;
 
                        interrupts-extended = <&intc GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&mpm 12 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&mpm 94 IRQ_TYPE_EDGE_BOTH>,
                                              <&mpm 93 IRQ_TYPE_EDGE_BOTH>,
-                                             <&mpm 94 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq",
-                                         "ss_phy_irq",
+                                             <&mpm 12 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
                                          "dm_hs_phy_irq",
-                                         "dp_hs_phy_irq";
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
 
index e55cd83c19b8a9ad87df2c50169be8d41d6170d6..29289fa41b1344c002e31920ef2dd230eef1bc67 100644 (file)
                        regulator-min-microvolt = <824000>;
                        regulator-max-microvolt = <928000>;
                        regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
                };
 
                vreg_l5a_2p7: ldo5 {
                        regulator-min-microvolt = <1696000>;
                        regulator-max-microvolt = <1952000>;
                        regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
                };
 
                vreg_l13a_1p8: ldo13 {
                        regulator-min-microvolt = <2696000>;
                        regulator-max-microvolt = <3304000>;
                        regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
                };
        };
 
                        regulator-min-microvolt = <1144000>;
                        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_l4c_1p8: ldo4 {
        };
 };
 
+&ufs_mem_hc {
+       vcc-supply = <&vreg_l19a_3p0>;
+       vcc-max-microamp = <600000>;
+       vccq2-supply = <&vreg_l12a_1p8>;
+       vccq2-max-microamp = <600000>;
+       status = "okay";
+};
+
+&ufs_mem_phy {
+       vdda-phy-supply = <&vreg_l4a_0p88>;
+       vdda-pll-supply = <&vreg_l3c_1p23>;
+       status = "okay";
+};
+
 &usb_1 {
        qcom,select-utmi-as-pipe-clk;
        status = "okay";
diff --git a/arch/arm64/boot/dts/qcom/sm7125-xiaomi-curtana.dts b/arch/arm64/boot/dts/qcom/sm7125-xiaomi-curtana.dts
new file mode 100644 (file)
index 0000000..12f517a
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023, Joe Mason <buddyjojo06@outlook.com>
+ */
+
+/dts-v1/;
+
+#include "sm7125-xiaomi-common.dtsi"
+
+/ {
+       model = "Xiaomi Redmi Note 9S";
+       compatible = "xiaomi,curtana", "qcom,sm7125";
+
+       /* required for bootloader to select correct board */
+       qcom,board-id = <0x20022 1>;
+};
index ade619805519e86c8a67454a94c47b058c445ec9..bc67e8c1fe4d15f58de781404d0432e3bd69d311 100644 (file)
                };
        };
 
+       /* Dummy regulator until PM6150L has LCDB VSP/VSN support */
+       lcdb_dummy: regulator-lcdb-dummy {
+               compatible = "regulator-fixed";
+               regulator-name = "lcdb_dummy";
+               regulator-min-microvolt = <5500000>;
+               regulator-max-microvolt = <5500000>;
+       };
+
        reserved-memory {
                /*
                 * The rmtfs memory region in downstream is 'dynamically allocated'
 };
 
 &adsp {
-       firmware-name = "qcom/sm7225/fairphone4/adsp.mdt";
+       firmware-name = "qcom/sm7225/fairphone4/adsp.mbn";
        status = "okay";
 };
 
 };
 
 &cdsp {
-       firmware-name = "qcom/sm7225/fairphone4/cdsp.mdt";
+       firmware-name = "qcom/sm7225/fairphone4/cdsp.mbn";
        status = "okay";
 };
 
        status = "okay";
 };
 
+&gpu {
+       status = "okay";
+};
+
+&gpu_zap_shader {
+       firmware-name = "qcom/sm7225/fairphone4/a615_zap.mbn";
+};
+
 &i2c0 {
        clock-frequency = <400000>;
        status = "okay";
 &ipa {
        qcom,gsi-loader = "self";
        memory-region = <&pil_ipa_fw_mem>;
-       firmware-name = "qcom/sm7225/fairphone4/ipa_fws.mdt";
+       firmware-name = "qcom/sm7225/fairphone4/ipa_fws.mbn";
+       status = "okay";
+};
+
+&mdss {
+       status = "okay";
+};
+
+&mdss_dsi0 {
+       vdda-supply = <&vreg_l22a>;
+       status = "okay";
+
+       panel@0 {
+               compatible = "djn,9a-3r063-1102b";
+               reg = <0>;
+
+               backlight = <&pm6150l_wled>;
+               reset-gpios = <&pm6150l_gpios 9 GPIO_ACTIVE_LOW>;
+
+               vdd1-supply = <&vreg_l1e>;
+               vsn-supply = <&lcdb_dummy>;
+               vsp-supply = <&lcdb_dummy>;
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&mdss_dsi0_out>;
+                       };
+               };
+       };
+};
+
+&mdss_dsi0_out {
+       data-lanes = <0 1 2 3>;
+       remote-endpoint = <&panel_in>;
+};
+
+&mdss_dsi0_phy {
+       vdds-supply = <&vreg_l18a>;
        status = "okay";
 };
 
 &mpss {
-       firmware-name = "qcom/sm7225/fairphone4/modem.mdt";
+       firmware-name = "qcom/sm7225/fairphone4/modem.mbn";
        status = "okay";
 };
 
index 761a6757dc26f082d0488661d8035f4f3e51a18e..a35c0852b5a14cd8e2833986916bc24d096eefb0 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
 
-                       gpu_speed_bin: gpu_speed_bin@133 {
+                       gpu_speed_bin: gpu-speed-bin@133 {
                                reg = <0x133 0x1>;
                                bits = <5 3>;
                        };
                        ranges = <0x01000000 0x0 0x00000000 0x0 0x60200000 0x0 0x100000>,
                                 <0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x3d00000>;
 
-                       interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                                 <&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
                                 <&gcc GCC_PCIE_0_SLV_AXI_CLK>,
                                 <&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>,
-                                <&gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>;
+                                <&gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>;
                        clock-names = "pipe",
                                      "aux",
                                      "cfg",
                                      "bus_master",
                                      "bus_slave",
                                      "slave_q2a",
-                                     "tbu";
+                                     "tbu",
+                                     "ref";
 
                        iommu-map = <0x0   &apps_smmu 0x1d80 0x1>,
                                    <0x100 &apps_smmu 0x1d81 0x1>;
                        phy-names = "pciephy";
 
                        perst-gpios = <&tlmm 35 GPIO_ACTIVE_HIGH>;
-                       enable-gpio = <&tlmm 37 GPIO_ACTIVE_HIGH>;
+                       wake-gpios = <&tlmm 37 GPIO_ACTIVE_HIGH>;
 
                        pinctrl-names = "default";
                        pinctrl-0 = <&pcie0_default_state>;
                        ranges = <0x01000000 0x0 0x00000000 0x0 0x40200000 0x0 0x100000>,
                                 <0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1fd00000>;
 
-                       interrupts = <GIC_SPI 307 IRQ_TYPE_EDGE_RISING>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 434 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                                 <&gcc GCC_PCIE_1_MSTR_AXI_CLK>,
                                 <&gcc GCC_PCIE_1_SLV_AXI_CLK>,
                                 <&gcc GCC_PCIE_1_SLV_Q2A_AXI_CLK>,
-                                <&gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>;
+                                <&gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>;
                        clock-names = "pipe",
                                      "aux",
                                      "cfg",
                                      "bus_master",
                                      "bus_slave",
                                      "slave_q2a",
-                                     "tbu";
+                                     "tbu",
+                                     "ref";
 
                        assigned-clocks = <&gcc GCC_PCIE_1_AUX_CLK>;
                        assigned-clock-rates = <19200000>;
                        compatible = "qcom,sm8150-qmp-ufs-phy";
                        reg = <0 0x01d87000 0 0x1000>;
 
+                       clocks = <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>,
+                                <&gcc GCC_UFS_MEM_CLKREF_CLK>;
                        clock-names = "ref",
-                                     "ref_aux";
-                       clocks = <&gcc GCC_UFS_MEM_CLKREF_CLK>,
-                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+                                     "ref_aux",
+                                     "qref";
 
                        power-domains = <&gcc UFS_PHY_GDSC>;
 
 
                        nvmem-cells = <&gpu_speed_bin>;
                        nvmem-cell-names = "speed_bin";
+                       #cooling-cells = <2>;
 
                        status = "disabled";
 
                                bias-disable;
                        };
 
-                       qup_spi6_default: qup-spi6_default-state {
+                       qup_spi6_default: qup-spi6-default-state {
                                pins = "gpio4", "gpio5", "gpio6", "gpio7";
                                function = "qup6";
                                drive-strength = <6>;
                                bias-disable;
                        };
 
-                       qup_spi7_default: qup-spi7_default-state {
+                       qup_spi7_default: qup-spi7-default-state {
                                pins = "gpio98", "gpio99", "gpio100", "gpio101";
                                function = "qup7";
                                drive-strength = <6>;
                                          <&gcc GCC_USB30_PRIM_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <200000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 6 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 9 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 8 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 9 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq",
-                                         "dm_hs_phy_irq", "dp_hs_phy_irq";
+                                             <&pdc 6 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
 
                                          <&gcc GCC_USB30_SEC_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <200000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 7 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 11 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 10 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 11 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq", "ss_phy_irq",
-                                         "dm_hs_phy_irq", "dp_hs_phy_irq";
+                                             <&pdc 7 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_SEC_GDSC>;
 
                                        hysteresis = <2000>;
                                        type = "hot";
                                };
-                               cluster0_crit: cluster0_crit {
+                               cluster0_crit: cluster0-crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                                        hysteresis = <2000>;
                                        type = "hot";
                                };
-                               cluster1_crit: cluster1_crit {
+                               cluster1_crit: cluster1-crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
 
                        thermal-sensors = <&tsens0 15>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_top_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
-                               gpu1_alert0: trip-point0 {
+                               gpu_top_alert0: trip-point0 {
                                        temperature = <90000>;
                                        hysteresis = <2000>;
                                        type = "hot";
 
                        thermal-sensors = <&tsens1 11>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_bottom_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
-                               gpu2_alert0: trip-point0 {
+                               gpu_bottom_alert0: trip-point0 {
                                        temperature = <90000>;
                                        hysteresis = <2000>;
                                        type = "hot";
index 946365f15a5985a6791d587308151ee9c1764b6c..6f54f50a70b0f8e0b0c81da5963e319858b6ddcd 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: BSD-3-Clause
 /*
- * Copyright (c) 2022, 2023 Jianhua Lu <lujianhua000@gmail.com>
+ * Copyright (c) 2022-2024 Jianhua Lu <lujianhua000@gmail.com>
  */
 
 #include <dt-bindings/arm/qcom,ids.h>
                vddio-supply = <&vreg_l14a_1p88>;
                reset-gpios = <&tlmm 75 GPIO_ACTIVE_LOW>;
                backlight = <&backlight>;
+               rotation = <90>;
 
                status = "disabled";
 
index 760501c1301a6216fc22c48b388c4e69aa966a18..39bd8f0eba1e653a7fe1b452cb7615317f3f6b68 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
 
-                       gpu_speed_bin: gpu_speed_bin@19b {
+                       gpu_speed_bin: gpu-speed-bin@19b {
                                reg = <0x19b 0x1>;
                                bits = <5 3>;
                        };
                                     <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi0", "msi1", "msi2", "msi3",
-                                         "msi4", "msi5", "msi6", "msi7";
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                        ranges = <0x01000000 0x0 0x00000000 0x0 0x40200000 0x0 0x100000>,
                                 <0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1fd00000>;
 
-                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 434 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                        ranges = <0x01000000 0x0 0x00000000 0x0 0x64200000 0x0 0x100000>,
                                 <0x02000000 0x0 0x64300000 0x0 0x64300000 0x0 0x3d00000>;
 
-                       interrupts = <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 290 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                        compatible = "qcom,sm8250-qmp-ufs-phy";
                        reg = <0 0x01d87000 0 0x1000>;
 
-                       clock-names = "ref",
-                                     "ref_aux";
                        clocks = <&rpmhcc RPMH_CXO_CLK>,
-                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>,
+                                <&gcc GCC_UFS_1X_CLKREF_EN>;
+                       clock-names = "ref",
+                                     "ref_aux",
+                                     "qref";
 
                        resets = <&ufs_mem_hc 0>;
                        reset-names = "ufsphy";
 
                        nvmem-cells = <&gpu_speed_bin>;
                        nvmem-cell-names = "speed_bin";
+                       #cooling-cells = <2>;
 
                        status = "disabled";
 
                                          <&gcc GCC_USB30_PRIM_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <200000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 15 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq",
-                                         "ss_phy_irq",
+                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
                                          "dm_hs_phy_irq",
-                                         "dp_hs_phy_irq";
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
                        wakeup-source;
                                          <&gcc GCC_USB30_SEC_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <200000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 16 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 12 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 13 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 12 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq",
-                                         "ss_phy_irq",
+                                             <&pdc 16 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
                                          "dm_hs_phy_irq",
-                                         "dp_hs_phy_irq";
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_SEC_GDSC>;
                        wakeup-source;
                                        hysteresis = <2000>;
                                        type = "hot";
                                };
-                               cluster0_crit: cluster0_crit {
+                               cluster0_crit: cluster0-crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                                        hysteresis = <2000>;
                                        type = "hot";
                                };
-                               cluster1_crit: cluster1_crit {
+                               cluster1_crit: cluster1-crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
 
                        thermal-sensors = <&tsens0 15>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_top_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
-                               gpu1_alert0: trip-point0 {
+                               gpu_top_alert0: trip-point0 {
                                        temperature = <90000>;
                                        hysteresis = <2000>;
                                        type = "hot";
 
                        thermal-sensors = <&tsens1 8>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_bottom_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
-                               gpu2_alert0: trip-point0 {
+                               gpu_bottom_alert0: trip-point0 {
                                        temperature = <90000>;
                                        hysteresis = <2000>;
                                        type = "hot";
index e78c83a897c283e855dac3183faeab48d798cc43..a5e7dbbd8c6c5ee1d9c46233f8ef034957b7984f 100644 (file)
                                     <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi0", "msi1", "msi2", "msi3",
-                                         "msi4", "msi5", "msi6", "msi7";
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                        ranges = <0x01000000 0x0 0x00000000 0x0 0x40200000 0x0 0x100000>,
                                 <0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1fd00000>;
 
-                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 434 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                        compatible = "qcom,sm8350-qmp-ufs-phy";
                        reg = <0 0x01d87000 0 0x1000>;
 
-                       clock-names = "ref",
-                                     "ref_aux";
                        clocks = <&rpmhcc RPMH_CXO_CLK>,
-                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>,
+                                <&gcc GCC_UFS_1_CLKREF_EN>;
+                       clock-names = "ref",
+                                     "ref_aux",
+                                     "qref";
 
                        resets = <&ufs_mem_hc 0>;
                        reset-names = "ufsphy";
                        operating-points-v2 = <&gpu_opp_table>;
 
                        qcom,gmu = <&gmu>;
+                       #cooling-cells = <2>;
 
                        status = "disabled";
 
                                          <&gcc GCC_USB30_PRIM_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <200000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 15 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq",
-                                         "ss_phy_irq",
+                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
                                          "dm_hs_phy_irq",
-                                         "dp_hs_phy_irq";
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
 
                                          <&gcc GCC_USB30_SEC_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <200000000>;
 
-                       interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 16 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 12 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 13 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 12 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq",
-                                         "ss_phy_irq",
+                                             <&pdc 16 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
                                          "dm_hs_phy_irq",
-                                         "dp_hs_phy_irq";
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_SEC_GDSC>;
 
                                        hysteresis = <2000>;
                                        type = "hot";
                                };
-                               cluster0_crit: cluster0_crit {
+                               cluster0_crit: cluster0-crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
                                        hysteresis = <2000>;
                                        type = "hot";
                                };
-                               cluster1_crit: cluster1_crit {
+                               cluster1_crit: cluster1-crit {
                                        temperature = <110000>;
                                        hysteresis = <2000>;
                                        type = "critical";
 
                        thermal-sensors = <&tsens1 1>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_top_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
-                               gpu1_alert0: trip-point0 {
+                               gpu_top_alert0: trip-point0 {
                                        temperature = <90000>;
                                        hysteresis = <1000>;
                                        type = "hot";
 
                        thermal-sensors = <&tsens1 2>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_bottom_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
-                               gpu2_alert0: trip-point0 {
+                               gpu_bottom_alert0: trip-point0 {
                                        temperature = <90000>;
                                        hysteresis = <1000>;
                                        type = "hot";
index a20d5d76af352ca6dc1aa7028cd6d094f72f35f2..0786cff07b8920f36576c9007f261d32c04fa08a 100644 (file)
                        "TX DMIC3", "MIC BIAS1",
                        "TX SWR_INPUT0", "ADC1_OUTPUT",
                        "TX SWR_INPUT1", "ADC2_OUTPUT",
-                       "TX SWR_INPUT2", "ADC3_OUTPUT",
-                       "TX SWR_INPUT3", "ADC4_OUTPUT";
+                       "TX SWR_INPUT0", "ADC3_OUTPUT",
+                       "TX SWR_INPUT1", "ADC4_OUTPUT";
 
        wcd-playback-dai-link {
                link-name = "WCD Playback";
 };
 
 &vamacro {
-       pinctrl-0 = <&dmic01_default>, <&dmic02_default>;
+       pinctrl-0 = <&dmic01_default>, <&dmic23_default>;
        pinctrl-names = "default";
        vdd-micb-supply = <&vreg_s10b_1p8>;
        qcom,dmic-sample-rate = <600000>;
index 01e4dfc4babd2904eee95b3eaf4d63516d6c019a..b86be34a912b943e7649eecbd71fae2b78411e5f 100644 (file)
                                pinctrl-names = "default";
                                pinctrl-0 = <&qup_uart20_default>;
                                interrupts = <GIC_SPI 587 IRQ_TYPE_LEVEL_HIGH>;
+                               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";
                                status = "disabled";
                        };
 
                                pinctrl-names = "default";
                                pinctrl-0 = <&qup_uart7_tx>, <&qup_uart7_rx>;
                                interrupts = <GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>;
+                               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";
                                status = "disabled";
                        };
                };
                        msi-map = <0x0 &gic_its 0x5981 0x1>,
                                  <0x100 &gic_its 0x5980 0x1>;
                        msi-map-mask = <0xff00>;
-                       interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                        msi-map = <0x0 &gic_its 0x5a01 0x1>,
                                  <0x100 &gic_its 0x5a00 0x1>;
                        msi-map-mask = <0xff00>;
-                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 0 0 434 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                        operating-points-v2 = <&gpu_opp_table>;
 
                        qcom,gmu = <&gmu>;
+                       #cooling-cells = <2>;
 
                        status = "disabled";
 
                                };
                        };
 
-                       dmic02_default: dmic02-default-state {
+                       dmic23_default: dmic23-default-state {
                                clk-pins {
                                        pins = "gpio8";
                                        function = "dmic2_clk";
                        assigned-clock-rates = <19200000>, <200000000>;
 
                        interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 15 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq",
-                                         "ss_phy_irq",
+                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
                                          "dm_hs_phy_irq",
-                                         "dp_hs_phy_irq";
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
 
                        polling-delay = <0>;
                        thermal-sensors = <&tsens0 14>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_top_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                thermal-engine-config {
                                        temperature = <125000>;
                                        type = "passive";
                                };
 
-                               gpu0_tj_cfg: tj-cfg {
+                               gpu_top_alert0: trip-point0 {
                                        temperature = <95000>;
                                        hysteresis = <5000>;
                                        type = "passive";
                        polling-delay = <0>;
                        thermal-sensors = <&tsens0 15>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu_bottom_alert0>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                thermal-engine-config {
                                        temperature = <125000>;
                                        type = "passive";
                                };
 
-                               gpu1_tj_cfg: tj-cfg {
+                               gpu_bottom_alert0: trip-point0 {
                                        temperature = <95000>;
                                        hysteresis = <5000>;
                                        type = "passive";
diff --git a/arch/arm64/boot/dts/qcom/sm8550-hdk.dts b/arch/arm64/boot/dts/qcom/sm8550-hdk.dts
new file mode 100644 (file)
index 0000000..12d60a0
--- /dev/null
@@ -0,0 +1,1306 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2024 Linaro Limited
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include "sm8550.dtsi"
+#include "pm8010.dtsi"
+#include "pm8550.dtsi"
+#include "pm8550b.dtsi"
+#define PMK8550VE_SID 5
+#include "pm8550ve.dtsi"
+#include "pm8550vs.dtsi"
+#include "pmk8550.dtsi"
+#include "pmr735d_a.dtsi"
+
+/ {
+       model = "Qualcomm Technologies, Inc. SM8550 HDK";
+       compatible = "qcom,sm8550-hdk", "qcom,sm8550";
+       chassis-type = "embedded";
+
+       aliases {
+               serial0 = &uart7;
+               serial1 = &uart14;
+       };
+
+       wcd938x: audio-codec {
+               compatible = "qcom,wcd9385-codec";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&wcd_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 108 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>;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       hdmi-out {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_connector_out: endpoint {
+                               remote-endpoint = <&lt9611_out>;
+                       };
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               pinctrl-0 = <&volume_up_n>;
+               pinctrl-names = "default";
+
+               key-volume-up {
+                       label = "Volume Up";
+                       linux,code = <KEY_VOLUMEUP>;
+                       gpios = <&pm8550_gpios 6 GPIO_ACTIVE_LOW>;
+                       debounce-interval = <15>;
+                       linux,can-disable;
+                       wakeup-source;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led-0 {
+                       function = LED_FUNCTION_BLUETOOTH;
+                       color = <LED_COLOR_ID_BLUE>;
+                       gpios = <&tlmm 159 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "bluetooth-power";
+                       default-state = "off";
+               };
+
+               led-1 {
+                       function = LED_FUNCTION_INDICATOR;
+                       color = <LED_COLOR_ID_GREEN>;
+                       gpios = <&tlmm 160 GPIO_ACTIVE_HIGH>;
+                       default-state = "off";
+                       panic-indicator;
+               };
+
+               led-2 {
+                       function = LED_FUNCTION_WLAN;
+                       color = <LED_COLOR_ID_ORANGE>;
+                       gpios = <&tlmm 162 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "phy0tx";
+                       default-state = "off";
+               };
+       };
+
+       pmic-glink {
+               compatible = "qcom,sm8550-pmic-glink", "qcom,pmic-glink";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               orientation-gpios = <&tlmm 11 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@1 {
+                                       reg = <1>;
+
+                                       pmic_glink_ss_in: endpoint {
+                                               remote-endpoint = <&usb_dp_qmpphy_out>;
+                                       };
+                               };
+
+                               port@2 {
+                                       reg = <2>;
+
+                                       pmic_glink_sbu: endpoint {
+                                               remote-endpoint = <&fsa4480_sbu_mux>;
+                                       };
+                               };
+                       };
+               };
+       };
+
+       lt9611_1v2: regulator-lt9611-1v2 {
+               compatible = "regulator-fixed";
+
+               regulator-name = "LT9611_1V2";
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <1200000>;
+
+               vin-supply = <&vph_pwr>;
+               gpio = <&tlmm 152 GPIO_ACTIVE_HIGH>;
+
+               enable-active-high;
+       };
+
+       lt9611_3v3: regulator-lt9611-3v3 {
+               compatible = "regulator-fixed";
+
+               regulator-name = "LT9611_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               vin-supply = <&vreg_bob_3v3>;
+               gpio = <&tlmm 6 GPIO_ACTIVE_HIGH>;
+
+               enable-active-high;
+       };
+
+       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_bob_3v3: regulator-vreg-bob-3v3 {
+               compatible = "regulator-fixed";
+
+               regulator-name = "VREG_BOB_3P3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               vin-supply = <&vph_pwr>;
+       };
+
+       sound {
+               compatible = "qcom,sm8550-sndcard", "qcom,sm8450-sndcard";
+               model = "SM8550-HDK";
+               audio-routing = "SpkrLeft IN", "WSA_SPK1 OUT",
+                               "SpkrRight IN", "WSA_SPK2 OUT",
+                               "IN1_HPHL", "HPHL_OUT",
+                               "IN2_HPHR", "HPHR_OUT",
+                               "AMIC1", "MIC BIAS1",
+                               "AMIC2", "MIC BIAS2",
+                               "AMIC5", "MIC BIAS4",
+                               "TX SWR_INPUT0", "ADC1_OUTPUT",
+                               "TX SWR_INPUT1", "ADC2_OUTPUT",
+                               "TX SWR_INPUT1", "ADC4_OUTPUT";
+
+               wcd-playback-dai-link {
+                       link-name = "WCD Playback";
+
+                       cpu {
+                               sound-dai = <&q6apmbedai RX_CODEC_DMA_RX_0>;
+                       };
+
+                       codec {
+                               sound-dai = <&wcd938x 0>, <&swr1 0>, <&lpass_rxmacro 0>;
+                       };
+
+                       platform {
+                               sound-dai = <&q6apm>;
+                       };
+               };
+
+               wcd-capture-dai-link {
+                       link-name = "WCD Capture";
+
+                       cpu {
+                               sound-dai = <&q6apmbedai TX_CODEC_DMA_TX_3>;
+                       };
+
+                       codec {
+                               sound-dai = <&wcd938x 1>, <&swr2 0>, <&lpass_txmacro 0>;
+                       };
+
+                       platform {
+                               sound-dai = <&q6apm>;
+                       };
+               };
+
+               wsa-dai-link {
+                       link-name = "WSA Playback";
+
+                       cpu {
+                               sound-dai = <&q6apmbedai WSA_CODEC_DMA_RX_0>;
+                       };
+
+                       codec {
+                               sound-dai = <&north_spkr>, <&south_spkr>, <&swr0 0>, <&lpass_wsamacro 0>;
+                       };
+
+                       platform {
+                               sound-dai = <&q6apm>;
+                       };
+               };
+
+               va-dai-link {
+                       link-name = "VA Capture";
+
+                       cpu {
+                               sound-dai = <&q6apmbedai TX_CODEC_DMA_TX_3>;
+                       };
+
+                       codec {
+                               sound-dai = <&lpass_vamacro 0>;
+                       };
+
+                       platform {
+                               sound-dai = <&q6apm>;
+                       };
+               };
+       };
+};
+
+&apps_rsc {
+       regulators-0 {
+               compatible = "qcom,pm8550-rpmh-regulators";
+
+               vdd-bob1-supply = <&vph_pwr>;
+               vdd-bob2-supply = <&vph_pwr>;
+               vdd-l1-l4-l10-supply = <&vreg_s6g_1p86>;
+               vdd-l2-l13-l14-supply = <&vreg_bob1>;
+               vdd-l3-supply = <&vreg_s4g_1p25>;
+               vdd-l5-l16-supply = <&vreg_bob1>;
+               vdd-l6-l7-supply = <&vreg_bob1>;
+               vdd-l8-l9-supply = <&vreg_bob1>;
+               vdd-l11-supply = <&vreg_s4g_1p25>;
+               vdd-l12-supply = <&vreg_s6g_1p86>;
+               vdd-l15-supply = <&vreg_s6g_1p86>;
+               vdd-l17-supply = <&vreg_bob2>;
+
+               qcom,pmic-id = "b";
+
+               vreg_bob1: bob1 {
+                       regulator-name = "vreg_bob1";
+                       regulator-min-microvolt = <3296000>;
+                       regulator-max-microvolt = <3960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_bob2: bob2 {
+                       regulator-name = "vreg_bob2";
+                       regulator-min-microvolt = <2720000>;
+                       regulator-max-microvolt = <3960000>;
+                       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>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l2b_3p0: ldo2 {
+                       regulator-name = "vreg_l2b_3p0";
+                       regulator-min-microvolt = <3008000>;
+                       regulator-max-microvolt = <3008000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l5b_3p1: ldo5 {
+                       regulator-name = "vreg_l5b_3p1";
+                       regulator-min-microvolt = <3104000>;
+                       regulator-max-microvolt = <3104000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l6b_1p8: ldo6 {
+                       regulator-name = "vreg_l6b_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <3008000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l7b_1p8: ldo7 {
+                       regulator-name = "vreg_l7b_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <3008000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l8b_1p8: ldo8 {
+                       regulator-name = "vreg_l8b_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <3008000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l9b_2p9: ldo9 {
+                       regulator-name = "vreg_l9b_2p9";
+                       regulator-min-microvolt = <2960000>;
+                       regulator-max-microvolt = <3008000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l11b_1p2: ldo11 {
+                       regulator-name = "vreg_l11b_1p2";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1504000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l12b_1p8: ldo12 {
+                       regulator-name = "vreg_l12b_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l13b_3p0: ldo13 {
+                       regulator-name = "vreg_l13b_3p0";
+                       regulator-min-microvolt = <3000000>;
+                       regulator-max-microvolt = <3000000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l14b_3p2: ldo14 {
+                       regulator-name = "vreg_l14b_3p2";
+                       regulator-min-microvolt = <3200000>;
+                       regulator-max-microvolt = <3200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  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-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l16b_2p8: ldo16 {
+                       regulator-name = "vreg_l16b_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       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,pm8550vs-rpmh-regulators";
+
+               vdd-l1-supply = <&vreg_s4g_1p25>;
+               vdd-l2-supply = <&vreg_s4e_0p95>;
+               vdd-l3-supply = <&vreg_s4e_0p95>;
+
+               qcom,pmic-id = "c";
+
+               vreg_l3c_0p9: ldo3 {
+                       regulator-name = "vreg_l3c_0p9";
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <912000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+       };
+
+       regulators-2 {
+               compatible = "qcom,pm8550vs-rpmh-regulators";
+
+               vdd-l1-supply = <&vreg_s4e_0p95>;
+               vdd-l2-supply = <&vreg_s4e_0p95>;
+               vdd-l3-supply = <&vreg_s4e_0p95>;
+
+               qcom,pmic-id = "d";
+
+               vreg_l1d_0p88: ldo1 {
+                       regulator-name = "vreg_l1d_0p88";
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <920000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               /* ldo2 supplies SM8550 VDD_LPI_MX */
+       };
+
+       regulators-3 {
+               compatible = "qcom,pm8550vs-rpmh-regulators";
+
+               vdd-l1-supply = <&vreg_s4e_0p95>;
+               vdd-l2-supply = <&vreg_s4e_0p95>;
+               vdd-l3-supply = <&vreg_s4g_1p25>;
+               vdd-s4-supply = <&vph_pwr>;
+               vdd-s5-supply = <&vph_pwr>;
+
+               qcom,pmic-id = "e";
+
+               vreg_s4e_0p95: smps4 {
+                       regulator-name = "vreg_s4e_0p95";
+                       regulator-min-microvolt = <904000>;
+                       regulator-max-microvolt = <984000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_s5e_1p08: smps5 {
+                       regulator-name = "vreg_s5e_1p08";
+                       regulator-min-microvolt = <1080000>;
+                       regulator-max-microvolt = <1120000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l1e_0p88: ldo1 {
+                       regulator-name = "vreg_l1e_0p88";
+                       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>;
+               };
+
+               vreg_l2e_0p9: ldo2 {
+                       regulator-name = "vreg_l2e_0p9";
+                       regulator-min-microvolt = <904000>;
+                       regulator-max-microvolt = <970000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  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-4 {
+               compatible = "qcom,pm8550ve-rpmh-regulators";
+
+               vdd-l1-supply = <&vreg_s4e_0p95>;
+               vdd-l2-supply = <&vreg_s4e_0p95>;
+               vdd-l3-supply = <&vreg_s4e_0p95>;
+               vdd-s4-supply = <&vph_pwr>;
+
+               qcom,pmic-id = "f";
+
+               vreg_s4f_0p5: smps4 {
+                       regulator-name = "vreg_s4f_0p5";
+                       regulator-min-microvolt = <500000>;
+                       regulator-max-microvolt = <700000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l1f_0p9: ldo1 {
+                       regulator-name = "vreg_l1f_0p9";
+                       regulator-min-microvolt = <912000>;
+                       regulator-max-microvolt = <912000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l2f_0p88: ldo2 {
+                       regulator-name = "vreg_l2f_0p88";
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <912000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l3f_0p88: ldo3 {
+                       regulator-name = "vreg_l3f_0p88";
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <912000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+       };
+
+       regulators-5 {
+               compatible = "qcom,pm8550vs-rpmh-regulators";
+
+               vdd-l1-supply = <&vreg_s4g_1p25>;
+               vdd-l2-supply = <&vreg_s4g_1p25>;
+               vdd-l3-supply = <&vreg_s4g_1p25>;
+               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>;
+
+               qcom,pmic-id = "g";
+
+               vreg_s1g_1p25: smps1 {
+                       regulator-name = "vreg_s1g_1p25";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1300000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_s2g_0p85: smps2 {
+                       regulator-name = "vreg_s2g_0p85";
+                       regulator-min-microvolt = <800000>;
+                       regulator-max-microvolt = <1000000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_s3g_0p8: smps3 {
+                       regulator-name = "vreg_s3g_0p8";
+                       regulator-min-microvolt = <300000>;
+                       regulator-max-microvolt = <1004000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_s4g_1p25: smps4 {
+                       regulator-name = "vreg_s4g_1p25";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1352000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_s5g_0p85: smps5 {
+                       regulator-name = "vreg_s5g_0p85";
+                       regulator-min-microvolt = <500000>;
+                       regulator-max-microvolt = <1004000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_s6g_1p86: smps6 {
+                       regulator-name = "vreg_s6g_1p86";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <2000000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l1g_1p2: ldo1 {
+                       regulator-name = "vreg_l1g_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_l3g_1p2: ldo3 {
+                       regulator-name = "vreg_l3g_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,pm8010-rpmh-regulators";
+
+               vdd-l1-l2-supply = <&vreg_s4g_1p25>;
+               vdd-l3-l4-supply = <&vreg_bob2>;
+               vdd-l5-supply = <&vreg_s6g_1p86>;
+               vdd-l6-supply = <&vreg_s6g_1p86>;
+               vdd-l7-supply = <&vreg_bob1>;
+
+               qcom,pmic-id = "m";
+
+               vreg_l1m_1p056: ldo1 {
+                       regulator-name = "vreg_l1m_1p056";
+                       regulator-min-microvolt = <1056000>;
+                       regulator-max-microvolt = <1056000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l2m_1p056: ldo2 {
+                       regulator-name = "vreg_l2m_1p056";
+                       regulator-min-microvolt = <1056000>;
+                       regulator-max-microvolt = <1056000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l3m_2p8: ldo3 {
+                       regulator-name = "vreg_l3m_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l4m_2p8: ldo4 {
+                       regulator-name = "vreg_l4m_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l5m_1p8: ldo5 {
+                       regulator-name = "vreg_l5m_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l6m_1p8: ldo6 {
+                       regulator-name = "vreg_l6m_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l7m_2p9: ldo7 {
+                       regulator-name = "vreg_l7m_2p9";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2904000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+       };
+
+       regulators-7 {
+               compatible = "qcom,pm8010-rpmh-regulators";
+
+               vdd-l1-l2-supply = <&vreg_s4g_1p25>;
+               vdd-l3-l4-supply = <&vreg_bob2>;
+               vdd-l5-supply = <&vreg_s6g_1p86>;
+               vdd-l6-supply = <&vreg_bob1>;
+               vdd-l7-supply = <&vreg_bob1>;
+
+               qcom,pmic-id = "n";
+
+               vreg_l1n_1p1: ldo1 {
+                       regulator-name = "vreg_l1n_1p1";
+                       regulator-min-microvolt = <1104000>;
+                       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_l2n_1p1: ldo2 {
+                       regulator-name = "vreg_l2n_1p1";
+                       regulator-min-microvolt = <1104000>;
+                       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_l3n_2p8: ldo3 {
+                       regulator-name = "vreg_l3n_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <3000000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l4n_2p8: ldo4 {
+                       regulator-name = "vreg_l4n_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l5n_1p8: ldo5 {
+                       regulator-name = "vreg_l5n_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l6n_3p3: ldo6 {
+                       regulator-name = "vreg_l6n_3p3";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <3304000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l7n_2p96: ldo7 {
+                       regulator-name = "vreg_l7n_2p96";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+       };
+};
+
+&i2c0 {
+       clock-frequency = <400000>;
+       status = "okay";
+
+       lt9611_codec: hdmi-bridge@2b {
+               compatible = "lontium,lt9611uxc";
+               reg = <0x2b>;
+
+               interrupts-extended = <&tlmm 8 IRQ_TYPE_EDGE_FALLING>;
+
+               reset-gpios = <&tlmm 7 GPIO_ACTIVE_HIGH>;
+
+               vdd-supply = <&lt9611_1v2>;
+               vcc-supply = <&lt9611_3v3>;
+
+               pinctrl-0 = <&lt9611_irq_pin>, <&lt9611_rst_pin>;
+               pinctrl-names = "default";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               lt9611_a: endpoint {
+                                       remote-endpoint = <&mdss_dsi0_out>;
+                               };
+                       };
+
+                       port@2 {
+                               reg = <2>;
+
+                               lt9611_out: endpoint {
+                                       remote-endpoint = <&hdmi_connector_out>;
+                               };
+                       };
+               };
+       };
+};
+
+&i2c_hub_2 {
+       status = "okay";
+
+       typec-mux@42 {
+               compatible = "fcs,fsa4480";
+               reg = <0x42>;
+
+               vcc-supply = <&vreg_bob1>;
+
+               mode-switch;
+               orientation-switch;
+
+               port {
+                       fsa4480_sbu_mux: endpoint {
+                               remote-endpoint = <&pmic_glink_sbu>;
+                       };
+               };
+       };
+};
+
+&i2c_master_hub_0 {
+       status = "okay";
+};
+
+&ipa {
+       qcom,gsi-loader = "self";
+       memory-region = <&ipa_fw_mem>;
+       firmware-name = "qcom/sm8550/ipa_fws.mbn";
+       status = "okay";
+};
+
+&gpi_dma1 {
+       status = "okay";
+};
+
+&gpu {
+       status = "okay";
+
+       zap-shader {
+               firmware-name = "qcom/sm8550/a740_zap.mbn";
+       };
+};
+
+&lpass_tlmm {
+       spkr_1_sd_n_active: spkr-1-sd-n-active-state {
+               pins = "gpio17";
+               function = "gpio";
+               drive-strength = <16>;
+               bias-disable;
+               output-low;
+       };
+
+       spkr_2_sd_n_active: spkr-2-sd-n-active-state {
+               pins = "gpio18";
+               function = "gpio";
+               drive-strength = <16>;
+               bias-disable;
+               output-low;
+       };
+};
+
+&mdss {
+       status = "okay";
+};
+
+&mdss_dsi0 {
+       vdda-supply = <&vreg_l3e_1p2>;
+       status = "okay";
+};
+
+&mdss_dsi0_out {
+       remote-endpoint = <&lt9611_a>;
+       data-lanes = <0 1 2 3>;
+};
+
+&mdss_dsi0_phy {
+       vdds-supply = <&vreg_l1e_0p88>;
+       status = "okay";
+};
+
+&mdss_dp0 {
+       status = "okay";
+};
+
+&mdss_dp0_out {
+       remote-endpoint = <&usb_dp_qmpphy_dp_in>;
+       data-lanes = <0 1>;
+};
+
+&pcie0 {
+       wake-gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>;
+       perst-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>;
+
+       pinctrl-0 = <&pcie0_default_state>;
+       pinctrl-names = "default";
+
+       status = "okay";
+};
+
+&pcie0_phy {
+       vdda-phy-supply = <&vreg_l1e_0p88>;
+       vdda-pll-supply = <&vreg_l3e_1p2>;
+
+       status = "okay";
+};
+
+&pcie1 {
+       wake-gpios = <&tlmm 99 GPIO_ACTIVE_HIGH>;
+       perst-gpios = <&tlmm 97 GPIO_ACTIVE_LOW>;
+
+       pinctrl-0 = <&pcie1_default_state>;
+       pinctrl-names = "default";
+
+       status = "okay";
+};
+
+&pcie1_phy {
+       vdda-phy-supply = <&vreg_l3c_0p9>;
+       vdda-pll-supply = <&vreg_l3e_1p2>;
+       vdda-qref-supply = <&vreg_l1e_0p88>;
+
+       status = "okay";
+};
+
+&pcie_1_phy_aux_clk {
+       clock-frequency = <1000>;
+};
+
+&pm8550_gpios {
+       sdc2_card_det_n: sdc2-card-det-state {
+               pins = "gpio12";
+               function = "normal";
+               input-enable;
+               output-disable;
+               bias-pull-up;
+               power-source = <1>; /* 1.8 V */
+       };
+
+       volume_up_n: volume-up-n-state {
+               pins = "gpio6";
+               function = "normal";
+               power-source = <1>;
+               bias-pull-up;
+               input-enable;
+       };
+};
+
+/* The RGB signals are routed to 3 separate LEDs on the HDK8550 */
+&pm8550_pwm {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       status = "okay";
+
+       led@1 {
+               reg = <1>;
+               function = LED_FUNCTION_STATUS;
+               color = <LED_COLOR_ID_RED>;
+               default-state = "off";
+       };
+
+       led@2 {
+               reg = <2>;
+               function = LED_FUNCTION_STATUS;
+               color = <LED_COLOR_ID_GREEN>;
+               default-state = "off";
+       };
+
+       led@3 {
+               reg = <3>;
+               function = LED_FUNCTION_STATUS;
+               color = <LED_COLOR_ID_BLUE>;
+               default-state = "off";
+       };
+};
+
+&pm8550b_eusb2_repeater {
+       vdd18-supply = <&vreg_l15b_1p8>;
+       vdd3-supply = <&vreg_l5b_3p1>;
+};
+
+&pon_pwrkey {
+       status = "okay";
+};
+
+&pon_resin {
+       linux,code = <KEY_VOLUMEDOWN>;
+
+       status = "okay";
+};
+
+&qupv3_id_0 {
+       status = "okay";
+};
+
+&qupv3_id_1 {
+       status = "okay";
+};
+
+&remoteproc_adsp {
+       firmware-name = "qcom/sm8550/adsp.mbn",
+                       "qcom/sm8550/adsp_dtb.mbn";
+       status = "okay";
+};
+
+&remoteproc_cdsp {
+       firmware-name = "qcom/sm8550/cdsp.mbn",
+                       "qcom/sm8550/cdsp_dtb.mbn";
+       status = "okay";
+};
+
+&remoteproc_mpss {
+       firmware-name = "qcom/sm8550/modem.mbn",
+                       "qcom/sm8550/modem_dtb.mbn";
+       status = "okay";
+};
+
+&sdhc_2 {
+       cd-gpios = <&pm8550_gpios 12 GPIO_ACTIVE_HIGH>;
+
+       pinctrl-0 = <&sdc2_default>, <&sdc2_card_det_n>;
+       pinctrl-1 = <&sdc2_sleep>, <&sdc2_card_det_n>;
+       pinctrl-names = "default", "sleep";
+
+       vmmc-supply = <&vreg_l9b_2p9>;
+       vqmmc-supply = <&vreg_l8b_1p8>;
+
+       bus-width = <4>;
+       no-sdio;
+       no-mmc;
+
+       status = "okay";
+};
+
+&sleep_clk {
+       clock-frequency = <32000>;
+};
+
+&swr0 {
+       status = "okay";
+
+       /* WSA8845, Speaker North */
+       north_spkr: speaker@0,0 {
+               compatible = "sdw20217020400";
+               reg = <0 0>;
+
+               pinctrl-0 = <&spkr_1_sd_n_active>;
+               pinctrl-names = "default";
+
+               powerdown-gpios = <&lpass_tlmm 17 GPIO_ACTIVE_LOW>;
+
+               vdd-1p8-supply = <&vreg_l15b_1p8>;
+               vdd-io-supply = <&vreg_l15b_1p8>;
+
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "SpkrLeft";
+       };
+
+       /* WSA8845, Speaker South */
+       south_spkr: speaker@0,1 {
+               compatible = "sdw20217020400";
+               reg = <0 1>;
+
+               pinctrl-0 = <&spkr_2_sd_n_active>;
+               pinctrl-names = "default";
+
+               powerdown-gpios = <&lpass_tlmm 18 GPIO_ACTIVE_LOW>;
+
+               vdd-1p8-supply = <&vreg_l15b_1p8>;
+               vdd-io-supply = <&vreg_l15b_1p8>;
+
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "SpkrRight";
+       };
+};
+
+&swr1 {
+       status = "okay";
+
+       /* WCD9385 RX */
+       wcd_rx: codec@0,4 {
+               compatible = "sdw20217010d00";
+               reg = <0 4>;
+
+               /*
+                * WCD9385 RX Port 1 (HPH_L/R)      <=> SWR1 Port 1 (HPH_L/R)
+                * WCD9385 RX Port 2 (CLSH)         <=> SWR1 Port 2 (CLSH)
+                * WCD9385 RX Port 3 (COMP_L/R)     <=> SWR1 Port 3 (COMP_L/R)
+                * WCD9385 RX Port 4 (LO)           <=> SWR1 Port 4 (LO)
+                * WCD9385 RX Port 5 (DSD_L/R)      <=> SWR1 Port 5 (DSD_L/R)
+                */
+               qcom,rx-port-mapping = <1 2 3 4 5>;
+       };
+};
+
+&swr2 {
+       status = "okay";
+
+       /* WCD9385 TX */
+       wcd_tx: codec@0,3 {
+               compatible = "sdw20217010d00";
+               reg = <0 3>;
+
+               /*
+                * WCD9385 TX Port 1 (ADC1,2)             <=> SWR2 Port 2 (TX SWR_INPUT 0,1,2,3)
+                * WCD9385 TX Port 2 (ADC3,4)             <=> SWR2 Port 2 (TX SWR_INPUT 0,1,2,3)
+                * WCD9385 TX Port 3 (DMIC0,1,2,3 & MBHC) <=> SWR2 Port 3 (TX SWR_INPUT 4,5,6,7)
+                * WCD9385 TX Port 4 (DMIC4,5,6,7)        <=> SWR2 Port 4 (TX SWR_INPUT 8,9,10,11)
+                */
+               qcom,tx-port-mapping = <2 2 3 4>;
+       };
+};
+
+&tlmm {
+       /* Reserved I/Os for NFC */
+       gpio-reserved-ranges = <32 8>;
+
+       bt_default: bt-default-state {
+               bt-en-pins {
+                       pins = "gpio81";
+                       function = "gpio";
+                       drive-strength = <16>;
+                       bias-disable;
+               };
+
+               sw-ctrl-pins {
+                       pins = "gpio82";
+                       function = "gpio";
+                       bias-pull-down;
+               };
+       };
+
+       lt9611_irq_pin: lt9611-irq-state {
+               pins = "gpio8";
+               function = "gpio";
+               bias-disable;
+       };
+
+       lt9611_rst_pin: lt9611-rst-state {
+               pins = "gpio7";
+               function = "gpio";
+               output-high;
+       };
+
+       wcd_default: wcd-reset-n-active-state {
+               pins = "gpio108";
+               function = "gpio";
+               drive-strength = <16>;
+               bias-disable;
+               output-low;
+       };
+};
+
+&uart7 {
+       status = "okay";
+};
+
+&uart14 {
+       status = "okay";
+
+       bluetooth {
+               compatible = "qcom,wcn7850-bt";
+
+               vddio-supply = <&vreg_l15b_1p8>;
+               vddaon-supply = <&vreg_s4e_0p95>;
+               vdddig-supply = <&vreg_s4e_0p95>;
+               vddrfa0p8-supply = <&vreg_s4e_0p95>;
+               vddrfa1p2-supply = <&vreg_s4g_1p25>;
+               vddrfa1p9-supply = <&vreg_s6g_1p86>;
+
+               max-speed = <3200000>;
+
+               enable-gpios = <&tlmm 81 GPIO_ACTIVE_HIGH>;
+               swctrl-gpios = <&tlmm 82 GPIO_ACTIVE_HIGH>;
+
+               pinctrl-0 = <&bt_default>;
+               pinctrl-names = "default";
+       };
+};
+
+&ufs_mem_hc {
+       reset-gpios = <&tlmm 210 GPIO_ACTIVE_LOW>;
+
+       vcc-supply = <&vreg_l17b_2p5>;
+       vcc-max-microamp = <1300000>;
+       vccq-supply = <&vreg_l1g_1p2>;
+       vccq-max-microamp = <1200000>;
+       vdd-hba-supply = <&vreg_l3g_1p2>;
+
+       status = "okay";
+};
+
+&ufs_mem_phy {
+       vdda-phy-supply = <&vreg_l1d_0p88>;
+       vdda-pll-supply = <&vreg_l3e_1p2>;
+
+       status = "okay";
+};
+
+&usb_1 {
+       status = "okay";
+};
+
+&usb_1_dwc3 {
+       dr_mode = "otg";
+       usb-role-switch;
+};
+
+&usb_1_dwc3_hs {
+       remote-endpoint = <&pmic_glink_hs_in>;
+};
+
+&usb_1_dwc3_ss {
+       remote-endpoint = <&usb_dp_qmpphy_usb_ss_in>;
+};
+
+&usb_1_hsphy {
+       vdd-supply = <&vreg_l1e_0p88>;
+       vdda12-supply = <&vreg_l3e_1p2>;
+
+       phys = <&pm8550b_eusb2_repeater>;
+
+       status = "okay";
+};
+
+&usb_dp_qmpphy {
+       vdda-phy-supply = <&vreg_l3e_1p2>;
+       vdda-pll-supply = <&vreg_l3f_0p88>;
+
+       orientation-switch;
+
+       status = "okay";
+};
+
+&usb_dp_qmpphy_dp_in {
+       remote-endpoint = <&mdss_dp0_out>;
+};
+
+&usb_dp_qmpphy_out {
+       remote-endpoint = <&pmic_glink_ss_in>;
+};
+
+&usb_dp_qmpphy_usb_ss_in {
+       remote-endpoint = <&usb_1_dwc3_ss>;
+};
+
+&xo_board {
+       clock-frequency = <76800000>;
+};
index c1135ad5fa696f5b2eb81a77819d9d55a23cbd70..3d4ad5aac70fa5e74aad9830be6131332c5f629a 100644 (file)
                                "SpkrRight IN", "WSA_SPK2 OUT",
                                "IN1_HPHL", "HPHL_OUT",
                                "IN2_HPHR", "HPHR_OUT",
+                               "AMIC1", "MIC BIAS1",
                                "AMIC2", "MIC BIAS2",
+                               "AMIC3", "MIC BIAS3",
+                               "AMIC4", "MIC BIAS3",
+                               "AMIC5", "MIC BIAS4",
                                "VA DMIC0", "MIC BIAS1",
                                "VA DMIC1", "MIC BIAS1",
                                "VA DMIC2", "MIC BIAS3",
                                "TX DMIC0", "MIC BIAS1",
                                "TX DMIC1", "MIC BIAS2",
                                "TX DMIC2", "MIC BIAS3",
-                               "TX SWR_ADC1", "ADC2_OUTPUT";
+                               "TX SWR_INPUT0", "ADC1_OUTPUT",
+                               "TX SWR_INPUT1", "ADC2_OUTPUT",
+                               "TX SWR_INPUT0", "ADC3_OUTPUT",
+                               "TX SWR_INPUT1", "ADC4_OUTPUT";
 
                wcd-playback-dai-link {
                        link-name = "WCD Playback";
        wcd_tx: codec@0,3 {
                compatible = "sdw20217010d00";
                reg = <0 3>;
-               qcom,tx-port-mapping = <1 1 2 3>;
+               qcom,tx-port-mapping = <2 2 3 4>;
        };
 };
 
index d401d63e5c4d2aff90a9845efa757ce584aae538..92f0150174187dab2d5194041838b4c4eac49e90 100644 (file)
                                "SpkrRight IN", "WSA_SPK2 OUT",
                                "IN1_HPHL", "HPHL_OUT",
                                "IN2_HPHR", "HPHR_OUT",
+                               "AMIC1", "MIC BIAS1",
                                "AMIC2", "MIC BIAS2",
+                               "AMIC3", "MIC BIAS3",
+                               "AMIC4", "MIC BIAS3",
+                               "AMIC5", "MIC BIAS4",
                                "VA DMIC0", "MIC BIAS1",
                                "VA DMIC1", "MIC BIAS1",
                                "VA DMIC2", "MIC BIAS3",
                                "TX DMIC0", "MIC BIAS1",
                                "TX DMIC1", "MIC BIAS2",
                                "TX DMIC2", "MIC BIAS3",
-                               "TX SWR_ADC1", "ADC2_OUTPUT";
+                               "TX SWR_INPUT0", "ADC1_OUTPUT",
+                               "TX SWR_INPUT1", "ADC2_OUTPUT",
+                               "TX SWR_INPUT0", "ADC3_OUTPUT",
+                               "TX SWR_INPUT1", "ADC4_OUTPUT";
 
                wcd-playback-dai-link {
                        link-name = "WCD Playback";
                 <&usb_dp_qmpphy QMP_USB43DP_USB3_PIPE_CLK>;
 };
 
+&gpi_dma1 {
+       status = "okay";
+};
+
 &gpu {
        status = "okay";
 
        };
 };
 
+&spi4 {
+       status = "okay";
+
+       touchscreen@0 {
+               compatible = "goodix,gt9916";
+               reg = <0>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
+
+               reset-gpios = <&tlmm 24 GPIO_ACTIVE_LOW>;
+
+               avdd-supply = <&vreg_l14b_3p2>;
+
+               spi-max-frequency = <1000000>;
+
+               touchscreen-size-x = <1080>;
+               touchscreen-size-y = <2400>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&ts_irq>, <&ts_reset>;
+       };
+};
+
 &swr1 {
        status = "okay";
 
        wcd_tx: codec@0,3 {
                compatible = "sdw20217010d00";
                reg = <0 3>;
-               qcom,tx-port-mapping = <1 1 2 3>;
+               qcom,tx-port-mapping = <2 2 3 4>;
        };
 };
 
                bias-pull-down;
        };
 
+       ts_irq: ts-irq-state {
+               pins = "gpio25";
+               function = "gpio";
+               drive-strength = <8>;
+               bias-pull-up;
+       };
+
+       ts_reset: ts-reset-state {
+               pins = "gpio24";
+               function = "gpio";
+               drive-strength = <8>;
+               bias-pull-up;
+       };
+
        wcd_default: wcd-reset-n-active-state {
                pins = "gpio108";
                function = "gpio";
index ee1ba5a8c8fc2fc25345f5b356b9f9f410f70b6a..3904348075f67945a9e54117a518631541806ad9 100644 (file)
                        linux,pci-domain = <0>;
                        num-lanes = <2>;
 
-                       interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
-
+                       interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                                        <&gem_noc MASTER_APPSS_PROC 0 &cnoc_main SLAVE_PCIE_0 0>;
                        interconnect-names = "pcie-mem", "cpu-pcie";
 
+                       /* Entries are reversed due to the unusual ITS DeviceID encoding */
+                       msi-map = <0x0 &gic_its 0x1401 0x1>,
+                                 <0x100 &gic_its 0x1400 0x1>;
                        iommu-map = <0x0   &apps_smmu 0x1400 0x1>,
                                    <0x100 &apps_smmu 0x1401 0x1>;
 
                        linux,pci-domain = <1>;
                        num-lanes = <2>;
 
-                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
-
+                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
                        interrupt-map = <0 0 0 1 &intc 0 0 0 434 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
                                        <&gem_noc MASTER_APPSS_PROC 0 &cnoc_main SLAVE_PCIE_1 0>;
                        interconnect-names = "pcie-mem", "cpu-pcie";
 
+                       /* Entries are reversed due to the unusual ITS DeviceID encoding */
+                       msi-map = <0x0 &gic_its 0x1481 0x1>,
+                                 <0x100 &gic_its 0x1480 0x1>;
                        iommu-map = <0x0   &apps_smmu 0x1480 0x1>,
                                    <0x100 &apps_smmu 0x1481 0x1>;
 
                ufs_mem_phy: phy@1d80000 {
                        compatible = "qcom,sm8550-qmp-ufs-phy";
                        reg = <0x0 0x01d80000 0x0 0x2000>;
-                       clocks = <&tcsr TCSR_UFS_CLKREF_EN>,
-                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
-                       clock-names = "ref", "ref_aux";
+                       clocks = <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>,
+                                <&tcsr TCSR_UFS_CLKREF_EN>;
+                       clock-names = "ref",
+                                     "ref_aux",
+                                     "qref";
 
                        power-domains = <&gcc UFS_MEM_PHY_GDSC>;
 
                        iommus = <&apps_smmu 0x60 0x0>;
                        dma-coherent;
 
+                       operating-points-v2 = <&ufs_opp_table>;
                        interconnects = <&aggre1_noc MASTER_UFS_MEM 0 &mc_virt SLAVE_EBI1 0>,
                                        <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_UFS_MEM_CFG 0>;
 
                                 <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>,
                                 <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>,
                                 <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>;
-                       freq-table-hz =
-                               <75000000 300000000>,
-                               <0 0>,
-                               <0 0>,
-                               <75000000 300000000>,
-                               <100000000 403000000>,
-                               <0 0>,
-                               <0 0>,
-                               <0 0>;
                        qcom,ice = <&ice>;
 
                        status = "disabled";
+
+                       ufs_opp_table: opp-table {
+                               compatible = "operating-points-v2";
+
+                               opp-75000000 {
+                                       opp-hz = /bits/ 64 <75000000>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <75000000>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <0>;
+                                       required-opps = <&rpmhpd_opp_low_svs>;
+                               };
+
+                               opp-150000000 {
+                                       opp-hz = /bits/ 64 <150000000>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <150000000>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <0>;
+                                       required-opps = <&rpmhpd_opp_svs>;
+                               };
+
+                               opp-300000000 {
+                                       opp-hz = /bits/ 64 <300000000>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <300000000>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <0>,
+                                                /bits/ 64 <0>;
+                                       required-opps = <&rpmhpd_opp_nom>;
+                               };
+                       };
                };
 
                ice: crypto@1d88000 {
                        operating-points-v2 = <&gpu_opp_table>;
 
                        qcom,gmu = <&gmu>;
+                       #cooling-cells = <2>;
 
                        status = "disabled";
 
                                };
                        };
 
-                       dmic02_default: dmic02-default-state {
+                       dmic23_default: dmic23-default-state {
                                clk-pins {
                                        pins = "gpio8";
                                        function = "dmic2_clk";
                        assigned-clock-rates = <19200000>, <200000000>;
 
                        interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>,
                                              <&pdc 15 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>;
-                       interrupt-names = "hs_phy_irq",
-                                         "ss_phy_irq",
+                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "hs_phy_irq",
+                                         "dp_hs_phy_irq",
                                          "dm_hs_phy_irq",
-                                         "dp_hs_phy_irq";
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
                        required-opps = <&rpmhpd_opp_nom>;
                spmi_bus: spmi@c400000 {
                        compatible = "qcom,spmi-pmic-arb";
                        reg = <0 0x0c400000 0 0x3000>,
-                             <0 0x0c500000 0 0x4000000>,
+                             <0 0x0c500000 0 0x400000>,
                              <0 0x0c440000 0 0x80000>,
                              <0 0x0c4c0000 0 0x20000>,
                              <0 0x0c42d000 0 0x4000>;
                                                reg = <3>;
                                                iommus = <&apps_smmu 0x1003 0x80>,
                                                         <&apps_smmu 0x1063 0x0>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@4 {
                                                reg = <4>;
                                                iommus = <&apps_smmu 0x1004 0x80>,
                                                         <&apps_smmu 0x1064 0x0>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@5 {
                                                reg = <5>;
                                                iommus = <&apps_smmu 0x1005 0x80>,
                                                         <&apps_smmu 0x1065 0x0>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@6 {
                                                reg = <6>;
                                                iommus = <&apps_smmu 0x1006 0x80>,
                                                         <&apps_smmu 0x1066 0x0>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@7 {
                                                reg = <7>;
                                                iommus = <&apps_smmu 0x1007 0x80>,
                                                         <&apps_smmu 0x1067 0x0>;
+                                               dma-coherent;
                                        };
                                };
 
                                                iommus = <&apps_smmu 0x1961 0x0>,
                                                         <&apps_smmu 0x0c01 0x20>,
                                                         <&apps_smmu 0x19c1 0x10>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@2 {
                                                iommus = <&apps_smmu 0x1962 0x0>,
                                                         <&apps_smmu 0x0c02 0x20>,
                                                         <&apps_smmu 0x19c2 0x10>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@3 {
                                                iommus = <&apps_smmu 0x1963 0x0>,
                                                         <&apps_smmu 0x0c03 0x20>,
                                                         <&apps_smmu 0x19c3 0x10>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@4 {
                                                iommus = <&apps_smmu 0x1964 0x0>,
                                                         <&apps_smmu 0x0c04 0x20>,
                                                         <&apps_smmu 0x19c4 0x10>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@5 {
                                                iommus = <&apps_smmu 0x1965 0x0>,
                                                         <&apps_smmu 0x0c05 0x20>,
                                                         <&apps_smmu 0x19c5 0x10>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@6 {
                                                iommus = <&apps_smmu 0x1966 0x0>,
                                                         <&apps_smmu 0x0c06 0x20>,
                                                         <&apps_smmu 0x19c6 0x10>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@7 {
                                                iommus = <&apps_smmu 0x1967 0x0>,
                                                         <&apps_smmu 0x0c07 0x20>,
                                                         <&apps_smmu 0x19c7 0x10>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@8 {
                                                iommus = <&apps_smmu 0x1968 0x0>,
                                                         <&apps_smmu 0x0c08 0x20>,
                                                         <&apps_smmu 0x19c8 0x10>;
+                                               dma-coherent;
                                        };
 
                                        /* note: secure cb9 in downstream */
                        polling-delay = <0>;
                        thermal-sensors = <&tsens2 1>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu0_junction_config>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                thermal-engine-config {
                                        temperature = <125000>;
                        polling-delay = <0>;
                        thermal-sensors = <&tsens2 2>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu1_junction_config>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                thermal-engine-config {
                                        temperature = <125000>;
                        polling-delay = <0>;
                        thermal-sensors = <&tsens2 3>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu2_junction_config>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                thermal-engine-config {
                                        temperature = <125000>;
                        polling-delay = <0>;
                        thermal-sensors = <&tsens2 4>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu3_junction_config>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                thermal-engine-config {
                                        temperature = <125000>;
                        polling-delay = <0>;
                        thermal-sensors = <&tsens2 5>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu4_junction_config>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                thermal-engine-config {
                                        temperature = <125000>;
                        polling-delay = <0>;
                        thermal-sensors = <&tsens2 6>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu5_junction_config>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                thermal-engine-config {
                                        temperature = <125000>;
                        polling-delay = <0>;
                        thermal-sensors = <&tsens2 7>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu6_junction_config>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                thermal-engine-config {
                                        temperature = <125000>;
                        polling-delay = <0>;
                        thermal-sensors = <&tsens2 8>;
 
+                       cooling-maps {
+                               map0 {
+                                       trip = <&gpu7_junction_config>;
+                                       cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+
                        trips {
                                thermal-engine-config {
                                        temperature = <125000>;
index 9d916edb1c73c10ef5e4fde52e33b75ff902a957..4450273f96671b53896c48c26b19fc06c648beb6 100644 (file)
                };
        };
 
+       sound {
+               compatible = "qcom,sm8650-sndcard", "qcom,sm8450-sndcard";
+               model = "SM8650-MTP";
+               audio-routing = "SpkrLeft IN", "WSA_SPK1 OUT",
+                               "SpkrRight IN", "WSA_SPK2 OUT";
+
+               wsa-dai-link {
+                       link-name = "WSA Playback";
+
+                       cpu {
+                               sound-dai = <&q6apmbedai WSA_CODEC_DMA_RX_0>;
+                       };
+
+                       codec {
+                               sound-dai = <&left_spkr>, <&right_spkr>, <&swr0 0>, <&lpass_wsamacro 0>;
+                       };
+
+                       platform {
+                               sound-dai = <&q6apm>;
+                       };
+               };
+       };
+
        vph_pwr: vph-pwr-regulator {
                compatible = "regulator-fixed";
 
                                                   RPMH_REGULATOR_MODE_HPM>;
                };
        };
+
+       regulators-6 {
+               compatible = "qcom,pm8010-rpmh-regulators";
+               qcom,pmic-id = "m";
+
+               vdd-l1-l2-supply = <&vreg_s1c_1p2>;
+               vdd-l3-l4-supply = <&vreg_bob2>;
+               vdd-l5-supply = <&vreg_s6c_1p8>;
+               vdd-l6-supply = <&vreg_bob1>;
+               vdd-l7-supply = <&vreg_bob1>;
+
+               vreg_l1m_1p1: ldo1 {
+                       regulator-name = "vreg_l1m_1p1";
+                       regulator-min-microvolt = <1104000>;
+                       regulator-max-microvolt = <1104000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l2m_1p056: ldo2 {
+                       regulator-name = "vreg_l2m_1p056";
+                       regulator-min-microvolt = <1056000>;
+                       regulator-max-microvolt = <1056000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l3m_2p8: ldo3 {
+                       regulator-name = "vreg_l3m_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l4m_2p8: ldo4 {
+                       regulator-name = "vreg_l4m_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l5m_1p8: ldo5 {
+                       regulator-name = "vreg_l5m_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l6m_2p8: ldo6 {
+                       regulator-name = "vreg_l6m_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l7m_2p96: ldo7 {
+                       regulator-name = "vreg_l7m_2p96";
+                       regulator-min-microvolt = <2960000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+       };
+
+       regulators-7 {
+               compatible = "qcom,pm8010-rpmh-regulators";
+               qcom,pmic-id = "n";
+
+               vdd-l1-l2-supply = <&vreg_s1c_1p2>;
+               vdd-l3-l4-supply = <&vreg_s6c_1p8>;
+               vdd-l5-supply = <&vreg_bob2>;
+               vdd-l6-supply = <&vreg_bob2>;
+               vdd-l7-supply = <&vreg_bob1>;
+
+               vreg_l1n_1p1: ldo1 {
+                       regulator-name = "vreg_l1n_1p1";
+                       regulator-min-microvolt = <1104000>;
+                       regulator-max-microvolt = <1104000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l2n_1p056: ldo2 {
+                       regulator-name = "vreg_l2n_1p056";
+                       regulator-min-microvolt = <1056000>;
+                       regulator-max-microvolt = <1056000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l3n_1p8: ldo3 {
+                       regulator-name = "vreg_l3n_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l4n_1p8: ldo4 {
+                       regulator-name = "vreg_l4n_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l5n_2p8: ldo5 {
+                       regulator-name = "vreg_l5n_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l6n_2p8: ldo6 {
+                       regulator-name = "vreg_l6n_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l7n_3p3: ldo7 {
+                       regulator-name = "vreg_l7n_3p3";
+                       regulator-min-microvolt = <3304000>;
+                       regulator-max-microvolt = <3304000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+       };
 };
 
 &dispcc {
 
 &tlmm {
        /* Reserved I/Os for NFC */
-       gpio-reserved-ranges = <32 8>;
+       gpio-reserved-ranges = <32 8>, <74 1>;
 
        disp0_reset_n_active: disp0-reset-n-active-state {
                pins = "gpio133";
index 592a67a47c782f667cd48d8d8bcad7d457a84ee4..b07cac2e5bc802ba667d054eb923b8b0e1bc0d46 100644 (file)
                                        reg = <1>;
 
                                        pmic_glink_ss_in: endpoint {
-                                               remote-endpoint = <&usb_1_dwc3_ss>;
+                                               remote-endpoint = <&redriver_ss_out>;
                                        };
                                };
+
+                               port@2 {
+                                       reg = <2>;
+
+                                       pmic_glink_sbu: endpoint {
+                                               remote-endpoint = <&wcd_usbss_sbu_mux>;
+                                   };
+                               };
+                       };
+               };
+       };
+
+       sound {
+               compatible = "qcom,sm8650-sndcard", "qcom,sm8450-sndcard";
+               model = "SM8650-QRD";
+               audio-routing = "SpkrLeft IN", "WSA_SPK1 OUT",
+                               "SpkrRight IN", "WSA_SPK2 OUT",
+                               "IN1_HPHL", "HPHL_OUT",
+                               "IN2_HPHR", "HPHR_OUT",
+                               "AMIC1", "MIC BIAS1",
+                               "AMIC2", "MIC BIAS2",
+                               "AMIC3", "MIC BIAS3",
+                               "AMIC4", "MIC BIAS3",
+                               "AMIC5", "MIC BIAS4",
+                               "TX SWR_INPUT0", "ADC1_OUTPUT",
+                               "TX SWR_INPUT1", "ADC2_OUTPUT",
+                               "TX SWR_INPUT2", "ADC3_OUTPUT",
+                               "TX SWR_INPUT3", "ADC4_OUTPUT";
+
+               wcd-playback-dai-link {
+                       link-name = "WCD Playback";
+
+                       cpu {
+                               sound-dai = <&q6apmbedai RX_CODEC_DMA_RX_0>;
+                       };
+
+                       codec {
+                               sound-dai = <&wcd939x 0>, <&swr1 0>, <&lpass_rxmacro 0>;
+                       };
+
+                       platform {
+                               sound-dai = <&q6apm>;
+                       };
+               };
+
+               wcd-capture-dai-link {
+                       link-name = "WCD Capture";
+
+                       cpu {
+                               sound-dai = <&q6apmbedai TX_CODEC_DMA_TX_3>;
+                       };
+
+                       codec {
+                               sound-dai = <&wcd939x 1>, <&swr2 0>, <&lpass_txmacro 0>;
+                       };
+
+                       platform {
+                               sound-dai = <&q6apm>;
+                       };
+               };
+
+               wsa-dai-link {
+                       link-name = "WSA Playback";
+
+                       cpu {
+                               sound-dai = <&q6apmbedai WSA_CODEC_DMA_RX_0>;
+                       };
+
+                       codec {
+                               sound-dai = <&left_spkr>, <&right_spkr>, <&swr0 0>, <&lpass_wsamacro 0>;
+                       };
+
+                       platform {
+                               sound-dai = <&q6apm>;
                        };
                };
        };
                regulator-always-on;
                regulator-boot-on;
        };
+
+       wcd939x: audio-codec {
+               compatible = "qcom,wcd9395-codec", "qcom,wcd9390-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 107 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>;
+
+               mode-switch;
+               orientation-switch;
+
+               port {
+                       wcd_codec_headset_in: endpoint {
+                               remote-endpoint = <&wcd_usbss_headset_out>;
+                       };
+               };
+       };
 };
 
 &apps_rsc {
                                                   RPMH_REGULATOR_MODE_HPM>;
                };
        };
+
+       regulators-6 {
+               compatible = "qcom,pm8010-rpmh-regulators";
+               qcom,pmic-id = "m";
+
+               vdd-l1-l2-supply = <&vreg_s1c_1p2>;
+               vdd-l3-l4-supply = <&vreg_bob2>;
+               vdd-l5-supply = <&vreg_s6c_1p8>;
+               vdd-l6-supply = <&vreg_bob1>;
+               vdd-l7-supply = <&vreg_bob1>;
+
+               vreg_l1m_1p1: ldo1 {
+                       regulator-name = "vreg_l1m_1p1";
+                       regulator-min-microvolt = <1104000>;
+                       regulator-max-microvolt = <1104000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l2m_1p056: ldo2 {
+                       regulator-name = "vreg_l2m_1p056";
+                       regulator-min-microvolt = <1056000>;
+                       regulator-max-microvolt = <1056000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l3m_2p8: ldo3 {
+                       regulator-name = "vreg_l3m_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l4m_2p8: ldo4 {
+                       regulator-name = "vreg_l4m_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l5m_1p8: ldo5 {
+                       regulator-name = "vreg_l5m_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l6m_2p8: ldo6 {
+                       regulator-name = "vreg_l6m_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l7m_2p96: ldo7 {
+                       regulator-name = "vreg_l7m_2p96";
+                       regulator-min-microvolt = <2960000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+       };
+
+       regulators-7 {
+               compatible = "qcom,pm8010-rpmh-regulators";
+               qcom,pmic-id = "n";
+
+               vdd-l1-l2-supply = <&vreg_s1c_1p2>;
+               vdd-l3-l4-supply = <&vreg_s6c_1p8>;
+               vdd-l5-supply = <&vreg_bob2>;
+               vdd-l6-supply = <&vreg_bob2>;
+               vdd-l7-supply = <&vreg_bob1>;
+
+               vreg_l1n_1p1: ldo1 {
+                       regulator-name = "vreg_l1n_1p1";
+                       regulator-min-microvolt = <1104000>;
+                       regulator-max-microvolt = <1104000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l2n_1p056: ldo2 {
+                       regulator-name = "vreg_l2n_1p056";
+                       regulator-min-microvolt = <1056000>;
+                       regulator-max-microvolt = <1056000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+                                                  RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l3n_1p8: ldo3 {
+                       regulator-name = "vreg_l3n_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l4n_1p8: ldo4 {
+                       regulator-name = "vreg_l4n_1p8";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l5n_2p8: ldo5 {
+                       regulator-name = "vreg_l5n_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l6n_2p8: ldo6 {
+                       regulator-name = "vreg_l6n_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l7n_3p3: ldo7 {
+                       regulator-name = "vreg_l7n_3p3";
+                       regulator-min-microvolt = <3304000>;
+                       regulator-max-microvolt = <3304000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+       };
 };
 
 &dispcc {
        status = "okay";
 };
 
+&i2c3 {
+       status = "okay";
+
+       wcd_usbss: typec-mux@e {
+               compatible = "qcom,wcd9395-usbss", "qcom,wcd9390-usbss";
+               reg = <0xe>;
+
+               vdd-supply = <&vreg_l15b_1p8>;
+               reset-gpios = <&tlmm 152 GPIO_ACTIVE_HIGH>;
+
+               mode-switch;
+               orientation-switch;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               wcd_usbss_sbu_mux: endpoint {
+                                       remote-endpoint = <&pmic_glink_sbu>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               wcd_usbss_headset_out: endpoint {
+                                       remote-endpoint = <&wcd_codec_headset_in>;
+                               };
+                       };
+               };
+       };
+};
+
+&i2c6 {
+       status = "okay";
+
+       typec-mux@1c {
+               compatible = "onnn,nb7vpq904m";
+               reg = <0x1c>;
+
+               vcc-supply = <&vreg_l15b_1p8>;
+
+               retimer-switch;
+               orientation-switch;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               redriver_ss_out: endpoint {
+                                       remote-endpoint = <&pmic_glink_ss_in>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               redriver_ss_in: endpoint {
+                                       data-lanes = <3 2 1 0>;
+                                       remote-endpoint = <&usb_dp_qmpphy_out>;
+                               };
+                       };
+               };
+       };
+};
+
 &ipa {
        qcom,gsi-loader = "self";
        memory-region = <&ipa_fw_mem>;
        status = "okay";
 };
 
+&lpass_tlmm {
+       spkr_1_sd_n_active: spkr-1-sd-n-active-state {
+               pins = "gpio21";
+               function = "gpio";
+               drive-strength = <16>;
+               bias-disable;
+               output-low;
+       };
+};
+
 &mdss {
        status = "okay";
 };
        status = "okay";
 };
 
+&mdss_dp0 {
+       status = "okay";
+};
+
+&mdss_dp0_out {
+       data-lanes = <0 1>;
+       remote-endpoint = <&usb_dp_qmpphy_dp_in>;
+};
+
 &mdss_mdp {
        status = "okay";
 };
        status = "okay";
 };
 
+&qup_i2c3_data_clk {
+       /* Use internal I2C pull-up */
+       bias-pull-up = <2200>;
+};
+
 &qupv3_id_0 {
        status = "okay";
 };
        };
 };
 
+&swr0 {
+       status = "okay";
+
+       /* WSA8845, Speaker Left */
+       left_spkr: speaker@0,0 {
+               compatible = "sdw20217020400";
+               reg = <0 0>;
+               pinctrl-0 = <&spkr_1_sd_n_active>;
+               pinctrl-names = "default";
+               powerdown-gpios = <&lpass_tlmm 21 GPIO_ACTIVE_LOW>;
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "SpkrLeft";
+               vdd-1p8-supply = <&vreg_l15b_1p8>;
+               vdd-io-supply = <&vreg_l3c_1p2>;
+       };
+
+       /* WSA8845, Speaker Right */
+       right_spkr: speaker@0,1 {
+               compatible = "sdw20217020400";
+               reg = <0 1>;
+               pinctrl-0 = <&spkr_2_sd_n_active>;
+               pinctrl-names = "default";
+               powerdown-gpios = <&tlmm 77 GPIO_ACTIVE_LOW>;
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "SpkrRight";
+               vdd-1p8-supply = <&vreg_l15b_1p8>;
+               vdd-io-supply = <&vreg_l3c_1p2>;
+       };
+};
+
+&swr1 {
+       status = "okay";
+
+       /* WCD9395 RX */
+       wcd_rx: codec@0,4 {
+               compatible = "sdw20217010e00";
+               reg = <0 4>;
+
+               /*
+                * WCD9395 RX Port 1 (HPH_L/R)      <=> SWR1 Port 1 (HPH_L/R)
+                * WCD9395 RX Port 2 (CLSH)         <=> SWR1 Port 2 (CLSH)
+                * WCD9395 RX Port 3 (COMP_L/R)     <=> SWR1 Port 3 (COMP_L/R)
+                * WCD9395 RX Port 4 (LO)           <=> SWR1 Port 4 (LO)
+                * WCD9395 RX Port 5 (DSD_L/R)      <=> SWR1 Port 5 (DSD_L/R)
+                * WCD9395 RX Port 6 (HIFI_PCM_L/R) <=> SWR1 Port 9 (HIFI_PCM_L/R)
+                */
+               qcom,rx-port-mapping = <1 2 3 4 5 9>;
+       };
+};
+
+&swr2 {
+       status = "okay";
+
+       /* WCD9395 TX */
+       wcd_tx: codec@0,3 {
+               compatible = "sdw20217010e00";
+               reg = <0 3>;
+
+               /*
+                * WCD9395 TX Port 1 (ADC1,2,3,4)         <=> SWR2 Port 2 (TX SWR_INPUT 0,1,2,3)
+                * WCD9395 TX Port 2 (ADC3,4 & DMIC0,1)   <=> SWR2 Port 2 (TX SWR_INPUT 0,1,2,3)
+                * WCD9395 TX Port 3 (DMIC0,1,2,3 & MBHC) <=> SWR2 Port 3 (TX SWR_INPUT 4,5,6,7)
+                * WCD9395 TX Port 4 (DMIC4,5,6,7)        <=> SWR2 Port 4 (TX SWR_INPUT 8,9,10,11)
+                */
+               qcom,tx-port-mapping = <2 2 3 4>;
+       };
+};
+
 &tlmm {
        /* Reserved I/Os for NFC */
-       gpio-reserved-ranges = <32 8>;
+       gpio-reserved-ranges = <32 8>, <74 1>;
 
        bt_default: bt-default-state {
                bt-en-pins {
                bias-pull-down;
        };
 
+       spkr_2_sd_n_active: spkr-2-sd-n-active-state {
+               pins = "gpio77";
+               function = "gpio";
+               drive-strength = <16>;
+               bias-disable;
+               output-low;
+       };
+
        ts_irq: ts-irq-state {
                pins = "gpio161";
                function = "gpio";
                drive-strength = <8>;
                bias-pull-up;
        };
+
+       wcd_default: wcd-reset-n-active-state {
+               pins = "gpio107";
+               function = "gpio";
+               drive-strength = <16>;
+               bias-disable;
+               output-low;
+       };
 };
 
 &uart14 {
 };
 
 &usb_1_dwc3_ss {
-       remote-endpoint = <&pmic_glink_ss_in>;
+       remote-endpoint = <&usb_dp_qmpphy_usb_ss_in>;
 };
 
 &usb_1_hsphy {
        vdda-phy-supply = <&vreg_l3i_1p2>;
        vdda-pll-supply = <&vreg_l3g_0p91>;
 
+       orientation-switch;
+
        status = "okay";
 };
 
+&usb_dp_qmpphy_dp_in {
+       remote-endpoint = <&mdss_dp0_out>;
+};
+
+&usb_dp_qmpphy_out {
+       remote-endpoint = <&redriver_ss_in>;
+};
+
+&usb_dp_qmpphy_usb_ss_in {
+       remote-endpoint = <&usb_1_dwc3_ss>;
+};
+
 &xo_board {
        clock-frequency = <76800000>;
 };
index 2df77123a8c7bbef5efa6c1e2cc8ea8ef856cece..ba72d8f3842073fd481926009ce37075894dc8c8 100644 (file)
                        no-map;
                };
 
+               qlink_logging_mem: qlink-logging@84800000 {
+                       reg = <0 0x84800000 0 0x200000>;
+                       no-map;
+               };
+
                mpss_dsm_mem: mpss-dsm@86b00000 {
                        reg = <0 0x86b00000 0 0x4900000>;
                        no-map;
                                clocks = <&gcc GCC_QUPV3_WRAP2_S6_CLK>;
                                clock-names = "se";
 
-                               interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS
+                               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>;
                                clocks = <&gcc GCC_QUPV3_WRAP2_S7_CLK>;
                                clock-names = "se";
 
-                               interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS
+                               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>;
                              <0 0x60100000 0 0x100000>;
                        reg-names = "parf", "dbi", "elbi", "atu", "config";
 
-                       interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
 
                        clocks = <&gcc GCC_PCIE_0_AUX_CLK>,
                                 <&gcc GCC_PCIE_0_CFG_AHB_CLK>,
                        interrupt-map-mask = <0 0 0 0x7>;
                        #interrupt-cells = <1>;
 
+                       /* Entries are reversed due to the unusual ITS DeviceID encoding */
+                       msi-map = <0x0 &gic_its 0x1401 0x1>,
+                                 <0x100 &gic_its 0x1400 0x1>;
+                       msi-map-mask = <0xff00>;
+
                        linux,pci-domain = <0>;
                        num-lanes = <2>;
                        bus-range = <0 0xff>;
                                    "atu",
                                    "config";
 
-                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "msi";
+                       interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
 
                        clocks = <&gcc GCC_PCIE_1_AUX_CLK>,
                                 <&gcc GCC_PCIE_1_CFG_AHB_CLK>,
                        interrupt-map-mask = <0 0 0 0x7>;
                        #interrupt-cells = <1>;
 
+                       /* Entries are reversed due to the unusual ITS DeviceID encoding */
+                       msi-map = <0x0 &gic_its 0x1481 0x1>,
+                                 <0x100 &gic_its 0x1480 0x1>;
+                       msi-map-mask = <0xff00>;
+
                        linux,pci-domain = <1>;
                        num-lanes = <2>;
                        bus-range = <0 0xff>;
                        compatible = "qcom,sm8650-qmp-ufs-phy";
                        reg = <0 0x01d80000 0 0x2000>;
 
-                       clocks = <&tcsr TCSR_UFS_CLKREF_EN>,
-                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+                       clocks = <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>,
+                                <&tcsr TCSR_UFS_CLKREF_EN>;
                        clock-names = "ref",
-                                     "ref_aux";
+                                     "ref_aux",
+                                     "qref";
 
                        resets = <&ufs_mem_hc 0>;
                        reset-names = "ufsphy";
                                             "mss";
 
                        memory-region = <&mpss_mem>, <&q6_mpss_dtb_mem>,
-                                       <&mpss_dsm_mem>, <&mpss_dsm_mem_2>;
+                                       <&mpss_dsm_mem>, <&mpss_dsm_mem_2>,
+                                       <&qlink_logging_mem>;
 
                        qcom,qmp = <&aoss_qmp>;
 
                                };
                        };
 
-                       dmic02_default: dmic02-default-state {
+                       dmic23_default: dmic23-default-state {
                                clk-pins {
                                        pins = "gpio8";
                                        function = "dmic2_clk";
                spmi_bus: spmi@c400000 {
                        compatible = "qcom,spmi-pmic-arb";
                        reg = <0 0x0c400000 0 0x3000>,
-                             <0 0x0c500000 0 0x4000000>,
+                             <0 0x0c500000 0 0x400000>,
                              <0 0x0c440000 0 0x80000>,
                              <0 0x0c4c0000 0 0x20000>,
                              <0 0x0c42d000 0 0x4000>;
 
                                                iommus = <&apps_smmu 0x1003 0x80>,
                                                         <&apps_smmu 0x1043 0x20>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@4 {
 
                                                iommus = <&apps_smmu 0x1004 0x80>,
                                                         <&apps_smmu 0x1044 0x20>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@5 {
 
                                                iommus = <&apps_smmu 0x1005 0x80>,
                                                         <&apps_smmu 0x1045 0x20>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@6 {
 
                                                iommus = <&apps_smmu 0x1006 0x80>,
                                                         <&apps_smmu 0x1046 0x20>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@7 {
                                                iommus = <&apps_smmu 0x1007 0x40>,
                                                         <&apps_smmu 0x1067 0x0>,
                                                         <&apps_smmu 0x1087 0x0>;
+                                               dma-coherent;
                                        };
                                };
 
                                                iommus = <&apps_smmu 0x1961 0x0>,
                                                         <&apps_smmu 0x0c01 0x20>,
                                                         <&apps_smmu 0x19c1 0x0>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@2 {
                                                iommus = <&apps_smmu 0x1962 0x0>,
                                                         <&apps_smmu 0x0c02 0x20>,
                                                         <&apps_smmu 0x19c2 0x0>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@3 {
                                                iommus = <&apps_smmu 0x1963 0x0>,
                                                         <&apps_smmu 0x0c03 0x20>,
                                                         <&apps_smmu 0x19c3 0x0>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@4 {
                                                iommus = <&apps_smmu 0x1964 0x0>,
                                                         <&apps_smmu 0x0c04 0x20>,
                                                         <&apps_smmu 0x19c4 0x0>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@5 {
                                                iommus = <&apps_smmu 0x1965 0x0>,
                                                         <&apps_smmu 0x0c05 0x20>,
                                                         <&apps_smmu 0x19c5 0x0>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@6 {
                                                iommus = <&apps_smmu 0x1966 0x0>,
                                                         <&apps_smmu 0x0c06 0x20>,
                                                         <&apps_smmu 0x19c6 0x0>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@7 {
                                                iommus = <&apps_smmu 0x1967 0x0>,
                                                         <&apps_smmu 0x0c07 0x20>,
                                                         <&apps_smmu 0x19c7 0x0>;
+                                               dma-coherent;
                                        };
 
                                        compute-cb@8 {
                                                iommus = <&apps_smmu 0x1968 0x0>,
                                                         <&apps_smmu 0x0c08 0x20>,
                                                         <&apps_smmu 0x19c8 0x0>;
+                                               dma-coherent;
                                        };
                                };
                        };
index 7532d8eca2de334b780f6f91d14885d174896958..6a0a54532e5feb494606f5da814cf1090256c725 100644 (file)
                serial0 = &uart21;
        };
 
+       wcd938x: audio-codec {
+               compatible = "qcom,wcd9385-codec";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&wcd_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>;
+       };
+
        chosen {
                stdout-path = "serial0:115200n8";
        };
 
+       sound {
+               compatible = "qcom,x1e80100-sndcard";
+               model = "X1E80100-CRD";
+               audio-routing = "WooferLeft IN", "WSA WSA_SPK1 OUT",
+                               "TwitterLeft IN", "WSA WSA_SPK2 OUT",
+                               "WooferRight IN", "WSA2 WSA_SPK2 OUT",
+                               "TwitterRight 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",
+                               "VA DMIC0", "VA MIC BIAS3",
+                               "VA DMIC1", "VA MIC BIAS3",
+                               "VA DMIC2", "VA MIC BIAS1",
+                               "VA DMIC3", "VA MIC BIAS1",
+                               "TX SWR_INPUT1", "ADC2_OUTPUT";
+
+               wcd-playback-dai-link {
+                       link-name = "WCD Playback";
+
+                       cpu {
+                               sound-dai = <&q6apmbedai RX_CODEC_DMA_RX_0>;
+                       };
+
+                       codec {
+                               sound-dai = <&wcd938x 0>, <&swr1 0>, <&lpass_rxmacro 0>;
+                       };
+
+                       platform {
+                               sound-dai = <&q6apm>;
+                       };
+               };
+
+               wcd-capture-dai-link {
+                       link-name = "WCD Capture";
+
+                       cpu {
+                               sound-dai = <&q6apmbedai TX_CODEC_DMA_TX_3>;
+                       };
+
+                       codec {
+                               sound-dai = <&wcd938x 1>, <&swr2 0>, <&lpass_txmacro 0>;
+                       };
+
+                       platform {
+                               sound-dai = <&q6apm>;
+                       };
+               };
+
+               wsa-dai-link {
+                       link-name = "WSA Playback";
+
+                       cpu {
+                               sound-dai = <&q6apmbedai WSA_CODEC_DMA_RX_0>;
+                       };
+
+                       codec {
+                               sound-dai = <&left_woofer>, <&left_tweeter>,
+                                           <&swr0 0>, <&lpass_wsamacro 0>,
+                                           <&right_woofer>, <&right_tweeter>,
+                                           <&swr3 0>, <&lpass_wsa2macro 0>;
+                       };
+
+                       platform {
+                               sound-dai = <&q6apm>;
+                       };
+               };
+
+               va-dai-link {
+                       link-name = "VA Capture";
+
+                       cpu {
+                               sound-dai = <&q6apmbedai VA_CODEC_DMA_TX_0>;
+                       };
+
+                       codec {
+                               sound-dai = <&lpass_vamacro 0>;
+                       };
+
+                       platform {
+                               sound-dai = <&q6apm>;
+                       };
+               };
+       };
+
        vph_pwr: vph-pwr-regulator {
                compatible = "regulator-fixed";
 
        };
 };
 
+&i2c0 {
+       clock-frequency = <400000>;
+
+       status = "okay";
+
+       touchpad@15 {
+               compatible = "hid-over-i2c";
+               reg = <0x15>;
+
+               hid-descr-addr = <0x1>;
+               interrupts-extended = <&tlmm 3 IRQ_TYPE_LEVEL_LOW>;
+
+               pinctrl-0 = <&tpad_default>;
+               pinctrl-names = "default";
+
+               wakeup-source;
+       };
+
+       keyboard@3a {
+               compatible = "hid-over-i2c";
+               reg = <0x3a>;
+
+               hid-descr-addr = <0x1>;
+               interrupts-extended = <&tlmm 67 IRQ_TYPE_LEVEL_LOW>;
+
+               pinctrl-0 = <&kybd_default>;
+               pinctrl-names = "default";
+
+               wakeup-source;
+       };
+};
+
+&i2c8 {
+       clock-frequency = <400000>;
+
+       status = "okay";
+
+       touchscreen@10 {
+               compatible = "hid-over-i2c";
+               reg = <0x10>;
+
+               hid-descr-addr = <0x1>;
+               interrupts-extended = <&tlmm 51 IRQ_TYPE_LEVEL_LOW>;
+
+               pinctrl-0 = <&ts0_default>;
+               pinctrl-names = "default";
+       };
+};
+
+&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_dp3 {
+       compatible = "qcom,x1e80100-dp";
+       /delete-property/ #sound-dai-cells;
+
+       data-lanes = <0 1 2 3>;
+
+       status = "okay";
+
+       aux-bus {
+               panel {
+                       compatible = "edp-panel";
+                       power-supply = <&vreg_edp_3p3>;
+
+                       port {
+                               edp_panel_in: endpoint {
+                                       remote-endpoint = <&mdss_dp3_out>;
+                               };
+                       };
+               };
+       };
+
+       ports {
+               port@1 {
+                       reg = <1>;
+                       mdss_dp3_out: endpoint {
+                               remote-endpoint = <&edp_panel_in>;
+                       };
+               };
+       };
+};
+
+&mdss_dp3_phy {
+       vdda-phy-supply = <&vreg_l3j_0p8>;
+       vdda-pll-supply = <&vreg_l2j_1p2>;
+
+       status = "okay";
+};
+
+&pcie4 {
+       status = "okay";
+};
+
+&pcie4_phy {
+       vdda-phy-supply = <&vreg_l3j_0p8>;
+       vdda-pll-supply = <&vreg_l3e_1p2>;
+
+       status = "okay";
+};
+
+&pcie6a {
+       status = "okay";
+};
+
+&pcie6a_phy {
+       vdda-phy-supply = <&vreg_l3j_0p8>;
+       vdda-pll-supply = <&vreg_l2j_1p2>;
+
+       status = "okay";
+};
+
+&qupv3_0 {
+       status = "okay";
+};
+
+&qupv3_1 {
+       status = "okay";
+};
+
 &qupv3_2 {
        status = "okay";
 };
 
+&remoteproc_adsp {
+       firmware-name = "qcom/x1e80100/adsp.mbn",
+                       "qcom/x1e80100/adsp_dtb.mbn";
+
+       status = "okay";
+};
+
+&remoteproc_cdsp {
+       firmware-name = "qcom/x1e80100/cdsp.mbn",
+                       "qcom/x1e80100/cdsp_dtb.mbn";
+
+       status = "okay";
+};
+
+&swr0 {
+       status = "okay";
+
+       /* WSA8845, Left Woofer */
+       left_woofer: speaker@0,0 {
+               compatible = "sdw20217020400";
+               reg = <0 0>;
+               pinctrl-0 = <&spkr_01_sd_n_active>;
+               pinctrl-names = "default";
+               powerdown-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>;
+       };
+
+       /* WSA8845, Left Tweeter */
+       left_tweeter: speaker@0,1 {
+               compatible = "sdw20217020400";
+               reg = <0 1>;
+               /* pinctrl in left_woofer node because of sharing the GPIO*/
+               powerdown-gpios = <&lpass_tlmm 12 GPIO_ACTIVE_LOW>;
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "TwitterLeft";
+               vdd-1p8-supply = <&vreg_l15b_1p8>;
+               vdd-io-supply = <&vreg_l12b_1p2>;
+       };
+};
+
+&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 = <1 1 2 3>;
+       };
+};
+
+&swr3 {
+       status = "okay";
+
+       /* WSA8845, Right Woofer */
+       right_woofer: speaker@0,0 {
+               compatible = "sdw20217020400";
+               reg = <0 0>;
+               pinctrl-0 = <&spkr_23_sd_n_active>;
+               pinctrl-names = "default";
+               powerdown-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>;
+       };
+
+       /* WSA8845, Right Tweeter */
+       right_tweeter: speaker@0,1 {
+               compatible = "sdw20217020400";
+               reg = <0 1>;
+               /* pinctrl in right_woofer node because of sharing the GPIO*/
+               powerdown-gpios = <&lpass_tlmm 13 GPIO_ACTIVE_LOW>;
+               #sound-dai-cells = <0>;
+               sound-name-prefix = "TwitterRight";
+               vdd-1p8-supply = <&vreg_l15b_1p8>;
+               vdd-io-supply = <&vreg_l12b_1p2>;
+       };
+};
+
 &tlmm {
        gpio-reserved-ranges = <34 2>, /* Unused */
                               <44 4>, /* SPI (TPM) */
                drive-strength = <16>;
                bias-disable;
        };
+
+       kybd_default: kybd-default-state {
+               pins = "gpio67";
+               function = "gpio";
+               bias-disable;
+       };
+
+       tpad_default: tpad-default-state {
+               pins = "gpio3";
+               function = "gpio";
+               bias-disable;
+       };
+
+       ts0_default: ts0-default-state {
+               int-n-pins {
+                       pins = "gpio51";
+                       function = "gpio";
+                       bias-disable;
+               };
+
+               reset-n-pins {
+                       pins = "gpio48";
+                       function = "gpio";
+                       output-high;
+                       drive-strength = <16>;
+               };
+       };
+
+       wcd_default: wcd-reset-n-active-state {
+               pins = "gpio191";
+               function = "gpio";
+               drive-strength = <16>;
+               bias-disable;
+               output-low;
+       };
 };
 
 &uart21 {
        compatible = "qcom,geni-debug-uart";
        status = "okay";
 };
+
+&usb_1_ss0_hsphy {
+       vdd-supply = <&vreg_l2e_0p8>;
+       vdda12-supply = <&vreg_l3e_1p2>;
+
+       status = "okay";
+};
+
+&usb_1_ss0_qmpphy {
+       status = "okay";
+};
+
+&usb_1_ss0 {
+       status = "okay";
+};
+
+&usb_1_ss0_dwc3 {
+       dr_mode = "host";
+       usb-role-switch;
+};
+
+&usb_1_ss1_hsphy {
+       vdd-supply = <&vreg_l2e_0p8>;
+       vdda12-supply = <&vreg_l3e_1p2>;
+
+       status = "okay";
+};
+
+&usb_1_ss1_qmpphy {
+       status = "okay";
+};
+
+&usb_1_ss1 {
+       status = "okay";
+};
+
+&usb_1_ss1_dwc3 {
+       dr_mode = "host";
+       usb-role-switch;
+};
+
+&usb_1_ss2_hsphy {
+       vdd-supply = <&vreg_l2e_0p8>;
+       vdda12-supply = <&vreg_l3e_1p2>;
+
+       status = "okay";
+};
+
+&usb_1_ss2_qmpphy {
+       status = "okay";
+};
+
+&usb_1_ss2 {
+       status = "okay";
+};
+
+&usb_1_ss2_dwc3 {
+       dr_mode = "host";
+       usb-role-switch;
+};
index a37ad9475c90d8e2a563bdb35c48779f1d6e962b..e76d29053d79bfa99274e0370872619f3c86e335 100644 (file)
@@ -5,6 +5,7 @@
 
 /dts-v1/;
 
+#include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
 #include "x1e80100.dtsi"
                regulator-always-on;
                regulator-boot-on;
        };
+
+       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-always-on;
+               regulator-boot-on;
+       };
 };
 
 &apps_rsc {
                qcom,pmic-id = "e";
 
                vdd-l2-supply = <&vreg_s1f_0p7>;
-               vdd-l3-supply = <&vph_pwr>;
+               vdd-l3-supply = <&vreg_s5j_1p2>;
 
                vreg_l2e_0p8: ldo2 {
                        regulator-name = "vreg_l2e_0p8";
                qcom,pmic-id = "j";
 
                vdd-l1-supply = <&vreg_s1f_0p7>;
-               vdd-l2-supply = <&vph_pwr>;
+               vdd-l2-supply = <&vreg_s5j_1p2>;
                vdd-l3-supply = <&vreg_s1f_0p7>;
                vdd-s5-supply = <&vph_pwr>;
 
        };
 };
 
+&mdss {
+       status = "okay";
+};
+
+&mdss_dp3 {
+       compatible = "qcom,x1e80100-dp";
+       /delete-property/ #sound-dai-cells;
+
+       data-lanes = <0 1 2 3>;
+
+       status = "okay";
+
+       aux-bus {
+               panel {
+                       compatible = "edp-panel";
+                       power-supply = <&vreg_edp_3p3>;
+
+                       port {
+                               edp_panel_in: endpoint {
+                                       remote-endpoint = <&mdss_dp3_out>;
+                               };
+                       };
+               };
+       };
+
+       ports {
+               port@1 {
+                       reg = <1>;
+                       mdss_dp3_out: endpoint {
+                               remote-endpoint = <&edp_panel_in>;
+                       };
+               };
+       };
+};
+
+&mdss_dp3_phy {
+       vdda-phy-supply = <&vreg_l3j_0p8>;
+       vdda-pll-supply = <&vreg_l2j_1p2>;
+
+       status = "okay";
+};
+
+&pcie4 {
+       status = "okay";
+};
+
+&pcie4_phy {
+       vdda-phy-supply = <&vreg_l3j_0p8>;
+       vdda-pll-supply = <&vreg_l3e_1p2>;
+
+       status = "okay";
+};
+
+&pcie6a {
+       status = "okay";
+};
+
+&pcie6a_phy {
+       vdda-phy-supply = <&vreg_l3j_0p8>;
+       vdda-pll-supply = <&vreg_l2j_1p2>;
+
+       status = "okay";
+};
+
+&qupv3_0 {
+       status = "okay";
+};
+
+&qupv3_1 {
+       status = "okay";
+};
+
 &qupv3_2 {
        status = "okay";
 };
 
+&remoteproc_adsp {
+       firmware-name = "qcom/x1e80100/adsp.mbn",
+                       "qcom/x1e80100/adsp_dtb.mbn";
+
+       status = "okay";
+};
+
+&remoteproc_cdsp {
+       firmware-name = "qcom/x1e80100/cdsp.mbn",
+                       "qcom/x1e80100/cdsp_dtb.mbn";
+
+       status = "okay";
+};
+
 &tlmm {
        gpio-reserved-ranges = <33 3>, /* Unused */
                               <44 4>, /* SPI (TPM) */
                               <238 1>; /* UFS Reset */
+
+       edp_reg_en: edp-reg-en-state {
+               pins = "gpio70";
+               function = "gpio";
+               drive-strength = <16>;
+               bias-disable;
+       };
 };
 
 &uart21 {
        compatible = "qcom,geni-debug-uart";
        status = "okay";
 };
+
+&usb_1_ss0_hsphy {
+       vdd-supply = <&vreg_l2e_0p8>;
+       vdda12-supply = <&vreg_l3e_1p2>;
+
+       status = "okay";
+};
+
+&usb_1_ss0_qmpphy {
+       status = "okay";
+};
+
+&usb_1_ss0 {
+       status = "okay";
+};
+
+&usb_1_ss0_dwc3 {
+       dr_mode = "host";
+       usb-role-switch;
+};
+
+&usb_1_ss1_hsphy {
+       vdd-supply = <&vreg_l2e_0p8>;
+       vdda12-supply = <&vreg_l3e_1p2>;
+
+       status = "okay";
+};
+
+&usb_1_ss1_qmpphy {
+       status = "okay";
+};
+
+&usb_1_ss1 {
+       status = "okay";
+};
+
+&usb_1_ss1_dwc3 {
+       dr_mode = "host";
+       usb-role-switch;
+};
+
+&usb_1_ss2_hsphy {
+       vdd-supply = <&vreg_l2e_0p8>;
+       vdda12-supply = <&vreg_l3e_1p2>;
+
+       status = "okay";
+};
+
+&usb_1_ss2_qmpphy {
+       status = "okay";
+};
+
+&usb_1_ss2 {
+       status = "okay";
+};
+
+&usb_1_ss2_dwc3 {
+       dr_mode = "host";
+       usb-role-switch;
+};
index 6f75fc342ceb38168f5ae33bfc490a1003eed755..8e517f76189e19cb038dfa0d3557ef729c630b46 100644 (file)
@@ -4,14 +4,20 @@
  */
 
 #include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/clock/qcom,x1e80100-dispcc.h>
 #include <dt-bindings/clock/qcom,x1e80100-gcc.h>
+#include <dt-bindings/clock/qcom,x1e80100-tcsr.h>
 #include <dt-bindings/dma/qcom-gpi.h>
 #include <dt-bindings/interconnect/qcom,icc.h>
 #include <dt-bindings/interconnect/qcom,x1e80100-rpmh.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/mailbox/qcom-ipcc.h>
+#include <dt-bindings/phy/phy-qcom-qmp.h>
 #include <dt-bindings/power/qcom,rpmhpd.h>
 #include <dt-bindings/power/qcom-rpmpd.h>
+#include <dt-bindings/soc/qcom,gpr.h>
 #include <dt-bindings/soc/qcom,rpmh-rsc.h>
+#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
 
 / {
        interrupt-parent = <&intc>;
                CLUSTER_PD0: power-domain-cpu-cluster0 {
                        #power-domain-cells = <0>;
                        domain-idle-states = <&CLUSTER_CL4>, <&CLUSTER_CL5>;
+                       power-domains = <&SYSTEM_PD>;
                };
 
                CLUSTER_PD1: power-domain-cpu-cluster1 {
                        #power-domain-cells = <0>;
                        domain-idle-states = <&CLUSTER_CL4>, <&CLUSTER_CL5>;
+                       power-domains = <&SYSTEM_PD>;
                };
 
                CLUSTER_PD2: power-domain-cpu-cluster2 {
                        #power-domain-cells = <0>;
                        domain-idle-states = <&CLUSTER_CL4>, <&CLUSTER_CL5>;
+                       power-domains = <&SYSTEM_PD>;
+               };
+
+               SYSTEM_PD: power-domain-system {
+                       #power-domain-cells = <0>;
+                       /* TODO: system-wide idle states */
                };
        };
 
                };
        };
 
+       smp2p-adsp {
+               compatible = "qcom,smp2p";
+
+               interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
+                                            IPCC_MPROC_SIGNAL_SMP2P
+                                            IRQ_TYPE_EDGE_RISING>;
+
+               mboxes = <&ipcc IPCC_CLIENT_LPASS
+                               IPCC_MPROC_SIGNAL_SMP2P>;
+
+               qcom,smem = <443>, <429>;
+               qcom,local-pid = <0>;
+               qcom,remote-pid = <2>;
+
+               smp2p_adsp_out: master-kernel {
+                       qcom,entry-name = "master-kernel";
+                       #qcom,smem-state-cells = <1>;
+               };
+
+               smp2p_adsp_in: slave-kernel {
+                       qcom,entry-name = "slave-kernel";
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       smp2p-cdsp {
+               compatible = "qcom,smp2p";
+
+               interrupts-extended = <&ipcc IPCC_CLIENT_CDSP
+                                            IPCC_MPROC_SIGNAL_SMP2P
+                                            IRQ_TYPE_EDGE_RISING>;
+
+               mboxes = <&ipcc IPCC_CLIENT_CDSP
+                               IPCC_MPROC_SIGNAL_SMP2P>;
+
+               qcom,smem = <94>, <432>;
+               qcom,local-pid = <0>;
+               qcom,remote-pid = <5>;
+
+               smp2p_cdsp_out: master-kernel {
+                       qcom,entry-name = "master-kernel";
+                       #qcom,smem-state-cells = <1>;
+               };
+
+               smp2p_cdsp_in: slave-kernel {
+                       qcom,entry-name = "slave-kernel";
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
        soc: soc@0 {
                compatible = "simple-bus";
 
                        clocks = <&bi_tcxo_div2>,
                                 <&sleep_clk>,
                                 <0>,
+                                <&pcie4_phy>,
                                 <0>,
+                                <&pcie6a_phy>,
                                 <0>,
-                                <0>,
-                                <0>,
-                                <0>,
-                                <0>,
-                                <0>;
+                                <&usb_1_ss0_qmpphy QMP_USB43DP_USB3_PIPE_CLK>,
+                                <&usb_1_ss1_qmpphy QMP_USB43DP_USB3_PIPE_CLK>,
+                                <&usb_1_ss2_qmpphy QMP_USB43DP_USB3_PIPE_CLK>;
 
                        power-domains = <&rpmhpd RPMHPD_CX>;
                        #clock-cells = <1>;
                        #power-domain-cells = <1>;
                };
 
+               ipcc: mailbox@408000 {
+                       compatible = "qcom,x1e80100-ipcc", "qcom,ipcc";
+                       reg = <0 0x00408000 0 0x1000>;
+
+                       interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+
+                       #mbox-cells = <2>;
+               };
+
                gpi_dma2: dma-controller@800000 {
                        compatible = "qcom,x1e80100-gpi-dma", "qcom,sm6350-gpi-dma";
                        reg = <0 0x00800000 0 0x60000>;
                                clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>;
                                clock-names = "se";
 
-                               interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS
+                               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>;
                        };
                };
 
+               usb_1_ss0_hsphy: phy@fd3000 {
+                       compatible = "qcom,x1e80100-snps-eusb2-phy",
+                                    "qcom,sm8550-snps-eusb2-phy";
+                       reg = <0 0x00fd3000 0 0x154>;
+                       #phy-cells = <0>;
+
+                       clocks = <&tcsr TCSR_USB2_1_CLKREF_EN>;
+                       clock-names = "ref";
+
+                       resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
+
+                       status = "disabled";
+               };
+
+               usb_1_ss0_qmpphy: phy@fd5000 {
+                       compatible = "qcom,x1e80100-qmp-usb3-dp-phy";
+                       reg = <0 0x00fd5000 0 0x4000>;
+
+                       clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>,
+                                <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+                       clock-names = "aux",
+                                     "ref",
+                                     "com_aux",
+                                     "usb3_pipe";
+
+                       power-domains = <&gcc GCC_USB_0_PHY_GDSC>;
+
+                       resets = <&gcc GCC_USB3_PHY_PRIM_BCR>,
+                                <&gcc GCC_USB4_0_DP0_PHY_PRIM_BCR>;
+                       reset-names = "phy",
+                                     "common";
+
+                       #clock-cells = <1>;
+                       #phy-cells = <1>;
+
+                       status = "disabled";
+               };
+
+               usb_1_ss1_hsphy: phy@fd9000 {
+                       compatible = "qcom,x1e80100-snps-eusb2-phy",
+                                    "qcom,sm8550-snps-eusb2-phy";
+                       reg = <0 0x00fd9000 0 0x154>;
+                       #phy-cells = <0>;
+
+                       clocks = <&tcsr TCSR_USB2_1_CLKREF_EN>;
+                       clock-names = "ref";
+
+                       resets = <&gcc GCC_QUSB2PHY_SEC_BCR>;
+
+                       status = "disabled";
+               };
+
+               usb_1_ss1_qmpphy: phy@fda000 {
+                       compatible = "qcom,x1e80100-qmp-usb3-dp-phy";
+                       reg = <0 0x00fda000 0 0x4000>;
+
+                       clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>,
+                                <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
+                       clock-names = "aux",
+                                     "ref",
+                                     "com_aux",
+                                     "usb3_pipe";
+
+                       power-domains = <&gcc GCC_USB_1_PHY_GDSC>;
+
+                       resets = <&gcc GCC_USB3_PHY_SEC_BCR>,
+                                <&gcc GCC_USB4_1_DP0_PHY_SEC_BCR>;
+                       reset-names = "phy",
+                                     "common";
+
+                       #clock-cells = <1>;
+                       #phy-cells = <1>;
+
+                       status = "disabled";
+               };
+
+               usb_1_ss2_hsphy: phy@fde000 {
+                       compatible = "qcom,x1e80100-snps-eusb2-phy",
+                                    "qcom,sm8550-snps-eusb2-phy";
+                       reg = <0 0x00fde000 0 0x154>;
+                       #phy-cells = <0>;
+
+                       clocks = <&tcsr TCSR_USB2_1_CLKREF_EN>;
+                       clock-names = "ref";
+
+                       resets = <&gcc GCC_QUSB2PHY_TERT_BCR>;
+
+                       status = "disabled";
+               };
+
+               usb_1_ss2_qmpphy: phy@fdf000 {
+                       compatible = "qcom,x1e80100-qmp-usb3-dp-phy";
+                       reg = <0 0x00fdf000 0 0x4000>;
+
+                       clocks = <&gcc GCC_USB3_TERT_PHY_AUX_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_USB3_TERT_PHY_COM_AUX_CLK>,
+                                <&gcc GCC_USB3_TERT_PHY_PIPE_CLK>;
+                       clock-names = "aux",
+                                     "ref",
+                                     "com_aux",
+                                     "usb3_pipe";
+
+                       power-domains = <&gcc GCC_USB_2_PHY_GDSC>;
+
+                       resets = <&gcc GCC_USB3_PHY_TERT_BCR>,
+                                <&gcc GCC_USB4_2_DP0_PHY_TERT_BCR>;
+                       reset-names = "phy",
+                                     "common";
+
+                       #clock-cells = <1>;
+                       #phy-cells = <1>;
+
+                       status = "disabled";
+               };
+
                cnoc_main: interconnect@1500000 {
                        compatible = "qcom,x1e80100-cnoc-main";
                        reg = <0 0x1500000 0 0x14400>;
                        #interconnect-cells = <2>;
                };
 
+               pcie6a: pci@1bf8000 {
+                       device_type = "pci";
+                       compatible = "qcom,pcie-x1e80100";
+                       reg = <0 0x01bf8000 0 0x3000>,
+                             <0 0x70000000 0 0xf1d>,
+                             <0 0x70000f20 0 0xa8>,
+                             <0 0x70001000 0 0x1000>,
+                             <0 0x70100000 0 0x100000>;
+                       reg-names = "parf",
+                                   "dbi",
+                                   "elbi",
+                                   "atu",
+                                   "config";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       ranges = <0x01000000 0 0x00000000 0 0x70200000 0 0x100000>,
+                                <0x02000000 0 0x70300000 0 0x70300000 0 0x3d00000>;
+                       bus-range = <0 0xff>;
+
+                       dma-coherent;
+
+                       linux,pci-domain = <7>;
+                       num-lanes = <2>;
+
+                       interrupts = <GIC_SPI 773 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 774 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 837 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 838 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 839 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 840 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 841 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 842 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
+
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0x7>;
+                       interrupt-map = <0 0 0 1 &intc 0 0 0 843 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 2 &intc 0 0 0 844 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 3 &intc 0 0 0 845 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 4 &intc 0 0 0 772 IRQ_TYPE_LEVEL_HIGH>;
+
+                       clocks = <&gcc GCC_PCIE_6A_AUX_CLK>,
+                                <&gcc GCC_PCIE_6A_CFG_AHB_CLK>,
+                                <&gcc GCC_PCIE_6A_MSTR_AXI_CLK>,
+                                <&gcc GCC_PCIE_6A_SLV_AXI_CLK>,
+                                <&gcc GCC_PCIE_6A_SLV_Q2A_AXI_CLK>,
+                                <&gcc GCC_CFG_NOC_PCIE_ANOC_SOUTH_AHB_CLK>,
+                                <&gcc GCC_CNOC_PCIE_SOUTH_SF_AXI_CLK>;
+                       clock-names = "aux",
+                                     "cfg",
+                                     "bus_master",
+                                     "bus_slave",
+                                     "slave_q2a",
+                                     "noc_aggr",
+                                     "cnoc_sf_axi";
+
+                       assigned-clocks = <&gcc GCC_PCIE_6A_AUX_CLK>;
+                       assigned-clock-rates = <19200000>;
+
+                       interconnects = <&pcie_south_anoc MASTER_PCIE_6A QCOM_ICC_TAG_ALWAYS
+                                        &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+                                       <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
+                                        &cnoc_main SLAVE_PCIE_6A QCOM_ICC_TAG_ALWAYS>;
+                       interconnect-names = "pcie-mem",
+                                            "cpu-pcie";
+
+                       resets = <&gcc GCC_PCIE_6A_BCR>,
+                                <&gcc GCC_PCIE_6A_LINK_DOWN_BCR>;
+                       reset-names = "pci",
+                                     "link_down";
+
+                       power-domains = <&gcc GCC_PCIE_6A_GDSC>;
+
+                       phys = <&pcie6a_phy>;
+                       phy-names = "pciephy";
+
+                       status = "disabled";
+               };
+
+               pcie6a_phy: phy@1bfc000 {
+                       compatible = "qcom,x1e80100-qmp-gen4x2-pcie-phy";
+                       reg = <0 0x01bfc000 0 0x2000>;
+
+                       clocks = <&gcc GCC_PCIE_6A_PHY_AUX_CLK>,
+                                <&gcc GCC_PCIE_6A_CFG_AHB_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_PCIE_6A_PHY_RCHNG_CLK>,
+                                <&gcc GCC_PCIE_6A_PIPE_CLK>;
+                       clock-names = "aux",
+                                     "cfg_ahb",
+                                     "ref",
+                                     "rchng",
+                                     "pipe";
+
+                       resets = <&gcc GCC_PCIE_6A_PHY_BCR>,
+                                <&gcc GCC_PCIE_6A_NOCSR_COM_PHY_BCR>;
+                       reset-names = "phy",
+                                     "phy_nocsr";
+
+                       assigned-clocks = <&gcc GCC_PCIE_6A_PHY_RCHNG_CLK>;
+                       assigned-clock-rates = <100000000>;
+
+                       power-domains = <&gcc GCC_PCIE_6_PHY_GDSC>;
+
+                       #clock-cells = <0>;
+                       clock-output-names = "pcie6a_pipe_clk";
+
+                       #phy-cells = <0>;
+
+                       status = "disabled";
+               };
+
+               pcie4: pci@1c08000 {
+                       device_type = "pci";
+                       compatible = "qcom,pcie-x1e80100";
+                       reg = <0 0x01c08000 0 0x3000>,
+                             <0 0x7c000000 0 0xf1d>,
+                             <0 0x7c000f40 0 0xa8>,
+                             <0 0x7c001000 0 0x1000>,
+                             <0 0x7c100000 0 0x100000>,
+                             <0 0x01c0b000 0 0x1000>;
+                       reg-names = "parf",
+                                   "dbi",
+                                   "elbi",
+                                   "atu",
+                                   "config",
+                                   "mhi";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       ranges = <0x01000000 0 0x00000000 0 0x7c200000 0 0x100000>,
+                                <0x02000000 0 0x7c300000 0 0x7c300000 0 0x3d00000>;
+                       bus-range = <0x00 0xff>;
+
+                       dma-coherent;
+
+                       linux,pci-domain = <5>;
+                       num-lanes = <2>;
+
+                       interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi0",
+                                         "msi1",
+                                         "msi2",
+                                         "msi3",
+                                         "msi4",
+                                         "msi5",
+                                         "msi6",
+                                         "msi7";
+
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 0x7>;
+                       interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 2 &intc 0 0 0 150 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 3 &intc 0 0 0 151 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 4 &intc 0 0 0 152 IRQ_TYPE_LEVEL_HIGH>;
+
+                       clocks = <&gcc GCC_PCIE_4_AUX_CLK>,
+                                <&gcc GCC_PCIE_4_CFG_AHB_CLK>,
+                                <&gcc GCC_PCIE_4_MSTR_AXI_CLK>,
+                                <&gcc GCC_PCIE_4_SLV_AXI_CLK>,
+                                <&gcc GCC_PCIE_4_SLV_Q2A_AXI_CLK>,
+                                <&gcc GCC_CFG_NOC_PCIE_ANOC_NORTH_AHB_CLK>,
+                                <&gcc GCC_CNOC_PCIE_NORTH_SF_AXI_CLK>;
+                       clock-names = "aux",
+                                     "cfg",
+                                     "bus_master",
+                                     "bus_slave",
+                                     "slave_q2a",
+                                     "noc_aggr",
+                                     "cnoc_sf_axi";
+
+                       assigned-clocks = <&gcc GCC_PCIE_4_AUX_CLK>;
+                       assigned-clock-rates = <19200000>;
+
+                       interconnects = <&pcie_south_anoc MASTER_PCIE_4 QCOM_ICC_TAG_ALWAYS
+                                        &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+                                       <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
+                                        &cnoc_main SLAVE_PCIE_4 QCOM_ICC_TAG_ALWAYS>;
+                       interconnect-names = "pcie-mem",
+                                            "cpu-pcie";
+
+                       resets = <&gcc GCC_PCIE_4_BCR>,
+                                <&gcc GCC_PCIE_4_LINK_DOWN_BCR>;
+                       reset-names = "pci",
+                                     "link_down";
+
+                       power-domains = <&gcc GCC_PCIE_4_GDSC>;
+
+                       phys = <&pcie4_phy>;
+                       phy-names = "pciephy";
+
+                       status = "disabled";
+               };
+
+               pcie4_phy: phy@1c0e000 {
+                       compatible = "qcom,x1e80100-qmp-gen3x2-pcie-phy";
+                       reg = <0 0x01c0e000 0 0x2000>;
+
+                       clocks = <&gcc GCC_PCIE_4_AUX_CLK>,
+                                <&gcc GCC_PCIE_4_CFG_AHB_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_PCIE_4_PHY_RCHNG_CLK>,
+                                <&gcc GCC_PCIE_4_PIPE_CLK>;
+                       clock-names = "aux",
+                                     "cfg_ahb",
+                                     "ref",
+                                     "rchng",
+                                     "pipe";
+
+                       resets = <&gcc GCC_PCIE_4_PHY_BCR>;
+                       reset-names = "phy";
+
+                       assigned-clocks = <&gcc GCC_PCIE_4_PHY_RCHNG_CLK>;
+                       assigned-clock-rates = <100000000>;
+
+                       power-domains = <&gcc GCC_PCIE_4_PHY_GDSC>;
+
+                       #clock-cells = <0>;
+                       clock-output-names = "pcie4_pipe_clk";
+
+                       #phy-cells = <0>;
+
+                       status = "disabled";
+               };
+
                tcsr_mutex: hwlock@1f40000 {
                        compatible = "qcom,tcsr-mutex";
                        reg = <0 0x01f40000 0 0x20000>;
                        #hwlock-cells = <1>;
                };
 
+               tcsr: clock-controller@1fc0000 {
+                       compatible = "qcom,x1e80100-tcsr", "syscon";
+                       reg = <0 0x01fc0000 0 0x30000>;
+                       clocks = <&rpmhcc RPMH_CXO_CLK>;
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+               };
+
                gem_noc: interconnect@26400000 {
                        compatible = "qcom,x1e80100-gem-noc";
                        reg = <0 0x26400000 0 0x311200>;
                        #interconnect-cells = <2>;
                };
 
+               lpass_wsa2macro: codec@6aa0000 {
+                       compatible = "qcom,x1e80100-lpass-wsa-macro", "qcom,sm8550-lpass-wsa-macro";
+                       reg = <0 0x06aa0000 0 0x1000>;
+                       clocks = <&q6prmcc LPASS_CLK_ID_WSA2_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&lpass_vamacro>;
+                       clock-names = "mclk",
+                                     "macro",
+                                     "dcodec",
+                                     "fsgen";
+
+                       #clock-cells = <0>;
+                       clock-output-names = "wsa2-mclk";
+                       #sound-dai-cells = <1>;
+                       sound-name-prefix = "WSA2";
+               };
+
+               swr3: soundwire@6ab0000 {
+                       compatible = "qcom,soundwire-v2.0.0";
+                       reg = <0 0x06ab0000 0 0x10000>;
+                       clocks = <&lpass_wsa2macro>;
+                       clock-names = "iface";
+                       interrupts = <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
+                       label = "WSA2";
+
+                       pinctrl-0 = <&wsa2_swr_active>;
+                       pinctrl-names = "default";
+
+                       qcom,din-ports = <4>;
+                       qcom,dout-ports = <9>;
+
+                       qcom,ports-sinterval =          /bits/ 16 <0x07 0x1f 0x3f 0x07 0x1f 0x3f 0xc8 0xff 0xff 0x0f 0x0f 0xff 0x31f>;
+                       qcom,ports-offset1 =            /bits/ 8 <0x01 0x03 0x05 0x02 0x04 0x15 0x00 0xff 0xff 0x06 0x0d 0xff 0x00>;
+                       qcom,ports-offset2 =            /bits/ 8 <0xff 0x07 0x1f 0xff 0x07 0x1f 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+                       qcom,ports-hstart =             /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>;
+                       qcom,ports-hstop =              /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>;
+                       qcom,ports-word-length =        /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x18>;
+                       qcom,ports-block-pack-mode =    /bits/ 8 <0x00 0x01 0x01 0x00 0x01 0x01 0x00 0x00 0x00 0x01 0x01 0x00 0x00>;
+                       qcom,ports-block-group-count =  /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+                       qcom,ports-lane-control =       /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+
+                       #address-cells = <2>;
+                       #size-cells = <0>;
+                       #sound-dai-cells = <1>;
+                       status = "disabled";
+               };
+
+               lpass_rxmacro: codec@6ac0000 {
+                       compatible = "qcom,x1e80100-lpass-rx-macro", "qcom,sm8550-lpass-rx-macro";
+                       reg = <0 0x06ac0000 0 0x1000>;
+                       clocks = <&q6prmcc LPASS_CLK_ID_RX_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&lpass_vamacro>;
+                       clock-names = "mclk",
+                                     "macro",
+                                     "dcodec",
+                                     "fsgen";
+
+                       #clock-cells = <0>;
+                       clock-output-names = "mclk";
+                       #sound-dai-cells = <1>;
+               };
+
+               swr1: soundwire@6ad0000 {
+                       compatible = "qcom,soundwire-v2.0.0";
+                       reg = <0 0x06ad0000 0 0x10000>;
+                       clocks = <&lpass_rxmacro>;
+                       clock-names = "iface";
+                       interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+                       label = "RX";
+
+                       pinctrl-0 = <&rx_swr_active>;
+                       pinctrl-names = "default";
+
+                       qcom,din-ports = <1>;
+                       qcom,dout-ports = <11>;
+
+                       qcom,ports-sinterval =          /bits/ 16 <0x03 0x1f 0x1f 0x07 0x00 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+                       qcom,ports-offset1 =            /bits/ 8 <0x00 0x00 0x0b 0x01 0x00 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+                       qcom,ports-offset2 =            /bits/ 8 <0x00 0x00 0x0b 0x00 0x00 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+                       qcom,ports-hstart =             /bits/ 8 <0xff 0x03 0x00 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+                       qcom,ports-hstop =              /bits/ 8 <0xff 0x06 0x0f 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+                       qcom,ports-word-length =        /bits/ 8 <0x01 0x07 0x04 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+                       qcom,ports-block-pack-mode =    /bits/ 8 <0xff 0x00 0x01 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+                       qcom,ports-block-group-count =  /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+                       qcom,ports-lane-control =       /bits/ 8 <0x01 0x00 0x00 0x00 0x00 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+
+                       #address-cells = <2>;
+                       #size-cells = <0>;
+                       #sound-dai-cells = <1>;
+                       status = "disabled";
+               };
+
+               lpass_txmacro: codec@6ae0000 {
+                       compatible = "qcom,x1e80100-lpass-tx-macro", "qcom,sm8550-lpass-tx-macro";
+                       reg = <0 0x06ae0000 0 0x1000>;
+                       clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&lpass_vamacro>;
+                       clock-names = "mclk",
+                                     "macro",
+                                     "dcodec",
+                                     "fsgen";
+
+                       #clock-cells = <0>;
+                       clock-output-names = "mclk";
+                       #sound-dai-cells = <1>;
+               };
+
+               lpass_wsamacro: codec@6b00000 {
+                       compatible = "qcom,x1e80100-lpass-wsa-macro", "qcom,sm8550-lpass-wsa-macro";
+                       reg = <0 0x06b00000 0 0x1000>;
+                       clocks = <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&lpass_vamacro>;
+                       clock-names = "mclk",
+                                     "macro",
+                                     "dcodec",
+                                     "fsgen";
+
+                       #clock-cells = <0>;
+                       clock-output-names = "mclk";
+                       #sound-dai-cells = <1>;
+                       sound-name-prefix = "WSA";
+               };
+
+               swr0: soundwire@6b10000 {
+                       compatible = "qcom,soundwire-v2.0.0";
+                       reg = <0 0x06b10000 0 0x10000>;
+                       clocks = <&lpass_wsamacro>;
+                       clock-names = "iface";
+                       interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
+                       label = "WSA";
+
+                       pinctrl-0 = <&wsa_swr_active>;
+                       pinctrl-names = "default";
+
+                       qcom,din-ports = <4>;
+                       qcom,dout-ports = <9>;
+
+                       qcom,ports-sinterval =          /bits/ 16 <0x07 0x1f 0x3f 0x07 0x1f 0x3f 0xc8 0xff 0xff 0x0f 0x0f 0xff 0x31f>;
+                       qcom,ports-offset1 =            /bits/ 8 <0x01 0x03 0x05 0x02 0x04 0x15 0x00 0xff 0xff 0x06 0x0d 0xff 0x00>;
+                       qcom,ports-offset2 =            /bits/ 8 <0xff 0x07 0x1f 0xff 0x07 0x1f 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+                       qcom,ports-hstart =             /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>;
+                       qcom,ports-hstop =              /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>;
+                       qcom,ports-word-length =        /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x18>;
+                       qcom,ports-block-pack-mode =    /bits/ 8 <0x00 0x01 0x01 0x00 0x01 0x01 0x00 0x00 0x00 0x01 0x01 0x00 0x00>;
+                       qcom,ports-block-group-count =  /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+                       qcom,ports-lane-control =       /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
+
+                       #address-cells = <2>;
+                       #size-cells = <0>;
+                       #sound-dai-cells = <1>;
+                       status = "disabled";
+               };
+
+               swr2: soundwire@6d30000 {
+                       compatible = "qcom,soundwire-v2.0.0";
+                       reg = <0 0x06d30000 0 0x10000>;
+                       clocks = <&lpass_txmacro>;
+                       clock-names = "iface";
+                       interrupts = <GIC_SPI 496 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 520 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "core", "wakeup";
+                       label = "TX";
+
+                       pinctrl-0 = <&tx_swr_active>;
+                       pinctrl-names = "default";
+
+                       qcom,din-ports = <4>;
+                       qcom,dout-ports = <1>;
+
+                       qcom,ports-sinterval-low =      /bits/ 8 <0x00 0x01 0x03 0x03 0x00>;
+                       qcom,ports-offset1 =            /bits/ 8 <0x00 0x01 0x02 0x00 0x00>;
+                       qcom,ports-offset2 =            /bits/ 8 <0x00 0x00 0x00 0x00 0xff>;
+                       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 0x00 0x00 0x01 0xff>;
+
+                       #address-cells = <2>;
+                       #size-cells = <0>;
+                       #sound-dai-cells = <1>;
+                       status = "disabled";
+               };
+
+               lpass_vamacro: codec@6d44000 {
+                       compatible = "qcom,x1e80100-lpass-va-macro", "qcom,sm8550-lpass-va-macro";
+                       reg = <0 0x06d44000 0 0x1000>;
+                       clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+                       clock-names = "mclk",
+                                     "macro",
+                                     "dcodec";
+
+                       #clock-cells = <0>;
+                       clock-output-names = "fsgen";
+                       #sound-dai-cells = <1>;
+               };
+
+               lpass_tlmm: pinctrl@6e80000 {
+                       compatible = "qcom,x1e80100-lpass-lpi-pinctrl", "qcom,sm8550-lpass-lpi-pinctrl";
+                       reg = <0 0x06e80000 0 0x20000>,
+                             <0 0x07250000 0 0x10000>;
+
+                       clocks = <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+                                <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+                       clock-names = "core", "audio";
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       gpio-ranges = <&lpass_tlmm 0 0 23>;
+
+                       tx_swr_active: tx-swr-active-state {
+                               clk-pins {
+                                       pins = "gpio0";
+                                       function = "swr_tx_clk";
+                                       drive-strength = <2>;
+                                       slew-rate = <1>;
+                                       bias-disable;
+                               };
+
+                               data-pins {
+                                       pins = "gpio1", "gpio2";
+                                       function = "swr_tx_data";
+                                       drive-strength = <2>;
+                                       slew-rate = <1>;
+                                       bias-bus-hold;
+                               };
+                       };
+
+                       rx_swr_active: rx-swr-active-state {
+                               clk-pins {
+                                       pins = "gpio3";
+                                       function = "swr_rx_clk";
+                                       drive-strength = <2>;
+                                       slew-rate = <1>;
+                                       bias-disable;
+                               };
+
+                               data-pins {
+                                       pins = "gpio4", "gpio5";
+                                       function = "swr_rx_data";
+                                       drive-strength = <2>;
+                                       slew-rate = <1>;
+                                       bias-bus-hold;
+                               };
+                       };
+
+                       dmic01_default: dmic01-default-state {
+                               clk-pins {
+                                       pins = "gpio6";
+                                       function = "dmic1_clk";
+                                       drive-strength = <8>;
+                                       output-high;
+                               };
+
+                               data-pins {
+                                       pins = "gpio7";
+                                       function = "dmic1_data";
+                                       drive-strength = <8>;
+                                       input-enable;
+                               };
+                       };
+
+                       dmic23_default: dmic23-default-state {
+                               clk-pins {
+                                       pins = "gpio8";
+                                       function = "dmic2_clk";
+                                       drive-strength = <8>;
+                                       output-high;
+                               };
+
+                               data-pins {
+                                       pins = "gpio9";
+                                       function = "dmic2_data";
+                                       drive-strength = <8>;
+                                       input-enable;
+                               };
+                       };
+
+                       wsa_swr_active: wsa-swr-active-state {
+                               clk-pins {
+                                       pins = "gpio10";
+                                       function = "wsa_swr_clk";
+                                       drive-strength = <2>;
+                                       slew-rate = <1>;
+                                       bias-disable;
+                               };
+
+                               data-pins {
+                                       pins = "gpio11";
+                                       function = "wsa_swr_data";
+                                       drive-strength = <2>;
+                                       slew-rate = <1>;
+                                       bias-bus-hold;
+                               };
+                       };
+
+                       wsa2_swr_active: wsa2-swr-active-state {
+                               clk-pins {
+                                       pins = "gpio15";
+                                       function = "wsa2_swr_clk";
+                                       drive-strength = <2>;
+                                       slew-rate = <1>;
+                                       bias-disable;
+                               };
+
+                               data-pins {
+                                       pins = "gpio16";
+                                       function = "wsa2_swr_data";
+                                       drive-strength = <2>;
+                                       slew-rate = <1>;
+                                       bias-bus-hold;
+                               };
+                       };
+               };
+
                lpass_ag_noc: interconnect@7e40000 {
                        compatible = "qcom,x1e80100-lpass-ag-noc";
                        reg = <0 0x7e40000 0 0xE080>;
                        #interconnect-cells = <2>;
                };
 
+               usb_2_hsphy: phy@88e0000 {
+                       compatible = "qcom,x1e80100-snps-eusb2-phy",
+                                    "qcom,sm8550-snps-eusb2-phy";
+                       reg = <0 0x088e0000 0 0x154>;
+                       #phy-cells = <0>;
+
+                       clocks = <&tcsr TCSR_USB2_2_CLKREF_EN>;
+                       clock-names = "ref";
+
+                       resets = <&gcc GCC_QUSB2PHY_USB20_HS_BCR>;
+
+                       status = "disabled";
+               };
+
+               usb_1_ss2: usb@a0f8800 {
+                       compatible = "qcom,x1e80100-dwc3", "qcom,dwc3";
+                       reg = <0 0x0a0f8800 0 0x400>;
+
+                       clocks = <&gcc GCC_CFG_NOC_USB3_TERT_AXI_CLK>,
+                                <&gcc GCC_USB30_TERT_MASTER_CLK>,
+                                <&gcc GCC_AGGRE_USB3_TERT_AXI_CLK>,
+                                <&gcc GCC_USB30_TERT_SLEEP_CLK>,
+                                <&gcc GCC_USB30_TERT_MOCK_UTMI_CLK>,
+                                <&gcc GCC_AGGRE_USB_NOC_AXI_CLK>,
+                                <&gcc GCC_AGGRE_NOC_USB_NORTH_AXI_CLK>,
+                                <&gcc GCC_AGGRE_NOC_USB_SOUTH_AXI_CLK>,
+                                <&gcc GCC_SYS_NOC_USB_AXI_CLK>;
+                       clock-names = "cfg_noc",
+                                     "core",
+                                     "iface",
+                                     "sleep",
+                                     "mock_utmi",
+                                     "noc_aggr",
+                                     "noc_aggr_north",
+                                     "noc_aggr_south",
+                                     "noc_sys";
+
+                       assigned-clocks = <&gcc GCC_USB30_TERT_MOCK_UTMI_CLK>,
+                                         <&gcc GCC_USB30_TERT_MASTER_CLK>;
+                       assigned-clock-rates = <19200000>,
+                                              <200000000>;
+
+                       interrupts-extended = <&intc GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 58 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 57 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 10 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
+
+                       power-domains = <&gcc GCC_USB30_TERT_GDSC>;
+                       required-opps = <&rpmhpd_opp_nom>;
+
+                       resets = <&gcc GCC_USB30_TERT_BCR>;
+
+                       interconnects = <&usb_south_anoc MASTER_USB3_2 QCOM_ICC_TAG_ALWAYS
+                                        &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+                                       <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
+                                        &config_noc SLAVE_USB3_2 QCOM_ICC_TAG_ALWAYS>;
+                       interconnect-names = "usb-ddr",
+                                            "apps-usb";
+
+                       wakeup-source;
+
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       status = "disabled";
+
+                       usb_1_ss2_dwc3: usb@a000000 {
+                               compatible = "snps,dwc3";
+                               reg = <0 0x0a000000 0 0xcd00>;
+
+                               interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+
+                               iommus = <&apps_smmu 0x14a0 0x0>;
+
+                               phys = <&usb_1_ss2_hsphy>,
+                                      <&usb_1_ss2_qmpphy QMP_USB43DP_USB3_PHY>;
+                               phy-names = "usb2-phy",
+                                           "usb3-phy";
+
+                               snps,dis_u2_susphy_quirk;
+                               snps,dis_enblslpm_quirk;
+                               snps,usb3_lpm_capable;
+
+                               dma-coherent;
+
+                               port {
+                                       usb_1_ss2_role_switch: endpoint {
+                                       };
+                               };
+                       };
+               };
+
+               usb_2: usb@a2f8800 {
+                       compatible = "qcom,x1e80100-dwc3", "qcom,dwc3";
+                       reg = <0 0x0a2f8800 0 0x400>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       clocks = <&gcc GCC_CFG_NOC_USB2_PRIM_AXI_CLK>,
+                                <&gcc GCC_USB20_MASTER_CLK>,
+                                <&gcc GCC_AGGRE_USB2_PRIM_AXI_CLK>,
+                                <&gcc GCC_USB20_SLEEP_CLK>,
+                                <&gcc GCC_USB20_MOCK_UTMI_CLK>,
+                                <&gcc GCC_AGGRE_USB_NOC_AXI_CLK>,
+                                <&gcc GCC_AGGRE_NOC_USB_NORTH_AXI_CLK>,
+                                <&gcc GCC_AGGRE_NOC_USB_SOUTH_AXI_CLK>,
+                                <&gcc GCC_SYS_NOC_USB_AXI_CLK>;
+                       clock-names = "cfg_noc",
+                                     "core",
+                                     "iface",
+                                     "sleep",
+                                     "mock_utmi",
+                                     "noc_aggr",
+                                     "noc_aggr_north",
+                                     "noc_aggr_south",
+                                     "noc_sys";
+
+                       assigned-clocks = <&gcc GCC_USB20_MOCK_UTMI_CLK>,
+                                         <&gcc GCC_USB20_MASTER_CLK>;
+                       assigned-clock-rates = <19200000>, <200000000>;
+
+                       interrupts-extended = <&intc GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 50 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 49 IRQ_TYPE_EDGE_BOTH>;
+                       interrupt-names = "pwr_event",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq";
+
+                       power-domains = <&gcc GCC_USB20_PRIM_GDSC>;
+                       required-opps = <&rpmhpd_opp_nom>;
+
+                       resets = <&gcc GCC_USB20_PRIM_BCR>;
+
+                       interconnects = <&usb_north_anoc MASTER_USB2 QCOM_ICC_TAG_ALWAYS
+                                        &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+                                       <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
+                                        &config_noc SLAVE_USB2 QCOM_ICC_TAG_ALWAYS>;
+                       interconnect-names = "usb-ddr",
+                                            "apps-usb";
+
+                       wakeup-source;
+
+                       status = "disabled";
+
+                       usb_2_dwc3: usb@a200000 {
+                               compatible = "snps,dwc3";
+                               reg = <0 0x0a200000 0 0xcd00>;
+                               interrupts = <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>;
+                               iommus = <&apps_smmu 0x14e0 0x0>;
+                               phys = <&usb_2_hsphy>;
+                               phy-names = "usb2-phy";
+                               maximum-speed = "high-speed";
+
+                               port {
+                                       usb_2_role_switch: endpoint {
+                                       };
+                               };
+                       };
+               };
+
+               usb_1_ss0: usb@a6f8800 {
+                       compatible = "qcom,x1e80100-dwc3", "qcom,dwc3";
+                       reg = <0 0x0a6f8800 0 0x400>;
+
+                       clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>,
+                                <&gcc GCC_USB30_PRIM_MASTER_CLK>,
+                                <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>,
+                                <&gcc GCC_USB30_PRIM_SLEEP_CLK>,
+                                <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
+                                <&gcc GCC_AGGRE_USB_NOC_AXI_CLK>,
+                                <&gcc GCC_CFG_NOC_USB_ANOC_NORTH_AHB_CLK>,
+                                <&gcc GCC_CFG_NOC_USB_ANOC_SOUTH_AHB_CLK>,
+                                <&gcc GCC_SYS_NOC_USB_AXI_CLK>;
+                       clock-names = "cfg_noc",
+                                     "core",
+                                     "iface",
+                                     "sleep",
+                                     "mock_utmi",
+                                     "noc_aggr",
+                                     "noc_aggr_north",
+                                     "noc_aggr_south",
+                                     "noc_sys";
+
+                       assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>,
+                                         <&gcc GCC_USB30_PRIM_MASTER_CLK>;
+                       assigned-clock-rates = <19200000>,
+                                              <200000000>;
+
+                       interrupts-extended = <&intc GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 61 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 15 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
+
+                       power-domains = <&gcc GCC_USB30_PRIM_GDSC>;
+                       required-opps = <&rpmhpd_opp_nom>;
+
+                       resets = <&gcc GCC_USB30_PRIM_BCR>;
+
+                       wakeup-source;
+
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       status = "disabled";
+
+                       usb_1_ss0_dwc3: usb@a600000 {
+                               compatible = "snps,dwc3";
+                               reg = <0 0x0a600000 0 0xcd00>;
+
+                               interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+
+                               iommus = <&apps_smmu 0x1420 0x0>;
+
+                               phys = <&usb_1_ss0_hsphy>,
+                                      <&usb_1_ss0_qmpphy QMP_USB43DP_USB3_PHY>;
+                               phy-names = "usb2-phy",
+                                           "usb3-phy";
+
+                               snps,dis_u2_susphy_quirk;
+                               snps,dis_enblslpm_quirk;
+                               snps,usb3_lpm_capable;
+
+                               dma-coherent;
+
+                               port {
+                                       usb_1_ss0_role_switch: endpoint {
+                                       };
+                               };
+                       };
+               };
+
+               usb_1_ss1: usb@a8f8800 {
+                       compatible = "qcom,x1e80100-dwc3", "qcom,dwc3";
+                       reg = <0 0x0a8f8800 0 0x400>;
+
+                       clocks = <&gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>,
+                                <&gcc GCC_USB30_SEC_MASTER_CLK>,
+                                <&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>,
+                                <&gcc GCC_USB30_SEC_SLEEP_CLK>,
+                                <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
+                                <&gcc GCC_AGGRE_USB_NOC_AXI_CLK>,
+                                <&gcc GCC_AGGRE_NOC_USB_NORTH_AXI_CLK>,
+                                <&gcc GCC_AGGRE_NOC_USB_SOUTH_AXI_CLK>,
+                                <&gcc GCC_SYS_NOC_USB_AXI_CLK>;
+                       clock-names = "cfg_noc",
+                                     "core",
+                                     "iface",
+                                     "sleep",
+                                     "mock_utmi",
+                                     "noc_aggr",
+                                     "noc_aggr_north",
+                                     "noc_aggr_south",
+                                     "noc_sys";
+
+                       assigned-clocks = <&gcc GCC_USB30_SEC_MOCK_UTMI_CLK>,
+                                         <&gcc GCC_USB30_SEC_MASTER_CLK>;
+                       assigned-clock-rates = <19200000>,
+                                              <200000000>;
+
+                       interrupts-extended = <&intc GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 60 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 11 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 47 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
+
+                       power-domains = <&gcc GCC_USB30_SEC_GDSC>;
+                       required-opps = <&rpmhpd_opp_nom>;
+
+                       resets = <&gcc GCC_USB30_SEC_BCR>;
+
+                       interconnects = <&usb_south_anoc MASTER_USB3_1 QCOM_ICC_TAG_ALWAYS
+                                        &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+                                       <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
+                                        &config_noc SLAVE_USB3_1 QCOM_ICC_TAG_ALWAYS>;
+                       interconnect-names = "usb-ddr",
+                                            "apps-usb";
+
+                       wakeup-source;
+
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       status = "disabled";
+
+                       usb_1_ss1_dwc3: usb@a800000 {
+                               compatible = "snps,dwc3";
+                               reg = <0 0x0a800000 0 0xcd00>;
+
+                               interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
+
+                               iommus = <&apps_smmu 0x1460 0x0>;
+
+                               phys = <&usb_1_ss1_hsphy>,
+                                      <&usb_1_ss1_qmpphy QMP_USB43DP_USB3_PHY>;
+                               phy-names = "usb2-phy",
+                                           "usb3-phy";
+
+                               snps,dis_u2_susphy_quirk;
+                               snps,dis_enblslpm_quirk;
+                               snps,usb3_lpm_capable;
+
+                               dma-coherent;
+
+                               port {
+                                       usb_1_ss1_role_switch: endpoint {
+                                       };
+                               };
+                       };
+               };
+
+               mdss: display-subsystem@ae00000 {
+                       compatible = "qcom,x1e80100-mdss";
+                       reg = <0 0x0ae00000 0 0x1000>;
+                       reg-names = "mdss";
+
+                       interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+
+                       clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+                                <&gcc GCC_DISP_HF_AXI_CLK>,
+                                <&dispcc DISP_CC_MDSS_MDP_CLK>;
+
+                       resets = <&dispcc DISP_CC_MDSS_CORE_BCR>;
+
+                       interconnects = <&mmss_noc MASTER_MDP QCOM_ICC_TAG_ALWAYS
+                                        &gem_noc SLAVE_LLCC QCOM_ICC_TAG_ALWAYS>,
+                                       <&mc_virt MASTER_LLCC QCOM_ICC_TAG_ALWAYS
+                                        &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+                                       <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY
+                                        &config_noc SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ACTIVE_ONLY>;
+                       interconnect-names = "mdp0-mem",
+                                            "mdp1-mem",
+                                            "cpu-cfg";
+
+                       power-domains = <&dispcc MDSS_GDSC>;
+
+                       iommus = <&apps_smmu 0x1c00 0x2>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       status = "disabled";
+
+                       mdss_mdp: display-controller@ae01000 {
+                               compatible = "qcom,x1e80100-dpu";
+                               reg = <0 0x0ae01000 0 0x8f000>,
+                                     <0 0x0aeb0000 0 0x2008>;
+                               reg-names = "mdp",
+                                           "vbif";
+
+                               interrupts-extended = <&mdss 0>;
+
+                               clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
+                                        <&dispcc DISP_CC_MDSS_AHB_CLK>,
+                                        <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
+                                        <&dispcc DISP_CC_MDSS_MDP_CLK>,
+                                        <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+                               clock-names = "nrt_bus",
+                                             "iface",
+                                             "lut",
+                                             "core",
+                                             "vsync";
+
+                               operating-points-v2 = <&mdp_opp_table>;
+
+                               power-domains = <&rpmhpd RPMHPD_MMCX>;
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+
+                                               mdss_intf0_out: endpoint {
+                                                       remote-endpoint = <&mdss_dp0_in>;
+                                               };
+                                       };
+
+                                       port@4 {
+                                               reg = <4>;
+
+                                               mdss_intf4_out: endpoint {
+                                                       remote-endpoint = <&mdss_dp1_in>;
+                                               };
+                                       };
+
+                                       port@5 {
+                                               reg = <5>;
+
+                                               mdss_intf5_out: endpoint {
+                                                       remote-endpoint = <&mdss_dp3_in>;
+                                               };
+                                       };
+
+                                       port@6 {
+                                               reg = <6>;
+
+                                               mdss_intf6_out: endpoint {
+                                                       remote-endpoint = <&mdss_dp2_in>;
+                                               };
+                                       };
+                               };
+
+                               mdp_opp_table: opp-table {
+                                       compatible = "operating-points-v2";
+
+                                       opp-200000000 {
+                                               opp-hz = /bits/ 64 <200000000>;
+                                               required-opps = <&rpmhpd_opp_low_svs>;
+                                       };
+
+                                       opp-325000000 {
+                                               opp-hz = /bits/ 64 <325000000>;
+                                               required-opps = <&rpmhpd_opp_svs>;
+                                       };
+
+                                       opp-375000000 {
+                                               opp-hz = /bits/ 64 <375000000>;
+                                               required-opps = <&rpmhpd_opp_svs_l1>;
+                                       };
+
+                                       opp-514000000 {
+                                               opp-hz = /bits/ 64 <514000000>;
+                                               required-opps = <&rpmhpd_opp_nom>;
+                                       };
+
+                                       opp-575000000 {
+                                               opp-hz = /bits/ 64 <575000000>;
+                                               required-opps = <&rpmhpd_opp_nom_l1>;
+                                       };
+                               };
+                       };
+
+                       mdss_dp0: displayport-controller@ae90000 {
+                               compatible = "qcom,x1e80100-dp";
+                               reg = <0 0xae90000 0 0x200>,
+                                     <0 0xae90200 0 0x200>,
+                                     <0 0xae90400 0 0x600>,
+                                     <0 0xae91000 0 0x400>,
+                                     <0 0xae91400 0 0x400>;
+
+                               interrupts-extended = <&mdss 12>;
+
+                               clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX0_AUX_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX0_LINK_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX0_LINK_INTF_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX0_PIXEL0_CLK>;
+                               clock-names = "core_iface",
+                                             "core_aux",
+                                             "ctrl_link",
+                                             "ctrl_link_iface",
+                                             "stream_pixel";
+
+                               assigned-clocks = <&dispcc DISP_CC_MDSS_DPTX0_LINK_CLK_SRC>,
+                                                 <&dispcc DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC>;
+                               assigned-clock-parents = <&usb_1_ss0_qmpphy QMP_USB43DP_DP_LINK_CLK>,
+                                                        <&usb_1_ss0_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>;
+
+                               operating-points-v2 = <&mdss_dp0_opp_table>;
+
+                               power-domains = <&rpmhpd RPMHPD_MMCX>;
+
+                               phys = <&usb_1_ss0_qmpphy QMP_USB43DP_DP_PHY>;
+                               phy-names = "dp";
+
+                               #sound-dai-cells = <0>;
+
+                               status = "disabled";
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+
+                                               mdss_dp0_in: endpoint {
+                                                       remote-endpoint = <&mdss_intf0_out>;
+                                               };
+                                       };
+
+                                       port@1 {
+                                               reg = <1>;
+
+                                               mdss_dp0_out: endpoint {
+                                               };
+                                       };
+                               };
+
+                               mdss_dp0_opp_table: opp-table {
+                                       compatible = "operating-points-v2";
+
+                                       opp-160000000 {
+                                               opp-hz = /bits/ 64 <160000000>;
+                                               required-opps = <&rpmhpd_opp_low_svs>;
+                                       };
+
+                                       opp-270000000 {
+                                               opp-hz = /bits/ 64 <270000000>;
+                                               required-opps = <&rpmhpd_opp_svs>;
+                                       };
+
+                                       opp-540000000 {
+                                               opp-hz = /bits/ 64 <540000000>;
+                                               required-opps = <&rpmhpd_opp_svs_l1>;
+                                       };
+
+                                       opp-810000000 {
+                                               opp-hz = /bits/ 64 <810000000>;
+                                               required-opps = <&rpmhpd_opp_nom>;
+                                       };
+                               };
+                       };
+
+                       mdss_dp1: displayport-controller@ae98000 {
+                               compatible = "qcom,x1e80100-dp";
+                               reg = <0 0xae98000 0 0x200>,
+                                     <0 0xae98200 0 0x200>,
+                                     <0 0xae98400 0 0x600>,
+                                     <0 0xae99000 0 0x400>,
+                                     <0 0xae99400 0 0x400>;
+
+                               interrupts-extended = <&mdss 13>;
+
+                               clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX1_AUX_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX1_LINK_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX1_LINK_INTF_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX1_PIXEL0_CLK>;
+                               clock-names = "core_iface",
+                                             "core_aux",
+                                             "ctrl_link",
+                                             "ctrl_link_iface",
+                                             "stream_pixel";
+
+                               assigned-clocks = <&dispcc DISP_CC_MDSS_DPTX1_LINK_CLK_SRC>,
+                                                 <&dispcc DISP_CC_MDSS_DPTX1_PIXEL0_CLK_SRC>;
+                               assigned-clock-parents = <&usb_1_ss1_qmpphy QMP_USB43DP_DP_LINK_CLK>,
+                                                        <&usb_1_ss1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>;
+
+                               operating-points-v2 = <&mdss_dp1_opp_table>;
+
+                               power-domains = <&rpmhpd RPMHPD_MMCX>;
+
+                               phys = <&usb_1_ss1_qmpphy QMP_USB43DP_DP_PHY>;
+                               phy-names = "dp";
+
+                               #sound-dai-cells = <0>;
+
+                               status = "disabled";
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+
+                                               mdss_dp1_in: endpoint {
+                                                       remote-endpoint = <&mdss_intf4_out>;
+                                               };
+                                       };
+
+                                       port@1 {
+                                               reg = <1>;
+
+                                               mdss_dp1_out: endpoint {
+                                               };
+                                       };
+                               };
+
+                               mdss_dp1_opp_table: opp-table {
+                                       compatible = "operating-points-v2";
+
+                                       opp-160000000 {
+                                               opp-hz = /bits/ 64 <160000000>;
+                                               required-opps = <&rpmhpd_opp_low_svs>;
+                                       };
+
+                                       opp-270000000 {
+                                               opp-hz = /bits/ 64 <270000000>;
+                                               required-opps = <&rpmhpd_opp_svs>;
+                                       };
+
+                                       opp-540000000 {
+                                               opp-hz = /bits/ 64 <540000000>;
+                                               required-opps = <&rpmhpd_opp_svs_l1>;
+                                       };
+
+                                       opp-810000000 {
+                                               opp-hz = /bits/ 64 <810000000>;
+                                               required-opps = <&rpmhpd_opp_nom>;
+                                       };
+                               };
+                       };
+
+                       mdss_dp2: displayport-controller@ae9a000 {
+                               compatible = "qcom,x1e80100-dp";
+                               reg = <0 0xae9a000 0 0x200>,
+                                     <0 0xae9a200 0 0x200>,
+                                     <0 0xae9a400 0 0x600>,
+                                     <0 0xae9b000 0 0x400>,
+                                     <0 0xae9b400 0 0x400>;
+
+                               interrupts-extended = <&mdss 14>;
+
+                               clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX2_AUX_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX2_LINK_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX2_LINK_INTF_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX2_PIXEL0_CLK>;
+                               clock-names = "core_iface",
+                                             "core_aux",
+                                             "ctrl_link",
+                                             "ctrl_link_iface",
+                                             "stream_pixel";
+
+                               assigned-clocks = <&dispcc DISP_CC_MDSS_DPTX2_LINK_CLK_SRC>,
+                                                 <&dispcc DISP_CC_MDSS_DPTX2_PIXEL0_CLK_SRC>;
+                               assigned-clock-parents = <&mdss_dp2_phy 0>,
+                                                        <&mdss_dp2_phy 1>;
+
+                               operating-points-v2 = <&mdss_dp2_opp_table>;
+
+                               power-domains = <&rpmhpd RPMHPD_MMCX>;
+
+                               phys = <&mdss_dp2_phy>;
+                               phy-names = "dp";
+
+                               #sound-dai-cells = <0>;
+
+                               status = "disabled";
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+                                               mdss_dp2_in: endpoint {
+                                                       remote-endpoint = <&mdss_intf6_out>;
+                                               };
+                                       };
+
+                                       port@1 {
+                                               reg = <1>;
+                                       };
+                               };
+
+                               mdss_dp2_opp_table: opp-table {
+                                       compatible = "operating-points-v2";
+
+                                       opp-160000000 {
+                                               opp-hz = /bits/ 64 <160000000>;
+                                               required-opps = <&rpmhpd_opp_low_svs>;
+                                       };
+
+                                       opp-270000000 {
+                                               opp-hz = /bits/ 64 <270000000>;
+                                               required-opps = <&rpmhpd_opp_svs>;
+                                       };
+
+                                       opp-540000000 {
+                                               opp-hz = /bits/ 64 <540000000>;
+                                               required-opps = <&rpmhpd_opp_svs_l1>;
+                                       };
+
+                                       opp-810000000 {
+                                               opp-hz = /bits/ 64 <810000000>;
+                                               required-opps = <&rpmhpd_opp_nom>;
+                                       };
+                               };
+                       };
+
+                       mdss_dp3: displayport-controller@aea0000 {
+                               compatible = "qcom,x1e80100-dp";
+                               reg = <0 0xaea0000 0 0x200>,
+                                     <0 0xaea0200 0 0x200>,
+                                     <0 0xaea0400 0 0x600>,
+                                     <0 0xaea1000 0 0x400>,
+                                     <0 0xaea1400 0 0x400>;
+
+                               interrupts-extended = <&mdss 15>;
+
+                               clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX3_AUX_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX3_LINK_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX3_LINK_INTF_CLK>,
+                                        <&dispcc DISP_CC_MDSS_DPTX3_PIXEL0_CLK>;
+                               clock-names = "core_iface",
+                                             "core_aux",
+                                             "ctrl_link",
+                                             "ctrl_link_iface",
+                                             "stream_pixel";
+
+                               assigned-clocks = <&dispcc DISP_CC_MDSS_DPTX3_LINK_CLK_SRC>,
+                                                 <&dispcc DISP_CC_MDSS_DPTX3_PIXEL0_CLK_SRC>;
+                               assigned-clock-parents = <&mdss_dp3_phy 0>,
+                                                        <&mdss_dp3_phy 1>;
+
+                               operating-points-v2 = <&mdss_dp3_opp_table>;
+
+                               power-domains = <&rpmhpd RPMHPD_MMCX>;
+
+                               phys = <&mdss_dp3_phy>;
+                               phy-names = "dp";
+
+                               #sound-dai-cells = <0>;
+
+                               status = "disabled";
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+
+                                               mdss_dp3_in: endpoint {
+                                                       remote-endpoint = <&mdss_intf5_out>;
+
+                                                       link-frequencies = /bits/ 64 <8100000000>;
+                                               };
+                                       };
+
+                                       port@1 {
+                                               reg = <1>;
+                                       };
+                               };
+
+                               mdss_dp3_opp_table: opp-table {
+                                       compatible = "operating-points-v2";
+
+                                       opp-160000000 {
+                                               opp-hz = /bits/ 64 <160000000>;
+                                               required-opps = <&rpmhpd_opp_low_svs>;
+                                       };
+
+                                       opp-270000000 {
+                                               opp-hz = /bits/ 64 <270000000>;
+                                               required-opps = <&rpmhpd_opp_svs>;
+                                       };
+
+                                       opp-540000000 {
+                                               opp-hz = /bits/ 64 <540000000>;
+                                               required-opps = <&rpmhpd_opp_svs_l1>;
+                                       };
+
+                                       opp-810000000 {
+                                               opp-hz = /bits/ 64 <810000000>;
+                                               required-opps = <&rpmhpd_opp_nom>;
+                                       };
+                               };
+                       };
+
+               };
+
+               mdss_dp2_phy: phy@aec2a00 {
+                       compatible = "qcom,x1e80100-dp-phy";
+                       reg = <0 0x0aec2a00 0 0x19c>,
+                             <0 0x0aec2200 0 0xec>,
+                             <0 0x0aec2600 0 0xec>,
+                             <0 0x0aec2000 0 0x1c8>;
+
+                       clocks = <&dispcc DISP_CC_MDSS_DPTX2_AUX_CLK>,
+                                <&dispcc DISP_CC_MDSS_AHB_CLK>;
+                       clock-names = "aux",
+                                     "cfg_ahb";
+
+                       power-domains = <&rpmhpd RPMHPD_MX>;
+
+                       #clock-cells = <1>;
+                       #phy-cells = <0>;
+
+                       status = "disabled";
+               };
+
+               mdss_dp3_phy: phy@aec5a00 {
+                       compatible = "qcom,x1e80100-dp-phy";
+                       reg = <0 0x0aec5a00 0 0x19c>,
+                             <0 0x0aec5200 0 0xec>,
+                             <0 0x0aec5600 0 0xec>,
+                             <0 0x0aec5000 0 0x1c8>;
+
+                       clocks = <&dispcc DISP_CC_MDSS_DPTX3_AUX_CLK>,
+                                <&dispcc DISP_CC_MDSS_AHB_CLK>;
+                       clock-names = "aux",
+                                     "cfg_ahb";
+
+                       power-domains = <&rpmhpd RPMHPD_MX>;
+
+                       #clock-cells = <1>;
+                       #phy-cells = <0>;
+
+                       status = "disabled";
+               };
+
+               dispcc: clock-controller@af00000 {
+                       compatible = "qcom,x1e80100-dispcc";
+                       reg = <0 0x0af00000 0 0x20000>;
+                       clocks = <&bi_tcxo_div2>,
+                                <&bi_tcxo_ao_div2>,
+                                <&gcc GCC_DISP_AHB_CLK>,
+                                <&sleep_clk>,
+                                <0>, /* dsi0 */
+                                <0>,
+                                <0>, /* dsi1 */
+                                <0>,
+                                <&usb_1_ss0_qmpphy QMP_USB43DP_DP_LINK_CLK>, /* dp0 */
+                                <&usb_1_ss0_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>,
+                                <&usb_1_ss1_qmpphy QMP_USB43DP_DP_LINK_CLK>, /* dp1 */
+                                <&usb_1_ss1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>,
+                                <&mdss_dp2_phy 0>, /* dp2 */
+                                <&mdss_dp2_phy 1>,
+                                <&mdss_dp3_phy 0>, /* dp3 */
+                                <&mdss_dp3_phy 1>;
+                       power-domains = <&rpmhpd RPMHPD_MMCX>;
+                       required-opps = <&rpmhpd_opp_low_svs>;
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+                       #power-domain-cells = <1>;
+               };
+
                pdc: interrupt-controller@b220000 {
                        compatible = "qcom,x1e80100-pdc", "qcom,pdc";
                        reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>;
                        interrupt-controller;
                };
 
+               aoss_qmp: power-management@c300000 {
+                       compatible = "qcom,x1e80100-aoss-qmp", "qcom,aoss-qmp";
+                       reg = <0 0x0c300000 0 0x400>;
+                       interrupt-parent = <&ipcc>;
+                       interrupts-extended = <&ipcc IPCC_CLIENT_AOP IPCC_MPROC_SIGNAL_GLINK_QMP
+                                                    IRQ_TYPE_EDGE_RISING>;
+                       mboxes = <&ipcc IPCC_CLIENT_AOP IPCC_MPROC_SIGNAL_GLINK_QMP>;
+
+                       #clock-cells = <0>;
+               };
+
+
                tlmm: pinctrl@f100000 {
                        compatible = "qcom,x1e80100-tlmm";
                        reg = <0 0x0f100000 0 0xf00000>;
                                /* TX, RX */
                                pins = "gpio86", "gpio87";
                                function = "qup2_se5";
-                               drive-strength= <2>;
+                               drive-strength = <2>;
                                bias-disable;
                        };
                };
                              <0 0x17510000 0 0x10000>,
                              <0 0x17520000 0 0x10000>;
                        reg-names = "drv-0", "drv-1", "drv-2";
-                       qcom,drv-count = <3>;
 
                        interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
                                          <WAKE_TCS      2>, <CONTROL_TCS   0>;
 
                        label = "apps_rsc";
+                       power-domains = <&SYSTEM_PD>;
 
                        apps_bcm_voter: bcm-voter {
                                compatible = "qcom,bcm-voter";
                                    "llcc_broadcast_base";
                        interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
                };
+
+               remoteproc_adsp: remoteproc@30000000 {
+                       compatible = "qcom,x1e80100-adsp-pas";
+                       reg = <0 0x30000000 0 0x100>;
+
+                       interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "wdog",
+                                         "fatal",
+                                         "ready",
+                                         "handover",
+                                         "stop-ack";
+
+                       clocks = <&rpmhcc RPMH_CXO_CLK>;
+                       clock-names = "xo";
+
+                       power-domains = <&rpmhpd RPMHPD_LCX>,
+                                       <&rpmhpd RPMHPD_LMX>;
+                       power-domain-names = "lcx",
+                                            "lmx";
+
+                       interconnects = <&lpass_lpicx_noc MASTER_LPASS_PROC QCOM_ICC_TAG_ALWAYS
+                                        &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
+
+                       memory-region = <&adspslpi_mem>,
+                                       <&q6_adsp_dtb_mem>;
+
+                       qcom,qmp = <&aoss_qmp>;
+
+                       qcom,smem-states = <&smp2p_adsp_out 0>;
+                       qcom,smem-state-names = "stop";
+
+                       status = "disabled";
+
+                       glink-edge {
+                               interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
+                                                            IPCC_MPROC_SIGNAL_GLINK_QMP
+                                                            IRQ_TYPE_EDGE_RISING>;
+                               mboxes = <&ipcc IPCC_CLIENT_LPASS
+                                               IPCC_MPROC_SIGNAL_GLINK_QMP>;
+
+                               label = "lpass";
+                               qcom,remote-pid = <2>;
+
+                               gpr {
+                                       compatible = "qcom,gpr";
+                                       qcom,glink-channels = "adsp_apps";
+                                       qcom,domain = <GPR_DOMAIN_ID_ADSP>;
+                                       qcom,intents = <512 20>;
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       q6apm: service@1 {
+                                               compatible = "qcom,q6apm";
+                                               reg = <GPR_APM_MODULE_IID>;
+                                               #sound-dai-cells = <0>;
+                                               qcom,protection-domain = "avs/audio",
+                                                                        "msm/adsp/audio_pd";
+
+                                               q6apmbedai: bedais {
+                                                       compatible = "qcom,q6apm-lpass-dais";
+                                                       #sound-dai-cells = <1>;
+                                               };
+
+                                               q6apmdai: dais {
+                                                       compatible = "qcom,q6apm-dais";
+                                                       iommus = <&apps_smmu 0x1001 0x80>,
+                                                                <&apps_smmu 0x1061 0x0>;
+                                               };
+                                       };
+
+                                       q6prm: service@2 {
+                                               compatible = "qcom,q6prm";
+                                               reg = <GPR_PRM_MODULE_IID>;
+                                               qcom,protection-domain = "avs/audio",
+                                                                        "msm/adsp/audio_pd";
+
+                                               q6prmcc: clock-controller {
+                                                       compatible = "qcom,q6prm-lpass-clocks";
+                                                       #clock-cells = <2>;
+                                               };
+                                       };
+                               };
+                       };
+               };
+
+               remoteproc_cdsp: remoteproc@32300000 {
+                       compatible = "qcom,x1e80100-cdsp-pas";
+                       reg = <0 0x32300000 0 0x1400000>;
+
+                       interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_cdsp_in 0 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_cdsp_in 1 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_cdsp_in 2 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_cdsp_in 3 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "wdog",
+                                         "fatal",
+                                         "ready",
+                                         "handover",
+                                         "stop-ack";
+
+                       clocks = <&rpmhcc RPMH_CXO_CLK>;
+                       clock-names = "xo";
+
+                       power-domains = <&rpmhpd RPMHPD_CX>,
+                                       <&rpmhpd RPMHPD_MXC>,
+                                       <&rpmhpd RPMHPD_NSP>;
+                       power-domain-names = "cx",
+                                            "mxc",
+                                            "nsp";
+
+                       interconnects = <&nsp_noc MASTER_CDSP_PROC QCOM_ICC_TAG_ALWAYS
+                                        &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
+
+                       memory-region = <&cdsp_mem>,
+                                       <&q6_cdsp_dtb_mem>;
+
+                       qcom,qmp = <&aoss_qmp>;
+
+                       qcom,smem-states = <&smp2p_cdsp_out 0>;
+                       qcom,smem-state-names = "stop";
+
+                       status = "disabled";
+
+                       glink-edge {
+                               interrupts-extended = <&ipcc IPCC_CLIENT_CDSP
+                                                            IPCC_MPROC_SIGNAL_GLINK_QMP
+                                                            IRQ_TYPE_EDGE_RISING>;
+                               mboxes = <&ipcc IPCC_CLIENT_CDSP
+                                               IPCC_MPROC_SIGNAL_GLINK_QMP>;
+
+                               label = "cdsp";
+                               qcom,remote-pid = <5>;
+                       };
+               };
        };
 
        timer {
index 8ea68d5827105b76f539326668783e4ccde5887d..5f3e0e61d78d130cfb68f836d8a0800324382a2d 100644 (file)
@@ -82,10 +82,15 @@ dtb-$(CONFIG_ARCH_R8A779F0) += r8a779f0-spider.dtb
 dtb-$(CONFIG_ARCH_R8A779F0) += r8a779f4-s4sk.dtb
 
 dtb-$(CONFIG_ARCH_R8A779G0) += r8a779g0-white-hawk.dtb
+dtb-$(CONFIG_ARCH_R8A779G0) += r8a779g0-white-hawk-cpu.dtb
 dtb-$(CONFIG_ARCH_R8A779G0) += r8a779g0-white-hawk-ard-audio-da7212.dtbo
 r8a779g0-white-hawk-ard-audio-da7212-dtbs := r8a779g0-white-hawk.dtb r8a779g0-white-hawk-ard-audio-da7212.dtbo
 dtb-$(CONFIG_ARCH_R8A779G0) += r8a779g0-white-hawk-ard-audio-da7212.dtb
 
+dtb-$(CONFIG_ARCH_R8A779G0) += r8a779g2-white-hawk-single.dtb
+
+dtb-$(CONFIG_ARCH_R8A779H0) += r8a779h0-gray-hawk-single.dtb
+
 dtb-$(CONFIG_ARCH_R8A77951) += r8a779m1-salvator-xs.dtb
 r8a779m1-salvator-xs-panel-aa104xd12-dtbs := r8a779m1-salvator-xs.dtb salvator-panel-aa104xd12.dtbo
 dtb-$(CONFIG_ARCH_R8A77951) += r8a779m1-salvator-xs-panel-aa104xd12.dtb
@@ -103,7 +108,10 @@ r8a779m5-salvator-xs-panel-aa104xd12-dtbs := r8a779m5-salvator-xs.dtb salvator-p
 dtb-$(CONFIG_ARCH_R8A77965) += r8a779m5-salvator-xs-panel-aa104xd12.dtb
 
 dtb-$(CONFIG_ARCH_R9A07G043) += r9a07g043u11-smarc.dtb
+dtb-$(CONFIG_ARCH_R9A07G043) += r9a07g043u11-smarc-cru-csi-ov5645.dtbo
 dtb-$(CONFIG_ARCH_R9A07G043) += r9a07g043-smarc-pmod.dtbo
+r9a07g043u11-smarc-cru-csi-ov5645-dtbs := r9a07g043u11-smarc.dtb r9a07g043u11-smarc-cru-csi-ov5645.dtbo
+dtb-$(CONFIG_ARCH_R9A07G043) += r9a07g043u11-smarc-cru-csi-ov5645.dtb
 r9a07g043u11-smarc-pmod-dtbs := r9a07g043u11-smarc.dtb r9a07g043-smarc-pmod.dtbo
 dtb-$(CONFIG_ARCH_R9A07G043) += r9a07g043u11-smarc-pmod.dtb
 
index 95b0a1f6debfcefb26c2635bdd2bb4735857e6c1..a8a44fe5e83bbd5c9d0095caabd57115e189cdcd 100644 (file)
                        interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 125>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 124>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 123>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 122>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 121>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774A1_PD_ALWAYS_ON>;
index 786660fcdea42b475610d889bb327bf3817b6138..4fff511e994cf8408b75b0e02a156c18ce12c4e4 100644 (file)
                        interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 125>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 124>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 123>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 122>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 121>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774B1_PD_ALWAYS_ON>;
index eed94ffed7c11cbf8bfcc167ced3fcc56d8b4180..1ef43d78c3a5740b241a9c9e3993720b23797ce9 100644 (file)
                        interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 125>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 124>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 123>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 122>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 121>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
index 175e5d296da6cec64effad9e89fdf150a6b76b64..be55ae83944cf225b1d207e57ab787bb5b45cd6b 100644 (file)
                        interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 125>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774E1_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 124>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774E1_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 123>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774E1_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 122>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774E1_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 121>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A774E1_PD_ALWAYS_ON>;
index a4260d9291bac365549d7d93c11b267abf70ab05..bea4edd17d5349099de7e18c00e395560603b01b 100644 (file)
                        interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 125>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 124>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 123>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 122>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 121>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
index a631ead171b29a4363933ca1755fcf76f79bc653..7846fea8e40da725c80bc588b6dd3331e0ea75cc 100644 (file)
                        interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 125>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 124>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 123>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 122>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 121>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
index 7254912a241f96f302c14a33c800546eac5d47e0..58f9286a5ab575340062886e95293ae771ea4b31 100644 (file)
                        interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 125>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77961_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 124>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77961_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 123>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77961_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 122>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77961_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 121>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77961_PD_ALWAYS_ON>;
index e57b9027066eb6e7b5ad4b176c12675841ec8c7d..692940662d38d89a8e345fe97b58ced327c53a39 100644 (file)
                        interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 125>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 124>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 123>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 122>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 121>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
index ed6e2e47c60479efbb28f43679ebd222e936c9f1..d2d3cecc76d52f8602d13abcc534f1944772d62f 100644 (file)
                        interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 125>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 124>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 123>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 122>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 121>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
index 5ed2daaca1f006493f037e7e84a782161d904219..c0ba110c74d6a3ac1eb63b7f1a7d3c1667495a1c 100644 (file)
                        interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 125>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 124>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 123>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        reg = <0 0xe6fe0000 0 0x30>;
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 122>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
                        reg = <0 0xffc00000 0 0x30>;
                        interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 369 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 121>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
index 8c2b28342387c7f2a5d76109eb6d0fb6113a5a44..37063e3f4e1be06d30ed236c55d928426a3829af 100644 (file)
                        interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 125>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 124>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 123>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 122>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 121>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77990_PD_ALWAYS_ON>;
index 8cf6473c63d37dd09479150dfece4512e0724b7e..89990dd8ebf7f18226977b735e645497fe932083 100644 (file)
                        interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 125>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 124>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 123>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 122>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 121>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
index 4e67a03564971b89a5b2fb7564b2eb93aa549819..cfa70b441e329a0b5c946d8542d64fbbfa789605 100644 (file)
                        interrupts = <GIC_SPI 512 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 513 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 514 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 713>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 504 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 505 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 506 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 506 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 507 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 714>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 508 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 509 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 510 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 510 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 511 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 715>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>;
                        reg = <0 0xe6fe0000 0 0x30>;
                        interrupts = <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 475 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 716>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>;
                        reg = <0 0xffc00000 0 0x30>;
                        interrupts = <GIC_SPI 476 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 478 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 478 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 479 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 717>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>;
                avb0: ethernet@e6800000 {
                        compatible = "renesas,etheravb-r8a779a0",
                                     "renesas,etheravb-rcar-gen4";
-                       reg = <0 0xe6800000 0 0x800>;
+                       reg = <0 0xe6800000 0 0x1000>;
                        interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>,
                avb1: ethernet@e6810000 {
                        compatible = "renesas,etheravb-r8a779a0",
                                     "renesas,etheravb-rcar-gen4";
-                       reg = <0 0xe6810000 0 0x800>;
+                       reg = <0 0xe6810000 0 0x1000>;
                        interrupts = <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>,
index 7fb4989cce8a63f176d7b8a7ac9c45cd9276c85a..72cf30341fc4d63eaa4df95f67c19550d1bf2674 100644 (file)
                        interrupts = <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 475 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 476 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 713>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 478 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 479 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 479 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 480 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 714>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 481 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 482 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 483 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 483 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 484 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 715>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
                        reg = <0 0xe6fe0000 0 0x30>;
                        interrupts = <GIC_SPI 485 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 486 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 487 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 487 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 488 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 716>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
                        reg = <0 0xffc00000 0 0x30>;
                        interrupts = <GIC_SPI 489 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 490 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 491 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 491 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 492 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 717>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
diff --git a/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dts b/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dts
new file mode 100644 (file)
index 0000000..c8b1bb5
--- /dev/null
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the standalone R-Car V4H White Hawk CPU board
+ *
+ * Copyright (C) 2023 Glider bv
+ */
+
+/dts-v1/;
+#include "r8a779g0-white-hawk-cpu.dtsi"
+
+/ {
+       model = "Renesas White Hawk CPU board based on r8a779g0";
+};
index 913f70fe6c5cd2d802474484a92c70bc9eb67cea..b1fe1aedc27d151df210aeb53d5bbf36b0d85044 100644 (file)
 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 /*
- * Device Tree Source for the White Hawk CPU board
+ * Device Tree Source for the R-Car V4H White Hawk CPU board
  *
  * Copyright (C) 2022 Renesas Electronics Corp.
  */
 
 #include "r8a779g0.dtsi"
-
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/leds/common.h>
+#include "white-hawk-cpu-common.dtsi"
 
 / {
        model = "Renesas White Hawk CPU board";
        compatible = "renesas,white-hawk-cpu", "renesas,r8a779g0";
-
-       aliases {
-               ethernet0 = &avb0;
-               serial0 = &hscif0;
-       };
-
-       chosen {
-               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
-               stdout-path = "serial0:921600n8";
-       };
-
-       keys {
-               compatible = "gpio-keys";
-
-               pinctrl-0 = <&keys_pins>;
-               pinctrl-names = "default";
-
-               key-1 {
-                       gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_1>;
-                       label = "SW47";
-                       wakeup-source;
-                       debounce-interval = <20>;
-               };
-
-               key-2 {
-                       gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_2>;
-                       label = "SW48";
-                       wakeup-source;
-                       debounce-interval = <20>;
-               };
-
-               key-3 {
-                       gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_3>;
-                       label = "SW49";
-                       wakeup-source;
-                       debounce-interval = <20>;
-               };
-       };
-
-       leds {
-               compatible = "gpio-leds";
-
-               led-1 {
-                       gpios = <&gpio7 0 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-                       function = LED_FUNCTION_INDICATOR;
-                       function-enumerator = <1>;
-               };
-
-               led-2 {
-                       gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-                       function = LED_FUNCTION_INDICATOR;
-                       function-enumerator = <2>;
-               };
-
-               led-3 {
-                       gpios = <&gpio7 2 GPIO_ACTIVE_HIGH>;
-                       color = <LED_COLOR_ID_GREEN>;
-                       function = LED_FUNCTION_INDICATOR;
-                       function-enumerator = <3>;
-               };
-       };
-
-       memory@48000000 {
-               device_type = "memory";
-               /* first 128MB is reserved for secure area. */
-               reg = <0x0 0x48000000 0x0 0x78000000>;
-       };
-
-       memory@480000000 {
-               device_type = "memory";
-               reg = <0x4 0x80000000 0x0 0x80000000>;
-       };
-
-       memory@600000000 {
-               device_type = "memory";
-               reg = <0x6 0x00000000 0x1 0x00000000>;
-       };
-
-       mini-dp-con {
-               compatible = "dp-connector";
-               label = "CN5";
-               type = "mini";
-
-               port {
-                       mini_dp_con_in: endpoint {
-                               remote-endpoint = <&sn65dsi86_out>;
-                       };
-               };
-       };
-
-       reg_1p2v: regulator-1p2v {
-               compatible = "regulator-fixed";
-               regulator-name = "fixed-1.2V";
-               regulator-min-microvolt = <1200000>;
-               regulator-max-microvolt = <1200000>;
-               regulator-boot-on;
-               regulator-always-on;
-       };
-
-       reg_1p8v: regulator-1p8v {
-               compatible = "regulator-fixed";
-               regulator-name = "fixed-1.8V";
-               regulator-min-microvolt = <1800000>;
-               regulator-max-microvolt = <1800000>;
-               regulator-boot-on;
-               regulator-always-on;
-       };
-
-       reg_3p3v: regulator-3p3v {
-               compatible = "regulator-fixed";
-               regulator-name = "fixed-3.3V";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
-               regulator-boot-on;
-               regulator-always-on;
-       };
-
-       sn65dsi86_refclk: clk-x6 {
-               compatible = "fixed-clock";
-               #clock-cells = <0>;
-               clock-frequency = <38400000>;
-       };
-};
-
-&avb0 {
-       pinctrl-0 = <&avb0_pins>;
-       pinctrl-names = "default";
-       phy-handle = <&phy0>;
-       tx-internal-delay-ps = <2000>;
-       status = "okay";
-
-       phy0: ethernet-phy@0 {
-               compatible = "ethernet-phy-id0022.1622",
-                            "ethernet-phy-ieee802.3-c22";
-               rxc-skew-ps = <1500>;
-               reg = <0>;
-               interrupt-parent = <&gpio7>;
-               interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
-               reset-gpios = <&gpio7 10 GPIO_ACTIVE_LOW>;
-       };
-};
-
-&dsi0 {
-       status = "okay";
-
-       ports {
-               port@1 {
-                       dsi0_out: endpoint {
-                               remote-endpoint = <&sn65dsi86_in>;
-                               data-lanes = <1 2 3 4>;
-                       };
-               };
-       };
-};
-
-&du {
-       status = "okay";
-};
-
-&extal_clk {
-       clock-frequency = <16666666>;
-};
-
-&extalr_clk {
-       clock-frequency = <32768>;
-};
-
-&hscif0 {
-       pinctrl-0 = <&hscif0_pins>;
-       pinctrl-names = "default";
-
-       status = "okay";
-};
-
-&i2c0 {
-       pinctrl-0 = <&i2c0_pins>;
-       pinctrl-names = "default";
-
-       status = "okay";
-       clock-frequency = <400000>;
-
-       io_expander_a: gpio@20 {
-               compatible = "onnn,pca9654";
-               reg = <0x20>;
-               interrupt-parent = <&gpio0>;
-               interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
-               gpio-controller;
-               #gpio-cells = <2>;
-               interrupt-controller;
-               #interrupt-cells = <2>;
-       };
-
-       eeprom@50 {
-               compatible = "rohm,br24g01", "atmel,24c01";
-               label = "cpu-board";
-               reg = <0x50>;
-               pagesize = <8>;
-       };
-};
-
-&i2c1 {
-       pinctrl-0 = <&i2c1_pins>;
-       pinctrl-names = "default";
-
-       status = "okay";
-       clock-frequency = <400000>;
-
-       bridge@2c {
-               compatible = "ti,sn65dsi86";
-               reg = <0x2c>;
-
-               clocks = <&sn65dsi86_refclk>;
-               clock-names = "refclk";
-
-               interrupt-parent = <&intc_ex>;
-               interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
-
-               enable-gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>;
-
-               vccio-supply = <&reg_1p8v>;
-               vpll-supply = <&reg_1p8v>;
-               vcca-supply = <&reg_1p2v>;
-               vcc-supply = <&reg_1p2v>;
-
-               ports {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       port@0 {
-                               reg = <0>;
-                               sn65dsi86_in: endpoint {
-                                       remote-endpoint = <&dsi0_out>;
-                               };
-                       };
-
-                       port@1 {
-                               reg = <1>;
-                               sn65dsi86_out: endpoint {
-                                       remote-endpoint = <&mini_dp_con_in>;
-                               };
-                       };
-               };
-       };
-};
-
-&mmc0 {
-       pinctrl-0 = <&mmc_pins>;
-       pinctrl-1 = <&mmc_pins>;
-       pinctrl-names = "default", "state_uhs";
-
-       vmmc-supply = <&reg_3p3v>;
-       vqmmc-supply = <&reg_1p8v>;
-       mmc-hs200-1_8v;
-       mmc-hs400-1_8v;
-       bus-width = <8>;
-       no-sd;
-       no-sdio;
-       non-removable;
-       full-pwr-cycle-in-suspend;
-       status = "okay";
-};
-
-&pfc {
-       pinctrl-0 = <&scif_clk_pins>;
-       pinctrl-names = "default";
-
-       avb0_pins: avb0 {
-               mux {
-                       groups = "avb0_link", "avb0_mdio", "avb0_rgmii",
-                                "avb0_txcrefclk";
-                       function = "avb0";
-               };
-
-               pins_mdio {
-                       groups = "avb0_mdio";
-                       drive-strength = <21>;
-               };
-
-               pins_mii {
-                       groups = "avb0_rgmii";
-                       drive-strength = <21>;
-               };
-
-       };
-       hscif0_pins: hscif0 {
-               groups = "hscif0_data";
-               function = "hscif0";
-       };
-
-       i2c0_pins: i2c0 {
-               groups = "i2c0";
-               function = "i2c0";
-       };
-
-       i2c1_pins: i2c1 {
-               groups = "i2c1";
-               function = "i2c1";
-       };
-
-       keys_pins: keys {
-               pins = "GP_5_0", "GP_5_1", "GP_5_2";
-               bias-pull-up;
-       };
-
-       mmc_pins: mmc {
-               groups = "mmc_data8", "mmc_ctrl", "mmc_ds";
-               function = "mmc";
-               power-source = <1800>;
-       };
-
-       qspi0_pins: qspi0 {
-               groups = "qspi0_ctrl", "qspi0_data4";
-               function = "qspi0";
-       };
-
-       scif_clk_pins: scif_clk {
-               groups = "scif_clk";
-               function = "scif_clk";
-       };
-};
-
-&rpc {
-       pinctrl-0 = <&qspi0_pins>;
-       pinctrl-names = "default";
-
-       status = "okay";
-
-       flash@0 {
-               compatible = "spansion,s25fs512s", "jedec,spi-nor";
-               reg = <0>;
-               spi-max-frequency = <40000000>;
-               spi-rx-bus-width = <4>;
-
-               partitions {
-                       compatible = "fixed-partitions";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       boot@0 {
-                               reg = <0x0 0x1200000>;
-                               read-only;
-                       };
-                       user@1200000 {
-                               reg = <0x1200000 0x2e00000>;
-                       };
-               };
-       };
-};
-
-&rwdt {
-       timeout-sec = <60>;
-       status = "okay";
-};
-
-&scif_clk {
-       clock-frequency = <24000000>;
 };
index eff1ef6e2cc83aba94d041996682b3616002c1be..784d4e8b204ce85ace90778133f4148e1662e238 100644 (file)
@@ -1,69 +1,15 @@
 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 /*
- * Device Tree Source for the White Hawk CPU and BreakOut boards
+ * Device Tree Source for the R-Car V4H White Hawk CPU and BreakOut boards
  *
  * Copyright (C) 2022 Renesas Electronics Corp.
  */
 
 /dts-v1/;
 #include "r8a779g0-white-hawk-cpu.dtsi"
-#include "r8a779g0-white-hawk-csi-dsi.dtsi"
-#include "r8a779g0-white-hawk-ethernet.dtsi"
+#include "white-hawk-common.dtsi"
 
 / {
        model = "Renesas White Hawk CPU and Breakout boards based on r8a779g0";
        compatible = "renesas,white-hawk-breakout", "renesas,white-hawk-cpu", "renesas,r8a779g0";
-
-       can_transceiver0: can-phy0 {
-               compatible = "nxp,tjr1443";
-               #phy-cells = <0>;
-               enable-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
-               max-bitrate = <5000000>;
-       };
-};
-
-&can_clk {
-       clock-frequency = <40000000>;
-};
-
-&canfd {
-       pinctrl-0 = <&canfd0_pins>, <&canfd1_pins>, <&can_clk_pins>;
-       pinctrl-names = "default";
-
-       status = "okay";
-
-       channel0 {
-               status = "okay";
-               phys = <&can_transceiver0>;
-       };
-
-       channel1 {
-               status = "okay";
-       };
-};
-
-&i2c0 {
-       eeprom@51 {
-               compatible = "rohm,br24g01", "atmel,24c01";
-               label = "breakout-board";
-               reg = <0x51>;
-               pagesize = <8>;
-       };
-};
-
-&pfc {
-       can_clk_pins: can-clk {
-               groups = "can_clk";
-               function = "can_clk";
-       };
-
-       canfd0_pins: canfd0 {
-               groups = "canfd0_data";
-               function = "canfd0";
-       };
-
-       canfd1_pins: canfd1 {
-               groups = "canfd1_data";
-               function = "canfd1";
-       };
 };
index d3d25e077c5d50531baf7d0dc2925f35f2dbc4c1..9bc542bc616909d17a54e638d9796f01abf5c794 100644 (file)
                };
        };
 
-       psci {
-               compatible = "arm,psci-1.0", "arm,psci-0.2";
-               method = "smc";
-       };
-
        extal_clk: extal {
                compatible = "fixed-clock";
                #clock-cells = <0>;
                interrupts-extended = <&gic GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>;
        };
 
-       /* External SCIF clock - to be overridden by boards that provide it */
+       psci {
+               compatible = "arm,psci-1.0", "arm,psci-0.2";
+               method = "smc";
+       };
+
+       /* External SCIF clocks - to be overridden by boards that provide them */
        scif_clk: scif {
                compatible = "fixed-clock";
                #clock-cells = <0>;
                clock-frequency = <0>;
        };
 
+       scif_clk2: scif2 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
        soc: soc {
                compatible = "simple-bus";
                interrupt-parent = <&gic>;
                        interrupts = <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 291 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2";
                        clocks = <&cpg CPG_MOD 713>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
                        reg = <0 0xe6fc0000 0 0x30>;
                        interrupts = <GIC_SPI 292 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 294 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 294 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 295 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 714>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
                        reg = <0 0xe6fd0000 0 0x30>;
                        interrupts = <GIC_SPI 296 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 715>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
                        reg = <0 0xe6fe0000 0 0x30>;
                        interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 716>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
                        reg = <0 0xffc00000 0 0x30>;
                        interrupts = <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
                        clocks = <&cpg CPG_MOD 717>;
                        clock-names = "fck";
                        power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
                        interrupts = <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 516>,
                                 <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>,
-                                <&scif_clk>;
+                                <&scif_clk2>;
                        clock-names = "fck", "brg_int", "scif_clk";
                        dmas = <&dmac0 0x35>, <&dmac0 0x34>,
                               <&dmac1 0x35>, <&dmac1 0x34>;
                avb0: ethernet@e6800000 {
                        compatible = "renesas,etheravb-r8a779g0",
                                     "renesas,etheravb-rcar-gen4";
-                       reg = <0 0xe6800000 0 0x800>;
+                       reg = <0 0xe6800000 0 0x1000>;
                        interrupts = <GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>,
                avb1: ethernet@e6810000 {
                        compatible = "renesas,etheravb-r8a779g0",
                                     "renesas,etheravb-rcar-gen4";
-                       reg = <0 0xe6810000 0 0x800>;
+                       reg = <0 0xe6810000 0 0x1000>;
                        interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 362 IRQ_TYPE_LEVEL_HIGH>,
                        interrupts = <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 705>,
                                 <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>,
-                                <&scif_clk>;
+                                <&scif_clk2>;
                        clock-names = "fck", "brg_int", "scif_clk";
                        dmas = <&dmac0 0x59>, <&dmac0 0x58>,
                               <&dmac1 0x59>, <&dmac1 0x58>;
                        };
                };
 
+               mmc0: mmc@ee140000 {
+                       compatible = "renesas,sdhi-r8a779g0",
+                                    "renesas,rcar-gen4-sdhi";
+                       reg = <0 0xee140000 0 0x2000>;
+                       interrupts = <GIC_SPI 440 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 706>,
+                                <&cpg CPG_CORE R8A779G0_CLK_SD0H>;
+                       clock-names = "core", "clkh";
+                       power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+                       resets = <&cpg 706>;
+                       max-frequency = <200000000>;
+                       iommus = <&ipmmu_ds0 32>;
+                       status = "disabled";
+               };
+
+               rpc: spi@ee200000 {
+                       compatible = "renesas,r8a779g0-rpc-if",
+                                    "renesas,rcar-gen4-rpc-if";
+                       reg = <0 0xee200000 0 0x200>,
+                             <0 0x08000000 0 0x04000000>,
+                             <0 0xee208000 0 0x100>;
+                       reg-names = "regs", "dirmap", "wbuf";
+                       interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 629>;
+                       power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
+                       resets = <&cpg 629>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
                ipmmu_rt0: iommu@ee480000 {
                        compatible = "renesas,ipmmu-r8a779g0",
                                     "renesas,rcar-gen4-ipmmu-vmsa";
                        #iommu-cells = <1>;
                };
 
-               mmc0: mmc@ee140000 {
-                       compatible = "renesas,sdhi-r8a779g0",
-                                    "renesas,rcar-gen4-sdhi";
-                       reg = <0 0xee140000 0 0x2000>;
-                       interrupts = <GIC_SPI 440 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&cpg CPG_MOD 706>,
-                                <&cpg CPG_CORE R8A779G0_CLK_SD0H>;
-                       clock-names = "core", "clkh";
-                       power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
-                       resets = <&cpg 706>;
-                       max-frequency = <200000000>;
-                       iommus = <&ipmmu_ds0 32>;
-                       status = "disabled";
-               };
-
-               rpc: spi@ee200000 {
-                       compatible = "renesas,r8a779g0-rpc-if",
-                                    "renesas,rcar-gen4-rpc-if";
-                       reg = <0 0xee200000 0 0x200>,
-                             <0 0x08000000 0 0x04000000>,
-                             <0 0xee208000 0 0x100>;
-                       reg-names = "regs", "dirmap", "wbuf";
-                       interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&cpg CPG_MOD 629>;
-                       power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>;
-                       resets = <&cpg 629>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       status = "disabled";
-               };
-
                gic: interrupt-controller@f1000000 {
                        compatible = "arm,gic-v3";
                        #interrupt-cells = <3>;
diff --git a/arch/arm64/boot/dts/renesas/r8a779g2-white-hawk-single.dts b/arch/arm64/boot/dts/renesas/r8a779g2-white-hawk-single.dts
new file mode 100644 (file)
index 0000000..2f79e5a
--- /dev/null
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the R-Car V4H ES2.0 White Hawk Single board
+ *
+ * Copyright (C) 2023 Glider bv
+ */
+
+/dts-v1/;
+#include "r8a779g2.dtsi"
+#include "white-hawk-cpu-common.dtsi"
+#include "white-hawk-common.dtsi"
+
+/ {
+       model = "Renesas White Hawk Single board based on r8a779g2";
+       compatible = "renesas,white-hawk-single", "renesas,r8a779g2",
+                    "renesas,r8a779g0";
+};
+
+&hscif0 {
+       uart-has-rtscts;
+};
+
+&hscif0_pins {
+       groups = "hscif0_data", "hscif0_ctrl";
+       function = "hscif0";
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a779g2.dtsi b/arch/arm64/boot/dts/renesas/r8a779g2.dtsi
new file mode 100644 (file)
index 0000000..e08f531
--- /dev/null
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the R-Car V4H (R8A779G2) SoC
+ *
+ * Copyright (C) 2023 Glider bv
+ */
+
+#include "r8a779g0.dtsi"
+
+/ {
+       compatible = "renesas,r8a779g2", "renesas,r8a779g0";
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a779h0-gray-hawk-single.dts b/arch/arm64/boot/dts/renesas/r8a779h0-gray-hawk-single.dts
new file mode 100644 (file)
index 0000000..bc8616a
--- /dev/null
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the R-Car V4M Gray Hawk Single board
+ *
+ * Copyright (C) 2023 Renesas Electronics Corp.
+ * Copyright (C) 2024 Glider bv
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "r8a779h0.dtsi"
+
+/ {
+       model = "Renesas Gray Hawk Single board based on r8a779h0";
+       compatible = "renesas,gray-hawk-single", "renesas,r8a779h0";
+
+       aliases {
+               serial0 = &hscif0;
+               ethernet0 = &avb0;
+       };
+
+       chosen {
+               bootargs = "ignore_loglevel";
+               stdout-path = "serial0:921600n8";
+       };
+
+       memory@48000000 {
+               device_type = "memory";
+               /* first 128MB is reserved for secure area. */
+               reg = <0x0 0x48000000 0x0 0x78000000>;
+       };
+
+       memory@480000000 {
+               device_type = "memory";
+               reg = <0x4 0x80000000 0x1 0x80000000>;
+       };
+
+       reg_1p8v: regulator-1p8v {
+                       compatible = "regulator-fixed";
+                       regulator-name = "fixed-1.8V";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-boot-on;
+                       regulator-always-on;
+       };
+
+       reg_3p3v: regulator-3p3v {
+                       compatible = "regulator-fixed";
+                       regulator-name = "fixed-3.3V";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-boot-on;
+                       regulator-always-on;
+       };
+};
+
+&avb0 {
+       pinctrl-0 = <&avb0_pins>;
+       pinctrl-names = "default";
+       phy-handle = <&phy0>;
+       tx-internal-delay-ps = <2000>;
+       status = "okay";
+
+       phy0: ethernet-phy@0 {
+               compatible = "ethernet-phy-id0022.1622",
+                            "ethernet-phy-ieee802.3-c22";
+               rxc-skew-ps = <1500>;
+               reg = <0>;
+               interrupt-parent = <&gpio7>;
+               interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
+               reset-gpios = <&gpio7 10 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&extal_clk {
+       clock-frequency = <16666666>;
+};
+
+&extalr_clk {
+       clock-frequency = <32768>;
+};
+
+&hscif0 {
+       pinctrl-0 = <&hscif0_pins>;
+       pinctrl-names = "default";
+
+       uart-has-rtscts;
+       status = "okay";
+};
+
+&i2c0 {
+       pinctrl-0 = <&i2c0_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+       clock-frequency = <400000>;
+
+       eeprom@50 {
+               compatible = "rohm,br24g01", "atmel,24c01";
+               label = "cpu-board";
+               reg = <0x50>;
+               pagesize = <8>;
+       };
+
+       eeprom@51 {
+               compatible = "rohm,br24g01", "atmel,24c01";
+               label = "breakout-board";
+               reg = <0x51>;
+               pagesize = <8>;
+       };
+
+       eeprom@52 {
+               compatible = "rohm,br24g01", "atmel,24c01";
+               label = "csi-dsi-sub-board-id";
+               reg = <0x52>;
+               pagesize = <8>;
+       };
+
+       eeprom@53 {
+               compatible = "rohm,br24g01", "atmel,24c01";
+               label = "ethernet-sub-board-id";
+               reg = <0x53>;
+               pagesize = <8>;
+       };
+};
+
+&mmc0 {
+       pinctrl-0 = <&mmc_pins>;
+       pinctrl-1 = <&mmc_pins>;
+       pinctrl-names = "default", "state_uhs";
+
+       vmmc-supply = <&reg_3p3v>;
+       vqmmc-supply = <&reg_1p8v>;
+       mmc-hs200-1_8v;
+       mmc-hs400-1_8v;
+       bus-width = <8>;
+       no-sd;
+       no-sdio;
+       non-removable;
+       full-pwr-cycle-in-suspend;
+       status = "okay";
+};
+
+&pfc {
+       pinctrl-0 = <&scif_clk_pins>;
+       pinctrl-names = "default";
+
+       avb0_pins: avb0 {
+               mux {
+                       groups = "avb0_link", "avb0_mdio", "avb0_rgmii",
+                                "avb0_txcrefclk";
+                       function = "avb0";
+               };
+
+               pins_mdio {
+                       groups = "avb0_mdio";
+                       drive-strength = <21>;
+               };
+
+               pins_mii {
+                       groups = "avb0_rgmii";
+                       drive-strength = <21>;
+               };
+       };
+
+       hscif0_pins: hscif0 {
+               groups = "hscif0_data", "hscif0_ctrl";
+               function = "hscif0";
+       };
+
+       i2c0_pins: i2c0 {
+               groups = "i2c0";
+               function = "i2c0";
+       };
+
+       mmc_pins: mmc {
+               groups = "mmc_data8", "mmc_ctrl", "mmc_ds";
+               function = "mmc";
+               power-source = <1800>;
+       };
+
+       qspi0_pins: qspi0 {
+               groups = "qspi0_ctrl", "qspi0_data4";
+               function = "qspi0";
+       };
+
+       scif_clk_pins: scif-clk {
+               groups = "scif_clk";
+               function = "scif_clk";
+       };
+};
+
+&rpc {
+       pinctrl-0 = <&qspi0_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+
+       flash@0 {
+               compatible = "spansion,s25fs512s", "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <40000000>;
+               spi-rx-bus-width = <4>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       boot@0 {
+                               reg = <0x0 0x1200000>;
+                               read-only;
+                       };
+                       user@1200000 {
+                               reg = <0x1200000 0x2e00000>;
+                       };
+               };
+       };
+};
+
+&rwdt {
+       timeout-sec = <60>;
+       status = "okay";
+};
+
+&scif_clk {
+       clock-frequency = <24000000>;
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a779h0.dtsi b/arch/arm64/boot/dts/renesas/r8a779h0.dtsi
new file mode 100644 (file)
index 0000000..1188572
--- /dev/null
@@ -0,0 +1,664 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the R-Car V4M (R8A779H0) SoC
+ *
+ * Copyright (C) 2023 Renesas Electronics Corp.
+ */
+
+#include <dt-bindings/clock/renesas,r8a779h0-cpg-mssr.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/power/renesas,r8a779h0-sysc.h>
+
+/ {
+       compatible = "renesas,r8a779h0";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       cluster0_opp: opp-table-0 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-500000000 {
+                       opp-hz = /bits/ 64 <500000000>;
+                       opp-microvolt = <825000>;
+                       clock-latency-ns = <500000>;
+               };
+               opp-1000000000 {
+                       opp-hz = /bits/ 64 <1000000000>;
+                       opp-microvolt = <825000>;
+                       clock-latency-ns = <500000>;
+               };
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&a76_0>;
+                               };
+                               core1 {
+                                       cpu = <&a76_1>;
+                               };
+                               core2 {
+                                       cpu = <&a76_2>;
+                               };
+                               core3 {
+                                       cpu = <&a76_3>;
+                               };
+                       };
+               };
+
+               a76_0: cpu@0 {
+                       compatible = "arm,cortex-a76";
+                       reg = <0>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A779H0_PD_A1E0D0C0>;
+                       next-level-cache = <&L3_CA76>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A779H0_CLK_ZC0>;
+                       operating-points-v2 = <&cluster0_opp>;
+               };
+
+               a76_1: cpu@100 {
+                       compatible = "arm,cortex-a76";
+                       reg = <0x100>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A779H0_PD_A1E0D0C1>;
+                       next-level-cache = <&L3_CA76>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A779H0_CLK_ZC1>;
+                       operating-points-v2 = <&cluster0_opp>;
+               };
+
+               a76_2: cpu@200 {
+                       compatible = "arm,cortex-a76";
+                       reg = <0x200>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A779H0_PD_A1E0D0C2>;
+                       next-level-cache = <&L3_CA76>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A779H0_CLK_ZC2>;
+                       operating-points-v2 = <&cluster0_opp>;
+               };
+
+               a76_3: cpu@300 {
+                       compatible = "arm,cortex-a76";
+                       reg = <0x300>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A779H0_PD_A1E0D0C3>;
+                       next-level-cache = <&L3_CA76>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A779H0_CLK_ZC3>;
+                       operating-points-v2 = <&cluster0_opp>;
+               };
+
+               idle-states {
+                       entry-method = "psci";
+
+                       CPU_SLEEP_0: cpu-sleep-0 {
+                               compatible = "arm,idle-state";
+                               arm,psci-suspend-param = <0x0010000>;
+                               local-timer-stop;
+                               entry-latency-us = <400>;
+                               exit-latency-us = <500>;
+                               min-residency-us = <4000>;
+                       };
+               };
+
+               L3_CA76: cache-controller {
+                       compatible = "cache";
+                       power-domains = <&sysc R8A779H0_PD_A2E0D0>;
+                       cache-unified;
+                       cache-level = <3>;
+               };
+       };
+
+       extal_clk: extal-clk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               /* This value must be overridden by the board */
+               clock-frequency = <0>;
+       };
+
+       extalr_clk: extalr-clk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               /* This value must be overridden by the board */
+               clock-frequency = <0>;
+       };
+
+       pmu-a76 {
+               compatible = "arm,cortex-a76-pmu";
+               interrupts-extended = <&gic GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>;
+       };
+
+       psci {
+               compatible = "arm,psci-1.0", "arm,psci-0.2";
+               method = "smc";
+       };
+
+       /* External SCIF clock - to be overridden by boards that provide it */
+       scif_clk: scif-clk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <0>;
+       };
+
+       soc: soc {
+               compatible = "simple-bus";
+               interrupt-parent = <&gic>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               rwdt: watchdog@e6020000 {
+                       compatible = "renesas,r8a779h0-wdt",
+                                    "renesas,rcar-gen4-wdt";
+                       reg = <0 0xe6020000 0 0x0c>;
+                       interrupts = <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 907>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 907>;
+                       status = "disabled";
+               };
+
+               pfc: pinctrl@e6050000 {
+                       compatible = "renesas,pfc-r8a779h0";
+                       reg = <0 0xe6050000 0 0x16c>, <0 0xe6050800 0 0x16c>,
+                             <0 0xe6058000 0 0x16c>, <0 0xe6058800 0 0x16c>,
+                             <0 0xe6060000 0 0x16c>, <0 0xe6060800 0 0x16c>,
+                             <0 0xe6061000 0 0x16c>, <0 0xe6061800 0 0x16c>;
+               };
+
+               gpio0: gpio@e6050180 {
+                       compatible = "renesas,gpio-r8a779h0",
+                                    "renesas,rcar-gen4-gpio";
+                       reg = <0 0xe6050180 0 0x54>;
+                       interrupts = <GIC_SPI 619 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 0 19>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 915>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 915>;
+               };
+
+               gpio1: gpio@e6050980 {
+                       compatible = "renesas,gpio-r8a779h0",
+                                    "renesas,rcar-gen4-gpio";
+                       reg = <0 0xe6050980 0 0x54>;
+                       interrupts = <GIC_SPI 623 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 32 30>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 915>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 915>;
+               };
+
+               gpio2: gpio@e6058180 {
+                       compatible = "renesas,gpio-r8a779h0",
+                                    "renesas,rcar-gen4-gpio";
+                       reg = <0 0xe6058180 0 0x54>;
+                       interrupts = <GIC_SPI 627 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 64 20>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 916>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 916>;
+               };
+
+               gpio3: gpio@e6058980 {
+                       compatible = "renesas,gpio-r8a779h0",
+                                    "renesas,rcar-gen4-gpio";
+                       reg = <0 0xe6058980 0 0x54>;
+                       interrupts = <GIC_SPI 631 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 96 32>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 916>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 916>;
+               };
+
+               gpio4: gpio@e6060180 {
+                       compatible = "renesas,gpio-r8a779h0",
+                                    "renesas,rcar-gen4-gpio";
+                       reg = <0 0xe6060180 0 0x54>;
+                       interrupts = <GIC_SPI 635 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 128 25>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 917>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 917>;
+               };
+
+               gpio5: gpio@e6060980 {
+                       compatible = "renesas,gpio-r8a779h0",
+                                    "renesas,rcar-gen4-gpio";
+                       reg = <0 0xe6060980 0 0x54>;
+                       interrupts = <GIC_SPI 639 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 160 21>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 917>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 917>;
+               };
+
+               gpio6: gpio@e6061180 {
+                       compatible = "renesas,gpio-r8a779h0",
+                                    "renesas,rcar-gen4-gpio";
+                       reg = <0 0xe6061180 0 0x54>;
+                       interrupts = <GIC_SPI 643 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 192 21>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 917>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 917>;
+               };
+
+               gpio7: gpio@e6061980 {
+                       compatible = "renesas,gpio-r8a779h0",
+                                    "renesas,rcar-gen4-gpio";
+                       reg = <0 0xe6061980 0 0x54>;
+                       interrupts = <GIC_SPI 647 IRQ_TYPE_LEVEL_HIGH>;
+                       #gpio-cells = <2>;
+                       gpio-controller;
+                       gpio-ranges = <&pfc 0 224 21>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       clocks = <&cpg CPG_MOD 917>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 917>;
+               };
+
+               cpg: clock-controller@e6150000 {
+                       compatible = "renesas,r8a779h0-cpg-mssr";
+                       reg = <0 0xe6150000 0 0x4000>;
+                       clocks = <&extal_clk>, <&extalr_clk>;
+                       clock-names = "extal", "extalr";
+                       #clock-cells = <2>;
+                       #power-domain-cells = <0>;
+                       #reset-cells = <1>;
+               };
+
+               rst: reset-controller@e6160000 {
+                       compatible = "renesas,r8a779h0-rst";
+                       reg = <0 0xe6160000 0 0x4000>;
+               };
+
+               sysc: system-controller@e6180000 {
+                       compatible = "renesas,r8a779h0-sysc";
+                       reg = <0 0xe6180000 0 0x4000>;
+                       #power-domain-cells = <1>;
+               };
+
+               i2c0: i2c@e6500000 {
+                       compatible = "renesas,i2c-r8a779h0",
+                                    "renesas,rcar-gen4-i2c";
+                       reg = <0 0xe6500000 0 0x40>;
+                       interrupts = <GIC_SPI 610 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 518>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 518>;
+                       dmas = <&dmac1 0x91>, <&dmac1 0x90>,
+                              <&dmac2 0x91>, <&dmac2 0x90>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       i2c-scl-internal-delay-ns = <110>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               i2c1: i2c@e6508000 {
+                       compatible = "renesas,i2c-r8a779h0",
+                                    "renesas,rcar-gen4-i2c";
+                       reg = <0 0xe6508000 0 0x40>;
+                       interrupts = <GIC_SPI 611 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 519>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 519>;
+                       dmas = <&dmac1 0x93>, <&dmac1 0x92>,
+                              <&dmac2 0x93>, <&dmac2 0x92>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       i2c-scl-internal-delay-ns = <110>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               i2c2: i2c@e6510000 {
+                       compatible = "renesas,i2c-r8a779h0",
+                                    "renesas,rcar-gen4-i2c";
+                       reg = <0 0xe6510000 0 0x40>;
+                       interrupts = <GIC_SPI 612 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 520>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 520>;
+                       dmas = <&dmac1 0x95>, <&dmac1 0x94>,
+                              <&dmac2 0x95>, <&dmac2 0x94>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       i2c-scl-internal-delay-ns = <110>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               i2c3: i2c@e66d0000 {
+                       compatible = "renesas,i2c-r8a779h0",
+                                    "renesas,rcar-gen4-i2c";
+                       reg = <0 0xe66d0000 0 0x40>;
+                       interrupts = <GIC_SPI 613 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 521>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 521>;
+                       dmas = <&dmac1 0x97>, <&dmac1 0x96>,
+                              <&dmac2 0x97>, <&dmac2 0x96>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       i2c-scl-internal-delay-ns = <110>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               hscif0: serial@e6540000 {
+                       compatible = "renesas,hscif-r8a779h0",
+                                    "renesas,rcar-gen4-hscif", "renesas,hscif";
+                       reg = <0 0xe6540000 0 0x60>;
+                       interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 514>,
+                                <&cpg CPG_CORE R8A779H0_CLK_SASYNCPERD1>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 514>;
+                       dmas = <&dmac1 0x31>, <&dmac1 0x30>,
+                              <&dmac2 0x31>, <&dmac2 0x30>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       status = "disabled";
+               };
+
+               avb0: ethernet@e6800000 {
+                       compatible = "renesas,etheravb-r8a779h0",
+                                    "renesas,etheravb-rcar-gen4";
+                       reg = <0 0xe6800000 0 0x1000>;
+                       interrupts = <GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 348 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 349 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 350 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "ch0", "ch1", "ch2", "ch3",
+                                         "ch4", "ch5", "ch6", "ch7",
+                                         "ch8", "ch9", "ch10", "ch11",
+                                         "ch12", "ch13", "ch14", "ch15",
+                                         "ch16", "ch17", "ch18", "ch19",
+                                         "ch20", "ch21", "ch22", "ch23",
+                                         "ch24";
+                       clocks = <&cpg CPG_MOD 211>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A779H0_PD_C4>;
+                       resets = <&cpg 211>;
+                       phy-mode = "rgmii";
+                       rx-internal-delay-ps = <0>;
+                       tx-internal-delay-ps = <0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               avb1: ethernet@e6810000 {
+                       compatible = "renesas,etheravb-r8a779h0",
+                                    "renesas,etheravb-rcar-gen4";
+                       reg = <0 0xe6810000 0 0x1000>;
+                       interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 362 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 363 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 365 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 366 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 367 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 368 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 369 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 380 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 381 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 382 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 383 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 384 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "ch0", "ch1", "ch2", "ch3",
+                                         "ch4", "ch5", "ch6", "ch7",
+                                         "ch8", "ch9", "ch10", "ch11",
+                                         "ch12", "ch13", "ch14", "ch15",
+                                         "ch16", "ch17", "ch18", "ch19",
+                                         "ch20", "ch21", "ch22", "ch23",
+                                         "ch24";
+                       clocks = <&cpg CPG_MOD 212>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A779H0_PD_C4>;
+                       resets = <&cpg 212>;
+                       phy-mode = "rgmii";
+                       rx-internal-delay-ps = <0>;
+                       tx-internal-delay-ps = <0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               avb2: ethernet@e6820000 {
+                       compatible = "renesas,etheravb-r8a779h0",
+                                    "renesas,etheravb-rcar-gen4";
+                       reg = <0 0xe6820000 0 0x1000>;
+                       interrupts = <GIC_SPI 385 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 386 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 387 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 388 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 389 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 390 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 391 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 392 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 409 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "ch0", "ch1", "ch2", "ch3",
+                                         "ch4", "ch5", "ch6", "ch7",
+                                         "ch8", "ch9", "ch10", "ch11",
+                                         "ch12", "ch13", "ch14", "ch15",
+                                         "ch16", "ch17", "ch18", "ch19",
+                                         "ch20", "ch21", "ch22", "ch23",
+                                         "ch24";
+                       clocks = <&cpg CPG_MOD 213>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A779H0_PD_C4>;
+                       resets = <&cpg 213>;
+                       phy-mode = "rgmii";
+                       rx-internal-delay-ps = <0>;
+                       tx-internal-delay-ps = <0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               dmac1: dma-controller@e7350000 {
+                       compatible = "renesas,dmac-r8a779h0",
+                                    "renesas,rcar-gen4-dmac";
+                       reg = <0 0xe7350000 0 0x1000>,
+                             <0 0xe7300000 0 0x10000>;
+                       interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error",
+                                         "ch0", "ch1", "ch2", "ch3", "ch4",
+                                         "ch5", "ch6", "ch7", "ch8", "ch9",
+                                         "ch10", "ch11", "ch12", "ch13",
+                                         "ch14", "ch15";
+                       clocks = <&cpg CPG_MOD 709>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 709>;
+                       #dma-cells = <1>;
+                       dma-channels = <16>;
+               };
+
+               dmac2: dma-controller@e7351000 {
+                       compatible = "renesas,dmac-r8a779h0",
+                                    "renesas,rcar-gen4-dmac";
+                       reg = <0 0xe7351000 0 0x1000>,
+                             <0 0xe7310000 0 0x10000>;
+                       interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "error",
+                                         "ch0", "ch1", "ch2", "ch3", "ch4",
+                                         "ch5", "ch6", "ch7";
+                       clocks = <&cpg CPG_MOD 710>;
+                       clock-names = "fck";
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 710>;
+                       #dma-cells = <1>;
+                       dma-channels = <8>;
+               };
+
+               mmc0: mmc@ee140000 {
+                       compatible = "renesas,sdhi-r8a779h0",
+                                    "renesas,rcar-gen4-sdhi";
+                       reg = <0 0xee140000 0 0x2000>;
+                       interrupts = <GIC_SPI 440 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 706>,
+                                <&cpg CPG_CORE R8A779H0_CLK_SD0H>;
+                       clock-names = "core", "clkh";
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 706>;
+                       max-frequency = <200000000>;
+                       status = "disabled";
+               };
+
+               rpc: spi@ee200000 {
+                       compatible = "renesas,r8a779h0-rpc-if",
+                                    "renesas,rcar-gen4-rpc-if";
+                       reg = <0 0xee200000 0 0x200>,
+                             <0 0x08000000 0 0x04000000>,
+                             <0 0xee208000 0 0x100>;
+                       reg-names = "regs", "dirmap", "wbuf";
+                       interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 629>;
+                       power-domains = <&sysc R8A779H0_PD_ALWAYS_ON>;
+                       resets = <&cpg 629>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               gic: interrupt-controller@f1000000 {
+                       compatible = "arm,gic-v3";
+                       #interrupt-cells = <3>;
+                       #address-cells = <0>;
+                       interrupt-controller;
+                       reg = <0x0 0xf1000000 0 0x20000>,
+                             <0x0 0xf1060000 0 0x110000>;
+                       interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               prr: chipid@fff00044 {
+                       compatible = "renesas,prr";
+                       reg = <0 0xfff00044 0 4>;
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts-extended = <&gic GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+                                     <&gic GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+                                     <&gic GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+                                     <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>,
+                                     <&gic GIC_PPI 12 IRQ_TYPE_LEVEL_LOW>;
+       };
+};
index 2ab231572d95ff0558fade63abe9ab062c40ddad..964b0a475eeeb6080f385750f795117db4fa31e3 100644 (file)
 &soc {
        interrupt-parent = <&gic>;
 
+       cru: video@10830000 {
+               compatible = "renesas,r9a07g043-cru", "renesas,rzg2l-cru";
+               reg = <0 0x10830000 0 0x400>;
+               clocks = <&cpg CPG_MOD R9A07G043_CRU_VCLK>,
+                        <&cpg CPG_MOD R9A07G043_CRU_PCLK>,
+                        <&cpg CPG_MOD R9A07G043_CRU_ACLK>;
+               clock-names = "video", "apb", "axi";
+               interrupts = <SOC_PERIPHERAL_IRQ(167) IRQ_TYPE_LEVEL_HIGH>,
+                            <SOC_PERIPHERAL_IRQ(168) IRQ_TYPE_LEVEL_HIGH>,
+                            <SOC_PERIPHERAL_IRQ(169) IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "image_conv", "image_conv_err", "axi_mst_err";
+               resets = <&cpg R9A07G043_CRU_PRESETN>,
+                        <&cpg R9A07G043_CRU_ARESETN>;
+               reset-names = "presetn", "aresetn";
+               power-domains = <&cpg>;
+               status = "disabled";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@1 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               reg = <1>;
+                               crucsi2: endpoint@0 {
+                                       reg = <0>;
+                                       remote-endpoint = <&csi2cru>;
+                               };
+                       };
+               };
+       };
+
+       csi2: csi2@10830400 {
+               compatible = "renesas,r9a07g043-csi2", "renesas,rzg2l-csi2";
+               reg = <0 0x10830400 0 0xfc00>;
+               interrupts = <SOC_PERIPHERAL_IRQ(166) IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cpg CPG_MOD R9A07G043_CRU_SYSCLK>,
+                        <&cpg CPG_MOD R9A07G043_CRU_VCLK>,
+                        <&cpg CPG_MOD R9A07G043_CRU_PCLK>;
+               clock-names = "system", "video", "apb";
+               resets = <&cpg R9A07G043_CRU_PRESETN>,
+                        <&cpg R9A07G043_CRU_CMN_RSTB>;
+               reset-names = "presetn", "cmn-rstb";
+               power-domains = <&cpg>;
+               status = "disabled";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                       };
+
+                       port@1 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <1>;
+
+                               csi2cru: endpoint@0 {
+                                       reg = <0>;
+                                       remote-endpoint = <&crucsi2>;
+                               };
+                       };
+               };
+       };
+
        irqc: interrupt-controller@110a0000 {
                compatible = "renesas,r9a07g043u-irqc",
                             "renesas,rzg2l-irqc";
                             <SOC_PERIPHERAL_IRQ(473) IRQ_TYPE_LEVEL_HIGH>,
                             <SOC_PERIPHERAL_IRQ(474) IRQ_TYPE_LEVEL_HIGH>,
                             <SOC_PERIPHERAL_IRQ(475) IRQ_TYPE_LEVEL_HIGH>,
-                            <SOC_PERIPHERAL_IRQ(25) IRQ_TYPE_EDGE_RISING>;
+                            <SOC_PERIPHERAL_IRQ(25) IRQ_TYPE_EDGE_RISING>,
+                            <SOC_PERIPHERAL_IRQ(34) IRQ_TYPE_EDGE_RISING>,
+                            <SOC_PERIPHERAL_IRQ(35) IRQ_TYPE_EDGE_RISING>,
+                            <SOC_PERIPHERAL_IRQ(36) IRQ_TYPE_EDGE_RISING>,
+                            <SOC_PERIPHERAL_IRQ(37) IRQ_TYPE_EDGE_RISING>,
+                            <SOC_PERIPHERAL_IRQ(38) IRQ_TYPE_EDGE_RISING>,
+                            <SOC_PERIPHERAL_IRQ(39) IRQ_TYPE_EDGE_RISING>;
                interrupt-names = "nmi",
                                  "irq0", "irq1", "irq2", "irq3",
                                  "irq4", "irq5", "irq6", "irq7",
                                  "tint20", "tint21", "tint22", "tint23",
                                  "tint24", "tint25", "tint26", "tint27",
                                  "tint28", "tint29", "tint30", "tint31",
-                                 "bus-err";
+                                 "bus-err", "ec7tie1-0", "ec7tie2-0",
+                                 "ec7tiovf-0", "ec7tie1-1", "ec7tie2-1",
+                                 "ec7tiovf-1";
                clocks = <&cpg CPG_MOD R9A07G043_IA55_CLK>,
                        <&cpg CPG_MOD R9A07G043_IA55_PCLK>;
                clock-names = "clk", "pclk";
diff --git a/arch/arm64/boot/dts/renesas/r9a07g043u11-smarc-cru-csi-ov5645.dtso b/arch/arm64/boot/dts/renesas/r9a07g043u11-smarc-cru-csi-ov5645.dtso
new file mode 100644 (file)
index 0000000..b41bb4b
--- /dev/null
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree overlay for the RZ/G2UL SMARC EVK with OV5645 camera
+ * connected to CSI and CRU enabled.
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/rzg2l-pinctrl.h>
+
+#define OV5645_PARENT_I2C i2c0
+#include "rz-smarc-cru-csi-ov5645.dtsi"
+
+&ov5645 {
+       enable-gpios = <&pinctrl RZG2L_GPIO(4, 4) GPIO_ACTIVE_HIGH>;
+       reset-gpios = <&pinctrl RZG2L_GPIO(0, 1) GPIO_ACTIVE_LOW>;
+};
index 66f68fc2b24118af11b2b1e5b73eab13652d3cc9..9f00b75d2bd0a984f0fa37c5c5c9ce1428313a40 100644 (file)
                        reset-names = "rst", "arst", "prst";
                        power-domains = <&cpg>;
                        status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       dsi0_in: endpoint {
+                                               remote-endpoint = <&du_out_dsi>;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                               };
+                       };
                };
 
                vspd: vsp@10870000 {
                        resets = <&cpg R9A07G044_LCDC_RESET_N>;
                };
 
+               du: display@10890000 {
+                       compatible = "renesas,r9a07g044-du";
+                       reg = <0 0x10890000 0 0x10000>;
+                       interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD R9A07G044_LCDC_CLK_A>,
+                                <&cpg CPG_MOD R9A07G044_LCDC_CLK_P>,
+                                <&cpg CPG_MOD R9A07G044_LCDC_CLK_D>;
+                       clock-names = "aclk", "pclk", "vclk";
+                       power-domains = <&cpg>;
+                       resets = <&cpg R9A07G044_LCDC_RESET_N>;
+                       renesas,vsps = <&vspd 0>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       du_out_dsi: endpoint {
+                                               remote-endpoint = <&dsi0_in>;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                               };
+                       };
+               };
+
                cpg: clock-controller@11010000 {
                        compatible = "renesas,r9a07g044-cpg";
                        reg = <0 0x11010000 0 0x10000>;
                                     <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 475 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 475 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 25 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 39 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "nmi", "irq0", "irq1", "irq2", "irq3",
+                                         "irq4", "irq5", "irq6", "irq7",
+                                         "tint0", "tint1", "tint2", "tint3",
+                                         "tint4", "tint5", "tint6", "tint7",
+                                         "tint8", "tint9", "tint10", "tint11",
+                                         "tint12", "tint13", "tint14", "tint15",
+                                         "tint16", "tint17", "tint18", "tint19",
+                                         "tint20", "tint21", "tint22", "tint23",
+                                         "tint24", "tint25", "tint26", "tint27",
+                                         "tint28", "tint29", "tint30", "tint31",
+                                         "bus-err", "ec7tie1-0", "ec7tie2-0",
+                                         "ec7tiovf-0", "ec7tie1-1", "ec7tie2-1",
+                                         "ec7tiovf-1";
                        clocks = <&cpg CPG_MOD R9A07G044_IA55_CLK>,
                                 <&cpg CPG_MOD R9A07G044_IA55_PCLK>;
                        clock-names = "clk", "pclk";
index 1f1d481dc7830de9dcdbad91a0cc48534dcd1708..53d8905f367afd5b8ef95bd08da6122cef240317 100644 (file)
                        reset-names = "rst", "arst", "prst";
                        power-domains = <&cpg>;
                        status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       dsi0_in: endpoint {
+                                               remote-endpoint = <&du_out_dsi>;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                               };
+                       };
                };
 
                vspd: vsp@10870000 {
                        resets = <&cpg R9A07G054_LCDC_RESET_N>;
                };
 
+               du: display@10890000 {
+                       compatible = "renesas,r9a07g054-du",
+                                    "renesas,r9a07g044-du";
+                       reg = <0 0x10890000 0 0x10000>;
+                       interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD R9A07G054_LCDC_CLK_A>,
+                                <&cpg CPG_MOD R9A07G054_LCDC_CLK_P>,
+                                <&cpg CPG_MOD R9A07G054_LCDC_CLK_D>;
+                       clock-names = "aclk", "pclk", "vclk";
+                       power-domains = <&cpg>;
+                       resets = <&cpg R9A07G054_LCDC_RESET_N>;
+                       renesas,vsps = <&vspd 0>;
+                       status = "disabled";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               port@0 {
+                                       reg = <0>;
+                                       du_out_dsi: endpoint {
+                                               remote-endpoint = <&dsi0_in>;
+                                       };
+                               };
+
+                               port@1 {
+                                       reg = <1>;
+                               };
+                       };
+               };
+
                cpg: clock-controller@11010000 {
                        compatible = "renesas,r9a07g054-cpg";
                        reg = <0 0x11010000 0 0x10000>;
                                     <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 475 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 475 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 25 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 39 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "nmi", "irq0", "irq1", "irq2", "irq3",
+                                         "irq4", "irq5", "irq6", "irq7",
+                                         "tint0", "tint1", "tint2", "tint3",
+                                         "tint4", "tint5", "tint6", "tint7",
+                                         "tint8", "tint9", "tint10", "tint11",
+                                         "tint12", "tint13", "tint14", "tint15",
+                                         "tint16", "tint17", "tint18", "tint19",
+                                         "tint20", "tint21", "tint22", "tint23",
+                                         "tint24", "tint25", "tint26", "tint27",
+                                         "tint28", "tint29", "tint30", "tint31",
+                                         "bus-err", "ec7tie1-0", "ec7tie2-0",
+                                         "ec7tiovf-0", "ec7tie1-1", "ec7tie2-1",
+                                         "ec7tiovf-1";
                        clocks = <&cpg CPG_MOD R9A07G054_IA55_CLK>,
                                 <&cpg CPG_MOD R9A07G054_IA55_PCLK>;
                        clock-names = "clk", "pclk";
index 5facfad9615838ecf422adc71905b40d033e08b1..f5f3f4f4c8d671f2b6f550ad07df17bc6532547e 100644 (file)
                clock-frequency = <0>;
        };
 
+       psci {
+               compatible = "arm,psci-1.0", "arm,psci-0.2";
+               method = "smc";
+       };
+
        soc: soc {
                compatible = "simple-bus";
                interrupt-parent = <&gic>;
                                     <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 459 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 460 IRQ_TYPE_LEVEL_HIGH>,
-                                    <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+                                    <GIC_SPI 29 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>;
                        interrupt-names = "nmi",
                                          "irq0", "irq1", "irq2", "irq3",
                                          "irq4", "irq5", "irq6", "irq7",
                                          "tint20", "tint21", "tint22", "tint23",
                                          "tint24", "tint25", "tint26", "tint27",
                                          "tint28", "tint29", "tint30", "tint31",
-                                         "bus-err";
+                                         "bus-err", "ec7tie1-0", "ec7tie2-0",
+                                         "ec7tiovf-0";
                        clocks = <&cpg CPG_MOD R9A08G045_IA55_CLK>,
                                 <&cpg CPG_MOD R9A08G045_IA55_PCLK>;
                        clock-names = "clk", "pclk";
                              <0x0 0x12440000 0 0x60000>;
                        interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_LOW>;
                };
+
+               wdt0: watchdog@12800800 {
+                       compatible = "renesas,r9a08g045-wdt", "renesas,rzg2l-wdt";
+                       reg = <0 0x12800800 0 0x400>;
+                       clocks = <&cpg CPG_MOD R9A08G045_WDT0_PCLK>,
+                                <&cpg CPG_MOD R9A08G045_WDT0_CLK>;
+                       clock-names = "pclk", "oscclk";
+                       interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "wdt", "perrout";
+                       resets = <&cpg R9A08G045_WDT0_PRESETN>;
+                       power-domains = <&cpg>;
+                       status = "disabled";
+               };
        };
 
        timer {
index 37807f1bda4d37a52886af0c8dd023d74e2d8f44..887dffe1491087a8dfd2eb0e981928506db2af9a 100644 (file)
        status = "okay";
 
        ports {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               port@0 {
-                       reg = <0>;
-                       dsi0_in: endpoint {
-                       };
-               };
-
                port@1 {
-                       reg = <1>;
                        dsi0_out: endpoint {
                                data-lanes = <1 2 3 4>;
                                remote-endpoint = <&adv7535_in>;
        };
 };
 
+&du {
+       status = "okay";
+};
+
 &i2c1 {
        adv7535: hdmi@3d {
                compatible = "adi,adv7535";
index 859bc8745e66a96441e3ce5e91ab6150e12edc92..f21508640b6eaaaf518f8302ffc009aa09d512b8 100644 (file)
        status = "okay";
 
        ports {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               port@0 {
-                       reg = <0>;
-                       dsi0_in: endpoint {
-                       };
-               };
-
                port@1 {
-                       reg = <1>;
                        dsi0_out: endpoint {
                                data-lanes = <1 2 3 4>;
                                remote-endpoint = <&adv7535_in>;
        };
 };
 
+&du {
+       status = "okay";
+};
+
 &i2c1 {
        adv7535: hdmi@3d {
                compatible = "adi,adv7535";
index f062d4ad78b79d9a2c511b31bd2159e9c89d6e87..acac4666ae59e38c1303806a9d188fb9dcd9b9a9 100644 (file)
 #endif
 
 &pinctrl {
+#if SW_CONFIG3 == SW_ON
        eth0-phy-irq-hog {
                gpio-hog;
                gpios = <RZG2L_GPIO(12, 0) GPIO_ACTIVE_LOW>;
                input;
                line-name = "eth0-phy-irq";
        };
+#endif
 
        eth0_pins: eth0 {
                txc {
                };
        };
 
+#if SW_CONFIG3 == SW_ON
        eth1-phy-irq-hog {
                gpio-hog;
                gpios = <RZG2L_GPIO(12, 1) GPIO_ACTIVE_LOW>;
                input;
                line-name = "eth1-phy-irq";
        };
+#endif
 
        eth1_pins: eth1 {
                txc {
                };
        };
 };
+
+&wdt0 {
+       timeout-sec = <60>;
+       status = "okay";
+};
index 21452013723084991f23dcf07c0a823f41633092..deb2ad37bb2e5d198efbf6c7fe8b94a52bf35685 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 #include <dt-bindings/pinctrl/rzg2l-pinctrl.h>
 
 / {
                mmc1 = &sdhi1;
        };
 
+       keys {
+               compatible = "gpio-keys";
+
+               key-1 {
+                       interrupts = <RZG2L_GPIO(18, 0) IRQ_TYPE_EDGE_FALLING>;
+                       interrupt-parent = <&pinctrl>;
+                       linux,code = <KEY_1>;
+                       label = "USER_SW1";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+
+               key-2 {
+                       interrupts = <RZG2L_GPIO(0, 1) IRQ_TYPE_EDGE_FALLING>;
+                       interrupt-parent = <&pinctrl>;
+                       linux,code = <KEY_2>;
+                       label = "USER_SW2";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+
+               key-3 {
+                       interrupts = <RZG2L_GPIO(0, 3) IRQ_TYPE_EDGE_FALLING>;
+                       interrupt-parent = <&pinctrl>;
+                       linux,code = <KEY_3>;
+                       label = "USER_SW3";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+       };
+
        vcc_sdhi1: regulator-vcc-sdhi1 {
                compatible = "regulator-fixed";
                regulator-name = "SDHI1 Vcc";
 };
 
 &pinctrl {
+       key-1-gpio-hog {
+               gpio-hog;
+               gpios = <RZG2L_GPIO(18, 0) GPIO_ACTIVE_LOW>;
+               input;
+               line-name = "key-1-gpio-irq";
+       };
+
+       key-2-gpio-hog {
+               gpio-hog;
+               gpios = <RZG2L_GPIO(0, 1) GPIO_ACTIVE_LOW>;
+               input;
+               line-name = "key-2-gpio-irq";
+       };
+
+       key-3-gpio-hog {
+               gpio-hog;
+               gpios = <RZG2L_GPIO(0, 3) GPIO_ACTIVE_LOW>;
+               input;
+               line-name = "key-3-gpio-irq";
+       };
+
        scif0_pins: scif0 {
                pinmux = <RZG2L_PORT_PINMUX(6, 3, 1)>, /* RXD */
                         <RZG2L_PORT_PINMUX(6, 4, 1)>; /* TXD */
index 3885ef3454ff6e92d8f0d00509d0f935e7e40fa6..431b37bf566192d22843769160a612961652d86e 100644 (file)
                };
        };
 
-       accel_3v3: regulator-acc-3v3 {
+       reg_t1p8v: regulator-t1p8v {
                compatible = "regulator-fixed";
-               regulator-name = "accel-3v3";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
-       };
-
-       hdmi_1v8: regulator-hdmi-1v8 {
-               compatible = "regulator-fixed";
-               regulator-name = "hdmi-1v8";
+               regulator-name = "T1.8V";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               regulator-always-on;
        };
 
-       hdmi_3v3: regulator-hdmi-3v3 {
+       pcie_1v5: regulator-pcie-1v5 {
                compatible = "regulator-fixed";
-               regulator-name = "hdmi-3v3";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
+               regulator-name = "pcie-1v5";
+               regulator-min-microvolt = <1500000>;
+               regulator-max-microvolt = <1500000>;
+               gpio = <&gpio_exp_77 15 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
        };
 
-       snd_3p3v: regulator-snd_3p3v {
+       pcie_3v3: regulator-pcie-3v3 {
                compatible = "regulator-fixed";
-               regulator-name = "snd-3.3v";
+               regulator-name = "pcie-3v3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
+               gpio = <&gpio_exp_77 14 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
        };
 
-       snd_vcc5v: regulator-snd_vcc5v {
+       reg_5v: regulator-5v {
                compatible = "regulator-fixed";
-               regulator-name = "snd-vcc5v";
+               regulator-name = "fixed-5V";
                regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
+               regulator-boot-on;
+               regulator-always-on;
        };
 
        wlan_en: regulator-wlan_en {
 
                                pd-gpios = <&gpio_exp_75 5 GPIO_ACTIVE_LOW>;
 
-                               avdd-supply = <&hdmi_1v8>;
-                               dvdd-supply = <&hdmi_1v8>;
-                               pvdd-supply = <&hdmi_1v8>;
-                               dvdd-3v-supply = <&hdmi_3v3>;
-                               bgvdd-supply = <&hdmi_1v8>;
+                               avdd-supply = <&reg_t1p8v>;
+                               dvdd-supply = <&reg_t1p8v>;
+                               pvdd-supply = <&reg_t1p8v>;
+                               dvdd-3v-supply = <&reg_3p3v>;
+                               bgvdd-supply = <&reg_t1p8v>;
 
                                adi,input-depth = <8>;
                                adi,input-colorspace = "rgb";
                                compatible = "st,lsm9ds0-imu";
                                reg = <0x1d>;
 
-                               vdd-supply = <&accel_3v3>;
-                               vddio-supply = <&accel_3v3>;
+                               vdd-supply = <&reg_3p3v>;
+                               vddio-supply = <&reg_3p3v>;
                        };
 
                        pcm3168a: audio-codec@44 {
                                clocks = <&clksndsel>;
                                clock-names = "scki";
 
-                               VDD1-supply = <&snd_3p3v>;
-                               VDD2-supply = <&snd_3p3v>;
-                               VCCAD1-supply = <&snd_vcc5v>;
-                               VCCAD2-supply = <&snd_vcc5v>;
-                               VCCDA1-supply = <&snd_vcc5v>;
-                               VCCDA2-supply = <&snd_vcc5v>;
+                               VDD1-supply = <&reg_3p3v>;
+                               VDD2-supply = <&reg_3p3v>;
+                               VCCAD1-supply = <&reg_5v>;
+                               VCCAD2-supply = <&reg_5v>;
+                               VCCDA1-supply = <&reg_5v>;
+                               VCCDA2-supply = <&reg_5v>;
                        };
 
                        gyroscope@6b {
                                compatible = "st,lsm9ds0-gyro";
                                reg = <0x6b>;
 
-                               vdd-supply = <&accel_3v3>;
-                               vddio-supply = <&accel_3v3>;
+                               vdd-supply = <&reg_3p3v>;
+                               vddio-supply = <&reg_3p3v>;
                        };
                };
        };
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-controller;
+               #interrupt-cells = <2>;
                interrupt-parent = <&gpio6>;
                interrupts = <8 IRQ_TYPE_EDGE_FALLING>;
 
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-controller;
+               #interrupt-cells = <2>;
                interrupt-parent = <&gpio6>;
                interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
        };
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-controller;
+               #interrupt-cells = <2>;
                interrupt-parent = <&gpio7>;
                interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
        };
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-controller;
+               #interrupt-cells = <2>;
                interrupt-parent = <&gpio5>;
                interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
        };
 
 &pciec1 {
        status = "okay";
+
+       vpcie1v5-supply = <&pcie_1v5>;
+       vpcie3v3-supply = <&pcie_3v3>;
 };
 
 &pfc {
        pinctrl-names = "default";
 
        status = "okay";
+
+       gnss {
+               compatible = "u-blox,neo-m8";
+               reset-gpios = <&gpio_exp_75 6 GPIO_ACTIVE_LOW>;
+               vcc-supply = <&reg_3p3v>;
+               current-speed = <9600>;
+       };
 };
 
 &sdhi3 {
diff --git a/arch/arm64/boot/dts/renesas/white-hawk-common.dtsi b/arch/arm64/boot/dts/renesas/white-hawk-common.dtsi
new file mode 100644 (file)
index 0000000..c99086e
--- /dev/null
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the common parts shared by the White Hawk BreakOut
+ * and White Hawk Single boards
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ */
+
+#include "white-hawk-csi-dsi.dtsi"
+#include "white-hawk-ethernet.dtsi"
+
+/ {
+       can_transceiver0: can-phy0 {
+               compatible = "nxp,tjr1443";
+               #phy-cells = <0>;
+               enable-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
+               max-bitrate = <5000000>;
+       };
+};
+
+&can_clk {
+       clock-frequency = <40000000>;
+};
+
+&canfd {
+       pinctrl-0 = <&canfd0_pins>, <&canfd1_pins>, <&can_clk_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+
+       channel0 {
+               status = "okay";
+               phys = <&can_transceiver0>;
+       };
+
+       channel1 {
+               status = "okay";
+       };
+};
+
+&i2c0 {
+       eeprom@51 {
+               compatible = "rohm,br24g01", "atmel,24c01";
+               label = "breakout-board";
+               reg = <0x51>;
+               pagesize = <8>;
+       };
+};
+
+&pfc {
+       can_clk_pins: can-clk {
+               groups = "can_clk";
+               function = "can_clk";
+       };
+
+       canfd0_pins: canfd0 {
+               groups = "canfd0_data";
+               function = "canfd0";
+       };
+
+       canfd1_pins: canfd1 {
+               groups = "canfd1_data";
+               function = "canfd1";
+       };
+};
diff --git a/arch/arm64/boot/dts/renesas/white-hawk-cpu-common.dtsi b/arch/arm64/boot/dts/renesas/white-hawk-cpu-common.dtsi
new file mode 100644 (file)
index 0000000..8ac1737
--- /dev/null
@@ -0,0 +1,375 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the common parts shared by the White Hawk CPU and
+ * White Hawk Single boards
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+       aliases {
+               ethernet0 = &avb0;
+               serial0 = &hscif0;
+       };
+
+       chosen {
+               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
+               stdout-path = "serial0:921600n8";
+       };
+
+       sn65dsi86_refclk: clk-x6 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <38400000>;
+       };
+
+       keys {
+               compatible = "gpio-keys";
+
+               pinctrl-0 = <&keys_pins>;
+               pinctrl-names = "default";
+
+               key-1 {
+                       gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_1>;
+                       label = "SW47";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+
+               key-2 {
+                       gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_2>;
+                       label = "SW48";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+
+               key-3 {
+                       gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_3>;
+                       label = "SW49";
+                       wakeup-source;
+                       debounce-interval = <20>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led-1 {
+                       gpios = <&gpio7 0 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_INDICATOR;
+                       function-enumerator = <1>;
+               };
+
+               led-2 {
+                       gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_INDICATOR;
+                       function-enumerator = <2>;
+               };
+
+               led-3 {
+                       gpios = <&gpio7 2 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_INDICATOR;
+                       function-enumerator = <3>;
+               };
+       };
+
+       memory@48000000 {
+               device_type = "memory";
+               /* first 128MB is reserved for secure area. */
+               reg = <0x0 0x48000000 0x0 0x78000000>;
+       };
+
+       memory@480000000 {
+               device_type = "memory";
+               reg = <0x4 0x80000000 0x0 0x80000000>;
+       };
+
+       memory@600000000 {
+               device_type = "memory";
+               reg = <0x6 0x00000000 0x1 0x00000000>;
+       };
+
+       mini-dp-con {
+               compatible = "dp-connector";
+               label = "CN5";
+               type = "mini";
+
+               port {
+                       mini_dp_con_in: endpoint {
+                               remote-endpoint = <&sn65dsi86_out>;
+                       };
+               };
+       };
+
+       reg_1p2v: regulator-1p2v {
+               compatible = "regulator-fixed";
+               regulator-name = "fixed-1.2V";
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <1200000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       reg_1p8v: regulator-1p8v {
+               compatible = "regulator-fixed";
+               regulator-name = "fixed-1.8V";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       reg_3p3v: regulator-3p3v {
+               compatible = "regulator-fixed";
+               regulator-name = "fixed-3.3V";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+};
+
+&avb0 {
+       pinctrl-0 = <&avb0_pins>;
+       pinctrl-names = "default";
+       phy-handle = <&phy0>;
+       tx-internal-delay-ps = <2000>;
+       status = "okay";
+
+       phy0: ethernet-phy@0 {
+               compatible = "ethernet-phy-id0022.1622",
+                            "ethernet-phy-ieee802.3-c22";
+               rxc-skew-ps = <1500>;
+               reg = <0>;
+               interrupt-parent = <&gpio7>;
+               interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
+               reset-gpios = <&gpio7 10 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&dsi0 {
+       status = "okay";
+
+       ports {
+               port@1 {
+                       dsi0_out: endpoint {
+                               remote-endpoint = <&sn65dsi86_in>;
+                               data-lanes = <1 2 3 4>;
+                       };
+               };
+       };
+};
+
+&du {
+       status = "okay";
+};
+
+&extal_clk {
+       clock-frequency = <16666666>;
+};
+
+&extalr_clk {
+       clock-frequency = <32768>;
+};
+
+&hscif0 {
+       pinctrl-0 = <&hscif0_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+};
+
+&i2c0 {
+       pinctrl-0 = <&i2c0_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+       clock-frequency = <400000>;
+
+       io_expander_a: gpio@20 {
+               compatible = "onnn,pca9654";
+               reg = <0x20>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+       };
+
+       eeprom@50 {
+               compatible = "rohm,br24g01", "atmel,24c01";
+               label = "cpu-board";
+               reg = <0x50>;
+               pagesize = <8>;
+       };
+};
+
+&i2c1 {
+       pinctrl-0 = <&i2c1_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+       clock-frequency = <400000>;
+
+       bridge@2c {
+               compatible = "ti,sn65dsi86";
+               reg = <0x2c>;
+
+               clocks = <&sn65dsi86_refclk>;
+               clock-names = "refclk";
+
+               interrupt-parent = <&intc_ex>;
+               interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+
+               enable-gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>;
+
+               vccio-supply = <&reg_1p8v>;
+               vpll-supply = <&reg_1p8v>;
+               vcca-supply = <&reg_1p2v>;
+               vcc-supply = <&reg_1p2v>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               sn65dsi86_in: endpoint {
+                                       remote-endpoint = <&dsi0_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+                               sn65dsi86_out: endpoint {
+                                       remote-endpoint = <&mini_dp_con_in>;
+                               };
+                       };
+               };
+       };
+};
+
+&mmc0 {
+       pinctrl-0 = <&mmc_pins>;
+       pinctrl-1 = <&mmc_pins>;
+       pinctrl-names = "default", "state_uhs";
+
+       vmmc-supply = <&reg_3p3v>;
+       vqmmc-supply = <&reg_1p8v>;
+       mmc-hs200-1_8v;
+       mmc-hs400-1_8v;
+       bus-width = <8>;
+       no-sd;
+       no-sdio;
+       non-removable;
+       full-pwr-cycle-in-suspend;
+       status = "okay";
+};
+
+&pfc {
+       pinctrl-0 = <&scif_clk_pins>;
+       pinctrl-names = "default";
+
+       avb0_pins: avb0 {
+               mux {
+                       groups = "avb0_link", "avb0_mdio", "avb0_rgmii",
+                                "avb0_txcrefclk";
+                       function = "avb0";
+               };
+
+               pins_mdio {
+                       groups = "avb0_mdio";
+                       drive-strength = <21>;
+               };
+
+               pins_mii {
+                       groups = "avb0_rgmii";
+                       drive-strength = <21>;
+               };
+
+       };
+
+       hscif0_pins: hscif0 {
+               groups = "hscif0_data";
+               function = "hscif0";
+       };
+
+       i2c0_pins: i2c0 {
+               groups = "i2c0";
+               function = "i2c0";
+       };
+
+       i2c1_pins: i2c1 {
+               groups = "i2c1";
+               function = "i2c1";
+       };
+
+       keys_pins: keys {
+               pins = "GP_5_0", "GP_5_1", "GP_5_2";
+               bias-pull-up;
+       };
+
+       mmc_pins: mmc {
+               groups = "mmc_data8", "mmc_ctrl", "mmc_ds";
+               function = "mmc";
+               power-source = <1800>;
+       };
+
+       qspi0_pins: qspi0 {
+               groups = "qspi0_ctrl", "qspi0_data4";
+               function = "qspi0";
+       };
+
+       scif_clk_pins: scif_clk {
+               groups = "scif_clk";
+               function = "scif_clk";
+       };
+};
+
+&rpc {
+       pinctrl-0 = <&qspi0_pins>;
+       pinctrl-names = "default";
+
+       status = "okay";
+
+       flash@0 {
+               compatible = "spansion,s25fs512s", "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <40000000>;
+               spi-rx-bus-width = <4>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       boot@0 {
+                               reg = <0x0 0x1200000>;
+                               read-only;
+                       };
+                       user@1200000 {
+                               reg = <0x1200000 0x2e00000>;
+                       };
+               };
+       };
+};
+
+&rwdt {
+       timeout-sec = <60>;
+       status = "okay";
+};
+
+&scif_clk {
+       clock-frequency = <24000000>;
+};
similarity index 97%
rename from arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-csi-dsi.dtsi
rename to arch/arm64/boot/dts/renesas/white-hawk-csi-dsi.dtsi
index f8537f7ea4defabad1c5327948a6749a694d427b..3006b0a64f41e625dd2467808526b18c4ab5cb96 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 /*
- * Device Tree Source for the R-Car V4H White Hawk CSI/DSI sub-board
+ * Device Tree Source for the White Hawk CSI/DSI sub-board
  *
  * Copyright (C) 2022 Glider bv
  */
similarity index 76%
rename from arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-ethernet.dtsi
rename to arch/arm64/boot/dts/renesas/white-hawk-ethernet.dtsi
index 4f411f95c674bd51507ac7f6fe9ff0282850390a..a218fda337cf4308f8ec90b0ed14c2a064facd10 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 /*
- * Device Tree Source for the R-Car V4H White Hawk RAVB/Ethernet(1000Base-T1)
+ * Device Tree Source for the White Hawk RAVB/Ethernet(1000Base-T1)
  * sub-board
  *
  * Copyright (C) 2022 Glider bv
index a7b30e11beaf41e994d467e084a6a680774eab7d..f906a868b71acad873485bcafe25ccf3649f5798 100644 (file)
@@ -71,6 +71,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-rockpro64.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire-excavator.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399pro-rock-pi-n10.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg-arc-d.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg-arc-s.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg353p.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg353ps.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg353v.dtb
@@ -78,6 +80,9 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg353vs.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg503.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinenote-v1.1.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinenote-v1.2.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinetab2-v0.1.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinetab2-v2.0.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-rgb10max3.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-rgb30.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-rk2023.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-x55.dtb
@@ -98,11 +103,13 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-lubancat-2.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-nanopi-r5c.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-nanopi-r5s.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-odroid-m1.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-qnap-ts433.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-radxa-e25.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-roc-pc.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-rock-3a.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-evb.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6a-io.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6a-wifi.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6b-io.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-v10.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-jaguar.dtb
@@ -110,9 +117,13 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-nanopc-t6.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-orangepi-5-plus.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-quartzpro64.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-rock-5b.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-tiger-haikou.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-toybrick-x0.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-turing-rk1.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-coolpi-4b.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-indiedroid-nova.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-khadas-edge2.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-nanopi-r6s.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-nanopi-r6c.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-rock-5a.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-orangepi-5.dtb
index 16798eb770770447f5d4a772127b41fedee37224..ae398acdcf45e6239257c8519528ce22035052a4 100644 (file)
 
 &uart5 {
        pinctrl-0 = <&uart5_xfer>;
+       rts-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index 12397755830bd57122a0a4bf44f0167d1a67d5f0..bb1aea82e666ed45f738aefccff8d31a1d331cc8 100644 (file)
        };
 };
 
+&pmu_io_domains {
+       pmuio1-supply = <&vcc_3v3>;
+       pmuio2-supply = <&vcc_3v3>;
+       status = "okay";
+};
+
 &saradc {
        vref-supply = <&vcc_1v8>;
        status = "okay";
index d0905515399bb00b8562305b7fa5cf8a0eee65b2..9137dd76e72cedb0cfbf1995032e5852cab80f96 100644 (file)
                clock-names = "spiclk", "apb_pclk";
                dmas = <&dmac 12>, <&dmac 13>;
                dma-names = "tx", "rx";
+               num-cs = <2>;
                pinctrl-names = "default";
                pinctrl-0 = <&spi0_clk &spi0_csn &spi0_miso &spi0_mosi>;
                #address-cells = <1>;
                clock-names = "spiclk", "apb_pclk";
                dmas = <&dmac 14>, <&dmac 15>;
                dma-names = "tx", "rx";
+               num-cs = <2>;
                pinctrl-names = "default";
                pinctrl-0 = <&spi1_clk &spi1_csn0 &spi1_csn1 &spi1_miso &spi1_mosi>;
                #address-cells = <1>;
index 3cda6c627b681e7b470643372148651878e38165..f09d60bbe6c4f331ef0d79c9127371537f07050a 100644 (file)
        assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>;
        assigned-clock-parents = <&gmac_clkin>, <&gmac_clkin>;
        clock_in_out = "input";
-       phy-handle = <&rtl8211e>;
+       phy-handle = <&rtl8211>;
        phy-mode = "rgmii";
        phy-supply = <&vcc_io>;
        pinctrl-names = "default";
                #address-cells = <1>;
                #size-cells = <0>;
 
-               rtl8211e: ethernet-phy@1 {
+               rtl8211: ethernet-phy@1 {
                        reg = <1>;
                        pinctrl-0 = <&eth_phy_int_pin>, <&eth_phy_reset_pin>;
                        pinctrl-names = "default";
index fb5dcf6e93272180bfd60b8e251a61e61f0e9155..b6f045069ee2f059b453c503d488112de6d709a8 100644 (file)
        pwm3: pwm@ff1b0030 {
                compatible = "rockchip,rk3328-pwm";
                reg = <0x0 0xff1b0030 0x0 0x10>;
-               interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>;
                clock-names = "pwm", "pclk";
                pinctrl-names = "default";
                status = "disabled";
 
                ports {
-                       hdmi_in: port {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       hdmi_in: port@0 {
+                               reg = <0>;
+
                                hdmi_in_vop: endpoint {
                                        remote-endpoint = <&vop_out_hdmi>;
                                };
                        };
+
+                       hdmi_out: port@1 {
+                               reg = <1>;
+                       };
                };
        };
 
index 9e3aec4440bd652c6d4b2702aa72e9653fc57adf..dfb2a0bdea5b736d7ce6554e22a60c01d0b31297 100644 (file)
@@ -22,9 +22,6 @@
                ethernet0 = &gmac;
                mmc0 = &sdmmc;
                mmc1 = &sdhci;
-               spi1 = &spi1;
-               spi2 = &spi2;
-               spi5 = &spi5;
        };
 
        avdd_0v9_s0: avdd-0v9-s0 {
index e7551449e718ca7f6f79b01a97194a9ecb12829f..e26e2d86279cb99d4dfb4e845918e94888006e5e 100644 (file)
@@ -14,7 +14,7 @@
 
 / {
        model = "Orange Pi RK3399 Board";
-       compatible = "rockchip,rk3399-orangepi", "rockchip,rk3399";
+       compatible = "xunlong,rk3399-orangepi", "rockchip,rk3399";
 
        aliases {
                ethernet0 = &gmac;
index 18a98c4648eae78cf927a848f9ba8e4f0b4cfdc5..2c3984a880af64ceaf3f7ec1a09ceee02f0dffeb 100644 (file)
 
 &uart0 {
        pinctrl-names = "default";
-       pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
+       pinctrl-0 = <&uart0_xfer>;
        status = "okay";
 };
 
 &uart2 {
+       rts-gpios = <&gpio2 RK_PC3 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index d5df8939a65819b2fe764c8fb004fb1757110df9..c68f45849c441ba4323e253fc93772d26d82cf3b 100644 (file)
@@ -19,6 +19,6 @@
        flash@0 {
                compatible = "jedec,spi-nor";
                reg = <0>;
-               spi-max-frequency = <10000000>;
+               spi-max-frequency = <108000000>;
        };
 };
index bee6d75883027dee42835984de9522295a26ddaa..6ea3180e57ca7346bc99b745a51cc90f09f084fe 100644 (file)
@@ -37,7 +37,7 @@
        flash@0 {
                compatible = "jedec,spi-nor";
                reg = <0>;
-               spi-max-frequency = <10000000>;
+               spi-max-frequency = <108000000>;
        };
 };
 
index de2ebe4cb4f3a43d02de94f807bea9eb66806834..5274938bf1b82de1e851d41ebba146bbd90d72ca 100644 (file)
@@ -49,7 +49,7 @@
        flash@0 {
                compatible = "jedec,spi-nor";
                reg = <0>;
-               spi-max-frequency = <10000000>;
+               spi-max-frequency = <108000000>;
        };
 };
 
index 6e12c5a920caba018fbecb2ba10c64c4ee527020..9d5f5b083e3cfa51492b945d17d03dbd2a264a2d 100644 (file)
                serial2 = &uart2;
                serial3 = &uart3;
                serial4 = &uart4;
+               spi0 = &spi0;
+               spi1 = &spi1;
+               spi2 = &spi2;
+               spi3 = &spi3;
+               spi4 = &spi4;
+               spi5 = &spi5;
        };
 
        cpus {
@@ -45,7 +51,7 @@
                #size-cells = <0>;
 
                cpu-map {
-                       cluster0 {
+                       cluster0 {      /* Cortex-A53 */
                                core0 {
                                        cpu = <&cpu_l0>;
                                };
@@ -60,7 +66,7 @@
                                };
                        };
 
-                       cluster1 {
+                       cluster1 {      /* Cortex-A72 */
                                core0 {
                                        cpu = <&cpu_b0>;
                                };
                        #cooling-cells = <2>; /* min followed by max */
                        dynamic-power-coefficient = <100>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
+                       i-cache-size = <0x8000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <128>;
+                       next-level-cache = <&l2_cache_l>;
                };
 
                cpu_l1: cpu@1 {
                        #cooling-cells = <2>; /* min followed by max */
                        dynamic-power-coefficient = <100>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
+                       i-cache-size = <0x8000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <128>;
+                       next-level-cache = <&l2_cache_l>;
                };
 
                cpu_l2: cpu@2 {
                        #cooling-cells = <2>; /* min followed by max */
                        dynamic-power-coefficient = <100>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
+                       i-cache-size = <0x8000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <128>;
+                       next-level-cache = <&l2_cache_l>;
                };
 
                cpu_l3: cpu@3 {
                        #cooling-cells = <2>; /* min followed by max */
                        dynamic-power-coefficient = <100>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
+                       i-cache-size = <0x8000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <128>;
+                       next-level-cache = <&l2_cache_l>;
                };
 
                cpu_b0: cpu@100 {
                        #cooling-cells = <2>; /* min followed by max */
                        dynamic-power-coefficient = <436>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
+                       i-cache-size = <0xC000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2_cache_b>;
 
                        thermal-idle {
                                #cooling-cells = <2>;
                        #cooling-cells = <2>; /* min followed by max */
                        dynamic-power-coefficient = <436>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
+                       i-cache-size = <0xC000>;
+                       i-cache-line-size = <64>;
+                       i-cache-sets = <256>;
+                       d-cache-size = <0x8000>;
+                       d-cache-line-size = <64>;
+                       d-cache-sets = <256>;
+                       next-level-cache = <&l2_cache_b>;
 
                        thermal-idle {
                                #cooling-cells = <2>;
                        };
                };
 
+               l2_cache_l: l2-cache-cluster0 {
+                       compatible = "cache";
+                       cache-level = <2>;
+                       cache-unified;
+                       cache-size = <0x80000>;
+                       cache-line-size = <64>;
+                       cache-sets = <512>;
+               };
+
+               l2_cache_b: l2-cache-cluster1 {
+                       compatible = "cache";
+                       cache-level = <2>;
+                       cache-unified;
+                       cache-size = <0x100000>;
+                       cache-line-size = <64>;
+                       cache-sets = <1024>;
+               };
+
                idle-states {
                        entry-method = "psci";
 
        hdmi: hdmi@ff940000 {
                compatible = "rockchip,rk3399-dw-hdmi";
                reg = <0x0 0xff940000 0x0 0x20000>;
+               reg-io-width = <4>;
                interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH 0>;
                clocks = <&cru PCLK_HDMI_CTRL>,
                         <&cru SCLK_HDMI_SFR>,
                         <&cru PLL_VPLL>;
                clock-names = "iahb", "isfr", "cec", "grf", "ref";
                power-domains = <&power RK3399_PD_HDCP>;
-               reg-io-width = <4>;
                rockchip,grf = <&grf>;
                #sound-dai-cells = <0>;
                status = "disabled";
 
                ports {
-                       hdmi_in: port {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       hdmi_in: port@0 {
+                               reg = <0>;
                                #address-cells = <1>;
                                #size-cells = <0>;
 
                                        remote-endpoint = <&vopl_out_hdmi>;
                                };
                        };
+
+                       hdmi_out: port@1 {
+                               reg = <1>;
+                       };
                };
        };
 
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc-d.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc-d.dts
new file mode 100644 (file)
index 0000000..ab83e8a
--- /dev/null
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rk3566-anbernic-rg-arc.dtsi"
+
+/ {
+       model = "Anbernic RG ARC-D";
+       compatible = "anbernic,rg-arc-d", "rockchip,rk3566";
+
+       aliases {
+               mmc0 = &sdhci;
+               mmc1 = &sdmmc0;
+               mmc2 = &sdmmc1;
+               mmc3 = &sdmmc2;
+       };
+};
+
+&i2c2 {
+       pinctrl-0 = <&i2c2m1_xfer>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       touchscreen@14 {
+               compatible = "goodix,gt927";
+               reg = <0x14>;
+               interrupt-parent = <&gpio4>;
+               interrupts = <RK_PB1 IRQ_TYPE_EDGE_FALLING>;
+               irq-gpios = <&gpio4 RK_PB1 GPIO_ACTIVE_HIGH>;
+               pinctrl-0 = <&touch_int>;
+               pinctrl-names = "default";
+               reset-gpios = <&gpio4 RK_PA6 GPIO_ACTIVE_HIGH>;
+               touchscreen-inverted-y;
+               touchscreen-size-x = <640>;
+               touchscreen-size-y = <480>;
+       };
+};
+
+&pinctrl {
+       touchscreen {
+               touch_int: touch_int {
+                       rockchip,pins = <4 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+};
+
+&sdhci {
+       bus-width = <8>;
+       mmc-hs200-1_8v;
+       non-removable;
+       pinctrl-0 = <&emmc_bus8>, <&emmc_clk>, <&emmc_cmd>,
+                   <&emmc_datastrobe>, <&emmc_rstnout>;
+       pinctrl-names = "default";
+       vmmc-supply = <&vcc_3v3>;
+       vqmmc-supply = <&vcc_1v8>;
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc-s.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc-s.dts
new file mode 100644 (file)
index 0000000..6264a8c
--- /dev/null
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rk3566-anbernic-rg-arc.dtsi"
+
+/ {
+       model = "Anbernic RG ARC-S";
+       compatible = "anbernic,rg-arc-s", "rockchip,rk3566";
+
+       aliases {
+               mmc1 = &sdmmc0;
+               mmc2 = &sdmmc1;
+               mmc3 = &sdmmc2;
+       };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc.dtsi
new file mode 100644 (file)
index 0000000..a4a60e4
--- /dev/null
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rk3566-anbernic-rgxx3.dtsi"
+
+/ {
+       backlight: backlight {
+               compatible = "pwm-backlight";
+               power-supply = <&vcc_sys>;
+               pwms = <&pwm4 0 25000 0>;
+       };
+
+       battery: battery {
+               compatible = "simple-battery";
+               charge-full-design-microamp-hours = <3472000>;
+               charge-term-current-microamp = <300000>;
+               constant-charge-current-max-microamp = <2000000>;
+               constant-charge-voltage-max-microvolt = <4200000>;
+               factory-internal-resistance-micro-ohms = <117000>;
+               voltage-max-design-microvolt = <4172000>;
+               voltage-min-design-microvolt = <3400000>;
+
+               ocv-capacity-celsius = <20>;
+               ocv-capacity-table-0 =  <4172000 100>, <4054000 95>, <3984000 90>, <3926000 85>,
+                                       <3874000 80>, <3826000 75>, <3783000 70>, <3746000 65>,
+                                       <3714000 60>, <3683000 55>, <3650000 50>, <3628000 45>,
+                                       <3612000 40>, <3600000 35>, <3587000 30>, <3571000 25>,
+                                       <3552000 20>, <3525000 15>, <3492000 10>, <3446000 5>,
+                                       <3400000 0>;
+       };
+
+       /* Channels reversed for both headphones and speakers. */
+       sound {
+               compatible = "simple-audio-card";
+               pinctrl-0 = <&hp_det>;
+               pinctrl-names = "default";
+               simple-audio-card,name = "rk817_ext";
+               simple-audio-card,aux-devs = <&spk_amp>;
+               simple-audio-card,format = "i2s";
+               simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
+               simple-audio-card,mclk-fs = <256>;
+               simple-audio-card,widgets =
+                       "Microphone", "Mic Jack",
+                       "Headphone", "Headphones",
+                       "Speaker", "Internal Speakers";
+               simple-audio-card,routing =
+                       "MICL", "Mic Jack",
+                       "Headphones", "HPOL",
+                       "Headphones", "HPOR",
+                       "Internal Speakers", "Speaker Amp OUTL",
+                       "Internal Speakers", "Speaker Amp OUTR",
+                       "Speaker Amp INL", "HPOL",
+                       "Speaker Amp INR", "HPOR";
+               simple-audio-card,pin-switches = "Internal Speakers";
+
+               simple-audio-card,codec {
+                       sound-dai = <&rk817>;
+               };
+
+               simple-audio-card,cpu {
+                       sound-dai = <&i2s1_8ch>;
+               };
+       };
+
+       spk_amp: audio-amplifier {
+               compatible = "simple-audio-amplifier";
+               enable-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>;
+               pinctrl-0 = <&spk_amp_enable_h>;
+               pinctrl-names = "default";
+               sound-name-prefix = "Speaker Amp";
+       };
+};
+
+&cru {
+       assigned-clocks = <&pmucru CLK_RTC_32K>, <&cru PLL_GPLL>,
+                         <&pmucru PLL_PPLL>, <&cru PLL_VPLL>;
+       assigned-clock-rates = <32768>, <1200000000>,
+                              <200000000>, <128000000>;
+};
+
+&dsi_dphy0 {
+       status = "okay";
+};
+
+&dsi0 {
+       status = "okay";
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       ports {
+               dsi0_in: port@0 {
+                       reg = <0>;
+                       dsi0_in_vp1: endpoint {
+                               remote-endpoint = <&vp1_out_dsi0>;
+                       };
+               };
+
+               dsi0_out: port@1 {
+                       reg = <1>;
+                       mipi_out_panel: endpoint {
+                               remote-endpoint = <&mipi_in_panel>;
+                       };
+               };
+       };
+
+       panel: panel@0 {
+               compatible = "anbernic,rg-arc-panel", "sitronix,st7701";
+               reg = <0>;
+               backlight = <&backlight>;
+               IOVCC-supply = <&vcc3v3_lcd0_n>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&lcd_rst>;
+               reset-gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_HIGH>;
+               rotation = <90>;
+               VCC-supply = <&vcc3v3_lcd0_n>;
+
+               port {
+                       mipi_in_panel: endpoint {
+                               remote-endpoint = <&mipi_out_panel>;
+                       };
+               };
+       };
+};
+
+/*
+ * Device uses a non-standard six button layout for a gamepad with X,
+ * Y, and Z on the top row of buttons and A, B, and C under the bottom
+ * row.
+ */
+&gpio_keys_control {
+       button-a {
+               gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_LOW>;
+               label = "A";
+               linux,code = <BTN_A>;
+       };
+
+       button-b {
+               gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>;
+               label = "B";
+               linux,code = <BTN_B>;
+       };
+
+       button-c {
+               gpios = <&gpio3 RK_PA2 GPIO_ACTIVE_LOW>;
+               label = "C";
+               linux,code = <BTN_C>;
+       };
+
+       button-left {
+               gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_LOW>;
+               label = "DPAD-LEFT";
+               linux,code = <BTN_DPAD_LEFT>;
+       };
+
+       button-r1 {
+               gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>;
+               label = "TR";
+               linux,code = <BTN_TR>;
+       };
+
+       button-r2 {
+               gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>;
+               label = "TR2";
+               linux,code = <BTN_TR2>;
+       };
+
+       button-right {
+               gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_LOW>;
+               label = "DPAD-RIGHT";
+               linux,code = <BTN_DPAD_RIGHT>;
+       };
+
+       button-x {
+               gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>;
+               label = "X";
+               linux,code = <BTN_X>;
+       };
+
+       button-y {
+               gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>;
+               label = "Y";
+               linux,code = <BTN_Y>;
+       };
+
+       button-z {
+               gpios = <&gpio3 RK_PA1 GPIO_ACTIVE_LOW>;
+               label = "Z";
+               linux,code = <BTN_Z>;
+       };
+};
+
+&pinctrl {
+       audio-amplifier {
+               spk_amp_enable_h: spk-amp-enable-h {
+                       rockchip,pins =
+                               <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       gpio-lcd {
+               lcd_rst: lcd-rst {
+                       rockchip,pins =
+                               <4 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       headphone {
+               hp_det: hp-det {
+                       rockchip,pins =
+                               <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+};
+
+&pwm4 {
+       status = "okay";
+};
+
+&rk817 {
+       rk817_charger: charger {
+               monitored-battery = <&battery>;
+               rockchip,resistor-sense-micro-ohms = <10000>;
+               rockchip,sleep-enter-current-microamp = <300000>;
+               rockchip,sleep-filter-current-microamp = <100000>;
+       };
+};
+
+&vp1 {
+       vp1_out_dsi0: endpoint@ROCKCHIP_VOP2_EP_MIPI0 {
+               reg = <ROCKCHIP_VOP2_EP_MIPI0>;
+               remote-endpoint = <&dsi0_in_vp1>;
+       };
+};
index 2a2821f4c580b0afe219394e0de64072e924482f..63a18ff36ceaeff81e5ca80cc6fa3868f8b03b9d 100644 (file)
@@ -8,11 +8,73 @@
 #include "rk3566-anbernic-rgxx3.dtsi"
 
 / {
+       adc-joystick {
+               compatible = "adc-joystick";
+               io-channels = <&adc_mux 0>,
+                             <&adc_mux 1>,
+                             <&adc_mux 2>,
+                             <&adc_mux 3>;
+               pinctrl-0 = <&joy_mux_en>;
+               pinctrl-names = "default";
+               poll-interval = <60>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               axis@0 {
+                       reg = <0>;
+                       abs-flat = <32>;
+                       abs-fuzz = <32>;
+                       abs-range = <1023 15>;
+                       linux,code = <ABS_X>;
+               };
+
+               axis@1 {
+                       reg = <1>;
+                       abs-flat = <32>;
+                       abs-fuzz = <32>;
+                       abs-range = <15 1023>;
+                       linux,code = <ABS_RX>;
+               };
+
+               axis@2 {
+                       reg = <2>;
+                       abs-flat = <32>;
+                       abs-fuzz = <32>;
+                       abs-range = <15 1023>;
+                       linux,code = <ABS_Y>;
+               };
+
+               axis@3 {
+                       reg = <3>;
+                       abs-flat = <32>;
+                       abs-fuzz = <32>;
+                       abs-range = <1023 15>;
+                       linux,code = <ABS_RY>;
+               };
+       };
+
+       adc_mux: adc-mux {
+               compatible = "io-channel-mux";
+               channels = "left_x", "right_x", "left_y", "right_y";
+               #io-channel-cells = <1>;
+               io-channels = <&saradc 3>;
+               io-channel-names = "parent";
+               mux-controls = <&gpio_mux>;
+               settle-time-us = <100>;
+       };
+
        backlight: backlight {
                compatible = "pwm-backlight";
                power-supply = <&vcc_sys>;
                pwms = <&pwm4 0 25000 0>;
        };
+
+       gpio_mux: mux-controller {
+               compatible = "gpio-mux";
+               mux-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>,
+                           <&gpio0 RK_PB7 GPIO_ACTIVE_LOW>;
+               #mux-control-cells = <0>;
+       };
 };
 
 &cru {
                linux,code = <BTN_DPAD_RIGHT>;
        };
 
+       button-thumbl {
+               gpios = <&gpio3 RK_PA1 GPIO_ACTIVE_LOW>;
+               label = "THUMBL";
+               linux,code = <BTN_THUMBL>;
+       };
+
+       button-thumbr {
+               gpios = <&gpio3 RK_PA2 GPIO_ACTIVE_LOW>;
+               label = "THUMBR";
+               linux,code = <BTN_THUMBR>;
+       };
+
        button-y {
                gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>;
                label = "WEST";
index c763c7f3b1b38b71fc1702c1e6a157d58e6af2e8..94e6dd61a2dbb4f1bca3efb7106c1d500ac3cb06 100644 (file)
                mmc2 = &sdmmc2;
        };
 
+       adc-joystick {
+               compatible = "adc-joystick";
+               io-channels = <&adc_mux 0>,
+                             <&adc_mux 1>,
+                             <&adc_mux 2>,
+                             <&adc_mux 3>;
+               pinctrl-0 = <&joy_mux_en>;
+               pinctrl-names = "default";
+               poll-interval = <60>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               axis@0 {
+                       reg = <0>;
+                       abs-flat = <32>;
+                       abs-fuzz = <32>;
+                       abs-range = <1023 15>;
+                       linux,code = <ABS_X>;
+               };
+
+               axis@1 {
+                       reg = <1>;
+                       abs-flat = <32>;
+                       abs-fuzz = <32>;
+                       abs-range = <15 1023>;
+                       linux,code = <ABS_RX>;
+               };
+
+               axis@2 {
+                       reg = <2>;
+                       abs-flat = <32>;
+                       abs-fuzz = <32>;
+                       abs-range = <15 1023>;
+                       linux,code = <ABS_Y>;
+               };
+
+               axis@3 {
+                       reg = <3>;
+                       abs-flat = <32>;
+                       abs-fuzz = <32>;
+                       abs-range = <1023 15>;
+                       linux,code = <ABS_RY>;
+               };
+       };
+
+       adc_mux: adc-mux {
+               compatible = "io-channel-mux";
+               channels = "left_x", "right_x", "left_y", "right_y";
+               #io-channel-cells = <1>;
+               io-channels = <&saradc 3>;
+               io-channel-names = "parent";
+               mux-controls = <&gpio_mux>;
+               settle-time-us = <100>;
+       };
+
        battery: battery {
                compatible = "simple-battery";
                charge-full-design-microamp-hours = <3472000>;
                                        <3400000 0>;
        };
 
+       gpio_mux: mux-controller {
+               compatible = "gpio-mux";
+               mux-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>,
+                           <&gpio0 RK_PB7 GPIO_ACTIVE_LOW>;
+               #mux-control-cells = <0>;
+       };
+
        gpio_spi: spi {
                compatible = "spi-gpio";
                pinctrl-names = "default";
                linux,code = <BTN_DPAD_RIGHT>;
        };
 
+       button-thumbl {
+               gpios = <&gpio3 RK_PA1 GPIO_ACTIVE_LOW>;
+               label = "THUMBL";
+               linux,code = <BTN_THUMBL>;
+       };
+
+       button-thumbr {
+               gpios = <&gpio3 RK_PA2 GPIO_ACTIVE_LOW>;
+               label = "THUMBR";
+               linux,code = <BTN_THUMBR>;
+       };
+
        button-y {
                gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>;
                label = "WEST";
index 8cbf3d9a4f22ee975fe45616c31c71f351597b0b..18b8c2e7befa75712c0e2b1af9b35113ffec4d84 100644 (file)
                stdout-path = "serial2:1500000n8";
        };
 
-       adc-joystick {
-               compatible = "adc-joystick";
-               io-channels = <&adc_mux 0>,
-                             <&adc_mux 1>,
-                             <&adc_mux 2>,
-                             <&adc_mux 3>;
-               pinctrl-0 = <&joy_mux_en>;
-               pinctrl-names = "default";
-               poll-interval = <60>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               axis@0 {
-                       reg = <0>;
-                       abs-flat = <32>;
-                       abs-fuzz = <32>;
-                       abs-range = <1023 15>;
-                       linux,code = <ABS_X>;
-               };
-
-               axis@1 {
-                       reg = <1>;
-                       abs-flat = <32>;
-                       abs-fuzz = <32>;
-                       abs-range = <15 1023>;
-                       linux,code = <ABS_RX>;
-               };
-
-               axis@2 {
-                       reg = <2>;
-                       abs-flat = <32>;
-                       abs-fuzz = <32>;
-                       abs-range = <15 1023>;
-                       linux,code = <ABS_Y>;
-               };
-
-               axis@3 {
-                       reg = <3>;
-                       abs-flat = <32>;
-                       abs-fuzz = <32>;
-                       abs-range = <1023 15>;
-                       linux,code = <ABS_RY>;
-               };
-       };
-
        adc_keys: adc-keys {
                compatible = "adc-keys";
                io-channels = <&saradc 0>;
                };
        };
 
-       adc_mux: adc-mux {
-               compatible = "io-channel-mux";
-               channels = "left_x", "right_x", "left_y", "right_y";
-               #io-channel-cells = <1>;
-               io-channels = <&saradc 3>;
-               io-channel-names = "parent";
-               mux-controls = <&gpio_mux>;
-               settle-time-us = <100>;
-       };
-
        gpio_keys_control: gpio-keys-control {
                compatible = "gpio-keys";
                pinctrl-0 = <&btn_pins_ctrl>;
                        linux,code = <BTN_START>;
                };
 
-               button-thumbl {
-                       gpios = <&gpio3 RK_PA1 GPIO_ACTIVE_LOW>;
-                       label = "THUMBL";
-                       linux,code = <BTN_THUMBL>;
-               };
-
-               button-thumbr {
-                       gpios = <&gpio3 RK_PA2 GPIO_ACTIVE_LOW>;
-                       label = "THUMBR";
-                       linux,code = <BTN_THUMBR>;
-               };
-
                button-up {
                        gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_LOW>;
                        label = "DPAD-UP";
                };
        };
 
-       gpio_mux: mux-controller {
-               compatible = "gpio-mux";
-               mux-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>,
-                           <&gpio0 RK_PB7 GPIO_ACTIVE_LOW>;
-               #mux-control-cells = <0>;
-       };
-
        hdmi-con {
                compatible = "hdmi-connector";
                ddc-i2c-bus = <&i2c5>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-pinetab2-v0.1.dts b/arch/arm64/boot/dts/rockchip/rk3566-pinetab2-v0.1.dts
new file mode 100644 (file)
index 0000000..5fe6ca5
--- /dev/null
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include "rk3566-pinetab2.dtsi"
+
+/ {
+       model = "Pine64 PineTab2 v0.1";
+       compatible = "pine64,pinetab2-v0.1", "pine64,pinetab2", "rockchip,rk3566";
+};
+
+&lcd {
+       reset-gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_LOW>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&lcd_pwren_h &lcd0_rst_l>;
+};
+
+&pinctrl {
+       lcd0 {
+               lcd0_rst_l: lcd0-rst-l {
+                       rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+};
+
+&sdmmc1 {
+       vmmc-supply = <&vcc3v3_sys>;
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-pinetab2-v2.0.dts b/arch/arm64/boot/dts/rockchip/rk3566-pinetab2-v2.0.dts
new file mode 100644 (file)
index 0000000..9349541
--- /dev/null
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include "rk3566-pinetab2.dtsi"
+
+/ {
+       model = "Pine64 PineTab2 v2.0";
+       compatible = "pine64,pinetab2-v2.0", "pine64,pinetab2", "rockchip,rk3566";
+};
+
+&gpio_keys {
+       pinctrl-0 = <&kb_id_det>, <&hall_int_l>;
+
+       event-hall-sensor {
+               debounce-interval = <20>;
+               gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_LOW>;
+               label = "Hall Sensor";
+               linux,code = <SW_LID>;
+               linux,input-type = <EV_SW>;
+               wakeup-event-action = <EV_ACT_DEASSERTED>;
+               wakeup-source;
+       };
+};
+
+&lcd {
+       reset-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_LOW>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&lcd_pwren_h &lcd0_rst_l>;
+};
+
+&pinctrl {
+       lcd0 {
+               lcd0_rst_l: lcd0-rst-l {
+                       rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       hall {
+               hall_int_l: hall-int-l {
+                       rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+};
+
+&sdmmc1 {
+       vmmc-supply = <&vcc_sys>;
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-pinetab2.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-pinetab2.dtsi
new file mode 100644 (file)
index 0000000..db40281
--- /dev/null
@@ -0,0 +1,943 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/gpio-keys.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+#include "rk3566.dtsi"
+
+/ {
+       chassis-type = "tablet";
+
+       aliases {
+               mmc0 = &sdhci;
+               mmc1 = &sdmmc0;
+       };
+
+       chosen {
+               stdout-path = "serial2:1500000n8";
+       };
+
+       adc-keys {
+               compatible = "adc-keys";
+               io-channels = <&saradc 0>;
+               io-channel-names = "buttons";
+               keyup-threshold-microvolt = <1800000>;
+               poll-interval = <25>;
+
+               button-vol-up {
+                       label = "Volume Up";
+                       linux,code = <KEY_VOLUMEUP>;
+                       press-threshold-microvolt = <297500>;
+               };
+
+               button-vol-down {
+                       label = "Volume Down";
+                       linux,code = <KEY_VOLUMEDOWN>;
+                       press-threshold-microvolt = <1750>;
+               };
+       };
+
+       backlight: backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm4 0 25000 0>;
+               brightness-levels = <20 220>;
+               num-interpolated-steps = <200>;
+               default-brightness-level = <100>;
+               power-supply = <&vcc_sys>;
+       };
+
+       battery: battery {
+               compatible = "simple-battery";
+               charge-full-design-microamp-hours = <6000000>;
+               charge-term-current-microamp = <300000>;
+               constant-charge-current-max-microamp = <2000000>;
+               constant-charge-voltage-max-microvolt = <4300000>;
+               voltage-max-design-microvolt = <4350000>;
+               voltage-min-design-microvolt = <3400000>;
+
+               ocv-capacity-celsius = <20>;
+               ocv-capacity-table-0 = <4322000 100>, <4250000 95>, <4192000 90>, <4136000 85>,
+                                      <4080000 80>, <4022000 75>, <3972000 70>, <3928000 65>,
+                                      <3885000 60>, <3833000 55>, <3798000 50>, <3780000 45>,
+                                      <3776000 40>, <3773000 35>, <3755000 30>, <3706000 25>,
+                                      <3640000 20>, <3589000 15>, <3535000 10>, <3492000 5>,
+                                      <3400000 0>;
+       };
+
+       gpio_keys: gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&kb_id_det>;
+
+               tablet-mode-switch {
+                       debounce-interval = <20>;
+                       gpios = <&gpio4 RK_PA4 GPIO_ACTIVE_HIGH>;
+                       label = "Tablet Mode";
+                       linux,input-type = <EV_SW>;
+                       linux,code = <SW_TABLET_MODE>;
+               };
+       };
+
+       hdmi-connector {
+               compatible = "hdmi-connector";
+               type = "d";
+
+               port {
+                       hdmi_con_in: endpoint {
+                               remote-endpoint = <&hdmi_out_con>;
+                       };
+               };
+       };
+
+       led-0 {
+               compatible = "regulator-led";
+               vled-supply = <&vcc5v0_flashled>;
+               color = <LED_COLOR_ID_WHITE>;
+               function = LED_FUNCTION_FLASH;
+       };
+
+       rk817-sound {
+               compatible = "simple-audio-card";
+               pinctrl-names = "default";
+               pinctrl-0 = <&hp_det_l>;
+               simple-audio-card,format = "i2s";
+               simple-audio-card,name = "rk817_ext";
+               simple-audio-card,mclk-fs = <256>;
+
+               simple-audio-card,widgets =
+                       "Microphone", "Mic Jack",
+                       "Headphone", "Headphones",
+                       "Speaker", "Internal Speakers";
+
+               simple-audio-card,routing =
+                       "MICR", "Mic Jack",
+                       "Headphones", "HPOL",
+                       "Headphones", "HPOR",
+                       "Internal Speakers", "Speaker Amplifier OUTL",
+                       "Internal Speakers", "Speaker Amplifier OUTR",
+                       "Speaker Amplifier INL", "HPOL",
+                       "Speaker Amplifier INR", "HPOR";
+               simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>;
+               simple-audio-card,aux-devs = <&speaker_amp>;
+               simple-audio-card,pin-switches = "Internal Speakers";
+
+               simple-audio-card,cpu {
+                       sound-dai = <&i2s1_8ch>;
+               };
+
+               simple-audio-card,codec {
+                       sound-dai = <&rk817>;
+               };
+       };
+
+       speaker_amp: speaker-amplifier {
+               compatible = "simple-audio-amplifier";
+               pinctrl-names = "default";
+               pinctrl-0 = <&spk_ctl>;
+               enable-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>;
+               sound-name-prefix = "Speaker Amplifier";
+               VCC-supply = <&vcc_bat>;
+       };
+
+       vcc_3v3: vcc-3v3-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_3v3";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vcc3v3_sys>;
+       };
+
+       vcc3v3_minipcie: vcc3v3-minipcie-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio4 RK_PC3 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pcie_pwren_h>;
+               regulator-name = "vcc3v3_minipcie";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vcc_sys>;
+       };
+
+       vcc3v3_sd: vcc3v3-sd-regulator {
+               compatible = "regulator-fixed";
+               gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&sdmmc_pwren_l>;
+               regulator-name = "vcc3v3_sd";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vcc3v3_sys>;
+       };
+
+       vcc5v0_flashled: vcc5v0-flashled-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&flash_led_en_h>;
+               regulator-name = "vcc5v0_flashled";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc5v_midu>;
+       };
+
+       vcc5v0_usb_host0: vcc5v0-usb-host0-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio4 RK_PC4 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&usb_host_pwren1_h>;
+               regulator-name = "vcc5v0_usb_host0";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc5v_midu>;
+       };
+
+       vcc5v0_usb_host2: vcc5v0-usb-host2-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio4 RK_PC5 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&usb_host_pwren2_h>;
+               regulator-name = "vcc5v0_usb_host2";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc5v_midu>;
+       };
+
+       vcc_bat: vcc-bat-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_bat";
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       vcc_sys: vcc-sys-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_sys";
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc_bat>;
+       };
+
+       vdd1v2_dvp: vdd1v2-dvp-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd1v2_dvp";
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <1200000>;
+               vin-supply = <&vcc_3v3>;
+       };
+};
+
+&combphy1 {
+       status = "okay";
+};
+
+&combphy2 {
+       status = "okay";
+};
+
+&cpu0 {
+       cpu-supply = <&vdd_cpu>;
+};
+
+&cpu1 {
+       cpu-supply = <&vdd_cpu>;
+};
+
+&cpu2 {
+       cpu-supply = <&vdd_cpu>;
+};
+
+&cpu3 {
+       cpu-supply = <&vdd_cpu>;
+};
+
+&cru {
+       assigned-clocks = <&pmucru CLK_RTC_32K>, <&cru PLL_GPLL>,
+                         <&pmucru PLL_PPLL>, <&cru PLL_VPLL>;
+       assigned-clock-rates = <32768>, <1200000000>, <200000000>, <500000000>;
+       assigned-clock-parents = <&pmucru CLK_RTC32K_FRAC>;
+};
+
+&csi_dphy {
+       status = "okay";
+};
+
+&dsi0 {
+       status = "okay";
+       clock-master;
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       lcd: panel@0 {
+               compatible = "boe,th101mb31ig002-28a";
+               reg = <0>;
+               backlight = <&backlight>;
+               enable-gpios = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>;
+               rotation = <90>;
+               power-supply = <&vcc_3v3>;
+
+               port@0 {
+                       panel_in_dsi: endpoint@0 {
+                               remote-endpoint = <&dsi0_out_con>;
+                       };
+               };
+       };
+};
+
+&dsi0_in {
+       dsi0_in_vp1: endpoint {
+               remote-endpoint = <&vp1_out_dsi0>;
+       };
+};
+
+&dsi0_out {
+       dsi0_out_con: endpoint {
+               remote-endpoint = <&panel_in_dsi>;
+       };
+};
+
+&dsi_dphy0 {
+       status = "okay";
+};
+
+&gpu {
+       mali-supply = <&vdd_gpu_npu>;
+       status = "okay";
+};
+
+&hdmi {
+       avdd-0v9-supply = <&vdda_0v9_p>;
+       avdd-1v8-supply = <&vcc_1v8>;
+       status = "okay";
+};
+
+&hdmi_in {
+       hdmi_in_vp0: endpoint {
+               remote-endpoint = <&vp0_out_hdmi>;
+       };
+};
+
+&hdmi_out {
+       hdmi_out_con: endpoint {
+               remote-endpoint = <&hdmi_con_in>;
+       };
+};
+
+&hdmi_sound {
+       status = "okay";
+};
+
+&i2c0 {
+       clock-frequency = <400000>;
+       status = "okay";
+
+       vdd_cpu: regulator@1c {
+               compatible = "tcs,tcs4525";
+               reg = <0x1c>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_cpu";
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <1150000>;
+               regulator-ramp-delay = <2300>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vcc_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+
+       rk817: pmic@20 {
+               compatible = "rockchip,rk817";
+               reg = <0x20>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PA3 IRQ_TYPE_LEVEL_LOW>;
+               assigned-clocks = <&cru I2S1_MCLKOUT_TX>;
+               assigned-clock-parents = <&cru CLK_I2S1_8CH_TX>;
+               clock-names = "mclk";
+               clocks = <&cru I2S1_MCLKOUT_TX>;
+               clock-output-names = "rk808-clkout1", "rk808-clkout2";
+               #clock-cells = <1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_int_l>, <&i2s1m0_mclk>;
+               rockchip,system-power-controller;
+               #sound-dai-cells = <0>;
+               wakeup-source;
+
+               vcc1-supply = <&vcc_sys>;
+               vcc2-supply = <&vcc_sys>;
+               vcc3-supply = <&vcc_sys>;
+               vcc4-supply = <&vcc_sys>;
+               vcc5-supply = <&vcc_sys>;
+               vcc6-supply = <&vcc_sys>;
+               vcc7-supply = <&vcc_sys>;
+               vcc8-supply = <&vcc_sys>;
+               vcc9-supply = <&vcc5v_midu>;
+
+               regulators {
+                       vdd_logic: DCDC_REG1 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <6001>;
+                               regulator-initial-mode = <0x2>;
+                               regulator-name = "vdd_logic";
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_gpu_npu: DCDC_REG2 {
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-ramp-delay = <6001>;
+                               regulator-initial-mode = <0x2>;
+                               regulator-name = "vdd_gpu_npu";
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_ddr: DCDC_REG3 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-initial-mode = <0x2>;
+                               regulator-name = "vcc_ddr";
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc3v3_sys: DCDC_REG4 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-initial-mode = <0x2>;
+                               regulator-name = "vcc3v3_sys";
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcca1v8_pmu: LDO_REG1 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcca1v8_pmu";
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vdda_0v9_p: LDO_REG2 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <900000>;
+                               regulator-name = "vdda_0v9_p";
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdda0v9_pmu: LDO_REG3 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <900000>;
+                               regulator-name = "vdda0v9_pmu";
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vccio_acodec: LDO_REG4 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vccio_acodec";
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vccio_sd: LDO_REG5 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vccio_sd";
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc3v3_pmu: LDO_REG6 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc3v3_pmu";
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc_1v8: LDO_REG7 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc_1v8";
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc1v8_dvp: LDO_REG8 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc1v8_dvp";
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc2v8_dvp: LDO_REG9 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-name = "vcc2v8_dvp";
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc5v_midu: BOOST {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <5000000>;
+                               regulator-max-microvolt = <5000000>;
+                               regulator-name = "boost";
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vbus: OTG_SWITCH {
+                               regulator-min-microvolt = <5000000>;
+                               regulator-max-microvolt = <5000000>;
+                               regulator-name = "otg_switch";
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+               };
+
+               charger {
+                       monitored-battery = <&battery>;
+                       rockchip,resistor-sense-micro-ohms = <10000>;
+                       rockchip,sleep-enter-current-microamp = <300000>;
+                       rockchip,sleep-filter-current-microamp = <100000>;
+               };
+       };
+};
+
+&i2c1 {
+       clock-frequency = <400000>;
+       status = "okay";
+
+       touchscreen@5d {
+               compatible = "goodix,gt911";
+               reg = <0x5d>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PB0 IRQ_TYPE_EDGE_FALLING>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&tp_int_l_pmuio2>, <&tp_rst_l_pmuio2>;
+               AVDD28-supply = <&vcc3v3_pmu>;
+               VDDIO-supply = <&vcca1v8_pmu>;
+               irq-gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&gpio0 RK_PC2 GPIO_ACTIVE_HIGH>;
+       };
+};
+
+&i2c2 {
+       clock-frequency = <400000>;
+       pinctrl-0 = <&i2c2m1_xfer>;
+       status = "okay";
+
+       vcm@c {
+               compatible = "dongwoon,dw9714";
+               reg = <0x0c>;
+               vcc-supply = <&vcc1v8_dvp>;
+       };
+
+       camera@36 {
+               compatible = "ovti,ov5648";
+               reg = <0x36>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&camerab_pdn_l &camerab_rst_l>;
+
+               clocks = <&cru CLK_CIF_OUT>;
+               assigned-clocks = <&cru CLK_CIF_OUT>;
+               assigned-clock-rates = <24000000>;
+
+               avdd-supply = <&vcc2v8_dvp>;
+               dvdd-supply = <&vdd1v2_dvp>;
+               dovdd-supply = <&vcc1v8_dvp>;
+               powerdown-gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_LOW>;
+               reset-gpios = <&gpio4 RK_PB1 GPIO_ACTIVE_LOW>;
+
+               port {
+                       endpoint {
+                               data-lanes = <1 2>;
+                               remote-endpoint = <0>;
+                               link-frequencies = /bits/ 64 <210000000 168000000>;
+                       };
+               };
+       };
+};
+
+&i2c5 {
+       clock-frequency = <400000>;
+       status = "okay";
+
+       accelerometer@18 {
+               compatible = "silan,sc7a20";
+               reg = <0x18>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <RK_PA2 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&gsensor_int_l>;
+               st,drdy-int-pin = <1>;
+               vdd-supply = <&vcc_1v8>;
+               vddio-supply = <&vcc_1v8>;
+               mount-matrix = "1", "0", "0",
+                              "0", "0", "1",
+                              "0", "1", "0";
+       };
+};
+
+&i2s0_8ch {
+       status = "okay";
+};
+
+&i2s1_8ch {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2s1m0_sclktx
+                    &i2s1m0_lrcktx
+                    &i2s1m0_sdi0
+                    &i2s1m0_sdo0>;
+       rockchip,trcm-sync-tx-only;
+       status = "okay";
+};
+
+&pcie2x1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie_reset_h>;
+       reset-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>;
+       vpcie3v3-supply = <&vcc3v3_minipcie>;
+       status = "okay";
+};
+
+&pinctrl {
+       camerab {
+               camerab_pdn_l: camerab-pdn-l {
+                       rockchip,pins = <4 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               camerab_rst_l: camerab-rst-l {
+                       rockchip,pins = <4 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       cameraf {
+               cameraf_pdn_l: cameraf-pdn-l {
+                       rockchip,pins = <4 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               cameraf_rst_l: cameraf-rst-l {
+                       rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       flash {
+               flash_led_en_h: flash-led-en-h {
+                       rockchip,pins = <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       fspi {
+               fspi_dual_io_pins: fspi-dual-io-pins {
+                       rockchip,pins =
+                               /* fspi_clk */
+                               <1 RK_PD0 1 &pcfg_pull_none>,
+                               /* fspi_cs0n */
+                               <1 RK_PD3 1 &pcfg_pull_none>,
+                               /* fspi_d0 */
+                               <1 RK_PD1 1 &pcfg_pull_none>,
+                               /* fspi_d1 */
+                               <1 RK_PD2 1 &pcfg_pull_none>;
+               };
+       };
+
+       gsensor {
+               gsensor_int_l: gsensor-int-l {
+                       rockchip,pins = <3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       kb {
+               kb_id_det: kb-id-det {
+                       rockchip,pins = <4 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       lcd {
+               lcd_pwren_h: lcd-pwren-h {
+                       rockchip,pins = <0 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       pcie {
+               pcie_pwren_h: pcie-pwren-h {
+                       rockchip,pins = <4 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               pcie_reset_h: pcie-reset-h {
+                       rockchip,pins = <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       pmic {
+               pmic_int_l: pmic-int-l {
+                       rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       sdmmc {
+               sdmmc_pwren_l: sdmmc-pwren-l {
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       sound {
+               hp_det_l: hp-det-l {
+                       rockchip,pins = <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               spk_ctl: spk-ctl {
+                       rockchip,pins = <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       tp {
+               tp_int_l_pmuio2: tp-int-l-pmuio2 {
+                       rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+
+               tp_rst_l_pmuio2: tp-rst-l-pmuio2 {
+                       rockchip,pins = <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       usb {
+               usbcc_int_l: usbcc-int-l {
+                       rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               usb_host_pwren1_h: usb-host-pwren1-h {
+                       rockchip,pins = <4 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               usb_host_pwren2_h: usb-host-pwren2-h {
+                       rockchip,pins = <4 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       wifi {
+               host_wake_wl: host-wake-wl {
+                       rockchip,pins = <0 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               wifi_wake_host_h: wifi-wake-host-h {
+                       rockchip,pins = <0 RK_PC4 RK_FUNC_GPIO &pcfg_pull_down>;
+               };
+       };
+};
+
+&pmu_io_domains {
+       pmuio1-supply = <&vcc3v3_pmu>;
+       pmuio2-supply = <&vcca1v8_pmu>;
+       vccio1-supply = <&vccio_acodec>;
+       vccio2-supply = <&vcc_1v8>;
+       vccio3-supply = <&vccio_sd>;
+       vccio4-supply = <&vcc_1v8>;
+       vccio5-supply = <&vcc_1v8>;
+       vccio6-supply = <&vcc1v8_dvp>;
+       vccio7-supply = <&vcc_3v3>;
+       status = "okay";
+};
+
+&pwm4 {
+       status = "okay";
+};
+
+&saradc {
+       vref-supply = <&vcc_1v8>;
+       status = "okay";
+};
+
+&sdhci {
+       bus-width = <8>;
+       no-sdio;
+       no-sd;
+       non-removable;
+       max-frequency = <200000000>;
+       mmc-hs200-1_8v;
+       pinctrl-names = "default";
+       pinctrl-0 = <&emmc_bus8
+                    &emmc_clk
+                    &emmc_cmd
+                    &emmc_datastrobe
+                    &emmc_rstnout>;
+       vmmc-supply = <&vcc_3v3>;
+       vqmmc-supply = <&vcc_1v8>;
+       status = "okay";
+};
+
+&sdmmc0 {
+       bus-width = <4>;
+       cap-sd-highspeed;
+       cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
+       disable-wp;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdmmc0_bus4
+                    &sdmmc0_clk
+                    &sdmmc0_cmd
+                    &sdmmc0_det>;
+       sd-uhs-sdr104;
+       vmmc-supply = <&vcc3v3_sd>;
+       vqmmc-supply = <&vccio_sd>;
+       status = "okay";
+};
+
+&sdmmc1 {
+       bus-width = <4>;
+       cap-sd-highspeed;
+       cap-sdio-irq;
+       keep-power-in-suspend;
+       non-removable;
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdmmc1_bus4
+                    &sdmmc1_cmd
+                    &sdmmc1_clk>;
+       sd-uhs-sdr104;
+       vqmmc-supply = <&vcca1v8_pmu>;
+       status = "okay";
+};
+
+&sfc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&fspi_dual_io_pins>;
+       status = "okay";
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <100000000>;
+               spi-rx-bus-width = <2>;
+               spi-tx-bus-width = <1>;
+       };
+};
+
+&tsadc {
+       rockchip,hw-tshut-mode = <1>;
+       rockchip,hw-tshut-polarity = <0>;
+       status = "okay";
+};
+
+&uart2 {
+       status = "okay";
+};
+
+&usb_host0_ehci {
+       status = "okay";
+};
+
+&usb_host0_ohci {
+       status = "okay";
+};
+
+&usb_host0_xhci {
+       status = "okay";
+};
+
+&usb_host1_xhci {
+       status = "okay";
+};
+
+&usb2phy0 {
+       status = "okay";
+};
+
+&usb2phy0_host {
+       phy-supply = <&vcc5v0_usb_host0>;
+       status = "okay";
+};
+
+&usb2phy0_otg {
+       status = "okay";
+};
+
+&usb2phy1 {
+       status = "okay";
+};
+
+&usb2phy1_otg {
+       phy-supply = <&vcc5v0_usb_host2>;
+       status = "okay";
+};
+
+&vop {
+       assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
+       assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
+       status = "okay";
+};
+
+&vop_mmu {
+       status = "okay";
+};
+
+&vp0 {
+       vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 {
+               reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+               remote-endpoint = <&hdmi_in_vp0>;
+       };
+};
+
+&vp1 {
+       vp1_out_dsi0: endpoint@ROCKCHIP_VOP2_EP_MIPI0 {
+               reg = <ROCKCHIP_VOP2_EP_MIPI0>;
+               remote-endpoint = <&dsi0_in_vp1>;
+       };
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb10max3.dts b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb10max3.dts
new file mode 100644 (file)
index 0000000..e5a474e
--- /dev/null
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rk3566-powkiddy-rk2023.dtsi"
+
+/ {
+       model = "Powkiddy RGB10MAX3";
+       compatible = "powkiddy,rgb10max3", "rockchip,rk3566";
+};
+
+&bluetooth {
+       compatible = "realtek,rtl8723ds-bt";
+};
+
+&cru {
+       assigned-clocks = <&pmucru CLK_RTC_32K>, <&cru PLL_GPLL>,
+                         <&pmucru PLL_PPLL>, <&cru PLL_VPLL>;
+       assigned-clock-rates = <32768>, <1200000000>,
+                              <200000000>, <126400000>;
+};
+
+&dsi0 {
+       panel: panel@0 {
+               compatible = "powkiddy,rgb10max3-panel";
+               reg = <0>;
+               backlight = <&backlight>;
+               iovcc-supply = <&vcc3v3_lcd0_n>;
+               pinctrl-0 = <&lcd_rst>;
+               pinctrl-names = "default";
+               reset-gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_LOW>;
+               rotation = <270>;
+               vcc-supply = <&vcc3v3_lcd0_n>;
+
+               port {
+                       mipi_in_panel: endpoint {
+                               remote-endpoint = <&mipi_out_panel>;
+                       };
+               };
+       };
+};
+
+&green_led {
+       default-state = "on";
+       function = LED_FUNCTION_POWER;
+};
+
+&i2c0 {
+       vdd_cpu: regulator@40 {
+               compatible = "fcs,fan53555";
+               reg = <0x40>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <712500>;
+               regulator-max-microvolt = <1390000>;
+               regulator-name = "vdd_cpu";
+               regulator-ramp-delay = <2300>;
+               vin-supply = <&vcc_sys>;
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+};
+
+&leds {
+       amber_led: led-2 {
+               color = <LED_COLOR_ID_AMBER>;
+               function = LED_FUNCTION_CHARGING;
+               max-brightness = <255>;
+               pwms = <&pwm0 0 25000 0>;
+       };
+};
+
+&pwm0 {
+       pinctrl-0 = <&pwm0m1_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&red_led {
+       default-state = "off";
+       function = LED_FUNCTION_STATUS;
+};
index 0ac64f043b807fdada61a431d6e37599b04ef434..1f567a14ac84e00b321a37459fba78b3fc2a8863 100644 (file)
                };
        };
 };
+
+&i2c0 {
+       vdd_cpu: regulator@1c {
+               compatible = "tcs,tcs4525";
+               reg = <0x1c>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <712500>;
+               regulator-max-microvolt = <1390000>;
+               regulator-name = "vdd_cpu";
+               regulator-ramp-delay = <2300>;
+               vin-supply = <&vcc_sys>;
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+};
index ba32d0793dca2224a7dc966c30f20cce64ddf7f3..bc9933d9e2626cce2f511c051ab8295ad0c65372 100644 (file)
                };
        };
 };
+
+&i2c0 {
+       vdd_cpu: regulator@1c {
+               compatible = "tcs,tcs4525";
+               reg = <0x1c>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <712500>;
+               regulator-max-microvolt = <1390000>;
+               regulator-name = "vdd_cpu";
+               regulator-ramp-delay = <2300>;
+               vin-supply = <&vcc_sys>;
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+};
index 0fa8f06f94cd90d638581710f67901e42a654bef..3ab751a01cb209023cfacff7d870236e3c828007 100644 (file)
                        rockchip,sleep-filter-current-microamp = <100000>;
                };
        };
-
-       vdd_cpu: regulator@1c {
-               compatible = "tcs,tcs4525";
-               reg = <0x1c>;
-               fcs,suspend-voltage-selector = <1>;
-               regulator-always-on;
-               regulator-boot-on;
-               regulator-min-microvolt = <712500>;
-               regulator-max-microvolt = <1390000>;
-               regulator-name = "vdd_cpu";
-               regulator-ramp-delay = <2300>;
-               vin-supply = <&vcc_sys>;
-               regulator-state-mem {
-                       regulator-off-in-suspend;
-               };
-       };
 };
 
 &i2c5 {
        uart-has-rtscts;
        status = "okay";
 
-       bluetooth {
+       bluetooth: bluetooth {
                compatible = "realtek,rtl8821cs-bt", "realtek,rtl8723bs-bt";
                device-wake-gpios = <&gpio4 4 GPIO_ACTIVE_HIGH>;
                enable-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
index f9127ddfbb7dfdaa9b2bfd6040ef9ed2ab1986b3..7b5f3904ef6104754d8d2bc6c96ab668e5b3b230 100644 (file)
@@ -13,7 +13,7 @@
 
 / {
        model = "Bananapi-R2 Pro (RK3568) DDR4 Board";
-       compatible = "rockchip,rk3568-bpi-r2pro", "rockchip,rk3568";
+       compatible = "sinovoip,rk3568-bpi-r2pro", "rockchip,rk3568";
 
        aliases {
                ethernet0 = &gmac0;
diff --git a/arch/arm64/boot/dts/rockchip/rk3568-qnap-ts433.dts b/arch/arm64/boot/dts/rockchip/rk3568-qnap-ts433.dts
new file mode 100644 (file)
index 0000000..6a99816
--- /dev/null
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2021 Rockchip Electronics Co., Ltd.
+ * Copyright (c) 2024 Uwe Kleine-König
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "rk3568.dtsi"
+
+/ {
+       model = "Qnap TS-433-4G NAS System 4-Bay";
+       compatible = "qnap,ts433", "rockchip,rk3568";
+};
+
+&gmac0 {
+       assigned-clocks = <&cru SCLK_GMAC0_RX_TX>, <&cru SCLK_GMAC0>;
+       assigned-clock-parents = <&cru SCLK_GMAC0_RGMII_SPEED>, <&cru CLK_MAC0_2TOP>;
+       assigned-clock-rates = <0>, <125000000>;
+       clock_in_out = "output";
+       phy-handle = <&rgmii_phy0>;
+       phy-mode = "rgmii";
+       pinctrl-names = "default";
+       pinctrl-0 = <&gmac0_miim
+                    &gmac0_tx_bus2
+                    &gmac0_rx_bus2
+                    &gmac0_rgmii_clk
+                    &gmac0_rgmii_bus>;
+       rx_delay = <0x2f>;
+       tx_delay = <0x3c>;
+       status = "okay";
+};
+
+&i2c0 {
+       pmic@20 {
+               compatible = "rockchip,rk809";
+               reg = <0x20>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+       };
+};
+
+&i2c1 {
+       status = "okay";
+
+       rtc@51 {
+               compatible = "microcrystal,rv8263";
+               reg = <0x51>;
+               wakeup-source;
+       };
+};
+
+&mdio0 {
+       rgmii_phy0: ethernet-phy@0 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0x0>;
+       };
+};
+
+&pcie30phy {
+       status = "okay";
+};
+
+&pcie3x1 {
+       /* The downstream dts has: rockchip,bifurcation, XXX: find out what this is about */
+       reset-gpios = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
+&sdhci {
+       bus-width = <8>;
+       max-frequency = <200000000>;
+       non-removable;
+       status = "okay";
+};
+
+/*
+ * Pins available on CN3 connector at TTL voltage level (3V3).
+ * ,_  _.
+ * |1234|  1=TX 2=VCC
+ * `----'  3=RX 4=GND
+ */
+&uart2 {
+       status = "okay";
+};
index c19c0f1b3778fe79f68d3657cb2b6512f70913f2..92f96ec01385d9cbf8be0300ce7b77b8d8f13341 100644 (file)
                compatible = "rockchip,rk3568-vpu";
                reg = <0x0 0xfdea0000 0x0 0x800>;
                interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "vdpu";
                clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>;
                clock-names = "aclk", "hclk";
                iommus = <&vdpu_mmu>;
                dmas = <&dmac1 4>, <&dmac1 5>;
                dma-names = "tx", "rx";
                resets = <&cru SRST_M_I2S2_2CH>;
-               reset-names = "m";
+               reset-names = "tx-m";
                rockchip,grf = <&grf>;
                pinctrl-names = "default";
                pinctrl-0 = <&i2s2m0_sclktx
index d4c70835e0fe28639548ed4bf4579439a5f92308..a4946cdc3bb34ef7bc084f74ae0a4ac8424994df 100644 (file)
@@ -72,7 +72,7 @@
                vin-supply = <&vcc3v3_sys>;
        };
 
-       vcc5v0_usb30_host: vcc5v0-usb30-host-regulator {
+       vcc5v0_usb_host1: vcc5v0_usb_host2: vcc5v0-usb-host-regulator {
                compatible = "regulator-fixed";
                regulator-name = "vcc5v0_host";
                regulator-boot-on;
        status = "okay";
 };
 
+/* Standard pcie */
 &pcie3x2 {
        reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>;
        vpcie3v3-supply = <&vcc3v3_sys>;
 
 /* M.2 M-Key ssd */
 &pcie3x4 {
+       num-lanes = <2>;
        reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
        vpcie3v3-supply = <&vcc3v3_sys>;
        status = "okay";
 };
 
 &u2phy2_host {
-       phy-supply = <&vcc5v0_usb30_host>;
+       phy-supply = <&vcc5v0_usb_host1>;
        status = "okay";
 };
 
 &u2phy3_host {
-       phy-supply = <&vcc5v0_usb30_host>;
+       phy-supply = <&vcc5v0_usb_host2>;
        status = "okay";
 };
 
index 0b02f4d6e00331d4731e60251240748b5415b660..cce1c8e835877c4341d90f2fe80da7c57dde8d0c 100644 (file)
@@ -16,8 +16,8 @@
 
        aliases {
                mmc0 = &sdhci;
-               mmc1 = &sdio;
-               mmc2 = &sdmmc;
+               mmc1 = &sdmmc;
+               mmc2 = &sdio;
                serial2 = &uart2;
        };
 
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-common.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-common.dtsi
new file mode 100644 (file)
index 0000000..c0d4a15
--- /dev/null
@@ -0,0 +1,466 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2023 Edgeble AI Technologies Pvt. Ltd.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+       aliases {
+               mmc0 = &sdhci;
+       };
+
+       gpio-leds {
+               compatible = "gpio-leds";
+
+               led_user: led-0 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_HEARTBEAT;
+                       gpios = <&gpio0 RK_PC2 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&led_user_en>;
+               };
+       };
+
+       vcc12v_dcin: vcc12v-dcin-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc12v_dcin";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+       };
+
+       vcc5v0_sys: vcc5v0-sys-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_sys";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc12v_dcin>;
+       };
+
+       vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_1v1_nldo_s3";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1100000>;
+               regulator-max-microvolt = <1100000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+};
+
+&cpu_b0 {
+       cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b1 {
+       cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b2 {
+       cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_b3 {
+       cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_l0 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&i2c0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c0m2_xfer>;
+       status = "okay";
+
+       vdd_cpu_big0_s0: regulator@42 {
+               compatible = "rockchip,rk8602";
+               reg = <0x42>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_cpu_big0_s0";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <550000>;
+               regulator-max-microvolt = <1050000>;
+               regulator-ramp-delay = <2300>;
+               vin-supply = <&vcc5v0_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+
+       vdd_cpu_big1_s0: regulator@43 {
+               compatible = "rockchip,rk8603", "rockchip,rk8602";
+               reg = <0x43>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_cpu_big1_s0";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <550000>;
+               regulator-max-microvolt = <1050000>;
+               regulator-ramp-delay = <2300>;
+               vin-supply = <&vcc5v0_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+};
+
+&pinctrl {
+       leds {
+               led_user_en: led_user_en {
+                       rockchip,pins = <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+};
+
+&sdhci {
+       bus-width = <8>;
+       no-sdio;
+       no-sd;
+       non-removable;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       status = "okay";
+};
+
+&spi2 {
+       status = "okay";
+       assigned-clocks = <&cru CLK_SPI2>;
+       assigned-clock-rates = <200000000>;
+       num-cs = <1>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+
+       pmic@0 {
+               compatible = "rockchip,rk806";
+               spi-max-frequency = <1000000>;
+               reg = <0x0>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PA7 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+                           <&rk806_dvs2_null>, <&rk806_dvs3_null>;
+
+               vcc1-supply = <&vcc5v0_sys>;
+               vcc2-supply = <&vcc5v0_sys>;
+               vcc3-supply = <&vcc5v0_sys>;
+               vcc4-supply = <&vcc5v0_sys>;
+               vcc5-supply = <&vcc5v0_sys>;
+               vcc6-supply = <&vcc5v0_sys>;
+               vcc7-supply = <&vcc5v0_sys>;
+               vcc8-supply = <&vcc5v0_sys>;
+               vcc9-supply = <&vcc5v0_sys>;
+               vcc10-supply = <&vcc5v0_sys>;
+               vcc11-supply = <&vcc_2v0_pldo_s3>;
+               vcc12-supply = <&vcc5v0_sys>;
+               vcc13-supply = <&vcc_1v1_nldo_s3>;
+               vcc14-supply = <&vcc_1v1_nldo_s3>;
+               vcca-supply = <&vcc5v0_sys>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               rk806_dvs1_null: dvs1-null-pins {
+                       pins = "gpio_pwrctrl2";
+                       function = "pin_fun0";
+               };
+
+               rk806_dvs2_null: dvs2-null-pins {
+                       pins = "gpio_pwrctrl2";
+                       function = "pin_fun0";
+               };
+
+               rk806_dvs3_null: dvs3-null-pins {
+                       pins = "gpio_pwrctrl3";
+                       function = "pin_fun0";
+               };
+
+               regulators {
+                       vdd_gpu_s0: vdd_gpu_mem_s0: dcdc-reg1 {
+                               regulator-name = "vdd_gpu_s0";
+                               regulator-boot-on;
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <400>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_cpu_lit_s0: vdd_cpu_lit_mem_s0: dcdc-reg2 {
+                               regulator-name = "vdd_cpu_lit_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_log_s0: dcdc-reg3 {
+                               regulator-name = "vdd_log_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <675000>;
+                               regulator-max-microvolt = <750000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <750000>;
+                               };
+                       };
+
+                       vdd_vdenc_s0: vdd_vdenc_mem_s0: dcdc-reg4 {
+                               regulator-name = "vdd_vdenc_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_ddr_s0: dcdc-reg5 {
+                               regulator-name = "vdd_ddr_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <675000>;
+                               regulator-max-microvolt = <900000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <850000>;
+                               };
+                       };
+
+                       vdd2_ddr_s3: dcdc-reg6 {
+                               regulator-name = "vdd2_ddr_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc_2v0_pldo_s3: dcdc-reg7 {
+                               regulator-name = "vdd_2v0_pldo_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <2000000>;
+                               regulator-max-microvolt = <2000000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <2000000>;
+                               };
+                       };
+
+                       vcc_3v3_s3: dcdc-reg8 {
+                               regulator-name = "vcc_3v3_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3300000>;
+                               };
+                       };
+
+                       vddq_ddr_s0: dcdc-reg9 {
+                               regulator-name = "vddq_ddr_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_1v8_s3: dcdc-reg10 {
+                               regulator-name = "vcc_1v8_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       avcc_1v8_s0: pldo-reg1 {
+                               regulator-name = "avcc_1v8_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_1v8_s0: pldo-reg2 {
+                               regulator-name = "vcc_1v8_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       avdd_1v2_s0: pldo-reg3 {
+                               regulator-name = "avdd_1v2_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_3v3_s0: pldo-reg4 {
+                               regulator-name = "vcc_3v3_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vccio_sd_s0: pldo-reg5 {
+                               regulator-name = "vccio_sd_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       pldo6_s3: pldo-reg6 {
+                               regulator-name = "pldo6_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vdd_0v75_s3: nldo-reg1 {
+                               regulator-name = "vdd_0v75_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <750000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <750000>;
+                               };
+                       };
+
+                       vdd_ddr_pll_s0: nldo-reg2 {
+                               regulator-name = "vdd_ddr_pll_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <850000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <850000>;
+                               };
+                       };
+
+                       avdd_0v75_s0: nldo-reg3 {
+                               regulator-name = "avdd_0v75_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <750000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_0v85_s0: nldo-reg4 {
+                               regulator-name = "vdd_0v85_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <850000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_0v75_s0: nldo-reg5 {
+                               regulator-name = "vdd_0v75_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <750000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+               };
+       };
+};
index be6a4f4f90f68bb98decaf12070e5f8a9670b500..46d5e21d4d27a338c743f70b15f8d39e7a21dcfb 100644 (file)
@@ -6,18 +6,10 @@
 /dts-v1/;
 #include "rk3588.dtsi"
 #include "rk3588-edgeble-neu6a.dtsi"
+#include "rk3588-edgeble-neu6a-io.dtsi"
 
 / {
        model = "Edgeble Neu6A IO Board";
        compatible = "edgeble,neural-compute-module-6a-io",
                     "edgeble,neural-compute-module-6a", "rockchip,rk3588";
-
-       chosen {
-               stdout-path = "serial2:1500000n8";
-       };
-};
-
-&uart2 {
-       pinctrl-0 = <&uart2m0_xfer>;
-       status = "okay";
 };
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dtsi
new file mode 100644 (file)
index 0000000..963e880
--- /dev/null
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2023 Edgeble AI Technologies Pvt. Ltd.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       chosen {
+               stdout-path = "serial2:1500000n8";
+       };
+
+       vcc3v3_pcie2x1l0: vcc3v3-pcie2x1l0-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc3v3_pcie2x1l0";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               startup-delay-us = <5000>;
+               vin-supply = <&vcc_3v3_s3>;
+       };
+
+       vcc3v3_pcie3x2: vcc3v3-pcie3x2-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpios = <&gpio2 RK_PC4 GPIO_ACTIVE_HIGH>; /* PCIE_4G_PWEN */
+               pinctrl-names = "default";
+               pinctrl-0 = <&pcie3x2_vcc3v3_en>;
+               regulator-name = "vcc3v3_pcie3x2";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               startup-delay-us = <5000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vcc3v3_pcie3x4: vcc3v3-pcie3x4-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpios = <&gpio2 RK_PC5 GPIO_ACTIVE_HIGH>; /* PCIE30x4_PWREN_H */
+               pinctrl-names = "default";
+               pinctrl-0 = <&pcie3x4_vcc3v3_en>;
+               regulator-name = "vcc3v3_pcie3x4";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               startup-delay-us = <5000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vcc5v0_host: vcc5v0-host-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio3 RK_PC7 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vcc5v0_host_en>;
+               regulator-name = "vcc5v0_host";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-boot-on;
+               regulator-always-on;
+               vin-supply = <&vcc5v0_sys>;
+       };
+};
+
+&combphy0_ps {
+       status = "okay";
+};
+
+&combphy1_ps {
+       status = "okay";
+};
+
+&i2c6 {
+       status = "okay";
+
+       hym8563: rtc@51 {
+               compatible = "haoyu,hym8563";
+               reg = <0x51>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
+               #clock-cells = <0>;
+               clock-output-names = "hym8563";
+               pinctrl-names = "default";
+               pinctrl-0 = <&hym8563_int>;
+               wakeup-source;
+       };
+};
+
+/* ETH */
+&pcie2x1l0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie2_0_rst>;
+       reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>; /* PCIE20_1_PERST_L */
+       vpcie3v3-supply = <&vcc3v3_pcie2x1l0>;
+       status = "okay";
+};
+
+&pcie30phy {
+       status = "okay";
+};
+
+/* B-Key and E-Key */
+&pcie3x2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie3x2_rst>;
+       reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>; /* PCIE30X4_PERSTn_M1_L */
+       vpcie3v3-supply = <&vcc3v3_pcie3x2>;
+       status = "okay";
+};
+
+/* M-Key */
+&pcie3x4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie3x4_rst>;
+       reset-gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_HIGH>; /* PCIE30X2_PERSTn_M1_L */
+       vpcie3v3-supply = <&vcc3v3_pcie3x4>;
+       status = "okay";
+};
+
+&pinctrl {
+       pcie2 {
+               pcie2_0_rst: pcie2-0-rst {
+                       rockchip,pins = <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       pcie3 {
+               pcie3x2_rst: pcie3x2-rst {
+                       rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               pcie3x2_vcc3v3_en: pcie3x2-vcc3v3-en {
+                       rockchip,pins = <2 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               pcie3x4_rst: pcie3x4-rst {
+                       rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               pcie3x4_vcc3v3_en: pcie3x4-vcc3v3-en {
+                       rockchip,pins = <2 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       hym8563 {
+               hym8563_int: hym8563-int {
+                       rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       usb {
+               vcc5v0_host_en: vcc5v0-host-en {
+                       rockchip,pins = <3 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+};
+
+/* FAN */
+&pwm2 {
+       pinctrl-0 = <&pwm2m1_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&sata0 {
+       status = "okay";
+};
+
+&sdmmc {
+       bus-width = <4>;
+       cap-mmc-highspeed;
+       cap-sd-highspeed;
+       disable-wp;
+       no-sdio;
+       no-mmc;
+       sd-uhs-sdr104;
+       vmmc-supply = <&vcc_3v3_s3>;
+       vqmmc-supply = <&vccio_sd_s0>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-0 = <&uart2m0_xfer>;
+       status = "okay";
+};
+
+/* RS232 */
+&uart6 {
+       pinctrl-0 = <&uart6m0_xfer>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+/* RS485 */
+&uart7 {
+       pinctrl-0 = <&uart7m2_xfer>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&u2phy2 {
+       status = "okay";
+};
+
+&u2phy2_host {
+       /* connected to USB hub, which is powered by vcc5v0_sys */
+       phy-supply = <&vcc5v0_sys>;
+       status = "okay";
+};
+
+&u2phy3 {
+       status = "okay";
+};
+
+&u2phy3_host {
+       phy-supply = <&vcc5v0_host>;
+       status = "okay";
+};
+
+&usb_host0_ehci {
+       status = "okay";
+};
+
+&usb_host0_ohci {
+       status = "okay";
+};
+
+&usb_host1_ehci {
+       status = "okay";
+};
+
+&usb_host1_ohci {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-wifi.dtso b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-wifi.dtso
new file mode 100644 (file)
index 0000000..e9a3855
--- /dev/null
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2022 Edgeble AI Technologies Pvt. Ltd.
+ *
+ * DT-overlay for Edgeble On-SoM WiFi6/BT M.2 1216 modules,
+ * - AW-XM548NF
+ * - Intel 8260D2W
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+
+&{/} {
+       vcc3v3_pcie2x1l1: vcc3v3-pcie2x1l1-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpios = <&gpio0 RK_PC4 GPIO_ACTIVE_HIGH>; /* WIFI_3V3_EN */
+               pinctrl-names = "default";
+               pinctrl-0 = <&pcie2_1_vcc3v3_en>;
+               regulator-name = "vcc3v3_pcie2x1l1";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               startup-delay-us = <50000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+};
+
+&combphy2_psu {
+       status = "okay";
+};
+
+/* WiFi6 */
+&pcie2x1l1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie2_1_rst>;
+       reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; /* PCIE20_2_WIFI_PERSTn */
+       vpcie3v3-supply = <&vcc3v3_pcie2x1l1>;
+       status = "okay";
+};
+
+&pinctrl {
+       pcie2 {
+               pcie2_1_rst: pcie2-1-rst {
+                       rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               pcie2_1_vcc3v3_en: pcie2-1-vcc-en {
+                       rockchip,pins = <0 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+};
index 727580aaa105b29454e7cc165216f7b448deddb8..4c76a00b41ebf0a89244335b1249624d4c7520f3 100644 (file)
@@ -3,29 +3,8 @@
  * Copyright (c) 2022 Edgeble AI Technologies Pvt. Ltd.
  */
 
+#include "rk3588-edgeble-neu6a-common.dtsi"
+
 / {
        compatible = "edgeble,neural-compute-module-6a", "rockchip,rk3588";
-
-       aliases {
-               mmc0 = &sdhci;
-       };
-
-       vcc12v_dcin: vcc12v-dcin-regulator {
-               compatible = "regulator-fixed";
-               regulator-name = "vcc12v_dcin";
-               regulator-always-on;
-               regulator-boot-on;
-               regulator-min-microvolt = <12000000>;
-               regulator-max-microvolt = <12000000>;
-       };
-};
-
-&sdhci {
-       bus-width = <8>;
-       no-sdio;
-       no-sd;
-       non-removable;
-       mmc-hs400-1_8v;
-       mmc-hs400-enhanced-strobe;
-       status = "okay";
 };
index 070baeb63431f960345f5622e1a1ee3a3df1b1ca..0d6f1be69ac88458feb1509c030d936c4a0d04fe 100644 (file)
@@ -6,84 +6,10 @@
 /dts-v1/;
 #include "rk3588j.dtsi"
 #include "rk3588-edgeble-neu6b.dtsi"
+#include "rk3588-edgeble-neu6a-io.dtsi"
 
 / {
        model = "Edgeble Neu6B IO Board";
        compatible = "edgeble,neural-compute-module-6a-io",
                     "edgeble,neural-compute-module-6b", "rockchip,rk3588";
-
-       chosen {
-               stdout-path = "serial2:1500000n8";
-       };
-};
-
-&combphy0_ps {
-       status = "okay";
-};
-
-&i2c6 {
-       status = "okay";
-
-       hym8563: rtc@51 {
-               compatible = "haoyu,hym8563";
-               reg = <0x51>;
-               interrupt-parent = <&gpio0>;
-               interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
-               #clock-cells = <0>;
-               clock-output-names = "hym8563";
-               pinctrl-names = "default";
-               pinctrl-0 = <&hym8563_int>;
-               wakeup-source;
-       };
-};
-
-&pinctrl {
-       hym8563 {
-               hym8563_int: hym8563-int {
-                       rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
-               };
-       };
-};
-
-/* FAN */
-&pwm2 {
-       pinctrl-0 = <&pwm2m1_pins>;
-       pinctrl-names = "default";
-       status = "okay";
-};
-
-&sata0 {
-       status = "okay";
-};
-
-&sdmmc {
-       bus-width = <4>;
-       cap-mmc-highspeed;
-       cap-sd-highspeed;
-       disable-wp;
-       no-sdio;
-       no-mmc;
-       sd-uhs-sdr104;
-       vmmc-supply = <&vcc_3v3_s3>;
-       vqmmc-supply = <&vccio_sd_s0>;
-       status = "okay";
-};
-
-&uart2 {
-       pinctrl-0 = <&uart2m0_xfer>;
-       status = "okay";
-};
-
-/* RS232 */
-&uart6 {
-       pinctrl-0 = <&uart6m0_xfer>;
-       pinctrl-names = "default";
-       status = "okay";
-};
-
-/* RS485 */
-&uart7 {
-       pinctrl-0 = <&uart7m2_xfer>;
-       pinctrl-names = "default";
-       status = "okay";
 };
index 017559bba37f7d5e2445fc418f08475051256316..c4634bc09fb442e45cbacaf8a6e36f241e5bf7ae 100644 (file)
@@ -3,387 +3,8 @@
  * Copyright (c) 2023 Edgeble AI Technologies Pvt. Ltd.
  */
 
+#include "rk3588-edgeble-neu6a-common.dtsi"
+
 / {
        compatible = "edgeble,neural-compute-module-6b", "rockchip,rk3588";
-
-       aliases {
-               mmc0 = &sdhci;
-       };
-
-       vcc12v_dcin: vcc12v-dcin-regulator {
-               compatible = "regulator-fixed";
-               regulator-name = "vcc12v_dcin";
-               regulator-always-on;
-               regulator-boot-on;
-               regulator-min-microvolt = <12000000>;
-               regulator-max-microvolt = <12000000>;
-       };
-
-       vcc5v0_sys: vcc5v0-sys-regulator {
-               compatible = "regulator-fixed";
-               regulator-name = "vcc5v0_sys";
-               regulator-always-on;
-               regulator-boot-on;
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-               vin-supply = <&vcc12v_dcin>;
-       };
-
-       vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator {
-               compatible = "regulator-fixed";
-               regulator-name = "vcc_1v1_nldo_s3";
-               regulator-always-on;
-               regulator-boot-on;
-               regulator-min-microvolt = <1100000>;
-               regulator-max-microvolt = <1100000>;
-               vin-supply = <&vcc5v0_sys>;
-       };
-};
-
-&cpu_l0 {
-       cpu-supply = <&vdd_cpu_lit_s0>;
-};
-
-&cpu_l1 {
-       cpu-supply = <&vdd_cpu_lit_s0>;
-};
-
-&cpu_l2 {
-       cpu-supply = <&vdd_cpu_lit_s0>;
-};
-
-&cpu_l3 {
-       cpu-supply = <&vdd_cpu_lit_s0>;
-};
-
-&sdhci {
-       bus-width = <8>;
-       no-sdio;
-       no-sd;
-       non-removable;
-       mmc-hs400-1_8v;
-       mmc-hs400-enhanced-strobe;
-       status = "okay";
-};
-
-&spi2 {
-       status = "okay";
-       assigned-clocks = <&cru CLK_SPI2>;
-       assigned-clock-rates = <200000000>;
-       num-cs = <1>;
-       pinctrl-names = "default";
-       pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
-
-       pmic@0 {
-               compatible = "rockchip,rk806";
-               spi-max-frequency = <1000000>;
-               reg = <0x0>;
-               interrupt-parent = <&gpio0>;
-               interrupts = <RK_PA7 IRQ_TYPE_LEVEL_LOW>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
-                           <&rk806_dvs2_null>, <&rk806_dvs3_null>;
-
-               vcc1-supply = <&vcc5v0_sys>;
-               vcc2-supply = <&vcc5v0_sys>;
-               vcc3-supply = <&vcc5v0_sys>;
-               vcc4-supply = <&vcc5v0_sys>;
-               vcc5-supply = <&vcc5v0_sys>;
-               vcc6-supply = <&vcc5v0_sys>;
-               vcc7-supply = <&vcc5v0_sys>;
-               vcc8-supply = <&vcc5v0_sys>;
-               vcc9-supply = <&vcc5v0_sys>;
-               vcc10-supply = <&vcc5v0_sys>;
-               vcc11-supply = <&vcc_2v0_pldo_s3>;
-               vcc12-supply = <&vcc5v0_sys>;
-               vcc13-supply = <&vcc_1v1_nldo_s3>;
-               vcc14-supply = <&vcc_1v1_nldo_s3>;
-               vcca-supply = <&vcc5v0_sys>;
-
-               gpio-controller;
-               #gpio-cells = <2>;
-
-               rk806_dvs1_null: dvs1-null-pins {
-                       pins = "gpio_pwrctrl2";
-                       function = "pin_fun0";
-               };
-
-               rk806_dvs2_null: dvs2-null-pins {
-                       pins = "gpio_pwrctrl2";
-                       function = "pin_fun0";
-               };
-
-               rk806_dvs3_null: dvs3-null-pins {
-                       pins = "gpio_pwrctrl3";
-                       function = "pin_fun0";
-               };
-
-               regulators {
-                       vdd_gpu_s0: vdd_gpu_mem_s0: dcdc-reg1 {
-                               regulator-name = "vdd_gpu_s0";
-                               regulator-boot-on;
-                               regulator-min-microvolt = <550000>;
-                               regulator-max-microvolt = <950000>;
-                               regulator-ramp-delay = <12500>;
-                               regulator-enable-ramp-delay = <400>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vdd_cpu_lit_s0: vdd_cpu_lit_mem_s0: dcdc-reg2 {
-                               regulator-name = "vdd_cpu_lit_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <550000>;
-                               regulator-max-microvolt = <950000>;
-                               regulator-ramp-delay = <12500>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vdd_log_s0: dcdc-reg3 {
-                               regulator-name = "vdd_log_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <675000>;
-                               regulator-max-microvolt = <750000>;
-                               regulator-ramp-delay = <12500>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                                       regulator-suspend-microvolt = <750000>;
-                               };
-                       };
-
-                       vdd_vdenc_s0: vdd_vdenc_mem_s0: dcdc-reg4 {
-                               regulator-name = "vdd_vdenc_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <550000>;
-                               regulator-max-microvolt = <950000>;
-                               regulator-init-microvolt = <750000>;
-                               regulator-ramp-delay = <12500>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vdd_ddr_s0: dcdc-reg5 {
-                               regulator-name = "vdd_ddr_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <675000>;
-                               regulator-max-microvolt = <900000>;
-                               regulator-ramp-delay = <12500>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                                       regulator-suspend-microvolt = <850000>;
-                               };
-                       };
-
-                       vdd2_ddr_s3: dcdc-reg6 {
-                               regulator-name = "vdd2_ddr_s3";
-                               regulator-always-on;
-                               regulator-boot-on;
-
-                               regulator-state-mem {
-                                       regulator-on-in-suspend;
-                               };
-                       };
-
-                       vcc_2v0_pldo_s3: dcdc-reg7 {
-                               regulator-name = "vdd_2v0_pldo_s3";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <2000000>;
-                               regulator-max-microvolt = <2000000>;
-                               regulator-ramp-delay = <12500>;
-
-                               regulator-state-mem {
-                                       regulator-on-in-suspend;
-                                       regulator-suspend-microvolt = <2000000>;
-                               };
-                       };
-
-                       vcc_3v3_s3: dcdc-reg8 {
-                               regulator-name = "vcc_3v3_s3";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <3300000>;
-                               regulator-max-microvolt = <3300000>;
-
-                               regulator-state-mem {
-                                       regulator-on-in-suspend;
-                                       regulator-suspend-microvolt = <3300000>;
-                               };
-                       };
-
-                       vddq_ddr_s0: dcdc-reg9 {
-                               regulator-name = "vddq_ddr_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vcc_1v8_s3: dcdc-reg10 {
-                               regulator-name = "vcc_1v8_s3";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-
-                               regulator-state-mem {
-                                       regulator-on-in-suspend;
-                                       regulator-suspend-microvolt = <1800000>;
-                               };
-                       };
-
-                       avcc_1v8_s0: pldo-reg1 {
-                               regulator-name = "avcc_1v8_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vcc_1v8_s0: pldo-reg2 {
-                               regulator-name = "vcc_1v8_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                                       regulator-suspend-microvolt = <1800000>;
-                               };
-                       };
-
-                       avdd_1v2_s0: pldo-reg3 {
-                               regulator-name = "avdd_1v2_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <1200000>;
-                               regulator-max-microvolt = <1200000>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vcc_3v3_s0: pldo-reg4 {
-                               regulator-name = "vcc_3v3_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <3300000>;
-                               regulator-max-microvolt = <3300000>;
-                               regulator-ramp-delay = <12500>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vccio_sd_s0: pldo-reg5 {
-                               regulator-name = "vccio_sd_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <3300000>;
-                               regulator-ramp-delay = <12500>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       pldo6_s3: pldo-reg6 {
-                               regulator-name = "pldo6_s3";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-
-                               regulator-state-mem {
-                                       regulator-on-in-suspend;
-                                       regulator-suspend-microvolt = <1800000>;
-                               };
-                       };
-
-                       vdd_0v75_s3: nldo-reg1 {
-                               regulator-name = "vdd_0v75_s3";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <750000>;
-                               regulator-max-microvolt = <750000>;
-
-                               regulator-state-mem {
-                                       regulator-on-in-suspend;
-                                       regulator-suspend-microvolt = <750000>;
-                               };
-                       };
-
-                       vdd_ddr_pll_s0: nldo-reg2 {
-                               regulator-name = "vdd_ddr_pll_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <850000>;
-                               regulator-max-microvolt = <850000>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                                       regulator-suspend-microvolt = <850000>;
-                               };
-                       };
-
-                       avdd_0v75_s0: nldo-reg3 {
-                               regulator-name = "avdd_0v75_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <750000>;
-                               regulator-max-microvolt = <750000>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vdd_0v85_s0: nldo-reg4 {
-                               regulator-name = "vdd_0v85_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <850000>;
-                               regulator-max-microvolt = <850000>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-
-                       vdd_0v75_s0: nldo-reg5 {
-                               regulator-name = "vdd_0v75_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
-                               regulator-min-microvolt = <750000>;
-                               regulator-max-microvolt = <750000>;
-
-                               regulator-state-mem {
-                                       regulator-off-in-suspend;
-                               };
-                       };
-               };
-       };
 };
index ac7c677b0fb9c3d6af9e7b8bcd399d9d24ef0b84..de30c2632b8e5fc8cc6d89272269353676b1e1a3 100644 (file)
                            <&rk806_dvs2_null>, <&rk806_dvs3_null>;
                pinctrl-names = "default";
                spi-max-frequency = <1000000>;
+               system-power-controller;
 
                vcc1-supply = <&vcc5v0_sys>;
                vcc2-supply = <&vcc5v0_sys>;
index 4ce70fb75a307ba34fdd8ad5a72d56401de0118e..39d65002add1e11e81bb0d660fd7f5ff90e4cdf7 100644 (file)
@@ -62,7 +62,6 @@
                compatible = "gpio-leds";
                pinctrl-names = "default";
                pinctrl-0 = <&led1_pin>;
-               status = "okay";
 
                /* LED1 on PCB */
                led-1 {
index d7722772ecd8a0afb7e844ffb168fa9a7462cb03..ad8e36a339dc45c8cca0eea36d8e5b1822e46138 100644 (file)
                regulator-max-microvolt = <3300000>;
                vin-supply = <&vcc5v0_sys>;
        };
+
+       vcc3v3_sd_s0: vcc3v3-sd-s0-regulator {
+               compatible = "regulator-fixed";
+               enable-active-low;
+               gpio = <&gpio4 RK_PA5 GPIO_ACTIVE_LOW>;
+               regulator-boot-on;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "vcc3v3_sd_s0";
+               vin-supply = <&vcc_3v3_s3>;
+       };
+
+       vdd_4g_3v3: vdd-4g-3v3-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pin_4g_lte_pwren>;
+               regulator-name = "vdd_4g_3v3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
 };
 
 &combphy0_ps {
        cpu-supply = <&vdd_cpu_lit_s0>;
 };
 
-&cpu_b0{
+&cpu_b0 {
        cpu-supply = <&vdd_cpu_big0_s0>;
 };
 
-&cpu_b1{
+&cpu_b1 {
        cpu-supply = <&vdd_cpu_big0_s0>;
 };
 
-&cpu_b2{
+&cpu_b2 {
        cpu-supply = <&vdd_cpu_big1_s0>;
 };
 
-&cpu_b3{
+&cpu_b3 {
        cpu-supply = <&vdd_cpu_big1_s0>;
 };
 
        };
 
        usb {
+               pin_4g_lte_pwren: 4g-lte-pwren {
+                       rockchip,pins = <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
                typec5v_pwren: typec5v-pwren {
                        rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        bus-width = <4>;
        cap-mmc-highspeed;
        cap-sd-highspeed;
+       cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
        disable-wp;
        no-mmc;
        no-sdio;
        sd-uhs-sdr104;
-       vmmc-supply = <&vcc_3v3_s3>;
+       vmmc-supply = <&vcc3v3_sd_s0>;
        vqmmc-supply = <&vccio_sd_s0>;
        status = "okay";
 };
 };
 
 &u2phy2_host {
+       phy-supply = <&vdd_4g_3v3>;
        status = "okay";
 };
 
index 3e660ff6cd5ff3d966356667e5b7db80a298da3b..1b606ea5b6cf2b32c72eab2bdac812b4a94d310c 100644 (file)
 &sdmmc {
        bus-width = <4>;
        cap-sd-highspeed;
-       cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
        disable-wp;
        max-frequency = <150000000>;
        no-sdio;
index 87a0abf95f7d4f9ac0846c61a7ad18ba6cdabea1..67414d72e2b6ef9308aa357c606f64d652c54075 100644 (file)
 &sdmmc {
        bus-width = <4>;
        cap-sd-highspeed;
-       cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
        disable-wp;
        max-frequency = <150000000>;
        no-sdio;
index a0e303c3a1dc6d839528188571cb53c2759535fa..1fe8b2a0ed75eeb3360fa82ceeb031be8e06e6b7 100644 (file)
                #cooling-cells = <2>;
        };
 
+       rfkill {
+               compatible = "rfkill-gpio";
+               label = "rfkill-pcie-wlan";
+               radio-type = "wlan";
+               shutdown-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
+       };
+
        vcc3v3_pcie2x1l0: vcc3v3-pcie2x1l0-regulator {
                compatible = "regulator-fixed";
                enable-active-high;
        bus-width = <4>;
        cap-mmc-highspeed;
        cap-sd-highspeed;
-       cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
        disable-wp;
        sd-uhs-sdr104;
        vmmc-supply = <&vcc_3v3_s3>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts
new file mode 100644 (file)
index 0000000..d672198
--- /dev/null
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2023 Theobroma Systems Design und Consulting GmbH
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include "rk3588-tiger.dtsi"
+
+/ {
+       model = "Theobroma Systems RK3588-Q7 SoM on Haikou devkit";
+       compatible = "tsd,rk3588-tiger-haikou", "tsd,rk3588-tiger", "rockchip,rk3588";
+
+       aliases {
+               ethernet0 = &gmac0;
+               mmc1 = &sdmmc;
+       };
+
+       chosen {
+               stdout-path = "serial2:115200n8";
+       };
+
+       dc_12v: dc-12v-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "dc_12v";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&haikou_keys_pin>;
+
+               button-batlow-n {
+                       label = "BATLOW#";
+                       linux,code = <KEY_BATTERY>;
+                       gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>;
+               };
+
+               button-slp-btn-n {
+                       label = "SLP_BTN#";
+                       linux,code = <KEY_SLEEP>;
+                       gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_LOW>;
+               };
+
+               button-wake-n {
+                       label = "WAKE#";
+                       linux,code = <KEY_WAKEUP>;
+                       gpios = <&gpio3 RK_PC6 GPIO_ACTIVE_LOW>;
+                       wakeup-source;
+               };
+
+               switch-lid-btn-n {
+                       label = "LID_BTN#";
+                       linux,code = <SW_LID>;
+                       linux,input-type = <EV_SW>;
+                       gpios = <&gpio3 RK_PD5 GPIO_ACTIVE_LOW>;
+               };
+       };
+
+       i2s3-sound {
+               compatible = "simple-audio-card";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,name = "Haikou,I2S-codec";
+               simple-audio-card,mclk-fs = <512>;
+               simple-audio-card,frame-master = <&sgtl5000_codec>;
+               simple-audio-card,bitclock-master = <&sgtl5000_codec>;
+
+               sgtl5000_codec: simple-audio-card,codec {
+                       sound-dai = <&sgtl5000>;
+               };
+
+               simple-audio-card,cpu {
+                       sound-dai = <&i2s3_2ch>;
+               };
+       };
+
+       sgtl5000_clk: sgtl5000-oscillator  {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <24576000>;
+       };
+
+       vcc3v3_baseboard: vcc3v3-baseboard-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc3v3_baseboard";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&dc_12v>;
+       };
+
+       vcc3v3_low_noise: vcc3v3-low-noise-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc3v3_low_noise";
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vcc5v0_usb>;
+       };
+
+       vcc5v0_baseboard: vcc5v0-baseboard-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_baseboard";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&dc_12v>;
+       };
+
+       vcc5v0_usb: vcc5v0-usb-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_usb";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&dc_12v>;
+       };
+
+       vddd_audio_1v6: vddd-audio-1v6-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vddd_audio_1v6";
+               regulator-boot-on;
+               regulator-min-microvolt = <1600000>;
+               regulator-max-microvolt = <1600000>;
+               vin-supply = <&vcc5v0_usb>;
+       };
+};
+
+&combphy2_psu {
+       status = "okay";
+};
+
+&gmac0 {
+       status = "okay";
+};
+
+&i2c1 {
+       status = "okay";
+
+       eeprom@50 {
+               reg = <0x50>;
+               compatible = "atmel,24c01";
+               pagesize = <8>;
+               size = <128>;
+               vcc-supply = <&vcc3v3_baseboard>;
+       };
+};
+
+&i2c5 {
+       clock-frequency = <400000>;
+       status = "okay";
+
+       sgtl5000: codec@a {
+               compatible = "fsl,sgtl5000";
+               reg = <0x0a>;
+               clocks = <&sgtl5000_clk>;
+               #sound-dai-cells = <0>;
+               VDDA-supply = <&vcc3v3_low_noise>;
+               VDDIO-supply = <&vcc3v3_baseboard>;
+               VDDD-supply = <&vddd_audio_1v6>;
+       };
+};
+
+&i2c8 {
+       status = "okay";
+};
+
+&i2s3_2ch {
+       status = "okay";
+};
+
+&pcie30phy {
+       status = "okay";
+};
+
+&pcie3x4 {
+       vpcie3v3-supply = <&vcc3v3_baseboard>;
+       status = "okay";
+};
+
+&pinctrl {
+       haikou {
+               haikou_keys_pin: haikou-keys-pin {
+                       rockchip,pins =
+                               /* BATLOW# */
+                               <3 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>,
+                               /* SLP_BTN# */
+                               <4 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>,
+                               /* WAKE# */
+                               <3 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>,
+                               /* LID_BTN */
+                               <3 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+};
+
+&sdmmc {
+       /* while the same pin, sdmmc_det does not detect card changes */
+       cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
+       disable-wp;
+       pinctrl-0 = <&sdmmc_bus4 &sdmmc_cmd &sdmmc_clk>;
+       sd-uhs-sdr12;
+       sd-uhs-sdr25;
+       sd-uhs-sdr50;
+       sd-uhs-sdr104;
+       vmmc-supply = <&vcc3v3_baseboard>;
+       status = "okay";
+};
+
+&u2phy2 {
+       status = "okay";
+};
+
+&u2phy2_host {
+       status = "okay";
+};
+
+&u2phy3 {
+       status = "okay";
+};
+
+&u2phy3_host {
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-0 = <&uart2m2_xfer>;
+       status = "okay";
+};
+
+&uart5 {
+       rts-gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
+/* host0 on Q7_USB_P2, lower usb3 port */
+&usb_host0_ehci {
+       status = "okay";
+};
+
+/* host0 on Q7_USB_P2, lower usb3 port */
+&usb_host0_ohci {
+       status = "okay";
+};
+
+/* host1 on Q7_USB_P3, usb2 port */
+&usb_host1_ehci {
+       status = "okay";
+};
+
+/* host1 on Q7_USB_P3, usb2 port */
+&usb_host1_ohci {
+       status = "okay";
+};
+
+/* host2 on Q7_USB_P2, lower usb3 port */
+&usb_host2_xhci {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-tiger.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-tiger.dtsi
new file mode 100644 (file)
index 0000000..1eb2543
--- /dev/null
@@ -0,0 +1,690 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2023 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rk3588.dtsi"
+
+/ {
+       compatible = "tsd,rk3588-tiger", "rockchip,rk3588";
+
+       aliases {
+               mmc0 = &sdhci;
+               rtc0 = &rtc_twi;
+       };
+
+       emmc_pwrseq: emmc-pwrseq {
+               compatible = "mmc-pwrseq-emmc";
+               pinctrl-0 = <&emmc_reset>;
+               pinctrl-names = "default";
+               reset-gpios = <&gpio2 RK_PA3 GPIO_ACTIVE_HIGH>;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&module_led_pin>;
+
+               /* Named LED1 on the board */
+               led-1 {
+                       gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_HIGH>;
+                       function = LED_FUNCTION_HEARTBEAT;
+                       linux,default-trigger = "heartbeat";
+                       color = <LED_COLOR_ID_AMBER>;
+               };
+       };
+
+       /*
+        * 100MHz reference clock for PCIe peripherals from PI6C557-05BLE
+        * clock generator.
+        * The clock output is gated via the OE pin on the clock generator.
+        * This is modeled as a fixed-clock plus a gpio-gate-clock.
+        */
+       pcie_refclk_gen: pcie-refclk-gen-clock {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <1000000000>;
+       };
+
+       pcie_refclk: pcie-refclk-clock {
+               compatible = "gpio-gate-clock";
+               clocks = <&pcie_refclk_gen>;
+               #clock-cells = <0>;
+               enable-gpios = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>; /* PCIE30X4_CLKREQN_M1_L */
+       };
+
+       vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_1v1_nldo_s3";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1100000>;
+               regulator-max-microvolt = <1100000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vcc_1v2_s3: vcc-1v2-s3-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_1v2_s3";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <1200000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vcc5v0_sys: vcc5v0-sys-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_sys";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc5v0_baseboard>;
+       };
+};
+
+&cpu_b0 {
+       cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b1 {
+       cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b2 {
+       cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_b3 {
+       cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_l0 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&gmac0 {
+       clock_in_out = "output";
+       phy-handle = <&rgmii_phy>;
+       phy-mode = "rgmii";
+       phy-supply = <&vcc_1v2_s3>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&gmac0_miim
+                    &gmac0_rx_bus2
+                    &gmac0_tx_bus2
+                    &gmac0_rgmii_clk
+                    &gmac0_rgmii_bus
+                    &eth0_pins
+                    &eth_reset>;
+       tx_delay = <0x10>;
+       rx_delay = <0x10>;
+       snps,reset-gpio = <&gpio4 RK_PC3 GPIO_ACTIVE_LOW>;
+       snps,reset-active-low;
+       snps,reset-delays-us = <0 10000 100000>;
+};
+
+&i2c1 {
+       pinctrl-0 = <&i2c1m0_xfer>;
+};
+
+&i2c1m0_xfer {
+       rockchip,pins =
+               /* i2c1_scl_m0 */
+               <0 RK_PB5 9 &pcfg_pull_none_drv_level_0>,
+               /* i2c1_sda_m0 */
+               <0 RK_PB6 9 &pcfg_pull_none_drv_level_0>;
+};
+
+&i2c2 {
+       pinctrl-0 = <&i2c2m3_xfer>;
+       status = "okay";
+};
+
+&i2c2m3_xfer {
+       rockchip,pins =
+               /* i2c2_scl_m3 */
+               <1 RK_PC5 9 &pcfg_pull_none_drv_level_0>,
+               /* i2c2_sda_m3 */
+               <1 RK_PC4 9 &pcfg_pull_none_drv_level_0>;
+};
+
+&i2c3 {
+       pinctrl-0 = <&i2c3m0_xfer>;
+};
+
+&i2c4 {
+       pinctrl-0 = <&i2c4m4_xfer>;
+       status = "okay";
+
+       vdd_npu_s0: regulator@42 {
+               compatible = "rockchip,rk8602";
+               reg = <0x42>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_npu_s0";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <550000>;
+               regulator-max-microvolt = <950000>;
+               regulator-ramp-delay = <2300>;
+               vin-supply = <&vcc5v0_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+};
+
+&i2c5 {
+       pinctrl-0 = <&i2c5m1_xfer>;
+};
+
+&i2c5m1_xfer {
+       rockchip,pins =
+               /* i2c5_scl_m1 */
+               <4 RK_PB6 9 &pcfg_pull_none_drv_level_0>,
+               /* i2c5_sda_m1 */
+               <4 RK_PB7 9 &pcfg_pull_none_drv_level_0>;
+};
+
+&i2c6 {
+       /*
+        * Mule-ATtiny can handle up to Fast mode Plus (1MHz) on I2C bus,
+        * but SOC can handle only up to (400kHz).
+        */
+       clock-frequency = <400000>;
+       status = "okay";
+
+       fan@18 {
+               compatible = "ti,amc6821";
+               reg = <0x18>;
+       };
+
+       rtc_twi: rtc@6f {
+               compatible = "isil,isl1208";
+               reg = <0x6f>;
+       };
+};
+
+&i2c6m0_xfer {
+       rockchip,pins =
+               /* i2c6_scl_m0 */
+               <0 RK_PD0 9 &pcfg_pull_none_drv_level_0>,
+               /* i2c6_sda_m0 */
+               <0 RK_PC7 9 &pcfg_pull_none_drv_level_0>;
+};
+
+&i2c7 {
+       status = "okay";
+
+       vdd_cpu_big0_s0: regulator@42 {
+               compatible = "rockchip,rk8602";
+               reg = <0x42>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_cpu_big0_s0";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <550000>;
+               regulator-max-microvolt = <1050000>;
+               regulator-ramp-delay = <2300>;
+               vin-supply = <&vcc5v0_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+
+       vdd_cpu_big1_s0: regulator@43 {
+               compatible = "rockchip,rk8603", "rockchip,rk8602";
+               reg = <0x43>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_cpu_big1_s0";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <550000>;
+               regulator-max-microvolt = <1050000>;
+               regulator-ramp-delay = <2300>;
+               vin-supply = <&vcc5v0_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+};
+
+&i2c7m0_xfer {
+       rockchip,pins =
+               /* i2c7_scl_m0 */
+               <1 RK_PD0 9 &pcfg_pull_none_drv_level_0>,
+               /* i2c7_sda_m0 */
+               <1 RK_PD1 9 &pcfg_pull_none_drv_level_0>;
+};
+
+&i2c8 {
+       pinctrl-0 = <&i2c8m2_xfer>;
+};
+
+&mdio0 {
+       rgmii_phy: ethernet-phy@6 {
+               /* KSZ9031 or KSZ9131 */
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0x6>;
+               clocks = <&cru REFCLKO25M_ETH0_OUT>;
+       };
+};
+
+&pcie3x4 {
+       /*
+        * The board has a gpio-controlled "pcie_refclk" generator,
+        * so add it to the list of clocks.
+        */
+       clocks = <&cru ACLK_PCIE_4L_MSTR>, <&cru ACLK_PCIE_4L_SLV>,
+                <&cru ACLK_PCIE_4L_DBI>, <&cru PCLK_PCIE_4L>,
+                <&cru CLK_PCIE_AUX0>, <&cru CLK_PCIE4L_PIPE>,
+                <&pcie_refclk>;
+       clock-names = "aclk_mst", "aclk_slv",
+                     "aclk_dbi", "pclk",
+                     "aux", "pipe",
+                     "ref";
+       reset-gpios = <&gpio3 RK_PB6 GPIO_ACTIVE_HIGH>;
+};
+
+&pinctrl {
+       emmc {
+               emmc_reset: emmc-reset {
+                       rockchip,pins = <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       ethernet {
+               eth_reset: eth-reset {
+                       rockchip,pins = <4 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       leds {
+               module_led_pin: module-led-pin {
+                       rockchip,pins = <1 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+};
+
+&saradc {
+       vref-supply = <&vcc_1v8_s0>;
+       status = "okay";
+};
+
+&sdhci {
+       bus-width = <8>;
+       cap-mmc-highspeed;
+       mmc-ddr-1_8v;
+       mmc-hs200-1_8v;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       mmc-pwrseq = <&emmc_pwrseq>;
+       no-sdio;
+       no-sd;
+       non-removable;
+       pinctrl-names = "default";
+       pinctrl-0 = <&emmc_bus8 &emmc_cmd &emmc_clk &emmc_data_strobe>;
+       supports-cqe;
+       vmmc-supply = <&vcc_3v3_s3>;
+       vqmmc-supply = <&vcc_1v8_s3>;
+       status = "okay";
+};
+
+&sdmmc {
+       bus-width = <4>;
+       cap-sd-highspeed;
+       max-frequency = <150000000>;
+       vqmmc-supply = <&vccio_sd_s0>;
+};
+
+&spi0 {
+       pinctrl-0 = <&spi0m1_cs0 &spi0m1_cs1 &spi0m3_pins>;
+};
+
+&spi2 {
+       assigned-clocks = <&cru CLK_SPI2>;
+       assigned-clock-rates = <200000000>;
+       num-cs = <1>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+       status = "okay";
+
+       pmic@0 {
+               compatible = "rockchip,rk806";
+               reg = <0x0>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+                           <&rk806_dvs2_null>, <&rk806_dvs3_null>;
+               spi-max-frequency = <1000000>;
+               system-power-controller;
+               vcc1-supply = <&vcc5v0_sys>;
+               vcc2-supply = <&vcc5v0_sys>;
+               vcc3-supply = <&vcc5v0_sys>;
+               vcc4-supply = <&vcc5v0_sys>;
+               vcc5-supply = <&vcc5v0_sys>;
+               vcc6-supply = <&vcc5v0_sys>;
+               vcc7-supply = <&vcc5v0_sys>;
+               vcc8-supply = <&vcc5v0_sys>;
+               vcc9-supply = <&vcc5v0_sys>;
+               vcc10-supply = <&vcc5v0_sys>;
+               vcc11-supply = <&vcc_2v0_pldo_s3>;
+               vcc12-supply = <&vcc5v0_sys>;
+               vcc13-supply = <&vcc_1v1_nldo_s3>;
+               vcc14-supply = <&vcc_1v1_nldo_s3>;
+               vcca-supply = <&vcc5v0_sys>;
+
+               rk806_dvs1_null: dvs1-null-pins {
+                       pins = "gpio_pwrctrl2";
+                       function = "pin_fun0";
+               };
+
+               rk806_dvs2_null: dvs2-null-pins {
+                       pins = "gpio_pwrctrl2";
+                       function = "pin_fun0";
+               };
+
+               rk806_dvs3_null: dvs3-null-pins {
+                       pins = "gpio_pwrctrl3";
+                       function = "pin_fun0";
+               };
+
+               regulators {
+                       vdd_gpu_s0: dcdc-reg1 {
+                               regulator-boot-on;
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-name = "vdd_gpu_s0";
+                               regulator-enable-ramp-delay = <400>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_cpu_lit_s0: dcdc-reg2 {
+                               regulator-name = "vdd_cpu_lit_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_log_s0: dcdc-reg3 {
+                               regulator-name = "vdd_log_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <675000>;
+                               regulator-max-microvolt = <750000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <750000>;
+                               };
+                       };
+
+                       vdd_vdenc_s0: dcdc-reg4 {
+                               regulator-name = "vdd_vdenc_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_ddr_s0: dcdc-reg5 {
+                               regulator-name = "vdd_ddr_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <675000>;
+                               regulator-max-microvolt = <900000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <850000>;
+                               };
+                       };
+
+                       vdd2_ddr_s3: dcdc-reg6 {
+                               regulator-name = "vdd2_ddr_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc_2v0_pldo_s3: dcdc-reg7 {
+                               regulator-name = "vcc_2v0_pldo_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <2000000>;
+                               regulator-max-microvolt = <2000000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <2000000>;
+                               };
+                       };
+
+                       vcc_3v3_s3: dcdc-reg8 {
+                               regulator-name = "vcc_3v3_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3300000>;
+                               };
+                       };
+
+                       vddq_ddr_s0: dcdc-reg9 {
+                               regulator-name = "vddq_ddr_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_1v8_s3: dcdc-reg10 {
+                               regulator-name = "vcc_1v8_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcca_1v8_s0: pldo-reg1 {
+                               regulator-name = "vcca_1v8_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_1v8_s0: pldo-reg2 {
+                               regulator-name = "vcc_1v8_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vdda_1v2_s0: pldo-reg3 {
+                               regulator-name = "vdda_1v2_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcca_3v3_s0: pldo-reg4 {
+                               regulator-name = "vcca_3v3_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vccio_sd_s0: pldo-reg5 {
+                               regulator-name = "vccio_sd_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       pldo6_s3: pldo-reg6 {
+                               regulator-name = "pldo6_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vdd_0v75_s3: nldo-reg1 {
+                               regulator-name = "vdd_0v75_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <750000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <750000>;
+                               };
+                       };
+
+                       vdda_ddr_pll_s0: nldo-reg2 {
+                               regulator-name = "vdda_ddr_pll_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <850000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <850000>;
+                               };
+                       };
+
+                       vdda_0v75_s0: nldo-reg3 {
+                               regulator-name = "vdda_0v75_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <750000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdda_0v85_s0: nldo-reg4 {
+                               regulator-name = "vdda_0v85_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <850000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_0v75_s0: nldo-reg5 {
+                               regulator-name = "vdd_0v75_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <750000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+               };
+       };
+};
+
+&tsadc {
+       status = "okay";
+};
+
+/* Mule-ATtiny UPDI */
+&uart4 {
+       pinctrl-0 = <&uart4m2_xfer>;
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dts b/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dts
new file mode 100644 (file)
index 0000000..9090c5c
--- /dev/null
@@ -0,0 +1,688 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2024 Rockchip Electronics Co., Ltd.
+ *
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "rk3588.dtsi"
+
+/ {
+       model = "Rockchip Toybrick TB-RK3588X Board";
+       compatible = "rockchip,rk3588-toybrick-x0", "rockchip,rk3588";
+
+       aliases {
+               mmc0 = &sdhci;
+       };
+
+       chosen {
+               stdout-path = "serial2:1500000n8";
+       };
+
+       adc-keys {
+               compatible = "adc-keys";
+               io-channels = <&saradc 1>;
+               io-channel-names = "buttons";
+               keyup-threshold-microvolt = <1800000>;
+               poll-interval = <100>;
+
+               button-vol-up {
+                       label = "Volume Up";
+                       linux,code = <KEY_VOLUMEUP>;
+                       press-threshold-microvolt = <17000>;
+               };
+
+               button-vol-down {
+                       label = "Volume Down";
+                       linux,code = <KEY_VOLUMEDOWN>;
+                       press-threshold-microvolt = <417000>;
+               };
+
+               button-menu {
+                       label = "Menu";
+                       linux,code = <KEY_MENU>;
+                       press-threshold-microvolt = <890000>;
+               };
+
+               button-escape {
+                       label = "Escape";
+                       linux,code = <KEY_ESC>;
+                       press-threshold-microvolt = <1235000>;
+               };
+       };
+
+       backlight: backlight {
+               compatible = "pwm-backlight";
+               power-supply = <&vcc12v_dcin>;
+               pwms = <&pwm2 0 25000 0>;
+       };
+
+       pcie20_avdd0v85: pcie20-avdd0v85-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "pcie20_avdd0v85";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <850000>;
+               regulator-max-microvolt = <850000>;
+               vin-supply = <&vdd_0v85_s0>;
+       };
+
+       pcie20_avdd1v8: pcie20-avdd1v8-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "pcie20_avdd1v8";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&avcc_1v8_s0>;
+       };
+
+       pcie30_avdd0v75: pcie30-avdd0v75-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "pcie30_avdd0v75";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <750000>;
+               regulator-max-microvolt = <750000>;
+               vin-supply = <&avdd_0v75_s0>;
+       };
+
+       pcie30_avdd1v8: pcie30-avdd1v8-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "pcie30_avdd1v8";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&avcc_1v8_s0>;
+       };
+
+       vcc12v_dcin: vcc12v-dcin-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc12v_dcin";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+       };
+
+       vcc5v0_host: vcc5v0-host-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio4 RK_PB0 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vcc5v0_host_en>;
+               regulator-name = "vcc5v0_host";
+               regulator-boot-on;
+               regulator-always-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc5v0_usb>;
+       };
+
+       vcc5v0_sys: vcc5v0-sys-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_sys";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc12v_dcin>;
+       };
+
+       vcc5v0_usbdcin: vcc5v0-usbdcin-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_usbdcin";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc12v_dcin>;
+       };
+
+       vcc5v0_usb: vcc5v0-usb-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_usb";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc5v0_usbdcin>;
+       };
+
+       vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_1v1_nldo_s3";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1100000>;
+               regulator-max-microvolt = <1100000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+};
+
+&combphy0_ps {
+       status = "okay";
+};
+
+&combphy2_psu {
+       status = "okay";
+};
+
+&cpu_b0 {
+       cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b1 {
+       cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b2 {
+       cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_b3 {
+       cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_l0 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&gmac0 {
+       clock_in_out = "output";
+       phy-handle = <&rgmii_phy>;
+       phy-mode = "rgmii-rxid";
+       pinctrl-0 = <&gmac0_miim
+                    &gmac0_tx_bus2
+                    &gmac0_rx_bus2
+                    &gmac0_rgmii_clk
+                    &gmac0_rgmii_bus>;
+       pinctrl-names = "default";
+       rx_delay = <0x00>;
+       tx_delay = <0x43>;
+       status = "okay";
+};
+
+&i2c0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c0m2_xfer>;
+       status = "okay";
+
+       vdd_cpu_big0_s0: regulator@42 {
+               compatible = "rockchip,rk8602";
+               reg = <0x42>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_cpu_big0_s0";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <550000>;
+               regulator-max-microvolt = <1050000>;
+               regulator-ramp-delay = <2300>;
+               vin-supply = <&vcc5v0_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+
+       vdd_cpu_big1_s0: regulator@43 {
+               compatible = "rockchip,rk8603", "rockchip,rk8602";
+               reg = <0x43>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_cpu_big1_s0";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <550000>;
+               regulator-max-microvolt = <1050000>;
+               regulator-ramp-delay = <2300>;
+               vin-supply = <&vcc5v0_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+};
+
+&i2c2 {
+       status = "okay";
+
+       hym8563: rtc@51 {
+               compatible = "haoyu,hym8563";
+               reg = <0x51>;
+               #clock-cells = <0>;
+               clock-output-names = "hym8563";
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PD4 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&hym8563_int>;
+               wakeup-source;
+       };
+};
+
+&mdio0 {
+       rgmii_phy: ethernet-phy@1 {
+               /* RTL8211F */
+               compatible = "ethernet-phy-id001c.c916";
+               reg = <0x1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&rtl8211f_rst>;
+               reset-assert-us = <20000>;
+               reset-deassert-us = <100000>;
+               reset-gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&pinctrl {
+       rtl8211f {
+               rtl8211f_rst: rtl8211f-rst {
+                       rockchip,pins = <4 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+       };
+
+       hym8563 {
+               hym8563_int: hym8563-int {
+                       rockchip,pins = <0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       usb {
+               vcc5v0_host_en: vcc5v0-host-en {
+                       rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+};
+
+&pwm2 {
+       status = "okay";
+};
+
+&saradc {
+       vref-supply = <&vcc_1v8_s0>;
+       status = "okay";
+};
+
+&sdhci {
+       bus-width = <8>;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+       no-sdio;
+       no-sd;
+       non-removable;
+       status = "okay";
+};
+
+&spi2 {
+       assigned-clocks = <&cru CLK_SPI2>;
+       assigned-clock-rates = <200000000>;
+       num-cs = <1>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+       status = "okay";
+
+       pmic@0 {
+               compatible = "rockchip,rk806";
+               reg = <0x0>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+                           <&rk806_dvs2_null>, <&rk806_dvs3_null>;
+               spi-max-frequency = <1000000>;
+               system-power-controller;
+
+               vcc1-supply = <&vcc5v0_sys>;
+               vcc2-supply = <&vcc5v0_sys>;
+               vcc3-supply = <&vcc5v0_sys>;
+               vcc4-supply = <&vcc5v0_sys>;
+               vcc5-supply = <&vcc5v0_sys>;
+               vcc6-supply = <&vcc5v0_sys>;
+               vcc7-supply = <&vcc5v0_sys>;
+               vcc8-supply = <&vcc5v0_sys>;
+               vcc9-supply = <&vcc5v0_sys>;
+               vcc10-supply = <&vcc5v0_sys>;
+               vcc11-supply = <&vcc_2v0_pldo_s3>;
+               vcc12-supply = <&vcc5v0_sys>;
+               vcc13-supply = <&vcc_1v1_nldo_s3>;
+               vcc14-supply = <&vcc_1v1_nldo_s3>;
+               vcca-supply = <&vcc5v0_sys>;
+
+               rk806_dvs1_null: dvs1-null-pins {
+                       pins = "gpio_pwrctrl1";
+                       function = "pin_fun0";
+               };
+
+               rk806_dvs2_null: dvs2-null-pins {
+                       pins = "gpio_pwrctrl2";
+                       function = "pin_fun0";
+               };
+
+               rk806_dvs3_null: dvs3-null-pins {
+                       pins = "gpio_pwrctrl3";
+                       function = "pin_fun0";
+               };
+
+               regulators {
+                       vdd_gpu_s0: vdd_gpu_mem_s0: dcdc-reg1 {
+                               regulator-name = "vdd_gpu_s0";
+                               regulator-boot-on;
+                               regulator-enable-ramp-delay = <400>;
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_cpu_lit_s0: vdd_cpu_lit_mem_s0: dcdc-reg2 {
+                               regulator-name = "vdd_cpu_lit_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_log_s0: dcdc-reg3 {
+                               regulator-name = "vdd_log_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <675000>;
+                               regulator-max-microvolt = <750000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <750000>;
+                               };
+                       };
+
+                       vdd_vdenc_s0: vdd_vdenc_mem_s0: dcdc-reg4 {
+                               regulator-name = "vdd_vdenc_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-init-microvolt = <750000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_ddr_s0: dcdc-reg5 {
+                               regulator-name = "vdd_ddr_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <675000>;
+                               regulator-max-microvolt = <900000>;
+                               regulator-ramp-delay = <12500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <850000>;
+                               };
+                       };
+
+                       vdd2_ddr_s3: dcdc-reg6 {
+                               regulator-name = "vdd2_ddr_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc_2v0_pldo_s3: dcdc-reg7 {
+                               regulator-name = "vdd_2v0_pldo_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <2000000>;
+                               regulator-max-microvolt = <2000000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <2000000>;
+                               };
+                       };
+
+                       vcc_3v3_s3: dcdc-reg8 {
+                               regulator-name = "vcc_3v3_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3300000>;
+                               };
+                       };
+
+                       vddq_ddr_s0: dcdc-reg9 {
+                               regulator-name = "vddq_ddr_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_1v8_s3: dcdc-reg10 {
+                               regulator-name = "vcc_1v8_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       avcc_1v8_s0: pldo-reg1 {
+                               regulator-name = "avcc_1v8_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_1v8_s0: pldo-reg2 {
+                               regulator-name = "vcc_1v8_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       avdd_1v2_s0: pldo-reg3 {
+                               regulator-name = "avdd_1v2_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_3v3_s0: pldo-reg4 {
+                               regulator-name = "vcc_3v3_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vccio_sd_s0: pldo-reg5 {
+                               regulator-name = "vccio_sd_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       pldo6_s3: pldo-reg6 {
+                               regulator-name = "pldo6_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vdd_0v75_s3: nldo-reg1 {
+                               regulator-name = "vdd_0v75_s3";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <750000>;
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <750000>;
+                               };
+                       };
+
+                       vdd_ddr_pll_s0: nldo-reg2 {
+                               regulator-name = "vdd_ddr_pll_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <850000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <850000>;
+                               };
+                       };
+
+                       avdd_0v75_s0: nldo-reg3 {
+                               regulator-name = "avdd_0v75_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <837500>;
+                               regulator-max-microvolt = <837500>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_0v85_s0: nldo-reg4 {
+                               regulator-name = "vdd_0v85_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <850000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_0v75_s0: nldo-reg5 {
+                               regulator-name = "vdd_0v75_s0";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <750000>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+               };
+       };
+};
+
+&u2phy2 {
+       status = "okay";
+};
+
+&u2phy2_host {
+       phy-supply = <&vcc5v0_host>;
+       status = "okay";
+};
+
+&u2phy3 {
+       status = "okay";
+};
+
+&u2phy3_host {
+       phy-supply = <&vcc5v0_host>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-0 = <&uart2m0_xfer>;
+       status = "okay";
+};
+
+&usb_host0_ehci {
+       status = "okay";
+};
+
+&usb_host0_ohci {
+       status = "okay";
+};
+
+&usb_host1_ehci {
+       status = "okay";
+};
+
+&usb_host1_ohci {
+       status = "okay";
+};
index ef4f058c20ff1565cb67e5c2c495f0f337ab2a1c..e037bf9db75af0402dccd26b82b50922823fe9f7 100644 (file)
@@ -19,8 +19,8 @@
 
        aliases {
                mmc0 = &sdhci;
-               mmc1 = &sdio;
-               mmc2 = &sdmmc;
+               mmc1 = &sdmmc;
+               mmc2 = &sdio;
        };
 
        analog-sound {
index dc677f29a9c7fca2359cf0d28b3ec3c9e97dda30..ce8119cbb82485ac39c3b15dfae234f1666ec3c9 100644 (file)
        status = "okay";
 };
 
+&combphy2_psu {
+       status = "okay";
+};
+
 &cpu_l0 {
        cpu-supply = <&vdd_cpu_lit_s0>;
 };
 
 &gpio1 {
        gpio-line-names = /* GPIO1 A0-A7 */
-                         "HEADER_27_3v3", "HEADER_28_3v3", "", "",
+                         "HEADER_27_3v3", "", "", "",
                          "HEADER_29_1v8", "", "HEADER_7_1v8", "",
                          /* GPIO1 B0-B7 */
                          "", "HEADER_31_1v8", "HEADER_33_1v8", "",
                          "HEADER_11_1v8", "HEADER_13_1v8", "", "",
                          /* GPIO1 C0-C7 */
-                         "", "", "", "",
+                         "", "HEADER_28_3v3", "", "",
                          "", "", "", "",
                          /* GPIO1 D0-D7 */
                          "", "", "", "",
 
 &gpio4 {
        gpio-line-names = /* GPIO4 A0-A7 */
-                         "", "", "HEADER_37_3v3", "HEADER_32_3v3",
-                         "HEADER_36_3v3", "", "HEADER_35_3v3", "HEADER_38_3v3",
+                         "", "", "HEADER_37_3v3", "HEADER_8_3v3",
+                         "HEADER_10_3v3", "", "HEADER_32_3v3", "HEADER_35_3v3",
                          /* GPIO4 B0-B7 */
                          "", "", "", "HEADER_40_3v3",
-                         "HEADER_8_3v3", "HEADER_10_3v3", "", "",
+                         "HEADER_38_3v3", "HEADER_36_3v3", "", "",
                          /* GPIO4 C0-C7 */
                          "", "", "", "",
                          "", "", "", "",
 &usb_host1_ohci {
        status = "okay";
 };
+
+&usb_host2_xhci {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6c.dts b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6c.dts
new file mode 100644 (file)
index 0000000..497bbb5
--- /dev/null
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include "rk3588s-nanopi-r6s.dts"
+
+/ {
+       model = "FriendlyElec NanoPi R6C";
+       compatible = "friendlyarm,nanopi-r6c", "rockchip,rk3588s";
+};
+
+&lan2_led {
+       label = "user_led";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6s.dts b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6s.dts
new file mode 100644 (file)
index 0000000..4fa644a
--- /dev/null
@@ -0,0 +1,764 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include "rk3588s.dtsi"
+
+/ {
+       model = "FriendlyElec NanoPi R6S";
+       compatible = "friendlyarm,nanopi-r6s", "rockchip,rk3588s";
+
+       aliases {
+               ethernet0 = &gmac1;
+               mmc0 = &sdmmc;
+               mmc1 = &sdhci;
+       };
+
+       chosen {
+               stdout-path = "serial2:1500000n8";
+       };
+
+       adc-keys {
+               compatible = "adc-keys";
+               io-channels = <&saradc 0>;
+               io-channel-names = "buttons";
+               keyup-threshold-microvolt = <1800000>;
+               poll-interval = <100>;
+
+               button-maskrom {
+                       label = "Maskrom";
+                       linux,code = <KEY_VENDOR>;
+                       press-threshold-microvolt = <1800>;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&key1_pin>;
+
+               button-user {
+                       label = "User";
+                       linux,code = <BTN_1>;
+                       gpios = <&gpio1 RK_PC0 GPIO_ACTIVE_LOW>;
+                       debounce-interval = <50>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               sys_led: led-0 {
+                       label = "sys_led";
+                       gpios = <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&sys_led_pin>;
+               };
+
+               wan_led: led-1 {
+                       label = "wan_led";
+                       gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_HIGH>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&wan_led_pin>;
+               };
+
+               lan1_led: led-2 {
+                       label = "lan1_led";
+                       gpios = <&gpio1 RK_PC3 GPIO_ACTIVE_HIGH>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&lan1_led_pin>;
+               };
+
+               lan2_led: led-3 {
+                       label = "lan2_led";
+                       gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_HIGH>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&lan2_led_pin>;
+               };
+       };
+
+       vcc5v0_sys: vcc5v0-sys-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_sys";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+       };
+
+       vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_1v1_nldo_s3";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1100000>;
+               regulator-max-microvolt = <1100000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vcc_3v3_s0: vcc-3v3-s0-regulator {
+               compatible = "regulator-fixed";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-name = "vcc_3v3_s0";
+               vin-supply = <&vcc_3v3_s3>;
+       };
+
+       vcc_3v3_sd_s0: vcc-3v3-sd-s0-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpios = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&sd_s0_pwr>;
+               regulator-name = "vcc_3v3_sd_s0";
+               regulator-boot-on;
+               regulator-max-microvolt = <3000000>;
+               regulator-min-microvolt = <3000000>;
+               vin-supply = <&vcc_3v3_s3>;
+       };
+
+       vcc_3v3_pcie20: vcc3v3-pcie20-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_3v3_pcie20";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vcc_3v3_s3>;
+       };
+
+       vcc5v0_usb: vcc5v0-usb-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_usb";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vcc5v0_usb_otg0: vcc5v0-usb-otg0-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&typec5v_pwren>;
+               regulator-name = "vcc5v0_usb_otg0";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc5v0_usb>;
+       };
+
+       vcc5v0_host_20: vcc5v0-host-20-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vcc5v0_host20_en>;
+               regulator-name = "vcc5v0_host_20";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vcc5v0_usb>;
+       };
+};
+
+&combphy0_ps {
+       status = "okay";
+};
+
+&combphy2_psu {
+       status = "okay";
+};
+
+&cpu_b0 {
+       cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b1 {
+       cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b2 {
+       cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_b3 {
+       cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_l0 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+       cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&gmac1 {
+       clock_in_out = "output";
+       phy-handle = <&rgmii_phy1>;
+       phy-mode = "rgmii-rxid";
+       pinctrl-0 = <&gmac1_miim
+                    &gmac1_tx_bus2
+                    &gmac1_rx_bus2
+                    &gmac1_rgmii_clk
+                    &gmac1_rgmii_bus>;
+       pinctrl-names = "default";
+       tx_delay = <0x42>;
+       status = "okay";
+};
+
+&i2c0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c0m2_xfer>;
+       status = "okay";
+
+       vdd_cpu_big0_s0: regulator@42 {
+               compatible = "rockchip,rk8602";
+               reg = <0x42>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_cpu_big0_s0";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <550000>;
+               regulator-max-microvolt = <1050000>;
+               regulator-ramp-delay = <2300>;
+               vin-supply = <&vcc5v0_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+
+       vdd_cpu_big1_s0: regulator@43 {
+               compatible = "rockchip,rk8603", "rockchip,rk8602";
+               reg = <0x43>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_cpu_big1_s0";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <550000>;
+               regulator-max-microvolt = <1050000>;
+               regulator-ramp-delay = <2300>;
+               vin-supply = <&vcc5v0_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+};
+
+&i2c2 {
+       status = "okay";
+
+       vdd_npu_s0: regulator@42 {
+               compatible = "rockchip,rk8602";
+               reg = <0x42>;
+               fcs,suspend-voltage-selector = <1>;
+               regulator-name = "vdd_npu_s0";
+               regulator-min-microvolt = <550000>;
+               regulator-max-microvolt = <950000>;
+               regulator-ramp-delay = <2300>;
+               regulator-boot-on;
+               regulator-always-on;
+               vin-supply = <&vcc5v0_sys>;
+
+               regulator-state-mem {
+                       regulator-off-in-suspend;
+               };
+       };
+};
+
+&i2c6 {
+       clock-frequency = <200000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c6m0_xfer>;
+       status = "okay";
+
+       hym8563: rtc@51 {
+               compatible = "haoyu,hym8563";
+               reg = <0x51>;
+               #clock-cells = <0>;
+               clock-output-names = "hym8563";
+               pinctrl-names = "default";
+               pinctrl-0 = <&rtc_int>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
+               wakeup-source;
+       };
+};
+
+&mdio1 {
+       rgmii_phy1: ethernet-phy@1 {
+               compatible = "ethernet-phy-id001c.c916";
+               reg = <0x1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&rtl8211f_rst>;
+               reset-assert-us = <20000>;
+               reset-deassert-us = <100000>;
+               reset-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&pcie2x1l1 {
+       reset-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>;
+       vpcie3v3-supply = <&vcc_3v3_pcie20>;
+       status = "okay";
+};
+
+&pcie2x1l2 {
+       reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>;
+       vpcie3v3-supply = <&vcc_3v3_pcie20>;
+       status = "okay";
+};
+
+&pinctrl {
+       gpio-key {
+               key1_pin: key1-pin {
+                       rockchip,pins = <1 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       gpio-leds {
+               sys_led_pin: sys-led-pin {
+                       rockchip,pins =
+                               <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               wan_led_pin: wan-led-pin {
+                       rockchip,pins =
+                               <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               lan1_led_pin: lan1-led-pin {
+                       rockchip,pins =
+                               <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               lan2_led_pin: lan2-led-pin {
+                       rockchip,pins =
+                               <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       hym8563 {
+               rtc_int: rtc-int {
+                       rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       sdmmc {
+               sd_s0_pwr: sd-s0-pwr {
+                       rockchip,pins = <4 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
+       usb {
+               typec5v_pwren: typec5v-pwren {
+                       rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               vcc5v0_host20_en: vcc5v0-host20-en {
+                       rockchip,pins = <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       rtl8211f {
+               rtl8211f_rst: rtl8211f-rst {
+                       rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+};
+
+&saradc {
+       vref-supply = <&avcc_1v8_s0>;
+       status = "okay";
+};
+
+&sdhci {
+       bus-width = <8>;
+       no-sdio;
+       no-sd;
+       non-removable;
+       mmc-hs200-1_8v;
+       status = "okay";
+};
+
+&sdmmc {
+       bus-width = <4>;
+       cap-sd-highspeed;
+       disable-wp;
+       max-frequency = <150000000>;
+       no-mmc;
+       no-sdio;
+       sd-uhs-sdr104;
+       vmmc-supply = <&vcc_3v3_sd_s0>;
+       vqmmc-supply = <&vccio_sd_s0>;
+       status = "okay";
+};
+
+&spi2 {
+       status = "okay";
+       assigned-clocks = <&cru CLK_SPI2>;
+       assigned-clock-rates = <200000000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+       num-cs = <1>;
+
+       pmic@0 {
+               compatible = "rockchip,rk806";
+               spi-max-frequency = <1000000>;
+               reg = <0x0>;
+
+               interrupt-parent = <&gpio0>;
+               interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+                           <&rk806_dvs2_null>, <&rk806_dvs3_null>;
+
+               system-power-controller;
+
+               vcc1-supply = <&vcc5v0_sys>;
+               vcc2-supply = <&vcc5v0_sys>;
+               vcc3-supply = <&vcc5v0_sys>;
+               vcc4-supply = <&vcc5v0_sys>;
+               vcc5-supply = <&vcc5v0_sys>;
+               vcc6-supply = <&vcc5v0_sys>;
+               vcc7-supply = <&vcc5v0_sys>;
+               vcc8-supply = <&vcc5v0_sys>;
+               vcc9-supply = <&vcc5v0_sys>;
+               vcc10-supply = <&vcc5v0_sys>;
+               vcc11-supply = <&vcc_2v0_pldo_s3>;
+               vcc12-supply = <&vcc5v0_sys>;
+               vcc13-supply = <&vcc_1v1_nldo_s3>;
+               vcc14-supply = <&vcc_1v1_nldo_s3>;
+               vcca-supply = <&vcc5v0_sys>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               rk806_dvs1_null: dvs1-null-pins {
+                       pins = "gpio_pwrctrl1";
+                       function = "pin_fun0";
+               };
+
+               rk806_dvs2_null: dvs2-null-pins {
+                       pins = "gpio_pwrctrl2";
+                       function = "pin_fun0";
+               };
+
+               rk806_dvs3_null: dvs3-null-pins {
+                       pins = "gpio_pwrctrl3";
+                       function = "pin_fun0";
+               };
+
+               regulators {
+                       vdd_gpu_s0: vdd_gpu_mem_s0: dcdc-reg1 {
+                               regulator-boot-on;
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-name = "vdd_gpu_s0";
+                               regulator-enable-ramp-delay = <400>;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_cpu_lit_s0: vdd_cpu_lit_mem_s0: dcdc-reg2 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-name = "vdd_cpu_lit_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_log_s0: dcdc-reg3 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <675000>;
+                               regulator-max-microvolt = <750000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-name = "vdd_log_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <750000>;
+                               };
+                       };
+
+                       vdd_vdenc_s0: vdd_vdenc_mem_s0: dcdc-reg4 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <550000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-name = "vdd_vdenc_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_ddr_s0: dcdc-reg5 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <675000>;
+                               regulator-max-microvolt = <900000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-name = "vdd_ddr_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <850000>;
+                               };
+                       };
+
+                       vdd2_ddr_s3: dcdc-reg6 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-name = "vdd2_ddr_s3";
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc_2v0_pldo_s3: dcdc-reg7 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <2000000>;
+                               regulator-max-microvolt = <2000000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-name = "vdd_2v0_pldo_s3";
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <2000000>;
+                               };
+                       };
+
+                       vcc_3v3_s3: dcdc-reg8 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc_3v3_s3";
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3300000>;
+                               };
+                       };
+
+                       vddq_ddr_s0: dcdc-reg9 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-name = "vddq_ddr_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vcc_1v8_s3: dcdc-reg10 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc_1v8_s3";
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       avcc_1v8_s0: pldo-reg1 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "avcc_1v8_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcc_1v8_s0: pldo-reg2 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc_1v8_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       avdd_1v2_s0: pldo-reg3 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-name = "avdd_1v2_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       avcc_3v3_s0: pldo-reg4 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-name = "avcc_3v3_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vccio_sd_s0: pldo-reg5 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-name = "vccio_sd_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       pldo6_s3: pldo-reg6 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "pldo6_s3";
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vdd_0v75_s3: nldo-reg1 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <750000>;
+                               regulator-name = "vdd_0v75_s3";
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <750000>;
+                               };
+                       };
+
+                       avdd_ddr_pll_s0: nldo-reg2 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <850000>;
+                               regulator-name = "avdd_ddr_pll_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                                       regulator-suspend-microvolt = <850000>;
+                               };
+                       };
+
+                       avdd_0v75_s0: nldo-reg3 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <750000>;
+                               regulator-name = "avdd_0v75_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       avdd_0v85_s0: nldo-reg4 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <850000>;
+                               regulator-name = "avdd_0v85_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       vdd_0v75_s0: nldo-reg5 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <750000>;
+                               regulator-max-microvolt = <750000>;
+                               regulator-name = "vdd_0v75_s0";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+               };
+       };
+};
+
+&tsadc {
+       status = "okay";
+};
+
+&u2phy2 {
+       status = "okay";
+};
+
+&u2phy2_host {
+       phy-supply = <&vcc5v0_host_20>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-0 = <&uart2m0_xfer>;
+       status = "okay";
+};
+
+&usb_host0_ehci {
+       status = "okay";
+};
+
+&usb_host0_ohci {
+       status = "okay";
+};
index 2002fd0221fa30cf2b81afcab5bf600dd8328ae1..00afb90d4eb10bab9db61591c9f5cb167c37ec93 100644 (file)
        bus-width = <4>;
        cap-mmc-highspeed;
        cap-sd-highspeed;
-       cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
        disable-wp;
        max-frequency = <150000000>;
        no-sdio;
index 36b1b7acfe6a15042600a595875054744d48f257..87b83c87bd55155623342fe002ad67cbe104b83c 100644 (file)
        vo1_grf: syscon@fd5a8000 {
                compatible = "rockchip,rk3588-vo-grf", "syscon";
                reg = <0x0 0xfd5a8000 0x0 0x100>;
+               clocks = <&cru PCLK_VO1GRF>;
        };
 
        php_grf: syscon@fd5b0000 {
                };
        };
 
+       hdptxphy0_grf: syscon@fd5e0000 {
+               compatible = "rockchip,rk3588-hdptxphy-grf", "syscon";
+               reg = <0x0 0xfd5e0000 0x0 0x100>;
+       };
+
        ioc: syscon@fd5f0000 {
                compatible = "rockchip,rk3588-ioc", "syscon";
                reg = <0x0 0xfd5f0000 0x0 0x10000>;
                dmas = <&dmac1 0>, <&dmac1 1>;
                dma-names = "tx", "rx";
                power-domains = <&power RK3588_PD_AUDIO>;
-               rockchip,trcm-sync-tx-only;
                pinctrl-names = "default";
                pinctrl-0 = <&i2s2m1_lrck
                             &i2s2m1_sclk
                dmas = <&dmac1 2>, <&dmac1 3>;
                dma-names = "tx", "rx";
                power-domains = <&power RK3588_PD_AUDIO>;
-               rockchip,trcm-sync-tx-only;
                pinctrl-names = "default";
                pinctrl-0 = <&i2s3_lrck
                             &i2s3_sclk
                #dma-cells = <1>;
        };
 
+       hdptxphy_hdmi0: phy@fed60000 {
+               compatible = "rockchip,rk3588-hdptx-phy";
+               reg = <0x0 0xfed60000 0x0 0x2000>;
+               clocks = <&cru CLK_USB2PHY_HDPTXRXPHY_REF>, <&cru PCLK_HDPTX0>;
+               clock-names = "ref", "apb";
+               #phy-cells = <0>;
+               resets = <&cru SRST_HDPTX0>, <&cru SRST_P_HDPTX0>,
+                        <&cru SRST_HDPTX0_INIT>, <&cru SRST_HDPTX0_CMN>,
+                        <&cru SRST_HDPTX0_LANE>, <&cru SRST_HDPTX0_ROPLL>,
+                        <&cru SRST_HDPTX0_LCPLL>;
+               reset-names = "phy", "apb", "init", "cmn", "lane", "ropll",
+                             "lcpll";
+               rockchip,grf = <&hdptxphy0_grf>;
+               status = "disabled";
+       };
+
        combphy0_ps: phy@fee00000 {
                compatible = "rockchip,rk3588-naneng-combphy";
                reg = <0x0 0xfee00000 0x0 0x100>;
index 96859d098ef8f6aa088a2a63787771fd04807b11..5dd4f3580a60feee79fae0946492293ee64b0edc 100644 (file)
                        compatible = "fixed-clock";
                        clock-frequency = <200000000>;
                };
+
+               ck_icn_p_vdec: ck-icn-p-vdec {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <200000000>;
+               };
+
+               ck_icn_p_venc: ck-icn-p-venc {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <200000000>;
+               };
        };
 
        firmware {
index e6fa596211f5c0aa5f5b8e338fd354e5ae0ee213..17f197c5b22b1b67973506090ee475ccda5e9998 100644 (file)
@@ -6,4 +6,21 @@
 #include "stm32mp253.dtsi"
 
 / {
+       soc@0 {
+               rifsc: rifsc-bus@42080000 {
+                       vdec: vdec@480d0000 {
+                               compatible = "st,stm32mp25-vdec";
+                               reg = <0x480d0000 0x3c8>;
+                               interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&ck_icn_p_vdec>;
+                       };
+
+                       venc: venc@480e0000 {
+                               compatible = "st,stm32mp25-venc";
+                               reg = <0x480e0000 0x800>;
+                               interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&ck_icn_ls_mcu>;
+                       };
+               };
+       };
 };
index aaffb50b8b60df37fbef30f78597c9d1cb916bfa..047a83cee6038394ebe3082fdb0bfb1d578f767c 100644 (file)
                        clocks = <&clock_peric PERIC_PCLK_UART0>,
                                 <&clock_peric PERIC_SCLK_UART0>;
                        clock-names = "uart", "clk_uart_baud0";
+                       samsung,uart-fifosize = <64>;
                        status = "disabled";
                };
 
                        clocks = <&clock_peric PERIC_PCLK_UART1>,
                                 <&clock_peric PERIC_SCLK_UART1>;
                        clock-names = "uart", "clk_uart_baud0";
+                       samsung,uart-fifosize = <64>;
                        status = "disabled";
                };
 
index 52c1dc9103087e82e6c360bc193f63c64edc91bc..9a722c2473fb7c3330a576188e22dbb1995d483c 100644 (file)
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # Make file to build device tree binaries for boards based on
 # Texas Instruments Inc processors
@@ -22,6 +22,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dev.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-mallow.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-yavia.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-am62x-phyboard-lyra-gpio-fan.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk.dtb
 
 # Boards with AM62Ax SoC
@@ -37,7 +38,15 @@ dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-imx219.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-hdmi-audio.dtbo
 
 # Boards with AM64x SoC
+k3-am642-hummingboard-t-pcie-dtbs := \
+       k3-am642-hummingboard-t.dtb k3-am642-hummingboard-t-pcie.dtbo
+k3-am642-hummingboard-t-usb3-dtbs := \
+       k3-am642-hummingboard-t.dtb k3-am642-hummingboard-t-usb3.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am642-evm.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-am642-evm-icssg1-dualemac.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-am642-hummingboard-t.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-am642-hummingboard-t-pcie.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-am642-hummingboard-t-usb3.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am642-phyboard-electra-rdk.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am642-sk.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am642-tqma64xxl-mbax4xxl.dtb
@@ -45,18 +54,24 @@ dtb-$(CONFIG_ARCH_K3) += k3-am64-tqma64xxl-mbax4xxl-sdcard.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am64-tqma64xxl-mbax4xxl-wlan.dtbo
 
 # Boards with AM65x SoC
-k3-am654-gp-evm-dtbs := k3-am654-base-board.dtb k3-am654-base-board-rocktech-rk101-panel.dtbo
+k3-am654-gp-evm-dtbs := k3-am654-base-board.dtb \
+       k3-am654-base-board-rocktech-rk101-panel.dtbo \
+       k3-am654-pcie-usb3.dtbo
 k3-am654-evm-dtbs := k3-am654-base-board.dtb k3-am654-icssg2.dtbo
-k3-am654-idk-dtbs := k3-am654-evm.dtb k3-am654-idk.dtbo
+k3-am654-idk-dtbs := k3-am654-evm.dtb k3-am654-idk.dtbo k3-am654-pcie-usb2.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am6528-iot2050-basic.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am6528-iot2050-basic-pg2.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced-m2.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced-pg2.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced-sm.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am654-base-board.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am654-gp-evm.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am654-evm.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am654-idk.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-am654-base-board-rocktech-rk101-panel.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-am654-pcie-usb2.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-am654-pcie-usb3.dtbo
 
 # Boards with J7200 SoC
 k3-j7200-evm-dtbs := k3-j7200-common-proc-board.dtb k3-j7200-evm-quad-port-eth-exp.dtbo
@@ -69,6 +84,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm-gesi-exp-board.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm-pcie0-ep.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-csi2-dual-imx219.dtbo
 
 # Boards with J721s2 SoC
 dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-base-board.dtb
@@ -78,6 +94,9 @@ k3-j721s2-evm-dtbs := k3-j721s2-common-proc-board.dtb k3-j721s2-evm-gesi-exp-boa
 dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-pcie1-ep.dtbo
 
+# Boards with J722s SoC
+dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm.dtb
+
 # Boards with J784s4 SoC
 dtb-$(CONFIG_ARCH_K3) += k3-am69-sk.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm.dtb
@@ -87,6 +106,8 @@ k3-am625-beagleplay-csi2-ov5640-dtbs := k3-am625-beagleplay.dtb \
        k3-am625-beagleplay-csi2-ov5640.dtbo
 k3-am625-beagleplay-csi2-tevi-ov5640-dtbs := k3-am625-beagleplay.dtb \
        k3-am625-beagleplay-csi2-tevi-ov5640.dtbo
+k3-am625-phyboard-lyra-gpio-fan-dtbs := k3-am625-phyboard-lyra-rdk.dtb \
+       k3-am62x-phyboard-lyra-gpio-fan.dtbo
 k3-am625-sk-csi2-imx219-dtbs := k3-am625-sk.dtb \
        k3-am62x-sk-csi2-imx219.dtbo
 k3-am625-sk-csi2-ov5640-dtbs := k3-am625-sk.dtb \
@@ -101,12 +122,27 @@ k3-am62a7-sk-csi2-ov5640-dtbs := k3-am62a7-sk.dtb \
        k3-am62x-sk-csi2-ov5640.dtbo
 k3-am62a7-sk-csi2-tevi-ov5640-dtbs := k3-am62a7-sk.dtb \
        k3-am62x-sk-csi2-tevi-ov5640.dtbo
+k3-am62a7-sk-hdmi-audio-dtbs := k3-am62a7-sk.dtb k3-am62x-sk-hdmi-audio.dtbo
+k3-am62p5-sk-csi2-imx219-dtbs := k3-am62p5-sk.dtb \
+       k3-am62x-sk-csi2-imx219.dtbo
+k3-am62p5-sk-csi2-ov5640-dtbs := k3-am62p5-sk.dtb \
+       k3-am62x-sk-csi2-ov5640.dtbo
+k3-am62p5-sk-csi2-tevi-ov5640-dtbs := k3-am62p5-sk.dtb \
+       k3-am62x-sk-csi2-tevi-ov5640.dtbo
+k3-am642-evm-icssg1-dualemac-dtbs := \
+       k3-am642-evm.dtb k3-am642-evm-icssg1-dualemac.dtbo
 k3-am642-tqma64xxl-mbax4xxl-sdcard-dtbs := \
        k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-sdcard.dtbo
 k3-am642-tqma64xxl-mbax4xxl-wlan-dtbs := \
        k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-wlan.dtbo
+k3-am68-sk-base-board-csi2-dual-imx219-dtbs := k3-am68-sk-base-board.dtb \
+       k3-j721e-sk-csi2-dual-imx219.dtbo
+k3-am69-sk-csi2-dual-imx219-dtbs := k3-am69-sk.dtb \
+       k3-j721e-sk-csi2-dual-imx219.dtbo
 k3-j721e-evm-pcie0-ep-dtbs := k3-j721e-common-proc-board.dtb \
        k3-j721e-evm-pcie0-ep.dtbo
+k3-j721e-sk-csi2-dual-imx219-dtbs := k3-j721e-sk.dtb \
+       k3-j721e-sk-csi2-dual-imx219.dtbo
 k3-j721s2-evm-pcie1-ep-dtbs := k3-j721s2-common-proc-board.dtb \
        k3-j721s2-evm-pcie1-ep.dtbo
 dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \
@@ -118,9 +154,17 @@ dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \
        k3-am62-lp-sk-hdmi-audio.dtb \
        k3-am62a7-sk-csi2-imx219.dtb \
        k3-am62a7-sk-csi2-ov5640.dtb \
+       k3-am62a7-sk-hdmi-audio.dtb \
+       k3-am62p5-sk-csi2-imx219.dtb \
+       k3-am62p5-sk-csi2-ov5640.dtb \
+       k3-am62p5-sk-csi2-tevi-ov5640.dtb \
+       k3-am642-evm-icssg1-dualemac.dtb \
        k3-am642-tqma64xxl-mbax4xxl-sdcard.dtb \
        k3-am642-tqma64xxl-mbax4xxl-wlan.dtb \
+       k3-am68-sk-base-board-csi2-dual-imx219-dtbs \
+       k3-am69-sk-csi2-dual-imx219-dtbs \
        k3-j721e-evm-pcie0-ep.dtb \
+       k3-j721e-sk-csi2-dual-imx219-dtbs \
        k3-j721s2-evm-pcie1-ep.dtb
 
 # Enable support for device-tree overlays
@@ -128,7 +172,12 @@ DTC_FLAGS_k3-am625-beagleplay += -@
 DTC_FLAGS_k3-am625-sk += -@
 DTC_FLAGS_k3-am62-lp-sk += -@
 DTC_FLAGS_k3-am62a7-sk += -@
+DTC_FLAGS_k3-am62p5-sk += -@
+DTC_FLAGS_k3-am642-evm += -@
 DTC_FLAGS_k3-am642-tqma64xxl-mbax4xxl += -@
 DTC_FLAGS_k3-am6548-iot2050-advanced-m2 += -@
+DTC_FLAGS_k3-am68-sk-base-board += -@
+DTC_FLAGS_k3-am69-sk += -@
 DTC_FLAGS_k3-j721e-common-proc-board += -@
+DTC_FLAGS_k3-j721e-sk += -@
 DTC_FLAGS_k3-j721s2-common-proc-board += -@
index 5e6feb8cd12552d9aec896d7d5ce5379911e8272..c4149059a4c5bcf4f2c59dbbdd45f9048663bfa3 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * AM62x LP SK: https://www.ti.com/tool/SK-AM62-LP
  *
- * Copyright (C) 2021-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index 464b7565d085d76f0a85120304afd03b39b034a0..e9cffca073efcd59216b71f089dd13439887a21b 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM625 SoC Family Main Domain peripherals
  *
- * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_main {
@@ -42,9 +42,8 @@
                };
        };
 
-       main_conf: syscon@100000 {
-               compatible = "syscon", "simple-mfd";
-               reg = <0x00 0x00100000 0x00 0x20000>;
+       main_conf: bus@100000 {
+               compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
                ranges = <0x0 0x00 0x00100000 0x20000>;
                clock-names = "clk_ahb", "clk_xin";
                assigned-clocks = <&k3_clks 57 6>;
                assigned-clock-parents = <&k3_clks 57 8>;
+               bus-width = <8>;
                mmc-ddr-1_8v;
                mmc-hs200-1_8v;
-               ti,trm-icp = <0x2>;
-               bus-width = <8>;
                ti,clkbuf-sel = <0x7>;
                ti,otap-del-sel-legacy = <0x0>;
                ti,otap-del-sel-mmc-hs = <0x0>;
                power-domains = <&k3_pds 58 TI_SCI_PD_EXCLUSIVE>;
                clocks = <&k3_clks 58 5>, <&k3_clks 58 6>;
                clock-names = "clk_ahb", "clk_xin";
-               ti,trm-icp = <0x2>;
+               bus-width = <4>;
+               ti,clkbuf-sel = <0x7>;
                ti,otap-del-sel-legacy = <0x8>;
                ti,otap-del-sel-sd-hs = <0x0>;
                ti,otap-del-sel-sdr12 = <0x0>;
                ti,itap-del-sel-sd-hs = <0x1>;
                ti,itap-del-sel-sdr12 = <0xa>;
                ti,itap-del-sel-sdr25 = <0x1>;
-               ti,clkbuf-sel = <0x7>;
-               bus-width = <4>;
                status = "disabled";
        };
 
                power-domains = <&k3_pds 184 TI_SCI_PD_EXCLUSIVE>;
                clocks = <&k3_clks 184 5>, <&k3_clks 184 6>;
                clock-names = "clk_ahb", "clk_xin";
-               ti,trm-icp = <0x2>;
+               bus-width = <4>;
+               ti,clkbuf-sel = <0x7>;
                ti,otap-del-sel-legacy = <0x8>;
                ti,otap-del-sel-sd-hs = <0x0>;
                ti,otap-del-sel-sdr12 = <0x0>;
                ti,itap-del-sel-sd-hs = <0xa>;
                ti,itap-del-sel-sdr12 = <0xa>;
                ti,itap-del-sel-sdr25 = <0x1>;
-               ti,clkbuf-sel = <0x7>;
                status = "disabled";
        };
 
                        interrupt-names = "host", "peripheral";
                        maximum-speed = "high-speed";
                        dr_mode = "otg";
+                       snps,usb2-gadget-lpm-disable;
+                       snps,usb2-lpm-disable;
                };
        };
 
                        interrupt-names = "host", "peripheral";
                        maximum-speed = "high-speed";
                        dr_mode = "otg";
+                       snps,usb2-gadget-lpm-disable;
+                       snps,usb2-lpm-disable;
                };
        };
 
                      <0x00 0x30207000 0x00 0x1000>, /* ovr1 */
                      <0x00 0x30208000 0x00 0x1000>, /* ovr2 */
                      <0x00 0x3020a000 0x00 0x1000>, /* vp1: Used for OLDI */
-                     <0x00 0x3020b000 0x00 0x1000>; /* vp2: Used as DPI Out */
+                     <0x00 0x3020b000 0x00 0x1000>, /* vp2: Used as DPI Out */
+                     <0x00 0x30201000 0x00 0x1000>; /* common1 */
                reg-names = "common", "vidl1", "vid",
-                           "ovr1", "ovr2", "vp1", "vp2";
+                           "ovr1", "ovr2", "vp1", "vp2", "common1";
                power-domains = <&k3_pds 186 TI_SCI_PD_EXCLUSIVE>;
                clocks = <&k3_clks 186 6>,
                         <&dss_vp1_clk>,
index 0e0b234581c637c89983eb04a3754aa2eaa0c101..e66d486ef1f21069e67096659db5295db9267e0f 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM625 SoC Family MCU Domain peripherals
  *
- * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_mcu {
index aa43e7407eee43df8b5c06cc3194e997c3c4a3a7..43488cc8bcb1e1e373647721b05d5193bba7d2af 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2022 - 2023 PHYTEC Messtechnik GmbH
+ * Copyright (C) 2022-2024 PHYTEC Messtechnik GmbH
  * Author: Wadim Egorov <w.egorov@phytec.de>
  *
  * Product homepage:
 &sdhci0 {
        pinctrl-names = "default";
        pinctrl-0 = <&main_mmc0_pins_default>;
-       ti,driver-strength-ohm = <50>;
        disable-wp;
        non-removable;
        status = "okay";
index a358757e26f07b8fb470b955d6340ae41d9ad1a8..12ba833002a11df3405753208f4166c742f84ea4 100644 (file)
@@ -1,4 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
 
 #include <dt-bindings/thermal/thermal.h>
 
index bf6d27e70bc484ec519d01f2c13d82b3a0a3cb22..6c4cec8728e4984870bf9c90de38c72176889679 100644 (file)
 
 /* Verdin SD_1 */
 &sdhci1 {
-       ti,driver-strength-ohm = <33>;
        status = "okay";
 };
 
index 680071688dcb6364914aa31bfbc26760bffc1b7f..be62648e7818aeedccbc1942776fff87f69a1f60 100644 (file)
 
 /* Verdin SD_1 */
 &sdhci1 {
-       ti,driver-strength-ohm = <33>;
        status = "okay";
 };
 
index 17b93534f6588b48b8008855aa420d8dbedf6b05..77b1beb638ad7bf400c0b7df836d0ea032e0f60f 100644 (file)
                    <&pinctrl_qspi1_cs2_gpio>;
        cs-gpios = <0>, <&main_gpio0 12 GPIO_ACTIVE_LOW>;
        status = "okay";
+
+       tpm@1 {
+               compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
+               reg = <1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_qspi1_dqs_gpio>;
+               interrupt-parent = <&main_gpio1>;
+               interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+               spi-max-frequency = <18500000>;
+       };
 };
 
 /* Verdin UART_3 */
index a6808b10c7b26d43156d35b45077e2a8c2ef7549..4768ef42c4fcc6ee7c74b4ff85a3f8d81696aa0a 100644 (file)
@@ -26,7 +26,6 @@
        mmc-pwrseq = <&wifi_pwrseq>;
        non-removable;
        ti,fails-without-test-cd;
-       ti,driver-strength-ohm = <50>;
        vmmc-supply = <&reg_3v3>;
        status = "okay";
 };
index 6a06724b6d168b1e2beeb8659f5fb03e5f52e589..e8d8857ad51ff2f25d4ed4ec6989fb19e9e39354 100644 (file)
                usb1 = &usb1;
        };
 
+       connector {
+               compatible = "gpio-usb-b-connector", "usb-b-connector";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usb0_id>;
+               id-gpios = <&main_gpio1 19 GPIO_ACTIVE_HIGH>;
+               label = "USB_1";
+               self-powered;
+               vbus-supply = <&reg_usb0_vbus>;
+
+               port {
+                       usb_dr_connector: endpoint {
+                               remote-endpoint = <&usb0_ep>;
+                       };
+               };
+       };
+
        verdin_gpio_keys: gpio-keys {
                compatible = "gpio-keys";
                pinctrl-names = "default";
                vin-supply = <&reg_sd_3v3_1v8>;
        };
 
+       reg_usb0_vbus: regulator-usb0-vbus {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usb0_en>;
+               enable-active-high;
+               /* Verdin USB_1_EN (SODIMM 155) */
+               gpio = <&main_gpio1 50 GPIO_ACTIVE_HIGH>;
+               regulator-max-microvolt = <5000000>;
+               regulator-min-microvolt = <5000000>;
+               regulator-name = "USB_1_EN";
+       };
+
        reserved-memory {
                #address-cells = <2>;
                #size-cells = <2>;
                >;
        };
 
+       /* Verdin USB_1_EN */
+       pinctrl_usb0_en: main-gpio1-50-default-pins {
+               pinctrl-single,pins = <
+                       AM62X_IOPAD(0x0254, PIN_INPUT, 7) /* (C20) USB0_DRVVBUS.GPIO1_50 */ /* SODIMM 155 */
+               >;
+       };
+
        /* On-module I2C - PMIC_I2C */
        pinctrl_i2c0: main-i2c0-default-pins {
                pinctrl-single,pins = <
                >;
        };
 
-       /* Verdin USB_1 */
-       pinctrl_usb0: main-usb0-default-pins {
-               pinctrl-single,pins = <
-                       AM62X_IOPAD(0x0254, PIN_OUTPUT, 0) /* (C20) USB0_DRVVBUS */ /* SODIMM 155 */
-               >;
-       };
-
        /* Verdin USB_2 */
        pinctrl_usb1: main-usb1-default-pins {
                pinctrl-single,pins = <
                "",
                "",
                "SODIMM_17",
-               "", /* 50 */
+               "SODIMM_155", /* 50 */
                "",
                "",
                "",
                                regulator-always-on;
                                regulator-boot-on;
                                regulator-max-microvolt = <850000>;
-                               regulator-min-microvolt = <850000>;
+                               regulator-min-microvolt = <750000>;
                                regulator-name = "+VDD_CORE (PMIC BUCK1)";
                        };
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_sdhci0>;
        non-removable;
-       ti,driver-strength-ohm = <50>;
        status = "okay";
 };
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_sdhci1>;
        disable-wp;
-       ti,driver-strength-ohm = <50>;
        vmmc-supply = <&reg_sdhc1_vmmc>;
        vqmmc-supply = <&reg_sdhc1_vqmmc>;
        status = "disabled";
        status = "disabled";
 };
 
-/* TODO: role swich using ID pin */
 &usb0 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usb0>, <&pinctrl_usb0_id>;
+       adp-disable;
+       usb-role-switch;
        status = "disabled";
+
+       port {
+               usb0_ep: endpoint {
+                       remote-endpoint = <&usb_dr_connector>;
+               };
+       };
 };
 
 /* Verdin USB_2 */
index fef76f52a52e30f27c619d4cb9508282180604a6..23ce1bfda8d6abbb75472d3b8a321f6e9eb3d8c3 100644 (file)
@@ -1,10 +1,12 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM625 SoC Family Wakeup Domain peripherals
  *
- * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
+#include <dt-bindings/bus/ti-sysc.h>
+
 &cbass_wakeup {
        wkup_conf: syscon@43000000 {
                bootph-all;
                };
        };
 
-       wkup_uart0: serial@2b300000 {
-               compatible = "ti,am64-uart", "ti,am654-uart";
-               reg = <0x00 0x2b300000 0x00 0x100>;
-               interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+       target-module@2b300050 {
+               compatible = "ti,sysc-omap2", "ti,sysc";
+               reg = <0x00 0x2b300050 0x00 0x4>,
+                     <0x00 0x2b300054 0x00 0x4>,
+                     <0x00 0x2b300058 0x00 0x4>;
+               reg-names = "rev", "sysc", "syss";
+               ti,sysc-mask = <(SYSC_OMAP2_ENAWAKEUP |
+                                SYSC_OMAP2_SOFTRESET |
+                                SYSC_OMAP2_AUTOIDLE)>;
+               ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                               <SYSC_IDLE_NO>,
+                               <SYSC_IDLE_SMART>,
+                               <SYSC_IDLE_SMART_WKUP>;
+               ti,syss-mask = <1>;
+               ti,no-reset-on-init;
                power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>;
                clocks = <&k3_clks 114 0>;
-               clock-names = "fclk";
-               status = "disabled";
+               clock-names = "fck";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x00 0x2b300000 0x100000>;
+
+               wkup_uart0: serial@0 {
+                       compatible = "ti,am64-uart", "ti,am654-uart";
+                       reg = <0x0 0x100>;
+                       interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
        };
 
        wkup_i2c0: i2c@2b200000 {
index f1e15206e1ce59a440cde9b489ac674221750ac4..f0781f2bea29806e1485d1b8d53f2342d124dcae 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM62 SoC Family
  *
- * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/gpio/gpio.h>
index 5e80ca7033ba7e961fe9f853655c32e38a3939cc..3b4643b7d19c9468d1f637159ce7d1de331573cf 100644 (file)
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * ALINX AN5641 & Digilent PCam 5C - OV5640 camera module
- * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index 5e1cbbc27c8f2ef35ad4df44cc190b359c21897c..81a2763d43c65f88eeb833daa779e1cbcf6d7fc2 100644 (file)
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Technexion TEVI-OV5640-*-RPI - OV5640 camera module
- * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index eadbdd9ffe37707a704b0eca59d50fb0995e0676..a34e0df2ab8646206b26c19f529629f9dfedf226 100644 (file)
@@ -1,9 +1,9 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * https://beagleplay.org/
  *
- * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/
- * Copyright (C) 2022-2023 Robert Nelson, BeagleBoard.org Foundation
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Robert Nelson, BeagleBoard.org Foundation
  */
 
 /dts-v1/;
@@ -29,7 +29,6 @@
                i2c3 = &main_i2c3;
                i2c4 = &wkup_i2c0;
                i2c5 = &mcu_i2c0;
-               mdio-gpio0 = &mdio0;
                mmc0 = &sdhci0;
                mmc1 = &sdhci1;
                mmc2 = &sdhci2;
                };
        };
 
-       /* Workaround for errata i2329 - just use mdio bitbang */
-       mdio0: mdio {
-               compatible = "virtual,mdio-gpio";
-               pinctrl-names = "default";
-               pinctrl-0 = <&mdio0_pins_default>;
-               gpios = <&main_gpio0 86 GPIO_ACTIVE_HIGH>, /* MDC */
-                       <&main_gpio0 85 GPIO_ACTIVE_HIGH>; /* MDIO */
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               cpsw3g_phy0: ethernet-phy@0 {
-                       reg = <0>;
-               };
-
-               cpsw3g_phy1: ethernet-phy@1 {
-                       reg = <1>;
-                       reset-gpios = <&main_gpio1 5 GPIO_ACTIVE_LOW>;
-                       reset-assert-us = <25>;
-                       reset-deassert-us = <60000>; /* T2 */
-               };
-       };
 };
 
 &main_pmx0 {
 
        mdio0_pins_default: mdio0-default-pins {
                pinctrl-single,pins = <
-                       AM62X_IOPAD(0x0160, PIN_OUTPUT, 7) /* (AD24) MDIO0_MDC.GPIO0_86 */
-                       AM62X_IOPAD(0x015c, PIN_INPUT, 7) /* (AB22) MDIO0_MDIO.GPIO0_85 */
+                       AM62X_IOPAD(0x0160, PIN_OUTPUT, 0) /* (AD24) MDIO0_MDC */
+                       AM62X_IOPAD(0x015c, PIN_INPUT, 0) /* (AB22) MDIO0_MDIO */
                >;
        };
 
 };
 
 &usbss0 {
+       bootph-all;
        ti,vbus-divider;
        status = "okay";
 };
 
 &usb0 {
+       bootph-all;
        dr_mode = "peripheral";
 };
 
 };
 
 &cpsw3g_mdio {
-       /* Workaround for errata i2329 - Use mdio bitbang */
-       status = "disabled";
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&mdio0_pins_default>;
+
+       cpsw3g_phy0: ethernet-phy@0 {
+               reg = <0>;
+       };
+
+       cpsw3g_phy1: ethernet-phy@1 {
+               reg = <1>;
+               reset-gpios = <&main_gpio1 5 GPIO_ACTIVE_LOW>;
+               reset-assert-us = <25>;
+               reset-deassert-us = <60000>; /* T2 */
+       };
 };
 
 &main_gpio0 {
        bootph-all;
        pinctrl-names = "default";
        pinctrl-0 = <&emmc_pins_default>;
-       ti,driver-strength-ohm = <50>;
        disable-wp;
        status = "okay";
 };
 
        vmmc-supply = <&vdd_3v3_sd>;
        vqmmc-supply = <&vdd_sd_dv>;
-       ti,driver-strength-ohm = <50>;
        disable-wp;
        cd-gpios = <&main_gpio1 48 GPIO_ACTIVE_LOW>;
        cd-debounce-delay-ms = <100>;
        vmmc-supply = <&wlan_en>;
        pinctrl-names = "default";
        pinctrl-0 = <&wifi_pins_default>, <&wifi_32k_clk>;
-       bus-width = <4>;
        non-removable;
        ti,fails-without-test-cd;
        cap-power-off-card;
        keep-power-in-suspend;
-       ti,driver-strength-ohm = <50>;
        assigned-clocks = <&k3_clks 157 158>;
        assigned-clock-parents = <&k3_clks 157 160>;
        #address-cells = <1>;
index 4bc0134c987d48ece8cea6b4d028a5b29d87a922..a83a90497857662d7d0fc51e9d530949ffc51f79 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2022 - 2023 PHYTEC Messtechnik GmbH
+ * Copyright (C) 2022-2024 PHYTEC Messtechnik GmbH
  * Author: Wadim Egorov <w.egorov@phytec.de>
  *
  * Product homepage:
        cpsw3g_phy3: ethernet-phy@3 {
                compatible = "ethernet-phy-id2000.a231", "ethernet-phy-ieee802.3-c22";
                reg = <3>;
+               ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
                ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
                ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
        };
        vqmmc-supply = <&vddshv5_sdio>;
        pinctrl-names = "default";
        pinctrl-0 = <&main_mmc1_pins_default>;
-       ti,driver-strength-ohm = <50>;
        disable-wp;
        no-1-8-v;
        status = "okay";
index b18092497c9a5342576c9ce8ae3bbcf3712d8a11..ae81ebb39d02d6c5fb3a228f37ce619264f48e44 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * AM625 SK: https://www.ti.com/lit/zip/sprr448
  *
- * Copyright (C) 2021-2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index 4193c2b3eed6024807f267db3ab0491f841f33f3..4014add6320d516b8bfb4a178d681e1979a1680c 100644 (file)
@@ -1,10 +1,10 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM625 SoC family in Quad core configuration
  *
  * TRM: https://www.ti.com/lit/pdf/spruiv7
  *
- * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index f0b8c9ab14593fe7b87adf196813936e3ca85c8f..aa1e057082f0829f5d09dccdfcf596c486cb7230 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM62A SoC Family Main Domain peripherals
  *
- * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_main {
@@ -42,9 +42,8 @@
                };
        };
 
-       main_conf: syscon@100000 {
-               compatible = "ti,j721e-system-controller", "syscon", "simple-mfd";
-               reg = <0x00 0x00100000 0x00 0x20000>;
+       main_conf: bus@100000 {
+               compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
                ranges = <0x00 0x00 0x00100000 0x20000>;
                status = "disabled";
        };
 
+       sdhci0: mmc@fa10000 {
+               compatible = "ti,am62-sdhci";
+               reg = <0x00 0xfa10000 0x00 0x260>, <0x00 0xfa18000 0x00 0x134>;
+               interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+               power-domains = <&k3_pds 57 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 57 5>, <&k3_clks 57 6>;
+               clock-names = "clk_ahb", "clk_xin";
+               assigned-clocks = <&k3_clks 57 6>;
+               assigned-clock-parents = <&k3_clks 57 8>;
+               bus-width = <8>;
+               mmc-hs200-1_8v;
+               ti,clkbuf-sel = <0x7>;
+               ti,otap-del-sel-legacy = <0x0>;
+               ti,otap-del-sel-mmc-hs = <0x0>;
+               ti,otap-del-sel-hs200 = <0x6>;
+               status = "disabled";
+       };
+
        sdhci1: mmc@fa00000 {
                compatible = "ti,am62-sdhci";
                reg = <0x00 0xfa00000 0x00 0x260>, <0x00 0xfa08000 0x00 0x134>;
                power-domains = <&k3_pds 58 TI_SCI_PD_EXCLUSIVE>;
                clocks = <&k3_clks 58 5>, <&k3_clks 58 6>;
                clock-names = "clk_ahb", "clk_xin";
-               ti,trm-icp = <0x2>;
+               bus-width = <4>;
+               ti,clkbuf-sel = <0x7>;
                ti,otap-del-sel-legacy = <0x0>;
                ti,otap-del-sel-sd-hs = <0x0>;
                ti,otap-del-sel-sdr12 = <0xf>;
                ti,itap-del-sel-sd-hs = <0x0>;
                ti,itap-del-sel-sdr12 = <0x0>;
                ti,itap-del-sel-sdr25 = <0x0>;
-               ti,clkbuf-sel = <0x7>;
+               no-1-8-v;
+               status = "disabled";
+       };
+
+       sdhci2: mmc@fa20000 {
+               compatible = "ti,am62-sdhci";
+               reg = <0x00 0xfa20000 0x00 0x260>, <0x00 0xfa28000 0x00 0x134>;
+               interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+               power-domains = <&k3_pds 184 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 184 5>, <&k3_clks 184 6>;
+               clock-names = "clk_ahb", "clk_xin";
                bus-width = <4>;
+               ti,clkbuf-sel = <0x7>;
+               ti,otap-del-sel-legacy = <0x0>;
+               ti,otap-del-sel-sd-hs = <0x0>;
+               ti,otap-del-sel-sdr12 = <0xf>;
+               ti,otap-del-sel-sdr25 = <0xf>;
+               ti,otap-del-sel-sdr50 = <0xc>;
+               ti,otap-del-sel-sdr104 = <0x6>;
+               ti,otap-del-sel-ddr50 = <0x9>;
+               ti,itap-del-sel-legacy = <0x0>;
+               ti,itap-del-sel-sd-hs = <0x0>;
+               ti,itap-del-sel-sdr12 = <0x0>;
+               ti,itap-del-sel-sdr25 = <0x0>;
                no-1-8-v;
                status = "disabled";
        };
                power-domains = <&k3_pds 185 TI_SCI_PD_EXCLUSIVE>;
                status = "disabled";
        };
+
+       dss: dss@30200000 {
+               compatible = "ti,am62a7-dss";
+               reg = <0x00 0x30200000 0x00 0x1000>, /* common */
+                     <0x00 0x30202000 0x00 0x1000>, /* vidl1 */
+                     <0x00 0x30206000 0x00 0x1000>, /* vid */
+                     <0x00 0x30207000 0x00 0x1000>, /* ovr1 */
+                     <0x00 0x30208000 0x00 0x1000>, /* ovr2 */
+                     <0x00 0x3020a000 0x00 0x1000>, /* vp1: Tied OFF in the SoC */
+                     <0x00 0x3020b000 0x00 0x1000>, /* vp2: Used as DPI Out */
+                     <0x00 0x30201000 0x00 0x1000>; /* common1 */
+               reg-names = "common", "vidl1", "vid",
+                           "ovr1", "ovr2", "vp1", "vp2", "common1";
+               power-domains = <&k3_pds 186 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 186 6>,
+                        <&k3_clks 186 0>,
+                        <&k3_clks 186 2>;
+               clock-names = "fck", "vp1", "vp2";
+               interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+               status = "disabled";
+
+               dss_ports: ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+       };
 };
index a6d16a94088c72d46f31850347b3d9712b774f6b..8c36e56f41388377666e06b14a4412cec3de458a 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM625 SoC Family MCU Domain peripherals
  *
- * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_mcu {
index 85ce545633ea5f471b0ef824c2f5cc647d5c5dd5..c7486fb2a5b45cfa2bd7798eb4746ad2af8c390a 100644 (file)
@@ -1,4 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
 
 #include <dt-bindings/thermal/thermal.h>
 
index 4e8279fa01e15c368afc4458131038d86ee47c1b..f7bec484705ad61f894aa58d91c4e1bb4feb3029 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM62A SoC Family Wakeup Domain peripherals
  *
- * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_wakeup {
index 61a210ecd5ff10947afa7302fd4480371f395232..b1b884600293ff89d6c962c711bf6dc8872c9366 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM62A SoC Family
  *
- * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/gpio/gpio.h>
index 7b71425862958b31b5455ad75d199378a633bfa4..f241637a5642a0407921fa18b8d66a311bde1197 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * AM62A SK: https://www.ti.com/lit/zip/sprr459
  *
- * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
@@ -20,6 +20,7 @@
                serial0 = &wkup_uart0;
                serial2 = &main_uart0;
                serial3 = &main_uart1;
+               mmc0 = &sdhci0;
                mmc1 = &sdhci1;
        };
 
                clock-frequency = <12288000>;
        };
 
+       hdmi0: connector-hdmi {
+               compatible = "hdmi-connector";
+               label = "hdmi";
+               type = "a";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&sii9022_out>;
+                       };
+               };
+       };
+
        codec_audio: sound {
                compatible = "simple-audio-card";
                simple-audio-card,name = "AM62Ax-SKEVM";
 };
 
 &main_pmx0 {
+       main_dss0_pins_default: main-dss0-default-pins {
+               pinctrl-single,pins = <
+                       AM62AX_IOPAD(0x100, PIN_OUTPUT, 0) /* (V17) VOUT0_VSYNC */
+                       AM62AX_IOPAD(0x0f8, PIN_OUTPUT, 0) /* (T18) VOUT0_HSYNC */
+                       AM62AX_IOPAD(0x104, PIN_OUTPUT, 0) /* (AA22) VOUT0_PCLK */
+                       AM62AX_IOPAD(0x0fc, PIN_OUTPUT, 0) /* (U17) VOUT0_DE */
+                       AM62AX_IOPAD(0x0b8, PIN_OUTPUT, 0) /* (U22) VOUT0_DATA0 */
+                       AM62AX_IOPAD(0x0bc, PIN_OUTPUT, 0) /* (U21) VOUT0_DATA1 */
+                       AM62AX_IOPAD(0x0c0, PIN_OUTPUT, 0) /* (U20) VOUT0_DATA2 */
+                       AM62AX_IOPAD(0x0c4, PIN_OUTPUT, 0) /* (U19) VOUT0_DATA3 */
+                       AM62AX_IOPAD(0x0c8, PIN_OUTPUT, 0) /* (T19) VOUT0_DATA4 */
+                       AM62AX_IOPAD(0x0cc, PIN_OUTPUT, 0) /* (U18) VOUT0_DATA5 */
+                       AM62AX_IOPAD(0x0d0, PIN_OUTPUT, 0) /* (V22) VOUT0_DATA6 */
+                       AM62AX_IOPAD(0x0d4, PIN_OUTPUT, 0) /* (V21) VOUT0_DATA7 */
+                       AM62AX_IOPAD(0x0d8, PIN_OUTPUT, 0) /* (V19) VOUT0_DATA8 */
+                       AM62AX_IOPAD(0x0dc, PIN_OUTPUT, 0) /* (V18) VOUT0_DATA9 */
+                       AM62AX_IOPAD(0x0e0, PIN_OUTPUT, 0) /* (W22) VOUT0_DATA10 */
+                       AM62AX_IOPAD(0x0e4, PIN_OUTPUT, 0) /* (W21) VOUT0_DATA11 */
+                       AM62AX_IOPAD(0x0e8, PIN_OUTPUT, 0) /* (W20) VOUT0_DATA12 */
+                       AM62AX_IOPAD(0x0ec, PIN_OUTPUT, 0) /* (W19) VOUT0_DATA13 */
+                       AM62AX_IOPAD(0x0f0, PIN_OUTPUT, 0) /* (Y21) VOUT0_DATA14 */
+                       AM62AX_IOPAD(0x0f4, PIN_OUTPUT, 0) /* (Y22) VOUT0_DATA15 */
+                       AM62AX_IOPAD(0x05c, PIN_OUTPUT, 1) /* (P22) GPMC0_AD8.VOUT0_DATA16 */
+                       AM62AX_IOPAD(0x060, PIN_OUTPUT, 1) /* (R19) GPMC0_AD9.VOUT0_DATA17 */
+                       AM62AX_IOPAD(0x064, PIN_OUTPUT, 1) /* (R20) GPMC0_AD10.VOUT0_DATA18 */
+                       AM62AX_IOPAD(0x068, PIN_OUTPUT, 1) /* (R22) GPMC0_AD11.VOUT0_DATA19 */
+                       AM62AX_IOPAD(0x06c, PIN_OUTPUT, 1) /* (T22) GPMC0_AD12.VOUT0_DATA20 */
+                       AM62AX_IOPAD(0x070, PIN_OUTPUT, 1) /* (R21) GPMC0_AD13.VOUT0_DATA21 */
+                       AM62AX_IOPAD(0x074, PIN_OUTPUT, 1) /* (T20) GPMC0_AD14.VOUT0_DATA22 */
+                       AM62AX_IOPAD(0x078, PIN_OUTPUT, 1) /* (T21) GPMC0_AD15.VOUT0_DATA23 */
+               >;
+       };
+
        main_uart0_pins_default: main-uart0-default-pins {
                pinctrl-single,pins = <
                        AM62AX_IOPAD(0x1c8, PIN_INPUT, 0) /* (E14) UART0_RXD */
                >;
        };
 
+       main_mmc0_pins_default: main-mmc0-default-pins {
+               pinctrl-single,pins = <
+                       AM62AX_IOPAD(0x220, PIN_INPUT, 0) /* (Y3) MMC0_CMD */
+                       AM62AX_IOPAD(0x218, PIN_INPUT, 0) /* (AB1) MMC0_CLKLB */
+                       AM62AX_IOPAD(0x21c, PIN_INPUT, 0) /* (AB1) MMC0_CLK */
+                       AM62AX_IOPAD(0x214, PIN_INPUT, 0) /* (AA2) MMC0_DAT0 */
+                       AM62AX_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (AA1) MMC0_DAT1 */
+                       AM62AX_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (AA3) MMC0_DAT2 */
+                       AM62AX_IOPAD(0x208, PIN_INPUT_PULLUP, 0) /* (Y4) MMC0_DAT3 */
+                       AM62AX_IOPAD(0x204, PIN_INPUT_PULLUP, 0) /* (AB2) MMC0_DAT4 */
+                       AM62AX_IOPAD(0x200, PIN_INPUT_PULLUP, 0) /* (AC1) MMC0_DAT5 */
+                       AM62AX_IOPAD(0x1fc, PIN_INPUT_PULLUP, 0) /* (AD2) MMC0_DAT6 */
+                       AM62AX_IOPAD(0x1f8, PIN_INPUT_PULLUP, 0) /* (AC2) MMC0_DAT7 */
+               >;
+       };
+
        main_mmc1_pins_default: main-mmc1-default-pins {
                pinctrl-single,pins = <
                        AM62AX_IOPAD(0x23c, PIN_INPUT, 0) /* (A21) MMC1_CMD */
                                  "CSI_EN", "AUTO_100M_1000M_CONFIG",
                                  "CSI_VLDO_SEL", "SoC_WLAN_SDIO_RST";
        };
+
+       sii9022: bridge-hdmi@3b {
+               compatible = "sil,sii9022";
+               reg = <0x3b>;
+               interrupt-parent = <&exp1>;
+               interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
+               #sound-dai-cells = <0>;
+               sil,i2s-data-lanes = < 0 >;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               sii9022_in: endpoint {
+                                       remote-endpoint = <&dpi1_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               sii9022_out: endpoint {
+                                       remote-endpoint = <&hdmi_connector_in>;
+                               };
+                       };
+               };
+       };
 };
 
 &main_i2c2 {
        clock-frequency = <400000>;
 };
 
+&sdhci0 {
+       /* eMMC */
+       status = "okay";
+       non-removable;
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_mmc0_pins_default>;
+       disable-wp;
+};
+
 &sdhci1 {
        /* SD/MMC */
        status = "okay";
        vmmc-supply = <&vdd_mmc1>;
        pinctrl-names = "default";
        pinctrl-0 = <&main_mmc1_pins_default>;
-       ti,driver-strength-ohm = <50>;
        disable-wp;
 };
 
        tx-num-evt = <32>;
        rx-num-evt = <32>;
 };
+
+&dss {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_dss0_pins_default>;
+};
+
+&dss_ports {
+       /* VP2: DPI Output */
+       port@1 {
+               reg = <1>;
+
+               dpi1_out: endpoint {
+                       remote-endpoint = <&sii9022_in>;
+               };
+       };
+};
index 58f1c43edcf8f8962b607fa3eab9631198397223..f86a23404e6dde3ca90e41ac0efdb378948e6d50 100644 (file)
@@ -1,10 +1,10 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM62A7 SoC family in Quad core configuration
  *
  * TRM: https://www.ti.com/lit/zip/spruj16
  *
- * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index 4c51bae06b57eb58e26f291f214856f0e70d885e..7337a9e1353542bfcb8633ea1306defb54e4b476 100644 (file)
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree file for the AM62P main domain peripherals
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_main {
                };
        };
 
+       dmss_csi: bus@4e000000 {
+               compatible = "simple-bus";
+               ranges = <0x00 0x4e000000 0x00 0x4e000000 0x00 0x408000>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               dma-ranges;
+               ti,sci-dev-id = <198>;
+
+               inta_main_dmss_csi: interrupt-controller@4e400000 {
+                       compatible = "ti,sci-inta";
+                       reg = <0x00 0x4e400000 0x00 0x8000>;
+                       #interrupt-cells = <0>;
+                       interrupt-controller;
+                       interrupt-parent = <&gic500>;
+                       msi-controller;
+                       power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>;
+                       ti,sci = <&dmsc>;
+                       ti,sci-dev-id = <200>;
+                       ti,interrupt-ranges = <0 237 8>;
+                       ti,unmapped-event-sources = <&main_bcdma_csi>;
+               };
+
+               main_bcdma_csi: dma-controller@4e230000 {
+                       compatible = "ti,am62a-dmss-bcdma-csirx";
+                       reg = <0x00 0x4e230000 0x00 0x100>,
+                             <0x00 0x4e180000 0x00 0x8000>,
+                             <0x00 0x4e100000 0x00 0x10000>;
+                       reg-names = "gcfg", "rchanrt", "ringrt";
+                       #dma-cells = <3>;
+                       msi-parent = <&inta_main_dmss_csi>;
+                       power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>;
+                       ti,sci = <&dmsc>;
+                       ti,sci-dev-id = <199>;
+                       ti,sci-rm-range-rchan = <0x21>;
+               };
+       };
+
        dmsc: system-controller@44043000 {
                compatible = "ti,k2g-sci";
                ti,host-id = <12>;
                clock-names = "clk_ahb", "clk_xin";
                assigned-clocks = <&k3_clks 57 2>;
                assigned-clock-parents = <&k3_clks 57 4>;
-               ti,otap-del-sel-legacy = <0x0>;
+               bus-width = <8>;
+               mmc-ddr-1_8v;
+               mmc-hs200-1_8v;
+               mmc-hs400-1_8v;
+               ti,clkbuf-sel = <0x7>;
+               ti,strobe-sel = <0x77>;
+               ti,trm-icp = <0x8>;
+               ti,otap-del-sel-legacy = <0x1>;
+               ti,otap-del-sel-mmc-hs = <0x1>;
+               ti,otap-del-sel-ddr52 = <0x6>;
+               ti,otap-del-sel-hs200 = <0x8>;
+               ti,otap-del-sel-hs400 = <0x5>;
+               ti,itap-del-sel-legacy = <0x10>;
+               ti,itap-del-sel-mmc-hs = <0xa>;
+               ti,itap-del-sel-ddr52 = <0x3>;
                status = "disabled";
        };
 
                power-domains = <&k3_pds 58 TI_SCI_PD_EXCLUSIVE>;
                clocks = <&k3_clks 58 5>, <&k3_clks 58 6>;
                clock-names = "clk_ahb", "clk_xin";
-               ti,otap-del-sel-legacy = <0x8>;
+               bus-width = <4>;
+               ti,clkbuf-sel = <0x7>;
+               ti,otap-del-sel-legacy = <0x0>;
+               ti,otap-del-sel-sd-hs = <0x0>;
+               ti,otap-del-sel-sdr12 = <0xf>;
+               ti,otap-del-sel-sdr25 = <0xf>;
+               ti,otap-del-sel-sdr50 = <0xc>;
+               ti,otap-del-sel-ddr50 = <0x9>;
+               ti,otap-del-sel-sdr104 = <0x6>;
+               ti,itap-del-sel-legacy = <0x0>;
+               ti,itap-del-sel-sd-hs = <0x0>;
+               ti,itap-del-sel-sdr12 = <0x0>;
+               ti,itap-del-sel-sdr25 = <0x0>;
                status = "disabled";
        };
 
                power-domains = <&k3_pds 184 TI_SCI_PD_EXCLUSIVE>;
                clocks = <&k3_clks 184 5>, <&k3_clks 184 6>;
                clock-names = "clk_ahb", "clk_xin";
-               ti,otap-del-sel-legacy = <0x8>;
+               bus-width = <4>;
+               ti,clkbuf-sel = <0x7>;
+               ti,otap-del-sel-legacy = <0x0>;
+               ti,otap-del-sel-sd-hs = <0x0>;
+               ti,otap-del-sel-sdr12 = <0xf>;
+               ti,otap-del-sel-sdr25 = <0xf>;
+               ti,otap-del-sel-sdr50 = <0xc>;
+               ti,otap-del-sel-ddr50 = <0x9>;
+               ti,otap-del-sel-sdr104 = <0x6>;
+               ti,itap-del-sel-legacy = <0x0>;
+               ti,itap-del-sel-sd-hs = <0x0>;
+               ti,itap-del-sel-sdr12 = <0x0>;
+               ti,itap-del-sel-sdr25 = <0x0>;
                status = "disabled";
        };
 
                power-domains = <&k3_pds 192 TI_SCI_PD_EXCLUSIVE>;
                status = "disabled";
        };
+
+       ti_csi2rx0: ticsi2rx@30102000 {
+               compatible = "ti,j721e-csi2rx-shim";
+               reg = <0x00 0x30102000 0x00 0x1000>;
+               ranges;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               dmas = <&main_bcdma_csi 0 0x5000 0>;
+               dma-names = "rx0";
+               power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+
+               cdns_csi2rx0: csi-bridge@30101000 {
+                       compatible = "ti,j721e-csi2rx", "cdns,csi2rx";
+                       reg = <0x00 0x30101000 0x00 0x1000>;
+                       clocks = <&k3_clks 182 0>, <&k3_clks 182 3>, <&k3_clks 182 0>,
+                               <&k3_clks 182 0>, <&k3_clks 182 4>, <&k3_clks 182 4>;
+                       clock-names = "sys_clk", "p_clk", "pixel_if0_clk",
+                               "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk";
+                       phys = <&dphy0>;
+                       phy-names = "dphy";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               csi0_port0: port@0 {
+                                       reg = <0>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port1: port@1 {
+                                       reg = <1>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port2: port@2 {
+                                       reg = <2>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port3: port@3 {
+                                       reg = <3>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port4: port@4 {
+                                       reg = <4>;
+                                       status = "disabled";
+                               };
+                       };
+               };
+       };
+
+       dphy0: phy@30110000 {
+               compatible = "cdns,dphy-rx";
+               reg = <0x00 0x30110000 0x00 0x1100>;
+               #phy-cells = <0>;
+               power-domains = <&k3_pds 185 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+       };
+
+       vpu: video-codec@30210000 {
+               compatible = "ti,j721s2-wave521c", "cnm,wave521c";
+               reg = <0x00 0x30210000 0x00 0x10000>;
+               interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&k3_clks 204 2>;
+               power-domains = <&k3_pds 204 TI_SCI_PD_EXCLUSIVE>;
+       };
 };
index c4b0b91d70cf30f0026f86ff2e21675f8efd3e17..b973b550eb9dfca9951957febc519ea7b93c2694 100644 (file)
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree file for the AM62P MCU domain peripherals
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_mcu {
                ranges = <0x79000000 0x00 0x79000000 0x8000>,
                         <0x79020000 0x00 0x79020000 0x8000>;
                power-domains = <&k3_pds 7 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+
                mcu_r5fss0_core0: r5f@79000000 {
                        compatible = "ti,am62-r5f";
                        reg = <0x79000000 0x00008000>,
index 85ce545633ea5f471b0ef824c2f5cc647d5c5dd5..c7486fb2a5b45cfa2bd7798eb4746ad2af8c390a 100644 (file)
@@ -1,4 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
 
 #include <dt-bindings/thermal/thermal.h>
 
index 19f42b39394ee65e8f89d8cfaafb8beb84331486..a84756c336d0569081d2f382984ff95141ac7319 100644 (file)
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree file for the AM62P wakeup domain peripherals
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_wakeup {
@@ -78,6 +78,7 @@
                ranges = <0x78000000 0x00 0x78000000 0x8000>,
                         <0x78100000 0x00 0x78100000 0x8000>;
                power-domains = <&k3_pds 119 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
 
                wkup_r5fss0_core0: r5f@78000000 {
                        compatible = "ti,am62-r5f";
index 84ffe7b9dcaf36f126da7b500a9d70a35acf8799..94babc412575aedbc1c1bb8adf8306d4fe9c9b06 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM62P SoC Family
  *
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/gpio/gpio.h>
@@ -71,7 +71,7 @@
                         <0x00 0x43600000 0x00 0x43600000 0x00 0x00010000>, /* SA3 sproxy data */
                         <0x00 0x44043000 0x00 0x44043000 0x00 0x00000fe0>, /* TI SCI DEBUG */
                         <0x00 0x44860000 0x00 0x44860000 0x00 0x00040000>, /* SA3 sproxy config */
-                        <0x00 0x48000000 0x00 0x48000000 0x00 0x06400000>, /* DMSS */
+                        <0x00 0x48000000 0x00 0x48000000 0x00 0x06408000>, /* DMSS */
                         <0x00 0x60000000 0x00 0x60000000 0x00 0x08000000>, /* FSS0 DAT1 */
                         <0x00 0x70000000 0x00 0x70000000 0x00 0x00010000>, /* OCSRAM */
                         <0x01 0x00000000 0x01 0x00000000 0x00 0x00310000>, /* A53 PERIPHBASE */
index 1773c05f752cdfa87437e1c54d6c4f90c4e125a6..e86f34e835c1ad2d2410a648f2758a909aaa5f22 100644 (file)
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree file for the AM62P5-SK
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  *
  * Schematics: https://www.ti.com/lit/zip/sprr487
  */
        status = "okay";
        ti,driver-strength-ohm = <50>;
        disable-wp;
+       bootph-all;
 };
 
 &sdhci1 {
        vqmmc-supply = <&vddshv_sdio>;
        pinctrl-names = "default";
        pinctrl-0 = <&main_mmc1_pins_default>;
-       ti,driver-strength-ohm = <50>;
        disable-wp;
-       no-1-8-v;
        bootph-all;
 };
 
 };
 
 &cpsw3g_mdio {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_mdio1_pins_default>;
+       status = "okay";
+
        cpsw3g_phy0: ethernet-phy@0 {
                reg = <0>;
                ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
index 50147bb63e032809ff41afe9ea69120ae87c3117..41f479dca455567c91bbb3a0b75d13810ea11157 100644 (file)
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree file for the AM62P5 SoC family (quad core)
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  *
  * TRM: https://www.ti.com/lit/pdf/spruj83
  */
diff --git a/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra-gpio-fan.dtso b/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra-gpio-fan.dtso
new file mode 100644 (file)
index 0000000..f0b2fd4
--- /dev/null
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Copyright (C) 2024 PHYTEC America LLC
+ * Author: Garrett Giordano <ggiordano@phytec.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/thermal/thermal.h>
+#include "k3-pinctrl.h"
+
+&{/} {
+       fan: gpio-fan {
+               compatible = "gpio-fan";
+               gpio-fan,speed-map = <0 0 8600 1>;
+               gpios = <&main_gpio0 40 GPIO_ACTIVE_LOW>;
+               #cooling-cells = <2>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&gpio_fan_pins_default>;
+       };
+};
+
+&main_pmx0 {
+       gpio_fan_pins_default: gpio-fan-default-pins {
+               pinctrl-single,pins = <
+                       AM62X_IOPAD(0x0a4, PIN_OUTPUT, 7) /* (M22) GPMC0_DIR.GPIO0_40 */
+               >;
+       };
+};
+
+&thermal_zones {
+       main0_thermal: main0-thermal {
+               trips {
+                       main0_thermal_trip0: main0-thermal-trip {
+                               temperature = <65000>;  /* millicelsius */
+                               hysteresis = <2000>;    /* millicelsius */
+                               type = "active";
+                       };
+               };
+
+               cooling-maps {
+                       map0 {
+                               trip = <&main0_thermal_trip0>;
+                               cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                       };
+               };
+       };
+};
index 33768c02d8eb16c3992534b05d20106ae59e867d..3c45782ab2b785c65d2f958f0b0ac13cfb4f0fc4 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Common dtsi for AM62x SK and derivatives
  *
- * Copyright (C) 2021-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/leds/common.h>
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&main_mmc0_pins_default>;
-       ti,driver-strength-ohm = <50>;
        disable-wp;
 };
 
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&main_mmc1_pins_default>;
-       ti,driver-strength-ohm = <50>;
        disable-wp;
 };
 
 };
 
 &usbss0 {
+       bootph-all;
        status = "okay";
        ti,vbus-divider;
 };
 };
 
 &usb0 {
+       bootph-all;
        #address-cells = <1>;
        #size-cells = <0>;
        usb-role-switch;
index 6f4cd73c2f4333d297af127bea76ca49b297f44f..76ca02127f95ff90dbeedf5107fd89cc606de1f9 100644 (file)
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * IMX219 (RPi v2) Camera Module
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index 9323a4b38389e0ab3ffaaef624df275a518afd89..ccc7f5e43184fa8c5580065ae2fd0e1f0f914c0a 100644 (file)
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * ALINX AN5641 & Digilent PCam 5C - OV5640 camera module
- * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index dcaa33a4c8d35431891d0f72da222950546a9a8f..4eaf9d757dd0ad3ba9b575f7355f7419bddcad6c 100644 (file)
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Technexion TEVI-OV5640-*-RPI - OV5640 camera module
- * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index 43a0ddc123e57513d690a8e6c09fa11515fed73e..18c3082f68e6ea0c6b9ad1402f17ffff674998bc 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /**
  * Audio playback via HDMI for AM625-SK and AM62-LP SK.
  *
@@ -6,7 +6,7 @@
  * AM625 SK: https://www.ti.com/tool/SK-AM62
  * AM62-LP SK: https://www.ti.com/tool/SK-AM62-LP
  *
- * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index e348114f42e017cfaa3dd02ab20e06e12dfed138..6f9aa5e02138f4613d7b8da9cf8a6841710ad571 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM642 SoC Family Main Domain peripherals
  *
- * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/phy/phy-cadence.h>
                        reg = <0x00000014 0x4>;
                };
 
-               serdes_ln_ctrl: mux-controller {
-                       compatible = "mmio-mux";
+               serdes_ln_ctrl: mux-controller@4080 {
+                       compatible = "reg-mux";
+                       reg = <0x4080 0x4>;
                        #mux-control-cells = <1>;
-                       mux-reg-masks = <0x4080 0x3>; /* SERDES0 lane0 select */
+                       mux-reg-masks = <0x0 0x3>; /* SERDES0 lane0 select */
                };
 
                phy_gmii_sel: phy@4044 {
                power-domains = <&k3_pds 57 TI_SCI_PD_EXCLUSIVE>;
                clocks = <&k3_clks 57 0>, <&k3_clks 57 1>;
                clock-names = "clk_ahb", "clk_xin";
+               bus-width = <8>;
                mmc-ddr-1_8v;
                mmc-hs200-1_8v;
+               ti,clkbuf-sel = <0x7>;
                ti,trm-icp = <0x2>;
                ti,otap-del-sel-legacy = <0x0>;
                ti,otap-del-sel-mmc-hs = <0x0>;
                ti,otap-del-sel-ddr52 = <0x6>;
                ti,otap-del-sel-hs200 = <0x7>;
+               ti,itap-del-sel-legacy = <0x10>;
+               ti,itap-del-sel-mmc-hs = <0xa>;
+               ti,itap-del-sel-ddr52 = <0x3>;
                status = "disabled";
        };
 
                power-domains = <&k3_pds 58 TI_SCI_PD_EXCLUSIVE>;
                clocks = <&k3_clks 58 3>, <&k3_clks 58 4>;
                clock-names = "clk_ahb", "clk_xin";
-               ti,trm-icp = <0x2>;
+               bus-width = <4>;
+               ti,clkbuf-sel = <0x7>;
                ti,otap-del-sel-legacy = <0x0>;
-               ti,otap-del-sel-sd-hs = <0xf>;
+               ti,otap-del-sel-sd-hs = <0x0>;
                ti,otap-del-sel-sdr12 = <0xf>;
                ti,otap-del-sel-sdr25 = <0xf>;
                ti,otap-del-sel-sdr50 = <0xc>;
                ti,otap-del-sel-sdr104 = <0x6>;
                ti,otap-del-sel-ddr50 = <0x9>;
-               ti,clkbuf-sel = <0x7>;
+               ti,itap-del-sel-legacy = <0x0>;
+               ti,itap-del-sel-sd-hs = <0x0>;
+               ti,itap-del-sel-sdr12 = <0x0>;
+               ti,itap-del-sel-sdr25 = <0x0>;
                status = "disabled";
        };
 
                status = "disabled";
        };
 
-       pcie0_ep: pcie-ep@f102000 {
-               compatible = "ti,am64-pcie-ep", "ti,j721e-pcie-ep";
-               reg = <0x00 0x0f102000 0x00 0x1000>,
-                     <0x00 0x0f100000 0x00 0x400>,
-                     <0x00 0x0d000000 0x00 0x00800000>,
-                     <0x00 0x68000000 0x00 0x08000000>;
-               reg-names = "intd_cfg", "user_cfg", "reg", "mem";
-               interrupt-names = "link_state";
-               interrupts = <GIC_SPI 203 IRQ_TYPE_EDGE_RISING>;
-               ti,syscon-pcie-ctrl = <&main_conf 0x4070>;
-               max-link-speed = <2>;
-               num-lanes = <1>;
-               power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>;
-               clocks = <&k3_clks 114 0>;
-               clock-names = "fck";
-               max-functions = /bits/ 8 <1>;
-               status = "disabled";
-       };
-
        epwm0: pwm@23000000 {
                compatible = "ti,am64-epwm", "ti,am3352-ehrpwm";
                #pwm-cells = <3>;
                        };
                };
 
+               icssg0_iep0: iep@2e000 {
+                       compatible = "ti,am654-icss-iep";
+                       reg = <0x2e000 0x1000>;
+                       clocks = <&icssg0_iepclk_mux>;
+               };
+
+               icssg0_iep1: iep@2f000 {
+                       compatible = "ti,am654-icss-iep";
+                       reg = <0x2f000 0x1000>;
+                       clocks = <&icssg0_iepclk_mux>;
+               };
+
                icssg0_mii_rt: mii-rt@32000 {
                        compatible = "ti,pruss-mii", "syscon";
                        reg = <0x32000 0x100>;
                        };
                };
 
+               icssg1_iep0: iep@2e000 {
+                       compatible = "ti,am654-icss-iep";
+                       reg = <0x2e000 0x1000>;
+                       clocks = <&icssg1_iepclk_mux>;
+               };
+
+               icssg1_iep1: iep@2f000 {
+                       compatible = "ti,am654-icss-iep";
+                       reg = <0x2f000 0x1000>;
+                       clocks = <&icssg1_iepclk_mux>;
+               };
+
                icssg1_mii_rt: mii-rt@32000 {
                        compatible = "ti,pruss-mii", "syscon";
                        reg = <0x32000 0x100>;
index b9508072bebb526885cd54dc25dea49cd905dc08..ec17285869da6ec65a6a2642d1b8895f0c53ba30 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM64 SoC Family MCU Domain peripherals
  *
- * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_mcu {
index 1678e74cb750e8c2eea612a6ddc37747fa225eb5..125e507966fb03b9d079407b2594c4da3ecd65ff 100644 (file)
@@ -1,9 +1,9 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2021 PHYTEC America, LLC - https://www.phytec.com
+ * Copyright (C) 2021-2024 PHYTEC America, LLC - https://www.phytec.com
  * Author: Matt McKee <mmckee@phytec.com>
  *
- * Copyright (C) 2022 PHYTEC Messtechnik GmbH
+ * Copyright (C) 2022-2024 PHYTEC Messtechnik GmbH
  * Author: Wadim Egorov <w.egorov@phytec.de>
  *
  * Product homepage:
        disable-wp;
        keep-power-in-suspend;
 };
+
+&tscadc0 {
+       status = "okay";
+       adc {
+               ti,adc-channels = <0 1 2 3 4 5 6 7>;
+       };
+};
index 036db56ba7977a076449d88c1877ee4eba6ba05e..b1cd5542428cfd99d56758d8e2a7f1b4d26a8d4d 100644 (file)
@@ -1,4 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
 
 #include <dt-bindings/thermal/thermal.h>
 
index 0187c42aed4f3693c1b8a4ff5f448a1ed4503047..74e56cc68d46d8e89ba64deeec5df0b4310cba56 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM642 SoC Family
  *
- * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/gpio/gpio.h>
diff --git a/arch/arm64/boot/dts/ti/k3-am642-evm-icssg1-dualemac.dtso b/arch/arm64/boot/dts/ti/k3-am642-evm-icssg1-dualemac.dtso
new file mode 100644 (file)
index 0000000..af2fd3e
--- /dev/null
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/**
+ * DT overlay for enabling 2nd ICSSG1 port on AM642 EVM
+ *
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "k3-pinctrl.h"
+
+&{/} {
+       aliases {
+               ethernet1 = "/icssg1-eth/ethernet-ports/port@1";
+       };
+
+       mdio-mux-2 {
+               compatible = "mdio-mux-multiplexer";
+               mux-controls = <&mdio_mux>;
+               mdio-parent-bus = <&icssg1_mdio>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               mdio@0 {
+                       reg = <0x0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       icssg1_phy2: ethernet-phy@3 {
+                               reg = <3>;
+                               tx-internal-delay-ps = <250>;
+                               rx-internal-delay-ps = <2000>;
+                       };
+               };
+       };
+};
+
+&main_pmx0 {
+       icssg1_rgmii2_pins_default: icssg1-rgmii2-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x0108, PIN_INPUT, 2) /* (W11) PRG1_PRU1_GPO0.RGMII2_RD0 */
+                       AM64X_IOPAD(0x010c, PIN_INPUT, 2) /* (V11) PRG1_PRU1_GPO1.RGMII2_RD1 */
+                       AM64X_IOPAD(0x0110, PIN_INPUT, 2) /* (AA12) PRG1_PRU1_GPO2.RGMII2_RD2 */
+                       AM64X_IOPAD(0x0114, PIN_INPUT, 2) /* (Y12) PRG1_PRU1_GPO3.RGMII2_RD3 */
+                       AM64X_IOPAD(0x0120, PIN_INPUT, 2) /* (U11) PRG1_PRU1_GPO6.RGMII2_RXC */
+                       AM64X_IOPAD(0x0118, PIN_INPUT, 2) /* (W12) PRG1_PRU1_GPO4.RGMII2_RX_CTL */
+                       AM64X_IOPAD(0x0134, PIN_OUTPUT, 2) /* (AA10) PRG1_PRU1_GPO11.RGMII2_TD0 */
+                       AM64X_IOPAD(0x0138, PIN_OUTPUT, 2) /* (V10) PRG1_PRU1_GPO12.RGMII2_TD1 */
+                       AM64X_IOPAD(0x013c, PIN_OUTPUT, 2) /* (U10) PRG1_PRU1_GPO13.RGMII2_TD2 */
+                       AM64X_IOPAD(0x0140, PIN_OUTPUT, 2) /* (AA11) PRG1_PRU1_GPO14.RGMII2_TD3 */
+                       AM64X_IOPAD(0x0148, PIN_OUTPUT, 2) /* (Y10) PRG1_PRU1_GPO16.RGMII2_TXC */
+                       AM64X_IOPAD(0x0144, PIN_OUTPUT, 2) /* (Y11) PRG1_PRU1_GPO15.RGMII2_TX_CTL */
+               >;
+       };
+};
+
+&cpsw3g {
+       pinctrl-0 = <&rgmii1_pins_default>;
+};
+
+&cpsw_port2 {
+       status = "disabled";
+};
+
+&mdio_mux_1 {
+       status = "disabled";
+};
+
+&icssg1_eth {
+       pinctrl-0 = <&icssg1_rgmii1_pins_default>, <&icssg1_rgmii2_pins_default>;
+};
+
+&icssg1_emac1 {
+       status = "okay";
+       phy-handle = <&icssg1_phy2>;
+       phy-mode = "rgmii-id";
+};
index 8c5651d2cf5ddc7033d51eb0701dd103de66a076..53fe1d065ddbbe2fb616d50d5f75685b0b66578f 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
@@ -32,6 +32,7 @@
                mmc1 = &sdhci1;
                ethernet0 = &cpsw_port1;
                ethernet1 = &cpsw_port2;
+               ethernet2 = &icssg1_emac0;
        };
 
        memory@80000000 {
                mux-gpios = <&exp1 12 GPIO_ACTIVE_HIGH>;
        };
 
-       mdio-mux-1 {
+       mdio_mux_1: mdio-mux-1 {
                compatible = "mdio-mux-multiplexer";
                mux-controls = <&mdio_mux>;
                mdio-parent-bus = <&cpsw3g_mdio>;
                max-bitrate = <5000000>;
                standby-gpios = <&exp1 9 GPIO_ACTIVE_HIGH>;
        };
+
+       icssg1_eth: icssg1-eth {
+               compatible = "ti,am642-icssg-prueth";
+               pinctrl-names = "default";
+               pinctrl-0 = <&icssg1_rgmii1_pins_default>;
+               sram = <&oc_sram>;
+               ti,prus = <&pru1_0>, <&rtu1_0>, <&tx_pru1_0>, <&pru1_1>, <&rtu1_1>, <&tx_pru1_1>;
+               firmware-name = "ti-pruss/am64x-sr2-pru0-prueth-fw.elf",
+                               "ti-pruss/am64x-sr2-rtu0-prueth-fw.elf",
+                               "ti-pruss/am64x-sr2-txpru0-prueth-fw.elf",
+                               "ti-pruss/am64x-sr2-pru1-prueth-fw.elf",
+                               "ti-pruss/am64x-sr2-rtu1-prueth-fw.elf",
+                               "ti-pruss/am64x-sr2-txpru1-prueth-fw.elf";
+
+               ti,pruss-gp-mux-sel = <2>,      /* MII mode */
+                                     <2>,
+                                     <2>,
+                                     <2>,      /* MII mode */
+                                     <2>,
+                                     <2>;
+               ti,mii-g-rt = <&icssg1_mii_g_rt>;
+               ti,mii-rt = <&icssg1_mii_rt>;
+               ti,iep = <&icssg1_iep0>,  <&icssg1_iep1>;
+               interrupt-parent = <&icssg1_intc>;
+               interrupts = <24 0 2>, <25 1 3>;
+               interrupt-names = "tx_ts0", "tx_ts1";
+               dmas = <&main_pktdma 0xc200 15>, /* egress slice 0 */
+                      <&main_pktdma 0xc201 15>, /* egress slice 0 */
+                      <&main_pktdma 0xc202 15>, /* egress slice 0 */
+                      <&main_pktdma 0xc203 15>, /* egress slice 0 */
+                      <&main_pktdma 0xc204 15>, /* egress slice 1 */
+                      <&main_pktdma 0xc205 15>, /* egress slice 1 */
+                      <&main_pktdma 0xc206 15>, /* egress slice 1 */
+                      <&main_pktdma 0xc207 15>, /* egress slice 1 */
+                      <&main_pktdma 0x4200 15>, /* ingress slice 0 */
+                      <&main_pktdma 0x4201 15>; /* ingress slice 1 */
+               dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3",
+                           "tx1-0", "tx1-1", "tx1-2", "tx1-3",
+                           "rx0", "rx1";
+
+               ethernet-ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       icssg1_emac0: port@0 {
+                               reg = <0>;
+                               phy-handle = <&icssg1_phy1>;
+                               phy-mode = "rgmii-id";
+                               /* Filled in by bootloader */
+                               local-mac-address = [00 00 00 00 00 00];
+                       };
+                       icssg1_emac1: port@1 {
+                               reg = <1>;
+                               /* Filled in by bootloader */
+                               local-mac-address = [00 00 00 00 00 00];
+                               status = "disabled";
+                       };
+               };
+       };
 };
 
 &main_pmx0 {
                        AM64X_IOPAD(0x0030, PIN_OUTPUT_PULLUP, 7) /* (L18) OSPI0_CSN1.GPIO0_12 */
                >;
        };
+
+       icssg1_mdio1_pins_default: icssg1-mdio1-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x015c, PIN_OUTPUT, 0) /* (Y6) PRG1_MDIO0_MDC */
+                       AM64X_IOPAD(0x0158, PIN_INPUT, 0) /* (AA6) PRG1_MDIO0_MDIO */
+               >;
+       };
+
+       icssg1_rgmii1_pins_default: icssg1-rgmii1-default-pins{
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x00b8, PIN_INPUT, 2) /* (Y7) PRG1_PRU0_GPO0.PRG1_RGMII1_RD0 */
+                       AM64X_IOPAD(0x00bc, PIN_INPUT, 2) /* (U8) PRG1_PRU0_GPO1.PRG1_RGMII1_RD1 */
+                       AM64X_IOPAD(0x00c0, PIN_INPUT, 2) /* (W8) PRG1_PRU0_GPO2.PRG1_RGMII1_RD2 */
+                       AM64X_IOPAD(0x00c4, PIN_INPUT, 2) /* (V8) PRG1_PRU0_GPO3.PRG1_RGMII1_RD3 */
+                       AM64X_IOPAD(0x00d0, PIN_INPUT, 2) /* (AA7) PRG1_PRU0_GPO6.PRG1_RGMII1_RXC */
+                       AM64X_IOPAD(0x00c8, PIN_INPUT, 2) /* (Y8) PRG1_PRU0_GPO4.PRG1_RGMII1_RX_CTL */
+                       AM64X_IOPAD(0x00e4, PIN_INPUT, 2) /* (AA8) PRG1_PRU0_GPO11.PRG1_RGMII1_TD0 */
+                       AM64X_IOPAD(0x00e8, PIN_INPUT, 2) /* (U9) PRG1_PRU0_GPO12.PRG1_RGMII1_TD1 */
+                       AM64X_IOPAD(0x00ec, PIN_INPUT, 2) /* (W9) PRG1_PRU0_GPO13.PRG1_RGMII1_TD2 */
+                       AM64X_IOPAD(0x00f0, PIN_INPUT, 2) /* (AA9) PRG1_PRU0_GPO14.PRG1_RGMII1_TD3 */
+                       AM64X_IOPAD(0x00f8, PIN_INPUT, 2) /* (V9) PRG1_PRU0_GPO16.PRG1_RGMII1_TXC */
+                       AM64X_IOPAD(0x00f4, PIN_INPUT, 2) /* (Y9) PRG1_PRU0_GPO15.PRG1_RGMII1_TX_CTL */
+               >;
+       };
 };
 
 &main_uart0 {
 /* eMMC */
 &sdhci0 {
        status = "okay";
-       bus-width = <8>;
        non-removable;
        ti,driver-strength-ohm = <50>;
        disable-wp;
+       bootph-all;
 };
 
 /* SD/MMC */
        status = "okay";
        vmmc-supply = <&vdd_mmc1>;
        pinctrl-names = "default";
-       bus-width = <4>;
        pinctrl-0 = <&main_mmc1_pins_default>;
-       ti,driver-strength-ohm = <50>;
        disable-wp;
 };
 
 };
 
 &main_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core0>;
        memory-region = <&main_r5fss0_core0_dma_memory_region>,
                        <&main_r5fss0_core0_memory_region>;
 };
 
 &main_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core1>;
        memory-region = <&main_r5fss0_core1_dma_memory_region>,
                        <&main_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss1_core0 {
-       mboxes = <&mailbox0_cluster4>, <&mbox_main_r5fss1_core0>;
+       mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core0>;
        memory-region = <&main_r5fss1_core0_dma_memory_region>,
                        <&main_r5fss1_core0_memory_region>;
 };
 
 &main_r5fss1_core1 {
-       mboxes = <&mailbox0_cluster4>, <&mbox_main_r5fss1_core1>;
+       mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core1>;
        memory-region = <&main_r5fss1_core1_dma_memory_region>,
                        <&main_r5fss1_core1_memory_region>;
 };
        num-lanes = <1>;
 };
 
-&pcie0_ep {
-       phys = <&serdes0_pcie_link>;
-       phy-names = "pcie-phy";
-       num-lanes = <1>;
-};
-
 &ecap0 {
        status = "okay";
        /* PWM is available on Pin 1 of header J12 */
        pinctrl-0 = <&main_mcan1_pins_default>;
        phys = <&transceiver2>;
 };
+
+&icssg1_mdio {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&icssg1_mdio1_pins_default>;
+
+       icssg1_phy1: ethernet-phy@f {
+               reg = <0xf>;
+               tx-internal-delay-ps = <250>;
+               rx-internal-delay-ps = <2000>;
+       };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-am642-hummingboard-t-pcie.dtso b/arch/arm64/boot/dts/ti/k3-am642-hummingboard-t-pcie.dtso
new file mode 100644 (file)
index 0000000..bd9a5ca
--- /dev/null
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Josua Mayer <josua@solid-run.com>
+ *
+ * Overlay for SolidRun AM642 HummingBoard-T to enable PCI-E.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/phy/phy.h>
+
+#include "k3-serdes.h"
+
+&pcie0_rc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie0_default_pins>;
+       reset-gpios = <&main_gpio1 15 GPIO_ACTIVE_HIGH>;
+       phys = <&serdes0_link>;
+       phy-names = "pcie-phy";
+       num-lanes = <1>;
+       status = "okay";
+};
+
+&serdes0 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       serdes0_link: phy@0 {
+               reg = <0>;
+               cdns,num-lanes = <1>;
+               cdns,phy-type = <PHY_TYPE_PCIE>;
+               #phy-cells = <0>;
+               resets = <&serdes_wiz0 1>;
+       };
+};
+
+&serdes_ln_ctrl {
+       idle-states = <AM64_SERDES0_LANE0_PCIE0>;
+};
+
+&serdes_mux {
+       idle-state = <1>;
+};
diff --git a/arch/arm64/boot/dts/ti/k3-am642-hummingboard-t-usb3.dtso b/arch/arm64/boot/dts/ti/k3-am642-hummingboard-t-usb3.dtso
new file mode 100644 (file)
index 0000000..ffcc3bd
--- /dev/null
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Josua Mayer <josua@solid-run.com>
+ *
+ * Overlay for SolidRun AM642 HummingBoard-T to enable USB-3.1.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/phy/phy.h>
+
+#include "k3-serdes.h"
+
+&serdes0 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       serdes0_link: phy@0 {
+               reg = <0>;
+               cdns,num-lanes = <1>;
+               cdns,phy-type = <PHY_TYPE_USB3>;
+               #phy-cells = <0>;
+               resets = <&serdes_wiz0 1>;
+       };
+};
+
+&serdes_ln_ctrl {
+       idle-states = <AM64_SERDES0_LANE0_USB>;
+};
+
+&serdes_mux {
+       idle-state = <0>;
+};
+
+&usbss0 {
+       /delete-property/ ti,usb2-only;
+};
+
+&usb0 {
+       maximum-speed = "super-speed";
+       phys = <&serdes0_link>;
+       phy-names = "cdns3,usb3-phy";
+};
diff --git a/arch/arm64/boot/dts/ti/k3-am642-hummingboard-t.dts b/arch/arm64/boot/dts/ti/k3-am642-hummingboard-t.dts
new file mode 100644 (file)
index 0000000..234d76e
--- /dev/null
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Josua Mayer <josua@solid-run.com>
+ *
+ * DTS for SolidRun AM642 HummingBoard-T,
+ * running on Cortex A53.
+ *
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/phy/phy.h>
+
+#include "k3-am642.dtsi"
+#include "k3-am642-sr-som.dtsi"
+
+/ {
+       model = "SolidRun AM642 HummingBoard-T";
+       compatible = "solidrun,am642-hummingboard-t", "solidrun,am642-sr-som", "ti,am642";
+
+       aliases {
+               serial5 = &main_uart3;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&leds_default_pins>;
+
+               /* D24 */
+               led1: led-1 {
+                       label = "led1";
+                       gpios = <&main_gpio0 29 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               /* D25 */
+               led2: led-2 {
+                       label = "led2";
+                       gpios = <&main_gpio0 30 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               /* D26 */
+               led3: led-3 {
+                       label = "led3";
+                       gpios = <&main_gpio0 33 GPIO_ACTIVE_HIGH>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+       };
+
+       regulator-m2-3v3 {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&regulator_pcie_3v3_default_pins>;
+               regulator-name = "m2-3v3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&main_gpio1 17 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-always-on;
+       };
+
+       regulator-vpp-1v8 {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&regulator_vpp_1v8_default_pins>;
+               regulator-name = "vpp-1v8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               gpio = <&main_gpio1 78 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       serdes_mux: mux-controller {
+               compatible = "gpio-mux";
+               pinctrl-names = "default";
+               pinctrl-0 = <&serdes_mux_default_pins>;
+               #mux-control-cells = <0>;
+               /*
+                * Mux has 2 IOs:
+                * - select: 0 = USB-3 (M2); 1 = PCIE (M1)
+                * - shutdown: 0 = active; 1 = disabled (high impedance)
+                */
+               mux-gpios = <&main_gpio1 40 GPIO_ACTIVE_HIGH>, <&main_gpio1 41 GPIO_ACTIVE_HIGH>;
+               /* default disabled */
+               idle-state = <2>;
+       };
+};
+
+&main_gpio0 {
+       m2-reset-hog {
+               gpio-hog;
+               gpios = <12 GPIO_ACTIVE_LOW>;
+               output-low; /* deasserted */
+               line-name = "m2-reset";
+       };
+
+       m1-m2-w-disable1-hog {
+               gpio-hog;
+               gpios = <32 GPIO_ACTIVE_LOW>;
+               output-low; /* deasserted */
+               line-name = "m1-m2-pcie-w-disable1";
+       };
+
+       m1-m2-w-disable2-hog {
+               gpio-hog;
+               gpios = <34 GPIO_ACTIVE_LOW>;
+               output-low; /* deasserted */
+               line-name = "m1-m2-pcie-w-disable2";
+       };
+};
+
+&main_gpio1 {
+       m1-pcie-clkreq0-hog {
+               gpio-hog;
+               gpios = <11 GPIO_ACTIVE_LOW>;
+               input;
+               line-name = "m1-pcie-clkreq0";
+       };
+
+       m2-pcie-clkreq-hog {
+               gpio-hog;
+               gpios = <35 GPIO_ACTIVE_LOW>;
+               input;
+               line-name = "m2-pcie-clkreq";
+       };
+};
+
+&main_i2c0 {
+       pinctrl-0 = <&main_i2c0_default_pins>, <&main_i2c0_int_default_pins>;
+
+       humidity-sensor@41 {
+               compatible = "ti,hdc2010";
+               reg = <0x41>;
+               interrupt-parent = <&main_gpio0>;
+               interrupts = <37 IRQ_TYPE_EDGE_FALLING>;
+       };
+
+       light-sensor@44 {
+               compatible = "ti,opt3001";
+               reg = <0x44>;
+               interrupt-parent = <&main_gpio0>;
+               interrupts = <37 IRQ_TYPE_EDGE_FALLING>;
+       };
+
+       /* charger@6a */
+};
+
+&main_i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_i2c1_default_pins>;
+       status = "okay";
+
+       rtc@69 {
+               compatible = "abracon,abx80x";
+               reg = <0x69>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&rtc_int_default_pins>;
+               abracon,tc-diode = "schottky";
+               abracon,tc-resistor = <3>;
+               interrupt-parent = <&main_gpio0>;
+               interrupts = <44 IRQ_TYPE_EDGE_FALLING>;
+       };
+};
+
+&main_mcan0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_mcan0_default_pins>;
+       status = "okay";
+
+       can-transceiver {
+               max-bitrate = <8000000>;
+       };
+};
+
+&main_mcan1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_mcan1_default_pins>;
+       status = "okay";
+
+       can-transceiver {
+               max-bitrate = <8000000>;
+       };
+};
+
+&main_pmx0 {
+       leds_default_pins: leds-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x0074, PIN_OUTPUT, 7) /* GPMC0_AD14.GPIO0_29 */
+                       AM64X_IOPAD(0x0078, PIN_OUTPUT, 7) /* GPMC0_AD15.GPIO0_30 */
+                       AM64X_IOPAD(0x0088, PIN_OUTPUT, 7) /* GPMC0_OEn_REn.GPIO0_33 */
+               >;
+       };
+
+       main_i2c0_int_default_pins: main-i2c0-int-default-pins {
+               pinctrl-single,pins = <
+                       /* external pull-up on Carrier */
+                       AM64X_IOPAD(0x0098, PIN_INPUT, 7) /* GPMC0_WAIT0.GPIO0_37 */
+               >;
+       };
+
+       main_i2c1_default_pins: main-i2c1-default-pins {
+               pinctrl-single,pins = <
+                       /* external pull-up on SoM */
+                       AM64X_IOPAD(0x0268, PIN_INPUT, 0) /* I2C1_SCL.I2C1_SCL */
+                       AM64X_IOPAD(0x026c, PIN_INPUT, 0) /* I2C1_SDA.I2C1_SDA */
+               >;
+       };
+
+       main_mcan0_default_pins: main-mcan0-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x0254, PIN_INPUT, 0) /* MCAN0_RX.MCAN0_RX */
+                       AM64X_IOPAD(0x0250, PIN_OUTPUT, 0) /* MCAN0_TX.MCAN0_TX */
+               >;
+       };
+
+       main_mcan1_default_pins: main-mcan1-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x025c, PIN_INPUT, 0) /* MCAN1_RX.MCAN1_RX */
+                       AM64X_IOPAD(0x0258, PIN_OUTPUT, 0) /* MCAN1_TX.MCAN1_TX */
+               >;
+       };
+
+       main_uart3_default_pins: main-uart3-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x016c, PIN_INPUT, 10) /* PRG0_PRU0_GPO3.UART3_CTSn */
+                       AM64X_IOPAD(0x0170, PIN_OUTPUT, 10) /* PRG0_PRU0_GPO4.UART3_TXD */
+                       AM64X_IOPAD(0x0174, PIN_OUTPUT, 10) /* PRG0_PRU0_GPO5.UART3_RTSn */
+                       AM64X_IOPAD(0x01ac, PIN_INPUT, 10) /* PRG0_PRU0_GPO19.UART3_RXD */
+               >;
+       };
+
+       pcie0_default_pins: pcie0-default-pins {
+               pinctrl-single,pins = <
+                       /* connector M2 RESET */
+                       AM64X_IOPAD(0x0030, PIN_OUTPUT, 7) /* OSPI0_CSn1.GPIO0_12 */
+                       /* connectors M1 & M2 W_DISABLE1 */
+                       AM64X_IOPAD(0x0084, PIN_OUTPUT, 7) /* GPMC0_ADVN_ALE.GPIO0_32 */
+                       /* connectors M1 & M2 W_DISABLE2 */
+                       AM64X_IOPAD(0x008c, PIN_OUTPUT, 7) /* GPMC0_WEN.GPIO0_34 */
+                       /* connectors M1 & M2 PERST0 (PCI Reset) */
+                       AM64X_IOPAD(0x019c, PIN_OUTPUT, 7) /* PRG0_PRU0_GPO15.GPIO1_15 */
+                       /* connector M1 CLKREQ0 */
+                       AM64X_IOPAD(0x018c, PIN_INPUT, 7) /* PRG0_PRU0_GPO11.GPIO1_11 */
+                       /* connector M2 CLKREQ0 */
+                       AM64X_IOPAD(0x01ec, PIN_INPUT, 7) /* PRG0_PRU1_GPO15.GPIO1_35 */
+               >;
+       };
+
+       regulator_pcie_3v3_default_pins: regulator-pcie-3v3-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x01a4, PIN_OUTPUT, 7) /* PRG0_PRU0_GPO17.GPIO1_17 */
+               >;
+       };
+
+       regulator_vpp_1v8_default_pins: regulator-vpp-1v8-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x029c, PIN_OUTPUT, 7) /* MMC1_SDWP.GPIO1_78 */
+               >;
+       };
+
+       rtc_int_default_pins: rtc-int-default-pins {
+               pinctrl-single,pins = <
+                       /* external pull-up on Carrier */
+                       AM64X_IOPAD(0x00b4, PIN_INPUT, 7) /* GPMC0_CSn3.GPIO0_44 */
+               >;
+       };
+
+       serdes_mux_default_pins: serdes-mux-default-pins {
+               pinctrl-single,pins = <
+                       /* SEL, 10k pull-down on carrier, 2.2k pullup on SoM */
+                       AM64X_IOPAD(0x0200, PIN_OUTPUT, 7) /* PRG0_MDIO0_MDIO.GPIO1_40 */
+                       /* EN */
+                       AM64X_IOPAD(0x0204, PIN_OUTPUT, 7) /* PRG0_MDIO0_MDC.GPIO1_41 */
+               >;
+       };
+};
+
+&main_uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_uart3_default_pins>;
+       uart-has-rtscts;
+       rs485-rts-active-low;
+       linux,rs485-enabled-at-boot-time;
+       status = "okay";
+};
+
+&usb0 {
+       dr_mode = "host";
+};
index 53b64e55413f99e45ca93ec98e39cd224e3599ee..8237b8c815b84a86874afaf8bd881889936fac5d 100644 (file)
@@ -1,9 +1,9 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2021 PHYTEC America, LLC - https://www.phytec.com
+ * Copyright (C) 2021-2024 PHYTEC America, LLC - https://www.phytec.com
  * Author: Matt McKee <mmckee@phytec.com>
  *
- * Copyright (C) 2022 PHYTEC Messtechnik GmbH
+ * Copyright (C) 2022-2024 PHYTEC Messtechnik GmbH
  * Author: Wadim Egorov <w.egorov@phytec.de>
  *
  * Product homepage:
                >;
        };
 
+       main_spi0_pins_default: main-spi0-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x020c, PIN_OUTPUT, 7)      /* (C13) SPI0_CS1.GPIO1_43 */
+                       AM64X_IOPAD(0x0210, PIN_INPUT, 0)       /* (D13) SPI0_CLK */
+                       AM64X_IOPAD(0x0214, PIN_OUTPUT, 0)      /* (A13) SPI0_D0 */
+                       AM64X_IOPAD(0x0218, PIN_INPUT, 0)       /* (A14) SPI0_D1 */
+               >;
+       };
+
        main_uart0_pins_default: main-uart0-default-pins {
                pinctrl-single,pins = <
                        AM64X_IOPAD(0x0230, PIN_INPUT, 0)       /* (D15) UART0_RXD */
        phys = <&can_tc2>;
 };
 
+&main_spi0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_spi0_pins_default>;
+       cs-gpios = <0>, <&main_gpio1 43 GPIO_ACTIVE_LOW>;
+       ti,pindir-d0-out-d1-in;
+
+       tpm@1 {
+               compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
+               reg = <1>;
+               spi-max-frequency = <10000000>;
+       };
+};
+
 &main_uart0 {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-names = "default";
        pinctrl-0 = <&main_mmc1_pins_default>;
        bus-width = <4>;
-       ti,driver-strength-ohm = <50>;
        disable-wp;
        no-1-8-v;
 };
index 1dddd6fc1a0d2dac05979333ec3c43c8ea59f421..67cd41bf806eab21e2d6d1d452686ecf60de573a 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
        status = "okay";
        vmmc-supply = <&vdd_mmc1>;
        pinctrl-names = "default";
-       bus-width = <4>;
        pinctrl-0 = <&main_mmc1_pins_default>;
-       ti,driver-strength-ohm = <50>;
        disable-wp;
 };
 
 };
 
 &main_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core0>;
        memory-region = <&main_r5fss0_core0_dma_memory_region>,
                        <&main_r5fss0_core0_memory_region>;
 };
 
 &main_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core1>;
        memory-region = <&main_r5fss0_core1_dma_memory_region>,
                        <&main_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss1_core0 {
-       mboxes = <&mailbox0_cluster4>, <&mbox_main_r5fss1_core0>;
+       mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core0>;
        memory-region = <&main_r5fss1_core0_dma_memory_region>,
                        <&main_r5fss1_core0_memory_region>;
 };
 
 &main_r5fss1_core1 {
-       mboxes = <&mailbox0_cluster4>, <&mbox_main_r5fss1_core1>;
+       mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core1>;
        memory-region = <&main_r5fss1_core1_dma_memory_region>,
                        <&main_r5fss1_core1_memory_region>;
 };
diff --git a/arch/arm64/boot/dts/ti/k3-am642-sr-som.dtsi b/arch/arm64/boot/dts/ti/k3-am642-sr-som.dtsi
new file mode 100644 (file)
index 0000000..c19d0b8
--- /dev/null
@@ -0,0 +1,594 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Josua Mayer <josua@solid-run.com>
+ *
+ */
+
+#include <dt-bindings/net/ti-dp83869.h>
+
+/ {
+       model = "SolidRun AM642 SoM";
+       compatible = "solidrun,am642-sr-som", "ti,am642";
+
+       aliases {
+               ethernet0 = &cpsw_port1;
+               ethernet1 = &icssg1_emac0;
+               ethernet2 = &icssg1_emac1;
+               mmc0 = &sdhci0;
+               mmc1 = &sdhci1;
+               serial2 = &main_uart0;
+       };
+
+       chosen {
+               /* SoC default UART console */
+               stdout-path = "serial2:115200n8";
+       };
+
+       /* PRU Ethernet Controller */
+       ethernet {
+               compatible = "ti,am642-icssg-prueth";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pru_rgmii1_default_pins>, <&pru_rgmii2_default_pins>;
+
+               sram = <&oc_sram>;
+               ti,prus = <&pru1_0>, <&rtu1_0>, <&tx_pru1_0>, <&pru1_1>, <&rtu1_1>, <&tx_pru1_1>;
+               firmware-name = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf",
+                               "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf",
+                               "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf",
+                               "ti-pruss/am65x-sr2-pru1-prueth-fw.elf",
+                               "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf",
+                               "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf";
+
+               /* configure internal pinmux for mii mode */
+               ti,pruss-gp-mux-sel = <2>, <2>, <2>, <2>, <2>, <2>;
+
+               ti,mii-g-rt = <&icssg1_mii_g_rt>;
+               ti,mii-rt = <&icssg1_mii_rt>;
+               ti,iep = <&icssg1_iep0>, <&icssg1_iep1>;
+
+               /*
+                * Configure icssg interrupt controller to map pru-internal
+                * interrupts 8/9 via channels 0/1 to host interrupts 0/1.
+                *
+                * For details see interrupt controller documentation:
+                * Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.yaml
+                */
+               interrupt-parent = <&icssg1_intc>;
+               interrupts = <24 0 2>, <25 1 3>;
+               interrupt-names = "tx_ts0", "tx_ts1";
+
+               dmas = <&main_pktdma 0xc200 15>, /* egress slice 0 */
+                      <&main_pktdma 0xc201 15>, /* egress slice 0 */
+                      <&main_pktdma 0xc202 15>, /* egress slice 0 */
+                      <&main_pktdma 0xc203 15>, /* egress slice 0 */
+                      <&main_pktdma 0xc204 15>, /* egress slice 1 */
+                      <&main_pktdma 0xc205 15>, /* egress slice 1 */
+                      <&main_pktdma 0xc206 15>, /* egress slice 1 */
+                      <&main_pktdma 0xc207 15>, /* egress slice 1 */
+                      <&main_pktdma 0x4200 15>, /* ingress slice 0 */
+                      <&main_pktdma 0x4201 15>; /* ingress slice 1 */
+               dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3",
+                           "tx1-0", "tx1-1", "tx1-2", "tx1-3",
+                           "rx0", "rx1";
+
+               ethernet-ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       icssg1_emac0: port@0 {
+                               reg = <0>;
+                               ti,syscon-rgmii-delay = <&main_conf 0x4110>;
+                               /* Filled in by bootloader */
+                               local-mac-address = [00 00 00 00 00 00];
+                               phy-handle = <&ethernet_phy2>;
+                               phy-mode = "rgmii-id";
+                       };
+
+                       icssg1_emac1: port@1 {
+                               reg = <1>;
+                               ti,syscon-rgmii-delay = <&main_conf 0x4114>;
+                               /* Filled in by bootloader */
+                               local-mac-address = [00 00 00 00 00 00];
+                               phy-handle = <&ethernet_phy1>;
+                               phy-mode = "rgmii-id";
+                       };
+               };
+       };
+
+       /* DDR16SS0:
+        * - Bank 1 @ 0x080000000-0x0FFFFFFFF: max. 2GB in 32-bit address space
+        * - Bank 2 @ 0x880000000-0x9FFFFFFFF: max. 6GB in 64-bit address space
+        */
+       memory@80000000 {
+               reg = <0x00000000 0x80000000 0x00000000 0x80000000>,
+                     <0x00000008 0x80000000 0x00000001 0x80000000>;
+               device_type = "memory";
+       };
+
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               secure_ddr: optee@9e800000 {
+                       reg = <0x00 0x9e800000 0x00 0x01800000>; /* for OP-TEE */
+                       no-map;
+               };
+
+               main_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0x00 0xa0000000 0x00 0x100000>;
+                       no-map;
+               };
+
+               main_r5fss0_core0_memory_region: r5f-memory@a0100000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0x00 0xa0100000 0x00 0xf00000>;
+                       no-map;
+               };
+
+               main_r5fss0_core1_dma_memory_region: r5f-dma-memory@a1000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0x00 0xa1000000 0x00 0x100000>;
+                       no-map;
+               };
+
+               main_r5fss0_core1_memory_region: r5f-memory@a1100000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0x00 0xa1100000 0x00 0xf00000>;
+                       no-map;
+               };
+
+               main_r5fss1_core0_dma_memory_region: r5f-dma-memory@a2000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0x00 0xa2000000 0x00 0x100000>;
+                       no-map;
+               };
+
+               main_r5fss1_core0_memory_region: r5f-memory@a2100000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0x00 0xa2100000 0x00 0xf00000>;
+                       no-map;
+               };
+
+               main_r5fss1_core1_dma_memory_region: r5f-dma-memory@a3000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0x00 0xa3000000 0x00 0x100000>;
+                       no-map;
+               };
+
+               main_r5fss1_core1_memory_region: r5f-memory@a3100000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0x00 0xa3100000 0x00 0xf00000>;
+                       no-map;
+               };
+       };
+
+       vdd_mmc0: regulator-vdd-mmc0 {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd-mmc0";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+};
+
+&cpsw3g {
+       pinctrl-names = "default";
+       pinctrl-0 = <&rgmii1_default_pins>;
+};
+
+&cpsw3g_mdio {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mdio0_default_pins>;
+       status = "okay";
+
+       ethernet_phy0: ethernet-phy@0 {
+               compatible = "ethernet-phy-id2000.a0f1";
+               reg = <0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ethernet_phy0_default_pins>;
+               ti,clk-output-sel = <DP83869_CLK_O_SEL_REF_CLK>;
+               ti,op-mode = <DP83869_RGMII_COPPER_ETHERNET>;
+               /*
+                * Disable interrupts because ISR never clears 0x0040
+                *
+                * interrupt-parent = <&main_gpio1>;
+                * interrupts = <70 IRQ_TYPE_LEVEL_LOW>;
+                */
+               /*
+                * Disable HW Reset because clock signal is daisy-chained
+                *
+                * reset-gpios = <&main_gpio0 84 GPIO_ACTIVE_LOW>;
+                * reset-assert-us = <1>;
+                * reset-deassert-us = <30>;
+                */
+       };
+};
+
+&cpsw_port1 {
+       phy-mode = "rgmii-id";
+       phy-handle = <&ethernet_phy0>;
+};
+
+&cpsw_port2 {
+       status = "disabled";
+};
+
+&icssg1_mdio {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pru1_mdio0_default_pins>;
+       status = "okay";
+
+       ethernet_phy1: ethernet-phy@3 {
+               compatible = "ethernet-phy-id2000.a0f1";
+               reg = <3>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ethernet_phy1_default_pins>;
+               ti,clk-output-sel = <DP83869_CLK_O_SEL_REF_CLK>;
+               ti,op-mode = <DP83869_RGMII_COPPER_ETHERNET>;
+               /*
+                * Disable interrupts because ISR never clears 0x0040
+                *
+                * interrupt-parent = <&main_gpio1>;
+                * interrupts = <70 IRQ_TYPE_LEVEL_LOW>;
+                */
+               /*
+                * Disable HW Reset because clock signal is daisy-chained
+                *
+                * reset-gpios = <&main_gpio0 20 GPIO_ACTIVE_LOW>;
+                * reset-assert-us = <1>;
+                * reset-deassert-us = <30>;
+                */
+       };
+
+       ethernet_phy2: ethernet-phy@f {
+               compatible = "ethernet-phy-id2000.a0f1";
+               reg = <0xf>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ethernet_phy2_default_pins>;
+               ti,op-mode = <DP83869_RGMII_COPPER_ETHERNET>;
+               /*
+                * Disable interrupts because ISR never clears 0x0040
+                *
+                * interrupt-parent = <&main_gpio1>;
+                * interrupts = <70 IRQ_TYPE_LEVEL_LOW>;
+                */
+               /*
+                * Disable HW Reset because clock signal is daisy-chained
+                *
+                * reset-gpios = <&main_gpio0 52 GPIO_ACTIVE_LOW>;
+                * reset-assert-us = <1>;
+                * reset-deassert-us = <30>;
+                */
+       };
+};
+
+&mailbox0_cluster2 {
+       status = "okay";
+
+       mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 {
+               ti,mbox-rx = <0 0 2>;
+               ti,mbox-tx = <1 0 2>;
+       };
+
+       mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 {
+               ti,mbox-rx = <2 0 2>;
+               ti,mbox-tx = <3 0 2>;
+       };
+};
+
+&mailbox0_cluster4 {
+       status = "okay";
+
+       mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 {
+               ti,mbox-rx = <0 0 2>;
+               ti,mbox-tx = <1 0 2>;
+       };
+
+       mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 {
+               ti,mbox-rx = <2 0 2>;
+               ti,mbox-tx = <3 0 2>;
+       };
+};
+
+&main_i2c0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_i2c0_default_pins>;
+       status = "okay";
+
+       som_eeprom: eeprom@50 {
+               compatible = "atmel,24c01";
+               reg = <0x50>;
+               pagesize = <8>;
+       };
+};
+
+&main_pmx0 {
+       /* hog global functions */
+       pinctrl-names = "default";
+       pinctrl-0 = <&ethernet_phy_default_pins>;
+
+       ethernet_phy_default_pins: ethernet-phy-default-pins {
+               pinctrl-single,pins = <
+                       /* interrupt / power-down, external pull-up on SoM */
+                       AM64X_IOPAD(0x0278, PIN_INPUT, 7) /* EXTINTn.GPIO1_70 */
+               >;
+       };
+
+       ethernet_phy0_default_pins: ethernet-phy0-default-pins {
+               pinctrl-single,pins = <
+                       /* reset */
+                       AM64X_IOPAD(0x0154, PIN_OUTPUT, 7) /* PRG1_PRU1_GPO19.GPIO0_84 */
+                       /* reference clock */
+                       AM64X_IOPAD(0x0274, PIN_OUTPUT, 5) /* EXT_REFCLK1.CLKOUT0 */
+               >;
+       };
+
+       ethernet_phy1_default_pins: ethernet-phy1-default-pins {
+               pinctrl-single,pins = <
+                       /* reset */
+                       AM64X_IOPAD(0x0150, PIN_OUTPUT, 7) /* PRG1_PRU1_GPO18.GPIO0_20 */
+                       /* led0, external pull-down on SoM */
+                       AM64X_IOPAD(0x0128, PIN_INPUT, 7) /* PRG1_PRU1_GPO8.GPIO0_73 */
+                       /* led1/rxer */
+                       AM64X_IOPAD(0x011c, PIN_INPUT, 7) /* PRG1_PRU1_GPO5.GPIO0_70 */
+               >;
+       };
+
+       ethernet_phy2_default_pins: ethernet-phy2-default-pins {
+               pinctrl-single,pins = <
+                       /* reset */
+                       AM64X_IOPAD(0x00d4, PIN_OUTPUT, 7) /* PRG1_PRU0_GPO7.GPIO0_52 */
+                       /* led0, external pull-down on SoM */
+                       AM64X_IOPAD(0x00d8, PIN_INPUT, 7) /* PRG1_PRU0_GPO8.GPIO0_53 */
+                       /* led1/rxer */
+                       AM64X_IOPAD(0x00cc, PIN_INPUT, 7) /* PRG1_PRU0_GPO5.GPIO0_50 */
+               >;
+       };
+
+       main_i2c0_default_pins: main-i2c0-default-pins {
+               pinctrl-single,pins = <
+                       /* external pull-up on SoM */
+                       AM64X_IOPAD(0x0260, PIN_INPUT, 0) /* I2C0_SCL.I2C0_SCL */
+                       AM64X_IOPAD(0x0264, PIN_INPUT, 0) /* I2C0_SDA.I2C0_SDA */
+               >;
+       };
+
+       /*
+        * main_mmc0_default_pins: main-mmc0-default-pins
+        *
+        * MMC0_CMD: no padconfig
+        * MMC0_CLK: no padconfig, external pull-up on SoM
+        * MMC0_DAT0: no padconfig
+        * MMC0_DAT1: no padconfig
+        * MMC0_DAT2: no padconfig
+        * MMC0_DAT3: no padconfig
+        * MMC0_DAT4: no padconfig
+        * MMC0_DAT5: no padconfig
+        * MMC0_DAT6: no padconfig
+        * MMC0_DAT7: no padconfig
+        * MMC0_DS: no padconfig, external pull-down on SoM
+        */
+
+       main_mmc1_default_pins: main-mmc1-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x0294, PIN_INPUT_PULLUP, 0) /* (J19) MMC1_CMD */
+                       AM64X_IOPAD(0x028c, PIN_INPUT, 0) /* MMC1_CLK.MMC1_CLK */
+                       AM64X_IOPAD(0x0288, PIN_INPUT_PULLUP, 0) /* MMC1_DAT0.MMC1_DAT0 */
+                       AM64X_IOPAD(0x0284, PIN_INPUT_PULLUP, 0) /* MMC1_DAT1.MMC1_DAT1 */
+                       AM64X_IOPAD(0x0280, PIN_INPUT_PULLUP, 0) /* MMC1_DAT2.MMC1_DAT2 */
+                       AM64X_IOPAD(0x027c, PIN_INPUT_PULLUP, 0) /* MMC1_DAT3.MMC1_DAT3 */
+                       /* external pull-down on SoM & Carrier */
+                       AM64X_IOPAD(0x0298, PIN_INPUT_PULLUP, 0) /* MMC1_SDCD.MMC1_SDCD */
+                       AM64X_IOPAD(0x0290, PIN_INPUT, 0) /* MMC1_CLKLB: clock loopback */
+               >;
+       };
+
+       main_uart0_default_pins: main-uart0-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x0230, PIN_INPUT, 0) /* UART0_RXD.UART0_RXD */
+                       AM64X_IOPAD(0x0234, PIN_OUTPUT, 0) /* UART0_TXD.UART0_TXD */
+               >;
+       };
+
+       mdio0_default_pins: mdio0-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x01fc, PIN_OUTPUT, 4) /* PRG0_PRU1_GPO19.MDIO0_MDC */
+                       AM64X_IOPAD(0x01f8, PIN_INPUT, 4) /* PRG0_PRU1_GPO18.MDIO0_MDIO */
+               >;
+       };
+
+       ospi0_default_pins: ospi0-default-pins {
+               pinctrl-single,pins = <
+                       /* external pull-down on SoM */
+                       AM64X_IOPAD(0x0000, PIN_OUTPUT, 0) /* OSPI0_CLK.OSPI0_CLK */
+                       AM64X_IOPAD(0x0008, PIN_OUTPUT, 0) /* OSPI0_DQS.OSPI0_DQS */
+                       /* external pull-up on SoM */
+                       AM64X_IOPAD(0x002c, PIN_OUTPUT, 0) /* OSPI0_CSn0.OSPI0_CSn0 */
+                       AM64X_IOPAD(0x000c, PIN_INPUT, 0) /* OSPI0_D0.OSPI0_D0 */
+                       AM64X_IOPAD(0x0010, PIN_INPUT, 0) /* OSPI0_D1.OSPI0_D1 */
+                       AM64X_IOPAD(0x0014, PIN_INPUT, 0) /* OSPI0_D2.OSPI0_D2 */
+                       AM64X_IOPAD(0x0018, PIN_INPUT, 0) /* OSPI0_D3.OSPI0_D3 */
+                       AM64X_IOPAD(0x001c, PIN_INPUT, 0) /* OSPI0_D4.OSPI0_D4 */
+                       AM64X_IOPAD(0x0020, PIN_INPUT, 0) /* OSPI0_D5.OSPI0_D5 */
+                       AM64X_IOPAD(0x0024, PIN_INPUT, 0) /* OSPI0_D6.OSPI0_D6 */
+                       AM64X_IOPAD(0x0028, PIN_INPUT, 0) /* OSPI0_D7.OSPI0_D7 */
+               >;
+       };
+
+       ospi0_flash0_default_pins: ospi0-flash0-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x0034, PIN_OUTPUT, 7) /* OSPI0_CSn2.GPIO0_13 */
+                       AM64X_IOPAD(0x0038, PIN_INPUT, 7) /* OSPI0_CSn3.GPIO0_14 */
+               >;
+       };
+
+       pru1_mdio0_default_pins: pru1-mdio0-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x015c, PIN_OUTPUT, 0) /* PRG1_MDIO0_MDC.PRG1_MDIO0_MDC */
+                       AM64X_IOPAD(0x0158, PIN_INPUT, 0) /* PRG1_MDIO0_MDIO.PRG1_MDIO0_MDIO */
+               >;
+       };
+
+       pru_rgmii1_default_pins: pru-rgmii1-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x00b8, PIN_INPUT, 2) /* (Y7) PRG1_PRU0_GPO0.PRG1_RGMII1_RD0 */
+                       AM64X_IOPAD(0x00bc, PIN_INPUT, 2) /* (U8) PRG1_PRU0_GPO1.PRG1_RGMII1_RD1 */
+                       AM64X_IOPAD(0x00c0, PIN_INPUT, 2) /* (W8) PRG1_PRU0_GPO2.PRG1_RGMII1_RD2 */
+                       AM64X_IOPAD(0x00c4, PIN_INPUT, 2) /* (V8) PRG1_PRU0_GPO3.PRG1_RGMII1_RD3 */
+                       AM64X_IOPAD(0x00d0, PIN_INPUT, 2) /* (AA7) PRG1_PRU0_GPO6.PRG1_RGMII1_RXC */
+                       AM64X_IOPAD(0x00c8, PIN_INPUT, 2) /* (Y8) PRG1_PRU0_GPO4.PRG1_RGMII1_RX_CTL */
+                       AM64X_IOPAD(0x00e4, PIN_OUTPUT, 2) /* (AA8) PRG1_PRU0_GPO11.PRG1_RGMII1_TD0 */
+                       AM64X_IOPAD(0x00e8, PIN_OUTPUT, 2) /* (U9) PRG1_PRU0_GPO12.PRG1_RGMII1_TD1 */
+                       AM64X_IOPAD(0x00ec, PIN_OUTPUT, 2) /* (W9) PRG1_PRU0_GPO13.PRG1_RGMII1_TD2 */
+                       AM64X_IOPAD(0x00f0, PIN_OUTPUT, 2) /* (AA9) PRG1_PRU0_GPO14.PRG1_RGMII1_TD3 */
+                       AM64X_IOPAD(0x00f8, PIN_INPUT, 2) /* (V9) PRG1_PRU0_GPO16.PRG1_RGMII1_TXC */
+                       AM64X_IOPAD(0x00f4, PIN_OUTPUT, 2) /* (Y9) PRG1_PRU0_GPO15.PRG1_RGMII1_TX_CTL */
+               >;
+       };
+
+       pru_rgmii2_default_pins: pru-rgmii2-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x0108, PIN_INPUT, 2) /* PRG1_PRU1_GPO0.RGMII2_RD0 */
+                       AM64X_IOPAD(0x010c, PIN_INPUT, 2) /* PRG1_PRU1_GPO1.RGMII2_RD1 */
+                       AM64X_IOPAD(0x0110, PIN_INPUT, 2) /* PRG1_PRU1_GPO2.RGMII2_RD2 */
+                       AM64X_IOPAD(0x0114, PIN_INPUT, 2) /* PRG1_PRU1_GPO3.RGMII2_RD3 */
+                       AM64X_IOPAD(0x0120, PIN_INPUT, 2) /* PRG1_PRU1_GPO6.RGMII2_RXC */
+                       AM64X_IOPAD(0x0118, PIN_INPUT, 2) /* PRG1_PRU1_GPO4.RGMII2_RX_CTL */
+                       AM64X_IOPAD(0x0134, PIN_OUTPUT, 2) /* PRG1_PRU1_GPO11.RGMII2_TD0 */
+                       AM64X_IOPAD(0x0138, PIN_OUTPUT, 2) /* PRG1_PRU1_GPO12.RGMII2_TD1 */
+                       AM64X_IOPAD(0x013c, PIN_OUTPUT, 2) /* PRG1_PRU1_GPO13.RGMII2_TD2 */
+                       AM64X_IOPAD(0x0140, PIN_OUTPUT, 2) /* PRG1_PRU1_GPO14.RGMII2_TD3 */
+                       AM64X_IOPAD(0x0148, PIN_INPUT, 2) /* PRG1_PRU1_GPO16.RGMII2_TXC */
+                       AM64X_IOPAD(0x0144, PIN_OUTPUT, 2) /* PRG1_PRU1_GPO15.RGMII2_TX_CTL */
+               >;
+       };
+
+       rgmii1_default_pins: rgmii1-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x01cc, PIN_INPUT, 4) /* PRG0_PRU1_GPO7.RGMII1_RD0 */
+                       AM64X_IOPAD(0x01d4, PIN_INPUT, 4) /* PRG0_PRU1_GPO9.RGMII1_RD1 */
+                       AM64X_IOPAD(0x01d8, PIN_INPUT, 4) /* PRG0_PRU1_GPO10.RGMII1_RD2 */
+                       AM64X_IOPAD(0x01f4, PIN_INPUT, 4) /* PRG0_PRU1_GPO17.RGMII1_RD3 */
+                       AM64X_IOPAD(0x0188, PIN_INPUT, 4) /* PRG0_PRU0_GPO10.RGMII1_RXC */
+                       AM64X_IOPAD(0x0184, PIN_INPUT, 4) /* PRG0_PRU0_GPO9.RGMII1_RX_CTL */
+                       AM64X_IOPAD(0x0124, PIN_OUTPUT, 4) /* PRG1_PRU1_GPO7.RGMII1_TD0 */
+                       AM64X_IOPAD(0x012c, PIN_OUTPUT, 4) /* PRG1_PRU1_GPO9.RGMII1_TD1 */
+                       AM64X_IOPAD(0x0130, PIN_OUTPUT, 4) /* PRG1_PRU1_GPO10.RGMII1_TD2 */
+                       AM64X_IOPAD(0x014c, PIN_OUTPUT, 4) /* PRG1_PRU1_GPO17.RGMII1_TD3 */
+                       AM64X_IOPAD(0x00e0, PIN_INPUT, 4) /* PRG1_PRU0_GPO10.RGMII1_TXC */
+                       AM64X_IOPAD(0x00dc, PIN_OUTPUT, 4) /* PRG1_PRU0_GPO9.RGMII1_TX_CTL */
+               >;
+       };
+
+       usb0_default_pins: usb0-default-pins {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x02a8, PIN_OUTPUT, 0) /* USB0_DRVVBUS.USB0_DRVVBUS */
+               >;
+       };
+};
+
+&main_r5fss0_core0 {
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core0>;
+       memory-region = <&main_r5fss0_core0_dma_memory_region>,
+                       <&main_r5fss0_core0_memory_region>;
+};
+
+&main_r5fss0_core1 {
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core1>;
+       memory-region = <&main_r5fss0_core1_dma_memory_region>,
+                       <&main_r5fss0_core1_memory_region>;
+};
+
+&main_r5fss1_core0 {
+       mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core0>;
+       memory-region = <&main_r5fss1_core0_dma_memory_region>,
+                       <&main_r5fss1_core0_memory_region>;
+};
+
+&main_r5fss1_core1 {
+       mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core1>;
+       memory-region = <&main_r5fss1_core1_dma_memory_region>,
+                       <&main_r5fss1_core1_memory_region>;
+};
+
+/* SoC default UART console */
+&main_uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_uart0_default_pins>;
+       status = "okay";
+};
+
+&ospi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&ospi0_default_pins>;
+       num-cs = <1>;
+       status = "okay";
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ospi0_flash0_default_pins>;
+               spi-tx-bus-width = <8>;
+               spi-rx-bus-width = <8>;
+               spi-max-frequency = <200000000>;
+               cdns,tshsl-ns = <50>;
+               cdns,tsd2d-ns = <50>;
+               cdns,tchsh-ns = <4>;
+               cdns,tslch-ns = <4>;
+               cdns,read-delay = <0>;
+               interrupt-parent = <&main_gpio0>;
+               interrupts = <14 IRQ_TYPE_LEVEL_LOW>;
+               reset-gpios = <&main_gpio0 13 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&sdhci0 {
+       /* mmc0 pins have no padconfig */
+       bus-width = <8>;
+       ti,driver-strength-ohm = <50>;
+       disable-wp;
+       non-removable;
+       cap-mmc-hw-reset;
+       no-sd;
+       /*
+        * MMC controller supports switching between 1.8V and 3.3V signalling.
+        * However MMC0 (unlike MMC1) does not integrate an LDO.
+        * Explicitly link a regulator node for indicating to the driver which
+        * voltages are actually usable.
+        */
+       vqmmc-supply = <&vdd_mmc0>;
+       status = "okay";
+};
+
+/*
+ * microSD is on carrier - however since SoC can boot from it,
+ * configure it just in case.
+ */
+&sdhci1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_mmc1_default_pins>;
+       bus-width = <4>;
+       ti,driver-strength-ohm = <50>;
+       disable-wp;
+       status = "okay";
+};
+
+/*
+ * USB settings are a carrier choice - however since SoC can boot from it,
+ * configure as USB-2.0 OTG here, keeping USB-3 serdes disabled.
+ */
+&usb0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&usb0_default_pins>;
+       dr_mode = "otg";
+       maximum-speed = "high-speed";
+};
+
+&usbss0 {
+       ti,vbus-divider;
+       ti,usb2-only;
+};
index 55102d35cecc1e1fd66e75d5188d8072882c9968..1f4dc5ad1696a5b29ffe941da22e1ab5a72b935d 100644 (file)
        cd-gpios = <&main_gpio1 77 GPIO_ACTIVE_LOW>;
        disable-wp;
        no-mmc;
-       ti,driver-strength-ohm = <50>;
        ti,fails-without-test-cd;
        /* Enabled by overlay */
 };
index 7a6eedea3aaec96ed65706d72c0047b7ea6abc32..8589ee55ef092efdf1a1d9deb6651eb6b1a9afbb 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM642 SoC family in Dual core configuration
  *
- * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-arduino-connector.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-arduino-connector.dtsi
new file mode 100644 (file)
index 0000000..7ff0abd
--- /dev/null
@@ -0,0 +1,768 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Siemens AG, 2018-2023
+ *
+ * Authors:
+ *   Le Jin <le.jin@siemens.com>
+ *   Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * Common bits for IOT2050 variants with Arduino connector
+ */
+
+&wkup_pmx0 {
+       pinctrl-names =
+               "default",
+               "d0-uart0-rxd",  "d0-gpio",  "d0-gpio-pullup",  "d0-gpio-pulldown",
+               "d1-uart0-txd",  "d1-gpio",  "d1-gpio-pullup",  "d1-gpio-pulldown",
+               "d2-uart0-ctsn", "d2-gpio",  "d2-gpio-pullup",  "d2-gpio-pulldown",
+               "d3-uart0-rtsn", "d3-gpio",  "d3-gpio-pullup",  "d3-gpio-pulldown",
+               "d10-spi0-cs0",  "d10-gpio", "d10-gpio-pullup", "d10-gpio-pulldown",
+               "d11-spi0-d0",   "d11-gpio", "d11-gpio-pullup", "d11-gpio-pulldown",
+               "d12-spi0-d1",   "d12-gpio", "d12-gpio-pullup", "d12-gpio-pulldown",
+               "d13-spi0-clk",  "d13-gpio", "d13-gpio-pullup", "d13-gpio-pulldown",
+               "a0-gpio", "a0-gpio-pullup", "a0-gpio-pulldown",
+               "a1-gpio", "a1-gpio-pullup", "a1-gpio-pulldown",
+               "a2-gpio", "a2-gpio-pullup", "a2-gpio-pulldown",
+               "a3-gpio", "a3-gpio-pullup", "a3-gpio-pulldown",
+               "a4-gpio", "a4-gpio-pullup", "a4-gpio-pulldown",
+               "a5-gpio", "a5-gpio-pullup", "a5-gpio-pulldown";
+
+       pinctrl-0 = <&d0_uart0_rxd>;
+       pinctrl-1 = <&d0_uart0_rxd>;
+       pinctrl-2 = <&d0_gpio>;
+       pinctrl-3 = <&d0_gpio_pullup>;
+       pinctrl-4 = <&d0_gpio_pulldown>;
+       pinctrl-5 = <&d1_uart0_txd>;
+       pinctrl-6 = <&d1_gpio>;
+       pinctrl-7 = <&d1_gpio_pullup>;
+       pinctrl-8 = <&d1_gpio_pulldown>;
+       pinctrl-9 = <&d2_uart0_ctsn>;
+       pinctrl-10 = <&d2_gpio>;
+       pinctrl-11 = <&d2_gpio_pullup>;
+       pinctrl-12 = <&d2_gpio_pulldown>;
+       pinctrl-13 = <&d3_uart0_rtsn>;
+       pinctrl-14 = <&d3_gpio>;
+       pinctrl-15 = <&d3_gpio_pullup>;
+       pinctrl-16 = <&d3_gpio_pulldown>;
+       pinctrl-17 = <&d10_spi0_cs0>;
+       pinctrl-18 = <&d10_gpio>;
+       pinctrl-19 = <&d10_gpio_pullup>;
+       pinctrl-20 = <&d10_gpio_pulldown>;
+       pinctrl-21 = <&d11_spi0_d0>;
+       pinctrl-22 = <&d11_gpio>;
+       pinctrl-23 = <&d11_gpio_pullup>;
+       pinctrl-24 = <&d11_gpio_pulldown>;
+       pinctrl-25 = <&d12_spi0_d1>;
+       pinctrl-26 = <&d12_gpio>;
+       pinctrl-27 = <&d12_gpio_pullup>;
+       pinctrl-28 = <&d12_gpio_pulldown>;
+       pinctrl-29 = <&d13_spi0_clk>;
+       pinctrl-30 = <&d13_gpio>;
+       pinctrl-31 = <&d13_gpio_pullup>;
+       pinctrl-32 = <&d13_gpio_pulldown>;
+       pinctrl-33 = <&a0_gpio>;
+       pinctrl-34 = <&a0_gpio_pullup>;
+       pinctrl-35 = <&a0_gpio_pulldown>;
+       pinctrl-36 = <&a1_gpio>;
+       pinctrl-37 = <&a1_gpio_pullup>;
+       pinctrl-38 = <&a1_gpio_pulldown>;
+       pinctrl-39 = <&a2_gpio>;
+       pinctrl-40 = <&a2_gpio_pullup>;
+       pinctrl-41 = <&a2_gpio_pulldown>;
+       pinctrl-42 = <&a3_gpio>;
+       pinctrl-43 = <&a3_gpio_pullup>;
+       pinctrl-44 = <&a3_gpio_pulldown>;
+       pinctrl-45 = <&a4_gpio>;
+       pinctrl-46 = <&a4_gpio_pullup>;
+       pinctrl-47 = <&a4_gpio_pulldown>;
+       pinctrl-48 = <&a5_gpio>;
+       pinctrl-49 = <&a5_gpio_pullup>;
+       pinctrl-50 = <&a5_gpio_pulldown>;
+
+       d0_uart0_rxd: d0-uart0-rxd-pins {
+               pinctrl-single,pins = <
+                       /* (P4) MCU_UART0_RXD */
+                       AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4)
+               >;
+       };
+
+       d0_gpio: d0-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (P4) WKUP_GPIO0_29 */
+                       AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 7)
+               >;
+       };
+
+       d0_gpio_pullup: d0-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (P4) WKUP_GPIO0_29 */
+                       AM65X_WKUP_IOPAD(0x0044, PIN_INPUT_PULLUP, 7)
+               >;
+       };
+
+       d0_gpio_pulldown: d0-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (P4) WKUP_GPIO0_29 */
+                       AM65X_WKUP_IOPAD(0x0044, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       d1_uart0_txd: d1-uart0-txd-pins {
+               pinctrl-single,pins = <
+                       /* (P5) MCU_UART0_TXD */
+                       AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4)
+               >;
+       };
+
+       d1_gpio: d1-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (P5) WKUP_GPIO0_30 */
+                       AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7)
+               >;
+       };
+
+       d1_gpio_pullup: d1-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (P5) WKUP_GPIO0_30 */
+                       AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7)
+               >;
+       };
+
+       d1_gpio_pulldown: d1-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (P5) WKUP_GPIO0_30 */
+                       AM65X_WKUP_IOPAD(0x0048, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       d2_uart0_ctsn: d2-uart0-ctsn-pins {
+               pinctrl-single,pins = <
+                       /* (P1) MCU_UART0_CTSn */
+                       AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 4)
+               >;
+       };
+
+       d2_gpio: d2-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (P5) WKUP_GPIO0_31 */
+                       AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7)
+               >;
+       };
+
+       d2_gpio_pullup: d2-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (P5) WKUP_GPIO0_31 */
+                       AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7)
+               >;
+       };
+
+       d2_gpio_pulldown: d2-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (P5) WKUP_GPIO0_31 */
+                       AM65X_WKUP_IOPAD(0x004C, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       d3_uart0_rtsn: d3-uart0-rtsn-pins {
+               pinctrl-single,pins = <
+                       /* (N3) MCU_UART0_RTSn */
+                       AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 4)
+               >;
+       };
+
+       d3_gpio: d3-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (N3) WKUP_GPIO0_33 */
+                       AM65X_WKUP_IOPAD(0x0054, PIN_INPUT, 7)
+               >;
+       };
+
+       d3_gpio_pullup: d3-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (N3) WKUP_GPIO0_33 */
+                       AM65X_WKUP_IOPAD(0x0054, PIN_INPUT, 7)
+               >;
+       };
+
+       d3_gpio_pulldown: d3-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (N3) WKUP_GPIO0_33 */
+                       AM65X_WKUP_IOPAD(0x0054, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       d10_spi0_cs0: d10-spi0-cs0-pins {
+               pinctrl-single,pins = <
+                       /* (Y4) MCU_SPI0_CS0 */
+                       AM65X_WKUP_IOPAD(0x009c, PIN_OUTPUT, 0)
+               >;
+       };
+
+       d10_gpio: d10-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (Y4) WKUP_GPIO0_51 */
+                       AM65X_WKUP_IOPAD(0x009c, PIN_INPUT, 7)
+               >;
+       };
+
+       d10_gpio_pullup: d10-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (Y4) WKUP_GPIO0_51 */
+                       AM65X_WKUP_IOPAD(0x009c, PIN_INPUT, 7)
+               >;
+       };
+
+       d10_gpio_pulldown: d10-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (Y4) WKUP_GPIO0_51 */
+                       AM65X_WKUP_IOPAD(0x009c, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       d11_spi0_d0: d11-spi0-d0-pins {
+               pinctrl-single,pins = <
+                       /* (Y3) MCU_SPI0_D0 */
+                       AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 0)
+               >;
+       };
+
+       d11_gpio: d11-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (Y3) WKUP_GPIO0_49 */
+                       AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 7)
+               >;
+       };
+
+       d11_gpio_pullup: d11-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (Y3) WKUP_GPIO0_49 */
+                       AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 7)
+               >;
+       };
+
+       d11_gpio_pulldown: d11-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (Y3) WKUP_GPIO0_49 */
+                       AM65X_WKUP_IOPAD(0x0094, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       d12_spi0_d1: d12-spi0-d1-pins {
+               pinctrl-single,pins = <
+                       /* (Y2) MCU_SPI0_D1 */
+                       AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 0)
+               >;
+       };
+
+       d12_gpio: d12-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (Y2) WKUP_GPIO0_50 */
+                       AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 7)
+               >;
+       };
+
+       d12_gpio_pullup: d12-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (Y2) WKUP_GPIO0_50 */
+                       AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 7)
+               >;
+       };
+
+       d12_gpio_pulldown: d12-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (Y2) WKUP_GPIO0_50 */
+                       AM65X_WKUP_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       d13_spi0_clk: d13-spi0-clk-pins {
+               pinctrl-single,pins = <
+                       /* (Y1) MCU_SPI0_CLK */
+                       AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 0)
+               >;
+       };
+
+       d13_gpio: d13-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (Y1) WKUP_GPIO0_48 */
+                       AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 7)
+               >;
+       };
+
+       d13_gpio_pullup: d13-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (Y1) WKUP_GPIO0_48 */
+                       AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 7)
+               >;
+       };
+
+       d13_gpio_pulldown: d13-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (Y1) WKUP_GPIO0_48 */
+                       AM65X_WKUP_IOPAD(0x0090, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       a0_gpio: a0-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (L6) WKUP_GPIO0_45 */
+                       AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 7)
+               >;
+       };
+
+       a0_gpio_pullup: a0-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (L6) WKUP_GPIO0_45 */
+                       AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 7)
+               >;
+       };
+
+       a0_gpio_pulldown: a0-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (L6) WKUP_GPIO0_45 */
+                       AM65X_WKUP_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       a1_gpio: a1-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (M6) WKUP_GPIO0_44 */
+                       AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 7)
+               >;
+       };
+
+       a1_gpio_pullup: a1-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (M6) WKUP_GPIO0_44 */
+                       AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 7)
+               >;
+       };
+
+       a1_gpio_pulldown: a1-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (M6) WKUP_GPIO0_44 */
+                       AM65X_WKUP_IOPAD(0x0080, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       a2_gpio: a2-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (L5) WKUP_GPIO0_43 */
+                       AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7)
+               >;
+       };
+
+       a2_gpio_pullup: a2-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (L5) WKUP_GPIO0_43 */
+                       AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7)
+               >;
+       };
+
+       a2_gpio_pulldown: a2-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (L5) WKUP_GPIO0_43 */
+                       AM65X_WKUP_IOPAD(0x007C, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       a3_gpio: a3-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (M5) WKUP_GPIO0_39 */
+                       AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7)
+               >;
+       };
+
+       a3_gpio_pullup: a3-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (M5) WKUP_GPIO0_39 */
+                       AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7)
+               >;
+       };
+
+       a3_gpio_pulldown: a3-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (M5) WKUP_GPIO0_39 */
+                       AM65X_WKUP_IOPAD(0x006C, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       a4_gpio: a4-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (L2) WKUP_GPIO0_42 */
+                       AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 7)
+               >;
+       };
+
+       a4_gpio_pullup: a4-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (L2) WKUP_GPIO0_42 */
+                       AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 7)
+               >;
+       };
+
+       a4_gpio_pulldown: a4-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (L2) WKUP_GPIO0_42 */
+                       AM65X_WKUP_IOPAD(0x0078, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       a5_gpio: a5-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (N5) WKUP_GPIO0_35 */
+                       AM65X_WKUP_IOPAD(0x005C, PIN_INPUT, 7)
+               >;
+       };
+
+       a5_gpio_pullup: a5-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (N5) WKUP_GPIO0_35 */
+                       AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLUP, 7)
+               >;
+       };
+
+       a5_gpio_pulldown: a5-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (N5) WKUP_GPIO0_35 */
+                       AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       wkup_i2c0_pins_default: wkup-i2c0-default-pins {
+               pinctrl-single,pins = <
+                       /* (AC7) WKUP_I2C0_SCL */
+                       AM65X_WKUP_IOPAD(0x00e0, PIN_INPUT,  0)
+                       /* (AD6) WKUP_I2C0_SDA */
+                       AM65X_WKUP_IOPAD(0x00e4, PIN_INPUT,  0)
+               >;
+       };
+
+       arduino_i2c_aio_switch_pins_default: arduino-i2c-aio-switch-default-pins {
+               pinctrl-single,pins = <
+                       /* (R2) WKUP_GPIO0_21 */
+                       AM65X_WKUP_IOPAD(0x0024, PIN_OUTPUT, 7)
+               >;
+       };
+
+       arduino_io_oe_pins_default: arduino-io-oe-default-pins {
+               pinctrl-single,pins = <
+                       /* (N4) WKUP_GPIO0_34 */
+                       AM65X_WKUP_IOPAD(0x0058, PIN_OUTPUT, 7)
+                       /* (M2) WKUP_GPIO0_36 */
+                       AM65X_WKUP_IOPAD(0x0060, PIN_OUTPUT, 7)
+                       /* (M3) WKUP_GPIO0_37 */
+                       AM65X_WKUP_IOPAD(0x0064, PIN_OUTPUT, 7)
+                       /* (M4) WKUP_GPIO0_38 */
+                       AM65X_WKUP_IOPAD(0x0068, PIN_OUTPUT, 7)
+                       /* (M1) WKUP_GPIO0_41 */
+                       AM65X_WKUP_IOPAD(0x0074, PIN_OUTPUT, 7)
+               >;
+       };
+};
+
+&main_pmx0 {
+       pinctrl-names =
+               "default",
+               "d4-ehrpwm0-a", "d4-gpio", "d4-gpio-pullup", "d4-gpio-pulldown",
+               "d5-ehrpwm1-a", "d5-gpio", "d5-gpio-pullup", "d5-gpio-pulldown",
+               "d6-ehrpwm2-a", "d6-gpio", "d6-gpio-pullup", "d6-gpio-pulldown",
+               "d7-ehrpwm3-a", "d7-gpio", "d7-gpio-pullup", "d7-gpio-pulldown",
+               "d8-ehrpwm4-a", "d8-gpio", "d8-gpio-pullup", "d8-gpio-pulldown",
+               "d9-ehrpwm5-a", "d9-gpio", "d9-gpio-pullup", "d9-gpio-pulldown";
+
+       pinctrl-0 = <&d4_ehrpwm0_a>;
+       pinctrl-1 = <&d4_ehrpwm0_a>;
+       pinctrl-2 = <&d4_gpio>;
+       pinctrl-3 = <&d4_gpio_pullup>;
+       pinctrl-4 = <&d4_gpio_pulldown>;
+
+       pinctrl-5 = <&d5_ehrpwm1_a>;
+       pinctrl-6 = <&d5_gpio>;
+       pinctrl-7 = <&d5_gpio_pullup>;
+       pinctrl-8 = <&d5_gpio_pulldown>;
+
+       pinctrl-9 = <&d6_ehrpwm2_a>;
+       pinctrl-10 = <&d6_gpio>;
+       pinctrl-11 = <&d6_gpio_pullup>;
+       pinctrl-12 = <&d6_gpio_pulldown>;
+
+       pinctrl-13 = <&d7_ehrpwm3_a>;
+       pinctrl-14 = <&d7_gpio>;
+       pinctrl-15 = <&d7_gpio_pullup>;
+       pinctrl-16 = <&d7_gpio_pulldown>;
+
+       pinctrl-17 = <&d8_ehrpwm4_a>;
+       pinctrl-18 = <&d8_gpio>;
+       pinctrl-19 = <&d8_gpio_pullup>;
+       pinctrl-20 = <&d8_gpio_pulldown>;
+
+       pinctrl-21 = <&d9_ehrpwm5_a>;
+       pinctrl-22 = <&d9_gpio>;
+       pinctrl-23 = <&d9_gpio_pullup>;
+       pinctrl-24 = <&d9_gpio_pulldown>;
+
+       d4_ehrpwm0_a: d4-ehrpwm0-a-pins {
+               pinctrl-single,pins = <
+                       /* (AG18) EHRPWM0_A */
+                       AM65X_IOPAD(0x0084, PIN_OUTPUT, 5)
+               >;
+       };
+
+       d4_gpio: d4-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (AG18) GPIO0_33 */
+                       AM65X_IOPAD(0x0084, PIN_INPUT, 7)
+               >;
+       };
+
+       d4_gpio_pullup: d4-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (AG18) GPIO0_33 */
+                       AM65X_IOPAD(0x0084, PIN_INPUT_PULLUP, 7)
+               >;
+       };
+
+       d4_gpio_pulldown: d4-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (AG18) GPIO0_33 */
+                       AM65X_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       d5_ehrpwm1_a: d5-ehrpwm1-a-pins {
+               pinctrl-single,pins = <
+                       /* (AF17) EHRPWM1_A */
+                       AM65X_IOPAD(0x008C, PIN_OUTPUT, 5)
+               >;
+       };
+
+       d5_gpio: d5-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (AF17) GPIO0_35 */
+                       AM65X_IOPAD(0x008C, PIN_INPUT, 7)
+               >;
+       };
+
+       d5_gpio_pullup: d5-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (AF17) GPIO0_35 */
+                       AM65X_IOPAD(0x008C, PIN_INPUT_PULLUP, 7)
+               >;
+       };
+
+       d5_gpio_pulldown: d5-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (AF17) GPIO0_35 */
+                       AM65X_IOPAD(0x008C, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       d6_ehrpwm2_a: d6-ehrpwm2-a-pins {
+               pinctrl-single,pins = <
+                       /* (AH16) EHRPWM2_A */
+                       AM65X_IOPAD(0x0098, PIN_OUTPUT, 5)
+               >;
+       };
+
+       d6_gpio: d6-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (AH16) GPIO0_38 */
+                       AM65X_IOPAD(0x0098, PIN_INPUT, 7)
+               >;
+       };
+
+       d6_gpio_pullup: d6-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (AH16) GPIO0_38 */
+                       AM65X_IOPAD(0x0098, PIN_INPUT_PULLUP, 7)
+               >;
+       };
+
+       d6_gpio_pulldown: d6-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (AH16) GPIO0_38 */
+                       AM65X_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       d7_ehrpwm3_a: d7-ehrpwm3-a-pins {
+               pinctrl-single,pins = <
+                       /* (AH15) EHRPWM3_A */
+                       AM65X_IOPAD(0x00AC, PIN_OUTPUT, 5)
+               >;
+       };
+
+       d7_gpio: d7-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (AH15) GPIO0_43 */
+                       AM65X_IOPAD(0x00AC, PIN_INPUT, 7)
+               >;
+       };
+
+       d7_gpio_pullup: d7-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (AH15) GPIO0_43 */
+                       AM65X_IOPAD(0x00AC, PIN_INPUT_PULLUP, 7)
+               >;
+       };
+
+       d7_gpio_pulldown: d7-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (AH15) GPIO0_43 */
+                       AM65X_IOPAD(0x00AC, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       d8_ehrpwm4_a: d8-ehrpwm4-a-pins {
+               pinctrl-single,pins = <
+                       /* (AG15) EHRPWM4_A */
+                       AM65X_IOPAD(0x00C0, PIN_OUTPUT, 5)
+               >;
+       };
+
+       d8_gpio: d8-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (AG15) GPIO0_48 */
+                       AM65X_IOPAD(0x00C0, PIN_INPUT, 7)
+               >;
+       };
+
+       d8_gpio_pullup: d8-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (AG15) GPIO0_48 */
+                       AM65X_IOPAD(0x00C0, PIN_INPUT_PULLUP, 7)
+               >;
+       };
+
+       d8_gpio_pulldown: d8-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (AG15) GPIO0_48 */
+                       AM65X_IOPAD(0x00C0, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+
+       d9_ehrpwm5_a: d9-ehrpwm5-a-pins {
+               pinctrl-single,pins = <
+                       /* (AD15) EHRPWM5_A */
+                       AM65X_IOPAD(0x00CC, PIN_OUTPUT, 5)
+               >;
+       };
+
+       d9_gpio: d9-gpio-pins {
+               pinctrl-single,pins = <
+                       /* (AD15) GPIO0_51 */
+                       AM65X_IOPAD(0x00CC, PIN_INPUT, 7)
+               >;
+       };
+
+       d9_gpio_pullup: d9-gpio-pullup-pins {
+               pinctrl-single,pins = <
+                       /* (AD15) GPIO0_51 */
+                       AM65X_IOPAD(0x00CC, PIN_INPUT_PULLUP, 7)
+               >;
+       };
+
+       d9_gpio_pulldown: d9-gpio-pulldown-pins {
+               pinctrl-single,pins = <
+                       /* (AD15) GPIO0_51 */
+                       AM65X_IOPAD(0x00CC, PIN_INPUT_PULLDOWN, 7)
+               >;
+       };
+};
+
+&main_gpio0 {
+       gpio-line-names =
+               "main_gpio0-base", "", "", "", "", "", "", "", "", "",
+               "", "", "", "", "", "", "", "", "", "",
+               "", "", "", "", "", "", "", "", "", "",
+               "", "", "", "IO4", "", "IO5", "", "", "IO6", "",
+               "", "", "", "IO7", "", "", "", "", "IO8", "",
+               "", "IO9";
+};
+
+&wkup_gpio0 {
+       pinctrl-names = "default";
+       pinctrl-0 =
+               <&arduino_i2c_aio_switch_pins_default>,
+               <&arduino_io_oe_pins_default>,
+               <&push_button_pins_default>,
+               <&db9_com_mode_pins_default>;
+       gpio-line-names =
+               /* 0..9 */
+               "wkup_gpio0-base", "", "", "", "UART0-mode1", "UART0-mode0",
+               "UART0-enable", "UART0-terminate", "", "WIFI-disable",
+               /* 10..19 */
+               "", "", "", "", "", "", "", "", "", "",
+               /* 20..29 */
+               "", "A4A5-I2C-mux", "", "", "", "USER-button", "", "", "","IO0",
+               /* 30..39 */
+               "IO1", "IO2", "", "IO3", "IO17-direction", "A5",
+               "IO16-direction", "IO15-direction", "IO14-direction", "A3",
+               /* 40..49 */
+               "", "IO18-direction", "A4", "A2", "A1", "A0", "", "", "IO13",
+               "IO11",
+               /* 50..51 */
+               "IO12", "IO10";
+};
+
+&wkup_i2c0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&wkup_i2c0_pins_default>;
+       clock-frequency = <400000>;
+};
+
+&mcu_i2c0 {
+       /* D4200 */
+       pcal9535_1: gpio@20 {
+               compatible = "nxp,pcal9535";
+               reg = <0x20>;
+               #gpio-cells = <2>;
+               gpio-controller;
+               gpio-line-names =
+                       "A0-pull", "A1-pull", "A2-pull", "A3-pull", "A4-pull",
+                       "A5-pull", "", "",
+                       "IO14-enable", "IO15-enable", "IO16-enable",
+                       "IO17-enable", "IO18-enable", "IO19-enable";
+       };
+
+       /* D4201 */
+       pcal9535_2: gpio@21 {
+               compatible = "nxp,pcal9535";
+               reg = <0x21>;
+               #gpio-cells = <2>;
+               gpio-controller;
+               gpio-line-names =
+                       "IO0-direction", "IO1-direction", "IO2-direction",
+                       "IO3-direction", "IO4-direction", "IO5-direction",
+                       "IO6-direction", "IO7-direction",
+                       "IO8-direction", "IO9-direction", "IO10-direction",
+                       "IO11-direction", "IO12-direction", "IO13-direction",
+                       "IO19-direction";
+       };
+
+       /* D4202 */
+       pcal9535_3: gpio@25 {
+               compatible = "nxp,pcal9535";
+               reg = <0x25>;
+               #gpio-cells = <2>;
+               gpio-controller;
+               gpio-line-names =
+                       "IO0-pull", "IO1-pull", "IO2-pull", "IO3-pull",
+                       "IO4-pull", "IO5-pull", "IO6-pull", "IO7-pull",
+                       "IO8-pull", "IO9-pull", "IO10-pull", "IO11-pull",
+                       "IO12-pull", "IO13-pull";
+       };
+};
+
+&mcu_uart0 {
+       status = "okay";
+};
+
+&tscadc1 {
+       status = "okay";
+       adc {
+               ti,adc-channels = <0 1 2 3 4 5>;
+       };
+};
index 1d197985958369ea5b1816068a02d67637b53e61..c50a585dd6384841b13063c65ca23ea47825657d 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) Siemens AG, 2021-2023
  *
@@ -8,10 +8,7 @@
  * Common bits of the IOT2050 Basic and Advanced variants, PG1
  */
 
-&dss {
-       assigned-clocks = <&k3_clks 67 2>;
-       assigned-clock-parents = <&k3_clks 67 5>;
-};
+#include "k3-am65-iot2050-dp.dtsi"
 
 &serdes0 {
        status = "disabled";
index e9b57b87e42e07c0d60eca757eb569cb53c4b81f..e2584a5efe3438d75118061103ea977660057eea 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) Siemens AG, 2021
+ * Copyright (c) Siemens AG, 2021-2023
  *
  * Authors:
  *   Chao Zeng <chao.zeng@siemens.com>
@@ -9,6 +9,11 @@
  * Common bits of the IOT2050 Basic and Advanced variants, PG2
  */
 
+&mcu_r5fss0 {
+       /* lock-step mode not supported on PG2 boards */
+       ti,cluster-mode = <0>;
+};
+
 &main_pmx0 {
        cp2102n_reset_pin_default: cp2102n-reset-default-pins {
                pinctrl-single,pins = <
        /* Workaround needed to get DP clock of 154Mhz */
        assigned-clocks = <&k3_clks 67 0>;
 };
-
-&serdes0 {
-       assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>;
-       assigned-clock-parents = <&k3_clks 153 7>, <&k3_clks 153 4>;
-};
-
-&dwc3_0 {
-       assigned-clock-parents = <&k3_clks 151 4>,  /* set REF_CLK to 20MHz i.e. PER0_PLL/48 */
-                                <&k3_clks 151 8>;  /* set PIPE3_TXB_CLK to WIZ8B2M4VSB */
-       phys = <&serdes0 PHY_TYPE_USB3 0>;
-       phy-names = "usb3-phy";
-};
-
-&usb0 {
-       maximum-speed = "super-speed";
-       snps,dis-u1-entry-quirk;
-       snps,dis-u2-entry-quirk;
-};
index 61a634afaa4fecab8ec2a8ce63a3de480925c2bc..ef34b851e178a726561b38399bb51b0c1e0aeb54 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) Siemens AG, 2018-2021
+ * Copyright (c) Siemens AG, 2018-2024
  *
  * Authors:
  *   Le Jin <le.jin@siemens.com>
@@ -9,6 +9,7 @@
  * Common bits of the IOT2050 Basic and Advanced variants, PG1 and PG2
  */
 
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/phy/phy.h>
 #include <dt-bindings/net/ti-dp83867.h>
 
                        alignment = <0x1000>;
                        no-map;
                };
+
+               /* To reserve the power-on(PON) reason for watchdog reset */
+               wdt_reset_memory_region: wdt-memory@a2200000 {
+                       reg = <0x00 0xa2200000 0x00 0x1000>;
+                       no-map;
+               };
        };
 
        leds {
                pinctrl-names = "default";
                pinctrl-0 = <&leds_pins_default>;
 
-               status-led-red {
+               led-0 {
+                       color = <LED_COLOR_ID_RED>;
+                       function = LED_FUNCTION_STATUS;
+                       label = "status-led-red";
                        gpios = <&wkup_gpio0 32 GPIO_ACTIVE_HIGH>;
                        panic-indicator;
                };
 
-               status-led-green {
+               led-1 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_STATUS;
+                       label = "status-led-green";
                        gpios = <&wkup_gpio0 24 GPIO_ACTIVE_HIGH>;
                };
 
-               user-led1-red {
+               led-2 {
+                       color = <LED_COLOR_ID_RED>;
+                       function = LED_FUNCTION_INDICATOR;
+                       label = "user-led1-red";
                        gpios = <&pcal9535_3 14 GPIO_ACTIVE_HIGH>;
                };
 
-               user-led1-green {
+               led-3 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_INDICATOR;
+                       label = "user-led1-green";
                        gpios = <&pcal9535_2 15 GPIO_ACTIVE_HIGH>;
                };
 
-               user-led2-red {
+               led-4 {
+                       color = <LED_COLOR_ID_RED>;
+                       function = LED_FUNCTION_INDICATOR;
+                       label = "user-led2-red";
                        gpios = <&wkup_gpio0 17 GPIO_ACTIVE_HIGH>;
                };
 
-               user-led2-green {
+               led-5 {
+                       color = <LED_COLOR_ID_RED>;
+                       function = LED_FUNCTION_INDICATOR;
+                       label = "user-led2-green";
                        gpios = <&wkup_gpio0 22 GPIO_ACTIVE_HIGH>;
                };
        };
 };
 
 &wkup_pmx0 {
-       pinctrl-names =
-               "default",
-               "d0-uart0-rxd",  "d0-gpio",  "d0-gpio-pullup",  "d0-gpio-pulldown",
-               "d1-uart0-txd",  "d1-gpio",  "d1-gpio-pullup",  "d1-gpio-pulldown",
-               "d2-uart0-ctsn", "d2-gpio",  "d2-gpio-pullup",  "d2-gpio-pulldown",
-               "d3-uart0-rtsn", "d3-gpio",  "d3-gpio-pullup",  "d3-gpio-pulldown",
-               "d10-spi0-cs0",  "d10-gpio", "d10-gpio-pullup", "d10-gpio-pulldown",
-               "d11-spi0-d0",   "d11-gpio", "d11-gpio-pullup", "d11-gpio-pulldown",
-               "d12-spi0-d1",   "d12-gpio", "d12-gpio-pullup", "d12-gpio-pulldown",
-               "d13-spi0-clk",  "d13-gpio", "d13-gpio-pullup", "d13-gpio-pulldown",
-               "a0-gpio", "a0-gpio-pullup", "a0-gpio-pulldown",
-               "a1-gpio", "a1-gpio-pullup", "a1-gpio-pulldown",
-               "a2-gpio", "a2-gpio-pullup", "a2-gpio-pulldown",
-               "a3-gpio", "a3-gpio-pullup", "a3-gpio-pulldown",
-               "a4-gpio", "a4-gpio-pullup", "a4-gpio-pulldown",
-               "a5-gpio", "a5-gpio-pullup", "a5-gpio-pulldown";
-
-       pinctrl-0 = <&d0_uart0_rxd>;
-       pinctrl-1 = <&d0_uart0_rxd>;
-       pinctrl-2 = <&d0_gpio>;
-       pinctrl-3 = <&d0_gpio_pullup>;
-       pinctrl-4 = <&d0_gpio_pulldown>;
-       pinctrl-5 = <&d1_uart0_txd>;
-       pinctrl-6 = <&d1_gpio>;
-       pinctrl-7 = <&d1_gpio_pullup>;
-       pinctrl-8 = <&d1_gpio_pulldown>;
-       pinctrl-9 = <&d2_uart0_ctsn>;
-       pinctrl-10 = <&d2_gpio>;
-       pinctrl-11 = <&d2_gpio_pullup>;
-       pinctrl-12 = <&d2_gpio_pulldown>;
-       pinctrl-13 = <&d3_uart0_rtsn>;
-       pinctrl-14 = <&d3_gpio>;
-       pinctrl-15 = <&d3_gpio_pullup>;
-       pinctrl-16 = <&d3_gpio_pulldown>;
-       pinctrl-17 = <&d10_spi0_cs0>;
-       pinctrl-18 = <&d10_gpio>;
-       pinctrl-19 = <&d10_gpio_pullup>;
-       pinctrl-20 = <&d10_gpio_pulldown>;
-       pinctrl-21 = <&d11_spi0_d0>;
-       pinctrl-22 = <&d11_gpio>;
-       pinctrl-23 = <&d11_gpio_pullup>;
-       pinctrl-24 = <&d11_gpio_pulldown>;
-       pinctrl-25 = <&d12_spi0_d1>;
-       pinctrl-26 = <&d12_gpio>;
-       pinctrl-27 = <&d12_gpio_pullup>;
-       pinctrl-28 = <&d12_gpio_pulldown>;
-       pinctrl-29 = <&d13_spi0_clk>;
-       pinctrl-30 = <&d13_gpio>;
-       pinctrl-31 = <&d13_gpio_pullup>;
-       pinctrl-32 = <&d13_gpio_pulldown>;
-       pinctrl-33 = <&a0_gpio>;
-       pinctrl-34 = <&a0_gpio_pullup>;
-       pinctrl-35 = <&a0_gpio_pulldown>;
-       pinctrl-36 = <&a1_gpio>;
-       pinctrl-37 = <&a1_gpio_pullup>;
-       pinctrl-38 = <&a1_gpio_pulldown>;
-       pinctrl-39 = <&a2_gpio>;
-       pinctrl-40 = <&a2_gpio_pullup>;
-       pinctrl-41 = <&a2_gpio_pulldown>;
-       pinctrl-42 = <&a3_gpio>;
-       pinctrl-43 = <&a3_gpio_pullup>;
-       pinctrl-44 = <&a3_gpio_pulldown>;
-       pinctrl-45 = <&a4_gpio>;
-       pinctrl-46 = <&a4_gpio_pullup>;
-       pinctrl-47 = <&a4_gpio_pulldown>;
-       pinctrl-48 = <&a5_gpio>;
-       pinctrl-49 = <&a5_gpio_pullup>;
-       pinctrl-50 = <&a5_gpio_pulldown>;
-
-       d0_uart0_rxd: d0-uart0-rxd-pins {
-               pinctrl-single,pins = <
-                       /* (P4) MCU_UART0_RXD */
-                       AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4)
-               >;
-       };
-
-       d0_gpio: d0-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (P4) WKUP_GPIO0_29 */
-                       AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 7)
-               >;
-       };
-
-       d0_gpio_pullup: d0-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (P4) WKUP_GPIO0_29 */
-                       AM65X_WKUP_IOPAD(0x0044, PIN_INPUT_PULLUP, 7)
-               >;
-       };
-
-       d0_gpio_pulldown: d0-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (P4) WKUP_GPIO0_29 */
-                       AM65X_WKUP_IOPAD(0x0044, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       d1_uart0_txd: d1-uart0-txd-pins {
-               pinctrl-single,pins = <
-                       /* (P5) MCU_UART0_TXD */
-                       AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4)
-               >;
-       };
-
-       d1_gpio: d1-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (P5) WKUP_GPIO0_30 */
-                       AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7)
-               >;
-       };
-
-       d1_gpio_pullup: d1-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (P5) WKUP_GPIO0_30 */
-                       AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7)
-               >;
-       };
-
-       d1_gpio_pulldown: d1-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (P5) WKUP_GPIO0_30 */
-                       AM65X_WKUP_IOPAD(0x0048, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       d2_uart0_ctsn: d2-uart0-ctsn-pins {
-               pinctrl-single,pins = <
-                       /* (P1) MCU_UART0_CTSn */
-                       AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 4)
-               >;
-       };
-
-       d2_gpio: d2-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (P5) WKUP_GPIO0_31 */
-                       AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7)
-               >;
-       };
-
-       d2_gpio_pullup: d2-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (P5) WKUP_GPIO0_31 */
-                       AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7)
-               >;
-       };
-
-       d2_gpio_pulldown: d2-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (P5) WKUP_GPIO0_31 */
-                       AM65X_WKUP_IOPAD(0x004C, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       d3_uart0_rtsn: d3-uart0-rtsn-pins {
-               pinctrl-single,pins = <
-                       /* (N3) MCU_UART0_RTSn */
-                       AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 4)
-               >;
-       };
-
-       d3_gpio: d3-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (N3) WKUP_GPIO0_33 */
-                       AM65X_WKUP_IOPAD(0x0054, PIN_INPUT, 7)
-               >;
-       };
-
-       d3_gpio_pullup: d3-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (N3) WKUP_GPIO0_33 */
-                       AM65X_WKUP_IOPAD(0x0054, PIN_INPUT, 7)
-               >;
-       };
-
-       d3_gpio_pulldown: d3-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (N3) WKUP_GPIO0_33 */
-                       AM65X_WKUP_IOPAD(0x0054, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       d10_spi0_cs0: d10-spi0-cs0-pins {
-               pinctrl-single,pins = <
-                       /* (Y4) MCU_SPI0_CS0 */
-                       AM65X_WKUP_IOPAD(0x009c, PIN_OUTPUT, 0)
-               >;
-       };
-
-       d10_gpio: d10-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (Y4) WKUP_GPIO0_51 */
-                       AM65X_WKUP_IOPAD(0x009c, PIN_INPUT, 7)
-               >;
-       };
-
-       d10_gpio_pullup: d10-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (Y4) WKUP_GPIO0_51 */
-                       AM65X_WKUP_IOPAD(0x009c, PIN_INPUT, 7)
-               >;
-       };
-
-       d10_gpio_pulldown: d10-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (Y4) WKUP_GPIO0_51 */
-                       AM65X_WKUP_IOPAD(0x009c, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       d11_spi0_d0: d11-spi0-d0-pins {
-               pinctrl-single,pins = <
-                       /* (Y3) MCU_SPI0_D0 */
-                       AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 0)
-               >;
-       };
-
-       d11_gpio: d11-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (Y3) WKUP_GPIO0_49 */
-                       AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 7)
-               >;
-       };
-
-       d11_gpio_pullup: d11-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (Y3) WKUP_GPIO0_49 */
-                       AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 7)
-               >;
-       };
-
-       d11_gpio_pulldown: d11-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (Y3) WKUP_GPIO0_49 */
-                       AM65X_WKUP_IOPAD(0x0094, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       d12_spi0_d1: d12-spi0-d1-pins {
-               pinctrl-single,pins = <
-                       /* (Y2) MCU_SPI0_D1 */
-                       AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 0)
-               >;
-       };
-
-       d12_gpio: d12-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (Y2) WKUP_GPIO0_50 */
-                       AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 7)
-               >;
-       };
-
-       d12_gpio_pullup: d12-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (Y2) WKUP_GPIO0_50 */
-                       AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 7)
-               >;
-       };
-
-       d12_gpio_pulldown: d12-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (Y2) WKUP_GPIO0_50 */
-                       AM65X_WKUP_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       d13_spi0_clk: d13-spi0-clk-pins {
-               pinctrl-single,pins = <
-                       /* (Y1) MCU_SPI0_CLK */
-                       AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 0)
-               >;
-       };
-
-       d13_gpio: d13-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (Y1) WKUP_GPIO0_48 */
-                       AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 7)
-               >;
-       };
-
-       d13_gpio_pullup: d13-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (Y1) WKUP_GPIO0_48 */
-                       AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 7)
-               >;
-       };
-
-       d13_gpio_pulldown: d13-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (Y1) WKUP_GPIO0_48 */
-                       AM65X_WKUP_IOPAD(0x0090, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       a0_gpio: a0-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (L6) WKUP_GPIO0_45 */
-                       AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 7)
-               >;
-       };
-
-       a0_gpio_pullup: a0-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (L6) WKUP_GPIO0_45 */
-                       AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 7)
-               >;
-       };
-
-       a0_gpio_pulldown: a0-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (L6) WKUP_GPIO0_45 */
-                       AM65X_WKUP_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       a1_gpio: a1-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (M6) WKUP_GPIO0_44 */
-                       AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 7)
-               >;
-       };
-
-       a1_gpio_pullup: a1-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (M6) WKUP_GPIO0_44 */
-                       AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 7)
-               >;
-       };
-
-       a1_gpio_pulldown: a1-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (M6) WKUP_GPIO0_44 */
-                       AM65X_WKUP_IOPAD(0x0080, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       a2_gpio: a2-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (L5) WKUP_GPIO0_43 */
-                       AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7)
-               >;
-       };
-
-       a2_gpio_pullup: a2-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (L5) WKUP_GPIO0_43 */
-                       AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7)
-               >;
-       };
-
-       a2_gpio_pulldown: a2-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (L5) WKUP_GPIO0_43 */
-                       AM65X_WKUP_IOPAD(0x007C, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       a3_gpio: a3-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (M5) WKUP_GPIO0_39 */
-                       AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7)
-               >;
-       };
-
-       a3_gpio_pullup: a3-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (M5) WKUP_GPIO0_39 */
-                       AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7)
-               >;
-       };
-
-       a3_gpio_pulldown: a3-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (M5) WKUP_GPIO0_39 */
-                       AM65X_WKUP_IOPAD(0x006C, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       a4_gpio: a4-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (L2) WKUP_GPIO0_42 */
-                       AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 7)
-               >;
-       };
-
-       a4_gpio_pullup: a4-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (L2) WKUP_GPIO0_42 */
-                       AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 7)
-               >;
-       };
-
-       a4_gpio_pulldown: a4-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (L2) WKUP_GPIO0_42 */
-                       AM65X_WKUP_IOPAD(0x0078, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       a5_gpio: a5-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (N5) WKUP_GPIO0_35 */
-                       AM65X_WKUP_IOPAD(0x005C, PIN_INPUT, 7)
-               >;
-       };
-
-       a5_gpio_pullup: a5-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (N5) WKUP_GPIO0_35 */
-                       AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLUP, 7)
-               >;
-       };
-
-       a5_gpio_pulldown: a5-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (N5) WKUP_GPIO0_35 */
-                       AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       wkup_i2c0_pins_default: wkup-i2c0-default-pins {
-               pinctrl-single,pins = <
-                       /* (AC7) WKUP_I2C0_SCL */
-                       AM65X_WKUP_IOPAD(0x00e0, PIN_INPUT,  0)
-                       /* (AD6) WKUP_I2C0_SDA */
-                       AM65X_WKUP_IOPAD(0x00e4, PIN_INPUT,  0)
-               >;
-       };
-
        mcu_i2c0_pins_default: mcu-i2c0-default-pins {
                pinctrl-single,pins = <
                        /* (AD8) MCU_I2C0_SCL */
                >;
        };
 
-       arduino_i2c_aio_switch_pins_default: arduino-i2c-aio-switch-default-pins {
-               pinctrl-single,pins = <
-                       /* (R2) WKUP_GPIO0_21 */
-                       AM65X_WKUP_IOPAD(0x0024, PIN_OUTPUT, 7)
-               >;
-       };
-
        push_button_pins_default: push-button-default-pins {
                pinctrl-single,pins = <
                        /* (T1) MCU_OSPI1_CLK.WKUP_GPIO0_25 */
                >;
        };
 
-
-       arduino_io_oe_pins_default: arduino-io-oe-default-pins {
-               pinctrl-single,pins = <
-                       /* (N4) WKUP_GPIO0_34 */
-                       AM65X_WKUP_IOPAD(0x0058, PIN_OUTPUT, 7)
-                       /* (M2) WKUP_GPIO0_36 */
-                       AM65X_WKUP_IOPAD(0x0060, PIN_OUTPUT, 7)
-                       /* (M3) WKUP_GPIO0_37 */
-                       AM65X_WKUP_IOPAD(0x0064, PIN_OUTPUT, 7)
-                       /* (M4) WKUP_GPIO0_38 */
-                       AM65X_WKUP_IOPAD(0x0068, PIN_OUTPUT, 7)
-                       /* (M1) WKUP_GPIO0_41 */
-                       AM65X_WKUP_IOPAD(0x0074, PIN_OUTPUT, 7)
-               >;
-       };
-
        mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-default-pins {
                pinctrl-single,pins = <
                        /* (V1) MCU_OSPI0_CLK */
 };
 
 &main_pmx0 {
-       pinctrl-names =
-               "default",
-               "d4-ehrpwm0-a", "d4-gpio", "d4-gpio-pullup", "d4-gpio-pulldown",
-               "d5-ehrpwm1-a", "d5-gpio", "d5-gpio-pullup", "d5-gpio-pulldown",
-               "d6-ehrpwm2-a", "d6-gpio", "d6-gpio-pullup", "d6-gpio-pulldown",
-               "d7-ehrpwm3-a", "d7-gpio", "d7-gpio-pullup", "d7-gpio-pulldown",
-               "d8-ehrpwm4-a", "d8-gpio", "d8-gpio-pullup", "d8-gpio-pulldown",
-               "d9-ehrpwm5-a", "d9-gpio", "d9-gpio-pullup", "d9-gpio-pulldown";
-
-       pinctrl-0 = <&d4_ehrpwm0_a>;
-       pinctrl-1 = <&d4_ehrpwm0_a>;
-       pinctrl-2 = <&d4_gpio>;
-       pinctrl-3 = <&d4_gpio_pullup>;
-       pinctrl-4 = <&d4_gpio_pulldown>;
-
-       pinctrl-5 = <&d5_ehrpwm1_a>;
-       pinctrl-6 = <&d5_gpio>;
-       pinctrl-7 = <&d5_gpio_pullup>;
-       pinctrl-8 = <&d5_gpio_pulldown>;
-
-       pinctrl-9 = <&d6_ehrpwm2_a>;
-       pinctrl-10 = <&d6_gpio>;
-       pinctrl-11 = <&d6_gpio_pullup>;
-       pinctrl-12 = <&d6_gpio_pulldown>;
-
-       pinctrl-13 = <&d7_ehrpwm3_a>;
-       pinctrl-14 = <&d7_gpio>;
-       pinctrl-15 = <&d7_gpio_pullup>;
-       pinctrl-16 = <&d7_gpio_pulldown>;
-
-       pinctrl-17 = <&d8_ehrpwm4_a>;
-       pinctrl-18 = <&d8_gpio>;
-       pinctrl-19 = <&d8_gpio_pullup>;
-       pinctrl-20 = <&d8_gpio_pulldown>;
-
-       pinctrl-21 = <&d9_ehrpwm5_a>;
-       pinctrl-22 = <&d9_gpio>;
-       pinctrl-23 = <&d9_gpio_pullup>;
-       pinctrl-24 = <&d9_gpio_pulldown>;
-
-       d4_ehrpwm0_a: d4-ehrpwm0-a-pins {
-               pinctrl-single,pins = <
-                       /* (AG18) EHRPWM0_A */
-                       AM65X_IOPAD(0x0084, PIN_OUTPUT, 5)
-               >;
-       };
-
-       d4_gpio: d4-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (AG18) GPIO0_33 */
-                       AM65X_IOPAD(0x0084, PIN_INPUT, 7)
-               >;
-       };
-
-       d4_gpio_pullup: d4-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (AG18) GPIO0_33 */
-                       AM65X_IOPAD(0x0084, PIN_INPUT_PULLUP, 7)
-               >;
-       };
-
-       d4_gpio_pulldown: d4-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (AG18) GPIO0_33 */
-                       AM65X_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       d5_ehrpwm1_a: d5-ehrpwm1-a-pins {
-               pinctrl-single,pins = <
-                       /* (AF17) EHRPWM1_A */
-                       AM65X_IOPAD(0x008C, PIN_OUTPUT, 5)
-               >;
-       };
-
-       d5_gpio: d5-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (AF17) GPIO0_35 */
-                       AM65X_IOPAD(0x008C, PIN_INPUT, 7)
-               >;
-       };
-
-       d5_gpio_pullup: d5-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (AF17) GPIO0_35 */
-                       AM65X_IOPAD(0x008C, PIN_INPUT_PULLUP, 7)
-               >;
-       };
-
-       d5_gpio_pulldown: d5-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (AF17) GPIO0_35 */
-                       AM65X_IOPAD(0x008C, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       d6_ehrpwm2_a: d6-ehrpwm2-a-pins {
-               pinctrl-single,pins = <
-                       /* (AH16) EHRPWM2_A */
-                       AM65X_IOPAD(0x0098, PIN_OUTPUT, 5)
-               >;
-       };
-
-       d6_gpio: d6-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (AH16) GPIO0_38 */
-                       AM65X_IOPAD(0x0098, PIN_INPUT, 7)
-               >;
-       };
-
-       d6_gpio_pullup: d6-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (AH16) GPIO0_38 */
-                       AM65X_IOPAD(0x0098, PIN_INPUT_PULLUP, 7)
-               >;
-       };
-
-       d6_gpio_pulldown: d6-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (AH16) GPIO0_38 */
-                       AM65X_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       d7_ehrpwm3_a: d7-ehrpwm3-a-pins {
-               pinctrl-single,pins = <
-                       /* (AH15) EHRPWM3_A */
-                       AM65X_IOPAD(0x00AC, PIN_OUTPUT, 5)
-               >;
-       };
-
-       d7_gpio: d7-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (AH15) GPIO0_43 */
-                       AM65X_IOPAD(0x00AC, PIN_INPUT, 7)
-               >;
-       };
-
-       d7_gpio_pullup: d7-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (AH15) GPIO0_43 */
-                       AM65X_IOPAD(0x00AC, PIN_INPUT_PULLUP, 7)
-               >;
-       };
-
-       d7_gpio_pulldown: d7-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (AH15) GPIO0_43 */
-                       AM65X_IOPAD(0x00AC, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       d8_ehrpwm4_a: d8-ehrpwm4-a-pins {
-               pinctrl-single,pins = <
-                       /* (AG15) EHRPWM4_A */
-                       AM65X_IOPAD(0x00C0, PIN_OUTPUT, 5)
-               >;
-       };
-
-       d8_gpio: d8-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (AG15) GPIO0_48 */
-                       AM65X_IOPAD(0x00C0, PIN_INPUT, 7)
-               >;
-       };
-
-       d8_gpio_pullup: d8-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (AG15) GPIO0_48 */
-                       AM65X_IOPAD(0x00C0, PIN_INPUT_PULLUP, 7)
-               >;
-       };
-
-       d8_gpio_pulldown: d8-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (AG15) GPIO0_48 */
-                       AM65X_IOPAD(0x00C0, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
-       d9_ehrpwm5_a: d9-ehrpwm5-a-pins {
-               pinctrl-single,pins = <
-                       /* (AD15) EHRPWM5_A */
-                       AM65X_IOPAD(0x00CC, PIN_OUTPUT, 5)
-               >;
-       };
-
-       d9_gpio: d9-gpio-pins {
-               pinctrl-single,pins = <
-                       /* (AD15) GPIO0_51 */
-                       AM65X_IOPAD(0x00CC, PIN_INPUT, 7)
-               >;
-       };
-
-       d9_gpio_pullup: d9-gpio-pullup-pins {
-               pinctrl-single,pins = <
-                       /* (AD15) GPIO0_51 */
-                       AM65X_IOPAD(0x00CC, PIN_INPUT_PULLUP, 7)
-               >;
-       };
-
-       d9_gpio_pulldown: d9-gpio-pulldown-pins {
-               pinctrl-single,pins = <
-                       /* (AD15) GPIO0_51 */
-                       AM65X_IOPAD(0x00CC, PIN_INPUT_PULLDOWN, 7)
-               >;
-       };
-
        main_pcie_enable_pins_default: main-pcie-enable-default-pins {
                pinctrl-single,pins = <
                        AM65X_IOPAD(0x01c4, PIN_INPUT_PULLUP, 7)  /* (AH13) GPIO1_17 */
                >;
        };
 
-       dss_vout1_pins_default: dss-vout1-default-pins {
-               pinctrl-single,pins = <
-                       AM65X_IOPAD(0x0000, PIN_OUTPUT, 1)  /* VOUT1_DATA0 */
-                       AM65X_IOPAD(0x0004, PIN_OUTPUT, 1)  /* VOUT1_DATA1 */
-                       AM65X_IOPAD(0x0008, PIN_OUTPUT, 1)  /* VOUT1_DATA2 */
-                       AM65X_IOPAD(0x000c, PIN_OUTPUT, 1)  /* VOUT1_DATA3 */
-                       AM65X_IOPAD(0x0010, PIN_OUTPUT, 1)  /* VOUT1_DATA4 */
-                       AM65X_IOPAD(0x0014, PIN_OUTPUT, 1)  /* VOUT1_DATA5 */
-                       AM65X_IOPAD(0x0018, PIN_OUTPUT, 1)  /* VOUT1_DATA6 */
-                       AM65X_IOPAD(0x001c, PIN_OUTPUT, 1)  /* VOUT1_DATA7 */
-                       AM65X_IOPAD(0x0020, PIN_OUTPUT, 1)  /* VOUT1_DATA8 */
-                       AM65X_IOPAD(0x0024, PIN_OUTPUT, 1)  /* VOUT1_DATA9 */
-                       AM65X_IOPAD(0x0028, PIN_OUTPUT, 1)  /* VOUT1_DATA10 */
-                       AM65X_IOPAD(0x002c, PIN_OUTPUT, 1)  /* VOUT1_DATA11 */
-                       AM65X_IOPAD(0x0030, PIN_OUTPUT, 1)  /* VOUT1_DATA12 */
-                       AM65X_IOPAD(0x0034, PIN_OUTPUT, 1)  /* VOUT1_DATA13 */
-                       AM65X_IOPAD(0x0038, PIN_OUTPUT, 1)  /* VOUT1_DATA14 */
-                       AM65X_IOPAD(0x003c, PIN_OUTPUT, 1)  /* VOUT1_DATA15 */
-                       AM65X_IOPAD(0x0040, PIN_OUTPUT, 1)  /* VOUT1_DATA16 */
-                       AM65X_IOPAD(0x0044, PIN_OUTPUT, 1)  /* VOUT1_DATA17 */
-                       AM65X_IOPAD(0x0048, PIN_OUTPUT, 1)  /* VOUT1_DATA18 */
-                       AM65X_IOPAD(0x004c, PIN_OUTPUT, 1)  /* VOUT1_DATA19 */
-                       AM65X_IOPAD(0x0050, PIN_OUTPUT, 1)  /* VOUT1_DATA20 */
-                       AM65X_IOPAD(0x0054, PIN_OUTPUT, 1)  /* VOUT1_DATA21 */
-                       AM65X_IOPAD(0x0058, PIN_OUTPUT, 1)  /* VOUT1_DATA22 */
-                       AM65X_IOPAD(0x005c, PIN_OUTPUT, 1)  /* VOUT1_DATA23 */
-                       AM65X_IOPAD(0x0060, PIN_OUTPUT, 1)  /* VOUT1_VSYNC */
-                       AM65X_IOPAD(0x0064, PIN_OUTPUT, 1)  /* VOUT1_HSYNC */
-                       AM65X_IOPAD(0x0068, PIN_OUTPUT, 1)  /* VOUT1_PCLK */
-                       AM65X_IOPAD(0x006c, PIN_OUTPUT, 1)  /* VOUT1_DE */
-               >;
-       };
-
-       dp_pins_default: dp-default-pins {
-               pinctrl-single,pins = <
-                       AM65X_IOPAD(0x0078, PIN_OUTPUT, 7)  /* (AF18) DP rst_n */
-               >;
-       };
-
        main_i2c2_pins_default: main-i2c2-default-pins {
                pinctrl-single,pins = <
                        AM65X_IOPAD(0x0074, PIN_INPUT,  5)  /* (T27) I2C2_SCL */
        pinctrl-0 = <&main_uart1_pins_default>;
 };
 
-&mcu_uart0 {
-       status = "okay";
-};
-
-&main_gpio0 {
-       gpio-line-names =
-               "main_gpio0-base", "", "", "", "", "", "", "", "", "",
-               "", "", "", "", "", "", "", "", "", "",
-               "", "", "", "", "", "", "", "", "", "",
-               "", "", "", "IO4", "", "IO5", "", "", "IO6", "",
-               "", "", "", "IO7", "", "", "", "", "IO8", "",
-               "", "IO9";
-};
-
 &main_gpio1 {
        pinctrl-names = "default";
        pinctrl-0 = <&main_pcie_enable_pins_default>;
 };
 
-&wkup_gpio0 {
-       pinctrl-names = "default";
-       pinctrl-0 =
-               <&arduino_i2c_aio_switch_pins_default>,
-               <&arduino_io_oe_pins_default>,
-               <&push_button_pins_default>,
-               <&db9_com_mode_pins_default>;
-       gpio-line-names =
-               /* 0..9 */
-               "wkup_gpio0-base", "", "", "", "UART0-mode1", "UART0-mode0",
-               "UART0-enable", "UART0-terminate", "", "WIFI-disable",
-               /* 10..19 */
-               "", "", "", "", "", "", "", "", "", "",
-               /* 20..29 */
-               "", "A4A5-I2C-mux", "", "", "", "USER-button", "", "", "","IO0",
-               /* 30..39 */
-               "IO1", "IO2", "", "IO3", "IO17-direction", "A5",
-               "IO16-direction", "IO15-direction", "IO14-direction", "A3",
-               /* 40..49 */
-               "", "IO18-direction", "A4", "A2", "A1", "A0", "", "", "IO13",
-               "IO11",
-               /* 50..51 */
-               "IO12", "IO10";
-};
-
-&wkup_i2c0 {
-       status = "okay";
-       pinctrl-names = "default";
-       pinctrl-0 = <&wkup_i2c0_pins_default>;
-       clock-frequency = <400000>;
-};
-
 &mcu_i2c0 {
        status = "okay";
        pinctrl-names = "default";
                ti,vsel1-state-high;
                ti,enable-vout-discharge;
        };
-
-       /* D4200 */
-       pcal9535_1: gpio@20 {
-               compatible = "nxp,pcal9535";
-               reg = <0x20>;
-               #gpio-cells = <2>;
-               gpio-controller;
-               gpio-line-names =
-                       "A0-pull", "A1-pull", "A2-pull", "A3-pull", "A4-pull",
-                       "A5-pull", "", "",
-                       "IO14-enable", "IO15-enable", "IO16-enable",
-                       "IO17-enable", "IO18-enable", "IO19-enable";
-       };
-
-       /* D4201 */
-       pcal9535_2: gpio@21 {
-               compatible = "nxp,pcal9535";
-               reg = <0x21>;
-               #gpio-cells = <2>;
-               gpio-controller;
-               gpio-line-names =
-                       "IO0-direction", "IO1-direction", "IO2-direction",
-                       "IO3-direction", "IO4-direction", "IO5-direction",
-                       "IO6-direction", "IO7-direction",
-                       "IO8-direction", "IO9-direction", "IO10-direction",
-                       "IO11-direction", "IO12-direction", "IO13-direction",
-                       "IO19-direction";
-       };
-
-       /* D4202 */
-       pcal9535_3: gpio@25 {
-               compatible = "nxp,pcal9535";
-               reg = <0x25>;
-               #gpio-cells = <2>;
-               gpio-controller;
-               gpio-line-names =
-                       "IO0-pull", "IO1-pull", "IO2-pull", "IO3-pull",
-                       "IO4-pull", "IO5-pull", "IO6-pull", "IO7-pull",
-                       "IO8-pull", "IO9-pull", "IO10-pull", "IO11-pull",
-                       "IO12-pull", "IO13-pull";
-       };
 };
 
 &main_i2c0 {
 
        #address-cells = <1>;
        #size-cells = <0>;
-
-       edp-bridge@f {
-               compatible = "toshiba,tc358767";
-               reg = <0x0f>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&dp_pins_default>;
-               reset-gpios = <&main_gpio0 30 GPIO_ACTIVE_HIGH>;
-
-               clock-names = "ref";
-               clocks = <&dp_refclk>;
-
-               toshiba,hpd-pin = <0>;
-
-               ports {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       port@1 {
-                               reg = <1>;
-
-                               bridge_in: endpoint {
-                                       remote-endpoint = <&dpi_out>;
-                               };
-                       };
-               };
-       };
 };
 
 &mcu_cpsw {
        ti,pindir-d0-out-d1-in;
 };
 
-&tscadc1 {
-       status = "okay";
-       adc {
-               ti,adc-channels = <0 1 2 3 4 5>;
-       };
-};
-
 &ospi0 {
        status = "okay";
        pinctrl-names = "default";
        };
 };
 
-&dss {
-       pinctrl-names = "default";
-       pinctrl-0 = <&dss_vout1_pins_default>;
-
-       assigned-clocks = <&k3_clks 67 2>;
-       assigned-clock-parents = <&k3_clks 67 5>;
-};
-
-&dss_ports {
-       #address-cells = <1>;
-       #size-cells = <0>;
-       port@1 {
-               reg = <1>;
-
-               dpi_out: endpoint {
-                       remote-endpoint = <&bridge_in>;
-               };
-       };
-};
-
 &pcie1_rc {
        status = "okay";
        pinctrl-names = "default";
 &mcu_r5fss0_core0 {
        memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
                        <&mcu_r5fss0_core0_memory_region>;
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
 };
 
 &mcu_r5fss0_core1 {
        memory-region = <&mcu_r5fss0_core1_dma_memory_region>,
                        <&mcu_r5fss0_core1_memory_region>;
-       mboxes = <&mailbox0_cluster1>, <&mbox_mcu_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster1 &mbox_mcu_r5fss0_core1>;
+};
+
+&mcu_rti1 {
+       memory-region = <&wdt_reset_memory_region>;
 };
 
 &icssg0_mdio {
diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-dp.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-dp.dtsi
new file mode 100644 (file)
index 0000000..984cc80
--- /dev/null
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Siemens AG, 2024
+ *
+ * Authors:
+ *   Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * Common bits for IOT2050 variants with Display Port
+ */
+
+&main_pmx0 {
+       dss_vout1_pins_default: dss-vout1-default-pins {
+               pinctrl-single,pins = <
+                       AM65X_IOPAD(0x0000, PIN_OUTPUT, 1)  /* VOUT1_DATA0 */
+                       AM65X_IOPAD(0x0004, PIN_OUTPUT, 1)  /* VOUT1_DATA1 */
+                       AM65X_IOPAD(0x0008, PIN_OUTPUT, 1)  /* VOUT1_DATA2 */
+                       AM65X_IOPAD(0x000c, PIN_OUTPUT, 1)  /* VOUT1_DATA3 */
+                       AM65X_IOPAD(0x0010, PIN_OUTPUT, 1)  /* VOUT1_DATA4 */
+                       AM65X_IOPAD(0x0014, PIN_OUTPUT, 1)  /* VOUT1_DATA5 */
+                       AM65X_IOPAD(0x0018, PIN_OUTPUT, 1)  /* VOUT1_DATA6 */
+                       AM65X_IOPAD(0x001c, PIN_OUTPUT, 1)  /* VOUT1_DATA7 */
+                       AM65X_IOPAD(0x0020, PIN_OUTPUT, 1)  /* VOUT1_DATA8 */
+                       AM65X_IOPAD(0x0024, PIN_OUTPUT, 1)  /* VOUT1_DATA9 */
+                       AM65X_IOPAD(0x0028, PIN_OUTPUT, 1)  /* VOUT1_DATA10 */
+                       AM65X_IOPAD(0x002c, PIN_OUTPUT, 1)  /* VOUT1_DATA11 */
+                       AM65X_IOPAD(0x0030, PIN_OUTPUT, 1)  /* VOUT1_DATA12 */
+                       AM65X_IOPAD(0x0034, PIN_OUTPUT, 1)  /* VOUT1_DATA13 */
+                       AM65X_IOPAD(0x0038, PIN_OUTPUT, 1)  /* VOUT1_DATA14 */
+                       AM65X_IOPAD(0x003c, PIN_OUTPUT, 1)  /* VOUT1_DATA15 */
+                       AM65X_IOPAD(0x0040, PIN_OUTPUT, 1)  /* VOUT1_DATA16 */
+                       AM65X_IOPAD(0x0044, PIN_OUTPUT, 1)  /* VOUT1_DATA17 */
+                       AM65X_IOPAD(0x0048, PIN_OUTPUT, 1)  /* VOUT1_DATA18 */
+                       AM65X_IOPAD(0x004c, PIN_OUTPUT, 1)  /* VOUT1_DATA19 */
+                       AM65X_IOPAD(0x0050, PIN_OUTPUT, 1)  /* VOUT1_DATA20 */
+                       AM65X_IOPAD(0x0054, PIN_OUTPUT, 1)  /* VOUT1_DATA21 */
+                       AM65X_IOPAD(0x0058, PIN_OUTPUT, 1)  /* VOUT1_DATA22 */
+                       AM65X_IOPAD(0x005c, PIN_OUTPUT, 1)  /* VOUT1_DATA23 */
+                       AM65X_IOPAD(0x0060, PIN_OUTPUT, 1)  /* VOUT1_VSYNC */
+                       AM65X_IOPAD(0x0064, PIN_OUTPUT, 1)  /* VOUT1_HSYNC */
+                       AM65X_IOPAD(0x0068, PIN_OUTPUT, 1)  /* VOUT1_PCLK */
+                       AM65X_IOPAD(0x006c, PIN_OUTPUT, 1)  /* VOUT1_DE */
+               >;
+       };
+
+       dp_pins_default: dp-default-pins {
+               pinctrl-single,pins = <
+                       AM65X_IOPAD(0x0078, PIN_OUTPUT, 7)  /* (AF18) DP rst_n */
+               >;
+       };
+};
+
+&main_i2c3 {
+       edp-bridge@f {
+               compatible = "toshiba,tc358767";
+               reg = <0x0f>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&dp_pins_default>;
+               reset-gpios = <&main_gpio0 30 GPIO_ACTIVE_HIGH>;
+
+               clock-names = "ref";
+               clocks = <&dp_refclk>;
+
+               toshiba,hpd-pin = <0>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@1 {
+                               reg = <1>;
+
+                               bridge_in: endpoint {
+                                       remote-endpoint = <&dpi_out>;
+                               };
+                       };
+               };
+       };
+};
+
+&dss {
+       pinctrl-names = "default";
+       pinctrl-0 = <&dss_vout1_pins_default>;
+
+       assigned-clocks = <&k3_clks 67 2>;
+       assigned-clock-parents = <&k3_clks 67 5>;
+};
+
+&dss_ports {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       port@1 {
+               reg = <1>;
+
+               dpi_out: endpoint {
+                       remote-endpoint = <&bridge_in>;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-usb3.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-usb3.dtsi
new file mode 100644 (file)
index 0000000..e5bd7c3
--- /dev/null
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Siemens AG, 2024
+ *
+ * Authors:
+ *   Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * Common bits for IOT2050 variants with USB3 support
+ */
+
+&serdes0 {
+       assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>;
+       assigned-clock-parents = <&k3_clks 153 7>, <&k3_clks 153 4>;
+};
+
+&dwc3_0 {
+       assigned-clock-parents = <&k3_clks 151 4>,  /* set REF_CLK to 20MHz i.e. PER0_PLL/48 */
+                                <&k3_clks 151 8>;  /* set PIPE3_TXB_CLK to WIZ8B2M4VSB */
+       phys = <&serdes0 PHY_TYPE_USB3 0>;
+       phy-names = "usb3-phy";
+};
+
+&usb0 {
+       maximum-speed = "super-speed";
+       snps,dis-u1-entry-quirk;
+       snps,dis-u2-entry-quirk;
+};
index fcea544656360c5b86f9f0859cf6472f70d702ef..ff857117d71937b132468ceb915500eb533fcb9a 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM6 SoC Family Main Domain peripherals
  *
- * Copyright (C) 2016-2018 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2016-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 #include <dt-bindings/phy/phy-am654-serdes.h>
 
                status = "disabled";
        };
 
-       pcie0_ep: pcie-ep@5500000 {
-               compatible = "ti,am654-pcie-ep";
-               reg = <0x0 0x5500000 0x0 0x1000>, <0x0 0x5501000 0x0 0x1000>, <0x0 0x10000000 0x0 0x8000000>, <0x0 0x5506000 0x0 0x1000>;
-               reg-names = "app", "dbics", "addr_space", "atu";
-               power-domains = <&k3_pds 120 TI_SCI_PD_EXCLUSIVE>;
-               ti,syscon-pcie-mode = <&scm_conf 0x4060>;
-               num-ib-windows = <16>;
-               num-ob-windows = <16>;
-               max-link-speed = <2>;
-               dma-coherent;
-               interrupts = <GIC_SPI 340 IRQ_TYPE_EDGE_RISING>;
-               status = "disabled";
-       };
-
        pcie1_rc: pcie@5600000 {
                compatible = "ti,am654-pcie-rc";
                reg = <0x0 0x5600000 0x0 0x1000>, <0x0 0x5601000 0x0 0x1000>, <0x0 0x18000000 0x0 0x2000>, <0x0 0x5606000 0x0 0x1000>;
                status = "disabled";
        };
 
-       pcie1_ep: pcie-ep@5600000 {
-               compatible = "ti,am654-pcie-ep";
-               reg = <0x0 0x5600000 0x0 0x1000>, <0x0 0x5601000 0x0 0x1000>, <0x0 0x18000000 0x0 0x4000000>, <0x0 0x5606000 0x0 0x1000>;
-               reg-names = "app", "dbics", "addr_space", "atu";
-               power-domains = <&k3_pds 121 TI_SCI_PD_EXCLUSIVE>;
-               ti,syscon-pcie-mode = <&scm_conf 0x4070>;
-               num-ib-windows = <16>;
-               num-ob-windows = <16>;
-               max-link-speed = <2>;
-               dma-coherent;
-               interrupts = <GIC_SPI 355 IRQ_TYPE_EDGE_RISING>;
-               status = "disabled";
-       };
-
        mcasp0: mcasp@2b00000 {
                compatible = "ti,am33xx-mcasp-audio";
                reg = <0x0 0x02b00000 0x0 0x2000>,
                      <0x0 0x04a07000 0x0 0x1000>, /* ovr1 */
                      <0x0 0x04a08000 0x0 0x1000>, /* ovr2 */
                      <0x0 0x04a0a000 0x0 0x1000>, /* vp1 */
-                     <0x0 0x04a0b000 0x0 0x1000>; /* vp2 */
+                     <0x0 0x04a0b000 0x0 0x1000>, /* vp2 */
+                     <0x0 0x04a01000 0x0 0x1000>; /* common1 */
                reg-names = "common", "vidl1", "vid",
-                       "ovr1", "ovr2", "vp1", "vp2";
+                       "ovr1", "ovr2", "vp1", "vp2", "common1";
 
                ti,am65x-oldi-io-ctrl = <&dss_oldi_io_ctrl>;
 
                };
        };
 
+       gpu: gpu@7000000 {
+               compatible = "ti,am6548-gpu", "img,powervr-sgx544";
+               reg = <0x0 0x7000000 0x0 0x10000>;
+               interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
+               power-domains = <&k3_pds 65 TI_SCI_PD_EXCLUSIVE>;
+       };
+
        ehrpwm0: pwm@3000000 {
                compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm";
                #pwm-cells = <3>;
index ecd7356f3315d1ad9ebbacd06ae1bf70fecf36d7..6ff3ccc39fb448c4ca9fd642740ff77bb20b558b 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM6 SoC Family MCU Domain peripherals
  *
- * Copyright (C) 2016-2020 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2016-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_mcu {
index f037b36243ceda1275c628f0b28f32d03ef62f53..37527890ddeaf9a5517d037deb7d7e98696e638d 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM6 SoC Family Wakeup Domain peripherals
  *
- * Copyright (C) 2016-2018 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2016-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_wakeup {
index 4d7b6155a76b7bb3a0d802e19fc8e6692284083a..c59baebc5a25b1baa548a992375bb2cba57a28b6 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM6 SoC Family
  *
- * Copyright (C) 2016-2018 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2016-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/gpio/gpio.h>
index 0f22e00faa9032ffa384cd1fb7d71ffdb1d5b72d..cbb3caaf82c3108dcda8953f379a494113e5ca29 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM65 SoC family in Dual core configuration
  *
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include "k3-am65.dtsi"
index 1d6cddb1199149756b6101f2c206d3e23e3ff56b..eed6fe70d2970a2e201cbbc619c90c4d92fc2c91 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) Siemens AG, 2018-2021
  *
@@ -11,6 +11,7 @@
 
 #include "k3-am652.dtsi"
 #include "k3-am65-iot2050-common.dtsi"
+#include "k3-am65-iot2050-arduino-connector.dtsi"
 
 / {
        memory@80000000 {
@@ -40,8 +41,3 @@
        pinctrl-names = "default";
        pinctrl-0 = <&main_uart0_pins_default>;
 };
-
-&mcu_r5fss0 {
-       /* lock-step mode not supported on Basic boards */
-       ti,cluster-mode = <0>;
-};
index c62549a4b43679f53b1e5f60be553cb792502a41..c1faf9497b63e8531206f5a7035e0c6ae508abc7 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) Siemens AG, 2018-2021
  *
@@ -17,6 +17,8 @@
 
 #include "k3-am6528-iot2050-basic-common.dtsi"
 #include "k3-am65-iot2050-common-pg2.dtsi"
+#include "k3-am65-iot2050-dp.dtsi"
+#include "k3-am65-iot2050-usb3.dtsi"
 
 / {
        compatible = "siemens,iot2050-basic-pg2", "ti,am654";
index 87928ff28214d027672c70b042aeb6b9c5234b09..29a31891b3db6c9f5bb7ec9f38e9419f024da7bf 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) Siemens AG, 2018-2021
  *
@@ -22,3 +22,8 @@
        compatible = "siemens,iot2050-basic", "ti,am654";
        model = "SIMATIC IOT2050 Basic";
 };
+
+&mcu_r5fss0 {
+       /* lock-step mode not supported on this board */
+       ti,cluster-mode = <0>;
+};
index 3be92c39ecbae72e6e973a83cb91e7a9b4cc4dc0..364c57b3b3a0612f1ad89f945aeccf1f9f384ffc 100644 (file)
@@ -1,10 +1,10 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /**
  * OLDI-LCD1EVM Rocktech integrated panel and touch DT overlay for AM654-EVM.
  * Panel Link: https://www.digimax.it/en/tft-lcd/20881-RK101II01D-CT
  * AM654 LCD EVM: https://www.ti.com/tool/TMDSLCD1EVM
  *
- * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index 822c288d2797635f51387fc95c212c5b7b614d06..aba0c52b121338feabdd5b01ef65bb85f85ed762 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2016-2020 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2016-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
 &mcu_r5fss0_core0 {
        memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
                        <&mcu_r5fss0_core0_memory_region>;
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
 };
 
 &mcu_r5fss0_core1 {
        memory-region = <&mcu_r5fss0_core1_dma_memory_region>,
                        <&mcu_r5fss0_core1_memory_region>;
-       mboxes = <&mailbox0_cluster1>, <&mbox_mcu_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster1 &mbox_mcu_r5fss0_core1>;
 };
 
 &ospi0 {
index ec8cf20ca3ac79e76d8e007de64874121e810adf..0a6e75265ba9296a369e3ec58b2adfed3af2b663 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /**
  * DT overlay for IDK application board on AM654 EVM
  *
- * Copyright (C) 2018-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index 150428dfce6f46dad729ef25010ceb9422d9e365..8bdb87fcbde007b4d65170d2527628d364816f64 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /**
  * DT overlay for IDK application board on AM654 EVM
  *
- * Copyright (C) 2018-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index 9021c738056be9f65b46e169cac8efb8c695ecc8..de5a2ed907a7761f4a27854e7dcf353aec28bd80 100644 (file)
@@ -1,4 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
 
 #include <dt-bindings/thermal/thermal.h>
 
diff --git a/arch/arm64/boot/dts/ti/k3-am654-pcie-usb2.dtso b/arch/arm64/boot/dts/ti/k3-am654-pcie-usb2.dtso
new file mode 100644 (file)
index 0000000..c3cb752
--- /dev/null
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/**
+ * DT overlay for SERDES personality card: 2lane PCIe + USB2.0 Host on AM654 EVM
+ *
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/phy/phy-am654-serdes.h>
+#include "k3-pinctrl.h"
+
+&serdes0 {
+       assigned-clocks = <&k3_clks 153 4>,
+                         <&serdes0 AM654_SERDES_CMU_REFCLK>,
+                         <&serdes0 AM654_SERDES_RO_REFCLK>;
+       assigned-clock-parents = <&k3_clks 153 8>,
+                                <&k3_clks 153 4>,
+                                <&k3_clks 153 4>;
+       status = "okay";
+};
+
+&serdes1 {
+       assigned-clocks = <&serdes1 AM654_SERDES_CMU_REFCLK>;
+       assigned-clock-parents = <&serdes0 AM654_SERDES_RO_REFCLK>;
+       status = "okay";
+};
+
+&pcie0_rc {
+       num-lanes = <2>;
+       phys = <&serdes0 PHY_TYPE_PCIE 1>, <&serdes1 PHY_TYPE_PCIE 1>;
+       phy-names = "pcie-phy0", "pcie-phy1";
+       reset-gpios = <&pca9555 5 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
+&main_pmx0 {
+       usb0_pins_default: usb0-default-pins {
+               pinctrl-single,pins = <
+                       AM65X_IOPAD(0x02bc, PIN_OUTPUT, 0) /* (AD9) USB0_DRVVBUS */
+               >;
+       };
+};
+
+&dwc3_0 {
+       status = "okay";
+};
+
+&usb0_phy {
+       status = "okay";
+};
+
+&usb0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&usb0_pins_default>;
+       dr_mode = "host";
+};
diff --git a/arch/arm64/boot/dts/ti/k3-am654-pcie-usb3.dtso b/arch/arm64/boot/dts/ti/k3-am654-pcie-usb3.dtso
new file mode 100644 (file)
index 0000000..333e423
--- /dev/null
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/**
+ * DT overlay for SERDES personality card: 1lane PCIe + USB3.0 DRD on AM654 EVM
+ *
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/phy/phy-am654-serdes.h>
+
+#include "k3-pinctrl.h"
+
+&serdes1 {
+       status = "okay";
+};
+
+&pcie1_rc {
+       num-lanes = <1>;
+       phys = <&serdes1 PHY_TYPE_PCIE 0>;
+       phy-names = "pcie-phy0";
+       reset-gpios = <&pca9555 5 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
+&main_pmx0 {
+       usb0_pins_default: usb0-default-pins {
+               pinctrl-single,pins = <
+                       AM65X_IOPAD(0x02bc, PIN_OUTPUT, 0) /* (AD9) USB0_DRVVBUS */
+               >;
+       };
+};
+
+&serdes0 {
+       status = "okay";
+       assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>;
+       assigned-clock-parents = <&k3_clks 153 7>, <&k3_clks 153 4>;
+};
+
+&dwc3_0 {
+       status = "okay";
+       assigned-clock-parents = <&k3_clks 151 4>,      /* set REF_CLK to 20MHz i.e. PER0_PLL/48 */
+       <&k3_clks 151 8>;      /* set PIPE3_TXB_CLK to WIZ8B2M4VSB */
+       phys = <&serdes0 PHY_TYPE_USB3 0>;
+       phy-names = "usb3-phy";
+};
+
+&usb0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&usb0_pins_default>;
+       dr_mode = "host";
+       maximum-speed = "super-speed";
+       snps,dis-u1-entry-quirk;
+       snps,dis-u2-entry-quirk;
+};
+
+&usb0_phy {
+       status = "okay";
+};
index 888567b921f0ac46530f9a38daeea174e634ad72..bb77c8454734b76b03e7929d914921423a042f19 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for AM6 SoC family in Quad core configuration
  *
- * Copyright (C) 2016-2018 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2016-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include "k3-am65.dtsi"
index 3864ec54e3716d984ea5ba4f342d37a26646a582..ae842b85b70de0b0524e9429f4e1c338c5425d40 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) Siemens AG, 2018-2021
  *
index bd6f2e696e94c7f49fc85acfd918c438d753ebbd..cc619bbec181eac4510700d7661b0d1712a3d383 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) Siemens AG, 2018-2023
  *
 
 #include "k3-am6548-iot2050-advanced-common.dtsi"
 #include "k3-am65-iot2050-common-pg2.dtsi"
+#include "k3-am65-iot2050-arduino-connector.dtsi"
+#include "k3-am65-iot2050-dp.dtsi"
 
 / {
        compatible = "siemens,iot2050-advanced-m2", "ti,am654";
        model = "SIMATIC IOT2050 Advanced M2";
 };
 
-&mcu_r5fss0 {
-       /* lock-step mode not supported on this board */
-       ti,cluster-mode = <0>;
-};
-
 &main_pmx0 {
        main_bkey_pcie_reset: main-bkey-pcie-reset-default-pins {
                pinctrl-single,pins = <
 &pcie1_rc {
        status = "disabled";
 };
-
-&dwc3_0 {
-       assigned-clock-parents = <&k3_clks 151 4>,  /* set REF_CLK to 20MHz i.e. PER0_PLL/48 */
-                                <&k3_clks 151 9>;  /* set PIPE3_TXB_CLK to CLK_12M_RC/256 (for HS only) */
-       /delete-property/ phys;
-       /delete-property/ phy-names;
-};
-
-&usb0 {
-       maximum-speed = "high-speed";
-       /delete-property/ snps,dis-u1-entry-quirk;
-       /delete-property/ snps,dis-u2-entry-quirk;
-};
index f00dc86d01b99a535445f852cc9f2a09f93f2391..ec721275e8e26efe5fbdfec824c3b9deee5d4b0b 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) Siemens AG, 2018-2021
+ * Copyright (c) Siemens AG, 2018-2023
  *
  * Authors:
  *   Le Jin <le.jin@siemens.com>
 
 #include "k3-am6548-iot2050-advanced-common.dtsi"
 #include "k3-am65-iot2050-common-pg2.dtsi"
+#include "k3-am65-iot2050-arduino-connector.dtsi"
+#include "k3-am65-iot2050-dp.dtsi"
+#include "k3-am65-iot2050-usb3.dtsi"
 
 / {
        compatible = "siemens,iot2050-advanced-pg2", "ti,am654";
        model = "SIMATIC IOT2050 Advanced PG2";
 };
-
-&mcu_r5fss0 {
-       /* lock-step mode not supported on this board */
-       ti,cluster-mode = <0>;
-};
diff --git a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-sm.dts b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-sm.dts
new file mode 100644 (file)
index 0000000..b829f4b
--- /dev/null
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Siemens AG, 2023
+ *
+ * Authors:
+ *   Baocheng Su <baocheng.su@siemens.com>
+ *   Chao Zeng <chao.zeng@siemens.com>
+ *   Huaqian Li <huaqian.li@siemens.com>
+ *
+ * AM6548-based (quad-core) IOT2050 SM variant, Product Generation 2
+ * 4 GB RAM, 16 GB eMMC, USB-serial converter on connector X30
+ *
+ * Product homepage:
+ * https://new.siemens.com/global/en/products/automation/pc-based/iot-gateways/simatic-iot2050.html
+ */
+
+/dts-v1/;
+
+#include "k3-am6548-iot2050-advanced-common.dtsi"
+#include "k3-am65-iot2050-common-pg2.dtsi"
+
+/ {
+       compatible = "siemens,iot2050-advanced-sm", "ti,am654";
+       model = "SIMATIC IOT2050 Advanced SM";
+
+       memory@80000000 {
+               device_type = "memory";
+               /* 4G RAM */
+               reg = <0x00000000 0x80000000 0x00000000 0x80000000>,
+                     <0x00000008 0x80000000 0x00000000 0x80000000>;
+       };
+
+       aliases {
+               spi1 = &main_spi0;
+       };
+
+       leds {
+               pinctrl-0 = <&leds_pins_default>, <&user1_led_pins>;
+
+               led-2 {
+                       gpios = <&wkup_gpio0 52 GPIO_ACTIVE_HIGH>;
+               };
+
+               led-3 {
+                       gpios = <&wkup_gpio0 53 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
+
+&main_pmx0 {
+       main_pcie_enable_pins_default: main-pcie-enable-default-pins {
+               pinctrl-single,pins = <
+                       AM65X_IOPAD(0x01d8, PIN_OUTPUT, 7)  /* (AH12) GPIO1_22 */
+               >;
+       };
+
+       main_spi0_pins: main-spi0-default-pins  {
+               pinctrl-single,pins = <
+                       AM65X_IOPAD(0x01c4, PIN_INPUT, 0) /* (AH13) SPI0_CLK */
+                       AM65X_IOPAD(0x01c8, PIN_INPUT, 0) /* (AE13) SPI0_D0 */
+                       AM65X_IOPAD(0x01cc, PIN_INPUT, 0) /* (AD13) SPI0_D1 */
+                       AM65X_IOPAD(0x01bc, PIN_OUTPUT, 0) /* (AG13) SPI0_CS0 */
+               >;
+       };
+};
+
+&main_pmx1 {
+       asic_spi_mux_ctrl_pin: asic-spi-mux-ctrl-default-pins {
+               pinctrl-single,pins = <
+                       AM65X_IOPAD(0x0010, PIN_OUTPUT, 7)  /* (D21) GPIO1_86 */
+               >;
+       };
+};
+
+&wkup_pmx0 {
+       user1_led_pins: user1-led-default-pins {
+               pinctrl-single,pins = <
+                       /* (AB1) WKUP_UART0_RXD:WKUP_GPIO0_52, as USER 1 led red */
+                       AM65X_WKUP_IOPAD(0x00a0, PIN_OUTPUT, 7)
+                       /* (AB5) WKUP_UART0_TXD:WKUP_GPIO0_53, as USER 1 led green */
+                       AM65X_WKUP_IOPAD(0x00a4, PIN_OUTPUT, 7)
+               >;
+       };
+
+       soc_asic_pins: soc-asic-default-pins {
+               pinctrl-single,pins = <
+                       AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 7)  /* (P4) WKUP_GPIO0_29 */
+                       AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7)  /* (P5) WKUP_GPIO0_30 */
+                       AM65X_WKUP_IOPAD(0x004c, PIN_INPUT, 7)  /* (P1) WKUP_GPIO0_31 */
+               >;
+       };
+};
+
+&main_gpio0 {
+       gpio-line-names = "main_gpio0-base";
+};
+
+&main_gpio1 {
+       pinctrl-names = "default";
+       pinctrl-0 =
+               <&cp2102n_reset_pin_default>,
+               <&main_pcie_enable_pins_default>,
+               <&asic_spi_mux_ctrl_pin>;
+       gpio-line-names =
+               /* 0..9 */
+               "", "", "", "", "", "", "", "", "", "",
+               /* 10..19 */
+               "", "", "", "", "", "", "", "", "", "",
+               /* 20..29 */
+               "", "", "", "", "CP2102N-RESET", "", "", "", "", "",
+               /* 30..39 */
+               "", "", "", "", "", "", "", "", "", "",
+               /* 40..49 */
+               "", "", "", "", "", "", "", "", "", "",
+               /* 50..59 */
+               "", "", "", "", "", "", "", "", "", "",
+               /* 60..69 */
+               "", "", "", "", "", "", "", "", "", "",
+               /* 70..79 */
+               "", "", "", "", "", "", "", "", "", "",
+               /* 80..86 */
+               "", "", "", "", "", "", "ASIC-spi-mux-ctrl";
+};
+
+&wkup_gpio0 {
+       pinctrl-names = "default";
+       pinctrl-0 =
+               <&push_button_pins_default>,
+               <&db9_com_mode_pins_default>,
+               <&soc_asic_pins>;
+       gpio-line-names =
+               /* 0..9 */
+               "wkup_gpio0-base", "", "", "", "UART0-mode1", "UART0-mode0",
+               "UART0-enable", "UART0-terminate", "", "WIFI-disable",
+               /* 10..19 */
+               "", "", "", "", "", "", "", "", "", "",
+               /* 20..29 */
+               "", "", "", "", "", "USER-button", "", "", "","ASIC-gpio-0",
+               /* 30..31 */
+               "ASIC-gpio-1", "ASIC-gpio-2";
+};
+
+&main_spi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_spi0_pins>;
+
+       #address-cells = <1>;
+       #size-cells= <0>;
+};
+
+&mcu_spi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcu_spi0_pins_default>;
+};
+
+&main_i2c3 {
+       accelerometer: lsm6dso@6a {
+               compatible = "st,lsm6dso";
+               reg = <0x6a>;
+       };
+};
+
+&dss {
+       status = "disabled";
+};
+
+&serdes0 {
+       assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>;
+       assigned-clock-parents = <&k3_clks 153 8>, <&k3_clks 153 4>;
+};
+
+&serdes1 {
+       status = "disabled";
+};
+
+&pcie0_rc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&minipcie_pins_default>;
+
+       num-lanes = <1>;
+       phys = <&serdes0 PHY_TYPE_PCIE 1>;
+       phy-names = "pcie-phy0";
+       reset-gpios = <&wkup_gpio0 27 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
+&pcie1_rc {
+       status = "disabled";
+};
index 077f165bdc687f2fbf8f373913e808b3a980f639..649652a540efa52411b06f1f142076c46a8b60aa 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) Siemens AG, 2018-2021
  *
@@ -17,6 +17,7 @@
 
 #include "k3-am6548-iot2050-advanced-common.dtsi"
 #include "k3-am65-iot2050-common-pg1.dtsi"
+#include "k3-am65-iot2050-arduino-connector.dtsi"
 
 / {
        compatible = "siemens,iot2050-advanced", "ti,am654";
index d0cfdeac21fbe12b979e4b70062e58cf1f22d934..d743f023cdd9deb79ac219e24b90d3658ef45b75 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  *
  * Base Board: https://www.ti.com/lit/zip/SPRR463
  */
                        };
                };
        };
+
+       csi_mux: mux-controller {
+               compatible = "gpio-mux";
+               #mux-state-cells = <1>;
+               mux-gpios = <&exp3 1 GPIO_ACTIVE_HIGH>;
+               idle-state = <0>;
+       };
 };
 
 &main_pmx0 {
                >;
        };
 
+       main_i2c1_pins_default: main-i2c1-default-pins {
+               pinctrl-single,pins = <
+                       J721S2_IOPAD(0x0ac, PIN_INPUT, 13) /* (AC25) MCASP0_AXR15.I2C1_SCL */
+                       J721S2_IOPAD(0x0b0, PIN_INPUT, 13) /* (AD26) MCASP1_AXR3.I2C1_SDA */
+               >;
+       };
+
        main_mmc1_pins_default: main-mmc1-default-pins {
                pinctrl-single,pins = <
                        J721S2_IOPAD(0x104, PIN_INPUT, 0) /* (P23) MMC1_CLK */
        };
 };
 
+&main_i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_i2c1_pins_default>;
+       status = "okay";
+
+       exp3: gpio@20 {
+               compatible = "ti,tca6408";
+               reg = <0x20>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               gpio-line-names = "CSI_VIO_SEL", "CSI_SEL_FPC_EXPn",
+                                 "IO_EXP_CSI2_EXP_RSTz","CSI0_B_GPIO1",
+                                 "CSI1_B_GPIO1";
+       };
+
+       i2c-mux@70 {
+               compatible = "nxp,pca9543";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x70>;
+
+               cam0_i2c: i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+               };
+
+               cam1_i2c: i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <1>;
+               };
+
+       };
+};
+
 &main_i2c4 {
        status = "okay";
        pinctrl-names = "default";
index 20861a0a46b0d357b1942f054b043eeff2be7085..0f4a5da0ebc4527723eb16a0ccfb9a721b6cc71d 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
 };
 
 &mcu_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
        memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
                        <&mcu_r5fss0_core0_memory_region>;
 };
 
 &mcu_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>;
        memory-region = <&mcu_r5fss0_core1_dma_memory_region>,
                        <&mcu_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>;
        memory-region = <&main_r5fss0_core0_dma_memory_region>,
                        <&main_r5fss0_core0_memory_region>;
 };
 
 &main_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>;
        memory-region = <&main_r5fss0_core1_dma_memory_region>,
                        <&main_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss1_core0 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core0>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>;
        memory-region = <&main_r5fss1_core0_dma_memory_region>,
                        <&main_r5fss1_core0_memory_region>;
 };
 
 &main_r5fss1_core1 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core1>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>;
        memory-region = <&main_r5fss1_core1_dma_memory_region>,
                        <&main_r5fss1_core1_memory_region>;
 };
 
 &c71_0 {
        status = "okay";
-       mboxes = <&mailbox0_cluster4>, <&mbox_c71_0>;
+       mboxes = <&mailbox0_cluster4 &mbox_c71_0>;
        memory-region = <&c71_0_dma_memory_region>,
                        <&c71_0_memory_region>;
 };
 
 &c71_1 {
        status = "okay";
-       mboxes = <&mailbox0_cluster4>, <&mbox_c71_1>;
+       mboxes = <&mailbox0_cluster4 &mbox_c71_1>;
        memory-region = <&c71_1_dma_memory_region>,
                        <&c71_1_memory_region>;
 };
index 8da5915798688a5fb3016990079b848d083e0c11..50de2a448a3a684ed9034a834cbf5084277270ac 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  *
  * Design Files: https://www.ti.com/lit/zip/SPRR466
  * TRM: https://www.ti.com/lit/zip/spruj52
@@ -33,6 +33,7 @@
 
        memory@80000000 {
                device_type = "memory";
+               bootph-all;
                /* 32G RAM */
                reg = <0x00 0x80000000 0x00 0x80000000>,
                      <0x08 0x80000000 0x07 0x80000000>;
                        };
                };
        };
+
+       csi_mux: mux-controller {
+               compatible = "gpio-mux";
+               #mux-state-cells = <1>;
+               mux-gpios = <&exp2 1 GPIO_ACTIVE_HIGH>;
+               idle-state = <0>;
+       };
+
+       transceiver1: can-phy0 {
+               compatible = "ti,tcan1042";
+               #phy-cells = <0>;
+               max-bitrate = <5000000>;
+       };
+
+       transceiver2: can-phy1 {
+               compatible = "ti,tcan1042";
+               #phy-cells = <0>;
+               max-bitrate = <5000000>;
+       };
+
+       transceiver3: can-phy2 {
+               compatible = "ti,tcan1042";
+               #phy-cells = <0>;
+               max-bitrate = <5000000>;
+       };
+
+       transceiver4: can-phy3 {
+               compatible = "ti,tcan1042";
+               #phy-cells = <0>;
+               max-bitrate = <5000000>;
+       };
+
 };
 
 &main_pmx0 {
                >;
        };
 
+       main_i2c1_pins_default: main-i2c1-default-pins {
+               pinctrl-single,pins = <
+                       J784S4_IOPAD(0x0ac, PIN_INPUT_PULLUP, 13) /* (AE34) MCASP0_AXR15.I2C1_SCL */
+                       J784S4_IOPAD(0x0b0, PIN_INPUT_PULLUP, 13) /* (AL33) MCASP1_AXR3.I2C1_SDA */
+               >;
+       };
+
        main_mmc1_pins_default: main-mmc1-default-pins {
                bootph-all;
                pinctrl-single,pins = <
                        J784S4_IOPAD(0x000, PIN_INPUT, 7) /* (AN35) EXTINTN.GPIO0_0 */
                >;
        };
+
+       main_mcan6_pins_default: main-mcan6-default-pins {
+               pinctrl-single,pins = <
+                       J784S4_IOPAD(0x098, PIN_INPUT, 0) /* (AH36) MCAN6_RX */
+                       J784S4_IOPAD(0x094, PIN_OUTPUT, 0) /* (AG35) MCAN6_TX */
+               >;
+       };
+
+       main_mcan7_pins_default: main-mcan7-default-pins {
+               pinctrl-single,pins = <
+                       J784S4_IOPAD(0x0A0, PIN_INPUT, 0) /* (AD34) MCAN7_RX */
+                       J784S4_IOPAD(0x09C, PIN_OUTPUT, 0) /* (AF35) MCAN7_TX */
+               >;
+       };
+
+};
+
+&wkup_pmx0 {
+       bootph-all;
+       mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-default-pins {
+               pinctrl-single,pins = <
+                       J784S4_WKUP_IOPAD(0x000, PIN_OUTPUT, 0) /* (E32) MCU_OSPI0_CLK */
+                       J784S4_WKUP_IOPAD(0x02c, PIN_OUTPUT, 0) /* (A32) MCU_OSPI0_CSn0 */
+                       J784S4_WKUP_IOPAD(0x00c, PIN_INPUT, 0) /* (B33) MCU_OSPI0_D0 */
+                       J784S4_WKUP_IOPAD(0x010, PIN_INPUT, 0) /* (B32) MCU_OSPI0_D1 */
+                       J784S4_WKUP_IOPAD(0x014, PIN_INPUT, 0) /* (C33) MCU_OSPI0_D2 */
+                       J784S4_WKUP_IOPAD(0x018, PIN_INPUT, 0) /* (C35) MCU_OSPI0_D3 */
+                       J784S4_WKUP_IOPAD(0x01c, PIN_INPUT, 0) /* (D33) MCU_OSPI0_D4 */
+                       J784S4_WKUP_IOPAD(0x020, PIN_INPUT, 0) /* (D34) MCU_OSPI0_D5 */
+                       J784S4_WKUP_IOPAD(0x024, PIN_INPUT, 0) /* (E34) MCU_OSPI0_D6 */
+                       J784S4_WKUP_IOPAD(0x028, PIN_INPUT, 0) /* (E33) MCU_OSPI0_D7 */
+                       J784S4_WKUP_IOPAD(0x008, PIN_INPUT, 0) /* (C34) MCU_OSPI0_DQS */
+               >;
+       };
 };
 
 &wkup_pmx2 {
                        J784S4_WKUP_IOPAD(0x090, PIN_INPUT, 7) /* (H37) WKUP_GPIO0_14 */
                >;
        };
+
+       mcu_mcan0_pins_default: mcu-mcan0-default-pins {
+               pinctrl-single,pins = <
+                       J784S4_WKUP_IOPAD(0x054, PIN_INPUT, 0) /* (F38) MCU_MCAN0_RX */
+                       J784S4_WKUP_IOPAD(0x050, PIN_OUTPUT, 0) /* (K33) MCU_MCAN0_TX */
+               >;
+       };
+
+       mcu_mcan1_pins_default: mcu-mcan1-default-pins {
+               pinctrl-single,pins = <
+                       J784S4_WKUP_IOPAD(0x06c, PIN_INPUT, 0) /* (K36) WKUP_GPIO0_5.MCU_MCAN1_RX */
+                       J784S4_WKUP_IOPAD(0x068, PIN_OUTPUT, 0)/* (H35) WKUP_GPIO0_4.MCU_MCAN1_TX */
+               >;
+       };
+
 };
 
 &wkup_pmx3 {
                pinctrl-names = "default";
                pinctrl-0 = <&pmic_irq_pins_default>;
                interrupt-parent = <&wkup_gpio0>;
-               interrupts = <39 IRQ_TYPE_EDGE_FALLING>;
+               interrupts = <83 IRQ_TYPE_EDGE_FALLING>;
                gpio-controller;
                #gpio-cells = <2>;
                ti,primary-pmic;
        };
 };
 
+&main_i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_i2c1_pins_default>;
+       clock-frequency = <400000>;
+       status = "okay";
+
+       exp2: gpio@21 {
+               compatible = "ti,tca6408";
+               reg = <0x21>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               gpio-line-names = "CSI_VIO_SEL", "CSI_MUX_SEL_2", "CSI2_RSTz",
+                                 "IO_EXP_CAM0_GPIO1", "IO_EXP_CAM1_GPIO1";
+       };
+
+       i2c-mux@70 {
+               compatible = "nxp,pca9543";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x70>;
+
+               cam0_i2c: i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+               };
+
+               cam1_i2c: i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <1>;
+               };
+
+       };
+};
+
 &main_sdhci0 {
        bootph-all;
        /* eMMC */
 };
 
 &mcu_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
        memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
                        <&mcu_r5fss0_core0_memory_region>;
 };
 
 &mcu_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>;
        memory-region = <&mcu_r5fss0_core1_dma_memory_region>,
                        <&mcu_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>;
        memory-region = <&main_r5fss0_core0_dma_memory_region>,
                        <&main_r5fss0_core0_memory_region>;
 };
 
 &main_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>;
        memory-region = <&main_r5fss0_core1_dma_memory_region>,
                        <&main_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss1_core0 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core0>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>;
        memory-region = <&main_r5fss1_core0_dma_memory_region>,
                        <&main_r5fss1_core0_memory_region>;
 };
 
 &main_r5fss1_core1 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core1>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>;
        memory-region = <&main_r5fss1_core1_dma_memory_region>,
                        <&main_r5fss1_core1_memory_region>;
 };
 
 &main_r5fss2_core0 {
-       mboxes = <&mailbox0_cluster3>, <&mbox_main_r5fss2_core0>;
+       mboxes = <&mailbox0_cluster3 &mbox_main_r5fss2_core0>;
        memory-region = <&main_r5fss2_core0_dma_memory_region>,
                        <&main_r5fss2_core0_memory_region>;
 };
 
 &main_r5fss2_core1 {
-       mboxes = <&mailbox0_cluster3>, <&mbox_main_r5fss2_core1>;
+       mboxes = <&mailbox0_cluster3 &mbox_main_r5fss2_core1>;
        memory-region = <&main_r5fss2_core1_dma_memory_region>,
                        <&main_r5fss2_core1_memory_region>;
 };
 
 &c71_0 {
        status = "okay";
-       mboxes = <&mailbox0_cluster4>, <&mbox_c71_0>;
+       mboxes = <&mailbox0_cluster4 &mbox_c71_0>;
        memory-region = <&c71_0_dma_memory_region>,
                        <&c71_0_memory_region>;
 };
 
 &c71_1 {
        status = "okay";
-       mboxes = <&mailbox0_cluster4>, <&mbox_c71_1>;
+       mboxes = <&mailbox0_cluster4 &mbox_c71_1>;
        memory-region = <&c71_1_dma_memory_region>,
                        <&c71_1_memory_region>;
 };
 
 &c71_2 {
        status = "okay";
-       mboxes = <&mailbox0_cluster5>, <&mbox_c71_2>;
+       mboxes = <&mailbox0_cluster5 &mbox_c71_2>;
        memory-region = <&c71_2_dma_memory_region>,
                        <&c71_2_memory_region>;
 };
 
 &c71_3 {
        status = "okay";
-       mboxes = <&mailbox0_cluster5>, <&mbox_c71_3>;
+       mboxes = <&mailbox0_cluster5 &mbox_c71_3>;
        memory-region = <&c71_3_dma_memory_region>,
                        <&c71_3_memory_region>;
 };
        pinctrl-names = "default";
        pinctrl-0 = <&dss_vout0_pins_default>;
        assigned-clocks = <&k3_clks 218 2>,
-                         <&k3_clks 218 5>,
-                         <&k3_clks 218 14>,
-                         <&k3_clks 218 18>;
+                         <&k3_clks 218 5>;
        assigned-clock-parents = <&k3_clks 218 3>,
-                                <&k3_clks 218 7>,
-                                <&k3_clks 218 16>,
-                                <&k3_clks 218 22>;
+                                <&k3_clks 218 7>;
 };
 
 &serdes_wiz4 {
                };
        };
 };
+
+&mcu_mcan0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcu_mcan0_pins_default>;
+       phys = <&transceiver1>;
+};
+
+&mcu_mcan1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcu_mcan1_pins_default>;
+       phys = <&transceiver2>;
+};
+
+&main_mcan6 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_mcan6_pins_default>;
+       phys = <&transceiver3>;
+};
+
+&main_mcan7 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_mcan7_pins_default>;
+       phys = <&transceiver4>;
+};
+
+&ospi0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcu_fss0_ospi0_pins_default>;
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0x0>;
+               spi-tx-bus-width = <8>;
+               spi-rx-bus-width = <8>;
+               spi-max-frequency = <25000000>;
+               cdns,tshsl-ns = <60>;
+               cdns,tsd2d-ns = <60>;
+               cdns,tchsh-ns = <60>;
+               cdns,tslch-ns = <60>;
+               cdns,read-delay = <4>;
+
+               partitions {
+                       bootph-all;
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "ospi.tiboot3";
+                               reg = <0x0 0x100000>;
+                       };
+
+                       partition@100000 {
+                               label = "ospi.tispl";
+                               reg = <0x100000 0x200000>;
+                       };
+
+                       partition@300000 {
+                               label = "ospi.u-boot";
+                               reg = <0x300000 0x400000>;
+                       };
+
+                       partition@700000 {
+                               label = "ospi.env";
+                               reg = <0x700000 0x40000>;
+                       };
+
+                       partition@740000 {
+                               label = "ospi.env.backup";
+                               reg = <0x740000 0x40000>;
+                       };
+
+                       partition@800000 {
+                               label = "ospi.rootfs";
+                               reg = <0x800000 0x37c0000>;
+                       };
+
+                       partition@3fc0000 {
+                               bootph-pre-ram;
+                               label = "ospi.phypattern";
+                               reg = <0x3fc0000 0x40000>;
+                       };
+               };
+       };
+};
index cee2b4b0eb87dafc6f9f42f0d63ff62478ce3c92..6593c5da82c06463c2d7cbbe01d6fa481be1aa1a 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
                states = <1800000 0x0>,
                         <3300000 0x1>;
        };
+
+       transceiver1: can-phy1 {
+               compatible = "ti,tcan1043";
+               #phy-cells = <0>;
+               max-bitrate = <5000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&mcu_mcan0_gpio_pins_default>;
+               standby-gpios = <&wkup_gpio0 58 GPIO_ACTIVE_LOW>;
+               enable-gpios = <&wkup_gpio0 0 GPIO_ACTIVE_HIGH>;
+       };
+
+       transceiver2: can-phy2 {
+               compatible = "ti,tcan1042";
+               #phy-cells = <0>;
+               max-bitrate = <5000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&mcu_mcan1_gpio_pins_default>;
+               standby-gpios = <&wkup_gpio0 2 GPIO_ACTIVE_HIGH>;
+       };
+
+       transceiver3: can-phy3 {
+               compatible = "ti,tcan1043";
+               #phy-cells = <0>;
+               max-bitrate = <5000000>;
+               standby-gpios = <&exp2 7 GPIO_ACTIVE_LOW>;
+               enable-gpios = <&exp2 6 GPIO_ACTIVE_HIGH>;
+               mux-states = <&mux0 1>;
+       };
 };
 
 &wkup_pmx0 {
+};
+
+&wkup_pmx2 {
        mcu_uart0_pins_default: mcu-uart0-default-pins {
                pinctrl-single,pins = <
-                       J721E_WKUP_IOPAD(0xf4, PIN_INPUT, 0) /* (D20) MCU_UART0_RXD */
-                       J721E_WKUP_IOPAD(0xf0, PIN_OUTPUT, 0) /* (D19) MCU_UART0_TXD */
-                       J721E_WKUP_IOPAD(0xf8, PIN_INPUT, 0) /* (E20) MCU_UART0_CTSn */
-                       J721E_WKUP_IOPAD(0xfc, PIN_OUTPUT, 0) /* (E21) MCU_UART0_RTSn */
+                       J721E_WKUP_IOPAD(0x90, PIN_INPUT, 0) /* (E20) MCU_UART0_CTSn */
+                       J721E_WKUP_IOPAD(0x94, PIN_OUTPUT, 0) /* (E21) MCU_UART0_RTSn */
+                       J721E_WKUP_IOPAD(0x8c, PIN_INPUT, 0) /* (D20) MCU_UART0_RXD */
+                       J721E_WKUP_IOPAD(0x88, PIN_OUTPUT, 0) /* (D19) MCU_UART0_TXD */
                >;
        };
 
        wkup_uart0_pins_default: wkup-uart0-default-pins {
                pinctrl-single,pins = <
-                       J721E_WKUP_IOPAD(0xb0, PIN_INPUT, 0) /* (B14) WKUP_UART0_RXD */
-                       J721E_WKUP_IOPAD(0xb4, PIN_OUTPUT, 0) /* (A14) WKUP_UART0_TXD */
+                       J721E_WKUP_IOPAD(0x48, PIN_INPUT, 0) /* (B14) WKUP_UART0_RXD */
+                       J721E_WKUP_IOPAD(0x4c, PIN_OUTPUT, 0) /* (A14) WKUP_UART0_TXD */
                >;
        };
-};
 
-&wkup_pmx2 {
        mcu_cpsw_pins_default: mcu-cpsw-default-pins {
                pinctrl-single,pins = <
                        J721E_WKUP_IOPAD(0x0000, PIN_OUTPUT, 0) /* MCU_RGMII1_TX_CTL */
                        J721E_WKUP_IOPAD(0x0030, PIN_INPUT, 0) /* (L4) MCU_MDIO0_MDIO */
                >;
        };
+
+       mcu_mcan0_pins_default: mcu-mcan0-default-pins {
+               pinctrl-single,pins = <
+                       J721E_WKUP_IOPAD(0x54, PIN_INPUT, 0) /* (A17) MCU_MCAN0_RX */
+                       J721E_WKUP_IOPAD(0x50, PIN_OUTPUT, 0) /* (A16) MCU_MCAN0_TX */
+               >;
+       };
+
+       mcu_mcan1_pins_default: mcu-mcan1-default-pins {
+               pinctrl-single,pins = <
+                       J721E_WKUP_IOPAD(0x6c, PIN_INPUT, 0) /* (B16) WKUP_GPIO0_5.MCU_MCAN1_RX */
+                       J721E_WKUP_IOPAD(0x68, PIN_OUTPUT, 0) /* (D13) WKUP_GPIO0_4.MCU_MCAN1_TX */
+               >;
+       };
+
+       mcu_mcan0_gpio_pins_default: mcu-mcan0-gpio-default-pins {
+               pinctrl-single,pins = <
+                       J721E_WKUP_IOPAD(0x58, PIN_INPUT, 7) /* (B18) WKUP_GPIO0_0 */
+                       J721E_WKUP_IOPAD(0x40, PIN_INPUT, 7) /* (B17) MCU_SPI0_D1 */
+               >;
+       };
+
+       mcu_mcan1_gpio_pins_default: mcu-mcan1-gpio-default-pins {
+               pinctrl-single,pins = <
+                       J721E_WKUP_IOPAD(0x60, PIN_INPUT, 7) /* (D14) WKUP_GPIO0_2 */
+               >;
+       };
 };
 
 &main_pmx0 {
                        J721E_IOPAD(0xd0, PIN_OUTPUT, 7) /* (T5) SPI0_D1.GPIO0_55 */
                >;
        };
+
+       main_mcan3_pins_default: main-mcan3-default-pins {
+               pinctrl-single,pins = <
+                       J721E_IOPAD(0x3c, PIN_INPUT, 0) /* (W16) MCAN3_RX */
+                       J721E_IOPAD(0x38, PIN_OUTPUT, 0) /* (Y21) MCAN3_TX */
+               >;
+       };
 };
 
 &main_pmx1 {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&mcu_uart0_pins_default>;
-       clock-frequency = <96000000>;
 };
 
 &main_uart0 {
 };
 
 &pcie1_rc {
+       status = "okay";
        reset-gpios = <&exp1 2 GPIO_ACTIVE_HIGH>;
        phys = <&serdes0_pcie_link>;
        phy-names = "pcie-phy";
        num-lanes = <2>;
 };
 
-&pcie1_ep {
-       phys = <&serdes0_pcie_link>;
-       phy-names = "pcie-phy";
-       num-lanes = <2>;
-       status = "disabled";
+&mcu_mcan0 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcu_mcan0_pins_default>;
+       phys = <&transceiver1>;
+};
+
+&mcu_mcan1 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcu_mcan1_pins_default>;
+       phys = <&transceiver2>;
+};
+
+&main_mcan3 {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_mcan3_pins_default>;
+       phys = <&transceiver3>;
 };
index 32d905235ed7ee984a8df9fdb0c645379c64529f..6432ca08ee8e41d31e16956d70e4922ca749edcd 100644 (file)
@@ -1,9 +1,9 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /**
  * DT Overlay for CPSW5G in QSGMII mode using J7 Quad Port ETH EXP Add-On Ethernet Card with
  * J7200 board.
  *
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index da67bf8fe703ebcbc574f114396a710abbda4999..657f9cc9f4ea017f034a3d83ac30a8b5325b9dab 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for J7200 SoC Family Main Domain peripherals
  *
- * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 / {
                ranges = <0x00 0x00 0x00100000 0x1c000>;
 
                serdes_ln_ctrl: mux-controller@4080 {
-                       compatible = "mmio-mux";
+                       compatible = "reg-mux";
+                       reg = <0x4080 0x20>;
                        #mux-control-cells = <1>;
-                       mux-reg-masks = <0x4080 0x3>, <0x4084 0x3>, /* SERDES0 lane0/1 select */
-                                       <0x4088 0x3>, <0x408c 0x3>; /* SERDES0 lane2/3 select */
+                       mux-reg-masks = <0x0 0x3>, <0x4 0x3>, /* SERDES0 lane0/1 select */
+                                       <0x8 0x3>, <0xc 0x3>; /* SERDES0 lane2/3 select */
                };
 
                cpsw0_phy_gmii_sel: phy@4044 {
                };
 
                usb_serdes_mux: mux-controller@4000 {
-                       compatible = "mmio-mux";
+                       compatible = "reg-mux";
+                       reg = <0x4000 0x4>;
                        #mux-control-cells = <1>;
-                       mux-reg-masks = <0x4000 0x8000000>; /* USB0 to SERDES0 lane 1/3 mux */
+                       mux-reg-masks = <0x0 0x8000000>; /* USB0 to SERDES0 lane 1/3 mux */
                };
        };
 
 
        /* TIMERIO pad input CTRLMMR_TIMER*_CTRL registers */
        main_timerio_input: pinctrl@104200 {
-               compatible = "pinctrl-single";
+               compatible = "ti,j7200-padconf", "pinctrl-single";
                reg = <0x0 0x104200 0x0 0x50>;
                #pinctrl-cells = <1>;
                pinctrl-single,register-width = <32>;
 
        /* TIMERIO pad output CTCTRLMMR_TIMERIO*_CTRL registers */
        main_timerio_output: pinctrl@104280 {
-               compatible = "pinctrl-single";
+               compatible = "ti,j7200-padconf", "pinctrl-single";
                reg = <0x0 0x104280 0x0 0x20>;
                #pinctrl-cells = <1>;
                pinctrl-single,register-width = <32>;
        };
 
        main_pmx0: pinctrl@11c000 {
-               compatible = "pinctrl-single";
+               compatible = "ti,j7200-padconf", "pinctrl-single";
                /* Proxy 0 addressing */
                reg = <0x00 0x11c000 0x00 0x10c>;
                #pinctrl-cells = <1>;
        };
 
        main_pmx1: pinctrl@11c11c {
-               compatible = "pinctrl-single";
+               compatible = "ti,j7200-padconf", "pinctrl-single";
                /* Proxy 0 addressing */
                reg = <0x00 0x11c11c 0x00 0xc>;
                #pinctrl-cells = <1>;
                ranges = <0x01000000 0x0 0x18001000  0x00 0x18001000  0x0 0x0010000>,
                         <0x02000000 0x0 0x18011000  0x00 0x18011000  0x0 0x7fef000>;
                dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>;
-       };
-
-       pcie1_ep: pcie-ep@2910000 {
-               compatible = "ti,j7200-pcie-ep", "ti,j721e-pcie-ep";
-               reg = <0x00 0x02910000 0x00 0x1000>,
-                     <0x00 0x02917000 0x00 0x400>,
-                     <0x00 0x0d800000 0x00 0x00800000>,
-                     <0x00 0x18000000 0x00 0x08000000>;
-               reg-names = "intd_cfg", "user_cfg", "reg", "mem";
-               interrupt-names = "link_state";
-               interrupts = <GIC_SPI 330 IRQ_TYPE_EDGE_RISING>;
-               ti,syscon-pcie-ctrl = <&scm_conf 0x4074>;
-               max-link-speed = <3>;
-               num-lanes = <4>;
-               power-domains = <&k3_pds 240 TI_SCI_PD_EXCLUSIVE>;
-               clocks = <&k3_clks 240 6>;
-               clock-names = "fck";
-               max-functions = /bits/ 8 <6>;
-               max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>;
-               dma-coherent;
+               status = "disabled";
        };
 
        usbss0: cdns-usb@4104000 {
                status = "disabled";
        };
 
+       main_mcan0: can@2701000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x02701000 0x00 0x200>,
+                     <0x00 0x02708000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 156 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 156 0>, <&k3_clks 156 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan1: can@2711000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x02711000 0x00 0x200>,
+                     <0x00 0x02718000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 158 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 158 0>, <&k3_clks 158 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan2: can@2721000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x02721000 0x00 0x200>,
+                     <0x00 0x02728000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 160 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 160 0>, <&k3_clks 160 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan3: can@2731000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x02731000 0x00 0x200>,
+                     <0x00 0x02738000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 161 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 161 0>, <&k3_clks 161 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan4: can@2741000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x02741000 0x00 0x200>,
+                     <0x00 0x02748000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 162 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 162 0>, <&k3_clks 162 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan5: can@2751000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x02751000 0x00 0x200>,
+                     <0x00 0x02758000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 163 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 163 0>, <&k3_clks 163 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan6: can@2761000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x02761000 0x00 0x200>,
+                     <0x00 0x02768000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 164 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 164 0>, <&k3_clks 164 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan7: can@2771000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x02771000 0x00 0x200>,
+                     <0x00 0x02778000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 165 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 165 0>, <&k3_clks 165 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan8: can@2781000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x02781000 0x00 0x200>,
+                     <0x00 0x02788000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 166 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 166 0>, <&k3_clks 166 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 576 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 577 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan9: can@2791000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x02791000 0x00 0x200>,
+                     <0x00 0x02798000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 167 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 167 0>, <&k3_clks 167 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 579 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 580 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan10: can@27a1000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x027a1000 0x00 0x200>,
+                     <0x00 0x027a8000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 168 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 168 0>, <&k3_clks 168 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 583 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan11: can@27b1000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x027b1000 0x00 0x200>,
+                     <0x00 0x027b8000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 169 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 169 0>, <&k3_clks 169 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 585 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 586 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan12: can@27c1000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x027c1000 0x00 0x200>,
+                     <0x00 0x027c8000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 170 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 170 0>, <&k3_clks 170 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 588 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 589 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan13: can@27d1000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x027d1000 0x00 0x200>,
+                     <0x00 0x027d8000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 171 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 171 0>, <&k3_clks 171 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 591 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 592 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan14: can@2681000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x02681000 0x00 0x200>,
+                     <0x00 0x02688000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 150 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 150 0>, <&k3_clks 150 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 594 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 595 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan15: can@2691000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x02691000 0x00 0x200>,
+                     <0x00 0x02698000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 151 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 151 0>, <&k3_clks 151 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 597 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 598 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan16: can@26a1000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x026a1000 0x00 0x200>,
+                     <0x00 0x026a8000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 152 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 152 0>, <&k3_clks 152 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 784 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 785 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       main_mcan17: can@26b1000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x026b1000 0x00 0x200>,
+                     <0x00 0x026b8000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 153 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 153 0>, <&k3_clks 153 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 787 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 788 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
        main_spi0: spi@2100000 {
                compatible = "ti,am654-mcspi","ti,omap4-mcspi";
                reg = <0x00 0x02100000 0x00 0x400>;
index 60b26374ae0ccfe6a9e9154832992bf854446df3..7cf21c99956e09c0cb40fc73e09853e51ef2139d 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for J7200 SoC Family MCU/WAKEUP Domain peripherals
  *
- * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_mcu_wakeup {
 
        /* MCU_TIMERIO pad input CTRLMMR_MCU_TIMER*_CTRL registers */
        mcu_timerio_input: pinctrl@40f04200 {
-               compatible = "pinctrl-single";
+               compatible = "ti,j7200-padconf", "pinctrl-single";
                reg = <0x0 0x40f04200 0x0 0x28>;
                #pinctrl-cells = <1>;
                pinctrl-single,register-width = <32>;
 
        /* MCU_TIMERIO pad output CTRLMMR_MCU_TIMERIO*_CTRL registers */
        mcu_timerio_output: pinctrl@40f04280 {
-               compatible = "pinctrl-single";
+               compatible = "ti,j7200-padconf", "pinctrl-single";
                reg = <0x0 0x40f04280 0x0 0x28>;
                #pinctrl-cells = <1>;
                pinctrl-single,register-width = <32>;
        };
 
        wkup_pmx0: pinctrl@4301c000 {
-               compatible = "pinctrl-single";
+               compatible = "ti,j7200-padconf", "pinctrl-single";
                /* Proxy 0 addressing */
                reg = <0x00 0x4301c000 0x00 0x34>;
                #pinctrl-cells = <1>;
        };
 
        wkup_pmx1: pinctrl@4301c038 {
-               compatible = "pinctrl-single";
+               compatible = "ti,j7200-padconf", "pinctrl-single";
                /* Proxy 0 addressing */
                reg = <0x00 0x4301c038 0x00 0x8>;
                #pinctrl-cells = <1>;
        };
 
        wkup_pmx2: pinctrl@4301c068 {
-               compatible = "pinctrl-single";
+               compatible = "ti,j7200-padconf", "pinctrl-single";
                /* Proxy 0 addressing */
                reg = <0x00 0x4301c068 0x00 0xec>;
                #pinctrl-cells = <1>;
        };
 
        wkup_pmx3: pinctrl@4301c174 {
-               compatible = "pinctrl-single";
+               compatible = "ti,j7200-padconf", "pinctrl-single";
                /* Proxy 0 addressing */
                reg = <0x00 0x4301c174 0x00 0x20>;
                #pinctrl-cells = <1>;
                status = "disabled";
        };
 
-       fss: syscon@47000000 {
-               compatible = "syscon", "simple-mfd";
+       fss: bus@47000000 {
+               compatible = "simple-bus";
                reg = <0x00 0x47000000 0x00 0x100>;
                #address-cells = <2>;
                #size-cells = <2>;
                ranges;
 
-               hbmc_mux: hbmc-mux {
-                       compatible = "mmio-mux";
+               hbmc_mux: mux-controller@47000004 {
+                       compatible = "reg-mux";
+                       reg = <0x00 0x47000004 0x00 0x4>;
                        #mux-control-cells = <1>;
-                       mux-reg-masks = <0x4 0x2>; /* HBMC select */
+                       mux-reg-masks = <0x0 0x2>; /* HBMC select */
                };
 
                hbmc: hyperbus@47034000 {
                ti,esm-pins = <95>;
                bootph-pre-ram;
        };
+
+       mcu_mcan0: can@40528000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x40528000 0x00 0x200>,
+                     <0x00 0x40500000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 172 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 172 0>, <&k3_clks 172 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 832 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 833 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
+
+       mcu_mcan1: can@40568000 {
+               compatible = "bosch,m_can";
+               reg = <0x00 0x40568000 0x00 0x200>,
+                     <0x00 0x40540000 0x00 0x8000>;
+               reg-names = "m_can", "message_ram";
+               power-domains = <&k3_pds 173 TI_SCI_PD_EXCLUSIVE>;
+               clocks = <&k3_clks 173 0>, <&k3_clks 173 2>;
+               clock-names = "hclk", "cclk";
+               interrupts = <GIC_SPI 835 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 836 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "int0", "int1";
+               bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>;
+               status = "disabled";
+       };
 };
index ea47f10d393afccc5423bad0eb54ac3433255d98..7e6a584ac6f0b52882a87eec7994c90383c62297 100644 (file)
@@ -1,10 +1,12 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
 
+#include <dt-bindings/gpio/gpio.h>
+
 #include "k3-j7200.dtsi"
 
 / {
                        no-map;
                };
        };
+
+       mux0: mux-controller {
+               compatible = "gpio-mux";
+               #mux-state-cells = <1>;
+               mux-gpios = <&exp_som 1 GPIO_ACTIVE_HIGH>;
+       };
+
+       mux1: mux-controller {
+               compatible = "gpio-mux";
+               #mux-state-cells = <1>;
+               mux-gpios = <&exp_som 2 GPIO_ACTIVE_HIGH>;
+       };
+
+       transceiver0: can-phy0 {
+               /* standby pin has been grounded by default */
+               compatible = "ti,tcan1042";
+               #phy-cells = <0>;
+               max-bitrate = <5000000>;
+       };
 };
 
 &wkup_pmx0 {
                        J721E_IOPAD(0xd8, PIN_INPUT_PULLUP, 0) /* (W2) I2C0_SDA */
                >;
        };
+
+       main_mcan0_pins_default: main-mcan0-default-pins {
+               pinctrl-single,pins = <
+                       J721E_IOPAD(0x24, PIN_INPUT, 0) /* (V20) MCAN0_RX */
+                       J721E_IOPAD(0x20, PIN_OUTPUT, 0) /* (V18) MCAN0_TX */
+               >;
+       };
 };
 
 &hbmc {
 };
 
 &mcu_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
        memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
                        <&mcu_r5fss0_core0_memory_region>;
 };
 
 &mcu_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>;
        memory-region = <&mcu_r5fss0_core1_dma_memory_region>,
                        <&mcu_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>;
        memory-region = <&main_r5fss0_core0_dma_memory_region>,
                        <&main_r5fss0_core0_memory_region>;
 };
 
 &main_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>;
        memory-region = <&main_r5fss0_core1_dma_memory_region>,
                        <&main_r5fss0_core1_memory_region>;
 };
                };
        };
 };
+
+&main_mcan0 {
+       status = "okay";
+       pinctrl-0 = <&main_mcan0_pins_default>;
+       pinctrl-names = "default";
+       phys = <&transceiver0>;
+};
index e7e3a643a6f0cc6536548e106d3c29e8b0ca3d1f..2d22a95a6fdbca73c83d722638ca4e748038f114 100644 (file)
@@ -1,4 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
 
 #include <dt-bindings/thermal/thermal.h>
 
index ef73e6d7e85815e026dbd44e00c4c55149bf45c0..d411911fdf713f0d880e6854ecaf1d92330d505a 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for J7200 SoC Family
  *
- * Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/interrupt-controller/irq.h>
index 2f954729f3533876e096735cf5a4f3afe617e2a5..a2925555fe818085fd64a7e52c5f14dbfc504e93 100644 (file)
@@ -1,9 +1,9 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * https://beagleboard.org/ai-64
- * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
- * Copyright (C) 2022 Jason Kridner, BeagleBoard.org Foundation
- * Copyright (C) 2022 Robert Nelson, BeagleBoard.org Foundation
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Jason Kridner, BeagleBoard.org Foundation
+ * Copyright (C) 2022-2024 Robert Nelson, BeagleBoard.org Foundation
  */
 
 /dts-v1/;
 };
 
 &mcu_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
        memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
                        <&mcu_r5fss0_core0_memory_region>;
 };
 
 &mcu_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>;
        memory-region = <&mcu_r5fss0_core1_dma_memory_region>,
                        <&mcu_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>;
        memory-region = <&main_r5fss0_core0_dma_memory_region>,
                        <&main_r5fss0_core0_memory_region>;
 };
 
 &main_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>;
        memory-region = <&main_r5fss0_core1_dma_memory_region>,
                        <&main_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss1_core0 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core0>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>;
        memory-region = <&main_r5fss1_core0_dma_memory_region>,
                        <&main_r5fss1_core0_memory_region>;
 };
 
 &main_r5fss1_core1 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core1>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>;
        memory-region = <&main_r5fss1_core1_dma_memory_region>,
                        <&main_r5fss1_core1_memory_region>;
 };
 
 &c66_0 {
        status = "okay";
-       mboxes = <&mailbox0_cluster3>, <&mbox_c66_0>;
+       mboxes = <&mailbox0_cluster3 &mbox_c66_0>;
        memory-region = <&c66_0_dma_memory_region>,
                        <&c66_0_memory_region>;
 };
 
 &c66_1 {
        status = "okay";
-       mboxes = <&mailbox0_cluster3>, <&mbox_c66_1>;
+       mboxes = <&mailbox0_cluster3 &mbox_c66_1>;
        memory-region = <&c66_1_dma_memory_region>,
                        <&c66_1_memory_region>;
 };
 
 &c71_0 {
        status = "okay";
-       mboxes = <&mailbox0_cluster4>, <&mbox_c71_0>;
+       mboxes = <&mailbox0_cluster4 &mbox_c71_0>;
        memory-region = <&c71_0_dma_memory_region>,
                        <&c71_0_memory_region>;
 };
index fe5207ac7d85d158ff8c95620e155955e16f02af..8230d53cd69609d44b4a832cf214afdc2ee90e02 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2019-2024 Texas Instruments Incorporated - https://www.ti.com/
  *
  * Product Link: https://www.ti.com/tool/J721EXCPXEVM
  */
index 6a7d37575da156a1f6485c4ad5dfe5d5c5aa3ce0..f84aa9f9454792ff77ee4515c27e435c5cfb7a18 100644 (file)
@@ -1,11 +1,11 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /**
  * DT Overlay for CPSW9G in RGMII mode using J7 GESI EXP BRD board with
  * J721E board.
  *
  * GESI Board Product Link: https://www.ti.com/tool/J7EXPCXEVM
  *
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index 0c82a13b65a47f2609cbc21b65d904867cd02d33..4062709d65792f7f6d361c92a1030d1c6749e295 100644 (file)
@@ -1,11 +1,11 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /**
  * DT Overlay for enabling PCIE0 instance in Endpoint Configuration with the
  * J7 common processor board.
  *
  * J7 Common Processor Board Product Link: https://www.ti.com/tool/J721EXCPXEVM
  *
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index d4c51ffc3d6b401fe1a8b89396164cfefa29cc59..8376fa4b6ee1606a9a1ea7b7fd2628431144589c 100644 (file)
@@ -1,9 +1,9 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /**
  * DT Overlay for CPSW9G in QSGMII mode using J7 Quad Port ETH EXP Add-On Ethernet Card with
  * J721E board.
  *
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index 2569b4c08ffb85fa329831ca4d64c27dbf8a96d6..c7eafbc862f96e58b009c7492d05b916797e7d49 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for J721E SoC Family Main Domain peripherals
  *
- * Copyright (C) 2016-2020 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2016-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 #include <dt-bindings/phy/phy.h>
 #include <dt-bindings/phy/phy-ti.h>
                ranges = <0x0 0x0 0x00100000 0x1c000>;
 
                serdes_ln_ctrl: mux-controller@4080 {
-                       compatible = "mmio-mux";
-                       reg = <0x00004080 0x50>;
+                       compatible = "reg-mux";
+                       reg = <0x4080 0x50>;
                        #mux-control-cells = <1>;
-                       mux-reg-masks = <0x4080 0x3>, <0x4084 0x3>, /* SERDES0 lane0/1 select */
-                                       <0x4090 0x3>, <0x4094 0x3>, /* SERDES1 lane0/1 select */
-                                       <0x40a0 0x3>, <0x40a4 0x3>, /* SERDES2 lane0/1 select */
-                                       <0x40b0 0x3>, <0x40b4 0x3>, /* SERDES3 lane0/1 select */
-                                       <0x40c0 0x3>, <0x40c4 0x3>, <0x40c8 0x3>, <0x40cc 0x3>;
-                                       /* SERDES4 lane0/1/2/3 select */
+                       mux-reg-masks = <0x0 0x3>, <0x4 0x3>, /* SERDES0 lane0/1 select */
+                                       <0x10 0x3>, <0x14 0x3>, /* SERDES1 lane0/1 select */
+                                       <0x20 0x3>, <0x24 0x3>, /* SERDES2 lane0/1 select */
+                                       <0x30 0x3>, <0x34 0x3>, /* SERDES3 lane0/1 select */
+                                       <0x40 0x3>, <0x44 0x3>, /* SERDES4 lane0/1 select */
+                                       <0x48 0x3>, <0x4c 0x3>; /* SERDES4 lane2/3 select */
                        idle-states = <J721E_SERDES0_LANE0_PCIE0_LANE0>, <J721E_SERDES0_LANE1_PCIE0_LANE1>,
                                      <J721E_SERDES1_LANE0_PCIE1_LANE0>, <J721E_SERDES1_LANE1_PCIE1_LANE1>,
                                      <J721E_SERDES2_LANE0_PCIE2_LANE0>, <J721E_SERDES2_LANE1_PCIE2_LANE1>,
                };
 
                usb_serdes_mux: mux-controller@4000 {
-                       compatible = "mmio-mux";
+                       compatible = "reg-mux";
+                       reg = <0x4000 0x20>;
                        #mux-control-cells = <1>;
-                       mux-reg-masks = <0x4000 0x8000000>, /* USB0 to SERDES0/3 mux */
-                                       <0x4010 0x8000000>; /* USB1 to SERDES1/2 mux */
+                       mux-reg-masks = <0x0 0x8000000>, /* USB0 to SERDES0/3 mux */
+                                       <0x10 0x8000000>; /* USB1 to SERDES1/2 mux */
                };
 
                ehrpwm_tbclk: clock-controller@4140 {
                pinctrl-single,function-mask = <0x0000001f>;
        };
 
+       ti_csi2rx0: ticsi2rx@4500000 {
+               compatible = "ti,j721e-csi2rx-shim";
+               reg = <0x0 0x4500000 0x0 0x1000>;
+               ranges;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               dmas = <&main_udmap 0x4940>;
+               dma-names = "rx0";
+               power-domains = <&k3_pds 26 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+
+               cdns_csi2rx0: csi-bridge@4504000 {
+                       compatible = "ti,j721e-csi2rx", "cdns,csi2rx";
+                       reg = <0x0 0x4504000 0x0 0x1000>;
+                       clocks = <&k3_clks 26 2>, <&k3_clks 26 0>, <&k3_clks 26 2>,
+                               <&k3_clks 26 2>, <&k3_clks 26 3>, <&k3_clks 26 3>;
+                       clock-names = "sys_clk", "p_clk", "pixel_if0_clk",
+                               "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk";
+                       phys = <&dphy0>;
+                       phy-names = "dphy";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               csi0_port0: port@0 {
+                                       reg = <0>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port1: port@1 {
+                                       reg = <1>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port2: port@2 {
+                                       reg = <2>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port3: port@3 {
+                                       reg = <3>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port4: port@4 {
+                                       reg = <4>;
+                                       status = "disabled";
+                               };
+                       };
+               };
+       };
+
+       ti_csi2rx1: ticsi2rx@4510000 {
+               compatible = "ti,j721e-csi2rx-shim";
+               reg = <0x0 0x4510000 0x0 0x1000>;
+               ranges;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               dmas = <&main_udmap 0x4960>;
+               dma-names = "rx0";
+               power-domains = <&k3_pds 27 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+
+               cdns_csi2rx1: csi-bridge@4514000 {
+                       compatible = "ti,j721e-csi2rx", "cdns,csi2rx";
+                       reg = <0x0 0x4514000 0x0 0x1000>;
+                       clocks = <&k3_clks 27 2>, <&k3_clks 27 0>, <&k3_clks 27 2>,
+                                <&k3_clks 27 2>, <&k3_clks 27 3>, <&k3_clks 27 3>;
+                       clock-names = "sys_clk", "p_clk", "pixel_if0_clk",
+                                     "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk";
+                       phys = <&dphy1>;
+                       phy-names = "dphy";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               csi1_port0: port@0 {
+                                       reg = <0>;
+                                       status = "disabled";
+                               };
+
+                               csi1_port1: port@1 {
+                                       reg = <1>;
+                                       status = "disabled";
+                               };
+
+                               csi1_port2: port@2 {
+                                       reg = <2>;
+                                       status = "disabled";
+                               };
+
+                               csi1_port3: port@3 {
+                                       reg = <3>;
+                                       status = "disabled";
+                               };
+
+                               csi1_port4: port@4 {
+                                       reg = <4>;
+                                       status = "disabled";
+                               };
+                       };
+               };
+       };
+
+       dphy0: phy@4580000 {
+               compatible = "cdns,dphy-rx";
+               reg = <0x0 0x4580000 0x0 0x1100>;
+               #phy-cells = <0>;
+               power-domains = <&k3_pds 147 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+       };
+
+       dphy1: phy@4590000 {
+               compatible = "cdns,dphy-rx";
+               reg = <0x0 0x4590000 0x0 0x1100>;
+               #phy-cells = <0>;
+               power-domains = <&k3_pds 148 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+       };
+
        serdes_wiz0: wiz@5000000 {
                compatible = "ti,j721e-wiz-16g";
                #address-cells = <1>;
index a74912d9e4dafdf307961e390110706a863a015e..4618b697fbc47c460f2739ea913247c41dfc9477 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for J721E SoC Family MCU/WAKEUP Domain peripherals
  *
- * Copyright (C) 2016-2020 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2016-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_mcu_wakeup {
 
                hbmc_mux: mux-controller@47000004 {
                        compatible = "reg-mux";
-                       reg = <0x00 0x47000004 0x00 0x2>;
+                       reg = <0x00 0x47000004 0x00 0x4>;
                        #mux-control-cells = <1>;
-                       mux-reg-masks = <0x4 0x2>; /* HBMC select */
+                       mux-reg-masks = <0x0 0x2>; /* HBMC select */
                };
 
                hbmc: hyperbus@47034000 {
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-sk-csi2-dual-imx219.dtso b/arch/arm64/boot/dts/ti/k3-j721e-sk-csi2-dual-imx219.dtso
new file mode 100644 (file)
index 0000000..47bb548
--- /dev/null
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/**
+ * DT Overlay for dual RPi Camera V2.1 (Sony IMX219) interfaced with CSI2
+ * on J721E SK, AM68 SK or AM69-SK board.
+ * https://datasheets.raspberrypi.org/camera/camera-v2-schematic.pdf
+ *
+ * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "k3-pinctrl.h"
+
+&{/} {
+       clk_imx219_fixed: imx219-xclk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <24000000>;
+       };
+};
+
+&csi_mux {
+       idle-state = <1>;
+};
+
+/* CAM0 I2C */
+&cam0_i2c {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       imx219_0: imx219-0@10 {
+               compatible = "sony,imx219";
+               reg = <0x10>;
+
+               clocks = <&clk_imx219_fixed>;
+               clock-names = "xclk";
+
+               port {
+                       csi2_cam0: endpoint {
+                               remote-endpoint = <&csi2rx0_in_sensor>;
+                               link-frequencies = /bits/ 64 <456000000>;
+                               clock-lanes = <0>;
+                               data-lanes = <1 2>;
+                       };
+               };
+       };
+};
+
+/* CAM1 I2C */
+&cam1_i2c {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       imx219_1: imx219-1@10 {
+               compatible = "sony,imx219";
+               reg = <0x10>;
+
+               clocks = <&clk_imx219_fixed>;
+               clock-names = "xclk";
+
+               port {
+                       csi2_cam1: endpoint {
+                               remote-endpoint = <&csi2rx1_in_sensor>;
+                               link-frequencies = /bits/ 64 <456000000>;
+                               clock-lanes = <0>;
+                               data-lanes = <1 2>;
+                       };
+               };
+       };
+};
+
+
+&cdns_csi2rx0 {
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               csi0_port0: port@0 {
+                       reg = <0>;
+                       status = "okay";
+
+                       csi2rx0_in_sensor: endpoint {
+                               remote-endpoint = <&csi2_cam0>;
+                               bus-type = <4>; /* CSI2 DPHY. */
+                               clock-lanes = <0>;
+                               data-lanes = <1 2>;
+                       };
+               };
+
+               csi0_port1: port@1 {
+                       reg = <1>;
+                       status = "disabled";
+               };
+
+               csi0_port2: port@2 {
+                       reg = <2>;
+                       status = "disabled";
+               };
+
+               csi0_port3: port@3 {
+                       reg = <3>;
+                       status = "disabled";
+               };
+
+               csi0_port4: port@4 {
+                       reg = <4>;
+                       status = "disabled";
+               };
+       };
+};
+
+&dphy0 {
+       status = "okay";
+};
+
+&ti_csi2rx0 {
+       status = "okay";
+};
+
+&cdns_csi2rx1 {
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               csi1_port0: port@0 {
+                       reg = <0>;
+                       status = "okay";
+
+                       csi2rx1_in_sensor: endpoint {
+                               remote-endpoint = <&csi2_cam1>;
+                               bus-type = <4>; /* CSI2 DPHY. */
+                               clock-lanes = <0>;
+                               data-lanes = <1 2>;
+                       };
+               };
+
+               csi1_port1: port@1 {
+                       reg = <1>;
+                       status = "disabled";
+               };
+
+               csi1_port2: port@2 {
+                       reg = <2>;
+                       status = "disabled";
+               };
+
+               csi1_port3: port@3 {
+                       reg = <3>;
+                       status = "disabled";
+               };
+
+               csi1_port4: port@4 {
+                       reg = <4>;
+                       status = "disabled";
+               };
+       };
+};
+
+&dphy1 {
+       status = "okay";
+};
+
+&ti_csi2rx1 {
+       status = "okay";
+};
index 188dfe291a32b42d5a2dd8e1bf37507cfe868d4e..0c4575ad8d7cb03919a7a4520acc2d4059a23287 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/
  *
  * J721E SK URL: https://www.ti.com/tool/SK-TDA4VM
  */
                        };
                };
        };
+
+       csi_mux: mux-controller {
+               compatible = "gpio-mux";
+               #mux-state-cells = <1>;
+               mux-gpios = <&main_gpio0 88 GPIO_ACTIVE_HIGH>;
+               idle-state = <0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&main_csi_mux_sel_pins_default>;
+       };
 };
 
 &main_pmx0 {
                >;
        };
 
+       main_csi_mux_sel_pins_default: main-csi-mux-sel-default-pins {
+               pinctrl-single,pins = <
+                       J721E_IOPAD(0x164, PIN_OUTPUT, 7) /* (V29) RGMII5_TD2 */
+               >;
+       };
+
        dp0_pins_default: dp0-default-pins {
                pinctrl-single,pins = <
                        J721E_IOPAD(0x1c4, PIN_INPUT, 5) /* SPI0_CS1.DP0_HPD */
                pinctrl-names = "default";
                pinctrl-0 = <&pmic_irq_pins_default>;
                interrupt-parent = <&wkup_gpio0>;
-               interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+               interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
                gpio-controller;
                #gpio-cells = <2>;
                ti,primary-pmic;
                reg = <0x4c>;
                system-power-controller;
                interrupt-parent = <&wkup_gpio0>;
-               interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+               interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
                gpio-controller;
                #gpio-cells = <2>;
                buck1234-supply = <&vsys_3v3>;
                reg = <0x70>;
 
                /* CSI0 I2C */
-               i2c@0 {
+               cam0_i2c: i2c@0 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <0>;
                };
 
                /* CSI1 I2C */
-               i2c@1 {
+               cam1_i2c: i2c@1 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <1>;
 };
 
 &mcu_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
        memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
                        <&mcu_r5fss0_core0_memory_region>;
 };
 
 &mcu_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>;
        memory-region = <&mcu_r5fss0_core1_dma_memory_region>,
                        <&mcu_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>;
        memory-region = <&main_r5fss0_core0_dma_memory_region>,
                        <&main_r5fss0_core0_memory_region>;
 };
 
 &main_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>;
        memory-region = <&main_r5fss0_core1_dma_memory_region>,
                        <&main_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss1_core0 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core0>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>;
        memory-region = <&main_r5fss1_core0_dma_memory_region>,
                        <&main_r5fss1_core0_memory_region>;
 };
 
 &main_r5fss1_core1 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core1>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>;
        memory-region = <&main_r5fss1_core1_dma_memory_region>,
                        <&main_r5fss1_core1_memory_region>;
 };
 
 &c66_0 {
        status = "okay";
-       mboxes = <&mailbox0_cluster3>, <&mbox_c66_0>;
+       mboxes = <&mailbox0_cluster3 &mbox_c66_0>;
        memory-region = <&c66_0_dma_memory_region>,
                        <&c66_0_memory_region>;
 };
 
 &c66_1 {
        status = "okay";
-       mboxes = <&mailbox0_cluster3>, <&mbox_c66_1>;
+       mboxes = <&mailbox0_cluster3 &mbox_c66_1>;
        memory-region = <&c66_1_dma_memory_region>,
                        <&c66_1_memory_region>;
 };
 
 &c71_0 {
        status = "okay";
-       mboxes = <&mailbox0_cluster4>, <&mbox_c71_0>;
+       mboxes = <&mailbox0_cluster4 &mbox_c71_0>;
        memory-region = <&c71_0_dma_memory_region>,
                        <&c71_0_memory_region>;
 };
index a75611eec791427d702efcc782a1226a5ad6fc65..1fae6495db074a9b9997681575bcfe35e67f240a 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2019-2020 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2019-2024 Texas Instruments Incorporated - https://www.ti.com/
  *
  * Product Link: https://www.ti.com/tool/J721EXSOMXEVM
  */
 };
 
 &mcu_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
        memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
                        <&mcu_r5fss0_core0_memory_region>;
 };
 
 &mcu_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>;
        memory-region = <&mcu_r5fss0_core1_dma_memory_region>,
                        <&mcu_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>;
        memory-region = <&main_r5fss0_core0_dma_memory_region>,
                        <&main_r5fss0_core0_memory_region>;
 };
 
 &main_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>;
        memory-region = <&main_r5fss0_core1_dma_memory_region>,
                        <&main_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss1_core0 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core0>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>;
        memory-region = <&main_r5fss1_core0_dma_memory_region>,
                        <&main_r5fss1_core0_memory_region>;
 };
 
 &main_r5fss1_core1 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core1>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>;
        memory-region = <&main_r5fss1_core1_dma_memory_region>,
                        <&main_r5fss1_core1_memory_region>;
 };
 
 &c66_0 {
        status = "okay";
-       mboxes = <&mailbox0_cluster3>, <&mbox_c66_0>;
+       mboxes = <&mailbox0_cluster3 &mbox_c66_0>;
        memory-region = <&c66_0_dma_memory_region>,
                        <&c66_0_memory_region>;
 };
 
 &c66_1 {
        status = "okay";
-       mboxes = <&mailbox0_cluster3>, <&mbox_c66_1>;
+       mboxes = <&mailbox0_cluster3 &mbox_c66_1>;
        memory-region = <&c66_1_dma_memory_region>,
                        <&c66_1_memory_region>;
 };
 
 &c71_0 {
        status = "okay";
-       mboxes = <&mailbox0_cluster4>, <&mbox_c71_0>;
+       mboxes = <&mailbox0_cluster4 &mbox_c71_0>;
        memory-region = <&c71_0_dma_memory_region>,
                        <&c71_0_memory_region>;
 };
index c2523279001bf4730f6950d77503dcc291090b3a..927f7614ae7a065aa8dd3e0aa9ce14e6661bf6cc 100644 (file)
@@ -1,4 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
 
 #include <dt-bindings/thermal/thermal.h>
 
index a200810df54a548c9bd0d476e3a880e99ee53d2b..5a72c518ceb6be4c9a3d67fd209394dc2b291507 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for J721E SoC Family
  *
- * Copyright (C) 2016-2019 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2016-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/interrupt-controller/irq.h>
index c6b85bbf9a179bfc3b68028f9b85564bf36efd72..c5a0b7cbb14f8866bbb06e337f1242455aeeea4e 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/
  *
  * Common Processor Board: https://www.ti.com/tool/J721EXCPXEVM
  */
                >;
        };
 
+       main_i2c5_pins_default: main-i2c5-default-pins {
+               pinctrl-single,pins = <
+                       J721S2_IOPAD(0x01c, PIN_INPUT, 8) /* (Y24) MCAN15_TX.I2C5_SCL */
+                       J721S2_IOPAD(0x018, PIN_INPUT, 8) /* (W23) MCAN14_RX.I2C5_SDA */
+               >;
+       };
+
        main_mmc1_pins_default: main-mmc1-default-pins {
                pinctrl-single,pins = <
                        J721S2_IOPAD(0x104, PIN_INPUT, 0) /* (P23) MMC1_CLK */
 &wkup_pmx2 {
        wkup_uart0_pins_default: wkup-uart0-default-pins {
                pinctrl-single,pins = <
-                       J721S2_WKUP_IOPAD(0x070, PIN_INPUT, 0) /* (E25) WKUP_GPIO0_6.WKUP_UART0_CTSn */
-                       J721S2_WKUP_IOPAD(0x074, PIN_OUTPUT, 0) /* (F28) WKUP_GPIO0_7.WKUP_UART0_RTSn */
                        J721S2_WKUP_IOPAD(0x048, PIN_INPUT, 0) /* (D28) WKUP_UART0_RXD */
                        J721S2_WKUP_IOPAD(0x04c, PIN_OUTPUT, 0) /* (D27) WKUP_UART0_TXD */
                >;
        };
 };
 
+&main_i2c5 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_i2c5_pins_default>;
+       clock-frequency = <400000>;
+       status = "okay";
+
+       exp5: gpio@20 {
+               compatible = "ti,tca6408";
+               reg = <0x20>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               gpio-line-names = "CSI2_EXP_RSTZ", "CSI2_EXP_A_GPIO0",
+                                 "CSI2_EXP_A_GPIO1", "CSI2_EXP_A_GPIO2",
+                                 "CSI2_EXP_B_GPIO1", "CSI2_EXP_B_GPIO2",
+                                 "CSI2_EXP_B_GPIO3", "CSI2_EXP_B_GPIO4";
+       };
+};
+
 &main_sdhci0 {
        /* eMMC */
        status = "okay";
index b78feea31b5476f2c7d5fd7e7736598c1d86a1c2..1be28283c7d9a77c4f5279c35d9bc3a782810331 100644 (file)
@@ -1,10 +1,10 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /**
  * DT Overlay for MAIN CPSW2G using GESI Expansion Board with J7 common processor board.
  *
  * GESI Board Product Link: https://www.ti.com/tool/J7EXPCXEVM
  *
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index 43568eb67d93f530f00a2bfd1ddcc1793acd8289..5ff390915b75b938fbf568feac665778af13318d 100644 (file)
@@ -1,11 +1,11 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /**
  * DT Overlay for enabling PCIE1 instance in Endpoint Configuration with the
  * J7 common processor board.
  *
  * J7 Common Processor Board Product Link: https://www.ti.com/tool/J721EXCPXEVM
  *
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
index ea7f2b2ab165d3020f1925733287ba5e207e876e..b70c8615e3c15efa172af62b072420de16333a1b 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for J721S2 SoC Family Main Domain peripherals
  *
- * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/phy/phy-cadence.h>
@@ -45,7 +45,7 @@
                ranges = <0x00 0x00 0x00104000 0x18000>;
 
                usb_serdes_mux: mux-controller@0 {
-                       compatible = "mmio-mux";
+                       compatible = "reg-mux";
                        reg = <0x0 0x4>;
                        #mux-control-cells = <1>;
                        mux-reg-masks = <0x0 0x8000000>; /* USB0 to SERDES0 lane 1/3 mux */
                };
 
                serdes_ln_ctrl: mux-controller@80 {
-                       compatible = "mmio-mux";
+                       compatible = "reg-mux";
                        reg = <0x80 0x10>;
                        #mux-control-cells = <1>;
-                       mux-reg-masks = <0x80 0x3>, <0x84 0x3>, /* SERDES0 lane0/1 select */
-                                       <0x88 0x3>, <0x8c 0x3>; /* SERDES0 lane2/3 select */
+                       mux-reg-masks = <0x0 0x3>, <0x4 0x3>, /* SERDES0 lane0/1 select */
+                                       <0x8 0x3>, <0xc 0x3>; /* SERDES0 lane2/3 select */
                };
 
                ehrpwm_tbclk: clock-controller@140 {
                status = "disabled";
        };
 
+       vpu: video-codec@4210000 {
+               compatible = "ti,j721s2-wave521c", "cnm,wave521c";
+               reg = <0x00 0x4210000 0x00 0x10000>;
+               interrupts = <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&k3_clks 179 2>;
+               power-domains = <&k3_pds 179 TI_SCI_PD_EXCLUSIVE>;
+       };
+
        main_sdhci0: mmc@4f80000 {
                compatible = "ti,j721e-sdhci-8bit";
                reg = <0x00 0x04f80000 0x00 0x1000>,
                        ti,sci-dev-id = <225>;
                        ti,sci-rm-range-rchan = <0x21>;
                        ti,sci-rm-range-tchan = <0x22>;
-                       status = "disabled";
                };
 
                cpts@310d0000 {
                };
        };
 
+       ti_csi2rx0: ticsi2rx@4500000 {
+               compatible = "ti,j721e-csi2rx-shim";
+               reg = <0x00 0x04500000 0x00 0x1000>;
+               ranges;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               dmas = <&main_bcdma_csi 0 0x4940 0>;
+               dma-names = "rx0";
+               power-domains = <&k3_pds 38 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+
+               cdns_csi2rx0: csi-bridge@4504000 {
+                       compatible = "ti,j721e-csi2rx", "cdns,csi2rx";
+                       reg = <0x00 0x04504000 0x00 0x1000>;
+                       clocks = <&k3_clks 38 3>, <&k3_clks 38 1>, <&k3_clks 38 3>,
+                               <&k3_clks 38 3>, <&k3_clks 38 4>, <&k3_clks 38 4>;
+                       clock-names = "sys_clk", "p_clk", "pixel_if0_clk",
+                               "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk";
+                       phys = <&dphy0>;
+                       phy-names = "dphy";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               csi0_port0: port@0 {
+                                       reg = <0>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port1: port@1 {
+                                       reg = <1>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port2: port@2 {
+                                       reg = <2>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port3: port@3 {
+                                       reg = <3>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port4: port@4 {
+                                       reg = <4>;
+                                       status = "disabled";
+                               };
+                       };
+               };
+       };
+
+       ti_csi2rx1: ticsi2rx@4510000 {
+               compatible = "ti,j721e-csi2rx-shim";
+               reg = <0x00 0x04510000 0x00 0x1000>;
+               ranges;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               dmas = <&main_bcdma_csi 0 0x4960 0>;
+               dma-names = "rx0";
+               power-domains = <&k3_pds 39 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+
+               cdns_csi2rx1: csi-bridge@4514000 {
+                       compatible = "ti,j721e-csi2rx", "cdns,csi2rx";
+                       reg = <0x00 0x04514000 0x00 0x1000>;
+                       clocks = <&k3_clks 39 3>, <&k3_clks 39 1>, <&k3_clks 39 3>,
+                               <&k3_clks 39 3>, <&k3_clks 39 4>, <&k3_clks 39 4>;
+                       clock-names = "sys_clk", "p_clk", "pixel_if0_clk",
+                               "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk";
+                       phys = <&dphy1>;
+                       phy-names = "dphy";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               csi1_port0: port@0 {
+                                       reg = <0>;
+                                       status = "disabled";
+                               };
+
+                               csi1_port1: port@1 {
+                                       reg = <1>;
+                                       status = "disabled";
+                               };
+
+                               csi1_port2: port@2 {
+                                       reg = <2>;
+                                       status = "disabled";
+                               };
+
+                               csi1_port3: port@3 {
+                                       reg = <3>;
+                                       status = "disabled";
+                               };
+
+                               csi1_port4: port@4 {
+                                       reg = <4>;
+                                       status = "disabled";
+                               };
+                       };
+               };
+       };
+
+       dphy0: phy@4580000 {
+               compatible = "cdns,dphy-rx";
+               reg = <0x00 0x04580000 0x00 0x1100>;
+               #phy-cells = <0>;
+               power-domains = <&k3_pds 152 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+       };
+
+       dphy1: phy@4590000 {
+               compatible = "cdns,dphy-rx";
+               reg = <0x00 0x04590000 0x00 0x1100>;
+               #phy-cells = <0>;
+               power-domains = <&k3_pds 153 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+       };
+
        serdes_wiz0: wiz@5060000 {
                compatible = "ti,j721s2-wiz-10g";
                #address-cells = <1>;
index 80aa33c58a452b5074920bd8fb65fc6c5c9c9a59..eaf7f709440e6e19f85dcb64324613bb09821aab 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for J721S2 SoC Family MCU/WAKEUP Domain peripherals
  *
- * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_mcu_wakeup {
                compatible = "ti,j7200-vtm";
                reg = <0x00 0x42040000 0x0 0x350>,
                      <0x00 0x42050000 0x0 0x350>;
-               power-domains = <&k3_pds 154 TI_SCI_PD_SHARED>;
+               power-domains = <&k3_pds 180 TI_SCI_PD_SHARED>;
                #thermal-sensor-cells = <1>;
        };
 
index da3237b23b63ac7a908c2cf8af61818062dd1b63..623c8421525d1932800140c2b424c10ed2be6227 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * SoM: https://www.ti.com/lit/zip/sprr439
  *
- * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 /dts-v1/;
 };
 
 &mcu_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>;
        memory-region = <&mcu_r5fss0_core0_dma_memory_region>,
                        <&mcu_r5fss0_core0_memory_region>;
 };
 
 &mcu_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster0>, <&mbox_mcu_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>;
        memory-region = <&mcu_r5fss0_core1_dma_memory_region>,
                        <&mcu_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss0_core0 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core0>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>;
        memory-region = <&main_r5fss0_core0_dma_memory_region>,
                        <&main_r5fss0_core0_memory_region>;
 };
 
 &main_r5fss0_core1 {
-       mboxes = <&mailbox0_cluster1>, <&mbox_main_r5fss0_core1>;
+       mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>;
        memory-region = <&main_r5fss0_core1_dma_memory_region>,
                        <&main_r5fss0_core1_memory_region>;
 };
 
 &main_r5fss1_core0 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core0>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>;
        memory-region = <&main_r5fss1_core0_dma_memory_region>,
                        <&main_r5fss1_core0_memory_region>;
 };
 
 &main_r5fss1_core1 {
-       mboxes = <&mailbox0_cluster2>, <&mbox_main_r5fss1_core1>;
+       mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>;
        memory-region = <&main_r5fss1_core1_dma_memory_region>,
                        <&main_r5fss1_core1_memory_region>;
 };
 
 &c71_0 {
        status = "okay";
-       mboxes = <&mailbox0_cluster4>, <&mbox_c71_0>;
+       mboxes = <&mailbox0_cluster4 &mbox_c71_0>;
        memory-region = <&c71_0_dma_memory_region>,
                        <&c71_0_memory_region>;
 };
 
 &c71_1 {
        status = "okay";
-       mboxes = <&mailbox0_cluster4>, <&mbox_c71_1>;
+       mboxes = <&mailbox0_cluster4 &mbox_c71_1>;
        memory-region = <&c71_1_dma_memory_region>,
                        <&c71_1_memory_region>;
 };
index f7b1a15b8fa0a29083ff2727af6223e44ff7f9f5..e3ef61c1658f4b6b2caff67b2dc6032eb2aada11 100644 (file)
@@ -1,4 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
 
 #include <dt-bindings/thermal/thermal.h>
 
index 1f636acd4eee4f648d5b7cffdeeae8be01764d43..be4502fe1c9d99c9e99e4f425652bb690be7d411 100644 (file)
@@ -1,10 +1,10 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for J721S2 SoC Family
  *
  * TRM (SPRUJ28 NOVEMBER 2021): https://www.ti.com/lit/pdf/spruj28
  *
- * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2021-2024 Texas Instruments Incorporated - https://www.ti.com/
  *
  */
 
diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts
new file mode 100644 (file)
index 0000000..cee3a86
--- /dev/null
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Device Tree file for the J722S EVM
+ * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * Schematics: https://www.ti.com/lit/zip/sprr495
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/net/ti-dp83867.h>
+#include "k3-j722s.dtsi"
+
+/ {
+       compatible = "ti,j722s-evm", "ti,j722s";
+       model = "Texas Instruments J722S EVM";
+
+       aliases {
+               serial0 = &wkup_uart0;
+               serial2 = &main_uart0;
+               mmc0 = &sdhci0;
+               mmc1 = &sdhci1;
+       };
+
+       chosen {
+               stdout-path = &main_uart0;
+       };
+
+       memory@80000000 {
+               /* 8G RAM */
+               reg = <0x00000000 0x80000000 0x00000000 0x80000000>,
+                     <0x00000008 0x80000000 0x00000001 0x80000000>;
+               device_type = "memory";
+               bootph-pre-ram;
+       };
+
+       reserved_memory: reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               secure_tfa_ddr: tfa@9e780000 {
+                       reg = <0x00 0x9e780000 0x00 0x80000>;
+                       no-map;
+               };
+
+               secure_ddr: optee@9e800000 {
+                       reg = <0x00 0x9e800000 0x00 0x01800000>;
+                       no-map;
+               };
+
+               wkup_r5fss0_core0_memory_region: r5f-memory@a0100000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0x00 0xa0100000 0x00 0xf00000>;
+                       no-map;
+               };
+
+       };
+
+       vmain_pd: regulator-0 {
+               /* TPS65988 PD CONTROLLER OUTPUT */
+               compatible = "regulator-fixed";
+               regulator-name = "vmain_pd";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               regulator-always-on;
+               regulator-boot-on;
+               bootph-all;
+       };
+
+       vsys_5v0: regulator-vsys5v0 {
+               /* Output of LM5140 */
+               compatible = "regulator-fixed";
+               regulator-name = "vsys_5v0";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               vin-supply = <&vmain_pd>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       vdd_mmc1: regulator-mmc1 {
+               /* TPS22918DBVR */
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_mmc1";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+               enable-active-high;
+               gpio = <&exp1 15 GPIO_ACTIVE_HIGH>;
+               bootph-all;
+       };
+
+       vdd_sd_dv: regulator-TLV71033 {
+               compatible = "regulator-gpio";
+               regulator-name = "tlv71033";
+               pinctrl-names = "default";
+               pinctrl-0 = <&vdd_sd_dv_pins_default>;
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+               vin-supply = <&vsys_5v0>;
+               gpios = <&main_gpio0 70 GPIO_ACTIVE_HIGH>;
+               states = <1800000 0x0>,
+                        <3300000 0x1>;
+       };
+
+       vsys_io_1v8: regulator-vsys-io-1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "vsys_io_1v8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       vsys_io_1v2: regulator-vsys-io-1v2 {
+               compatible = "regulator-fixed";
+               regulator-name = "vsys_io_1v2";
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <1200000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+};
+
+&main_pmx0 {
+
+       main_i2c0_pins_default: main-i2c0-default-pins {
+               pinctrl-single,pins = <
+                       J722S_IOPAD(0x01e0, PIN_INPUT_PULLUP, 0) /* (D23) I2C0_SCL */
+                       J722S_IOPAD(0x01e4, PIN_INPUT_PULLUP, 0) /* (B22) I2C0_SDA */
+               >;
+               bootph-all;
+       };
+
+       main_uart0_pins_default: main-uart0-default-pins {
+               pinctrl-single,pins = <
+                       J722S_IOPAD(0x01c8, PIN_INPUT, 0)       /* (A22) UART0_RXD */
+                       J722S_IOPAD(0x01cc, PIN_OUTPUT, 0)      /* (B22) UART0_TXD */
+               >;
+               bootph-all;
+       };
+
+       vdd_sd_dv_pins_default: vdd-sd-dv-default-pins {
+               pinctrl-single,pins = <
+                       J722S_IOPAD(0x0120, PIN_INPUT, 7) /* (F27) MMC2_CMD.GPIO0_70 */
+               >;
+               bootph-all;
+       };
+
+       main_mmc1_pins_default: main-mmc1-default-pins {
+               pinctrl-single,pins = <
+                       J722S_IOPAD(0x023c, PIN_INPUT, 0) /* (H22) MMC1_CMD */
+                       J722S_IOPAD(0x0234, PIN_OUTPUT, 0) /* (H24) MMC1_CLK */
+                       J722S_IOPAD(0x0230, PIN_INPUT, 0) /* (H23) MMC1_DAT0 */
+                       J722S_IOPAD(0x022c, PIN_INPUT_PULLUP, 0) /* (H20) MMC1_DAT1 */
+                       J722S_IOPAD(0x0228, PIN_INPUT_PULLUP, 0) /* (J23) MMC1_DAT2 */
+                       J722S_IOPAD(0x0224, PIN_INPUT_PULLUP, 0) /* (H25) MMC1_DAT3 */
+                       J722S_IOPAD(0x0240, PIN_INPUT, 0) /* (B24) MMC1_SDCD */
+               >;
+               bootph-all;
+       };
+
+       mdio_pins_default: mdio-default-pins {
+               pinctrl-single,pins = <
+                       J722S_IOPAD(0x0160, PIN_OUTPUT, 0) /* (AC24) MDIO0_MDC */
+                       J722S_IOPAD(0x015c, PIN_INPUT, 0) /* (AD25) MDIO0_MDIO */
+               >;
+       };
+
+       ospi0_pins_default: ospi0-default-pins {
+               pinctrl-single,pins = <
+                       J722S_IOPAD(0x0000, PIN_OUTPUT, 0) /* (L24) OSPI0_CLK */
+                       J722S_IOPAD(0x002c, PIN_OUTPUT, 0) /* (K26) OSPI0_CSn0 */
+                       J722S_IOPAD(0x000c, PIN_INPUT, 0) /* (K27) OSPI0_D0 */
+                       J722S_IOPAD(0x0010, PIN_INPUT, 0) /* (L27) OSPI0_D1 */
+                       J722S_IOPAD(0x0014, PIN_INPUT, 0) /* (L26) OSPI0_D2 */
+                       J722S_IOPAD(0x0018, PIN_INPUT, 0) /* (L25) OSPI0_D3 */
+                       J722S_IOPAD(0x001c, PIN_INPUT, 0) /* (L21) OSPI0_D4 */
+                       J722S_IOPAD(0x0020, PIN_INPUT, 0) /* (M26) OSPI0_D5 */
+                       J722S_IOPAD(0x0024, PIN_INPUT, 0) /* (N27) OSPI0_D6 */
+                       J722S_IOPAD(0x0028, PIN_INPUT, 0) /* (M27) OSPI0_D7 */
+                       J722S_IOPAD(0x0008, PIN_INPUT, 0) /* (L22) OSPI0_DQS */
+               >;
+               bootph-all;
+       };
+
+       rgmii1_pins_default: rgmii1-default-pins {
+               pinctrl-single,pins = <
+                       J722S_IOPAD(0x014c, PIN_INPUT, 0) /* (AC25) RGMII1_RD0 */
+                       J722S_IOPAD(0x0150, PIN_INPUT, 0) /* (AD27) RGMII1_RD1 */
+                       J722S_IOPAD(0x0154, PIN_INPUT, 0) /* (AE24) RGMII1_RD2 */
+                       J722S_IOPAD(0x0158, PIN_INPUT, 0) /* (AE26) RGMII1_RD3 */
+                       J722S_IOPAD(0x0148, PIN_INPUT, 0) /* (AE27) RGMII1_RXC */
+                       J722S_IOPAD(0x0144, PIN_INPUT, 0) /* (AD23) RGMII1_RX_CTL */
+                       J722S_IOPAD(0x0134, PIN_OUTPUT, 0) /* (AF27) RGMII1_TD0 */
+                       J722S_IOPAD(0x0138, PIN_OUTPUT, 0) /* (AE23) RGMII1_TD1 */
+                       J722S_IOPAD(0x013c, PIN_OUTPUT, 0) /* (AG25) RGMII1_TD2 */
+                       J722S_IOPAD(0x0140, PIN_OUTPUT, 0) /* (AF24) RGMII1_TD3 */
+                       J722S_IOPAD(0x0130, PIN_OUTPUT, 0) /* (AG26) RGMII1_TXC */
+                       J722S_IOPAD(0x012c, PIN_OUTPUT, 0) /* (AF25) RGMII1_TX_CTL */
+               >;
+       };
+};
+
+&cpsw3g {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&rgmii1_pins_default>;
+};
+
+&cpsw3g_mdio {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&mdio_pins_default>;
+
+       cpsw3g_phy0: ethernet-phy@0 {
+               reg = <0>;
+               ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+               ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+               ti,min-output-impedance;
+       };
+};
+
+&cpsw_port1 {
+       phy-mode = "rgmii-rxid";
+       phy-handle = <&cpsw3g_phy0>;
+};
+
+&cpsw_port2 {
+       status = "disabled";
+};
+
+&main_gpio1 {
+       status = "okay";
+};
+
+&main_uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_uart0_pins_default>;
+       status = "okay";
+       bootph-all;
+};
+
+&mcu_pmx0 {
+
+       wkup_uart0_pins_default: wkup-uart0-default-pins {
+               pinctrl-single,pins = <
+                       J722S_MCU_IOPAD(0x02c, PIN_INPUT, 0)    /* (C7) WKUP_UART0_CTSn */
+                       J722S_MCU_IOPAD(0x030, PIN_OUTPUT, 0)   /* (C6) WKUP_UART0_RTSn */
+                       J722S_MCU_IOPAD(0x024, PIN_INPUT, 0)    /* (D8) WKUP_UART0_RXD */
+                       J722S_MCU_IOPAD(0x028, PIN_OUTPUT, 0)   /* (D7) WKUP_UART0_TXD */
+               >;
+               bootph-all;
+       };
+
+       wkup_i2c0_pins_default: wkup-i2c0-default-pins {
+               pinctrl-single,pins = <
+                       J722S_MCU_IOPAD(0x04c, PIN_INPUT_PULLUP, 0)     /* (C7) WKUP_I2C0_SCL */
+                       J722S_MCU_IOPAD(0x050, PIN_INPUT_PULLUP, 0)     /* (C6) WKUP_I2C1_SDA */
+               >;
+               bootph-all;
+       };
+};
+
+&wkup_uart0 {
+       /* WKUP UART0 is used by Device Manager firmware */
+       pinctrl-names = "default";
+       pinctrl-0 = <&wkup_uart0_pins_default>;
+       status = "reserved";
+       bootph-all;
+};
+
+&wkup_i2c0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&wkup_i2c0_pins_default>;
+       clock-frequency = <400000>;
+       status = "okay";
+       bootph-all;
+};
+
+&main_i2c0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_i2c0_pins_default>;
+       clock-frequency = <400000>;
+       status = "okay";
+       bootph-all;
+
+       exp1: gpio@23 {
+               compatible = "ti,tca6424";
+               reg = <0x23>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               gpio-line-names = "TRC_MUX_SEL", "OSPI/ONAND_MUX_SEL",
+                                 "MCASP1_FET_SEL", "CTRL_PM_I2C_OE#",
+                                 "CSI_VIO_SEL", "USB2.0_MUX_SEL",
+                                 "CSI01_MUX_SEL_2", "CSI23_MUX_SEL_2",
+                                 "LMK1_OE1", "LMK1_OE0",
+                                 "LMK2_OE0", "LMK2_OE1",
+                                 "GPIO_RGMII1_RST#", "GPIO_AUD_RSTn",
+                                 "GPIO_eMMC_RSTn", "GPIO_uSD_PWR_EN",
+                                 "USER_LED2", "MCAN0_STB",
+                                 "PCIe0_1L_RC_RSTz", "PCIe0_1L_PRSNT#",
+                                 "ENET1_EXP_SPARE2", "ENET1_EXP_PWRDN",
+                                 "PD_I2ENET1_I2CMUX_SELC_IRQ", "ENET1_EXP_RESETZ";
+       };
+};
+
+&ospi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&ospi0_pins_default>;
+       status = "okay";
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0x0>;
+               spi-tx-bus-width = <8>;
+               spi-rx-bus-width = <8>;
+               spi-max-frequency = <25000000>;
+               cdns,tshsl-ns = <60>;
+               cdns,tsd2d-ns = <60>;
+               cdns,tchsh-ns = <60>;
+               cdns,tslch-ns = <60>;
+               cdns,read-delay = <4>;
+               bootph-all;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "ospi.tiboot3";
+                               reg = <0x00 0x80000>;
+                       };
+
+                       partition@80000 {
+                               label = "ospi.tispl";
+                               reg = <0x80000 0x200000>;
+                       };
+
+                       partition@280000 {
+                               label = "ospi.u-boot";
+                               reg = <0x280000 0x400000>;
+                       };
+
+                       partition@680000 {
+                               label = "ospi.env";
+                               reg = <0x680000 0x40000>;
+                       };
+
+                       partition@6c0000 {
+                               label = "ospi.env.backup";
+                               reg = <0x6c0000 0x40000>;
+                       };
+
+                       partition@800000 {
+                               label = "ospi.rootfs";
+                               reg = <0x800000 0x37c0000>;
+                       };
+
+                       partition@3fc0000 {
+                               label = "ospi.phypattern";
+                               reg = <0x3fc0000 0x40000>;
+                       };
+               };
+       };
+
+};
+
+&sdhci1 {
+       /* SD/MMC */
+       vmmc-supply = <&vdd_mmc1>;
+       vqmmc-supply = <&vdd_sd_dv>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_mmc1_pins_default>;
+       ti,driver-strength-ohm = <50>;
+       disable-wp;
+       no-1-8-v;
+       status = "okay";
+       bootph-all;
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j722s.dtsi b/arch/arm64/boot/dts/ti/k3-j722s.dtsi
new file mode 100644 (file)
index 0000000..c75744e
--- /dev/null
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Device Tree Source for J722S SoC Family
+ *
+ * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/soc/ti,sci_pm_domain.h>
+
+#include "k3-am62p5.dtsi"
+
+/ {
+       model = "Texas Instruments K3 J722S SoC";
+       compatible = "ti,j722s";
+
+       cbass_main: bus@f0000 {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+
+               ranges = <0x00 0x000f0000 0x00 0x000f0000 0x00 0x00030000>, /* Main MMRs */
+                        <0x00 0x00420000 0x00 0x00420000 0x00 0x00001000>, /* ESM0 */
+                        <0x00 0x00600000 0x00 0x00600000 0x00 0x00001100>, /* GPIO */
+                        <0x00 0x00703000 0x00 0x00703000 0x00 0x00000200>, /* USB0 debug trace */
+                        <0x00 0x0070c000 0x00 0x0070c000 0x00 0x00000200>, /* USB1 debug trace */
+                        <0x00 0x00a40000 0x00 0x00a40000 0x00 0x00000800>, /* Timesync router */
+                        <0x00 0x01000000 0x00 0x01000000 0x00 0x01b28400>, /* First peripheral window */
+                        <0x00 0x08000000 0x00 0x08000000 0x00 0x00200000>, /* Main CPSW */
+                        <0x00 0x0d000000 0x00 0x0d000000 0x00 0x00800000>, /* PCIE_0 */
+                        <0x00 0x0e000000 0x00 0x0e000000 0x00 0x01d20000>, /* Second peripheral window */
+                        <0x00 0x0fd80000 0x00 0x0fd80000 0x00 0x00080000>, /* GPU */
+                        <0x00 0x0fd20000 0x00 0x0fd20000 0x00 0x00000100>, /* JPEGENC0_CORE */
+                        <0x00 0x0fd20200 0x00 0x0fd20200 0x00 0x00000200>, /* JPEGENC0_CORE_MMU */
+                        <0x00 0x20000000 0x00 0x20000000 0x00 0x0a008000>, /* Third peripheral window */
+                        <0x00 0x30040000 0x00 0x30040000 0x00 0x00080000>, /* PRUSS-M */
+                        <0x00 0x301C0000 0x00 0x301C0000 0x00 0x00001000>, /* DPHY-TX */
+                        <0x00 0x30101000 0x00 0x30101000 0x00 0x00080100>, /* CSI window */
+                        <0x00 0x30200000 0x00 0x30200000 0x00 0x00010000>, /* DSS */
+                        <0x00 0x30210000 0x00 0x30210000 0x00 0x00010000>, /* VPU */
+                        <0x00 0x30220000 0x00 0x30220000 0x00 0x00010000>, /* DSS1 */
+                        <0x00 0x30270000 0x00 0x30270000 0x00 0x00010000>, /* DSI-base1 */
+                        <0x00 0x30500000 0x00 0x30500000 0x00 0x00100000>, /* DSI-base2 */
+                        <0x00 0x31000000 0x00 0x31000000 0x00 0x00050000>, /* USB0 DWC3 Core window */
+                        <0x00 0x31200000 0x00 0x31200000 0x00 0x00040000>, /* USB1 DWC3 Core window */
+                        <0x00 0x40900000 0x00 0x40900000 0x00 0x00030000>, /* SA3UL */
+                        <0x00 0x43600000 0x00 0x43600000 0x00 0x00010000>, /* SA3 sproxy data */
+                        <0x00 0x44043000 0x00 0x44043000 0x00 0x00000fe0>, /* TI SCI DEBUG */
+                        <0x00 0x44860000 0x00 0x44860000 0x00 0x00040000>, /* SA3 sproxy config */
+                        <0x00 0x48000000 0x00 0x48000000 0x00 0x06408000>, /* DMSS */
+                        <0x00 0x60000000 0x00 0x60000000 0x00 0x08000000>, /* FSS0 DAT1 */
+                        <0x00 0x68000000 0x00 0x68000000 0x00 0x08000000>, /* PCIe0 DAT0 */
+                        <0x00 0x70000000 0x00 0x70000000 0x00 0x00040000>, /* OCSRAM */
+                        <0x00 0x78400000 0x00 0x78400000 0x00 0x00008000>, /* MAIN R5FSS0 ATCM */
+                        <0x00 0x78500000 0x00 0x78500000 0x00 0x00008000>, /* MAIN R5FSS0 BTCM */
+                        <0x00 0x7e000000 0x00 0x7e000000 0x00 0x00200000>, /* C7X_0 L2SRAM */
+                        <0x00 0x7e200000 0x00 0x7e200000 0x00 0x00200000>, /* C7X_1 L2SRAM */
+                        <0x01 0x00000000 0x01 0x00000000 0x00 0x00310000>, /* A53 PERIPHBASE */
+                        <0x05 0x00000000 0x05 0x00000000 0x01 0x00000000>, /* FSS0 DAT3 */
+                        <0x06 0x00000000 0x06 0x00000000 0x01 0x00000000>, /* PCIe0 DAT1 */
+
+                        /* MCU Domain Range */
+                        <0x00 0x04000000 0x00 0x04000000 0x00 0x01ff1400>,
+                        <0x00 0x79000000 0x00 0x79000000 0x00 0x00008000>,
+                        <0x00 0x79020000 0x00 0x79020000 0x00 0x00008000>,
+                        <0x00 0x79100000 0x00 0x79100000 0x00 0x00040000>,
+                        <0x00 0x79140000 0x00 0x79140000 0x00 0x00040000>,
+
+                        /* Wakeup Domain Range */
+                        <0x00 0x00b00000 0x00 0x00b00000 0x00 0x00002400>,
+                        <0x00 0x2b000000 0x00 0x2b000000 0x00 0x00300400>,
+                        <0x00 0x43000000 0x00 0x43000000 0x00 0x00020000>,
+                        <0x00 0x78000000 0x00 0x78000000 0x00 0x00008000>,
+                        <0x00 0x78100000 0x00 0x78100000 0x00 0x00008000>;
+       };
+};
+
+/* Main domain overrides */
+
+&inta_main_dmss {
+       ti,interrupt-ranges = <7 71 21>;
+};
+
+&oc_sram {
+       reg = <0x00 0x70000000 0x00 0x40000>;
+       ranges = <0x00 0x00 0x70000000 0x40000>;
+};
index f34b92acc56d870f50cddd2b039c9c513171a32a..81fd7afac8c577a632175c206fe008ee393fad6e 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
- * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  *
  * EVM Board Schematics: https://www.ti.com/lit/zip/sprr458
  */
@@ -31,6 +31,7 @@
 
        memory@80000000 {
                device_type = "memory";
+               bootph-all;
                /* 32G RAM */
                reg = <0x00 0x80000000 0x00 0x80000000>,
                      <0x08 0x80000000 0x07 0x80000000>;
                >;
        };
 
+       main_i2c5_pins_default: main-i2c5-default-pins {
+               pinctrl-single,pins = <
+                       J784S4_IOPAD(0x01c, PIN_INPUT, 8) /* (AG34) MCAN15_TX.I2C5_SCL */
+                       J784S4_IOPAD(0x018, PIN_INPUT, 8) /* (AK36) MCAN14_RX.I2C5_SDA */
+               >;
+       };
+
        main_mmc1_pins_default: main-mmc1-default-pins {
                bootph-all;
                pinctrl-single,pins = <
        wkup_uart0_pins_default: wkup-uart0-default-pins {
                bootph-all;
                pinctrl-single,pins = <
-                       J721S2_WKUP_IOPAD(0x070, PIN_INPUT, 0) /* (L37) WKUP_GPIO0_6.WKUP_UART0_CTSn */
-                       J721S2_WKUP_IOPAD(0x074, PIN_INPUT, 0) /* (L36) WKUP_GPIO0_7.WKUP_UART0_RTSn */
                        J721S2_WKUP_IOPAD(0x048, PIN_INPUT, 0) /* (K35) WKUP_UART0_RXD */
                        J721S2_WKUP_IOPAD(0x04c, PIN_INPUT, 0) /* (K34) WKUP_UART0_TXD */
                >;
        };
 };
 
+&main_i2c5 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_i2c5_pins_default>;
+       clock-frequency = <400000>;
+       status = "okay";
+
+       exp5: gpio@20 {
+               compatible = "ti,tca6408";
+               reg = <0x20>;
+               gpio-controller;
+               #gpio-cells = <2>;
+               gpio-line-names = "CSI2_EXP_RSTZ", "CSI2_EXP_A_GPIO0",
+                                 "CSI2_EXP_A_GPIO1", "CSI2_EXP_A_GPIO3",
+                                 "CSI2_EXP_B_GPIO1", "CSI2_EXP_B_GPIO2",
+                                 "CSI2_EXP_B_GPIO3", "CSI2_EXP_B_GPIO4";
+       };
+};
+
 &main_sdhci0 {
        bootph-all;
        /* eMMC */
index f2b720ed1e4f232261a6efa7e493c873680ec076..b67c37460a73d8033107ded849b3b445e49d7d35 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for J784S4 SoC Family Main Domain peripherals
  *
- * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #include <dt-bindings/mux/mux.h>
                        compatible = "reg-mux";
                        reg = <0x00004080 0x30>;
                        #mux-control-cells = <1>;
-                       mux-reg-masks = <0x4080 0x3>, <0x4084 0x3>, /* SERDES0 lane0/1 select */
-                                       <0x4088 0x3>, <0x408c 0x3>, /* SERDES0 lane2/3 select */
-                                       <0x4090 0x3>, <0x4094 0x3>, /* SERDES1 lane0/1 select */
-                                       <0x4098 0x3>, <0x409c 0x3>, /* SERDES1 lane2/3 select */
-                                       <0x40a0 0x3>, <0x40a4 0x3>, /* SERDES2 lane0/1 select */
-                                       <0x40a8 0x3>, <0x40ac 0x3>; /* SERDES2 lane2/3 select */
+                       mux-reg-masks = <0x0 0x3>, <0x4 0x3>, /* SERDES0 lane0/1 select */
+                                       <0x8 0x3>, <0xc 0x3>, /* SERDES0 lane2/3 select */
+                                       <0x10 0x3>, <0x14 0x3>, /* SERDES1 lane0/1 select */
+                                       <0x18 0x3>, <0x1c 0x3>, /* SERDES1 lane2/3 select */
+                                       <0x20 0x3>, <0x24 0x3>, /* SERDES2 lane0/1 select */
+                                       <0x28 0x3>, <0x2c 0x3>; /* SERDES2 lane2/3 select */
                        idle-states = <J784S4_SERDES0_LANE0_PCIE1_LANE0>,
                                      <J784S4_SERDES0_LANE1_PCIE1_LANE1>,
                                      <J784S4_SERDES0_LANE2_IP3_UNUSED>,
                status = "disabled";
        };
 
+       ti_csi2rx0: ticsi2rx@4500000 {
+               compatible = "ti,j721e-csi2rx-shim";
+               reg = <0x00 0x04500000 0x00 0x00001000>;
+               ranges;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               dmas = <&main_bcdma_csi 0 0x4940 0>;
+               dma-names = "rx0";
+               power-domains = <&k3_pds 72 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+
+               cdns_csi2rx0: csi-bridge@4504000 {
+                       compatible = "ti,j721e-csi2rx", "cdns,csi2rx";
+                       reg = <0x00 0x04504000 0x00 0x00001000>;
+                       clocks = <&k3_clks 72 2>, <&k3_clks 72 0>, <&k3_clks 72 2>,
+                               <&k3_clks 72 2>, <&k3_clks 72 3>, <&k3_clks 72 3>;
+                       clock-names = "sys_clk", "p_clk", "pixel_if0_clk",
+                               "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk";
+                       phys = <&dphy0>;
+                       phy-names = "dphy";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               csi0_port0: port@0 {
+                                       reg = <0>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port1: port@1 {
+                                       reg = <1>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port2: port@2 {
+                                       reg = <2>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port3: port@3 {
+                                       reg = <3>;
+                                       status = "disabled";
+                               };
+
+                               csi0_port4: port@4 {
+                                       reg = <4>;
+                                       status = "disabled";
+                               };
+                       };
+               };
+       };
+
+       ti_csi2rx1: ticsi2rx@4510000 {
+               compatible = "ti,j721e-csi2rx-shim";
+               reg = <0x00 0x04510000 0x00 0x1000>;
+               ranges;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               dmas = <&main_bcdma_csi 0 0x4960 0>;
+               dma-names = "rx0";
+               power-domains = <&k3_pds 73 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+
+               cdns_csi2rx1: csi-bridge@4514000 {
+                       compatible = "ti,j721e-csi2rx", "cdns,csi2rx";
+                       reg = <0x00 0x04514000 0x00 0x00001000>;
+                       clocks = <&k3_clks 73 2>, <&k3_clks 73 0>, <&k3_clks 73 2>,
+                               <&k3_clks 73 2>, <&k3_clks 73 3>, <&k3_clks 73 3>;
+                       clock-names = "sys_clk", "p_clk", "pixel_if0_clk",
+                               "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk";
+                       phys = <&dphy1>;
+                       phy-names = "dphy";
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               csi1_port0: port@0 {
+                                       reg = <0>;
+                                       status = "disabled";
+                               };
+
+                               csi1_port1: port@1 {
+                                       reg = <1>;
+                                       status = "disabled";
+                               };
+
+                               csi1_port2: port@2 {
+                                       reg = <2>;
+                                       status = "disabled";
+                               };
+
+                               csi1_port3: port@3 {
+                                       reg = <3>;
+                                       status = "disabled";
+                               };
+
+                               csi1_port4: port@4 {
+                                       reg = <4>;
+                                       status = "disabled";
+                               };
+                       };
+               };
+       };
+
+       ti_csi2rx2: ticsi2rx@4520000 {
+               compatible = "ti,j721e-csi2rx-shim";
+               reg = <0x00 0x04520000 0x00 0x00001000>;
+               ranges;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               dmas = <&main_bcdma_csi 0 0x4980 0>;
+               dma-names = "rx0";
+               power-domains = <&k3_pds 74 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+
+               cdns_csi2rx2: csi-bridge@4524000 {
+                       compatible = "ti,j721e-csi2rx", "cdns,csi2rx";
+                       reg = <0x00 0x04524000 0x00 0x00001000>;
+                       clocks = <&k3_clks 74 2>, <&k3_clks 74 0>, <&k3_clks 74 2>,
+                               <&k3_clks 74 2>, <&k3_clks 74 3>, <&k3_clks 74 3>;
+                       clock-names = "sys_clk", "p_clk", "pixel_if0_clk",
+                               "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk";
+                       phys = <&dphy2>;
+                       phy-names = "dphy";
+
+                       ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               csi2_port0: port@0 {
+                                       reg = <0>;
+                                       status = "disabled";
+                               };
+
+                               csi2_port1: port@1 {
+                                       reg = <1>;
+                                       status = "disabled";
+                               };
+
+                               csi2_port2: port@2 {
+                                       reg = <2>;
+                                       status = "disabled";
+                               };
+
+                               csi2_port3: port@3 {
+                                       reg = <3>;
+                                       status = "disabled";
+                               };
+
+                               csi2_port4: port@4 {
+                                       reg = <4>;
+                                       status = "disabled";
+                               };
+                       };
+               };
+       };
+
+       dphy0: phy@4580000 {
+               compatible = "cdns,dphy-rx";
+               reg = <0x00 0x04580000 0x00 0x00001100>;
+               #phy-cells = <0>;
+               power-domains = <&k3_pds 212 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+       };
+
+       dphy1: phy@4590000 {
+               compatible = "cdns,dphy-rx";
+               reg = <0x00 0x04590000 0x00 0x00001100>;
+               #phy-cells = <0>;
+               power-domains = <&k3_pds 213 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+       };
+
+       dphy2: phy@45a0000 {
+               compatible = "cdns,dphy-rx";
+               reg = <0x00 0x045a0000 0x00 0x00001100>;
+               #phy-cells = <0>;
+               power-domains = <&k3_pds 214 TI_SCI_PD_EXCLUSIVE>;
+               status = "disabled";
+       };
+
+       vpu0: video-codec@4210000 {
+               compatible = "ti,j721s2-wave521c", "cnm,wave521c";
+               reg = <0x00 0x4210000 0x00 0x10000>;
+               interrupts = <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&k3_clks 241 2>;
+               power-domains = <&k3_pds 241 TI_SCI_PD_EXCLUSIVE>;
+       };
+
+       vpu1: video-codec@4220000 {
+               compatible = "ti,j721s2-wave521c", "cnm,wave521c";
+               reg = <0x00 0x4220000 0x00 0x10000>;
+               interrupts = <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&k3_clks 242 2>;
+               power-domains = <&k3_pds 242 TI_SCI_PD_EXCLUSIVE>;
+       };
+
        main_sdhci0: mmc@4f80000 {
                compatible = "ti,j721e-sdhci-8bit";
                reg = <0x00 0x04f80000 0x00 0x1000>,
                        ti,sci-dev-id = <281>;
                        ti,sci-rm-range-rchan = <0x21>;
                        ti,sci-rm-range-tchan = <0x22>;
-                       status = "disabled";
                };
 
                cpts@310d0000 {
index 3902a921d7e58500b37e3dcec91eaf0d6a4fe941..77a8d99139ec15677c0cfc2cb6d4e919f489af00 100644 (file)
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for J784S4 SoC Family MCU/WAKEUP Domain peripherals
  *
- * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 &cbass_mcu_wakeup {
                compatible = "ti,j7200-vtm";
                reg = <0x00 0x42040000 0x00 0x350>,
                      <0x00 0x42050000 0x00 0x350>;
-               power-domains = <&k3_pds 154 TI_SCI_PD_SHARED>;
+               power-domains = <&k3_pds 243 TI_SCI_PD_SHARED>;
                #thermal-sensor-cells = <1>;
        };
 
index f7b1a15b8fa0a29083ff2727af6223e44ff7f9f5..e3ef61c1658f4b6b2caff67b2dc6032eb2aada11 100644 (file)
@@ -1,4 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
 
 #include <dt-bindings/thermal/thermal.h>
 
index 4398c3a463e1a9ca6828f7603aa0f6862ccdb277..6e2e92ffe7452b8a8ed1c1ece3b451a6360dceec 100644 (file)
@@ -1,10 +1,10 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
 /*
  * Device Tree Source for J784S4 SoC Family
  *
  * TRM (SPRUJ43 JULY 2022): https://www.ti.com/lit/zip/spruj52
  *
- * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/
  *
  */
 
                ranges = <0x00 0x00100000 0x00 0x00100000 0x00 0x00020000>, /* ctrl mmr */
                         <0x00 0x00600000 0x00 0x00600000 0x00 0x00031100>, /* GPIO */
                         <0x00 0x01000000 0x00 0x01000000 0x00 0x0d000000>, /* Most peripherals */
+                        <0x00 0x04210000 0x00 0x04210000 0x00 0x00010000>, /* VPU0 */
+                        <0x00 0x04220000 0x00 0x04220000 0x00 0x00010000>, /* VPU1 */
                         <0x00 0x0d000000 0x00 0x0d000000 0x00 0x01000000>, /* PCIe Core*/
                         <0x00 0x10000000 0x00 0x10000000 0x00 0x08000000>, /* PCIe0 DAT0 */
                         <0x00 0x18000000 0x00 0x18000000 0x00 0x08000000>, /* PCIe1 DAT0 */
index 2a4e0e084d695d0a5feff71b149277499b1fba0d..4cd2df467d0b41dad2925836d13e0e970f7abd42 100644 (file)
@@ -1,9 +1,9 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
 /*
  * This header provides constants for pinctrl bindings for TI's K3 SoC
  * family.
  *
- * Copyright (C) 2018-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 #ifndef DTS_ARM64_TI_K3_PINCTRL_H
 #define DTS_ARM64_TI_K3_PINCTRL_H
@@ -59,6 +59,9 @@
 #define J721S2_IOPAD(pa, val, muxmode)         (((pa) & 0x1fff)) ((val) | (muxmode))
 #define J721S2_WKUP_IOPAD(pa, val, muxmode)    (((pa) & 0x1fff)) ((val) | (muxmode))
 
+#define J722S_IOPAD(pa, val, muxmode)          (((pa) & 0x1fff)) ((val) | (muxmode))
+#define J722S_MCU_IOPAD(pa, val, muxmode)      (((pa) & 0x1fff)) ((val) | (muxmode))
+
 #define J784S4_IOPAD(pa, val, muxmode)         (((pa) & 0x1fff)) ((val) | (muxmode))
 #define J784S4_WKUP_IOPAD(pa, val, muxmode)    (((pa) & 0x1fff)) ((val) | (muxmode))
 
index 21b4886c47ba09665acdeb095e9ce6dd90af288c..a011ad893b44c6653f35d911fc08ad98ae99b8e6 100644 (file)
@@ -1,8 +1,8 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
 /*
  * This header provides constants for SERDES MUX for TI SoCs
  *
- * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
  */
 
 #ifndef DTS_ARM64_TI_K3_SERDES_H
index ccaca29200bb93519432a7983ca6bb9f4acf3280..dd4569e7bd95801197b602aeda74b278f784c855 100644 (file)
 
 &uart0 {
        clocks = <&zynqmp_clk UART0_REF>, <&zynqmp_clk LPD_LSBUS>;
+       assigned-clocks = <&zynqmp_clk UART0_REF>;
 };
 
 &uart1 {
        clocks = <&zynqmp_clk UART1_REF>, <&zynqmp_clk LPD_LSBUS>;
+       assigned-clocks = <&zynqmp_clk UART1_REF>;
 };
 
-&dwc3_0 {
+&usb0 {
        clocks = <&zynqmp_clk USB0_BUS_REF>, <&zynqmp_clk USB3_DUAL_REF>;
+       assigned-clocks = <&zynqmp_clk USB0_BUS_REF>, <&zynqmp_clk USB3_DUAL_REF>;
 };
 
-&dwc3_1 {
+&dwc3_0 {
+       clocks = <&zynqmp_clk USB3_DUAL_REF>;
+};
+
+&usb1 {
        clocks = <&zynqmp_clk USB1_BUS_REF>, <&zynqmp_clk USB3_DUAL_REF>;
+       assigned-clocks = <&zynqmp_clk USB1_BUS_REF>, <&zynqmp_clk USB3_DUAL_REF>;
+};
+
+&dwc3_1 {
+       clocks = <&zynqmp_clk USB3_DUAL_REF>;
 };
 
 &watchdog0 {
index 92f4190d564db12e127fc102cdb33deee191cdb6..d7535a77b45e34785670b71d008db9e63a753cc5 100644 (file)
        bus-width = <4>;
 };
 
-&gem3 { /* required by spec */
+&gem3 {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_gem3_default>;
        };
 };
 
-&pinctrl0 { /* required by spec */
+&pinctrl0 {
        status = "okay";
 
+       pinctrl_gpio0_default: gpio0-default {
+                conf {
+                        groups = "gpio0_38_grp";
+                        bias-pull-up;
+                        power-source = <IO_STANDARD_LVCMOS18>;
+                };
+
+                mux {
+                        groups = "gpio0_38_grp";
+                        function = "gpio0";
+                };
+
+                conf-tx {
+                        pins = "MIO38";
+                        bias-disable;
+                        output-enable;
+                };
+        };
+
        pinctrl_uart1_default: uart1-default {
                conf {
                        groups = "uart1_9_grp";
                conf-tx {
                        pins = "MIO36";
                        bias-disable;
+                       output-enable;
                };
 
                mux {
                };
        };
 
-       pinctrl_i2c1_gpio: i2c1-gpio {
+       pinctrl_i2c1_gpio: i2c1-gpio-grp {
                conf {
                        groups = "gpio0_24_grp", "gpio0_25_grp";
                        slew-rate = <SLEW_RATE_SLOW>;
                conf-bootstrap {
                        pins = "MIO71", "MIO73", "MIO75";
                        bias-disable;
+                       output-enable;
                        low-power-disable;
                };
 
                        pins = "MIO64", "MIO65", "MIO66",
                                "MIO67", "MIO68", "MIO69";
                        bias-disable;
+                       output-enable;
                        low-power-enable;
                };
 
                        slew-rate = <SLEW_RATE_SLOW>;
                        power-source = <IO_STANDARD_LVCMOS18>;
                        bias-disable;
+                       output-enable;
                };
 
                mux-mdio {
                        pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
                        "MIO60", "MIO61", "MIO62", "MIO63";
                        bias-disable;
+                       output-enable;
                        drive-strength = <4>;
                        slew-rate = <SLEW_RATE_SLOW>;
                };
        };
 };
 
+&gpio {
+        status = "okay";
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_gpio0_default>;
+};
+
 &uart1 {
        status = "okay";
        pinctrl-names = "default";
index f88b71f5b07a63fa4ca40ee5c4a91ee516f0125e..a7b8fffad49936b505f6ae2d6264bbb6213baeff 100644 (file)
@@ -94,6 +94,7 @@
        pinctrl-0 = <&pinctrl_usb0_default>;
        phy-names = "usb3-phy";
        phys = <&psgtr 2 PHY_TYPE_USB3 0 1>;
+       assigned-clock-rates = <250000000>, <20000000>;
 };
 
 &dwc3_0 {
        bus-width = <4>;
 };
 
-&gem3 { /* required by spec */
+&gem3 {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_gem3_default>;
        };
 };
 
-&pinctrl0 { /* required by spec */
+&pinctrl0 {
        status = "okay";
 
+       pinctrl_gpio0_default: gpio0-default {
+               conf {
+                       groups = "gpio0_38_grp";
+                       bias-pull-up;
+                       power-source = <IO_STANDARD_LVCMOS18>;
+               };
+
+               mux {
+                       groups = "gpio0_38_grp";
+                       function = "gpio0";
+               };
+
+               conf-tx {
+                       pins = "MIO38";
+                       bias-disable;
+                       output-enable;
+               };
+       };
+
        pinctrl_uart1_default: uart1-default {
                conf {
                        groups = "uart1_9_grp";
                conf-tx {
                        pins = "MIO36";
                        bias-disable;
+                       output-enable;
                };
 
                mux {
                };
        };
 
-       pinctrl_i2c1_gpio: i2c1-gpio {
+       pinctrl_i2c1_gpio: i2c1-gpio-grp {
                conf {
                        groups = "gpio0_24_grp", "gpio0_25_grp";
                        slew-rate = <SLEW_RATE_SLOW>;
                conf-bootstrap {
                        pins = "MIO71", "MIO73", "MIO75";
                        bias-disable;
+                       output-enable;
                        low-power-disable;
                };
 
                        pins = "MIO64", "MIO65", "MIO66",
                                "MIO67", "MIO68", "MIO69";
                        bias-disable;
+                       output-enable;
                        low-power-enable;
                };
 
                        slew-rate = <SLEW_RATE_SLOW>;
                        power-source = <IO_STANDARD_LVCMOS18>;
                        bias-disable;
+                       output-enable;
                };
 
                mux-mdio {
                        pins = "MIO54", "MIO56", "MIO57", "MIO58", "MIO59",
                        "MIO60", "MIO61", "MIO62", "MIO63";
                        bias-disable;
+                       output-enable;
                        drive-strength = <4>;
                        slew-rate = <SLEW_RATE_SLOW>;
                };
        };
 };
 
+&gpio {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpio0_default>;
+};
+
 &uart1 {
        status = "okay";
        pinctrl-names = "default";
index 73491626e01e657e8c041b8dc83283673ef98cf0..6aff22d433616a01ab1828b63491f0bf0a4e84b2 100644 (file)
                };
        };
 
-       pinctrl_i2c1_gpio: i2c1-gpio {
+       pinctrl_i2c1_gpio: i2c1-gpio-grp {
                mux {
                        groups = "gpio0_36_grp", "gpio0_37_grp";
                        function = "gpio0";
index f767708fb50d92b5a192e78894a6aaf08f69e587..1850325e1d6c41473f06b2a191647390908094df 100644 (file)
                };
        };
 
-       pinctrl_i2c0_gpio: i2c0-gpio {
+       pinctrl_i2c0_gpio: i2c0-gpio-grp {
                mux {
                        groups = "gpio0_6_grp", "gpio0_7_grp";
                        function = "gpio0";
index b1857e17ab7e8b95d62f03c60139a7e5bb8149ac..53aa3dca1dca270d4a316d6ec06f0c1526b81af9 100644 (file)
                };
        };
 
-       pinctrl_i2c0_gpio: i2c0-gpio {
+       pinctrl_i2c0_gpio: i2c0-gpio-grp {
                mux {
                        groups = "gpio0_74_grp", "gpio0_75_grp";
                        function = "gpio0";
                };
        };
 
-       pinctrl_i2c1_gpio: i2c1-gpio {
+       pinctrl_i2c1_gpio: i2c1-gpio-grp {
                mux {
                        groups = "gpio0_76_grp", "gpio0_77_grp";
                        function = "gpio0";
index 52f998c225381790a7cf83a300dbaa32baa91e56..c5945067cd5729f4423b52215c692361e45931ca 100644 (file)
                };
        };
 
-       pinctrl_i2c1_gpio: i2c1-gpio {
+       pinctrl_i2c1_gpio: i2c1-gpio-grp {
                mux {
                        groups = "gpio0_4_grp", "gpio0_5_grp";
                        function = "gpio0";
index 84952c14f0219966887004401e39cd0d2962f6dd..ad8f23a0ec67ba8a3907c046427984a665559cae 100644 (file)
                                reg = <0x5d>;
                                temperature-stability = <50>; /* copy from zc702 */
                                factory-fout = <156250000>;
-                               clock-frequency = <148500000>;
+                               clock-frequency = <156250000>;
                                clock-output-names = "si570_mgt";
                        };
                };
                };
        };
 
-       pinctrl_i2c0_gpio: i2c0-gpio {
+       pinctrl_i2c0_gpio: i2c0-gpio-grp {
                mux {
                        groups = "gpio0_14_grp", "gpio0_15_grp";
                        function = "gpio0";
                };
        };
 
-       pinctrl_i2c1_gpio: i2c1-gpio {
+       pinctrl_i2c1_gpio: i2c1-gpio-grp {
                mux {
                        groups = "gpio0_16_grp", "gpio0_17_grp";
                        function = "gpio0";
index 5084ddcee00f2de4abc648553056eef84149e92d..b1eca1bb6a633c31901748449fd0bfe349ff20c0 100644 (file)
                };
        };
 
-       pinctrl_i2c1_gpio: i2c1-gpio {
+       pinctrl_i2c1_gpio: i2c1-gpio-grp {
                mux {
                        groups = "gpio0_16_grp", "gpio0_17_grp";
                        function = "gpio0";
index b273bd1d920ab36326e5fc2f7c1e00fafa4b32fa..ddc74d963a05ed96b34cf2c962ca98644ba6ab8f 100644 (file)
                };
        };
 
-       pinctrl_i2c1_gpio: i2c1-gpio {
+       pinctrl_i2c1_gpio: i2c1-gpio-grp {
                mux {
                        groups = "gpio0_16_grp", "gpio0_17_grp";
                        function = "gpio0";
index 50c384aa253e407c073843dc221b14919d1bb9d4..7beedd730f940e279411f1cf2990f4272a892b6d 100644 (file)
                                reg = <0x5d>;
                                temperature-stability = <50>; /* copy from zc702 */
                                factory-fout = <156250000>;
-                               clock-frequency = <148500000>;
+                               clock-frequency = <156250000>;
                                clock-output-names = "si570_mgt";
                        };
                };
                };
        };
 
-       pinctrl_i2c0_gpio: i2c0-gpio {
+       pinctrl_i2c0_gpio: i2c0-gpio-grp {
                mux {
                        groups = "gpio0_14_grp", "gpio0_15_grp";
                        function = "gpio0";
                };
        };
 
-       pinctrl_i2c1_gpio: i2c1-gpio {
+       pinctrl_i2c1_gpio: i2c1-gpio-grp {
                mux {
                        groups = "gpio0_16_grp", "gpio0_17_grp";
                        function = "gpio0";
index 617cb0405a7d5424d9971d0573be1a7019572171..b67ff7ecf3c3f9e40f7f9f43e2a6e3b7f2853baf 100644 (file)
                };
        };
 
-       pinctrl_i2c0_gpio: i2c0-gpio {
+       pinctrl_i2c0_gpio: i2c0-gpio-grp {
                mux {
                        groups = "gpio0_14_grp", "gpio0_15_grp";
                        function = "gpio0";
                };
        };
 
-       pinctrl_i2c1_gpio: i2c1-gpio {
+       pinctrl_i2c1_gpio: i2c1-gpio-grp {
                mux {
                        groups = "gpio0_16_grp", "gpio0_17_grp";
                        function = "gpio0";
index c406017b0348f240393cd6ffaf14864e53babd1b..a38c2baeba6cfff23a83f72a9e568dd5a46a4de2 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * dts file for Xilinx ZynqMP ZC1275
+ * dts file for Xilinx ZynqMP ZCU1275
  *
  * (C) Copyright 2017 - 2021, Xilinx, Inc.
  *
index eaba466804bc304eecf205c962a7c5d4c5e977fa..25d20d8032305d1f922c3cbb28b9705bcd4b1e57 100644 (file)
        #address-cells = <2>;
        #size-cells = <2>;
 
+       options {
+               u-boot {
+                       compatible = "u-boot,config";
+                       bootscr-address = /bits/ 64 <0x20000000>;
+               };
+       };
+
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
        };
 
        firmware {
+               optee: optee  {
+                       compatible = "linaro,optee-tz";
+                       method = "smc";
+               };
+
                zynqmp_firmware: zynqmp-firmware {
                        compatible = "xlnx,zynqmp-firmware";
                        #power-domain-cells = <1>;
                        method = "smc";
                        bootph-all;
 
-                       zynqmp_power: zynqmp-power {
+                       zynqmp_power: power-management {
                                bootph-all;
                                compatible = "xlnx,zynqmp-power";
                                interrupt-parent = <&gic>;
                        interrupt-parent = <&gic>;
                        tx-fifo-depth = <0x40>;
                        rx-fifo-depth = <0x40>;
+                       resets = <&zynqmp_reset ZYNQMP_RESET_CAN0>;
                        power-domains = <&zynqmp_firmware PD_CAN_0>;
                };
 
                        interrupt-parent = <&gic>;
                        tx-fifo-depth = <0x40>;
                        rx-fifo-depth = <0x40>;
+                       resets = <&zynqmp_reset ZYNQMP_RESET_CAN1>;
                        power-domains = <&zynqmp_firmware PD_CAN_1>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <128>;
-                       iommus = <&smmu 0x14e8>;
+                       /* iommus = <&smmu 0x14e8>; */
                        power-domains = <&zynqmp_firmware PD_GDMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <128>;
-                       iommus = <&smmu 0x14e9>;
+                       /* iommus = <&smmu 0x14e9>; */
                        power-domains = <&zynqmp_firmware PD_GDMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <128>;
-                       iommus = <&smmu 0x14ea>;
+                       /* iommus = <&smmu 0x14ea>; */
                        power-domains = <&zynqmp_firmware PD_GDMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <128>;
-                       iommus = <&smmu 0x14eb>;
+                       /* iommus = <&smmu 0x14eb>; */
                        power-domains = <&zynqmp_firmware PD_GDMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <128>;
-                       iommus = <&smmu 0x14ec>;
+                       /* iommus = <&smmu 0x14ec>; */
                        power-domains = <&zynqmp_firmware PD_GDMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <128>;
-                       iommus = <&smmu 0x14ed>;
+                       /* iommus = <&smmu 0x14ed>; */
                        power-domains = <&zynqmp_firmware PD_GDMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <128>;
-                       iommus = <&smmu 0x14ee>;
+                       /* iommus = <&smmu 0x14ee>; */
                        power-domains = <&zynqmp_firmware PD_GDMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <128>;
-                       iommus = <&smmu 0x14ef>;
+                       /* iommus = <&smmu 0x14ef>; */
                        power-domains = <&zynqmp_firmware PD_GDMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <64>;
-                       iommus = <&smmu 0x868>;
+                       /* iommus = <&smmu 0x868>; */
                        power-domains = <&zynqmp_firmware PD_ADMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <64>;
-                       iommus = <&smmu 0x869>;
+                       /* iommus = <&smmu 0x869>; */
                        power-domains = <&zynqmp_firmware PD_ADMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <64>;
-                       iommus = <&smmu 0x86a>;
+                       /* iommus = <&smmu 0x86a>; */
                        power-domains = <&zynqmp_firmware PD_ADMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <64>;
-                       iommus = <&smmu 0x86b>;
+                       /* iommus = <&smmu 0x86b>; */
                        power-domains = <&zynqmp_firmware PD_ADMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <64>;
-                       iommus = <&smmu 0x86c>;
+                       /* iommus = <&smmu 0x86c>; */
                        power-domains = <&zynqmp_firmware PD_ADMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <64>;
-                       iommus = <&smmu 0x86d>;
+                       /* iommus = <&smmu 0x86d>; */
                        power-domains = <&zynqmp_firmware PD_ADMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <64>;
-                       iommus = <&smmu 0x86e>;
+                       /* iommus = <&smmu 0x86e>; */
                        power-domains = <&zynqmp_firmware PD_ADMA>;
                };
 
                        clock-names = "clk_main", "clk_apb";
                        #dma-cells = <1>;
                        xlnx,bus-width = <64>;
-                       iommus = <&smmu 0x86f>;
+                       /* iommus = <&smmu 0x86f>; */
                        power-domains = <&zynqmp_firmware PD_ADMA>;
                };
 
                        interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       iommus = <&smmu 0x872>;
+                       /* iommus = <&smmu 0x872>; */
                        power-domains = <&zynqmp_firmware PD_NAND>;
                };
 
                                     <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
                        reg = <0x0 0xff0b0000 0x0 0x1000>;
                        clock-names = "pclk", "hclk", "tx_clk", "rx_clk", "tsu_clk";
-                       iommus = <&smmu 0x874>;
+                       /* iommus = <&smmu 0x874>; */
                        power-domains = <&zynqmp_firmware PD_ETH_0>;
                        resets = <&zynqmp_reset ZYNQMP_RESET_GEM0>;
                        reset-names = "gem0_rst";
                                     <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
                        reg = <0x0 0xff0c0000 0x0 0x1000>;
                        clock-names = "pclk", "hclk", "tx_clk", "rx_clk", "tsu_clk";
-                       iommus = <&smmu 0x875>;
+                       /* iommus = <&smmu 0x875>; */
                        power-domains = <&zynqmp_firmware PD_ETH_1>;
                        resets = <&zynqmp_reset ZYNQMP_RESET_GEM1>;
                        reset-names = "gem1_rst";
                                     <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
                        reg = <0x0 0xff0d0000 0x0 0x1000>;
                        clock-names = "pclk", "hclk", "tx_clk", "rx_clk", "tsu_clk";
-                       iommus = <&smmu 0x876>;
+                       /* iommus = <&smmu 0x876>; */
                        power-domains = <&zynqmp_firmware PD_ETH_2>;
                        resets = <&zynqmp_reset ZYNQMP_RESET_GEM2>;
                        reset-names = "gem2_rst";
                                     <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
                        reg = <0x0 0xff0e0000 0x0 0x1000>;
                        clock-names = "pclk", "hclk", "tx_clk", "rx_clk", "tsu_clk";
-                       iommus = <&smmu 0x877>;
+                       /* iommus = <&smmu 0x877>; */
                        power-domains = <&zynqmp_firmware PD_ETH_3>;
                        resets = <&zynqmp_reset ZYNQMP_RESET_GEM3>;
                        reset-names = "gem3_rst";
                        msi-parent = <&pcie>;
                        reg = <0x0 0xfd0e0000 0x0 0x1000>,
                              <0x0 0xfd480000 0x0 0x1000>,
-                             <0x80 0x00000000 0x0 0x1000000>;
+                             <0x80 0x00000000 0x0 0x10000000>;
                        reg-names = "breg", "pcireg", "cfg";
                        ranges = <0x02000000 0x00000000 0xe0000000 0x00000000 0xe0000000 0x00000000 0x10000000>,/* non-prefetchable memory */
                                 <0x43000000 0x00000006 0x00000000 0x00000006 0x00000000 0x00000002 0x00000000>;/* prefetchable memory */
                                        <0x0 0x0 0x0 0x2 &pcie_intc 0x2>,
                                        <0x0 0x0 0x0 0x3 &pcie_intc 0x3>,
                                        <0x0 0x0 0x0 0x4 &pcie_intc 0x4>;
-                       iommus = <&smmu 0x4d0>;
+                       /* iommus = <&smmu 0x4d0>; */
                        power-domains = <&zynqmp_firmware PD_PCIE>;
                        pcie_intc: legacy-interrupt-controller {
                                interrupt-controller;
                              <0x0 0xc0000000 0x0 0x8000000>;
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       iommus = <&smmu 0x873>;
+                       /* iommus = <&smmu 0x873>; */
                        power-domains = <&zynqmp_firmware PD_QSPI>;
                };
 
                        interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
                        power-domains = <&zynqmp_firmware PD_SATA>;
                        resets = <&zynqmp_reset ZYNQMP_RESET_SATA>;
-                       iommus = <&smmu 0x4c0>, <&smmu 0x4c1>,
-                                <&smmu 0x4c2>, <&smmu 0x4c3>;
+                       /* iommus = <&smmu 0x4c0>, <&smmu 0x4c1>, <&smmu 0x4c2>, <&smmu 0x4c3>; */
                };
 
                sdhci0: mmc@ff160000 {
                        interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
                        reg = <0x0 0xff160000 0x0 0x1000>;
                        clock-names = "clk_xin", "clk_ahb";
-                       iommus = <&smmu 0x870>;
+                       /* iommus = <&smmu 0x870>; */
                        #clock-cells = <1>;
                        clock-output-names = "clk_out_sd0", "clk_in_sd0";
                        power-domains = <&zynqmp_firmware PD_SD_0>;
                        interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
                        reg = <0x0 0xff170000 0x0 0x1000>;
                        clock-names = "clk_xin", "clk_ahb";
-                       iommus = <&smmu 0x871>;
+                       /* iommus = <&smmu 0x871>; */
                        #clock-cells = <1>;
                        clock-output-names = "clk_out_sd1", "clk_in_sd1";
                        power-domains = <&zynqmp_firmware PD_SD_1>;
                        status = "disabled";
                        compatible = "xlnx,zynqmp-dwc3";
                        reg = <0x0 0xff9d0000 0x0 0x100>;
+                       clock-names = "bus_clk", "ref_clk";
                        power-domains = <&zynqmp_firmware PD_USB_0>;
                        resets = <&zynqmp_reset ZYNQMP_RESET_USB0_CORERESET>,
                                 <&zynqmp_reset ZYNQMP_RESET_USB0_HIBERRESET>,
 
                        dwc3_0: usb@fe200000 {
                                compatible = "snps,dwc3";
+                               status = "disabled";
                                reg = <0x0 0xfe200000 0x0 0x40000>;
                                interrupt-parent = <&gic>;
                                interrupt-names = "host", "peripheral", "otg";
                                interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
-                               clock-names = "bus_early", "ref";
-                               iommus = <&smmu 0x860>;
+                               clock-names = "ref";
+                               /* iommus = <&smmu 0x860>; */
                                snps,quirk-frame-length-adjustment = <0x20>;
                                snps,resume-hs-terminations;
                                /* dma-coherent; */
                        status = "disabled";
                        compatible = "xlnx,zynqmp-dwc3";
                        reg = <0x0 0xff9e0000 0x0 0x100>;
+                       clock-names = "bus_clk", "ref_clk";
                        power-domains = <&zynqmp_firmware PD_USB_1>;
                        resets = <&zynqmp_reset ZYNQMP_RESET_USB1_CORERESET>,
                                 <&zynqmp_reset ZYNQMP_RESET_USB1_HIBERRESET>,
 
                        dwc3_1: usb@fe300000 {
                                compatible = "snps,dwc3";
+                               status = "disabled";
                                reg = <0x0 0xfe300000 0x0 0x40000>;
                                interrupt-parent = <&gic>;
                                interrupt-names = "host", "peripheral", "otg";
                                interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
-                               clock-names = "bus_early", "ref";
-                               iommus = <&smmu 0x861>;
+                               clock-names = "ref";
+                               /* iommus = <&smmu 0x861>; */
                                snps,quirk-frame-length-adjustment = <0x20>;
                                snps,resume-hs-terminations;
                                /* dma-coherent; */
                        interrupt-parent = <&gic>;
                        clock-names = "axi_clk";
                        power-domains = <&zynqmp_firmware PD_DP>;
+                       /* iommus = <&smmu 0xce4>; */
                        #dma-cells = <1>;
                };
 
                        reg-names = "dp", "blend", "av_buf", "aud";
                        interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-parent = <&gic>;
+                       /* iommus = <&smmu 0xce3>; */
                        clock-names = "dp_apb_clk", "dp_aud_clk",
                                      "dp_vtc_pixel_clk_in";
                        power-domains = <&zynqmp_firmware PD_DP>;
index e6cf3e5d63c3017970a74121de80ef156325180d..5f0632a72d05b4b2d90c0a0c308a9c280de4cdf1 100644 (file)
@@ -251,6 +251,9 @@ CONFIG_RASPBERRYPI_FIRMWARE=y
 CONFIG_INTEL_STRATIX10_SERVICE=y
 CONFIG_INTEL_STRATIX10_RSU=m
 CONFIG_MTK_ADSP_IPC=m
+CONFIG_GOOGLE_FIRMWARE=y
+CONFIG_GOOGLE_CBMEM=m
+CONFIG_GOOGLE_COREBOOT_TABLE=m
 CONFIG_EFI_CAPSULE_LOADER=y
 CONFIG_IMX_SCU=y
 CONFIG_QCOM_QSEECOM=y
@@ -432,6 +435,7 @@ CONFIG_MOUSE_ELAN_I2C=m
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=m
 CONFIG_TOUCHSCREEN_GOODIX=m
+CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI=m
 CONFIG_TOUCHSCREEN_ELAN=m
 CONFIG_TOUCHSCREEN_EDT_FT5X06=m
 CONFIG_INPUT_MISC=y
@@ -620,6 +624,7 @@ CONFIG_PINCTRL_SM8350_LPASS_LPI=m
 CONFIG_PINCTRL_SM8450_LPASS_LPI=m
 CONFIG_PINCTRL_SC8280XP_LPASS_LPI=m
 CONFIG_PINCTRL_SM8550_LPASS_LPI=m
+CONFIG_PINCTRL_SM8650_LPASS_LPI=m
 CONFIG_GPIO_ALTERA=m
 CONFIG_GPIO_DAVINCI=y
 CONFIG_GPIO_DWAPB=y
@@ -632,6 +637,7 @@ CONFIG_GPIO_SYSCON=y
 CONFIG_GPIO_UNIPHIER=y
 CONFIG_GPIO_VISCONTI=y
 CONFIG_GPIO_WCD934X=m
+CONFIG_GPIO_VF610=y
 CONFIG_GPIO_XGENE=y
 CONFIG_GPIO_XGENE_SB=y
 CONFIG_GPIO_MAX732X=y
@@ -752,6 +758,7 @@ CONFIG_REGULATOR_HI6421V530=y
 CONFIG_REGULATOR_HI655X=y
 CONFIG_REGULATOR_MAX77620=y
 CONFIG_REGULATOR_MAX8973=y
+CONFIG_REGULATOR_MAX20411=m
 CONFIG_REGULATOR_MP8859=y
 CONFIG_REGULATOR_MT6315=m
 CONFIG_REGULATOR_MT6357=y
@@ -792,13 +799,16 @@ CONFIG_USB_VIDEO_CLASS=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_SDR_PLATFORM_DRIVERS=y
 CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_AMPHION_VPU=m
 CONFIG_VIDEO_CADENCE_CSI2RX=m
 CONFIG_VIDEO_MEDIATEK_JPEG=m
 CONFIG_VIDEO_MEDIATEK_VCODEC=m
+CONFIG_VIDEO_WAVE_VPU=m
 CONFIG_VIDEO_IMX7_CSI=m
 CONFIG_VIDEO_IMX_MIPI_CSIS=m
 CONFIG_VIDEO_IMX8_ISI=m
 CONFIG_VIDEO_IMX8_ISI_M2M=y
+CONFIG_VIDEO_IMX8_JPEG=m
 CONFIG_VIDEO_QCOM_CAMSS=m
 CONFIG_VIDEO_QCOM_VENUS=m
 CONFIG_VIDEO_RCAR_ISP=m
@@ -861,6 +871,7 @@ CONFIG_DRM_PANEL_RAYDIUM_RM67191=m
 CONFIG_DRM_PANEL_SITRONIX_ST7703=m
 CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA=m
 CONFIG_DRM_PANEL_VISIONOX_VTDR6130=m
+CONFIG_DRM_FSL_LDB=m
 CONFIG_DRM_LONTIUM_LT8912B=m
 CONFIG_DRM_LONTIUM_LT9611=m
 CONFIG_DRM_LONTIUM_LT9611UXC=m
@@ -992,6 +1003,8 @@ CONFIG_SND_SOC_TLV320AIC32X4_I2C=m
 CONFIG_SND_SOC_TLV320AIC3X_I2C=m
 CONFIG_SND_SOC_WCD9335=m
 CONFIG_SND_SOC_WCD934X=m
+CONFIG_SND_SOC_WCD939X=m
+CONFIG_SND_SOC_WCD939X_SDW=m
 CONFIG_SND_SOC_WM8524=m
 CONFIG_SND_SOC_WM8904=m
 CONFIG_SND_SOC_WM8960=m
@@ -1032,6 +1045,7 @@ CONFIG_USB_CDNS_SUPPORT=m
 CONFIG_USB_CDNS3=m
 CONFIG_USB_CDNS3_GADGET=y
 CONFIG_USB_CDNS3_HOST=y
+CONFIG_USB_CDNS3_IMX=m
 CONFIG_USB_MTU3=y
 CONFIG_USB_MUSB_HDRC=y
 CONFIG_USB_MUSB_SUNXI=y
@@ -1049,6 +1063,7 @@ CONFIG_USB_QCOM_EUD=m
 CONFIG_USB_HSIC_USB3503=y
 CONFIG_USB_ONBOARD_HUB=m
 CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_MXS_PHY=m
 CONFIG_USB_GADGET=y
 CONFIG_USB_RENESAS_USBHS_UDC=m
 CONFIG_USB_RZV2M_USB3DRD=y
@@ -1079,6 +1094,7 @@ CONFIG_TYPEC_HD3SS3220=m
 CONFIG_TYPEC_MUX_FSA4480=m
 CONFIG_TYPEC_MUX_GPIO_SBU=m
 CONFIG_TYPEC_MUX_NB7VPQ904M=m
+CONFIG_TYPEC_MUX_WCD939X_USBSS=m
 CONFIG_TYPEC_DP_ALTMODE=m
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK_MINORS=32
@@ -1242,7 +1258,11 @@ CONFIG_COMMON_CLK_MT8192_SCP_ADSP=y
 CONFIG_COMMON_CLK_MT8192_VDECSYS=y
 CONFIG_COMMON_CLK_MT8192_VENCSYS=y
 CONFIG_COMMON_CLK_QCOM=y
+CONFIG_CLK_X1E80100_CAMCC=m
+CONFIG_CLK_X1E80100_DISPCC=m
 CONFIG_CLK_X1E80100_GCC=y
+CONFIG_CLK_X1E80100_GPUCC=m
+CONFIG_CLK_X1E80100_TCSRCC=y
 CONFIG_QCOM_A53PLL=y
 CONFIG_QCOM_CLK_APCS_MSM8916=y
 CONFIG_QCOM_CLK_APCC_MSM8996=y
@@ -1265,6 +1285,7 @@ CONFIG_MSM_MMCC_8998=m
 CONFIG_QCM_GCC_2290=y
 CONFIG_QCM_DISPCC_2290=m
 CONFIG_QCS_GCC_404=y
+CONFIG_QDU_GCC_1000=y
 CONFIG_SC_CAMCC_8280XP=m
 CONFIG_SC_DISPCC_8280XP=m
 CONFIG_SA_GCC_8775P=y
@@ -1366,6 +1387,7 @@ CONFIG_QCOM_STATS=m
 CONFIG_QCOM_WCNSS_CTRL=m
 CONFIG_QCOM_APR=m
 CONFIG_QCOM_ICC_BWMON=m
+CONFIG_QCOM_PBS=m
 CONFIG_ARCH_R8A77995=y
 CONFIG_ARCH_R8A77990=y
 CONFIG_ARCH_R8A77951=y
@@ -1377,6 +1399,7 @@ CONFIG_ARCH_R8A77980=y
 CONFIG_ARCH_R8A77970=y
 CONFIG_ARCH_R8A779A0=y
 CONFIG_ARCH_R8A779G0=y
+CONFIG_ARCH_R8A779H0=y
 CONFIG_ARCH_R8A774C0=y
 CONFIG_ARCH_R8A774E1=y
 CONFIG_ARCH_R8A774A1=y
@@ -1410,6 +1433,7 @@ CONFIG_EXTCON_USBC_CROS_EC=y
 CONFIG_RENESAS_RPCIF=m
 CONFIG_IIO=y
 CONFIG_EXYNOS_ADC=y
+CONFIG_IMX8QXP_ADC=m
 CONFIG_IMX93_ADC=m
 CONFIG_MAX9611=m
 CONFIG_MEDIATEK_MT6577_AUXADC=m
@@ -1461,6 +1485,7 @@ CONFIG_PHY_SUN4I_USB=y
 CONFIG_PHY_CADENCE_TORRENT=m
 CONFIG_PHY_CADENCE_DPHY_RX=m
 CONFIG_PHY_CADENCE_SIERRA=m
+CONFIG_PHY_CADENCE_SALVO=m
 CONFIG_PHY_MIXEL_MIPI_DPHY=m
 CONFIG_PHY_FSL_IMX8M_PCIE=y
 CONFIG_PHY_HI6220_USB=y
@@ -1490,6 +1515,7 @@ CONFIG_PHY_ROCKCHIP_INNO_USB2=y
 CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY=m
 CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY=m
 CONFIG_PHY_ROCKCHIP_PCIE=m
+CONFIG_PHY_ROCKCHIP_SAMSUNG_HDPTX=m
 CONFIG_PHY_ROCKCHIP_SNPS_PCIE3=y
 CONFIG_PHY_ROCKCHIP_TYPEC=y
 CONFIG_PHY_SAMSUNG_UFS=y
@@ -1550,8 +1576,9 @@ CONFIG_INTERCONNECT_QCOM=y
 CONFIG_INTERCONNECT_QCOM_MSM8916=m
 CONFIG_INTERCONNECT_QCOM_MSM8996=m
 CONFIG_INTERCONNECT_QCOM_OSM_L3=m
-CONFIG_INTERCONNECT_QCOM_QCM2290=m
+CONFIG_INTERCONNECT_QCOM_QCM2290=y
 CONFIG_INTERCONNECT_QCOM_QCS404=m
+CONFIG_INTERCONNECT_QCOM_QDU1000=y
 CONFIG_INTERCONNECT_QCOM_SA8775P=y
 CONFIG_INTERCONNECT_QCOM_SC7180=y
 CONFIG_INTERCONNECT_QCOM_SC7280=y
@@ -1560,7 +1587,7 @@ CONFIG_INTERCONNECT_QCOM_SC8280XP=y
 CONFIG_INTERCONNECT_QCOM_SDM845=y
 CONFIG_INTERCONNECT_QCOM_SDX75=y
 CONFIG_INTERCONNECT_QCOM_SM8150=m
-CONFIG_INTERCONNECT_QCOM_SM8250=m
+CONFIG_INTERCONNECT_QCOM_SM8250=y
 CONFIG_INTERCONNECT_QCOM_SM8350=m
 CONFIG_INTERCONNECT_QCOM_SM8450=y
 CONFIG_INTERCONNECT_QCOM_SM8550=y
@@ -1571,8 +1598,7 @@ CONFIG_RZ_MTU3_CNT=m
 CONFIG_HTE=y
 CONFIG_HTE_TEGRA194=y
 CONFIG_HTE_TEGRA194_TEST=m
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_BTRFS_FS=m
 CONFIG_BTRFS_FS_POSIX_ACL=y
index c47c36f8f67b7c4b4c9e548d5f15f1486bf9c8d2..2d1d2ce7ae2a438ff06074afa67a1452a3d5e5ad 100644 (file)
@@ -14,6 +14,7 @@
 # CONFIG_ARCH_BERLIN is not set
 # CONFIG_ARCH_BRCMSTB is not set
 # CONFIG_ARCH_EXYNOS is not set
+# CONFIG_ARCH_SPARX5 is not set
 # CONFIG_ARCH_K3 is not set
 # CONFIG_ARCH_LAYERSCAPE is not set
 # CONFIG_ARCH_LG1K is not set
 # CONFIG_ARCH_MESON is not set
 # CONFIG_ARCH_MVEBU is not set
 # CONFIG_ARCH_NXP is not set
+# CONFIG_ARCH_MA35 is not set
 # CONFIG_ARCH_MXC is not set
 # CONFIG_ARCH_NPCM is not set
 # CONFIG_ARCH_QCOM is not set
+# CONFIG_ARCH_REALTEK is not set
 # CONFIG_ARCH_RENESAS is not set
 # CONFIG_ARCH_ROCKCHIP is not set
 # CONFIG_ARCH_S32 is not set
 # CONFIG_ARCH_SEATTLE is not set
 # CONFIG_ARCH_INTEL_SOCFPGA is not set
+# CONFIG_ARCH_STM32 is not set
 # CONFIG_ARCH_SYNQUACER is not set
 # CONFIG_ARCH_TEGRA is not set
 # CONFIG_ARCH_TESLA_FSD is not set
index bac4cabef6073e5b0c652d0ed031ea7cce97c72f..467ac2f768ac2bb423b92eb797dce8bde697f259 100644 (file)
@@ -227,8 +227,19 @@ static int ctr_encrypt(struct skcipher_request *req)
                        src += blocks * AES_BLOCK_SIZE;
                }
                if (nbytes && walk.nbytes == walk.total) {
+                       u8 buf[AES_BLOCK_SIZE];
+                       u8 *d = dst;
+
+                       if (unlikely(nbytes < AES_BLOCK_SIZE))
+                               src = dst = memcpy(buf + sizeof(buf) - nbytes,
+                                                  src, nbytes);
+
                        neon_aes_ctr_encrypt(dst, src, ctx->enc, ctx->key.rounds,
                                             nbytes, walk.iv);
+
+                       if (unlikely(nbytes < AES_BLOCK_SIZE))
+                               memcpy(d, dst, nbytes);
+
                        nbytes = 0;
                }
                kernel_neon_end();
index 21c824edf8ce4a6fa1c208b7a882df4b4e31eeb7..bd8d4ca81a48c9c3bfb012b1830eed185b7de679 100644 (file)
@@ -83,7 +83,7 @@ struct arm64_ftr_bits {
  * to full-0 denotes that this field has no override
  *
  * A @mask field set to full-0 with the corresponding @val field set
- * to full-1 denotes thath this field has an invalid override.
+ * to full-1 denotes that this field has an invalid override.
  */
 struct arm64_ftr_override {
        u64             val;
index 7c7493cb571f97bf98b0b4841aeb756d43990718..52f076afeb96006c42dfee6edefcf348048af96b 100644 (file)
@@ -61,6 +61,7 @@
 #define ARM_CPU_IMP_HISI               0x48
 #define ARM_CPU_IMP_APPLE              0x61
 #define ARM_CPU_IMP_AMPERE             0xC0
+#define ARM_CPU_IMP_MICROSOFT          0x6D
 
 #define ARM_CPU_PART_AEM_V8            0xD0F
 #define ARM_CPU_PART_FOUNDATION                0xD00
 
 #define AMPERE_CPU_PART_AMPERE1                0xAC3
 
+#define MICROSOFT_CPU_PART_AZURE_COBALT_100    0xD49 /* Based on r0p0 of ARM Neoverse N2 */
+
 #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
 #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
 #define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72)
 #define MIDR_APPLE_M2_BLIZZARD_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_MAX)
 #define MIDR_APPLE_M2_AVALANCHE_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX)
 #define MIDR_AMPERE1 MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1)
+#define MIDR_MICROSOFT_AZURE_COBALT_100 MIDR_CPU_MODEL(ARM_CPU_IMP_MICROSOFT, MICROSOFT_CPU_PART_AZURE_COBALT_100)
 
 /* Fujitsu Erratum 010001 affects A64FX 1.0 and 1.1, (v0r0 and v1r0) */
 #define MIDR_FUJITSU_ERRATUM_010001            MIDR_FUJITSU_A64FX
index 50e5f25d3024ced8b3c107de352a69e65b6ab7f6..b67b89c54e1c83644cfdd7c63a4807dd24b8d06d 100644 (file)
@@ -62,13 +62,13 @@ static inline void cpacr_restore(unsigned long cpacr)
  * When we defined the maximum SVE vector length we defined the ABI so
  * that the maximum vector length included all the reserved for future
  * expansion bits in ZCR rather than those just currently defined by
- * the architecture. While SME follows a similar pattern the fact that
- * it includes a square matrix means that any allocations that attempt
- * to cover the maximum potential vector length (such as happen with
- * the regset used for ptrace) end up being extremely large. Define
- * the much lower actual limit for use in such situations.
+ * the architecture.  Using this length to allocate worst size buffers
+ * results in excessively large allocations, and this effect is even
+ * more pronounced for SME due to ZA.  Define more suitable VLs for
+ * these situations.
  */
-#define SME_VQ_MAX     16
+#define ARCH_SVE_VQ_MAX ((ZCR_ELx_LEN_MASK >> ZCR_ELx_LEN_SHIFT) + 1)
+#define SME_VQ_MAX     ((SMCR_ELx_LEN_MASK >> SMCR_ELx_LEN_SHIFT) + 1)
 
 struct task_struct;
 
@@ -386,6 +386,7 @@ extern void sme_alloc(struct task_struct *task, bool flush);
 extern unsigned int sme_get_vl(void);
 extern int sme_set_current_vl(unsigned long arg);
 extern int sme_get_current_vl(void);
+extern void sme_suspend_exit(void);
 
 /*
  * Return how many bytes of memory are required to store the full SME
@@ -421,6 +422,7 @@ static inline int sme_max_vl(void) { return 0; }
 static inline int sme_max_virtualisable_vl(void) { return 0; }
 static inline int sme_set_current_vl(unsigned long arg) { return -EINVAL; }
 static inline int sme_get_current_vl(void) { return -EINVAL; }
+static inline void sme_suspend_exit(void) { }
 
 static inline size_t sme_state_size(struct task_struct const *task)
 {
index 2403f7b4cdbfb63d038b5b3a86cc6570061928fc..792e9fe881dcf51128a15b40cddf55ccd2884dd9 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/const.h>
 
 /* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT             CONFIG_ARM64_PAGE_SHIFT
+#define PAGE_SHIFT             CONFIG_PAGE_SHIFT
 #define PAGE_SIZE              (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK              (~(PAGE_SIZE-1))
 
index 967c7c7a4e7db3db7e3d05a7637e8e7d13e0d273..76b8dd37092ad2a9dd6e59a92d1c1fab887589da 100644 (file)
@@ -374,6 +374,7 @@ static const struct midr_range erratum_1463225[] = {
 static const struct midr_range trbe_overwrite_fill_mode_cpus[] = {
 #ifdef CONFIG_ARM64_ERRATUM_2139208
        MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
+       MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100),
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_2119858
        MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
@@ -387,6 +388,7 @@ static const struct midr_range trbe_overwrite_fill_mode_cpus[] = {
 static const struct midr_range tsb_flush_fail_cpus[] = {
 #ifdef CONFIG_ARM64_ERRATUM_2067961
        MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
+       MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100),
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_2054223
        MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
@@ -399,6 +401,7 @@ static const struct midr_range tsb_flush_fail_cpus[] = {
 static struct midr_range trbe_write_out_of_range_cpus[] = {
 #ifdef CONFIG_ARM64_ERRATUM_2253138
        MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
+       MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100),
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_2224489
        MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
index a5dc6f764195847251dc25c196304cbef44d8850..f27acca550d5539d00d958d441ca8631c8dba8d4 100644 (file)
@@ -1311,6 +1311,22 @@ void __init sme_setup(void)
                get_sme_default_vl());
 }
 
+void sme_suspend_exit(void)
+{
+       u64 smcr = 0;
+
+       if (!system_supports_sme())
+               return;
+
+       if (system_supports_fa64())
+               smcr |= SMCR_ELx_FA64;
+       if (system_supports_sme2())
+               smcr |= SMCR_ELx_EZT0;
+
+       write_sysreg_s(smcr, SYS_SMCR_EL1);
+       write_sysreg_s(0, SYS_SMPRI_EL1);
+}
+
 #endif /* CONFIG_ARM64_SME */
 
 static void sve_init_regs(void)
@@ -1635,7 +1651,7 @@ void fpsimd_preserve_current_state(void)
 void fpsimd_signal_preserve_current_state(void)
 {
        fpsimd_preserve_current_state();
-       if (test_thread_flag(TIF_SVE))
+       if (current->thread.fp_type == FP_STATE_SVE)
                sve_to_fpsimd(current);
 }
 
index dc6cf0e37194e428519d7d58524ad0f624f4bebb..e3bef38fc2e2d36b85a9a4069729e276f9368846 100644 (file)
@@ -1500,7 +1500,8 @@ static const struct user_regset aarch64_regsets[] = {
 #ifdef CONFIG_ARM64_SVE
        [REGSET_SVE] = { /* Scalable Vector Extension */
                .core_note_type = NT_ARM_SVE,
-               .n = DIV_ROUND_UP(SVE_PT_SIZE(SVE_VQ_MAX, SVE_PT_REGS_SVE),
+               .n = DIV_ROUND_UP(SVE_PT_SIZE(ARCH_SVE_VQ_MAX,
+                                             SVE_PT_REGS_SVE),
                                  SVE_VQ_BYTES),
                .size = SVE_VQ_BYTES,
                .align = SVE_VQ_BYTES,
index 0e8beb3349ea2a1aae6340f879f78dd568e04f51..425b1bc17a3f6dc3237e81fabcb35d774f1aa9d1 100644 (file)
@@ -242,7 +242,7 @@ static int preserve_sve_context(struct sve_context __user *ctx)
                vl = task_get_sme_vl(current);
                vq = sve_vq_from_vl(vl);
                flags |= SVE_SIG_FLAG_SM;
-       } else if (test_thread_flag(TIF_SVE)) {
+       } else if (current->thread.fp_type == FP_STATE_SVE) {
                vq = sve_vq_from_vl(vl);
        }
 
@@ -878,7 +878,7 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
        if (system_supports_sve() || system_supports_sme()) {
                unsigned int vq = 0;
 
-               if (add_all || test_thread_flag(TIF_SVE) ||
+               if (add_all || current->thread.fp_type == FP_STATE_SVE ||
                    thread_sm_enabled(&current->thread)) {
                        int vl = max(sve_max_vl(), sme_max_vl());
 
index 7f88028a00c02c0e176af5ae7674ae606f5afd3a..b2a60e0bcfd21d28a60db750590732bf1115551d 100644 (file)
@@ -247,7 +247,7 @@ struct kunwind_consume_entry_data {
        void *cookie;
 };
 
-static bool
+static __always_inline bool
 arch_kunwind_consume_entry(const struct kunwind_state *state, void *cookie)
 {
        struct kunwind_consume_entry_data *data = cookie;
index eca4d043521183adc7263da95cf656323a4cc73a..eaaff94329cddb8d1fb8d1523395453f3501c9a5 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/daifflags.h>
 #include <asm/debug-monitors.h>
 #include <asm/exec.h>
+#include <asm/fpsimd.h>
 #include <asm/mte.h>
 #include <asm/memory.h>
 #include <asm/mmu_context.h>
@@ -80,6 +81,8 @@ void notrace __cpu_suspend_exit(void)
         */
        spectre_v4_enable_mitigation(NULL);
 
+       sme_suspend_exit();
+
        /* Restore additional feature-specific configuration */
        ptrauth_suspend_exit();
 }
index 5562daf38a22f59478a935d73dd3375117e7d759..89b6e78400023d0cfb02d8e4ff059e243a7e3f59 100644 (file)
@@ -69,10 +69,7 @@ static struct vdso_abi_info vdso_info[] __ro_after_init = {
 /*
  * The vDSO data page.
  */
-static union {
-       struct vdso_data        data[CS_BASES];
-       u8                      page[PAGE_SIZE];
-} vdso_data_store __page_aligned_data;
+static union vdso_data_store vdso_data_store __page_aligned_data;
 struct vdso_data *vdso_data = vdso_data_store.data;
 
 static int vdso_mremap(const struct vm_special_mapping *sm,
index 6c3c8ca73e7fda8bb29792218bb11d031e7527ff..27ca89b628a02499d18505953ad1cee73ccf7f88 100644 (file)
@@ -3,7 +3,6 @@
 # KVM configuration
 #
 
-source "virt/lib/Kconfig"
 source "virt/kvm/Kconfig"
 
 menuconfig VIRTUALIZATION
index c651df904fe3eb940e07785aac1ac76079743666..ab9d05fcf98b23b992343d6a11a1daf9de806b3a 100644 (file)
@@ -1419,7 +1419,6 @@ kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt,
                                 level + 1);
        if (ret) {
                kvm_pgtable_stage2_free_unlinked(mm_ops, pgtable, level);
-               mm_ops->put_page(pgtable);
                return ERR_PTR(ret);
        }
 
@@ -1502,7 +1501,6 @@ static int stage2_split_walker(const struct kvm_pgtable_visit_ctx *ctx,
 
        if (!stage2_try_break_pte(ctx, mmu)) {
                kvm_pgtable_stage2_free_unlinked(mm_ops, childp, level);
-               mm_ops->put_page(childp);
                return -EAGAIN;
        }
 
index 8350fb8fee0b998ccf27dca4b7bf2e858846ccd3..b7be96a5359737d41576af46eee1f68852632846 100644 (file)
@@ -101,6 +101,17 @@ void __init kvm_hyp_reserve(void)
                 hyp_mem_base);
 }
 
+static void __pkvm_destroy_hyp_vm(struct kvm *host_kvm)
+{
+       if (host_kvm->arch.pkvm.handle) {
+               WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm,
+                                         host_kvm->arch.pkvm.handle));
+       }
+
+       host_kvm->arch.pkvm.handle = 0;
+       free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc);
+}
+
 /*
  * Allocates and donates memory for hypervisor VM structs at EL2.
  *
@@ -181,7 +192,7 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm)
        return 0;
 
 destroy_vm:
-       pkvm_destroy_hyp_vm(host_kvm);
+       __pkvm_destroy_hyp_vm(host_kvm);
        return ret;
 free_vm:
        free_pages_exact(hyp_vm, hyp_vm_sz);
@@ -194,23 +205,19 @@ int pkvm_create_hyp_vm(struct kvm *host_kvm)
 {
        int ret = 0;
 
-       mutex_lock(&host_kvm->lock);
+       mutex_lock(&host_kvm->arch.config_lock);
        if (!host_kvm->arch.pkvm.handle)
                ret = __pkvm_create_hyp_vm(host_kvm);
-       mutex_unlock(&host_kvm->lock);
+       mutex_unlock(&host_kvm->arch.config_lock);
 
        return ret;
 }
 
 void pkvm_destroy_hyp_vm(struct kvm *host_kvm)
 {
-       if (host_kvm->arch.pkvm.handle) {
-               WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm,
-                                         host_kvm->arch.pkvm.handle));
-       }
-
-       host_kvm->arch.pkvm.handle = 0;
-       free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc);
+       mutex_lock(&host_kvm->arch.config_lock);
+       __pkvm_destroy_hyp_vm(host_kvm);
+       mutex_unlock(&host_kvm->arch.config_lock);
 }
 
 int pkvm_init_host_vm(struct kvm *host_kvm)
index e2764d0ffa9f32094c57580ed5d987f99b5d2ade..28a93074eca17dbb10c7c75e23baf72edf126391 100644 (file)
@@ -468,6 +468,9 @@ static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
                }
 
                irq = vgic_get_irq(vcpu->kvm, NULL, intids[i]);
+               if (!irq)
+                       continue;
+
                raw_spin_lock_irqsave(&irq->irq_lock, flags);
                irq->pending_latch = pendmask & (1U << bit_nr);
                vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
@@ -1432,6 +1435,8 @@ static int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its,
 
        for (i = 0; i < irq_count; i++) {
                irq = vgic_get_irq(kvm, NULL, intids[i]);
+               if (!irq)
+                       continue;
 
                update_affinity(irq, vcpu2);
 
index cf2a6fd7dff8715529a7365867c1819f01bf7dbf..9c2723ab1c9415e9bab37e3b81b54b0a8936c76b 100644 (file)
@@ -89,6 +89,7 @@ config CSKY
        select HAVE_KPROBES if !CPU_CK610
        select HAVE_KPROBES_ON_FTRACE if !CPU_CK610
        select HAVE_KRETPROBES if !CPU_CK610
+       select HAVE_PAGE_SIZE_4KB
        select HAVE_PERF_EVENTS
        select HAVE_PERF_REGS
        select HAVE_PERF_USER_STACK_DUMP
index 4a0502e324a60a3e25a50d7dcccbdca754beb2c7..0ca6c408c07f27ee76398a9dc0ae502813e17408 100644 (file)
@@ -10,7 +10,7 @@
 /*
  * PAGE_SHIFT determines the page size: 4KB
  */
-#define PAGE_SHIFT     12
+#define PAGE_SHIFT     CONFIG_PAGE_SHIFT
 #define PAGE_SIZE      (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE - 1))
 #define THREAD_SIZE    (PAGE_SIZE * 2)
@@ -82,11 +82,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
        return __pa(kaddr) >> PAGE_SHIFT;
 }
 
-static inline void * pfn_to_virt(unsigned long pfn)
-{
-       return (void *)((unsigned long)__va(pfn) << PAGE_SHIFT);
-}
-
 #define MAP_NR(x)      PFN_DOWN((unsigned long)(x) - PAGE_OFFSET - \
                                 PHYS_OFFSET_OFFSET)
 #define virt_to_page(x)        (mem_map + MAP_NR(x))
index bdce581b5fcb8113129221acab65436dfbf8de9a..181a15edafe87ef54cc7380bfac9e66d1484a815 100644 (file)
@@ -5,11 +5,6 @@
 
 #include <linux/types.h>
 
-#ifndef GENERIC_TIME_VSYSCALL
-struct vdso_data {
-};
-#endif
-
 /*
  * The VDSO symbols are mapped into Linux so we can just use regular symbol
  * addressing to get their offsets in userspace.  The symbols are mapped at an
index 8e42352cbf123f4bc771dfefda013bf12d818cfa..92dbbf3e0205b61bb9b89697750e501a22747390 100644 (file)
@@ -152,10 +152,6 @@ void arch_irq_work_raise(void)
 }
 #endif
 
-void __init smp_prepare_boot_cpu(void)
-{
-}
-
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
 }
index 16c20d64d16532b1d1498a007193c7916a6bb15a..2ca886e4a458b36e38014a8ca7b30dd0cc55a6e3 100644 (file)
@@ -8,25 +8,15 @@
 #include <linux/slab.h>
 
 #include <asm/page.h>
-#ifdef GENERIC_TIME_VSYSCALL
 #include <vdso/datapage.h>
-#else
-#include <asm/vdso.h>
-#endif
 
 extern char vdso_start[], vdso_end[];
 
 static unsigned int vdso_pages;
 static struct page **vdso_pagelist;
 
-/*
- * The vDSO data page.
- */
-static union {
-       struct vdso_data        data;
-       u8                      page[PAGE_SIZE];
-} vdso_data_store __page_aligned_data;
-struct vdso_data *vdso_data = &vdso_data_store.data;
+static union vdso_data_store vdso_data_store __page_aligned_data;
+struct vdso_data *vdso_data = vdso_data_store.data;
 
 static int __init vdso_init(void)
 {
index a880ee067d2ec20c10b7c3c5827b34b7aa8a62a0..1414052e7d6b2ad5c22975d1cb5b002f558ebc1e 100644 (file)
@@ -8,6 +8,10 @@ config HEXAGON
        select ARCH_HAS_SYNC_DMA_FOR_DEVICE
        select ARCH_NO_PREEMPT
        select DMA_GLOBAL_POOL
+       select HAVE_PAGE_SIZE_4KB
+       select HAVE_PAGE_SIZE_16KB
+       select HAVE_PAGE_SIZE_64KB
+       select HAVE_PAGE_SIZE_256KB
        # Other pending projects/to-do items.
        # select HAVE_REGS_AND_STACK_ACCESS_API
        # select HAVE_HW_BREAKPOINT if PERF_EVENTS
@@ -120,26 +124,6 @@ config NR_CPUS
          This is purely to save memory - each supported CPU adds
          approximately eight kilobytes to the kernel image.
 
-choice
-       prompt "Kernel page size"
-       default PAGE_SIZE_4KB
-       help
-         Changes the default page size; use with caution.
-
-config PAGE_SIZE_4KB
-       bool "4KB"
-
-config PAGE_SIZE_16KB
-       bool "16KB"
-
-config PAGE_SIZE_64KB
-       bool "64KB"
-
-config PAGE_SIZE_256KB
-       bool "256KB"
-
-endchoice
-
 source "kernel/Kconfig.hz"
 
 endmenu
index 10f1bc07423ccfdd3e57504a972133b8c3482e45..8a6af57274c2dbc271da1105afa7bf7b5c00f8e3 100644 (file)
 /*  This is probably not the most graceful way to handle this.  */
 
 #ifdef CONFIG_PAGE_SIZE_4KB
-#define PAGE_SHIFT 12
 #define HEXAGON_L1_PTE_SIZE __HVM_PDE_S_4KB
 #endif
 
 #ifdef CONFIG_PAGE_SIZE_16KB
-#define PAGE_SHIFT 14
 #define HEXAGON_L1_PTE_SIZE __HVM_PDE_S_16KB
 #endif
 
 #ifdef CONFIG_PAGE_SIZE_64KB
-#define PAGE_SHIFT 16
 #define HEXAGON_L1_PTE_SIZE __HVM_PDE_S_64KB
 #endif
 
 #ifdef CONFIG_PAGE_SIZE_256KB
-#define PAGE_SHIFT 18
 #define HEXAGON_L1_PTE_SIZE __HVM_PDE_S_256KB
 #endif
 
 #ifdef CONFIG_PAGE_SIZE_1MB
-#define PAGE_SHIFT 20
 #define HEXAGON_L1_PTE_SIZE __HVM_PDE_S_1MB
 #endif
 
@@ -50,6 +45,7 @@
 #define HVM_HUGEPAGE_SIZE 0x5
 #endif
 
+#define PAGE_SHIFT CONFIG_PAGE_SHIFT
 #define PAGE_SIZE  (1UL << PAGE_SHIFT)
 #define PAGE_MASK  (~((1 << PAGE_SHIFT) - 1))
 
@@ -133,12 +129,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
        return __pa(kaddr) >> PAGE_SHIFT;
 }
 
-static inline void *pfn_to_virt(unsigned long pfn)
-{
-       return (void *)((unsigned long)__va(pfn) << PAGE_SHIFT);
-}
-
-
 #define page_to_virt(page)     __va(page_to_phys(page))
 
 #include <asm/mem-layout.h>
index 608884bc3396763eefcc4dc44896322a89da6763..65e1fdf9fdb21d730c36675d0ffdac287db8252f 100644 (file)
@@ -114,10 +114,6 @@ void send_ipi(const struct cpumask *cpumask, enum ipi_message_type msg)
        local_irq_restore(flags);
 }
 
-void __init smp_prepare_boot_cpu(void)
-{
-}
-
 /*
  * interrupts should already be disabled from the VM
  * SP should already be correct; need to set THREADINFO_REG
index 929f68926b3432e52a6d7b84a92d402a5d8bc11a..b274784c2e261a0e51369de70e7874b81b87a536 100644 (file)
@@ -227,15 +227,6 @@ config MACH_LOONGSON64
 config FIX_EARLYCON_MEM
        def_bool y
 
-config PAGE_SIZE_4KB
-       bool
-
-config PAGE_SIZE_16KB
-       bool
-
-config PAGE_SIZE_64KB
-       bool
-
 config PGTABLE_2LEVEL
        bool
 
@@ -288,7 +279,7 @@ choice
 
 config 4KB_3LEVEL
        bool "4KB with 3 levels"
-       select PAGE_SIZE_4KB
+       select HAVE_PAGE_SIZE_4KB
        select PGTABLE_3LEVEL
        help
          This option selects 4KB page size with 3 level page tables, which
@@ -296,7 +287,7 @@ config 4KB_3LEVEL
 
 config 4KB_4LEVEL
        bool "4KB with 4 levels"
-       select PAGE_SIZE_4KB
+       select HAVE_PAGE_SIZE_4KB
        select PGTABLE_4LEVEL
        help
          This option selects 4KB page size with 4 level page tables, which
@@ -304,7 +295,7 @@ config 4KB_4LEVEL
 
 config 16KB_2LEVEL
        bool "16KB with 2 levels"
-       select PAGE_SIZE_16KB
+       select HAVE_PAGE_SIZE_16KB
        select PGTABLE_2LEVEL
        help
          This option selects 16KB page size with 2 level page tables, which
@@ -312,7 +303,7 @@ config 16KB_2LEVEL
 
 config 16KB_3LEVEL
        bool "16KB with 3 levels"
-       select PAGE_SIZE_16KB
+       select HAVE_PAGE_SIZE_16KB
        select PGTABLE_3LEVEL
        help
          This option selects 16KB page size with 3 level page tables, which
@@ -320,7 +311,7 @@ config 16KB_3LEVEL
 
 config 64KB_2LEVEL
        bool "64KB with 2 levels"
-       select PAGE_SIZE_64KB
+       select HAVE_PAGE_SIZE_64KB
        select PGTABLE_2LEVEL
        help
          This option selects 64KB page size with 2 level page tables, which
@@ -328,7 +319,7 @@ config 64KB_2LEVEL
 
 config 64KB_3LEVEL
        bool "64KB with 3 levels"
-       select PAGE_SIZE_64KB
+       select HAVE_PAGE_SIZE_64KB
        select PGTABLE_3LEVEL
        help
          This option selects 64KB page size with 3 level page tables, which
index b38071a4d0b023c7faf29935d3bb6d5e0c65ca76..8aefb0c126722980a345062cae02a6127c02b52e 100644 (file)
@@ -60,7 +60,7 @@
 
        #address-cells = <1>;
        #size-cells = <0>;
-       eeprom@57{
+       eeprom@57 {
                compatible = "atmel,24c16";
                reg = <0x57>;
                pagesize = <16>;
index 132a2d1ea8bce1ac95222875b6ad74d5ebf06b14..ed4d324340411dee9b88e52720329cf839307ad0 100644 (file)
@@ -78,7 +78,7 @@
 
        #address-cells = <1>;
        #size-cells = <0>;
-       eeprom@57{
+       eeprom@57 {
                compatible = "atmel,24c16";
                reg = <0x57>;
                pagesize = <16>;
index 63f137ce82a41fc4e251f2adceef441e72dcd691..afb6fa16b82636caed29820a118a895f7446ad72 100644 (file)
 /*
  * PAGE_SHIFT determines the page size
  */
-#ifdef CONFIG_PAGE_SIZE_4KB
-#define PAGE_SHIFT     12
-#endif
-#ifdef CONFIG_PAGE_SIZE_16KB
-#define PAGE_SHIFT     14
-#endif
-#ifdef CONFIG_PAGE_SIZE_64KB
-#define PAGE_SHIFT     16
-#endif
+#define PAGE_SHIFT     CONFIG_PAGE_SHIFT
 #define PAGE_SIZE      (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE - 1))
 
index edf2bba80130670364e144ad301868a7dfd3bf93..634ef17fd38bf10d8bd9deef8a6693f0f4777c1e 100644 (file)
@@ -357,6 +357,8 @@ void __init platform_init(void)
        acpi_gbl_use_default_register_widths = false;
        acpi_boot_table_init();
 #endif
+
+       early_init_fdt_scan_reserved_mem();
        unflatten_and_copy_device_tree();
 
 #ifdef CONFIG_NUMA
@@ -390,8 +392,6 @@ static void __init arch_mem_init(char **cmdline_p)
 
        check_kernel_sections_mem();
 
-       early_init_fdt_scan_reserved_mem();
-
        /*
         * In order to reduce the possibility of kernel panic when failed to
         * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
index 2b49d30eb7c0185e043e462859e76a4ae64ecd67..aabee0b280fe5f43a70d8a1091e6268a37d701e9 100644 (file)
@@ -88,6 +88,73 @@ void show_ipi_list(struct seq_file *p, int prec)
        }
 }
 
+static inline void set_cpu_core_map(int cpu)
+{
+       int i;
+
+       cpumask_set_cpu(cpu, &cpu_core_setup_map);
+
+       for_each_cpu(i, &cpu_core_setup_map) {
+               if (cpu_data[cpu].package == cpu_data[i].package) {
+                       cpumask_set_cpu(i, &cpu_core_map[cpu]);
+                       cpumask_set_cpu(cpu, &cpu_core_map[i]);
+               }
+       }
+}
+
+static inline void set_cpu_sibling_map(int cpu)
+{
+       int i;
+
+       cpumask_set_cpu(cpu, &cpu_sibling_setup_map);
+
+       for_each_cpu(i, &cpu_sibling_setup_map) {
+               if (cpus_are_siblings(cpu, i)) {
+                       cpumask_set_cpu(i, &cpu_sibling_map[cpu]);
+                       cpumask_set_cpu(cpu, &cpu_sibling_map[i]);
+               }
+       }
+}
+
+static inline void clear_cpu_sibling_map(int cpu)
+{
+       int i;
+
+       for_each_cpu(i, &cpu_sibling_setup_map) {
+               if (cpus_are_siblings(cpu, i)) {
+                       cpumask_clear_cpu(i, &cpu_sibling_map[cpu]);
+                       cpumask_clear_cpu(cpu, &cpu_sibling_map[i]);
+               }
+       }
+
+       cpumask_clear_cpu(cpu, &cpu_sibling_setup_map);
+}
+
+/*
+ * Calculate a new cpu_foreign_map mask whenever a
+ * new cpu appears or disappears.
+ */
+void calculate_cpu_foreign_map(void)
+{
+       int i, k, core_present;
+       cpumask_t temp_foreign_map;
+
+       /* Re-calculate the mask */
+       cpumask_clear(&temp_foreign_map);
+       for_each_online_cpu(i) {
+               core_present = 0;
+               for_each_cpu(k, &temp_foreign_map)
+                       if (cpus_are_siblings(i, k))
+                               core_present = 1;
+               if (!core_present)
+                       cpumask_set_cpu(i, &temp_foreign_map);
+       }
+
+       for_each_online_cpu(i)
+               cpumask_andnot(&cpu_foreign_map[i],
+                              &temp_foreign_map, &cpu_sibling_map[i]);
+}
+
 /* Send mailbox buffer via Mail_Send */
 static void csr_mail_send(uint64_t data, int cpu, int mailbox)
 {
@@ -303,6 +370,7 @@ int loongson_cpu_disable(void)
        numa_remove_cpu(cpu);
 #endif
        set_cpu_online(cpu, false);
+       clear_cpu_sibling_map(cpu);
        calculate_cpu_foreign_map();
        local_irq_save(flags);
        irq_migrate_all_off_this_cpu();
@@ -337,6 +405,7 @@ void __noreturn arch_cpu_idle_dead(void)
                addr = iocsr_read64(LOONGARCH_IOCSR_MBUF0);
        } while (addr == 0);
 
+       local_irq_disable();
        init_fn = (void *)TO_CACHE(addr);
        iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_CLEAR);
 
@@ -379,59 +448,6 @@ static int __init ipi_pm_init(void)
 core_initcall(ipi_pm_init);
 #endif
 
-static inline void set_cpu_sibling_map(int cpu)
-{
-       int i;
-
-       cpumask_set_cpu(cpu, &cpu_sibling_setup_map);
-
-       for_each_cpu(i, &cpu_sibling_setup_map) {
-               if (cpus_are_siblings(cpu, i)) {
-                       cpumask_set_cpu(i, &cpu_sibling_map[cpu]);
-                       cpumask_set_cpu(cpu, &cpu_sibling_map[i]);
-               }
-       }
-}
-
-static inline void set_cpu_core_map(int cpu)
-{
-       int i;
-
-       cpumask_set_cpu(cpu, &cpu_core_setup_map);
-
-       for_each_cpu(i, &cpu_core_setup_map) {
-               if (cpu_data[cpu].package == cpu_data[i].package) {
-                       cpumask_set_cpu(i, &cpu_core_map[cpu]);
-                       cpumask_set_cpu(cpu, &cpu_core_map[i]);
-               }
-       }
-}
-
-/*
- * Calculate a new cpu_foreign_map mask whenever a
- * new cpu appears or disappears.
- */
-void calculate_cpu_foreign_map(void)
-{
-       int i, k, core_present;
-       cpumask_t temp_foreign_map;
-
-       /* Re-calculate the mask */
-       cpumask_clear(&temp_foreign_map);
-       for_each_online_cpu(i) {
-               core_present = 0;
-               for_each_cpu(k, &temp_foreign_map)
-                       if (cpus_are_siblings(i, k))
-                               core_present = 1;
-               if (!core_present)
-                       cpumask_set_cpu(i, &temp_foreign_map);
-       }
-
-       for_each_online_cpu(i)
-               cpumask_andnot(&cpu_foreign_map[i],
-                              &temp_foreign_map, &cpu_sibling_map[i]);
-}
-
 /* Preload SMP state for boot cpu */
 void smp_prepare_boot_cpu(void)
 {
index 14941e4be66d8273adaebb7de388e8782e07a892..90dfccb41c14a0036f03e97ee886612a3c7cee97 100644 (file)
 #include <asm/vdso.h>
 #include <vdso/helpers.h>
 #include <vdso/vsyscall.h>
+#include <vdso/datapage.h>
 #include <generated/vdso-offsets.h>
 
 extern char vdso_start[], vdso_end[];
 
 /* Kernel-provided data used by the VDSO. */
-static union {
-       u8 page[PAGE_SIZE];
-       struct vdso_data data[CS_BASES];
-} generic_vdso_data __page_aligned_data;
+static union vdso_data_store generic_vdso_data __page_aligned_data;
 
 static union {
        u8 page[LOONGARCH_VDSO_DATA_SIZE];
index 27701991886dda7e3a6f75bd8a7f71a86995735b..36106922b5d75b7f7de70df5df0d72a697440f0f 100644 (file)
@@ -298,74 +298,73 @@ static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val)
        return ret;
 }
 
-static int _kvm_get_cpucfg(int id, u64 *v)
+static int _kvm_get_cpucfg_mask(int id, u64 *v)
 {
-       int ret = 0;
-
-       if (id < 0 && id >= KVM_MAX_CPUCFG_REGS)
+       if (id < 0 || id >= KVM_MAX_CPUCFG_REGS)
                return -EINVAL;
 
        switch (id) {
        case 2:
-               /* Return CPUCFG2 features which have been supported by KVM */
+               /* CPUCFG2 features unconditionally supported by KVM */
                *v = CPUCFG2_FP     | CPUCFG2_FPSP  | CPUCFG2_FPDP     |
                     CPUCFG2_FPVERS | CPUCFG2_LLFTP | CPUCFG2_LLFTPREV |
                     CPUCFG2_LAM;
                /*
-                * If LSX is supported by CPU, it is also supported by KVM,
-                * as we implement it.
+                * For the ISA extensions listed below, if one is supported
+                * by the host, then it is also supported by KVM.
                 */
                if (cpu_has_lsx)
                        *v |= CPUCFG2_LSX;
-               /*
-                * if LASX is supported by CPU, it is also supported by KVM,
-                * as we implement it.
-                */
                if (cpu_has_lasx)
                        *v |= CPUCFG2_LASX;
 
-               break;
+               return 0;
        default:
-               ret = -EINVAL;
-               break;
+               /*
+                * No restrictions on other valid CPUCFG IDs' values, but
+                * CPUCFG data is limited to 32 bits as the LoongArch ISA
+                * manual says (Volume 1, Section 2.2.10.5 "CPUCFG").
+                */
+               *v = U32_MAX;
+               return 0;
        }
-       return ret;
 }
 
 static int kvm_check_cpucfg(int id, u64 val)
 {
-       u64 mask;
-       int ret = 0;
-
-       if (id < 0 && id >= KVM_MAX_CPUCFG_REGS)
-               return -EINVAL;
+       int ret;
+       u64 mask = 0;
 
-       if (_kvm_get_cpucfg(id, &mask))
+       ret = _kvm_get_cpucfg_mask(id, &mask);
+       if (ret)
                return ret;
 
+       if (val & ~mask)
+               /* Unsupported features and/or the higher 32 bits should not be set */
+               return -EINVAL;
+
        switch (id) {
        case 2:
-               /* CPUCFG2 features checking */
-               if (val & ~mask)
-                       /* The unsupported features should not be set */
-                       ret = -EINVAL;
-               else if (!(val & CPUCFG2_LLFTP))
-                       /* The LLFTP must be set, as guest must has a constant timer */
-                       ret = -EINVAL;
-               else if ((val & CPUCFG2_FP) && (!(val & CPUCFG2_FPSP) || !(val & CPUCFG2_FPDP)))
-                       /* Single and double float point must both be set when enable FP */
-                       ret = -EINVAL;
-               else if ((val & CPUCFG2_LSX) && !(val & CPUCFG2_FP))
-                       /* FP should be set when enable LSX */
-                       ret = -EINVAL;
-               else if ((val & CPUCFG2_LASX) && !(val & CPUCFG2_LSX))
-                       /* LSX, FP should be set when enable LASX, and FP has been checked before. */
-                       ret = -EINVAL;
-               break;
+               if (!(val & CPUCFG2_LLFTP))
+                       /* Guests must have a constant timer */
+                       return -EINVAL;
+               if ((val & CPUCFG2_FP) && (!(val & CPUCFG2_FPSP) || !(val & CPUCFG2_FPDP)))
+                       /* Single and double float point must both be set when FP is enabled */
+                       return -EINVAL;
+               if ((val & CPUCFG2_LSX) && !(val & CPUCFG2_FP))
+                       /* LSX architecturally implies FP but val does not satisfy that */
+                       return -EINVAL;
+               if ((val & CPUCFG2_LASX) && !(val & CPUCFG2_LSX))
+                       /* LASX architecturally implies LSX and FP but val does not satisfy that */
+                       return -EINVAL;
+               return 0;
        default:
-               break;
+               /*
+                * Values for the other CPUCFG IDs are not being further validated
+                * besides the mask check above.
+                */
+               return 0;
        }
-       return ret;
 }
 
 static int kvm_get_one_reg(struct kvm_vcpu *vcpu,
@@ -566,7 +565,7 @@ static int kvm_loongarch_get_cpucfg_attr(struct kvm_vcpu *vcpu,
        uint64_t val;
        uint64_t __user *uaddr = (uint64_t __user *)attr->addr;
 
-       ret = _kvm_get_cpucfg(attr->attr, &val);
+       ret = _kvm_get_cpucfg_mask(attr->attr, &val);
        if (ret)
                return ret;
 
index 4b3e93cac72320307fa5c1bcc8127fe30204e419..7b709453d5e7eb054a897fcfabc4e80a1d594600 100644 (file)
@@ -84,12 +84,15 @@ config MMU
 
 config MMU_MOTOROLA
        bool
+       select HAVE_PAGE_SIZE_4KB
 
 config MMU_COLDFIRE
+       select HAVE_PAGE_SIZE_8KB
        bool
 
 config MMU_SUN3
        bool
+       select HAVE_PAGE_SIZE_8KB
        depends on MMU && !MMU_MOTOROLA && !MMU_COLDFIRE
 
 config ARCH_SUPPORTS_KEXEC
index 9dcf245c9cbfabd9ea028f2d4b5d6b939cdd36d9..c777a129768a0980939e6442aabd873be7b6ca0e 100644 (file)
@@ -30,6 +30,7 @@ config COLDFIRE
        select GENERIC_CSUM
        select GPIOLIB
        select HAVE_LEGACY_CLK
+       select HAVE_PAGE_SIZE_8KB if !MMU
 
 endchoice
 
@@ -45,6 +46,7 @@ config M68000
        select GENERIC_CSUM
        select CPU_NO_EFFICIENT_FFS
        select HAVE_ARCH_HASH
+       select HAVE_PAGE_SIZE_4KB
        select LEGACY_TIMER_TICK
        help
          The Freescale (was Motorola) 68000 CPU is the first generation of
index 76ef1a67c3611bbcd864d27fe59127c4c27f038a..0abcf994ce5503e3e713f0ee2f1d563f978786a4 100644 (file)
 KBUILD_DEFCONFIG := multi_defconfig
 
 ifdef cross_compiling
-        ifeq ($(CROSS_COMPILE),)
+    ifeq ($(CROSS_COMPILE),)
                CROSS_COMPILE := $(call cc-cross-prefix, \
                        m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-)
-        endif
+    endif
 endif
 
 #
index b4d71fea558f1f0f5010fb0d6c077a98e3a4b3dc..a6f6607efe79cd203f2b21dbf873c435400cadb9 100644 (file)
@@ -336,7 +336,6 @@ CONFIG_ATA=y
 CONFIG_PATA_GAYLE=y
 CONFIG_PATA_BUDDHA=y
 CONFIG_MD=y
-CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_UNSTRIPED=m
 CONFIG_DM_CRYPT=m
@@ -579,12 +578,10 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_AEGIS128=m
index 682d8cd3dd3cea941175ca75fa9bc84d19eb6460..0ca1f9f930bc1fd321054243bc68362b644f8fb5 100644 (file)
@@ -316,7 +316,6 @@ CONFIG_SCSI_SAS_ATTRS=m
 CONFIG_ISCSI_TCP=m
 CONFIG_ISCSI_BOOT_SYSFS=m
 CONFIG_MD=y
-CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_UNSTRIPED=m
 CONFIG_DM_CRYPT=m
@@ -536,12 +535,10 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_AEGIS128=m
index 15259ced84632b142fcce2570ad369d0e0374873..be030659d8d76ca0921d38d104ac03489d7dddde 100644 (file)
@@ -331,7 +331,6 @@ CONFIG_ATA=y
 # CONFIG_ATA_BMDMA is not set
 CONFIG_PATA_FALCON=y
 CONFIG_MD=y
-CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_UNSTRIPED=m
 CONFIG_DM_CRYPT=m
@@ -556,12 +555,10 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_AEGIS128=m
index 7395c12caef6e84a58c29c920f83911cb46f1afa..ad8f81fbb630c2bc54d59d623eb8b627e6761a12 100644 (file)
@@ -314,7 +314,6 @@ CONFIG_ISCSI_TCP=m
 CONFIG_ISCSI_BOOT_SYSFS=m
 CONFIG_BVME6000_SCSI=y
 CONFIG_MD=y
-CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_UNSTRIPED=m
 CONFIG_DM_CRYPT=m
@@ -528,12 +527,10 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_AEGIS128=m
index 92506bc7f78daef12c3ed7c9c483fc73e709fdd2..ff253b6accecbd3b9bf8f90e932386a5f88a70e5 100644 (file)
@@ -315,7 +315,6 @@ CONFIG_SCSI_SAS_ATTRS=m
 CONFIG_ISCSI_TCP=m
 CONFIG_ISCSI_BOOT_SYSFS=m
 CONFIG_MD=y
-CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_UNSTRIPED=m
 CONFIG_DM_CRYPT=m
@@ -538,12 +537,10 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_AEGIS128=m
index 144bc8c0d8b590b3b09e4b8f4404b2036e218823..f92b866620a7de86e0d65b22c55c184a596d2116 100644 (file)
@@ -320,7 +320,6 @@ CONFIG_ATA=y
 # CONFIG_ATA_BMDMA is not set
 CONFIG_PATA_PLATFORM=y
 CONFIG_MD=y
-CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_UNSTRIPED=m
 CONFIG_DM_CRYPT=m
@@ -555,12 +554,10 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_AEGIS128=m
index 07594c72949773f604c2ce650ce97762ae2e1088..bd813beaa8a725530f1ff3334d587fa3facb6ab4 100644 (file)
@@ -363,7 +363,6 @@ CONFIG_PATA_GAYLE=y
 CONFIG_PATA_BUDDHA=y
 CONFIG_PATA_PLATFORM=y
 CONFIG_MD=y
-CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_UNSTRIPED=m
 CONFIG_DM_CRYPT=m
@@ -641,12 +640,10 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_AEGIS128=m
index c34de6c1de203f1615d8c85cd957b111dda64a68..2237ee0fe4337607c32545a830b4e1ceff0f4a86 100644 (file)
@@ -313,7 +313,6 @@ CONFIG_ISCSI_TCP=m
 CONFIG_ISCSI_BOOT_SYSFS=m
 CONFIG_MVME147_SCSI=y
 CONFIG_MD=y
-CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_UNSTRIPED=m
 CONFIG_DM_CRYPT=m
@@ -527,12 +526,10 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_AEGIS128=m
index 83bc029d1f335338b952a1875ac7a4f084f31101..afb5aa9c5012c4d137fda8acaa604916b4a14bb4 100644 (file)
@@ -314,7 +314,6 @@ CONFIG_ISCSI_TCP=m
 CONFIG_ISCSI_BOOT_SYSFS=m
 CONFIG_MVME16x_SCSI=y
 CONFIG_MD=y
-CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_UNSTRIPED=m
 CONFIG_DM_CRYPT=m
@@ -528,12 +527,10 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_AEGIS128=m
index 4f551dac2ed72e360544cf10b89209b8a5e36227..e40f7a308966e8f1ee28727ac7658b68d02db9f9 100644 (file)
@@ -320,7 +320,6 @@ CONFIG_ATA=y
 # CONFIG_ATA_BMDMA is not set
 CONFIG_PATA_FALCON=y
 CONFIG_MD=y
-CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_UNSTRIPED=m
 CONFIG_DM_CRYPT=m
@@ -545,12 +544,10 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_AEGIS128=m
index b1bf01182bd32fa2aa47732c3c045a10b1fc85fb..4df397c0395f4240a3dde0bd6c948b7f4e538b18 100644 (file)
@@ -310,7 +310,6 @@ CONFIG_ISCSI_TCP=m
 CONFIG_ISCSI_BOOT_SYSFS=m
 CONFIG_SUN3_SCSI=y
 CONFIG_MD=y
-CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_UNSTRIPED=m
 CONFIG_DM_CRYPT=m
@@ -526,12 +525,10 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_AEGIS128=m
index 5c9a3f71f036e36144f9ee7dc620d8c18bd2cc3e..aa7719b3947fb17bf7c670b4f2a5e89136da2eed 100644 (file)
@@ -311,7 +311,6 @@ CONFIG_ISCSI_TCP=m
 CONFIG_ISCSI_BOOT_SYSFS=m
 CONFIG_SUN3X_ESP=y
 CONFIG_MD=y
-CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_UNSTRIPED=m
 CONFIG_DM_CRYPT=m
@@ -526,12 +525,10 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_CTS=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
 CONFIG_CRYPTO_AEGIS128=m
index a708fbd5a844f8a2c6a60cea6eb2e5a126e8dbdb..642fb80c5c4e31f6c595e1663a19d7760c68e1e1 100644 (file)
@@ -96,6 +96,9 @@ static const struct block_device_operations nfhd_ops = {
 
 static int __init nfhd_init_one(int id, u32 blocks, u32 bsize)
 {
+       struct queue_limits lim = {
+               .logical_block_size     = bsize,
+       };
        struct nfhd_device *dev;
        int dev_id = id - NFHD_DEV_OFFSET;
        int err = -ENOMEM;
@@ -117,9 +120,11 @@ static int __init nfhd_init_one(int id, u32 blocks, u32 bsize)
        dev->bsize = bsize;
        dev->bshift = ffs(bsize) - 10;
 
-       dev->disk = blk_alloc_disk(NUMA_NO_NODE);
-       if (!dev->disk)
+       dev->disk = blk_alloc_disk(&lim, NUMA_NO_NODE);
+       if (IS_ERR(dev->disk)) {
+               err = PTR_ERR(dev->disk);
                goto free_dev;
+       }
 
        dev->disk->major = major_num;
        dev->disk->first_minor = dev_id * 16;
@@ -128,7 +133,6 @@ static int __init nfhd_init_one(int id, u32 blocks, u32 bsize)
        dev->disk->private_data = dev;
        sprintf(dev->disk->disk_name, "nfhd%u", dev_id);
        set_capacity(dev->disk, (sector_t)blocks * (bsize / 512));
-       blk_queue_logical_block_size(dev->disk->queue, bsize);
        err = add_disk(dev->disk);
        if (err)
                goto out_cleanup_disk;
index a5993ad83ed8a577013a053cc3ae82474ae11759..8cfb84b49975146162da5a62d93a4781d1479099 100644 (file)
@@ -7,11 +7,7 @@
 #include <asm/page_offset.h>
 
 /* PAGE_SHIFT determines the page size */
-#if defined(CONFIG_SUN3) || defined(CONFIG_COLDFIRE)
-#define PAGE_SHIFT     13
-#else
-#define PAGE_SHIFT     12
-#endif
+#define PAGE_SHIFT     CONFIG_PAGE_SHIFT
 #define PAGE_SIZE      (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 #define PAGE_OFFSET    (PAGE_OFFSET_RAW)
index 211f338d6235d00dfa3592fec1ff21acd8b510c1..f18ec02ddeb2335150ee5b0ae9adb4342806aa3b 100644 (file)
@@ -31,6 +31,7 @@ config MICROBLAZE
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_TRACER
+       select HAVE_PAGE_SIZE_4KB
        select HAVE_PCI
        select IRQ_DOMAIN
        select XILINX_INTC
index 86a4ce07c192b11feddce52000e81847a8097c7b..8810f4f1c3b02d347592a320a50c14546a2fb360 100644 (file)
@@ -20,7 +20,7 @@
 #ifdef __KERNEL__
 
 /* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT             12
+#define PAGE_SHIFT     CONFIG_PAGE_SHIFT
 #define PAGE_SIZE      (ASM_CONST(1) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
index 797ae590ebdba505c313b448720c7207b29673f8..24bac93affee940d14c3791a76394c693235b506 100644 (file)
@@ -81,6 +81,9 @@ config MIPS
        select HAVE_LD_DEAD_CODE_DATA_ELIMINATION
        select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_NMI
+       select HAVE_PAGE_SIZE_4KB if !CPU_LOONGSON2EF && !CPU_LOONGSON64
+       select HAVE_PAGE_SIZE_16KB if !CPU_R3000
+       select HAVE_PAGE_SIZE_64KB if !CPU_R3000
        select HAVE_PERF_EVENTS
        select HAVE_PERF_REGS
        select HAVE_PERF_USER_STACK_DUMP
@@ -1608,6 +1611,8 @@ config CPU_CAVIUM_OCTEON
        depends on SYS_HAS_CPU_CAVIUM_OCTEON
        select CPU_HAS_PREFETCH
        select CPU_SUPPORTS_64BIT_KERNEL
+       select HAVE_PAGE_SIZE_8KB if !MIPS_VA_BITS_48
+       select HAVE_PAGE_SIZE_32KB if !MIPS_VA_BITS_48
        select WEAK_ORDERING
        select CPU_SUPPORTS_HIGHMEM
        select CPU_SUPPORTS_HUGEPAGES
@@ -2029,59 +2034,6 @@ config ZBOOT_LOAD_ADDRESS
 
          This is only used if non-zero.
 
-choice
-       prompt "Kernel page size"
-       default PAGE_SIZE_4KB
-
-config PAGE_SIZE_4KB
-       bool "4kB"
-       depends on !CPU_LOONGSON2EF && !CPU_LOONGSON64
-       help
-         This option select the standard 4kB Linux page size.  On some
-         R3000-family processors this is the only available page size.  Using
-         4kB page size will minimize memory consumption and is therefore
-         recommended for low memory systems.
-
-config PAGE_SIZE_8KB
-       bool "8kB"
-       depends on CPU_CAVIUM_OCTEON
-       depends on !MIPS_VA_BITS_48
-       help
-         Using 8kB page size will result in higher performance kernel at
-         the price of higher memory consumption.  This option is available
-         only on cnMIPS processors.  Note that you will need a suitable Linux
-         distribution to support this.
-
-config PAGE_SIZE_16KB
-       bool "16kB"
-       depends on !CPU_R3000
-       help
-         Using 16kB page size will result in higher performance kernel at
-         the price of higher memory consumption.  This option is available on
-         all non-R3000 family processors.  Note that you will need a suitable
-         Linux distribution to support this.
-
-config PAGE_SIZE_32KB
-       bool "32kB"
-       depends on CPU_CAVIUM_OCTEON
-       depends on !MIPS_VA_BITS_48
-       help
-         Using 32kB page size will result in higher performance kernel at
-         the price of higher memory consumption.  This option is available
-         only on cnMIPS cores.  Note that you will need a suitable Linux
-         distribution to support this.
-
-config PAGE_SIZE_64KB
-       bool "64kB"
-       depends on !CPU_R3000
-       help
-         Using 64kB page size will result in higher performance kernel at
-         the price of higher memory consumption.  This option is available on
-         all non-R3000 family processor.  Not that at the time of this
-         writing this option is still high experimental.
-
-endchoice
-
 config ARCH_FORCE_MAX_ORDER
        int "Maximum zone order"
        default "13" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_64KB
index 4044eaf989ac7dad0f2094c5d4cfab05ac9fb5c3..0921ddda11a4b353c1c4d754417d3de4d003c12f 100644 (file)
@@ -241,7 +241,8 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
        "       .set    pop"
        : "=&r" (sum), "=&r" (tmp)
        : "r" (saddr), "r" (daddr),
-         "0" (htonl(len)), "r" (htonl(proto)), "r" (sum));
+         "0" (htonl(len)), "r" (htonl(proto)), "r" (sum)
+       : "memory");
 
        return csum_fold(sum);
 }
index ef9585d96f6b08f2ba6d0edcb5031acdb6ca573d..4609cb0326cf31f18465896d26b23ce0e5fdd553 100644 (file)
 /*
  * PAGE_SHIFT determines the page size
  */
-#ifdef CONFIG_PAGE_SIZE_4KB
-#define PAGE_SHIFT     12
-#endif
-#ifdef CONFIG_PAGE_SIZE_8KB
-#define PAGE_SHIFT     13
-#endif
-#ifdef CONFIG_PAGE_SIZE_16KB
-#define PAGE_SHIFT     14
-#endif
-#ifdef CONFIG_PAGE_SIZE_32KB
-#define PAGE_SHIFT     15
-#endif
-#ifdef CONFIG_PAGE_SIZE_64KB
-#define PAGE_SHIFT     16
-#endif
+#define PAGE_SHIFT     CONFIG_PAGE_SHIFT
 #define PAGE_SIZE      (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~((1 << PAGE_SHIFT) - 1))
 
index daf3cf244ea972c9a8bf134a09fa081931645425..d14d0e37ad02ddf10b42cfed590c65f97f8de424 100644 (file)
@@ -60,6 +60,7 @@ static inline void instruction_pointer_set(struct pt_regs *regs,
                                            unsigned long val)
 {
        regs->cp0_epc = val;
+       regs->cp0_cause &= ~CAUSEF_BD;
 }
 
 /* Query offset/name of register from its name/offset */
@@ -154,6 +155,8 @@ static inline long regs_return_value(struct pt_regs *regs)
 }
 
 #define instruction_pointer(regs) ((regs)->cp0_epc)
+extern unsigned long exception_ip(struct pt_regs *regs);
+#define exception_ip(regs) exception_ip(regs)
 #define profile_pc(regs) instruction_pointer(regs)
 
 extern asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall);
index cc7b516129a8fbc43bf532a85fac26801a2ba753..afb03d45bcd0d83716adf2d867c814f5f0fb0d1f 100644 (file)
@@ -50,9 +50,4 @@ extern struct mips_vdso_image vdso_image_o32;
 extern struct mips_vdso_image vdso_image_n32;
 #endif
 
-union mips_vdso_data {
-       struct vdso_data data[CS_BASES];
-       u8 page[PAGE_SIZE];
-};
-
 #endif /* __ASM_VDSO_H */
index d9df543f7e2c4cd17b29522840154f1e323cacb0..59288c13b581b89ccb46214c7be02126a017dab2 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/seccomp.h>
 #include <linux/ftrace.h>
 
+#include <asm/branch.h>
 #include <asm/byteorder.h>
 #include <asm/cpu.h>
 #include <asm/cpu-info.h>
 #define CREATE_TRACE_POINTS
 #include <trace/events/syscalls.h>
 
+unsigned long exception_ip(struct pt_regs *regs)
+{
+       return exception_epc(regs);
+}
+EXPORT_SYMBOL(exception_ip);
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
index f6d40e43f10851205b03a84dbe0a82b227038f2c..dda36fa26307e27d3de414c811450ed912294a0e 100644 (file)
@@ -24,7 +24,7 @@
 #include <vdso/vsyscall.h>
 
 /* Kernel-provided data used by the VDSO. */
-static union mips_vdso_data mips_vdso_data __page_aligned_data;
+static union vdso_data_store mips_vdso_data __page_aligned_data;
 struct vdso_data *vdso_data = mips_vdso_data.data;
 
 /*
index 58d9565dc2c770679111bb522c0ced0eae9aff5a..79d3039b29f1fbcb5401765743426cea65f84452 100644 (file)
@@ -15,6 +15,7 @@ config NIOS2
        select GENERIC_IRQ_SHOW
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_KGDB
+       select HAVE_PAGE_SIZE_4KB
        select IRQ_DOMAIN
        select LOCK_MM_AND_FIND_VMA
        select MODULES_USE_ELF_RELA
index 0ae7d9ce369b9ffc5344c30e83f45cb55d834380..0722f88e63cc7c6dfeee78cf33b8303769d1d17a 100644 (file)
@@ -21,7 +21,7 @@
 /*
  * PAGE_SHIFT determines the page size
  */
-#define PAGE_SHIFT     12
+#define PAGE_SHIFT     CONFIG_PAGE_SHIFT
 #define PAGE_SIZE      (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE - 1))
 
index fd9bb76a610bf043e292d12e9ab1cdb817bce336..3586cda55bdecaf687114d2dad14c8b1e9ceef97 100644 (file)
@@ -25,6 +25,7 @@ config OPENRISC
        select GENERIC_CPU_DEVICES
        select HAVE_PCI
        select HAVE_UID16
+       select HAVE_PAGE_SIZE_8KB
        select GENERIC_ATOMIC64
        select GENERIC_CLOCKEVENTS_BROADCAST
        select GENERIC_SMP_IDLE_THREAD
index 44fc1fd5671726c4fcc8be3c90d754f7f4e74f8d..1d5913f67c312f8691b697e92290b7d5d7f2b0e8 100644 (file)
@@ -18,7 +18,7 @@
 
 /* PAGE_SHIFT determines the page size */
 
-#define PAGE_SHIFT      13
+#define PAGE_SHIFT      CONFIG_PAGE_SHIFT
 #ifdef __ASSEMBLY__
 #define PAGE_SIZE       (1 << PAGE_SHIFT)
 #else
@@ -77,11 +77,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
        return __pa(kaddr) >> PAGE_SHIFT;
 }
 
-static inline void * pfn_to_virt(unsigned long pfn)
-{
-       return (void *)((unsigned long)__va(pfn) << PAGE_SHIFT);
-}
-
 #define virt_to_page(addr) \
        (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT))
 
index 1c5a2d71d6753e8a02a8903712c163802e56891c..86da4bc5ee0bbeb7fbc2a36a3275a271624feffe 100644 (file)
@@ -57,10 +57,6 @@ static void boot_secondary(unsigned int cpu, struct task_struct *idle)
        spin_unlock(&boot_lock);
 }
 
-void __init smp_prepare_boot_cpu(void)
-{
-}
-
 void __init smp_init_cpus(void)
 {
        struct device_node *cpu;
index 5c845e8d59d92f8cd3594fccf1476503d8957149..b180e684fa0dbe45347def1f5c01c1994de50699 100644 (file)
@@ -273,6 +273,7 @@ choice
 
 config PARISC_PAGE_SIZE_4KB
        bool "4KB"
+       select HAVE_PAGE_SIZE_4KB
        help
          This lets you select the page size of the kernel.  For best
          performance, a page size of 16KB is recommended.  For best
@@ -288,10 +289,12 @@ config PARISC_PAGE_SIZE_4KB
 
 config PARISC_PAGE_SIZE_16KB
        bool "16KB"
+       select HAVE_PAGE_SIZE_16KB
        depends on PA8X00 && BROKEN && !KFENCE
 
 config PARISC_PAGE_SIZE_64KB
        bool "64KB"
+       select HAVE_PAGE_SIZE_64KB
        depends on PA8X00 && BROKEN && !KFENCE
 
 endchoice
index 7486b3b3059491490f5626224f9177eb5efd6cdb..316f84f1d15c8f8c6e65dd3862dc5db1144f95bb 100644 (file)
@@ -50,12 +50,12 @@ export CROSS32CC
 
 # Set default cross compiler for kernel build
 ifdef cross_compiling
-        ifeq ($(CROSS_COMPILE),)
+    ifeq ($(CROSS_COMPILE),)
                CC_SUFFIXES = linux linux-gnu unknown-linux-gnu suse-linux
                CROSS_COMPILE := $(call cc-cross-prefix, \
                        $(foreach a,$(CC_ARCHES), \
                        $(foreach s,$(CC_SUFFIXES),$(a)-$(s)-)))
-        endif
+    endif
 endif
 
 ifdef CONFIG_DYNAMIC_FTRACE
index 0a175ac876980c7c90b747bd8f8f34658499997a..0f42f5c8e3b66a8cbcf6f95a3312cb22f456cca8 100644 (file)
 #ifndef _PARISC_KPROBES_H
 #define _PARISC_KPROBES_H
 
+#include <asm-generic/kprobes.h>
+
 #ifdef CONFIG_KPROBES
 
-#include <asm-generic/kprobes.h>
 #include <linux/types.h>
 #include <linux/ptrace.h>
 #include <linux/notifier.h>
index 667e703c0e8f695045e1354826a0f41f7c7cdfe0..ad4e15d12ed1c503dd74f78d41410b5d19e692e4 100644 (file)
@@ -4,15 +4,7 @@
 
 #include <linux/const.h>
 
-#if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
-# define PAGE_SHIFT    12
-#elif defined(CONFIG_PARISC_PAGE_SIZE_16KB)
-# define PAGE_SHIFT    14
-#elif defined(CONFIG_PARISC_PAGE_SIZE_64KB)
-# define PAGE_SHIFT    16
-#else
-# error "unknown default kernel page size"
-#endif
+#define PAGE_SHIFT     CONFIG_PAGE_SHIFT
 #define PAGE_SIZE      (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
index d1defb9ede70c0ae73e46363e850fc28ef91cebd..621a4b386ae4fcc90fa5e2ad9b7ac6b947fd903d 100644 (file)
@@ -78,7 +78,7 @@ asmlinkage void notrace __hot ftrace_function_trampoline(unsigned long parent,
 #endif
 }
 
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#if defined(CONFIG_DYNAMIC_FTRACE) && defined(CONFIG_FUNCTION_GRAPH_TRACER)
 int ftrace_enable_ftrace_graph_caller(void)
 {
        static_key_enable(&ftrace_graph_enable.key);
index e95a977ba5f376eb813d4c7806d205a92f539880..bf73562706b2e8ec337bc8cde4b6fd9e5cd7f43e 100644 (file)
@@ -172,7 +172,6 @@ static int __init processor_probe(struct parisc_device *dev)
        p->cpu_num = cpu_info.cpu_num;
        p->cpu_loc = cpu_info.cpu_loc;
 
-       set_cpu_possible(cpuid, true);
        store_cpu_topology(cpuid);
 
 #ifdef CONFIG_SMP
@@ -474,13 +473,6 @@ static struct parisc_driver cpu_driver __refdata = {
  */
 void __init processor_init(void)
 {
-       unsigned int cpu;
-
        reset_cpu_topology();
-
-       /* reset possible mask. We will mark those which are possible. */
-       for_each_possible_cpu(cpu)
-               set_cpu_possible(cpu, false);
-
        register_parisc_driver(&cpu_driver);
 }
index 27ae40a443b80c5fa575e8579bca7f08ef6d36ab..f7e0fee5ee55a3e055679e75b06c280679b603ad 100644 (file)
@@ -228,10 +228,8 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int
 #ifdef CONFIG_IRQSTACKS
        extern void * const _call_on_stack;
 #endif /* CONFIG_IRQSTACKS */
-       void *ptr;
 
-       ptr = dereference_kernel_function_descriptor(&handle_interruption);
-       if (pc_is_kernel_fn(pc, ptr)) {
+       if (pc_is_kernel_fn(pc, handle_interruption)) {
                struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN);
                dbg("Unwinding through handle_interruption()\n");
                info->prev_sp = regs->gr[30];
@@ -239,13 +237,13 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int
                return 1;
        }
 
-       if (pc_is_kernel_fn(pc, ret_from_kernel_thread) ||
-           pc_is_kernel_fn(pc, syscall_exit)) {
+       if (pc == (unsigned long)&ret_from_kernel_thread ||
+           pc == (unsigned long)&syscall_exit) {
                info->prev_sp = info->prev_ip = 0;
                return 1;
        }
 
-       if (pc_is_kernel_fn(pc, intr_return)) {
+       if (pc == (unsigned long)&intr_return) {
                struct pt_regs *regs;
 
                dbg("Found intr_return()\n");
@@ -257,14 +255,14 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int
        }
 
        if (pc_is_kernel_fn(pc, _switch_to) ||
-           pc_is_kernel_fn(pc, _switch_to_ret)) {
+           pc == (unsigned long)&_switch_to_ret) {
                info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
                info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
                return 1;
        }
 
 #ifdef CONFIG_IRQSTACKS
-       if (pc_is_kernel_fn(pc, _call_on_stack)) {
+       if (pc == (unsigned long)&_call_on_stack) {
                info->prev_sp = *(unsigned long *)(info->sp - FRAME_SIZE - REG_SZ);
                info->prev_ip = *(unsigned long *)(info->sp - FRAME_SIZE - RP_OFFSET);
                return 1;
index b9fc064d38d281f1c32584e79edd705c670b1731..8fad4e5d7ad5d5a6d7c1c00eab65598aa5acd0c1 100644 (file)
@@ -212,7 +212,7 @@ config PPC
        select HAVE_ARCH_HUGE_VMAP              if PPC_RADIX_MMU || PPC_8xx
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_ARCH_JUMP_LABEL_RELATIVE
-       select HAVE_ARCH_KASAN                  if PPC32 && PPC_PAGE_SHIFT <= 14
+       select HAVE_ARCH_KASAN                  if PPC32 && PAGE_SHIFT <= 14
        select HAVE_ARCH_KASAN                  if PPC_RADIX_MMU
        select HAVE_ARCH_KASAN                  if PPC_BOOK3E_64
        select HAVE_ARCH_KASAN_VMALLOC          if HAVE_ARCH_KASAN
@@ -809,19 +809,23 @@ choice
 config PPC_4K_PAGES
        bool "4k page size"
        select HAVE_ARCH_SOFT_DIRTY if PPC_BOOK3S_64
+       select HAVE_PAGE_SIZE_4KB
 
 config PPC_16K_PAGES
        bool "16k page size"
        depends on 44x || PPC_8xx
+       select HAVE_PAGE_SIZE_16KB
 
 config PPC_64K_PAGES
        bool "64k page size"
        depends on 44x || PPC_BOOK3S_64
        select HAVE_ARCH_SOFT_DIRTY if PPC_BOOK3S_64
+       select HAVE_PAGE_SIZE_64KB
 
 config PPC_256K_PAGES
        bool "256k page size (Requires non-standard binutils settings)"
        depends on 44x && !PPC_47x
+       select HAVE_PAGE_SIZE_256KB
        help
          Make the page size 256k.
 
@@ -832,29 +836,6 @@ config PPC_256K_PAGES
 
 endchoice
 
-config PAGE_SIZE_4KB
-       def_bool y
-       depends on PPC_4K_PAGES
-
-config PAGE_SIZE_16KB
-       def_bool y
-       depends on PPC_16K_PAGES
-
-config PAGE_SIZE_64KB
-       def_bool y
-       depends on PPC_64K_PAGES
-
-config PAGE_SIZE_256KB
-       def_bool y
-       depends on PPC_256K_PAGES
-
-config PPC_PAGE_SHIFT
-       int
-       default 18 if PPC_256K_PAGES
-       default 16 if PPC_64K_PAGES
-       default 14 if PPC_16K_PAGES
-       default 12
-
 config THREAD_SHIFT
        int "Thread shift" if EXPERT
        range 13 15
@@ -891,7 +872,7 @@ config DATA_SHIFT
        default 23 if (DEBUG_PAGEALLOC || KFENCE) && PPC_8xx && PIN_TLB_DATA
        default 19 if (DEBUG_PAGEALLOC || KFENCE) && PPC_8xx
        default 24 if STRICT_KERNEL_RWX && PPC_85xx
-       default PPC_PAGE_SHIFT
+       default PAGE_SHIFT
        help
          On Book3S 32 (603+), DBATs are used to map kernel text and rodata RO.
          Smaller is the alignment, greater is the number of necessary DBATs.
index 1ebd2ca97f1201f1e760fcb46fe4c5e043727333..107fc5a484569673af80bd58e2e5980ae4082fab 100644 (file)
 #ifndef __ASSEMBLY__
 extern void _mcount(void);
 
-static inline unsigned long ftrace_call_adjust(unsigned long addr)
-{
-       if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY))
-               addr += MCOUNT_INSN_SIZE;
-
-       return addr;
-}
-
 unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip,
                                    unsigned long sp);
 
@@ -142,8 +134,10 @@ static inline u8 this_cpu_get_ftrace_enabled(void) { return 1; }
 #ifdef CONFIG_FUNCTION_TRACER
 extern unsigned int ftrace_tramp_text[], ftrace_tramp_init[];
 void ftrace_free_init_tramp(void);
+unsigned long ftrace_call_adjust(unsigned long addr);
 #else
 static inline void ftrace_free_init_tramp(void) { }
+static inline unsigned long ftrace_call_adjust(unsigned long addr) { return addr; }
 #endif
 #endif /* !__ASSEMBLY__ */
 
index e5fcc79b5bfba175b56b2783763d8041a355debe..e411e5a70ea39fbeaa653c7f99102a7a08ffb031 100644 (file)
@@ -21,7 +21,7 @@
  * page size. When using 64K pages however, whether we are really supporting
  * 64K pages in HW or not is irrelevant to those definitions.
  */
-#define PAGE_SHIFT             CONFIG_PPC_PAGE_SHIFT
+#define PAGE_SHIFT             CONFIG_PAGE_SHIFT
 #define PAGE_SIZE              (ASM_CONST(1) << PAGE_SHIFT)
 
 #ifndef __ASSEMBLY__
index 0dbbff59101d6f31d4ac9f59c2fa74a7d4e90cae..c3cd5b131033eb3ef5c8fc1e99f0a8da0b78157a 100644 (file)
@@ -32,7 +32,7 @@ typedef struct {
  */
 struct papr_sysparm_buf {
        __be16 len;
-       char val[PAPR_SYSPARM_MAX_OUTPUT];
+       u8 val[PAPR_SYSPARM_MAX_OUTPUT];
 };
 
 struct papr_sysparm_buf *papr_sysparm_buf_alloc(void);
index ce2b1b5eebddcf5eb2e84b5e8853f89cf06501a6..a8b7e8682f5bd6c58ff9faa31a152a31e1b5280d 100644 (file)
@@ -30,6 +30,16 @@ void *pci_traverse_device_nodes(struct device_node *start,
                                void *data);
 extern void pci_devs_phb_init_dynamic(struct pci_controller *phb);
 
+#if defined(CONFIG_IOMMU_API) && (defined(CONFIG_PPC_PSERIES) || \
+                                 defined(CONFIG_PPC_POWERNV))
+extern void ppc_iommu_register_device(struct pci_controller *phb);
+extern void ppc_iommu_unregister_device(struct pci_controller *phb);
+#else
+static inline void ppc_iommu_register_device(struct pci_controller *phb) { }
+static inline void ppc_iommu_unregister_device(struct pci_controller *phb) { }
+#endif
+
+
 /* From rtas_pci.h */
 extern void init_pci_config_tokens (void);
 extern unsigned long get_phb_buid (struct device_node *);
index 7fd09f25452d4f697728f7958a9ad5b277f73a50..bb47af9054a9545f54bf5080a14bde235ef29a30 100644 (file)
 #endif
 #define SPRN_HID2      0x3F8           /* Hardware Implementation Register 2 */
 #define SPRN_HID2_GEKKO        0x398           /* Gekko HID2 Register */
+#define SPRN_HID2_G2_LE        0x3F3           /* G2_LE HID2 Register */
+#define  HID2_G2_LE_HBE        (1<<18)         /* High BAT Enable (G2_LE) */
 #define SPRN_IABR      0x3F2   /* Instruction Address Breakpoint Register */
 #define SPRN_IABR2     0x3FA           /* 83xx */
 #define SPRN_IBCR      0x135           /* 83xx Insn Breakpoint Control Reg */
index 9bb2210c8d4417a4262aab81d68d851e175b77b4..065ffd1b2f8adaef8369846531bf4e6f78159b57 100644 (file)
@@ -69,7 +69,7 @@ enum rtas_function_index {
        RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE,
        RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE2,
        RTAS_FNIDX__IBM_REMOVE_PE_DMA_WINDOW,
-       RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOWS,
+       RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOW,
        RTAS_FNIDX__IBM_SCAN_LOG_DUMP,
        RTAS_FNIDX__IBM_SET_DYNAMIC_INDICATOR,
        RTAS_FNIDX__IBM_SET_EEH_OPTION,
@@ -164,7 +164,7 @@ typedef struct {
 #define RTAS_FN_IBM_READ_SLOT_RESET_STATE         rtas_fn_handle(RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE)
 #define RTAS_FN_IBM_READ_SLOT_RESET_STATE2        rtas_fn_handle(RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE2)
 #define RTAS_FN_IBM_REMOVE_PE_DMA_WINDOW          rtas_fn_handle(RTAS_FNIDX__IBM_REMOVE_PE_DMA_WINDOW)
-#define RTAS_FN_IBM_RESET_PE_DMA_WINDOWS          rtas_fn_handle(RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOWS)
+#define RTAS_FN_IBM_RESET_PE_DMA_WINDOW           rtas_fn_handle(RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOW)
 #define RTAS_FN_IBM_SCAN_LOG_DUMP                 rtas_fn_handle(RTAS_FNIDX__IBM_SCAN_LOG_DUMP)
 #define RTAS_FN_IBM_SET_DYNAMIC_INDICATOR         rtas_fn_handle(RTAS_FNIDX__IBM_SET_DYNAMIC_INDICATOR)
 #define RTAS_FN_IBM_SET_EEH_OPTION                rtas_fn_handle(RTAS_FNIDX__IBM_SET_EEH_OPTION)
index ea26665f82cfc833a93b87f23ae2b196eb5a4180..f43f3a6b0051cf24bd76428987366d1fcdf5de5d 100644 (file)
@@ -14,6 +14,7 @@ typedef struct func_desc func_desc_t;
 
 extern char __head_end[];
 extern char __srwx_boundary[];
+extern char __exittext_begin[], __exittext_end[];
 
 /* Patch sites */
 extern s32 patch__call_flush_branch_caches1;
index bf5dde1a411471fcc95d4503dfb41d3881aad9fe..15c5691dd218440d32142779a2a1e2ce5058d60c 100644 (file)
@@ -14,7 +14,7 @@
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_KASAN
+#if defined(CONFIG_KASAN) && CONFIG_THREAD_SHIFT < 15
 #define MIN_THREAD_SHIFT       (CONFIG_THREAD_SHIFT + 1)
 #else
 #define MIN_THREAD_SHIFT       CONFIG_THREAD_SHIFT
index 9f9a0f267ea57c2593448bcfbd0af4f4f0582f08..f733467b1534eb9bf3dad20042b06afd85ab8f41 100644 (file)
@@ -14,7 +14,7 @@ enum {
 struct papr_sysparm_io_block {
        __u32 parameter;
        __u16 length;
-       char data[PAPR_SYSPARM_MAX_OUTPUT];
+       __u8 data[PAPR_SYSPARM_MAX_OUTPUT];
 };
 
 /**
index f29ce3dd6140f40c026a0d8f67e79858c86dabd9..bfd3f442e5eb9dfcb851f1b1c5b68e690f1702ae 100644 (file)
@@ -26,6 +26,15 @@ BEGIN_FTR_SECTION
        bl      __init_fpu_registers
 END_FTR_SECTION_IFCLR(CPU_FTR_FPU_UNAVAILABLE)
        bl      setup_common_caches
+
+       /*
+        * This assumes that all cores using __setup_cpu_603 with
+        * MMU_FTR_USE_HIGH_BATS are G2_LE compatible
+        */
+BEGIN_MMU_FTR_SECTION
+       bl      setup_g2_le_hid2
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
+
        mtlr    r5
        blr
 _GLOBAL(__setup_cpu_604)
@@ -115,6 +124,16 @@ SYM_FUNC_START_LOCAL(setup_604_hid0)
        blr
 SYM_FUNC_END(setup_604_hid0)
 
+/* Enable high BATs for G2_LE and derivatives like e300cX */
+SYM_FUNC_START_LOCAL(setup_g2_le_hid2)
+       mfspr   r11,SPRN_HID2_G2_LE
+       oris    r11,r11,HID2_G2_LE_HBE@h
+       mtspr   SPRN_HID2_G2_LE,r11
+       sync
+       isync
+       blr
+SYM_FUNC_END(setup_g2_le_hid2)
+
 /* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some
  * erratas we work around here.
  * Moto MPC710CE.pdf describes them, those are errata
@@ -495,4 +514,3 @@ _GLOBAL(__restore_cpu_setup)
        mtcr    r7
        blr
 _ASM_NOKPROBE_SYMBOL(__restore_cpu_setup)
-
index ceb06b109f831355a833a0e929ef68d86ccbc321..2ae8e9a7b461c8c35755bd4ac0ab48e29a4daf79 100644 (file)
@@ -8,7 +8,8 @@
 
 #ifdef CONFIG_PPC64
 #define COMMON_USER_BOOKE      (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \
-                                PPC_FEATURE_HAS_FPU | PPC_FEATURE_64)
+                                PPC_FEATURE_HAS_FPU | PPC_FEATURE_64 | \
+                                PPC_FEATURE_BOOKE)
 #else
 #define COMMON_USER_BOOKE      (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \
                                 PPC_FEATURE_BOOKE)
index bd863702d81218d80e61c73e469d448f963eb265..1ad059a9e2fef3da806514bc35158966d626072b 100644 (file)
@@ -52,7 +52,8 @@ _ASM_NOKPROBE_SYMBOL(system_call_vectored_\name)
        mr      r10,r1
        ld      r1,PACAKSAVE(r13)
        std     r10,0(r1)
-       std     r11,_NIP(r1)
+       std     r11,_LINK(r1)
+       std     r11,_NIP(r1)    /* Saved LR is also the next instruction */
        std     r12,_MSR(r1)
        std     r0,GPR0(r1)
        std     r10,GPR1(r1)
@@ -70,7 +71,6 @@ _ASM_NOKPROBE_SYMBOL(system_call_vectored_\name)
        std     r9,GPR13(r1)
        SAVE_NVGPRS(r1)
        std     r11,_XER(r1)
-       std     r11,_LINK(r1)
        std     r11,_CTR(r1)
 
        li      r11,\trapnr
index d71eac3b2887b98ff5ea23ec1874243283524f4c..1185efebf032b6e7d2cf08db4c953938948a44b1 100644 (file)
@@ -1289,8 +1289,10 @@ spapr_tce_platform_iommu_attach_dev(struct iommu_domain *platform_domain,
        struct iommu_table_group *table_group;
 
        /* At first attach the ownership is already set */
-       if (!domain)
+       if (!domain) {
+               iommu_group_put(grp);
                return 0;
+       }
 
        table_group = iommu_group_get_iommudata(grp);
        /*
@@ -1358,7 +1360,7 @@ static struct iommu_device *spapr_tce_iommu_probe_device(struct device *dev)
        struct pci_controller *hose;
 
        if (!dev_is_pci(dev))
-               return ERR_PTR(-EPERM);
+               return ERR_PTR(-ENODEV);
 
        pdev = to_pci_dev(dev);
        hose = pdev->bus->sysdata;
@@ -1407,6 +1409,21 @@ static const struct attribute_group *spapr_tce_iommu_groups[] = {
        NULL,
 };
 
+void ppc_iommu_register_device(struct pci_controller *phb)
+{
+       iommu_device_sysfs_add(&phb->iommu, phb->parent,
+                               spapr_tce_iommu_groups, "iommu-phb%04x",
+                               phb->global_number);
+       iommu_device_register(&phb->iommu, &spapr_tce_iommu_ops,
+                               phb->parent);
+}
+
+void ppc_iommu_unregister_device(struct pci_controller *phb)
+{
+       iommu_device_unregister(&phb->iommu);
+       iommu_device_sysfs_remove(&phb->iommu);
+}
+
 /*
  * This registers IOMMU devices of PHBs. This needs to happen
  * after core_initcall(iommu_init) + postcore_initcall(pci_driver_init) and
@@ -1417,11 +1434,7 @@ static int __init spapr_tce_setup_phb_iommus_initcall(void)
        struct pci_controller *hose;
 
        list_for_each_entry(hose, &hose_list, list_node) {
-               iommu_device_sysfs_add(&hose->iommu, hose->parent,
-                                      spapr_tce_iommu_groups, "iommu-phb%04x",
-                                      hose->global_number);
-               iommu_device_register(&hose->iommu, &spapr_tce_iommu_ops,
-                                     hose->parent);
+               ppc_iommu_register_device(hose);
        }
        return 0;
 }
index 7e793b503e29f1ff878e7289c8703e7c4cf20edc..8064d9c3de8620d27d9c87f829676ef048aeed40 100644 (file)
@@ -375,8 +375,13 @@ static struct rtas_function rtas_function_table[] __ro_after_init = {
        [RTAS_FNIDX__IBM_REMOVE_PE_DMA_WINDOW] = {
                .name = "ibm,remove-pe-dma-window",
        },
-       [RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOWS] = {
-               .name = "ibm,reset-pe-dma-windows",
+       [RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOW] = {
+               /*
+                * Note: PAPR+ v2.13 7.3.31.4.1 spells this as
+                * "ibm,reset-pe-dma-windows" (plural), but RTAS
+                * implementations use the singular form in practice.
+                */
+               .name = "ibm,reset-pe-dma-window",
        },
        [RTAS_FNIDX__IBM_SCAN_LOG_DUMP] = {
                .name = "ibm,scan-log-dump",
index 693334c20d07db70e46224333c565abc457be11a..a60e4139214be58384edca3e282f8df936b8c4ea 100644 (file)
@@ -984,7 +984,7 @@ static bool shared_caches __ro_after_init;
 /* cpumask of CPUs with asymmetric SMT dependency */
 static int powerpc_smt_flags(void)
 {
-       int flags = SD_SHARE_CPUCAPACITY | SD_SHARE_PKG_RESOURCES;
+       int flags = SD_SHARE_CPUCAPACITY | SD_SHARE_LLC;
 
        if (cpu_has_feature(CPU_FTR_ASYM_SMT)) {
                printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n");
@@ -1010,9 +1010,9 @@ static __ro_after_init DEFINE_STATIC_KEY_FALSE(splpar_asym_pack);
 static int powerpc_shared_cache_flags(void)
 {
        if (static_branch_unlikely(&splpar_asym_pack))
-               return SD_SHARE_PKG_RESOURCES | SD_ASYM_PACKING;
+               return SD_SHARE_LLC | SD_ASYM_PACKING;
 
-       return SD_SHARE_PKG_RESOURCES;
+       return SD_SHARE_LLC;
 }
 
 static int powerpc_shared_proc_flags(void)
index 82010629cf887ca1753d4f64bfa5916cdc1d7b48..d8d6b4fd9a14cbf8f8f93e499500eed11190be71 100644 (file)
 #include <asm/ftrace.h>
 #include <asm/syscall.h>
 #include <asm/inst.h>
+#include <asm/sections.h>
 
 #define        NUM_FTRACE_TRAMPS       2
 static unsigned long ftrace_tramps[NUM_FTRACE_TRAMPS];
 
+unsigned long ftrace_call_adjust(unsigned long addr)
+{
+       if (addr >= (unsigned long)__exittext_begin && addr < (unsigned long)__exittext_end)
+               return 0;
+
+       if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY))
+               addr += MCOUNT_INSN_SIZE;
+
+       return addr;
+}
+
 static ppc_inst_t ftrace_create_branch_inst(unsigned long ip, unsigned long addr, int link)
 {
        ppc_inst_t op;
index 7b85c3b460a3c048ec31cce44e9b21066b96c5a8..12fab1803bcf45cafb3fd230c1f7871e2c539f1d 100644 (file)
 #define        NUM_FTRACE_TRAMPS       8
 static unsigned long ftrace_tramps[NUM_FTRACE_TRAMPS];
 
+unsigned long ftrace_call_adjust(unsigned long addr)
+{
+       return addr;
+}
+
 static ppc_inst_t
 ftrace_call_replace(unsigned long ip, unsigned long addr, int link)
 {
index 1c5970df32336655703888b1ffafb8180e79c446..f420df7888a75c5f515a3457708c3188661fa331 100644 (file)
@@ -281,7 +281,9 @@ SECTIONS
         * to deal with references from __bug_table
         */
        .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) {
+               __exittext_begin = .;
                EXIT_TEXT
+               __exittext_end = .;
        }
 
        . = ALIGN(PAGE_SIZE);
index 52427fc2a33fa4ad7032bcc6323bc6364918d98f..0b921704da45eb6b718cac8f031c5d0c45176746 100644 (file)
@@ -391,6 +391,24 @@ static void kvmppc_set_pvr_hv(struct kvm_vcpu *vcpu, u32 pvr)
 /* Dummy value used in computing PCR value below */
 #define PCR_ARCH_31    (PCR_ARCH_300 << 1)
 
+static inline unsigned long map_pcr_to_cap(unsigned long pcr)
+{
+       unsigned long cap = 0;
+
+       switch (pcr) {
+       case PCR_ARCH_300:
+               cap = H_GUEST_CAP_POWER9;
+               break;
+       case PCR_ARCH_31:
+               cap = H_GUEST_CAP_POWER10;
+               break;
+       default:
+               break;
+       }
+
+       return cap;
+}
+
 static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
 {
        unsigned long host_pcr_bit = 0, guest_pcr_bit = 0, cap = 0;
@@ -424,11 +442,9 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
                        break;
                case PVR_ARCH_300:
                        guest_pcr_bit = PCR_ARCH_300;
-                       cap = H_GUEST_CAP_POWER9;
                        break;
                case PVR_ARCH_31:
                        guest_pcr_bit = PCR_ARCH_31;
-                       cap = H_GUEST_CAP_POWER10;
                        break;
                default:
                        return -EINVAL;
@@ -440,6 +456,12 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
                return -EINVAL;
 
        if (kvmhv_on_pseries() && kvmhv_is_nestedv2()) {
+               /*
+                * 'arch_compat == 0' would mean the guest should default to
+                * L1's compatibility. In this case, the guest would pick
+                * host's PCR and evaluate the corresponding capabilities.
+                */
+               cap = map_pcr_to_cap(guest_pcr_bit);
                if (!(cap & nested_capabilities))
                        return -EINVAL;
        }
index 5378eb40b162f2690879f43fbaeb3f0b003536a7..8e6f5355f08b5d925c54606db4a70cbe24d74e61 100644 (file)
@@ -138,6 +138,7 @@ static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb,
        vector128 v;
        int rc, i;
        u16 iden;
+       u32 arch_compat = 0;
 
        vcpu = gsm->data;
 
@@ -347,8 +348,23 @@ static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb,
                        break;
                }
                case KVMPPC_GSID_LOGICAL_PVR:
-                       rc = kvmppc_gse_put_u32(gsb, iden,
-                                               vcpu->arch.vcore->arch_compat);
+                       /*
+                        * Though 'arch_compat == 0' would mean the default
+                        * compatibility, arch_compat, being a Guest Wide
+                        * Element, cannot be filled with a value of 0 in GSB
+                        * as this would result into a kernel trap.
+                        * Hence, when `arch_compat == 0`, arch_compat should
+                        * default to L1's PVR.
+                        */
+                       if (!vcpu->arch.vcore->arch_compat) {
+                               if (cpu_has_feature(CPU_FTR_ARCH_31))
+                                       arch_compat = PVR_ARCH_31;
+                               else if (cpu_has_feature(CPU_FTR_ARCH_300))
+                                       arch_compat = PVR_ARCH_300;
+                       } else {
+                               arch_compat = vcpu->arch.vcore->arch_compat;
+                       }
+                       rc = kvmppc_gse_put_u32(gsb, iden, arch_compat);
                        break;
                }
 
index a70828a6d9357d5fb399375f9624a7fb06d4a129..aa9aa11927b2f842718d98e7818fcd499efd0e54 100644 (file)
@@ -64,6 +64,7 @@ int __init __weak kasan_init_region(void *start, size_t size)
        if (ret)
                return ret;
 
+       k_start = k_start & PAGE_MASK;
        block = memblock_alloc(k_end - k_start, PAGE_SIZE);
        if (!block)
                return -ENOMEM;
index e966b2ad8ecd42a97d8eb9fc7d6a70922165b2d9..b3327a358eb434dfe4c3357b534ea3f8102425e1 100644 (file)
@@ -27,7 +27,7 @@
 
 #include "mpc85xx.h"
 
-void __init mpc8536_ds_pic_init(void)
+static void __init mpc8536_ds_pic_init(void)
 {
        struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
                        0, 256, " OpenPIC  ");
index 1b59e45a0c64f1bd4dc257b52df072b07a555abf..19122daadb55a64842c4d5e56ad6e08ad762ab28 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "mpc85xx.h"
 
-void __init mvme2500_pic_init(void)
+static void __init mvme2500_pic_init(void)
 {
        struct mpic *mpic = mpic_alloc(NULL, 0,
                  MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU,
index 10d6f1fa33275a8b5b4153226c827e6f1d2816fa..491895ac8bcfe2121f99138e352255cd15085ccd 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "mpc85xx.h"
 
-void __init p1010_rdb_pic_init(void)
+static void __init p1010_rdb_pic_init(void)
 {
        struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
          MPIC_SINGLE_DEST_CPU,
index 0dd786a061a6a2195e51a1ecf2d6be65d6d38221..adc3a2ee141509f0ca06ccb1d648efd17292f7be 100644 (file)
@@ -370,7 +370,7 @@ exit:
  *
  * @pixclock: the wavelength, in picoseconds, of the clock
  */
-void p1022ds_set_pixel_clock(unsigned int pixclock)
+static void p1022ds_set_pixel_clock(unsigned int pixclock)
 {
        struct device_node *guts_np = NULL;
        struct ccsr_guts __iomem *guts;
@@ -418,7 +418,7 @@ void p1022ds_set_pixel_clock(unsigned int pixclock)
 /**
  * p1022ds_valid_monitor_port: set the monitor port for sysfs
  */
-enum fsl_diu_monitor_port
+static enum fsl_diu_monitor_port
 p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port)
 {
        switch (port) {
@@ -432,7 +432,7 @@ p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port)
 
 #endif
 
-void __init p1022_ds_pic_init(void)
+static void __init p1022_ds_pic_init(void)
 {
        struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
                MPIC_SINGLE_DEST_CPU,
index 25ab6e9c14703a66fd9b702324f36574166ab114..6198299d95b1b88806f83da5743961034dc35b8f 100644 (file)
@@ -40,7 +40,7 @@
  *
  * @pixclock: the wavelength, in picoseconds, of the clock
  */
-void p1022rdk_set_pixel_clock(unsigned int pixclock)
+static void p1022rdk_set_pixel_clock(unsigned int pixclock)
 {
        struct device_node *guts_np = NULL;
        struct ccsr_guts __iomem *guts;
@@ -88,7 +88,7 @@ void p1022rdk_set_pixel_clock(unsigned int pixclock)
 /**
  * p1022rdk_valid_monitor_port: set the monitor port for sysfs
  */
-enum fsl_diu_monitor_port
+static enum fsl_diu_monitor_port
 p1022rdk_valid_monitor_port(enum fsl_diu_monitor_port port)
 {
        return FSL_DIU_PORT_DVI;
@@ -96,7 +96,7 @@ p1022rdk_valid_monitor_port(enum fsl_diu_monitor_port port)
 
 #endif
 
-void __init p1022_rdk_pic_init(void)
+static void __init p1022_rdk_pic_init(void)
 {
        struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
                MPIC_SINGLE_DEST_CPU,
index baa12eff6d5de460f56832a60bd3116e3748fa32..60e0b8947ce6106873dcc1abb22b51450524c3b2 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/of_irq.h>
 #include <linux/io.h>
 
+#include "socrates_fpga_pic.h"
+
 /*
  * The FPGA supports 9 interrupt sources, which can be routed to 3
  * interrupt request lines of the MPIC. The line to be used can be
index 45f257fc1ade055a7fdcc6a9142e0b5404f77f0b..2582427d8d0182fffdb79d70ed584889c6ff0d5f 100644 (file)
@@ -37,7 +37,7 @@
 #define MPC85xx_L2CTL_L2I              0x40000000 /* L2 flash invalidate */
 #define MPC85xx_L2CTL_L2SIZ_MASK       0x30000000 /* L2 SRAM size (R/O) */
 
-void __init xes_mpc85xx_pic_init(void)
+static void __init xes_mpc85xx_pic_init(void)
 {
        struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
                        0, 256, " OpenPIC  ");
index 496e16c588aaa8edcd0294825862312471928506..e8c4129697b142ba48490481ee38793086e8425a 100644 (file)
@@ -574,29 +574,6 @@ static void iommu_table_setparms(struct pci_controller *phb,
 
 struct iommu_table_ops iommu_table_lpar_multi_ops;
 
-/*
- * iommu_table_setparms_lpar
- *
- * Function: On pSeries LPAR systems, return TCE table info, given a pci bus.
- */
-static void iommu_table_setparms_lpar(struct pci_controller *phb,
-                                     struct device_node *dn,
-                                     struct iommu_table *tbl,
-                                     struct iommu_table_group *table_group,
-                                     const __be32 *dma_window)
-{
-       unsigned long offset, size, liobn;
-
-       of_parse_dma_window(dn, dma_window, &liobn, &offset, &size);
-
-       iommu_table_setparms_common(tbl, phb->bus->number, liobn, offset, size, IOMMU_PAGE_SHIFT_4K, NULL,
-                                   &iommu_table_lpar_multi_ops);
-
-
-       table_group->tce32_start = offset;
-       table_group->tce32_size = size;
-}
-
 struct iommu_table_ops iommu_table_pseries_ops = {
        .set = tce_build_pSeries,
        .clear = tce_free_pSeries,
@@ -724,26 +701,71 @@ struct iommu_table_ops iommu_table_lpar_multi_ops = {
  * dynamic 64bit DMA window, walking up the device tree.
  */
 static struct device_node *pci_dma_find(struct device_node *dn,
-                                       const __be32 **dma_window)
+                                       struct dynamic_dma_window_prop *prop)
 {
-       const __be32 *dw = NULL;
+       const __be32 *default_prop = NULL;
+       const __be32 *ddw_prop = NULL;
+       struct device_node *rdn = NULL;
+       bool default_win = false, ddw_win = false;
 
        for ( ; dn && PCI_DN(dn); dn = dn->parent) {
-               dw = of_get_property(dn, "ibm,dma-window", NULL);
-               if (dw) {
-                       if (dma_window)
-                               *dma_window = dw;
-                       return dn;
+               default_prop = of_get_property(dn, "ibm,dma-window", NULL);
+               if (default_prop) {
+                       rdn = dn;
+                       default_win = true;
+               }
+               ddw_prop = of_get_property(dn, DIRECT64_PROPNAME, NULL);
+               if (ddw_prop) {
+                       rdn = dn;
+                       ddw_win = true;
+                       break;
+               }
+               ddw_prop = of_get_property(dn, DMA64_PROPNAME, NULL);
+               if (ddw_prop) {
+                       rdn = dn;
+                       ddw_win = true;
+                       break;
                }
-               dw = of_get_property(dn, DIRECT64_PROPNAME, NULL);
-               if (dw)
-                       return dn;
-               dw = of_get_property(dn, DMA64_PROPNAME, NULL);
-               if (dw)
-                       return dn;
+
+               /* At least found default window, which is the case for normal boot */
+               if (default_win)
+                       break;
        }
 
-       return NULL;
+       /* For PCI devices there will always be a DMA window, either on the device
+        * or parent bus
+        */
+       WARN_ON(!(default_win | ddw_win));
+
+       /* caller doesn't want to get DMA window property */
+       if (!prop)
+               return rdn;
+
+       /* parse DMA window property. During normal system boot, only default
+        * DMA window is passed in OF. But, for kdump, a dedicated adapter might
+        * have both default and DDW in FDT. In this scenario, DDW takes precedence
+        * over default window.
+        */
+       if (ddw_win) {
+               struct dynamic_dma_window_prop *p;
+
+               p = (struct dynamic_dma_window_prop *)ddw_prop;
+               prop->liobn = p->liobn;
+               prop->dma_base = p->dma_base;
+               prop->tce_shift = p->tce_shift;
+               prop->window_shift = p->window_shift;
+       } else if (default_win) {
+               unsigned long offset, size, liobn;
+
+               of_parse_dma_window(rdn, default_prop, &liobn, &offset, &size);
+
+               prop->liobn = cpu_to_be32((u32)liobn);
+               prop->dma_base = cpu_to_be64(offset);
+               prop->tce_shift = cpu_to_be32(IOMMU_PAGE_SHIFT_4K);
+               prop->window_shift = cpu_to_be32(order_base_2(size));
+       }
+
+       return rdn;
 }
 
 static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
@@ -751,17 +773,20 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
        struct iommu_table *tbl;
        struct device_node *dn, *pdn;
        struct pci_dn *ppci;
-       const __be32 *dma_window = NULL;
+       struct dynamic_dma_window_prop prop;
 
        dn = pci_bus_to_OF_node(bus);
 
        pr_debug("pci_dma_bus_setup_pSeriesLP: setting up bus %pOF\n",
                 dn);
 
-       pdn = pci_dma_find(dn, &dma_window);
+       pdn = pci_dma_find(dn, &prop);
 
-       if (dma_window == NULL)
-               pr_debug("  no ibm,dma-window property !\n");
+       /* In PPC architecture, there will always be DMA window on bus or one of the
+        * parent bus. During reboot, there will be ibm,dma-window property to
+        * define DMA window. For kdump, there will at least be default window or DDW
+        * or both.
+        */
 
        ppci = PCI_DN(pdn);
 
@@ -771,13 +796,24 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
        if (!ppci->table_group) {
                ppci->table_group = iommu_pseries_alloc_group(ppci->phb->node);
                tbl = ppci->table_group->tables[0];
-               if (dma_window) {
-                       iommu_table_setparms_lpar(ppci->phb, pdn, tbl,
-                                                 ppci->table_group, dma_window);
 
-                       if (!iommu_init_table(tbl, ppci->phb->node, 0, 0))
-                               panic("Failed to initialize iommu table");
-               }
+               iommu_table_setparms_common(tbl, ppci->phb->bus->number,
+                               be32_to_cpu(prop.liobn),
+                               be64_to_cpu(prop.dma_base),
+                               1ULL << be32_to_cpu(prop.window_shift),
+                               be32_to_cpu(prop.tce_shift), NULL,
+                               &iommu_table_lpar_multi_ops);
+
+               /* Only for normal boot with default window. Doesn't matter even
+                * if we set these with DDW which is 64bit during kdump, since
+                * these will not be used during kdump.
+                */
+               ppci->table_group->tce32_start = be64_to_cpu(prop.dma_base);
+               ppci->table_group->tce32_size = 1 << be32_to_cpu(prop.window_shift);
+
+               if (!iommu_init_table(tbl, ppci->phb->node, 0, 0))
+                       panic("Failed to initialize iommu table");
+
                iommu_register_group(ppci->table_group,
                                pci_domain_nr(bus), 0);
                pr_debug("  created table: %p\n", ppci->table_group);
@@ -968,6 +1004,12 @@ static void find_existing_ddw_windows_named(const char *name)
                        continue;
                }
 
+               /* If at the time of system initialization, there are DDWs in OF,
+                * it means this is during kexec. DDW could be direct or dynamic.
+                * We will just mark DDWs as "dynamic" since this is kdump path,
+                * no need to worry about perforance. ddw_list_new_entry() will
+                * set window->direct = false.
+                */
                window = ddw_list_new_entry(pdn, dma64);
                if (!window) {
                        of_node_put(pdn);
@@ -1524,8 +1566,8 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
 {
        struct device_node *pdn, *dn;
        struct iommu_table *tbl;
-       const __be32 *dma_window = NULL;
        struct pci_dn *pci;
+       struct dynamic_dma_window_prop prop;
 
        pr_debug("pci_dma_dev_setup_pSeriesLP: %s\n", pci_name(dev));
 
@@ -1538,7 +1580,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
        dn = pci_device_to_OF_node(dev);
        pr_debug("  node is %pOF\n", dn);
 
-       pdn = pci_dma_find(dn, &dma_window);
+       pdn = pci_dma_find(dn, &prop);
        if (!pdn || !PCI_DN(pdn)) {
                printk(KERN_WARNING "pci_dma_dev_setup_pSeriesLP: "
                       "no DMA window found for pci dev=%s dn=%pOF\n",
@@ -1551,8 +1593,20 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
        if (!pci->table_group) {
                pci->table_group = iommu_pseries_alloc_group(pci->phb->node);
                tbl = pci->table_group->tables[0];
-               iommu_table_setparms_lpar(pci->phb, pdn, tbl,
-                               pci->table_group, dma_window);
+
+               iommu_table_setparms_common(tbl, pci->phb->bus->number,
+                               be32_to_cpu(prop.liobn),
+                               be64_to_cpu(prop.dma_base),
+                               1ULL << be32_to_cpu(prop.window_shift),
+                               be32_to_cpu(prop.tce_shift), NULL,
+                               &iommu_table_lpar_multi_ops);
+
+               /* Only for normal boot with default window. Doesn't matter even
+                * if we set these with DDW which is 64bit during kdump, since
+                * these will not be used during kdump.
+                */
+               pci->table_group->tce32_start = be64_to_cpu(prop.dma_base);
+               pci->table_group->tce32_size = 1 << be32_to_cpu(prop.window_shift);
 
                iommu_init_table(tbl, pci->phb->node, 0, 0);
                iommu_register_group(pci->table_group,
index 4561667832ed403e2a4ce1847bda97d844a12485..4e9916bb03d71fb687f49c989b7f65cce08bd066 100644 (file)
@@ -662,8 +662,12 @@ u64 pseries_paravirt_steal_clock(int cpu)
 {
        struct lppaca *lppaca = &lppaca_of(cpu);
 
-       return be64_to_cpu(READ_ONCE(lppaca->enqueue_dispatch_tb)) +
-               be64_to_cpu(READ_ONCE(lppaca->ready_enqueue_tb));
+       /*
+        * VPA steal time counters are reported at TB frequency. Hence do a
+        * conversion to ns before returning
+        */
+       return tb_to_ns(be64_to_cpu(READ_ONCE(lppaca->enqueue_dispatch_tb)) +
+                       be64_to_cpu(READ_ONCE(lppaca->ready_enqueue_tb)));
 }
 #endif
 
index 4ba8245681192120860ad1278a1b7ec7110a4bfc..4448386268d99155657fe6179ad8fd0132676f13 100644 (file)
@@ -35,6 +35,8 @@ struct pci_controller *init_phb_dynamic(struct device_node *dn)
 
        pseries_msi_allocate_domains(phb);
 
+       ppc_iommu_register_device(phb);
+
        /* Create EEH devices for the PHB */
        eeh_phb_pe_create(phb);
 
@@ -76,6 +78,8 @@ int remove_phb_dynamic(struct pci_controller *phb)
                }
        }
 
+       ppc_iommu_unregister_device(phb);
+
        pseries_msi_free_domains(phb);
 
        /* Keep a reference so phb isn't freed yet */
index 5020044400dcb3caa60d5efebe366249dc7ff65e..4de57ba52236513f5c2f92e42ae4d7059d6e4f2f 100644 (file)
@@ -41,7 +41,7 @@ struct memcons memcons = {
        .input_end = &memcons_input[CONFIG_PPC_MEMCONS_INPUT_SIZE],
 };
 
-void memcons_putc(char c)
+static void memcons_putc(char c)
 {
        char *new_output_pos;
 
@@ -54,7 +54,7 @@ void memcons_putc(char c)
        memcons.output_pos = new_output_pos;
 }
 
-int memcons_getc_poll(void)
+static int memcons_getc_poll(void)
 {
        char c;
        char *new_input_pos;
@@ -77,7 +77,7 @@ int memcons_getc_poll(void)
        return -1;
 }
 
-int memcons_getc(void)
+static int memcons_getc(void)
 {
        int c;
 
index bffbd869a0682842883591788da784648acf1626..d2c257a0da2ac082d8bfcac827f4bc0514afeefb 100644 (file)
@@ -136,6 +136,7 @@ config RISCV
        select HAVE_LD_DEAD_CODE_DATA_ELIMINATION if !LD_IS_LLD
        select HAVE_MOVE_PMD
        select HAVE_MOVE_PUD
+       select HAVE_PAGE_SIZE_4KB
        select HAVE_PCI
        select HAVE_PERF_EVENTS
        select HAVE_PERF_REGS
@@ -315,7 +316,6 @@ config AS_HAS_OPTION_ARCH
        # https://reviews.llvm.org/D123515
        def_bool y
        depends on $(as-instr, .option arch$(comma) +m)
-       depends on !$(as-instr, .option arch$(comma) -i)
 
 source "arch/riscv/Kconfig.socs"
 source "arch/riscv/Kconfig.errata"
@@ -983,7 +983,19 @@ config RISCV_ISA_FALLBACK
 config BUILTIN_DTB
        bool "Built-in device tree"
        depends on OF && NONPORTABLE
-       default y if XIP_KERNEL
+       help
+         Build a device tree into the Linux image.
+         This option should be selected if no bootloader is being used.
+         If unsure, say N.
+
+
+config BUILTIN_DTB_SOURCE
+       string "Built-in device tree source"
+       depends on BUILTIN_DTB
+       help
+         DTS file path (without suffix, relative to arch/riscv/boot/dts)
+         for the DTS file that will be used to produce the DTB linked into the
+         kernel.
 
 endmenu # "Boot options"
 
index e08e91c49abecf3838a90a8ce8d72b7ca1c90585..623de5f8a2089848372c9ccd314b66db4f8236d4 100644 (file)
@@ -84,36 +84,4 @@ config SOC_CANAAN
        help
          This enables support for Canaan Kendryte K210 SoC platform hardware.
 
-if ARCH_CANAAN
-
-config ARCH_CANAAN_K210_DTB_BUILTIN
-       def_bool SOC_CANAAN_K210_DTB_BUILTIN
-
-config SOC_CANAAN_K210_DTB_BUILTIN
-       bool "Builtin device tree for the Canaan Kendryte K210"
-       depends on ARCH_CANAAN
-       default y
-       select OF
-       select BUILTIN_DTB
-       help
-         Build a device tree for the Kendryte K210 into the Linux image.
-         This option should be selected if no bootloader is being used.
-         If unsure, say Y.
-
-config ARCH_CANAAN_K210_DTB_SOURCE
-       string
-       default SOC_CANAAN_K210_DTB_SOURCE
-
-config SOC_CANAAN_K210_DTB_SOURCE
-       string "Source file for the Canaan Kendryte K210 builtin DTB"
-       depends on ARCH_CANAAN
-       depends on ARCH_CANAAN_K210_DTB_BUILTIN
-       default "k210_generic"
-       help
-         Base name (without suffix, relative to arch/riscv/boot/dts/canaan)
-         for the DTS file that will be used to produce the DTB linked into the
-         kernel.
-
-endif # ARCH_CANAAN
-
 endmenu # "SoC selection"
index 72030fd727af64be783c19d0c4654c9c10e89caf..fdae05bbf5563e1caf3a2b870b35841479fb77bb 100644 (file)
@@ -8,4 +8,4 @@ subdir-y += sophgo
 subdir-y += starfive
 subdir-y += thead
 
-obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
+obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix .dtb.o, $(CONFIG_BUILTIN_DTB_SOURCE))
index 520623264c87a5c0d2bb64425b2a0afc5b9e0e99..987d1f0c41f0e8473bafede018a6d8ba1a58fd08 100644 (file)
@@ -5,5 +5,3 @@ dtb-$(CONFIG_ARCH_CANAAN) += sipeed_maix_bit.dtb
 dtb-$(CONFIG_ARCH_CANAAN) += sipeed_maix_dock.dtb
 dtb-$(CONFIG_ARCH_CANAAN) += sipeed_maix_go.dtb
 dtb-$(CONFIG_ARCH_CANAAN) += sipeed_maixduino.dtb
-
-obj-$(CONFIG_ARCH_CANAAN_K210_DTB_BUILTIN) += $(addsuffix .dtb.o, $(CONFIG_ARCH_CANAAN_K210_DTB_SOURCE))
index 45adc4926e799d0d2a602a4b4bdf330b12a50693..e177815bf1a2f56937141d696d90383558e89bf6 100644 (file)
@@ -4,4 +4,3 @@ dtb-$(CONFIG_ARCH_MICROCHIP_POLARFIRE) += mpfs-m100pfsevp.dtb
 dtb-$(CONFIG_ARCH_MICROCHIP_POLARFIRE) += mpfs-polarberry.dtb
 dtb-$(CONFIG_ARCH_MICROCHIP_POLARFIRE) += mpfs-sev-kit.dtb
 dtb-$(CONFIG_ARCH_MICROCHIP_POLARFIRE) += mpfs-tysom-m.dtb
-obj-$(CONFIG_BUILTIN_DTB) += $(addsuffix .o, $(dtb-y))
index 6a5fbd4ed96a09e4a10e21b74f1ddde32f5dca5d..495bf760a909c8b0a6921f23acb685aa7af2832d 100644 (file)
@@ -1,4 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_SIFIVE) += hifive-unleashed-a00.dtb \
                             hifive-unmatched-a00.dtb
-obj-$(CONFIG_BUILTIN_DTB) += $(addsuffix .o, $(dtb-y))
index 07387f9c135ca7e8ddf7d45de10ccdb933a2e4d4..72b87b08ab444ef1dc1ed200a6e8b3cbb9bfc73f 100644 (file)
                interrupt-parent = <&gpio>;
                interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
                interrupt-controller;
+               #interrupt-cells = <2>;
 
                onkey {
                        compatible = "dlg,da9063-onkey";
index ead1cc35d88b2f13bfecf935a6e66e6049a24a75..81fda312f988c9d91a250ba3a91819fef75bdd47 100644 (file)
@@ -6,6 +6,8 @@
 /dts-v1/;
 #include <dt-bindings/interrupt-controller/irq.h>
 
+#include <dt-bindings/reset/sophgo,sg2042-reset.h>
+
 #include "sg2042-cpus.dtsi"
 
 / {
                        riscv,ndev = <224>;
                };
 
+               rstgen: reset-controller@7030013000 {
+                       compatible = "sophgo,sg2042-reset";
+                       reg = <0x00000070 0x30013000 0x00000000 0x0000000c>;
+                       #reset-cells = <1>;
+               };
+
                uart0: serial@7040000000 {
                        compatible = "snps,dw-apb-uart";
                        reg = <0x00000070 0x40000000 0x00000000 0x00001000>;
                        clock-frequency = <500000000>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
+                       resets = <&rstgen RST_UART0>;
                        status = "disabled";
                };
        };
index c216aaecac53f2d7d1ec47b4f250ea5ae08e11cb..5d499d8aa8044672664af972d788819a56ca3f55 100644 (file)
                        thermal-sensors = <&sfctemp>;
 
                        trips {
-                               cpu_alert0 {
+                               cpu-alert0 {
                                        /* milliCelsius */
                                        temperature = <75000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit {
+                               cpu-crit {
                                        /* milliCelsius */
                                        temperature = <90000>;
                                        hysteresis = <2000>;
                };
        };
 
-       osc_sys: osc_sys {
+       osc_sys: osc-sys {
                compatible = "fixed-clock";
                #clock-cells = <0>;
+               clock-output-names = "osc_sys";
                /* This value must be overridden by the board */
                clock-frequency = <0>;
        };
 
-       osc_aud: osc_aud {
+       osc_aud: osc-aud {
                compatible = "fixed-clock";
                #clock-cells = <0>;
+               clock-output-names = "osc_aud";
                /* This value must be overridden by the board */
                clock-frequency = <0>;
        };
 
-       gmac_rmii_ref: gmac_rmii_ref {
+       gmac_rmii_ref: gmac-rmii-ref {
                compatible = "fixed-clock";
                #clock-cells = <0>;
+               clock-output-names = "gmac_rmii_ref";
                /* Should be overridden by the board when needed */
                clock-frequency = <0>;
        };
 
-       gmac_gr_mii_rxclk: gmac_gr_mii_rxclk {
+       gmac_gr_mii_rxclk: gmac-gr-mii-rxclk {
                compatible = "fixed-clock";
                #clock-cells = <0>;
+               clock-output-names = "gmac_gr_mii_rxclk";
                /* Should be overridden by the board when needed */
                clock-frequency = <0>;
        };
index 45213cdf50dc75a9fa6610710a4d0cbe58b44c51..74ed3b9264d8f15ee10400b4bf5fcf855b7cecd0 100644 (file)
                        };
 
                        trips {
-                               cpu_alert0: cpu_alert0 {
+                               cpu_alert0: cpu-alert0 {
                                        /* milliCelsius */
                                        temperature = <85000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
 
-                               cpu_crit {
+                               cpu-crit {
                                        /* milliCelsius */
                                        temperature = <100000>;
                                        hysteresis = <2000>;
index 146c46d0525b4afd7a298dcc612715a23b4daea0..7e75200543f453eadeec1bce6214d6a9d9e9a325 100644 (file)
@@ -33,6 +33,8 @@ CONFIG_SMP=y
 CONFIG_NR_CPUS=2
 CONFIG_CMDLINE="earlycon console=ttySIF0"
 CONFIG_CMDLINE_FORCE=y
+CONFIG_BUILTIN_DTB=y
+CONFIG_BUILTIN_DTB_SOURCE="canaan/k210_generic"
 # CONFIG_SECCOMP is not set
 # CONFIG_STACKPROTECTOR is not set
 # CONFIG_GCC_PLUGINS is not set
index 95d8d1808f194dfd4c38c4993a919f603b3e7343..0ba353e9ca71eebc91fbcb19dcda95d66613459a 100644 (file)
@@ -25,6 +25,8 @@ CONFIG_SMP=y
 CONFIG_NR_CPUS=2
 CONFIG_CMDLINE="earlycon console=ttySIF0 root=/dev/mmcblk0p1 rootwait ro"
 CONFIG_CMDLINE_FORCE=y
+CONFIG_BUILTIN_DTB=y
+CONFIG_BUILTIN_DTB_SOURCE="canaan/k210_generic"
 # CONFIG_SECCOMP is not set
 # CONFIG_STACKPROTECTOR is not set
 # CONFIG_GCC_PLUGINS is not set
index 510014051f5dbb1aa61098e4974e7e7ac02145ee..2468c55933cd0d5d55d71d83a52226172bd5121c 100644 (file)
 # define CSR_STATUS    CSR_MSTATUS
 # define CSR_IE                CSR_MIE
 # define CSR_TVEC      CSR_MTVEC
+# define CSR_ENVCFG    CSR_MENVCFG
 # define CSR_SCRATCH   CSR_MSCRATCH
 # define CSR_EPC       CSR_MEPC
 # define CSR_CAUSE     CSR_MCAUSE
 # define CSR_STATUS    CSR_SSTATUS
 # define CSR_IE                CSR_SIE
 # define CSR_TVEC      CSR_STVEC
+# define CSR_ENVCFG    CSR_SENVCFG
 # define CSR_SCRATCH   CSR_SSCRATCH
 # define CSR_EPC       CSR_SEPC
 # define CSR_CAUSE     CSR_SCAUSE
index 3291721229523456247532009bc2ed2ddc444540..15055f9df4daa1e4250c8a37c64193bf5c943ee3 100644 (file)
 
 #define ARCH_SUPPORTS_FTRACE_OPS 1
 #ifndef __ASSEMBLY__
+
+extern void *return_address(unsigned int level);
+
+#define ftrace_return_address(n) return_address(n)
+
 void MCOUNT_NAME(void);
 static inline unsigned long ftrace_call_adjust(unsigned long addr)
 {
index 20f9c3ba2341412812ba003caf86f546c162bd34..22deb7a2a6ec4e4daba8322c7c6c28137b49f5f8 100644 (file)
@@ -11,8 +11,10 @@ static inline void arch_clear_hugepage_flags(struct page *page)
 }
 #define arch_clear_hugepage_flags arch_clear_hugepage_flags
 
+#ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION
 bool arch_hugetlb_migration_supported(struct hstate *h);
 #define arch_hugetlb_migration_supported arch_hugetlb_migration_supported
+#endif
 
 #ifdef CONFIG_RISCV_ISA_SVNAPOT
 #define __HAVE_ARCH_HUGE_PTE_CLEAR
index 5340f818746b71a805319eb6f941fa311c9b36a2..1f2d2599c655d20be6df7516382e20a7e3956301 100644 (file)
@@ -81,6 +81,8 @@
 #define RISCV_ISA_EXT_ZTSO             72
 #define RISCV_ISA_EXT_ZACAS            73
 
+#define RISCV_ISA_EXT_XLINUXENVCFG     127
+
 #define RISCV_ISA_EXT_MAX              128
 #define RISCV_ISA_EXT_INVALID          U32_MAX
 
index 57e887bfa34cb70b3d829d13dbb80c3fc6bf7ba9..2947423b5082e9b7f69b25a347685af499258161 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/pfn.h>
 #include <linux/const.h>
 
-#define PAGE_SHIFT     (12)
+#define PAGE_SHIFT     CONFIG_PAGE_SHIFT
 #define PAGE_SIZE      (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE - 1))
 
index d169a4f41a2e728276a97898e1270c7b4763f9ed..c80bb9990d32ef706452d7d4fcc1c049cd7436d9 100644 (file)
@@ -95,7 +95,13 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
                __pud_free(mm, pud);
 }
 
-#define __pud_free_tlb(tlb, pud, addr)  pud_free((tlb)->mm, pud)
+#define __pud_free_tlb(tlb, pud, addr)                                 \
+do {                                                                   \
+       if (pgtable_l4_enabled) {                                       \
+               pagetable_pud_dtor(virt_to_ptdesc(pud));                \
+               tlb_remove_page_ptdesc((tlb), virt_to_ptdesc(pud));     \
+       }                                                               \
+} while (0)
 
 #define p4d_alloc_one p4d_alloc_one
 static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long addr)
@@ -124,7 +130,11 @@ static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d)
                __p4d_free(mm, p4d);
 }
 
-#define __p4d_free_tlb(tlb, p4d, addr)  p4d_free((tlb)->mm, p4d)
+#define __p4d_free_tlb(tlb, p4d, addr)                                 \
+do {                                                                   \
+       if (pgtable_l5_enabled)                                         \
+               tlb_remove_page_ptdesc((tlb), virt_to_ptdesc(p4d));     \
+} while (0)
 #endif /* __PAGETABLE_PMD_FOLDED */
 
 static inline void sync_kernel_mappings(pgd_t *pgd)
@@ -149,7 +159,11 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
 #ifndef __PAGETABLE_PMD_FOLDED
 
-#define __pmd_free_tlb(tlb, pmd, addr)  pmd_free((tlb)->mm, pmd)
+#define __pmd_free_tlb(tlb, pmd, addr)                         \
+do {                                                           \
+       pagetable_pmd_dtor(virt_to_ptdesc(pmd));                \
+       tlb_remove_page_ptdesc((tlb), virt_to_ptdesc(pmd));     \
+} while (0)
 
 #endif /* __PAGETABLE_PMD_FOLDED */
 
index b42017d76924f74386bc712719280af21781bb5d..b99bd66107a69038c835ead6b77725aaeaf882c3 100644 (file)
@@ -136,7 +136,7 @@ enum napot_cont_order {
  * 10010 - IO   Strongly-ordered, Non-cacheable, Non-bufferable, Shareable, Non-trustable
  */
 #define _PAGE_PMA_THEAD                ((1UL << 62) | (1UL << 61) | (1UL << 60))
-#define _PAGE_NOCACHE_THEAD    ((1UL < 61) | (1UL << 60))
+#define _PAGE_NOCACHE_THEAD    ((1UL << 61) | (1UL << 60))
 #define _PAGE_IO_THEAD         ((1UL << 63) | (1UL << 60))
 #define _PAGE_MTMASK_THEAD     (_PAGE_PMA_THEAD | _PAGE_IO_THEAD | (1UL << 59))
 
index 0c94260b5d0c126f6302f39a59507f19eed48dac..6066822e7396fa5078a546356a3a6f6605470712 100644 (file)
@@ -84,7 +84,7 @@
  * Define vmemmap for pfn_to_page & page_to_pfn calls. Needed if kernel
  * is configured with CONFIG_SPARSEMEM_VMEMMAP enabled.
  */
-#define vmemmap                ((struct page *)VMEMMAP_START)
+#define vmemmap                ((struct page *)VMEMMAP_START - (phys_ram_base >> PAGE_SHIFT))
 
 #define PCI_IO_SIZE      SZ_16M
 #define PCI_IO_END       VMEMMAP_START
@@ -439,6 +439,10 @@ static inline pte_t pte_mkhuge(pte_t pte)
        return pte;
 }
 
+#define pte_leaf_size(pte)     (pte_napot(pte) ?                               \
+                                       napot_cont_size(napot_cont_order(pte)) :\
+                                       PAGE_SIZE)
+
 #ifdef CONFIG_NUMA_BALANCING
 /*
  * See the comment in include/asm-generic/pgtable.h
index 02f87867389a9e660f91b64c7ca818a6b61637dc..491296a335d0ce6cd9c8f242646c3c60c762bc87 100644 (file)
@@ -14,6 +14,7 @@ struct suspend_context {
        struct pt_regs regs;
        /* Saved and restored by high-level functions */
        unsigned long scratch;
+       unsigned long envcfg;
        unsigned long tvec;
        unsigned long ie;
 #ifdef CONFIG_MMU
index 924d01b56c9a1eb1eacd53a923fc55591cda654f..51f6dfe19745aa486bd73d7de472faa538cf0486 100644 (file)
@@ -19,65 +19,6 @@ static inline bool arch_vmap_pmd_supported(pgprot_t prot)
        return true;
 }
 
-#ifdef CONFIG_RISCV_ISA_SVNAPOT
-#include <linux/pgtable.h>
+#endif
 
-#define arch_vmap_pte_range_map_size arch_vmap_pte_range_map_size
-static inline unsigned long arch_vmap_pte_range_map_size(unsigned long addr, unsigned long end,
-                                                        u64 pfn, unsigned int max_page_shift)
-{
-       unsigned long map_size = PAGE_SIZE;
-       unsigned long size, order;
-
-       if (!has_svnapot())
-               return map_size;
-
-       for_each_napot_order_rev(order) {
-               if (napot_cont_shift(order) > max_page_shift)
-                       continue;
-
-               size = napot_cont_size(order);
-               if (end - addr < size)
-                       continue;
-
-               if (!IS_ALIGNED(addr, size))
-                       continue;
-
-               if (!IS_ALIGNED(PFN_PHYS(pfn), size))
-                       continue;
-
-               map_size = size;
-               break;
-       }
-
-       return map_size;
-}
-
-#define arch_vmap_pte_supported_shift arch_vmap_pte_supported_shift
-static inline int arch_vmap_pte_supported_shift(unsigned long size)
-{
-       int shift = PAGE_SHIFT;
-       unsigned long order;
-
-       if (!has_svnapot())
-               return shift;
-
-       WARN_ON_ONCE(size >= PMD_SIZE);
-
-       for_each_napot_order_rev(order) {
-               if (napot_cont_size(order) > size)
-                       continue;
-
-               if (!IS_ALIGNED(size, napot_cont_size(order)))
-                       continue;
-
-               shift = napot_cont_shift(order);
-               break;
-       }
-
-       return shift;
-}
-
-#endif /* CONFIG_RISCV_ISA_SVNAPOT */
-#endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
 #endif /* _ASM_RISCV_VMALLOC_H */
index f71910718053d841a361fd97e7d62da4f86bebcf..604d6bf7e47672e9b01902f6fa497aeb4e102ee5 100644 (file)
@@ -7,6 +7,7 @@ ifdef CONFIG_FTRACE
 CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_patch.o  = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_sbi.o    = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_return_address.o = $(CC_FLAGS_FTRACE)
 endif
 CFLAGS_syscall_table.o += $(call cc-option,-Wno-override-init,)
 CFLAGS_compat_syscall_table.o += $(call cc-option,-Wno-override-init,)
@@ -46,6 +47,7 @@ obj-y += irq.o
 obj-y  += process.o
 obj-y  += ptrace.o
 obj-y  += reset.o
+obj-y  += return_address.o
 obj-y  += setup.o
 obj-y  += signal.o
 obj-y  += syscall_table.o
index 89920f84d0a34385471e9afbf9c26d287cbbd838..79a5a35fab964d3b54db97b5504f45f68dface11 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/hwprobe.h>
 #include <asm/patch.h>
 #include <asm/processor.h>
+#include <asm/sbi.h>
 #include <asm/vector.h>
 
 #include "copy-unaligned.h"
@@ -201,6 +202,16 @@ static const unsigned int riscv_zvbb_exts[] = {
        RISCV_ISA_EXT_ZVKB
 };
 
+/*
+ * While the [ms]envcfg CSRs were not defined until version 1.12 of the RISC-V
+ * privileged ISA, the existence of the CSRs is implied by any extension which
+ * specifies [ms]envcfg bit(s). Hence, we define a custom ISA extension for the
+ * existence of the CSR, and treat it as a subset of those other extensions.
+ */
+static const unsigned int riscv_xlinuxenvcfg_exts[] = {
+       RISCV_ISA_EXT_XLINUXENVCFG
+};
+
 /*
  * The canonical order of ISA extension names in the ISA string is defined in
  * chapter 27 of the unprivileged specification.
@@ -250,8 +261,8 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
        __RISCV_ISA_EXT_DATA(c, RISCV_ISA_EXT_c),
        __RISCV_ISA_EXT_DATA(v, RISCV_ISA_EXT_v),
        __RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h),
-       __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM),
-       __RISCV_ISA_EXT_DATA(zicboz, RISCV_ISA_EXT_ZICBOZ),
+       __RISCV_ISA_EXT_SUPERSET(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts),
+       __RISCV_ISA_EXT_SUPERSET(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts),
        __RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR),
        __RISCV_ISA_EXT_DATA(zicond, RISCV_ISA_EXT_ZICOND),
        __RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR),
@@ -538,6 +549,20 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap)
                        set_bit(RISCV_ISA_EXT_ZIHPM, isainfo->isa);
                }
 
+               /*
+                * "V" in ISA strings is ambiguous in practice: it should mean
+                * just the standard V-1.0 but vendors aren't well behaved.
+                * Many vendors with T-Head CPU cores which implement the 0.7.1
+                * version of the vector specification put "v" into their DTs.
+                * CPU cores with the ratified spec will contain non-zero
+                * marchid.
+                */
+               if (acpi_disabled && riscv_cached_mvendorid(cpu) == THEAD_VENDOR_ID &&
+                   riscv_cached_marchid(cpu) == 0x0) {
+                       this_hwcap &= ~isa2hwcap[RISCV_ISA_EXT_v];
+                       clear_bit(RISCV_ISA_EXT_v, isainfo->isa);
+               }
+
                /*
                 * All "okay" hart should have same isa. Set HWCAP based on
                 * common capabilities of every "okay" hart, in case they don't
@@ -950,7 +975,7 @@ arch_initcall(check_unaligned_access_all_cpus);
 void riscv_user_isa_enable(void)
 {
        if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_ZICBOZ))
-               csr_set(CSR_SENVCFG, ENVCFG_CBZE);
+               csr_set(CSR_ENVCFG, ENVCFG_CBZE);
 }
 
 #ifdef CONFIG_RISCV_ALTERNATIVE
index 8e114f5930cec6148b98f7f81abd72a798caf8e8..0d6225fd3194e14ed71ac9afc716b2e81168e9a5 100644 (file)
@@ -41,7 +41,7 @@ static int __init parse_no_stealacc(char *arg)
 
 early_param("no-steal-acc", parse_no_stealacc);
 
-DEFINE_PER_CPU(struct sbi_sta_struct, steal_time) __aligned(64);
+static DEFINE_PER_CPU(struct sbi_sta_struct, steal_time) __aligned(64);
 
 static bool __init has_pv_steal_clock(void)
 {
@@ -91,8 +91,8 @@ static int pv_time_cpu_down_prepare(unsigned int cpu)
 static u64 pv_time_steal_clock(int cpu)
 {
        struct sbi_sta_struct *st = per_cpu_ptr(&steal_time, cpu);
-       u32 sequence;
-       u64 steal;
+       __le32 sequence;
+       __le64 steal;
 
        /*
         * Check the sequence field before and after reading the steal
diff --git a/arch/riscv/kernel/return_address.c b/arch/riscv/kernel/return_address.c
new file mode 100644 (file)
index 0000000..c8115ec
--- /dev/null
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * This code come from arch/arm64/kernel/return_address.c
+ *
+ * Copyright (C) 2023 SiFive.
+ */
+
+#include <linux/export.h>
+#include <linux/kprobes.h>
+#include <linux/stacktrace.h>
+
+struct return_address_data {
+       unsigned int level;
+       void *addr;
+};
+
+static bool save_return_addr(void *d, unsigned long pc)
+{
+       struct return_address_data *data = d;
+
+       if (!data->level) {
+               data->addr = (void *)pc;
+               return false;
+       }
+
+       --data->level;
+
+       return true;
+}
+NOKPROBE_SYMBOL(save_return_addr);
+
+noinline void *return_address(unsigned int level)
+{
+       struct return_address_data data;
+
+       data.level = level + 3;
+       data.addr = NULL;
+
+       arch_stack_walk(save_return_addr, &data, current, NULL);
+
+       if (!data.level)
+               return data.addr;
+       else
+               return NULL;
+
+}
+EXPORT_SYMBOL_GPL(return_address);
+NOKPROBE_SYMBOL(return_address);
index 519b6bd946e5d1b69edf3379e31b345e38a03deb..c4ed7d977f57b2c305e5ecbf2b767fd9b0c175df 100644 (file)
 
 static DECLARE_COMPLETION(cpu_running);
 
-void __init smp_prepare_boot_cpu(void)
-{
-}
-
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
        int cpuid;
index 239509367e4233336806c19da964a06537d5a9b5..299795341e8a2207dc922373511e31118bbd0f8b 100644 (file)
@@ -15,6 +15,8 @@
 void suspend_save_csrs(struct suspend_context *context)
 {
        context->scratch = csr_read(CSR_SCRATCH);
+       if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_XLINUXENVCFG))
+               context->envcfg = csr_read(CSR_ENVCFG);
        context->tvec = csr_read(CSR_TVEC);
        context->ie = csr_read(CSR_IE);
 
@@ -36,6 +38,8 @@ void suspend_save_csrs(struct suspend_context *context)
 void suspend_restore_csrs(struct suspend_context *context)
 {
        csr_write(CSR_SCRATCH, context->scratch);
+       if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_XLINUXENVCFG))
+               csr_write(CSR_ENVCFG, context->envcfg);
        csr_write(CSR_TVEC, context->tvec);
        csr_write(CSR_IE, context->ie);
 
index 2cf76218a5bd02c8f148318f78abd648dab276bf..98315b98256df412d48479c0114b5a5b49a7b583 100644 (file)
@@ -30,14 +30,8 @@ enum rv_vdso_map {
 
 #define VVAR_SIZE  (VVAR_NR_PAGES << PAGE_SHIFT)
 
-/*
- * The vDSO data page.
- */
-static union {
-       struct vdso_data        data;
-       u8                      page[PAGE_SIZE];
-} vdso_data_store __page_aligned_data;
-struct vdso_data *vdso_data = &vdso_data_store.data;
+static union vdso_data_store vdso_data_store __page_aligned_data;
+struct vdso_data *vdso_data = vdso_data_store.data;
 
 struct __vdso_info {
        const char *name;
index 01f09fe8c3b020968be3f623097c9a48ab958087..d8cf9ca28c616e9d4073465a71dcc7479be3d35a 100644 (file)
@@ -26,8 +26,12 @@ void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu)
 {
        gpa_t shmem = vcpu->arch.sta.shmem;
        u64 last_steal = vcpu->arch.sta.last_steal;
-       u32 *sequence_ptr, sequence;
-       u64 *steal_ptr, steal;
+       __le32 __user *sequence_ptr;
+       __le64 __user *steal_ptr;
+       __le32 sequence_le;
+       __le64 steal_le;
+       u32 sequence;
+       u64 steal;
        unsigned long hva;
        gfn_t gfn;
 
@@ -47,22 +51,22 @@ void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu)
                return;
        }
 
-       sequence_ptr = (u32 *)(hva + offset_in_page(shmem) +
+       sequence_ptr = (__le32 __user *)(hva + offset_in_page(shmem) +
                               offsetof(struct sbi_sta_struct, sequence));
-       steal_ptr = (u64 *)(hva + offset_in_page(shmem) +
+       steal_ptr = (__le64 __user *)(hva + offset_in_page(shmem) +
                            offsetof(struct sbi_sta_struct, steal));
 
-       if (WARN_ON(get_user(sequence, sequence_ptr)))
+       if (WARN_ON(get_user(sequence_le, sequence_ptr)))
                return;
 
-       sequence = le32_to_cpu(sequence);
+       sequence = le32_to_cpu(sequence_le);
        sequence += 1;
 
        if (WARN_ON(put_user(cpu_to_le32(sequence), sequence_ptr)))
                return;
 
-       if (!WARN_ON(get_user(steal, steal_ptr))) {
-               steal = le64_to_cpu(steal);
+       if (!WARN_ON(get_user(steal_le, steal_ptr))) {
+               steal = le64_to_cpu(steal_le);
                vcpu->arch.sta.last_steal = READ_ONCE(current->sched_info.run_delay);
                steal += vcpu->arch.sta.last_steal - last_steal;
                WARN_ON(put_user(cpu_to_le64(steal), steal_ptr));
index 29c7606414d276d1c3639e2a80e10037ea899cfc..5ef2a6891158a6d59de8f36b4f4d98cf3ad6eb2a 100644 (file)
@@ -426,10 +426,12 @@ bool __init arch_hugetlb_valid_size(unsigned long size)
        return __hugetlb_valid_size(size);
 }
 
+#ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION
 bool arch_hugetlb_migration_supported(struct hstate *h)
 {
        return __hugetlb_valid_size(huge_page_size(h));
 }
+#endif
 
 #ifdef CONFIG_CONTIG_ALLOC
 static __init int gigantic_pages_init(void)
index fe565f3a3a917d0da83dbd8329a503910fa41948..36e14e7c8f87eb8275b8ccf6d882b83f9997ffe0 100644 (file)
@@ -127,6 +127,7 @@ config S390
        select ARCH_WANT_DEFAULT_BPF_JIT
        select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_WANT_KERNEL_PMD_MKWRITE
+       select ARCH_WANT_LD_ORPHAN_WARN
        select ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP
        select BUILDTIME_TABLE_SORT
        select CLONE_BACKWARDS2
@@ -199,6 +200,7 @@ config S390
        select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_NMI
        select HAVE_NOP_MCOUNT
+       select HAVE_PAGE_SIZE_4KB
        select HAVE_PCI
        select HAVE_PERF_EVENTS
        select HAVE_PERF_REGS
@@ -448,7 +450,7 @@ config COMPAT
        select COMPAT_OLD_SIGACTION
        select HAVE_UID16
        depends on MULTIUSER
-       depends on !CC_IS_CLANG
+       depends on !CC_IS_CLANG && !LD_IS_LLD
        help
          Select this option if you want to enable your system kernel to
          handle system-calls from ELF binaries for 31 bit ESA.  This option
@@ -582,14 +584,23 @@ config RELOCATABLE
        help
          This builds a kernel image that retains relocation information
          so it can be loaded at an arbitrary address.
-         The kernel is linked as a position-independent executable (PIE)
-         and contains dynamic relocations which are processed early in the
-         bootup process.
          The relocations make the kernel image about 15% larger (compressed
          10%), but are discarded at runtime.
          Note: this option exists only for documentation purposes, please do
          not remove it.
 
+config PIE_BUILD
+       def_bool CC_IS_CLANG && !$(cc-option,-munaligned-symbols)
+       help
+         If the compiler is unable to generate code that can manage unaligned
+         symbols, the kernel is linked as a position-independent executable
+         (PIE) and includes dynamic relocations that are processed early
+         during bootup.
+
+         For kpatch functionality, it is recommended to build the kernel
+         without the PIE_BUILD option. PIE_BUILD is only enabled when the
+         compiler lacks proper support for handling unaligned symbols.
+
 config RANDOMIZE_BASE
        bool "Randomize the address of the kernel image (KASLR)"
        default y
index 73873e4516866ab16239edc1427f7889d954acff..2a58e1864931913dbbcc78cf76545775fa000630 100644 (file)
@@ -14,8 +14,14 @@ KBUILD_AFLAGS_MODULE += -fPIC
 KBUILD_CFLAGS_MODULE += -fPIC
 KBUILD_AFLAGS  += -m64
 KBUILD_CFLAGS  += -m64
+ifdef CONFIG_PIE_BUILD
 KBUILD_CFLAGS  += -fPIE
-LDFLAGS_vmlinux        := -pie
+LDFLAGS_vmlinux        := -pie -z notext
+else
+KBUILD_CFLAGS  += $(call cc-option,-munaligned-symbols,)
+LDFLAGS_vmlinux        := --emit-relocs --discard-none
+extra_tools    := relocs
+endif
 aflags_dwarf   := -Wa,-gdwarf-2
 KBUILD_AFLAGS_DECOMPRESSOR := $(CLANG_FLAGS) -m64 -D__ASSEMBLY__
 ifndef CONFIG_AS_IS_LLVM
@@ -143,7 +149,7 @@ archheaders:
 
 archprepare:
        $(Q)$(MAKE) $(build)=$(syscalls) kapi
-       $(Q)$(MAKE) $(build)=$(tools) kapi
+       $(Q)$(MAKE) $(build)=$(tools) kapi $(extra_tools)
 ifeq ($(KBUILD_EXTMOD),)
 # We need to generate vdso-offsets.h before compiling certain files in kernel/.
 # In order to do that, we should use the archprepare target, but we can't since
index f56591bc089754fee1a4f67f19f38a0bd22696ba..f5ef099e2fd33a7a6d2ebbacfcc424ab0ab023ad 100644 (file)
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 image
 bzImage
+relocs.S
 section_cmp.*
 vmlinux
 vmlinux.lds
index c7c81e5f9218993f5726bf20228e2594ce2fe40c..294f08a8811a2211442bbf659cbaddc93cd59dd6 100644 (file)
@@ -37,7 +37,8 @@ CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char
 
 obj-y  := head.o als.o startup.o physmem_info.o ipl_parm.o ipl_report.o vmem.o
 obj-y  += string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o
-obj-y  += version.o pgm_check_info.o ctype.o ipl_data.o machine_kexec_reloc.o
+obj-y  += version.o pgm_check_info.o ctype.o ipl_data.o
+obj-y  += $(if $(CONFIG_PIE_BUILD),machine_kexec_reloc.o,relocs.o)
 obj-$(findstring y, $(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) $(CONFIG_PGSTE))  += uv.o
 obj-$(CONFIG_RANDOMIZE_BASE)   += kaslr.o
 obj-y  += $(if $(CONFIG_KERNEL_UNCOMPRESSED),,decompressor.o) info.o
@@ -48,6 +49,9 @@ targets       := bzImage section_cmp.boot.data section_cmp.boot.preserved.data $(obj-y
 targets        += vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2
 targets += vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.lz4
 targets += vmlinux.bin.zst info.bin syms.bin vmlinux.syms $(obj-all)
+ifndef CONFIG_PIE_BUILD
+targets += relocs.S
+endif
 
 OBJECTS := $(addprefix $(obj)/,$(obj-y))
 OBJECTS_ALL := $(addprefix $(obj)/,$(obj-all))
@@ -56,9 +60,9 @@ clean-files += vmlinux.map
 
 quiet_cmd_section_cmp = SECTCMP $*
 define cmd_section_cmp
-       s1=`$(OBJDUMP) -t -j "$*" "$<" | sort | \
+       s1=`$(OBJDUMP) -t "$<" | grep "\s$*\s\+" | sort | \
                sed -n "/0000000000000000/! s/.*\s$*\s\+//p" | sha256sum`; \
-       s2=`$(OBJDUMP) -t -j "$*" "$(word 2,$^)" | sort | \
+       s2=`$(OBJDUMP) -t "$(word 2,$^)" | grep "\s$*\s\+" | sort | \
                sed -n "/0000000000000000/! s/.*\s$*\s\+//p" | sha256sum`; \
        if [ "$$s1" != "$$s2" ]; then \
                echo "error: section $* differs between $< and $(word 2,$^)" >&2; \
@@ -73,11 +77,12 @@ $(obj)/bzImage: $(obj)/vmlinux $(obj)/section_cmp.boot.data $(obj)/section_cmp.b
 $(obj)/section_cmp%: vmlinux $(obj)/vmlinux FORCE
        $(call if_changed,section_cmp)
 
-LDFLAGS_vmlinux := --oformat $(LD_BFD) -e startup $(if $(CONFIG_VMLINUX_MAP),-Map=$(obj)/vmlinux.map) --build-id=sha1 -T
+LDFLAGS_vmlinux-$(CONFIG_LD_ORPHAN_WARN) := --orphan-handling=$(CONFIG_LD_ORPHAN_WARN_LEVEL)
+LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y) --oformat $(LD_BFD) -e startup $(if $(CONFIG_VMLINUX_MAP),-Map=$(obj)/vmlinux.map) --build-id=sha1 -T
 $(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS_ALL) FORCE
        $(call if_changed,ld)
 
-LDFLAGS_vmlinux.syms := --oformat $(LD_BFD) -e startup -T
+LDFLAGS_vmlinux.syms := $(LDFLAGS_vmlinux-y) --oformat $(LD_BFD) -e startup -T
 $(obj)/vmlinux.syms: $(obj)/vmlinux.lds $(OBJECTS) FORCE
        $(call if_changed,ld)
 
@@ -93,7 +98,7 @@ OBJCOPYFLAGS_syms.o := -I binary -O elf64-s390 -B s390:64-bit --rename-section .
 $(obj)/syms.o: $(obj)/syms.bin FORCE
        $(call if_changed,objcopy)
 
-OBJCOPYFLAGS_info.bin := -O binary --only-section=.vmlinux.info --set-section-flags .vmlinux.info=load
+OBJCOPYFLAGS_info.bin := -O binary --only-section=.vmlinux.info --set-section-flags .vmlinux.info=alloc,load
 $(obj)/info.bin: vmlinux FORCE
        $(call if_changed,objcopy)
 
@@ -105,6 +110,14 @@ OBJCOPYFLAGS_vmlinux.bin := -O binary --remove-section=.comment --remove-section
 $(obj)/vmlinux.bin: vmlinux FORCE
        $(call if_changed,objcopy)
 
+ifndef CONFIG_PIE_BUILD
+CMD_RELOCS=arch/s390/tools/relocs
+quiet_cmd_relocs = RELOCS $@
+       cmd_relocs = $(CMD_RELOCS) $< > $@
+$(obj)/relocs.S: vmlinux FORCE
+       $(call if_changed,relocs)
+endif
+
 suffix-$(CONFIG_KERNEL_GZIP)  := .gz
 suffix-$(CONFIG_KERNEL_BZIP2) := .bz2
 suffix-$(CONFIG_KERNEL_LZ4)  := .lz4
index 222c6886acf6f7d9cd6bbf149b16c63c85765263..567d60f78bbcca273378a6f66e748df167a4af13 100644 (file)
@@ -25,9 +25,14 @@ struct vmlinux_info {
        unsigned long bootdata_size;
        unsigned long bootdata_preserved_off;
        unsigned long bootdata_preserved_size;
+#ifdef CONFIG_PIE_BUILD
        unsigned long dynsym_start;
        unsigned long rela_dyn_start;
        unsigned long rela_dyn_end;
+#else
+       unsigned long got_start;
+       unsigned long got_end;
+#endif
        unsigned long amode31_size;
        unsigned long init_mm_off;
        unsigned long swapper_pg_dir_off;
@@ -83,6 +88,7 @@ extern unsigned long vmalloc_size;
 extern int vmalloc_size_set;
 extern char __boot_data_start[], __boot_data_end[];
 extern char __boot_data_preserved_start[], __boot_data_preserved_end[];
+extern char __vmlinux_relocs_64_start[], __vmlinux_relocs_64_end[];
 extern char _decompressor_syms_start[], _decompressor_syms_end[];
 extern char _stack_start[], _stack_end[];
 extern char _end[], _decompressor_end[];
index 9cc76e631759b17f16f639a082c3deb8c00f09f2..6cf89314209a628a530ec9142dc70e25aece3b9f 100644 (file)
@@ -141,7 +141,8 @@ static void copy_bootdata(void)
        memcpy((void *)vmlinux.bootdata_preserved_off, __boot_data_preserved_start, vmlinux.bootdata_preserved_size);
 }
 
-static void handle_relocs(unsigned long offset)
+#ifdef CONFIG_PIE_BUILD
+static void kaslr_adjust_relocs(unsigned long min_addr, unsigned long max_addr, unsigned long offset)
 {
        Elf64_Rela *rela_start, *rela_end, *rela;
        int r_type, r_sym, rc;
@@ -172,6 +173,54 @@ static void handle_relocs(unsigned long offset)
        }
 }
 
+static void kaslr_adjust_got(unsigned long offset) {}
+static void rescue_relocs(void) {}
+static void free_relocs(void) {}
+#else
+static int *vmlinux_relocs_64_start;
+static int *vmlinux_relocs_64_end;
+
+static void rescue_relocs(void)
+{
+       unsigned long size = __vmlinux_relocs_64_end - __vmlinux_relocs_64_start;
+
+       vmlinux_relocs_64_start = (void *)physmem_alloc_top_down(RR_RELOC, size, 0);
+       vmlinux_relocs_64_end = (void *)vmlinux_relocs_64_start + size;
+       memmove(vmlinux_relocs_64_start, __vmlinux_relocs_64_start, size);
+}
+
+static void free_relocs(void)
+{
+       physmem_free(RR_RELOC);
+}
+
+static void kaslr_adjust_relocs(unsigned long min_addr, unsigned long max_addr, unsigned long offset)
+{
+       int *reloc;
+       long loc;
+
+       /* Adjust R_390_64 relocations */
+       for (reloc = vmlinux_relocs_64_start; reloc < vmlinux_relocs_64_end; reloc++) {
+               loc = (long)*reloc + offset;
+               if (loc < min_addr || loc > max_addr)
+                       error("64-bit relocation outside of kernel!\n");
+               *(u64 *)loc += offset;
+       }
+}
+
+static void kaslr_adjust_got(unsigned long offset)
+{
+       u64 *entry;
+
+       /*
+        * Even without -fPIE, Clang still uses a global offset table for some
+        * reason. Adjust the GOT entries.
+        */
+       for (entry = (u64 *)vmlinux.got_start; entry < (u64 *)vmlinux.got_end; entry++)
+               *entry += offset;
+}
+#endif
+
 /*
  * Merge information from several sources into a single ident_map_size value.
  * "ident_map_size" represents the upper limit of physical memory we may ever
@@ -299,14 +348,19 @@ static void setup_vmalloc_size(void)
        vmalloc_size = max(size, vmalloc_size);
 }
 
-static void offset_vmlinux_info(unsigned long offset)
+static void kaslr_adjust_vmlinux_info(unsigned long offset)
 {
        *(unsigned long *)(&vmlinux.entry) += offset;
        vmlinux.bootdata_off += offset;
        vmlinux.bootdata_preserved_off += offset;
+#ifdef CONFIG_PIE_BUILD
        vmlinux.rela_dyn_start += offset;
        vmlinux.rela_dyn_end += offset;
        vmlinux.dynsym_start += offset;
+#else
+       vmlinux.got_start += offset;
+       vmlinux.got_end += offset;
+#endif
        vmlinux.init_mm_off += offset;
        vmlinux.swapper_pg_dir_off += offset;
        vmlinux.invalid_pg_dir_off += offset;
@@ -361,6 +415,7 @@ void startup_kernel(void)
        detect_physmem_online_ranges(max_physmem_end);
        save_ipl_cert_comp_list();
        rescue_initrd(safe_addr, ident_map_size);
+       rescue_relocs();
 
        if (kaslr_enabled()) {
                vmlinux_lma = randomize_within_range(vmlinux.image_size + vmlinux.bss_size,
@@ -368,7 +423,7 @@ void startup_kernel(void)
                                                     ident_map_size);
                if (vmlinux_lma) {
                        __kaslr_offset = vmlinux_lma - vmlinux.default_lma;
-                       offset_vmlinux_info(__kaslr_offset);
+                       kaslr_adjust_vmlinux_info(__kaslr_offset);
                }
        }
        vmlinux_lma = vmlinux_lma ?: vmlinux.default_lma;
@@ -393,18 +448,20 @@ void startup_kernel(void)
        /*
         * The order of the following operations is important:
         *
-        * - handle_relocs() must follow clear_bss_section() to establish static
-        *   memory references to data in .bss to be used by setup_vmem()
+        * - kaslr_adjust_relocs() must follow clear_bss_section() to establish
+        *   static memory references to data in .bss to be used by setup_vmem()
         *   (i.e init_mm.pgd)
         *
-        * - setup_vmem() must follow handle_relocs() to be able using
+        * - setup_vmem() must follow kaslr_adjust_relocs() to be able using
         *   static memory references to data in .bss (i.e init_mm.pgd)
         *
-        * - copy_bootdata() must follow setup_vmem() to propagate changes to
-        *   bootdata made by setup_vmem()
+        * - copy_bootdata() must follow setup_vmem() to propagate changes
+        *   to bootdata made by setup_vmem()
         */
        clear_bss_section(vmlinux_lma);
-       handle_relocs(__kaslr_offset);
+       kaslr_adjust_relocs(vmlinux_lma, vmlinux_lma + vmlinux.image_size, __kaslr_offset);
+       kaslr_adjust_got(__kaslr_offset);
+       free_relocs();
        setup_vmem(asce_limit);
        copy_bootdata();
 
index 389df0e0d9e5d58fb89025e7e0eb4c532569e35e..3d7ea585ab9935b9792412d319fc28bfc03de92f 100644 (file)
@@ -31,6 +31,7 @@ SECTIONS
                _text = .;      /* Text */
                *(.text)
                *(.text.*)
+               INIT_TEXT
                _etext = . ;
        }
        .rodata : {
@@ -39,6 +40,9 @@ SECTIONS
                *(.rodata.*)
                _erodata = . ;
        }
+       .got : {
+               *(.got)
+       }
        NOTES
        .data : {
                _data = . ;
@@ -106,6 +110,24 @@ SECTIONS
                _compressed_end = .;
        }
 
+#ifndef CONFIG_PIE_BUILD
+       /*
+        * When the kernel is built with CONFIG_KERNEL_UNCOMPRESSED, the entire
+        * uncompressed vmlinux.bin is positioned in the bzImage decompressor
+        * image at the default kernel LMA of 0x100000, enabling it to be
+        * executed in-place. However, the size of .vmlinux.relocs could be
+        * large enough to cause an overlap with the uncompressed kernel at the
+        * address 0x100000. To address this issue, .vmlinux.relocs is
+        * positioned after the .rodata.compressed.
+        */
+       . = ALIGN(4);
+       .vmlinux.relocs : {
+               __vmlinux_relocs_64_start = .;
+               *(.vmlinux.relocs_64)
+               __vmlinux_relocs_64_end = .;
+       }
+#endif
+
 #define SB_TRAILER_SIZE 32
        /* Trailer needed for Secure Boot */
        . += SB_TRAILER_SIZE; /* make sure .sb.trailer does not overwrite the previous section */
@@ -118,8 +140,34 @@ SECTIONS
        }
        _end = .;
 
+       DWARF_DEBUG
+       ELF_DETAILS
+
+       /*
+        * Make sure that the .got.plt is either completely empty or it
+        * contains only the three reserved double words.
+        */
+       .got.plt : {
+               *(.got.plt)
+       }
+       ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, "Unexpected GOT/PLT entries detected!")
+
+       /*
+        * Sections that should stay zero sized, which is safer to
+        * explicitly check instead of blindly discarding.
+        */
+       .plt : {
+               *(.plt) *(.plt.*) *(.iplt) *(.igot .igot.plt)
+       }
+       ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!")
+       .rela.dyn : {
+               *(.rela.*) *(.rela_*)
+       }
+       ASSERT(SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations (.rela) detected!")
+
        /* Sections to be discarded */
        /DISCARD/ : {
+               COMMON_DISCARDS
                *(.eh_frame)
                *(__ex_table)
                *(*__ksymtab*)
diff --git a/arch/s390/configs/compat.config b/arch/s390/configs/compat.config
new file mode 100644 (file)
index 0000000..6fd0514
--- /dev/null
@@ -0,0 +1,3 @@
+# Help: Enable compat support
+CONFIG_COMPAT=y
+CONFIG_COMPAT_32BIT_TIME=y
index cae2dd34fbb49d16ee020e72fb669010dca832f8..4032e6e136ac1dfb23e207aa6d21e3d62e9c42af 100644 (file)
@@ -118,7 +118,6 @@ CONFIG_UNIX=y
 CONFIG_UNIX_DIAG=m
 CONFIG_XFRM_USER=m
 CONFIG_NET_KEY=m
-CONFIG_SMC=m
 CONFIG_SMC_DIAG=m
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
@@ -374,6 +373,7 @@ CONFIG_NET_ACT_POLICE=m
 CONFIG_NET_ACT_GACT=m
 CONFIG_GACT_PROB=y
 CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
 CONFIG_NET_ACT_NAT=m
 CONFIG_NET_ACT_PEDIT=m
 CONFIG_NET_ACT_SIMP=m
@@ -436,9 +436,6 @@ CONFIG_SCSI_DH_ALUA=m
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
 # CONFIG_MD_BITMAP_FILE is not set
-CONFIG_MD_LINEAR=m
-CONFIG_MD_MULTIPATH=m
-CONFIG_MD_FAULTY=m
 CONFIG_MD_CLUSTER=m
 CONFIG_BCACHE=m
 CONFIG_BLK_DEV_DM=y
@@ -637,7 +634,6 @@ CONFIG_FUSE_FS=y
 CONFIG_CUSE=m
 CONFIG_VIRTIO_FS=m
 CONFIG_OVERLAY_FS=m
-CONFIG_NETFS_SUPPORT=m
 CONFIG_NETFS_STATS=y
 CONFIG_FSCACHE=y
 CONFIG_CACHEFILES=m
@@ -709,7 +705,6 @@ CONFIG_IMA_DEFAULT_HASH_SHA256=y
 CONFIG_IMA_WRITE_POLICY=y
 CONFIG_IMA_APPRAISE=y
 CONFIG_LSM="yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor"
-CONFIG_INIT_STACK_NONE=y
 CONFIG_BUG_ON_DATA_CORRUPTION=y
 CONFIG_CRYPTO_USER=m
 # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
@@ -739,7 +734,6 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
@@ -830,6 +824,8 @@ CONFIG_TEST_LOCKUP=m
 CONFIG_DEBUG_PREEMPT=y
 CONFIG_PROVE_LOCKING=y
 CONFIG_LOCK_STAT=y
+CONFIG_LOCKDEP_BITS=16
+CONFIG_LOCKDEP_CHAINS_BITS=17
 CONFIG_DEBUG_ATOMIC_SLEEP=y
 CONFIG_DEBUG_LOCKING_API_SELFTESTS=y
 CONFIG_DEBUG_IRQFLAGS=y
@@ -886,4 +882,3 @@ CONFIG_ATOMIC64_SELFTEST=y
 CONFIG_STRING_SELFTEST=y
 CONFIG_TEST_BITOPS=m
 CONFIG_TEST_BPF=m
-CONFIG_TEST_LIVEPATCH=m
index 42b988873e5443df15b054d78610697fdf769293..d33f814f78b2c115f31bdbb9bfbe6417258501f0 100644 (file)
@@ -109,7 +109,6 @@ CONFIG_UNIX=y
 CONFIG_UNIX_DIAG=m
 CONFIG_XFRM_USER=m
 CONFIG_NET_KEY=m
-CONFIG_SMC=m
 CONFIG_SMC_DIAG=m
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
@@ -364,6 +363,7 @@ CONFIG_NET_ACT_POLICE=m
 CONFIG_NET_ACT_GACT=m
 CONFIG_GACT_PROB=y
 CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
 CONFIG_NET_ACT_NAT=m
 CONFIG_NET_ACT_PEDIT=m
 CONFIG_NET_ACT_SIMP=m
@@ -426,9 +426,6 @@ CONFIG_SCSI_DH_ALUA=m
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
 # CONFIG_MD_BITMAP_FILE is not set
-CONFIG_MD_LINEAR=m
-CONFIG_MD_MULTIPATH=m
-CONFIG_MD_FAULTY=m
 CONFIG_MD_CLUSTER=m
 CONFIG_BCACHE=m
 CONFIG_BLK_DEV_DM=y
@@ -622,7 +619,6 @@ CONFIG_FUSE_FS=y
 CONFIG_CUSE=m
 CONFIG_VIRTIO_FS=m
 CONFIG_OVERLAY_FS=m
-CONFIG_NETFS_SUPPORT=m
 CONFIG_NETFS_STATS=y
 CONFIG_FSCACHE=y
 CONFIG_CACHEFILES=m
@@ -693,7 +689,6 @@ CONFIG_IMA_DEFAULT_HASH_SHA256=y
 CONFIG_IMA_WRITE_POLICY=y
 CONFIG_IMA_APPRAISE=y
 CONFIG_LSM="yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor"
-CONFIG_INIT_STACK_NONE=y
 CONFIG_BUG_ON_DATA_CORRUPTION=y
 CONFIG_CRYPTO_FIPS=y
 CONFIG_CRYPTO_USER=m
@@ -724,11 +719,9 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_CFB=m
 CONFIG_CRYPTO_HCTR2=m
 CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_OFB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_AEGIS128=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
@@ -815,4 +808,3 @@ CONFIG_KPROBES_SANITY_TEST=m
 CONFIG_PERCPU_TEST=m
 CONFIG_ATOMIC64_SELFTEST=y
 CONFIG_TEST_BPF=m
-CONFIG_TEST_LIVEPATCH=m
index 30d2a16876650e9c3ea32997f771131e6372e2fc..c51f3ec4eb28ab189b7d27d12ca28b98261178e2 100644 (file)
@@ -8,6 +8,7 @@ CONFIG_BPF_SYSCALL=y
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KEXEC=y
 CONFIG_CRASH_DUMP=y
 CONFIG_MARCH_Z13=y
 CONFIG_NR_CPUS=2
@@ -64,7 +65,6 @@ CONFIG_ZFCP=y
 # CONFIG_MISC_FILESYSTEMS is not set
 # CONFIG_NETWORK_FILESYSTEMS is not set
 CONFIG_LSM="yama,loadpin,safesetid,integrity"
-CONFIG_INIT_STACK_NONE=y
 # CONFIG_ZLIB_DFLTCC is not set
 CONFIG_XZ_DEC_MICROLZMA=y
 CONFIG_PRINTK_TIME=y
index ed9959e6f7149e2c0b2645ad38ef3bf9138b69ac..f8b0c52e77a4fab95de18f8cda80e098b4fe5ee1 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/sizes.h>
-#include <asm/fpu/api.h>
+#include <asm/fpu.h>
 #include "chacha-s390.h"
 
 static void chacha20_crypt_s390(u32 *state, u8 *dst, const u8 *src,
                                unsigned int nbytes, const u32 *key,
                                u32 *counter)
 {
-       struct kernel_fpu vxstate;
+       DECLARE_KERNEL_FPU_ONSTACK32(vxstate);
 
        kernel_fpu_begin(&vxstate, KERNEL_VXR);
        chacha20_vx(dst, src, nbytes, key, counter);
index 37cb63f25b17697e1396ee95a3f366ba8e38bc36..63f3102678c0840113194206425fb8a46751abf4 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <linux/linkage.h>
 #include <asm/nospec-insn.h>
-#include <asm/vx-insn.h>
+#include <asm/fpu-insn.h>
 
 #define SP     %r15
 #define FRAME  (16 * 8 + 4 * 8)
index 017143e9cef715887647746800f9bae2fc5434cb..74f17c905d1233b00538609ff39b84408b3d9d42 100644 (file)
@@ -13,8 +13,8 @@
 #include <linux/cpufeature.h>
 #include <linux/crc32.h>
 #include <crypto/internal/hash.h>
-#include <asm/fpu/api.h>
-
+#include <asm/fpu.h>
+#include "crc32-vx.h"
 
 #define CRC32_BLOCK_SIZE       1
 #define CRC32_DIGEST_SIZE      4
@@ -31,11 +31,6 @@ struct crc_desc_ctx {
        u32 crc;
 };
 
-/* Prototypes for functions in assembly files */
-u32 crc32_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
-u32 crc32_be_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
-u32 crc32c_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
-
 /*
  * DEFINE_CRC32_VX() - Define a CRC-32 function using the vector extension
  *
@@ -49,8 +44,8 @@ u32 crc32c_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
        static u32 __pure ___fname(u32 crc,                                 \
                                unsigned char const *data, size_t datalen)  \
        {                                                                   \
-               struct kernel_fpu vxstate;                                  \
                unsigned long prealign, aligned, remaining;                 \
+               DECLARE_KERNEL_FPU_ONSTACK16(vxstate);                      \
                                                                            \
                if (datalen < VX_MIN_LEN + VX_ALIGN_MASK)                   \
                        return ___crc32_sw(crc, data, datalen);             \
diff --git a/arch/s390/crypto/crc32-vx.h b/arch/s390/crypto/crc32-vx.h
new file mode 100644 (file)
index 0000000..652c96e
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _CRC32_VX_S390_H
+#define _CRC32_VX_S390_H
+
+#include <linux/types.h>
+
+u32 crc32_be_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
+u32 crc32_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
+u32 crc32c_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
+
+#endif /* _CRC32_VX_S390_H */
similarity index 56%
rename from arch/s390/crypto/crc32be-vx.S
rename to arch/s390/crypto/crc32be-vx.c
index 34ee4792689188847bf9868e829239391306f9ae..fed7c9c70d055cf980990769389319a858e09bec 100644 (file)
  * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
  */
 
-#include <linux/linkage.h>
-#include <asm/nospec-insn.h>
-#include <asm/vx-insn.h>
+#include <linux/types.h>
+#include <asm/fpu.h>
+#include "crc32-vx.h"
 
 /* Vector register range containing CRC-32 constants */
-#define CONST_R1R2             %v9
-#define CONST_R3R4             %v10
-#define CONST_R5               %v11
-#define CONST_R6               %v12
-#define CONST_RU_POLY          %v13
-#define CONST_CRC_POLY         %v14
-
-       .data
-       .balign 8
+#define CONST_R1R2             9
+#define CONST_R3R4             10
+#define CONST_R5               11
+#define CONST_R6               12
+#define CONST_RU_POLY          13
+#define CONST_CRC_POLY         14
 
 /*
  * The CRC-32 constant block contains reduction constants to fold and
  *     P'(x) = 0xEDB88320
  */
 
-SYM_DATA_START_LOCAL(constants_CRC_32_BE)
-       .quad           0x08833794c, 0x0e6228b11        # R1, R2
-       .quad           0x0c5b9cd4c, 0x0e8a45605        # R3, R4
-       .quad           0x0f200aa66, 1 << 32            # R5, x32
-       .quad           0x0490d678d, 1                  # R6, 1
-       .quad           0x104d101df, 0                  # u
-       .quad           0x104C11DB7, 0                  # P(x)
-SYM_DATA_END(constants_CRC_32_BE)
-
-       .previous
-
-       GEN_BR_THUNK %r14
-
-       .text
-/*
- * The CRC-32 function(s) use these calling conventions:
- *
- * Parameters:
- *
- *     %r2:    Initial CRC value, typically ~0; and final CRC (return) value.
- *     %r3:    Input buffer pointer, performance might be improved if the
- *             buffer is on a doubleword boundary.
- *     %r4:    Length of the buffer, must be 64 bytes or greater.
+static unsigned long constants_CRC_32_BE[] = {
+       0x08833794c, 0x0e6228b11,       /* R1, R2 */
+       0x0c5b9cd4c, 0x0e8a45605,       /* R3, R4 */
+       0x0f200aa66, 1UL << 32,         /* R5, x32 */
+       0x0490d678d, 1,                 /* R6, 1 */
+       0x104d101df, 0,                 /* u */
+       0x104C11DB7, 0,                 /* P(x) */
+};
+
+/**
+ * crc32_be_vgfm_16 - Compute CRC-32 (BE variant) with vector registers
+ * @crc: Initial CRC value, typically ~0.
+ * @buf: Input buffer pointer, performance might be improved if the
+ *       buffer is on a doubleword boundary.
+ * @size: Size of the buffer, must be 64 bytes or greater.
  *
  * Register usage:
- *
- *     %r5:    CRC-32 constant pool base pointer.
  *     V0:     Initial CRC value and intermediate constants and results.
  *     V1..V4: Data for CRC computation.
  *     V5..V8: Next data chunks that are fetched from the input buffer.
- *
  *     V9..V14: CRC-32 constants.
  */
-SYM_FUNC_START(crc32_be_vgfm_16)
+u32 crc32_be_vgfm_16(u32 crc, unsigned char const *buf, size_t size)
+{
        /* Load CRC-32 constants */
-       larl    %r5,constants_CRC_32_BE
-       VLM     CONST_R1R2,CONST_CRC_POLY,0,%r5
+       fpu_vlm(CONST_R1R2, CONST_CRC_POLY, &constants_CRC_32_BE);
+       fpu_vzero(0);
 
        /* Load the initial CRC value into the leftmost word of V0. */
-       VZERO   %v0
-       VLVGF   %v0,%r2,0
+       fpu_vlvgf(0, crc, 0);
 
        /* Load a 64-byte data chunk and XOR with CRC */
-       VLM     %v1,%v4,0,%r3           /* 64-bytes into V1..V4 */
-       VX      %v1,%v0,%v1             /* V1 ^= CRC */
-       aghi    %r3,64                  /* BUF = BUF + 64 */
-       aghi    %r4,-64                 /* LEN = LEN - 64 */
-
-       /* Check remaining buffer size and jump to proper folding method */
-       cghi    %r4,64
-       jl      .Lless_than_64bytes
-
-.Lfold_64bytes_loop:
-       /* Load the next 64-byte data chunk into V5 to V8 */
-       VLM     %v5,%v8,0,%r3
+       fpu_vlm(1, 4, buf);
+       fpu_vx(1, 0, 1);
+       buf += 64;
+       size -= 64;
+
+       while (size >= 64) {
+               /* Load the next 64-byte data chunk into V5 to V8 */
+               fpu_vlm(5, 8, buf);
+
+               /*
+                * Perform a GF(2) multiplication of the doublewords in V1 with
+                * the reduction constants in V0.  The intermediate result is
+                * then folded (accumulated) with the next data chunk in V5 and
+                * stored in V1.  Repeat this step for the register contents
+                * in V2, V3, and V4 respectively.
+                */
+               fpu_vgfmag(1, CONST_R1R2, 1, 5);
+               fpu_vgfmag(2, CONST_R1R2, 2, 6);
+               fpu_vgfmag(3, CONST_R1R2, 3, 7);
+               fpu_vgfmag(4, CONST_R1R2, 4, 8);
+               buf += 64;
+               size -= 64;
+       }
 
-       /*
-        * Perform a GF(2) multiplication of the doublewords in V1 with
-        * the reduction constants in V0.  The intermediate result is
-        * then folded (accumulated) with the next data chunk in V5 and
-        * stored in V1.  Repeat this step for the register contents
-        * in V2, V3, and V4 respectively.
-        */
-       VGFMAG  %v1,CONST_R1R2,%v1,%v5
-       VGFMAG  %v2,CONST_R1R2,%v2,%v6
-       VGFMAG  %v3,CONST_R1R2,%v3,%v7
-       VGFMAG  %v4,CONST_R1R2,%v4,%v8
-
-       /* Adjust buffer pointer and length for next loop */
-       aghi    %r3,64                  /* BUF = BUF + 64 */
-       aghi    %r4,-64                 /* LEN = LEN - 64 */
-
-       cghi    %r4,64
-       jnl     .Lfold_64bytes_loop
-
-.Lless_than_64bytes:
        /* Fold V1 to V4 into a single 128-bit value in V1 */
-       VGFMAG  %v1,CONST_R3R4,%v1,%v2
-       VGFMAG  %v1,CONST_R3R4,%v1,%v3
-       VGFMAG  %v1,CONST_R3R4,%v1,%v4
-
-       /* Check whether to continue with 64-bit folding */
-       cghi    %r4,16
-       jl      .Lfinal_fold
+       fpu_vgfmag(1, CONST_R3R4, 1, 2);
+       fpu_vgfmag(1, CONST_R3R4, 1, 3);
+       fpu_vgfmag(1, CONST_R3R4, 1, 4);
 
-.Lfold_16bytes_loop:
+       while (size >= 16) {
+               fpu_vl(2, buf);
+               fpu_vgfmag(1, CONST_R3R4, 1, 2);
+               buf += 16;
+               size -= 16;
+       }
 
-       VL      %v2,0,,%r3              /* Load next data chunk */
-       VGFMAG  %v1,CONST_R3R4,%v1,%v2  /* Fold next data chunk */
-
-       /* Adjust buffer pointer and size for folding next data chunk */
-       aghi    %r3,16
-       aghi    %r4,-16
-
-       /* Process remaining data chunks */
-       cghi    %r4,16
-       jnl     .Lfold_16bytes_loop
-
-.Lfinal_fold:
        /*
         * The R5 constant is used to fold a 128-bit value into an 96-bit value
         * that is XORed with the next 96-bit input data chunk.  To use a single
@@ -164,7 +130,7 @@ SYM_FUNC_START(crc32_be_vgfm_16)
         * form an intermediate 96-bit value (with appended zeros) which is then
         * XORed with the intermediate reduction result.
         */
-       VGFMG   %v1,CONST_R5,%v1
+       fpu_vgfmg(1, CONST_R5, 1);
 
        /*
         * Further reduce the remaining 96-bit value to a 64-bit value using a
@@ -173,7 +139,7 @@ SYM_FUNC_START(crc32_be_vgfm_16)
         * doubleword with R6.  The result is a 64-bit value and is subject to
         * the Barret reduction.
         */
-       VGFMG   %v1,CONST_R6,%v1
+       fpu_vgfmg(1, CONST_R6, 1);
 
        /*
         * The input values to the Barret reduction are the degree-63 polynomial
@@ -194,20 +160,15 @@ SYM_FUNC_START(crc32_be_vgfm_16)
         */
 
        /* T1(x) = floor( R(x) / x^32 ) GF2MUL u */
-       VUPLLF  %v2,%v1
-       VGFMG   %v2,CONST_RU_POLY,%v2
+       fpu_vupllf(2, 1);
+       fpu_vgfmg(2, CONST_RU_POLY, 2);
 
        /*
         * Compute the GF(2) product of the CRC polynomial in VO with T1(x) in
         * V2 and XOR the intermediate result, T2(x),  with the value in V1.
         * The final result is in the rightmost word of V2.
         */
-       VUPLLF  %v2,%v2
-       VGFMAG  %v2,CONST_CRC_POLY,%v2,%v1
-
-.Ldone:
-       VLGVF   %r2,%v2,3
-       BR_EX   %r14
-SYM_FUNC_END(crc32_be_vgfm_16)
-
-.previous
+       fpu_vupllf(2, 2);
+       fpu_vgfmag(2, CONST_CRC_POLY, 2, 1);
+       return fpu_vlgvf(2, 3);
+}
similarity index 52%
rename from arch/s390/crypto/crc32le-vx.S
rename to arch/s390/crypto/crc32le-vx.c
index 5a819ae09a0b9a0933fe63b63ac791eb44803b91..2f629f394df750881043f383de571021d44ca656 100644 (file)
  * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
  */
 
-#include <linux/linkage.h>
-#include <asm/nospec-insn.h>
-#include <asm/vx-insn.h>
+#include <linux/types.h>
+#include <asm/fpu.h>
+#include "crc32-vx.h"
 
 /* Vector register range containing CRC-32 constants */
-#define CONST_PERM_LE2BE       %v9
-#define CONST_R2R1             %v10
-#define CONST_R4R3             %v11
-#define CONST_R5               %v12
-#define CONST_RU_POLY          %v13
-#define CONST_CRC_POLY         %v14
-
-       .data
-       .balign 8
+#define CONST_PERM_LE2BE       9
+#define CONST_R2R1             10
+#define CONST_R4R3             11
+#define CONST_R5               12
+#define CONST_RU_POLY          13
+#define CONST_CRC_POLY         14
 
 /*
  * The CRC-32 constant block contains reduction constants to fold and
  *     P'(x) = 0x82F63B78
  */
 
-SYM_DATA_START_LOCAL(constants_CRC_32_LE)
-       .octa           0x0F0E0D0C0B0A09080706050403020100      # BE->LE mask
-       .quad           0x1c6e41596, 0x154442bd4                # R2, R1
-       .quad           0x0ccaa009e, 0x1751997d0                # R4, R3
-       .octa           0x163cd6124                             # R5
-       .octa           0x1F7011641                             # u'
-       .octa           0x1DB710641                             # P'(x) << 1
-SYM_DATA_END(constants_CRC_32_LE)
-
-SYM_DATA_START_LOCAL(constants_CRC_32C_LE)
-       .octa           0x0F0E0D0C0B0A09080706050403020100      # BE->LE mask
-       .quad           0x09e4addf8, 0x740eef02                 # R2, R1
-       .quad           0x14cd00bd6, 0xf20c0dfe                 # R4, R3
-       .octa           0x0dd45aab8                             # R5
-       .octa           0x0dea713f1                             # u'
-       .octa           0x105ec76f0                             # P'(x) << 1
-SYM_DATA_END(constants_CRC_32C_LE)
-
-       .previous
-
-       GEN_BR_THUNK %r14
-
-       .text
-
-/*
- * The CRC-32 functions use these calling conventions:
- *
- * Parameters:
- *
- *     %r2:    Initial CRC value, typically ~0; and final CRC (return) value.
- *     %r3:    Input buffer pointer, performance might be improved if the
- *             buffer is on a doubleword boundary.
- *     %r4:    Length of the buffer, must be 64 bytes or greater.
+static unsigned long constants_CRC_32_LE[] = {
+       0x0f0e0d0c0b0a0908, 0x0706050403020100, /* BE->LE mask */
+       0x1c6e41596, 0x154442bd4,               /* R2, R1 */
+       0x0ccaa009e, 0x1751997d0,               /* R4, R3 */
+       0x0, 0x163cd6124,                       /* R5 */
+       0x0, 0x1f7011641,                       /* u' */
+       0x0, 0x1db710641                        /* P'(x) << 1 */
+};
+
+static unsigned long constants_CRC_32C_LE[] = {
+       0x0f0e0d0c0b0a0908, 0x0706050403020100, /* BE->LE mask */
+       0x09e4addf8, 0x740eef02,                /* R2, R1 */
+       0x14cd00bd6, 0xf20c0dfe,                /* R4, R3 */
+       0x0, 0x0dd45aab8,                       /* R5 */
+       0x0, 0x0dea713f1,                       /* u' */
+       0x0, 0x105ec76f0                        /* P'(x) << 1 */
+};
+
+/**
+ * crc32_le_vgfm_generic - Compute CRC-32 (LE variant) with vector registers
+ * @crc: Initial CRC value, typically ~0.
+ * @buf: Input buffer pointer, performance might be improved if the
+ *      buffer is on a doubleword boundary.
+ * @size: Size of the buffer, must be 64 bytes or greater.
+ * @constants: CRC-32 constant pool base pointer.
  *
  * Register usage:
- *
- *     %r5:    CRC-32 constant pool base pointer.
- *     V0:     Initial CRC value and intermediate constants and results.
- *     V1..V4: Data for CRC computation.
- *     V5..V8: Next data chunks that are fetched from the input buffer.
- *     V9:     Constant for BE->LE conversion and shift operations
- *
+ *     V0:       Initial CRC value and intermediate constants and results.
+ *     V1..V4:   Data for CRC computation.
+ *     V5..V8:   Next data chunks that are fetched from the input buffer.
+ *     V9:       Constant for BE->LE conversion and shift operations
  *     V10..V14: CRC-32 constants.
  */
-
-SYM_FUNC_START(crc32_le_vgfm_16)
-       larl    %r5,constants_CRC_32_LE
-       j       crc32_le_vgfm_generic
-SYM_FUNC_END(crc32_le_vgfm_16)
-
-SYM_FUNC_START(crc32c_le_vgfm_16)
-       larl    %r5,constants_CRC_32C_LE
-       j       crc32_le_vgfm_generic
-SYM_FUNC_END(crc32c_le_vgfm_16)
-
-SYM_FUNC_START(crc32_le_vgfm_generic)
+static u32 crc32_le_vgfm_generic(u32 crc, unsigned char const *buf, size_t size, unsigned long *constants)
+{
        /* Load CRC-32 constants */
-       VLM     CONST_PERM_LE2BE,CONST_CRC_POLY,0,%r5
+       fpu_vlm(CONST_PERM_LE2BE, CONST_CRC_POLY, constants);
 
        /*
         * Load the initial CRC value.
@@ -125,90 +101,73 @@ SYM_FUNC_START(crc32_le_vgfm_generic)
         * vector register and is later XORed with the LSB portion
         * of the loaded input data.
         */
-       VZERO   %v0                     /* Clear V0 */
-       VLVGF   %v0,%r2,3               /* Load CRC into rightmost word */
+       fpu_vzero(0);                   /* Clear V0 */
+       fpu_vlvgf(0, crc, 3);           /* Load CRC into rightmost word */
 
        /* Load a 64-byte data chunk and XOR with CRC */
-       VLM     %v1,%v4,0,%r3           /* 64-bytes into V1..V4 */
-       VPERM   %v1,%v1,%v1,CONST_PERM_LE2BE
-       VPERM   %v2,%v2,%v2,CONST_PERM_LE2BE
-       VPERM   %v3,%v3,%v3,CONST_PERM_LE2BE
-       VPERM   %v4,%v4,%v4,CONST_PERM_LE2BE
+       fpu_vlm(1, 4, buf);
+       fpu_vperm(1, 1, 1, CONST_PERM_LE2BE);
+       fpu_vperm(2, 2, 2, CONST_PERM_LE2BE);
+       fpu_vperm(3, 3, 3, CONST_PERM_LE2BE);
+       fpu_vperm(4, 4, 4, CONST_PERM_LE2BE);
+
+       fpu_vx(1, 0, 1);                /* V1 ^= CRC */
+       buf += 64;
+       size -= 64;
+
+       while (size >= 64) {
+               fpu_vlm(5, 8, buf);
+               fpu_vperm(5, 5, 5, CONST_PERM_LE2BE);
+               fpu_vperm(6, 6, 6, CONST_PERM_LE2BE);
+               fpu_vperm(7, 7, 7, CONST_PERM_LE2BE);
+               fpu_vperm(8, 8, 8, CONST_PERM_LE2BE);
+               /*
+                * Perform a GF(2) multiplication of the doublewords in V1 with
+                * the R1 and R2 reduction constants in V0.  The intermediate
+                * result is then folded (accumulated) with the next data chunk
+                * in V5 and stored in V1. Repeat this step for the register
+                * contents in V2, V3, and V4 respectively.
+                */
+               fpu_vgfmag(1, CONST_R2R1, 1, 5);
+               fpu_vgfmag(2, CONST_R2R1, 2, 6);
+               fpu_vgfmag(3, CONST_R2R1, 3, 7);
+               fpu_vgfmag(4, CONST_R2R1, 4, 8);
+               buf += 64;
+               size -= 64;
+       }
 
-       VX      %v1,%v0,%v1             /* V1 ^= CRC */
-       aghi    %r3,64                  /* BUF = BUF + 64 */
-       aghi    %r4,-64                 /* LEN = LEN - 64 */
-
-       cghi    %r4,64
-       jl      .Lless_than_64bytes
-
-.Lfold_64bytes_loop:
-       /* Load the next 64-byte data chunk into V5 to V8 */
-       VLM     %v5,%v8,0,%r3
-       VPERM   %v5,%v5,%v5,CONST_PERM_LE2BE
-       VPERM   %v6,%v6,%v6,CONST_PERM_LE2BE
-       VPERM   %v7,%v7,%v7,CONST_PERM_LE2BE
-       VPERM   %v8,%v8,%v8,CONST_PERM_LE2BE
-
-       /*
-        * Perform a GF(2) multiplication of the doublewords in V1 with
-        * the R1 and R2 reduction constants in V0.  The intermediate result
-        * is then folded (accumulated) with the next data chunk in V5 and
-        * stored in V1. Repeat this step for the register contents
-        * in V2, V3, and V4 respectively.
-        */
-       VGFMAG  %v1,CONST_R2R1,%v1,%v5
-       VGFMAG  %v2,CONST_R2R1,%v2,%v6
-       VGFMAG  %v3,CONST_R2R1,%v3,%v7
-       VGFMAG  %v4,CONST_R2R1,%v4,%v8
-
-       aghi    %r3,64                  /* BUF = BUF + 64 */
-       aghi    %r4,-64                 /* LEN = LEN - 64 */
-
-       cghi    %r4,64
-       jnl     .Lfold_64bytes_loop
-
-.Lless_than_64bytes:
        /*
         * Fold V1 to V4 into a single 128-bit value in V1.  Multiply V1 with R3
         * and R4 and accumulating the next 128-bit chunk until a single 128-bit
         * value remains.
         */
-       VGFMAG  %v1,CONST_R4R3,%v1,%v2
-       VGFMAG  %v1,CONST_R4R3,%v1,%v3
-       VGFMAG  %v1,CONST_R4R3,%v1,%v4
-
-       cghi    %r4,16
-       jl      .Lfinal_fold
-
-.Lfold_16bytes_loop:
-
-       VL      %v2,0,,%r3              /* Load next data chunk */
-       VPERM   %v2,%v2,%v2,CONST_PERM_LE2BE
-       VGFMAG  %v1,CONST_R4R3,%v1,%v2  /* Fold next data chunk */
+       fpu_vgfmag(1, CONST_R4R3, 1, 2);
+       fpu_vgfmag(1, CONST_R4R3, 1, 3);
+       fpu_vgfmag(1, CONST_R4R3, 1, 4);
+
+       while (size >= 16) {
+               fpu_vl(2, buf);
+               fpu_vperm(2, 2, 2, CONST_PERM_LE2BE);
+               fpu_vgfmag(1, CONST_R4R3, 1, 2);
+               buf += 16;
+               size -= 16;
+       }
 
-       aghi    %r3,16
-       aghi    %r4,-16
-
-       cghi    %r4,16
-       jnl     .Lfold_16bytes_loop
-
-.Lfinal_fold:
        /*
         * Set up a vector register for byte shifts.  The shift value must
         * be loaded in bits 1-4 in byte element 7 of a vector register.
         * Shift by 8 bytes: 0x40
         * Shift by 4 bytes: 0x20
         */
-       VLEIB   %v9,0x40,7
+       fpu_vleib(9, 0x40, 7);
 
        /*
         * Prepare V0 for the next GF(2) multiplication: shift V0 by 8 bytes
         * to move R4 into the rightmost doubleword and set the leftmost
         * doubleword to 0x1.
         */
-       VSRLB   %v0,CONST_R4R3,%v9
-       VLEIG   %v0,1,0
+       fpu_vsrlb(0, CONST_R4R3, 9);
+       fpu_vleig(0, 1, 0);
 
        /*
         * Compute GF(2) product of V1 and V0.  The rightmost doubleword
@@ -216,7 +175,7 @@ SYM_FUNC_START(crc32_le_vgfm_generic)
         * multiplied by 0x1 and is then XORed with rightmost product.
         * Implicitly, the intermediate leftmost product becomes padded
         */
-       VGFMG   %v1,%v0,%v1
+       fpu_vgfmg(1, 0, 1);
 
        /*
         * Now do the final 32-bit fold by multiplying the rightmost word
@@ -231,10 +190,10 @@ SYM_FUNC_START(crc32_le_vgfm_generic)
         * rightmost doubleword and the leftmost doubleword is zero to ignore
         * the leftmost product of V1.
         */
-       VLEIB   %v9,0x20,7                /* Shift by words */
-       VSRLB   %v2,%v1,%v9               /* Store remaining bits in V2 */
-       VUPLLF  %v1,%v1                   /* Split rightmost doubleword */
-       VGFMAG  %v1,CONST_R5,%v1,%v2      /* V1 = (V1 * R5) XOR V2 */
+       fpu_vleib(9, 0x20, 7);            /* Shift by words */
+       fpu_vsrlb(2, 1, 9);               /* Store remaining bits in V2 */
+       fpu_vupllf(1, 1);                 /* Split rightmost doubleword */
+       fpu_vgfmag(1, CONST_R5, 1, 2);    /* V1 = (V1 * R5) XOR V2 */
 
        /*
         * Apply a Barret reduction to compute the final 32-bit CRC value.
@@ -256,20 +215,26 @@ SYM_FUNC_START(crc32_le_vgfm_generic)
         */
 
        /* T1(x) = floor( R(x) / x^32 ) GF2MUL u */
-       VUPLLF  %v2,%v1
-       VGFMG   %v2,CONST_RU_POLY,%v2
+       fpu_vupllf(2, 1);
+       fpu_vgfmg(2, CONST_RU_POLY, 2);
 
        /*
         * Compute the GF(2) product of the CRC polynomial with T1(x) in
         * V2 and XOR the intermediate result, T2(x), with the value in V1.
         * The final result is stored in word element 2 of V2.
         */
-       VUPLLF  %v2,%v2
-       VGFMAG  %v2,CONST_CRC_POLY,%v2,%v1
+       fpu_vupllf(2, 2);
+       fpu_vgfmag(2, CONST_CRC_POLY, 2, 1);
+
+       return fpu_vlgvf(2, 2);
+}
 
-.Ldone:
-       VLGVF   %r2,%v2,2
-       BR_EX   %r14
-SYM_FUNC_END(crc32_le_vgfm_generic)
+u32 crc32_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size)
+{
+       return crc32_le_vgfm_generic(crc, buf, size, &constants_CRC_32_LE[0]);
+}
 
-.previous
+u32 crc32c_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size)
+{
+       return crc32_le_vgfm_generic(crc, buf, size, &constants_CRC_32C_LE[0]);
+}
index 55ee5567a5ea923b38c95754a1ed29cabacabd0e..99f7e1f2b70aff61da33cc06bc0e7455394150a8 100644 (file)
@@ -125,20 +125,8 @@ struct s390_pxts_ctx {
 static inline int __paes_keyblob2pkey(struct key_blob *kb,
                                     struct pkey_protkey *pk)
 {
-       int i, ret;
-
-       /* try three times in case of failure */
-       for (i = 0; i < 3; i++) {
-               if (i > 0 && ret == -EAGAIN && in_task())
-                       if (msleep_interruptible(1000))
-                               return -EINTR;
-               ret = pkey_keyblob2pkey(kb->key, kb->keylen,
-                                       pk->protkey, &pk->len, &pk->type);
-               if (ret == 0)
-                       break;
-       }
-
-       return ret;
+       return pkey_keyblob2pkey(kb->key, kb->keylen,
+                                pk->protkey, &pk->len, &pk->type);
 }
 
 static inline int __paes_convert_key(struct s390_paes_ctx *ctx)
index 9a2786079e3a791f151900f0fb80aaaafefc9e97..4131f0daa5ead9ace2eae667fe280c830f9d9be6 100644 (file)
@@ -20,8 +20,7 @@
  */
 static void diag0c_fn(void *data)
 {
-       diag_stat_inc(DIAG_STAT_X00C);
-       diag_amode31_ops.diag0c(((void **)data)[smp_processor_id()]);
+       diag0c(((void **)data)[smp_processor_id()]);
 }
 
 /*
index f5f7e78ddc0c8deee7795818c2633c227f4f427c..9fc3f0dae8f0a24a724320c411ae543e64cdda52 100644 (file)
@@ -25,7 +25,7 @@
 
 static inline unsigned long __hypfs_sprp_diag304(void *data, unsigned long cmd)
 {
-       union register_pair r1 = { .even = (unsigned long)data, };
+       union register_pair r1 = { .even = virt_to_phys(data), };
 
        asm volatile("diag %[r1],%[r3],0x304\n"
                     : [r1] "+&d" (r1.pair)
@@ -74,7 +74,7 @@ static int __hypfs_sprp_ioctl(void __user *user_area)
        int rc;
 
        rc = -ENOMEM;
-       data = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       data = (void *)get_zeroed_page(GFP_KERNEL);
        diag304 = kzalloc(sizeof(*diag304), GFP_KERNEL);
        if (!data || !diag304)
                goto out;
diff --git a/arch/s390/include/asm/access-regs.h b/arch/s390/include/asm/access-regs.h
new file mode 100644 (file)
index 0000000..1a6412d
--- /dev/null
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright IBM Corp. 1999, 2024
+ */
+
+#ifndef __ASM_S390_ACCESS_REGS_H
+#define __ASM_S390_ACCESS_REGS_H
+
+#include <linux/instrumented.h>
+#include <asm/sigcontext.h>
+
+struct access_regs {
+       unsigned int regs[NUM_ACRS];
+};
+
+static inline void save_access_regs(unsigned int *acrs)
+{
+       struct access_regs *regs = (struct access_regs *)acrs;
+
+       instrument_write(regs, sizeof(*regs));
+       asm volatile("stamy     0,15,%[regs]"
+                    : [regs] "=QS" (*regs)
+                    :
+                    : "memory");
+}
+
+static inline void restore_access_regs(unsigned int *acrs)
+{
+       struct access_regs *regs = (struct access_regs *)acrs;
+
+       instrument_read(regs, sizeof(*regs));
+       asm volatile("lamy      0,15,%[regs]"
+                    :
+                    : [regs] "QS" (*regs)
+                    : "memory");
+}
+
+#endif /* __ASM_S390_ACCESS_REGS_H */
index f2240392c70807635ef5d9c5e630855f954af6ce..a92ebbc7aa7a383d03442ef86f25d844e28c74e5 100644 (file)
@@ -54,13 +54,13 @@ static inline int appldata_asm(struct appldata_parameter_list *parm_list,
        parm_list->function = fn;
        parm_list->parlist_length = sizeof(*parm_list);
        parm_list->buffer_length = length;
-       parm_list->product_id_addr = (unsigned long) id;
+       parm_list->product_id_addr = virt_to_phys(id);
        parm_list->buffer_addr = virt_to_phys(buffer);
        diag_stat_inc(DIAG_STAT_X0DC);
        asm volatile(
                "       diag    %1,%0,0xdc"
                : "=d" (ry)
-               : "d" (parm_list), "m" (*parm_list), "m" (*id)
+               : "d" (virt_to_phys(parm_list)), "m" (*parm_list), "m" (*id)
                : "cc");
        return ry;
 }
index a873e873e1ee4bdf11c1ff813afcc5129fd09fd7..56096ae26f296b22a350592d6c354ea83e03a359 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <linux/kvm_host.h>
 #include <linux/ftrace.h>
-#include <asm/fpu/api.h>
+#include <asm/fpu.h>
 #include <asm-generic/asm-prototypes.h>
 
 __int128_t __ashlti3(__int128_t a, int b);
index aebe1e22c7befa486bbe269383164f9a792b5c89..c500d45fb465c5868f0269406f7ae6567ca5a3a0 100644 (file)
@@ -14,7 +14,7 @@
                ".section .rodata.str,\"aMS\",@progbits,1\n"    \
                "1:     .asciz  \""__FILE__"\"\n"               \
                ".previous\n"                                   \
-               ".section __bug_table,\"awM\",@progbits,%2\n"   \
+               ".section __bug_table,\"aw\"\n"                 \
                "2:     .long   0b-.\n"                         \
                "       .long   1b-.\n"                         \
                "       .short  %0,%1\n"                        \
@@ -30,7 +30,7 @@
 #define __EMIT_BUG(x) do {                                     \
        asm_inline volatile(                                    \
                "0:     mc      0,0\n"                          \
-               ".section __bug_table,\"awM\",@progbits,%1\n"   \
+               ".section __bug_table,\"aw\"\n"                 \
                "1:     .long   0b-.\n"                         \
                "       .short  %0\n"                           \
                "       .org    1b+%1\n"                        \
index 69837eec2ff5dbeeaa932ff57d93fe4de8daa6e1..b89159591ca08d7caf6248ef270d325772fdeb85 100644 (file)
 #ifndef _S390_CHECKSUM_H
 #define _S390_CHECKSUM_H
 
-#include <linux/kasan-checks.h>
+#include <linux/instrumented.h>
 #include <linux/in6.h>
 
-/*
- * Computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit).
- *
- * Returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic.
- *
- * This function must be called with even lengths, except
- * for the last fragment, which may be odd.
- *
- * It's best to have buff aligned on a 32-bit boundary.
- */
-static inline __wsum csum_partial(const void *buff, int len, __wsum sum)
+static inline __wsum cksm(const void *buff, int len, __wsum sum)
 {
        union register_pair rp = {
-               .even = (unsigned long) buff,
-               .odd = (unsigned long) len,
+               .even = (unsigned long)buff,
+               .odd = (unsigned long)len,
        };
 
-       kasan_check_read(buff, len);
-       asm volatile(
+       instrument_read(buff, len);
+       asm volatile("\n"
                "0:     cksm    %[sum],%[rp]\n"
                "       jo      0b\n"
                : [sum] "+&d" (sum), [rp] "+&d" (rp.pair) : : "cc", "memory");
        return sum;
 }
 
+__wsum csum_partial(const void *buff, int len, __wsum sum);
+
+#define _HAVE_ARCH_CSUM_AND_COPY
+__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);
+
 /*
  * Fold a partial checksum without adding pseudo headers.
  */
index bed804137537becd6a5d0ecdc2c74c7c764ba04b..20b94220113b3d385f8f9f8e9229d63aa92e7caf 100644 (file)
@@ -44,6 +44,13 @@ enum diag_stat_enum {
 void diag_stat_inc(enum diag_stat_enum nr);
 void diag_stat_inc_norecursion(enum diag_stat_enum nr);
 
+struct hypfs_diag0c_entry;
+
+/*
+ * Diagnose 0c: Pseudo Timer
+ */
+void diag0c(struct hypfs_diag0c_entry *data);
+
 /*
  * Diagnose 10: Release page range
  */
@@ -331,10 +338,10 @@ struct hypfs_diag0c_entry;
  */
 struct diag_ops {
        int (*diag210)(struct diag210 *addr);
-       int (*diag26c)(void *req, void *resp, enum diag26c_sc subcode);
+       int (*diag26c)(unsigned long rx, unsigned long rx1, enum diag26c_sc subcode);
        int (*diag14)(unsigned long rx, unsigned long ry1, unsigned long subcode);
        int (*diag8c)(struct diag8c *addr, struct ccw_dev_id *devno, size_t len);
-       void (*diag0c)(struct hypfs_diag0c_entry *entry);
+       void (*diag0c)(unsigned long rx);
        void (*diag308_reset)(void);
 };
 
@@ -342,9 +349,9 @@ extern struct diag_ops diag_amode31_ops;
 extern struct diag210 *__diag210_tmp_amode31;
 
 int _diag210_amode31(struct diag210 *addr);
-int _diag26c_amode31(void *req, void *resp, enum diag26c_sc subcode);
+int _diag26c_amode31(unsigned long rx, unsigned long rx1, enum diag26c_sc subcode);
 int _diag14_amode31(unsigned long rx, unsigned long ry1, unsigned long subcode);
-void _diag0c_amode31(struct hypfs_diag0c_entry *entry);
+void _diag0c_amode31(unsigned long rx);
 void _diag308_reset_amode31(void);
 int _diag8c_amode31(struct diag8c *addr, struct ccw_dev_id *devno, size_t len);
 
index fdd319a622b065c1a96bcbd0b03fbe83e8d4c17e..7f5004065e8aa2b1598f37f501e0c2537d6529a2 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/processor.h>
 #include <linux/uaccess.h>
 #include <asm/timex.h>
-#include <asm/fpu/api.h>
+#include <asm/fpu.h>
 #include <asm/pai.h>
 
 #define ARCH_EXIT_TO_USER_MODE_WORK (_TIF_GUARDED_STORAGE | _TIF_PER_TRAP)
@@ -41,8 +41,7 @@ static __always_inline void arch_exit_to_user_mode_work(struct pt_regs *regs,
 
 static __always_inline void arch_exit_to_user_mode(void)
 {
-       if (test_cpu_flag(CIF_FPU))
-               __load_fpu_regs();
+       load_user_fpu_regs();
 
        if (IS_ENABLED(CONFIG_DEBUG_ENTRY))
                debug_user_asce(1);
similarity index 86%
rename from arch/s390/include/asm/vx-insn-asm.h
rename to arch/s390/include/asm/fpu-insn-asm.h
index 360f8b36d962255ea3f0ded72d949eda1381adfc..02ccfe46050a08ce94a5eef63f4703c0d029f7ca 100644 (file)
@@ -9,11 +9,11 @@
  * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
  */
 
-#ifndef __ASM_S390_VX_INSN_INTERNAL_H
-#define __ASM_S390_VX_INSN_INTERNAL_H
+#ifndef __ASM_S390_FPU_INSN_ASM_H
+#define __ASM_S390_FPU_INSN_ASM_H
 
-#ifndef __ASM_S390_VX_INSN_H
-#error only <asm/vx-insn.h> can be included directly
+#ifndef __ASM_S390_FPU_INSN_H
+#error only <asm/fpu-insn.h> can be included directly
 #endif
 
 #ifdef __ASSEMBLY__
 /* RXB - Compute most significant bit used vector registers
  *
  * @rxb:       Operand to store computed RXB value
- * @v1:                First vector register designated operand
- * @v2:                Second vector register designated operand
- * @v3:                Third vector register designated operand
- * @v4:                Fourth vector register designated operand
+ * @v1:                Vector register designated operand whose MSB is stored in
+ *             RXB bit 0 (instruction bit 36) and whose remaining bits
+ *             are stored in instruction bits 8-11.
+ * @v2:                Vector register designated operand whose MSB is stored in
+ *             RXB bit 1 (instruction bit 37) and whose remaining bits
+ *             are stored in instruction bits 12-15.
+ * @v3:                Vector register designated operand whose MSB is stored in
+ *             RXB bit 2 (instruction bit 38) and whose remaining bits
+ *             are stored in instruction bits 16-19.
+ * @v4:                Vector register designated operand whose MSB is stored in
+ *             RXB bit 3 (instruction bit 39) and whose remaining bits
+ *             are stored in instruction bits 32-35.
+ *
+ * Note: In most vector instruction formats [1] V1, V2, V3, and V4 directly
+ * correspond to @v1, @v2, @v3, and @v4. But there are exceptions, such as but
+ * not limited to the vector instruction formats VRR-g, VRR-h, VRS-a, VRS-d,
+ * and VSI.
+ *
+ * [1] IBM z/Architecture Principles of Operation, chapter "Program
+ * Execution, section "Instructions", subsection "Instruction Formats".
  */
 .macro RXB     rxb v1 v2=0 v3=0 v4=0
        \rxb = 0
  * @v2:                Second vector register designated operand (for RXB)
  * @v3:                Third vector register designated operand (for RXB)
  * @v4:                Fourth vector register designated operand (for RXB)
+ *
+ * Note: For @v1, @v2, @v3, and @v4 also refer to the RXB macro
+ * description for further details.
  */
 .macro MRXB    m v1 v2=0 v3=0 v4=0
        rxb = 0
  * @v2:                Second vector register designated operand (for RXB)
  * @v3:                Third vector register designated operand (for RXB)
  * @v4:                Fourth vector register designated operand (for RXB)
+ *
+ * Note: For @v1, @v2, @v3, and @v4 also refer to the RXB macro
+ * description for further details.
  */
 .macro MRXBOPC m opc v1 v2=0 v3=0 v4=0
        MRXB    \m, \v1, \v2, \v3, \v4
        VX_NUM  v3, \vr
        .word   0xE700 | (r1 << 4) | (v3&15)
        .word   (b2 << 12) | (\disp)
-       MRXBOPC \m, 0x21, v3
+       MRXBOPC \m, 0x21, 0, v3
 .endm
 .macro VLGVB   gr, vr, disp, base="%r0"
        VLGV    \gr, \vr, \disp, \base, 0
        VMRL    \vr1, \vr2, \vr3, 3
 .endm
 
+/* VECTOR LOAD WITH LENGTH */
+.macro VLL     v, gr, disp, base
+       VX_NUM  v1, \v
+       GR_NUM  b2, \base
+       GR_NUM  r3, \gr
+       .word   0xE700 | ((v1&15) << 4) | r3
+       .word   (b2 << 12) | (\disp)
+       MRXBOPC 0, 0x37, v1
+.endm
+
+/* VECTOR STORE WITH LENGTH */
+.macro VSTL    v, gr, disp, base
+       VX_NUM  v1, \v
+       GR_NUM  b2, \base
+       GR_NUM  r3, \gr
+       .word   0xE700 | ((v1&15) << 4) | r3
+       .word   (b2 << 12) | (\disp)
+       MRXBOPC 0, 0x3f, v1
+.endm
 
 /* Vector integer instructions */
 
        MRXBOPC 0, 0x68, v1, v2, v3
 .endm
 
+/* VECTOR CHECKSUM */
+.macro VCKSM   vr1, vr2, vr3
+       VX_NUM  v1, \vr1
+       VX_NUM  v2, \vr2
+       VX_NUM  v3, \vr3
+       .word   0xE700 | ((v1&15) << 4) | (v2&15)
+       .word   ((v3&15) << 12)
+       MRXBOPC 0, 0x66, v1, v2, v3
+.endm
+
 /* VECTOR EXCLUSIVE OR */
 .macro VX      vr1, vr2, vr3
        VX_NUM  v1, \vr1
 .endm
 
 #endif /* __ASSEMBLY__ */
-#endif /* __ASM_S390_VX_INSN_INTERNAL_H */
+#endif /* __ASM_S390_FPU_INSN_ASM_H */
diff --git a/arch/s390/include/asm/fpu-insn.h b/arch/s390/include/asm/fpu-insn.h
new file mode 100644 (file)
index 0000000..c1e2e52
--- /dev/null
@@ -0,0 +1,486 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Support for Floating Point and Vector Instructions
+ *
+ */
+
+#ifndef __ASM_S390_FPU_INSN_H
+#define __ASM_S390_FPU_INSN_H
+
+#include <asm/fpu-insn-asm.h>
+
+#ifndef __ASSEMBLY__
+
+#include <linux/instrumented.h>
+#include <asm/asm-extable.h>
+
+asm(".include \"asm/fpu-insn-asm.h\"\n");
+
+/*
+ * Various small helper functions, which can and should be used within
+ * kernel fpu code sections. Each function represents only one floating
+ * point or vector instruction (except for helper functions which require
+ * exception handling).
+ *
+ * This allows to use floating point and vector instructions like C
+ * functions, which has the advantage that all supporting code, like
+ * e.g. loops, can be written in easy to read C code.
+ *
+ * Each of the helper functions provides support for code instrumentation,
+ * like e.g. KASAN. Therefore instrumentation is also covered automatically
+ * when using these functions.
+ *
+ * In order to ensure that code generated with the helper functions stays
+ * within kernel fpu sections, which are guarded with kernel_fpu_begin()
+ * and kernel_fpu_end() calls, each function has a mandatory "memory"
+ * barrier.
+ */
+
+static __always_inline void fpu_cefbr(u8 f1, s32 val)
+{
+       asm volatile("cefbr     %[f1],%[val]\n"
+                    :
+                    : [f1] "I" (f1), [val] "d" (val)
+                    : "memory");
+}
+
+static __always_inline unsigned long fpu_cgebr(u8 f2, u8 mode)
+{
+       unsigned long val;
+
+       asm volatile("cgebr     %[val],%[mode],%[f2]\n"
+                    : [val] "=d" (val)
+                    : [f2] "I" (f2), [mode] "I" (mode)
+                    : "memory");
+       return val;
+}
+
+static __always_inline void fpu_debr(u8 f1, u8 f2)
+{
+       asm volatile("debr      %[f1],%[f2]\n"
+                    :
+                    : [f1] "I" (f1), [f2] "I" (f2)
+                    : "memory");
+}
+
+static __always_inline void fpu_ld(unsigned short fpr, freg_t *reg)
+{
+       instrument_read(reg, sizeof(*reg));
+       asm volatile("ld         %[fpr],%[reg]\n"
+                    :
+                    : [fpr] "I" (fpr), [reg] "Q" (reg->ui)
+                    : "memory");
+}
+
+static __always_inline void fpu_ldgr(u8 f1, u32 val)
+{
+       asm volatile("ldgr      %[f1],%[val]\n"
+                    :
+                    : [f1] "I" (f1), [val] "d" (val)
+                    : "memory");
+}
+
+static __always_inline void fpu_lfpc(unsigned int *fpc)
+{
+       instrument_read(fpc, sizeof(*fpc));
+       asm volatile("lfpc      %[fpc]"
+                    :
+                    : [fpc] "Q" (*fpc)
+                    : "memory");
+}
+
+/**
+ * fpu_lfpc_safe - Load floating point control register safely.
+ * @fpc: new value for floating point control register
+ *
+ * Load floating point control register. This may lead to an exception,
+ * since a saved value may have been modified by user space (ptrace,
+ * signal return, kvm registers) to an invalid value. In such a case
+ * set the floating point control register to zero.
+ */
+static inline void fpu_lfpc_safe(unsigned int *fpc)
+{
+       u32 tmp;
+
+       instrument_read(fpc, sizeof(*fpc));
+       asm volatile("\n"
+               "0:     lfpc    %[fpc]\n"
+               "1:     nopr    %%r7\n"
+               ".pushsection .fixup, \"ax\"\n"
+               "2:     lghi    %[tmp],0\n"
+               "       sfpc    %[tmp]\n"
+               "       jg      1b\n"
+               ".popsection\n"
+               EX_TABLE(1b, 2b)
+               : [tmp] "=d" (tmp)
+               : [fpc] "Q" (*fpc)
+               : "memory");
+}
+
+static __always_inline void fpu_std(unsigned short fpr, freg_t *reg)
+{
+       instrument_write(reg, sizeof(*reg));
+       asm volatile("std        %[fpr],%[reg]\n"
+                    : [reg] "=Q" (reg->ui)
+                    : [fpr] "I" (fpr)
+                    : "memory");
+}
+
+static __always_inline void fpu_sfpc(unsigned int fpc)
+{
+       asm volatile("sfpc      %[fpc]"
+                    :
+                    : [fpc] "d" (fpc)
+                    : "memory");
+}
+
+static __always_inline void fpu_stfpc(unsigned int *fpc)
+{
+       instrument_write(fpc, sizeof(*fpc));
+       asm volatile("stfpc     %[fpc]"
+                    : [fpc] "=Q" (*fpc)
+                    :
+                    : "memory");
+}
+
+static __always_inline void fpu_vab(u8 v1, u8 v2, u8 v3)
+{
+       asm volatile("VAB       %[v1],%[v2],%[v3]"
+                    :
+                    : [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
+                    : "memory");
+}
+
+static __always_inline void fpu_vcksm(u8 v1, u8 v2, u8 v3)
+{
+       asm volatile("VCKSM     %[v1],%[v2],%[v3]"
+                    :
+                    : [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
+                    : "memory");
+}
+
+static __always_inline void fpu_vesravb(u8 v1, u8 v2, u8 v3)
+{
+       asm volatile("VESRAVB   %[v1],%[v2],%[v3]"
+                    :
+                    : [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
+                    : "memory");
+}
+
+static __always_inline void fpu_vgfmag(u8 v1, u8 v2, u8 v3, u8 v4)
+{
+       asm volatile("VGFMAG    %[v1],%[v2],%[v3],%[v4]"
+                    :
+                    : [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3), [v4] "I" (v4)
+                    : "memory");
+}
+
+static __always_inline void fpu_vgfmg(u8 v1, u8 v2, u8 v3)
+{
+       asm volatile("VGFMG     %[v1],%[v2],%[v3]"
+                    :
+                    : [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
+                    : "memory");
+}
+
+#ifdef CONFIG_CC_IS_CLANG
+
+static __always_inline void fpu_vl(u8 v1, const void *vxr)
+{
+       instrument_read(vxr, sizeof(__vector128));
+       asm volatile("\n"
+               "       la      1,%[vxr]\n"
+               "       VL      %[v1],0,,1\n"
+               :
+               : [vxr] "R" (*(__vector128 *)vxr),
+                 [v1] "I" (v1)
+               : "memory", "1");
+}
+
+#else /* CONFIG_CC_IS_CLANG */
+
+static __always_inline void fpu_vl(u8 v1, const void *vxr)
+{
+       instrument_read(vxr, sizeof(__vector128));
+       asm volatile("VL        %[v1],%O[vxr],,%R[vxr]\n"
+                    :
+                    : [vxr] "Q" (*(__vector128 *)vxr),
+                      [v1] "I" (v1)
+                    : "memory");
+}
+
+#endif /* CONFIG_CC_IS_CLANG */
+
+static __always_inline void fpu_vleib(u8 v, s16 val, u8 index)
+{
+       asm volatile("VLEIB     %[v],%[val],%[index]"
+                    :
+                    : [v] "I" (v), [val] "K" (val), [index] "I" (index)
+                    : "memory");
+}
+
+static __always_inline void fpu_vleig(u8 v, s16 val, u8 index)
+{
+       asm volatile("VLEIG     %[v],%[val],%[index]"
+                    :
+                    : [v] "I" (v), [val] "K" (val), [index] "I" (index)
+                    : "memory");
+}
+
+static __always_inline u64 fpu_vlgvf(u8 v, u16 index)
+{
+       u64 val;
+
+       asm volatile("VLGVF     %[val],%[v],%[index]"
+                    : [val] "=d" (val)
+                    : [v] "I" (v), [index] "L" (index)
+                    : "memory");
+       return val;
+}
+
+#ifdef CONFIG_CC_IS_CLANG
+
+static __always_inline void fpu_vll(u8 v1, u32 index, const void *vxr)
+{
+       unsigned int size;
+
+       size = min(index + 1, sizeof(__vector128));
+       instrument_read(vxr, size);
+       asm volatile("\n"
+               "       la      1,%[vxr]\n"
+               "       VLL     %[v1],%[index],0,1\n"
+               :
+               : [vxr] "R" (*(u8 *)vxr),
+                 [index] "d" (index),
+                 [v1] "I" (v1)
+               : "memory", "1");
+}
+
+#else /* CONFIG_CC_IS_CLANG */
+
+static __always_inline void fpu_vll(u8 v1, u32 index, const void *vxr)
+{
+       unsigned int size;
+
+       size = min(index + 1, sizeof(__vector128));
+       instrument_read(vxr, size);
+       asm volatile("VLL       %[v1],%[index],%O[vxr],%R[vxr]\n"
+                    :
+                    : [vxr] "Q" (*(u8 *)vxr),
+                      [index] "d" (index),
+                      [v1] "I" (v1)
+                    : "memory");
+}
+
+#endif /* CONFIG_CC_IS_CLANG */
+
+#ifdef CONFIG_CC_IS_CLANG
+
+#define fpu_vlm(_v1, _v3, _vxrs)                                       \
+({                                                                     \
+       unsigned int size = ((_v3) - (_v1) + 1) * sizeof(__vector128);  \
+       struct {                                                        \
+               __vector128 _v[(_v3) - (_v1) + 1];                      \
+       } *_v = (void *)(_vxrs);                                        \
+                                                                       \
+       instrument_read(_v, size);                                      \
+       asm volatile("\n"                                               \
+               "       la      1,%[vxrs]\n"                            \
+               "       VLM     %[v1],%[v3],0,1\n"                      \
+               :                                                       \
+               : [vxrs] "R" (*_v),                                     \
+                 [v1] "I" (_v1), [v3] "I" (_v3)                        \
+               : "memory", "1");                                       \
+       (_v3) - (_v1) + 1;                                              \
+})
+
+#else /* CONFIG_CC_IS_CLANG */
+
+#define fpu_vlm(_v1, _v3, _vxrs)                                       \
+({                                                                     \
+       unsigned int size = ((_v3) - (_v1) + 1) * sizeof(__vector128);  \
+       struct {                                                        \
+               __vector128 _v[(_v3) - (_v1) + 1];                      \
+       } *_v = (void *)(_vxrs);                                        \
+                                                                       \
+       instrument_read(_v, size);                                      \
+       asm volatile("VLM       %[v1],%[v3],%O[vxrs],%R[vxrs]\n"        \
+                    :                                                  \
+                    : [vxrs] "Q" (*_v),                                \
+                      [v1] "I" (_v1), [v3] "I" (_v3)                   \
+                    : "memory");                                       \
+       (_v3) - (_v1) + 1;                                              \
+})
+
+#endif /* CONFIG_CC_IS_CLANG */
+
+static __always_inline void fpu_vlr(u8 v1, u8 v2)
+{
+       asm volatile("VLR       %[v1],%[v2]"
+                    :
+                    : [v1] "I" (v1), [v2] "I" (v2)
+                    : "memory");
+}
+
+static __always_inline void fpu_vlvgf(u8 v, u32 val, u16 index)
+{
+       asm volatile("VLVGF     %[v],%[val],%[index]"
+                    :
+                    : [v] "I" (v), [val] "d" (val), [index] "L" (index)
+                    : "memory");
+}
+
+static __always_inline void fpu_vn(u8 v1, u8 v2, u8 v3)
+{
+       asm volatile("VN        %[v1],%[v2],%[v3]"
+                    :
+                    : [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
+                    : "memory");
+}
+
+static __always_inline void fpu_vperm(u8 v1, u8 v2, u8 v3, u8 v4)
+{
+       asm volatile("VPERM     %[v1],%[v2],%[v3],%[v4]"
+                    :
+                    : [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3), [v4] "I" (v4)
+                    : "memory");
+}
+
+static __always_inline void fpu_vrepib(u8 v1, s16 i2)
+{
+       asm volatile("VREPIB    %[v1],%[i2]"
+                    :
+                    : [v1] "I" (v1), [i2] "K" (i2)
+                    : "memory");
+}
+
+static __always_inline void fpu_vsrlb(u8 v1, u8 v2, u8 v3)
+{
+       asm volatile("VSRLB     %[v1],%[v2],%[v3]"
+                    :
+                    : [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
+                    : "memory");
+}
+
+#ifdef CONFIG_CC_IS_CLANG
+
+static __always_inline void fpu_vst(u8 v1, const void *vxr)
+{
+       instrument_write(vxr, sizeof(__vector128));
+       asm volatile("\n"
+               "       la      1,%[vxr]\n"
+               "       VST     %[v1],0,,1\n"
+               : [vxr] "=R" (*(__vector128 *)vxr)
+               : [v1] "I" (v1)
+               : "memory", "1");
+}
+
+#else /* CONFIG_CC_IS_CLANG */
+
+static __always_inline void fpu_vst(u8 v1, const void *vxr)
+{
+       instrument_write(vxr, sizeof(__vector128));
+       asm volatile("VST       %[v1],%O[vxr],,%R[vxr]\n"
+                    : [vxr] "=Q" (*(__vector128 *)vxr)
+                    : [v1] "I" (v1)
+                    : "memory");
+}
+
+#endif /* CONFIG_CC_IS_CLANG */
+
+#ifdef CONFIG_CC_IS_CLANG
+
+static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr)
+{
+       unsigned int size;
+
+       size = min(index + 1, sizeof(__vector128));
+       instrument_write(vxr, size);
+       asm volatile("\n"
+               "       la      1,%[vxr]\n"
+               "       VSTL    %[v1],%[index],0,1\n"
+               : [vxr] "=R" (*(u8 *)vxr)
+               : [index] "d" (index), [v1] "I" (v1)
+               : "memory", "1");
+}
+
+#else /* CONFIG_CC_IS_CLANG */
+
+static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr)
+{
+       unsigned int size;
+
+       size = min(index + 1, sizeof(__vector128));
+       instrument_write(vxr, size);
+       asm volatile("VSTL      %[v1],%[index],%O[vxr],%R[vxr]\n"
+                    : [vxr] "=Q" (*(u8 *)vxr)
+                    : [index] "d" (index), [v1] "I" (v1)
+                    : "memory");
+}
+
+#endif /* CONFIG_CC_IS_CLANG */
+
+#ifdef CONFIG_CC_IS_CLANG
+
+#define fpu_vstm(_v1, _v3, _vxrs)                                      \
+({                                                                     \
+       unsigned int size = ((_v3) - (_v1) + 1) * sizeof(__vector128);  \
+       struct {                                                        \
+               __vector128 _v[(_v3) - (_v1) + 1];                      \
+       } *_v = (void *)(_vxrs);                                        \
+                                                                       \
+       instrument_write(_v, size);                                     \
+       asm volatile("\n"                                               \
+               "       la      1,%[vxrs]\n"                            \
+               "       VSTM    %[v1],%[v3],0,1\n"                      \
+               : [vxrs] "=R" (*_v)                                     \
+               : [v1] "I" (_v1), [v3] "I" (_v3)                        \
+               : "memory", "1");                                       \
+       (_v3) - (_v1) + 1;                                              \
+})
+
+#else /* CONFIG_CC_IS_CLANG */
+
+#define fpu_vstm(_v1, _v3, _vxrs)                                      \
+({                                                                     \
+       unsigned int size = ((_v3) - (_v1) + 1) * sizeof(__vector128);  \
+       struct {                                                        \
+               __vector128 _v[(_v3) - (_v1) + 1];                      \
+       } *_v = (void *)(_vxrs);                                        \
+                                                                       \
+       instrument_write(_v, size);                                     \
+       asm volatile("VSTM      %[v1],%[v3],%O[vxrs],%R[vxrs]\n"        \
+                    : [vxrs] "=Q" (*_v)                                \
+                    : [v1] "I" (_v1), [v3] "I" (_v3)                   \
+                    : "memory");                                       \
+       (_v3) - (_v1) + 1;                                              \
+})
+
+#endif /* CONFIG_CC_IS_CLANG */
+
+static __always_inline void fpu_vupllf(u8 v1, u8 v2)
+{
+       asm volatile("VUPLLF    %[v1],%[v2]"
+                    :
+                    : [v1] "I" (v1), [v2] "I" (v2)
+                    : "memory");
+}
+
+static __always_inline void fpu_vx(u8 v1, u8 v2, u8 v3)
+{
+       asm volatile("VX        %[v1],%[v2],%[v3]"
+                    :
+                    : [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
+                    : "memory");
+}
+
+static __always_inline void fpu_vzero(u8 v)
+{
+       asm volatile("VZERO     %[v]"
+                    :
+                    : [v] "I" (v)
+                    : "memory");
+}
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_S390_FPU_INSN_H */
diff --git a/arch/s390/include/asm/fpu-types.h b/arch/s390/include/asm/fpu-types.h
new file mode 100644 (file)
index 0000000..8d58d5a
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * FPU data structures
+ *
+ * Copyright IBM Corp. 2015
+ * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ */
+
+#ifndef _ASM_S390_FPU_TYPES_H
+#define _ASM_S390_FPU_TYPES_H
+
+#include <asm/sigcontext.h>
+
+struct fpu {
+       u32 fpc;
+       __vector128 vxrs[__NUM_VXRS] __aligned(8);
+};
+
+struct kernel_fpu_hdr {
+       int     mask;
+       u32     fpc;
+};
+
+struct kernel_fpu {
+       struct kernel_fpu_hdr hdr;
+       __vector128 vxrs[] __aligned(8);
+};
+
+#define KERNEL_FPU_STRUCT(vxr_size)                            \
+struct kernel_fpu_##vxr_size {                                 \
+       struct kernel_fpu_hdr hdr;                              \
+       __vector128 vxrs[vxr_size] __aligned(8);                \
+}
+
+KERNEL_FPU_STRUCT(8);
+KERNEL_FPU_STRUCT(16);
+KERNEL_FPU_STRUCT(32);
+
+#define DECLARE_KERNEL_FPU_ONSTACK(vxr_size, name)             \
+       struct kernel_fpu_##vxr_size name __uninitialized
+
+#define DECLARE_KERNEL_FPU_ONSTACK8(name)                      \
+       DECLARE_KERNEL_FPU_ONSTACK(8, name)
+
+#define DECLARE_KERNEL_FPU_ONSTACK16(name)                     \
+       DECLARE_KERNEL_FPU_ONSTACK(16, name)
+
+#define DECLARE_KERNEL_FPU_ONSTACK32(name)                     \
+       DECLARE_KERNEL_FPU_ONSTACK(32, name)
+
+#endif /* _ASM_S390_FPU_TYPES_H */
diff --git a/arch/s390/include/asm/fpu.h b/arch/s390/include/asm/fpu.h
new file mode 100644 (file)
index 0000000..c84cb33
--- /dev/null
@@ -0,0 +1,295 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * In-kernel FPU support functions
+ *
+ *
+ * Consider these guidelines before using in-kernel FPU functions:
+ *
+ *  1. Use kernel_fpu_begin() and kernel_fpu_end() to enclose all in-kernel
+ *     use of floating-point or vector registers and instructions.
+ *
+ *  2. For kernel_fpu_begin(), specify the vector register range you want to
+ *     use with the KERNEL_VXR_* constants. Consider these usage guidelines:
+ *
+ *     a) If your function typically runs in process-context, use the lower
+ *       half of the vector registers, for example, specify KERNEL_VXR_LOW.
+ *     b) If your function typically runs in soft-irq or hard-irq context,
+ *       prefer using the upper half of the vector registers, for example,
+ *       specify KERNEL_VXR_HIGH.
+ *
+ *     If you adhere to these guidelines, an interrupted process context
+ *     does not require to save and restore vector registers because of
+ *     disjoint register ranges.
+ *
+ *     Also note that the __kernel_fpu_begin()/__kernel_fpu_end() functions
+ *     includes logic to save and restore up to 16 vector registers at once.
+ *
+ *  3. You can nest kernel_fpu_begin()/kernel_fpu_end() by using different
+ *     struct kernel_fpu states.  Vector registers that are in use by outer
+ *     levels are saved and restored.  You can minimize the save and restore
+ *     effort by choosing disjoint vector register ranges.
+ *
+ *  5. To use vector floating-point instructions, specify the KERNEL_FPC
+ *     flag to save and restore floating-point controls in addition to any
+ *     vector register range.
+ *
+ *  6. To use floating-point registers and instructions only, specify the
+ *     KERNEL_FPR flag.  This flag triggers a save and restore of vector
+ *     registers V0 to V15 and floating-point controls.
+ *
+ * Copyright IBM Corp. 2015
+ * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ */
+
+#ifndef _ASM_S390_FPU_H
+#define _ASM_S390_FPU_H
+
+#include <linux/processor.h>
+#include <linux/preempt.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <asm/sigcontext.h>
+#include <asm/fpu-types.h>
+#include <asm/fpu-insn.h>
+#include <asm/facility.h>
+
+static inline bool cpu_has_vx(void)
+{
+       return likely(test_facility(129));
+}
+
+enum {
+       KERNEL_FPC_BIT = 0,
+       KERNEL_VXR_V0V7_BIT,
+       KERNEL_VXR_V8V15_BIT,
+       KERNEL_VXR_V16V23_BIT,
+       KERNEL_VXR_V24V31_BIT,
+};
+
+#define KERNEL_FPC             BIT(KERNEL_FPC_BIT)
+#define KERNEL_VXR_V0V7                BIT(KERNEL_VXR_V0V7_BIT)
+#define KERNEL_VXR_V8V15       BIT(KERNEL_VXR_V8V15_BIT)
+#define KERNEL_VXR_V16V23      BIT(KERNEL_VXR_V16V23_BIT)
+#define KERNEL_VXR_V24V31      BIT(KERNEL_VXR_V24V31_BIT)
+
+#define KERNEL_VXR_LOW         (KERNEL_VXR_V0V7   | KERNEL_VXR_V8V15)
+#define KERNEL_VXR_MID         (KERNEL_VXR_V8V15  | KERNEL_VXR_V16V23)
+#define KERNEL_VXR_HIGH                (KERNEL_VXR_V16V23 | KERNEL_VXR_V24V31)
+
+#define KERNEL_VXR             (KERNEL_VXR_LOW    | KERNEL_VXR_HIGH)
+#define KERNEL_FPR             (KERNEL_FPC        | KERNEL_VXR_LOW)
+
+void load_fpu_state(struct fpu *state, int flags);
+void save_fpu_state(struct fpu *state, int flags);
+void __kernel_fpu_begin(struct kernel_fpu *state, int flags);
+void __kernel_fpu_end(struct kernel_fpu *state, int flags);
+
+static __always_inline void save_vx_regs(__vector128 *vxrs)
+{
+       fpu_vstm(0, 15, &vxrs[0]);
+       fpu_vstm(16, 31, &vxrs[16]);
+}
+
+static __always_inline void load_vx_regs(__vector128 *vxrs)
+{
+       fpu_vlm(0, 15, &vxrs[0]);
+       fpu_vlm(16, 31, &vxrs[16]);
+}
+
+static __always_inline void __save_fp_regs(freg_t *fprs, unsigned int offset)
+{
+       fpu_std(0, &fprs[0 * offset]);
+       fpu_std(1, &fprs[1 * offset]);
+       fpu_std(2, &fprs[2 * offset]);
+       fpu_std(3, &fprs[3 * offset]);
+       fpu_std(4, &fprs[4 * offset]);
+       fpu_std(5, &fprs[5 * offset]);
+       fpu_std(6, &fprs[6 * offset]);
+       fpu_std(7, &fprs[7 * offset]);
+       fpu_std(8, &fprs[8 * offset]);
+       fpu_std(9, &fprs[9 * offset]);
+       fpu_std(10, &fprs[10 * offset]);
+       fpu_std(11, &fprs[11 * offset]);
+       fpu_std(12, &fprs[12 * offset]);
+       fpu_std(13, &fprs[13 * offset]);
+       fpu_std(14, &fprs[14 * offset]);
+       fpu_std(15, &fprs[15 * offset]);
+}
+
+static __always_inline void __load_fp_regs(freg_t *fprs, unsigned int offset)
+{
+       fpu_ld(0, &fprs[0 * offset]);
+       fpu_ld(1, &fprs[1 * offset]);
+       fpu_ld(2, &fprs[2 * offset]);
+       fpu_ld(3, &fprs[3 * offset]);
+       fpu_ld(4, &fprs[4 * offset]);
+       fpu_ld(5, &fprs[5 * offset]);
+       fpu_ld(6, &fprs[6 * offset]);
+       fpu_ld(7, &fprs[7 * offset]);
+       fpu_ld(8, &fprs[8 * offset]);
+       fpu_ld(9, &fprs[9 * offset]);
+       fpu_ld(10, &fprs[10 * offset]);
+       fpu_ld(11, &fprs[11 * offset]);
+       fpu_ld(12, &fprs[12 * offset]);
+       fpu_ld(13, &fprs[13 * offset]);
+       fpu_ld(14, &fprs[14 * offset]);
+       fpu_ld(15, &fprs[15 * offset]);
+}
+
+static __always_inline void save_fp_regs(freg_t *fprs)
+{
+       __save_fp_regs(fprs, sizeof(freg_t) / sizeof(freg_t));
+}
+
+static __always_inline void load_fp_regs(freg_t *fprs)
+{
+       __load_fp_regs(fprs, sizeof(freg_t) / sizeof(freg_t));
+}
+
+static __always_inline void save_fp_regs_vx(__vector128 *vxrs)
+{
+       freg_t *fprs = (freg_t *)&vxrs[0].high;
+
+       __save_fp_regs(fprs, sizeof(__vector128) / sizeof(freg_t));
+}
+
+static __always_inline void load_fp_regs_vx(__vector128 *vxrs)
+{
+       freg_t *fprs = (freg_t *)&vxrs[0].high;
+
+       __load_fp_regs(fprs, sizeof(__vector128) / sizeof(freg_t));
+}
+
+static inline void load_user_fpu_regs(void)
+{
+       struct thread_struct *thread = &current->thread;
+
+       if (!thread->ufpu_flags)
+               return;
+       load_fpu_state(&thread->ufpu, thread->ufpu_flags);
+       thread->ufpu_flags = 0;
+}
+
+static __always_inline void __save_user_fpu_regs(struct thread_struct *thread, int flags)
+{
+       save_fpu_state(&thread->ufpu, flags);
+       __atomic_or(flags, &thread->ufpu_flags);
+}
+
+static inline void save_user_fpu_regs(void)
+{
+       struct thread_struct *thread = &current->thread;
+       int mask, flags;
+
+       mask = __atomic_or(KERNEL_FPC | KERNEL_VXR, &thread->kfpu_flags);
+       flags = ~READ_ONCE(thread->ufpu_flags) & (KERNEL_FPC | KERNEL_VXR);
+       if (flags)
+               __save_user_fpu_regs(thread, flags);
+       barrier();
+       WRITE_ONCE(thread->kfpu_flags, mask);
+}
+
+static __always_inline void _kernel_fpu_begin(struct kernel_fpu *state, int flags)
+{
+       struct thread_struct *thread = &current->thread;
+       int mask, uflags;
+
+       mask = __atomic_or(flags, &thread->kfpu_flags);
+       state->hdr.mask = mask;
+       uflags = READ_ONCE(thread->ufpu_flags);
+       if ((uflags & flags) != flags)
+               __save_user_fpu_regs(thread, ~uflags & flags);
+       if (mask & flags)
+               __kernel_fpu_begin(state, flags);
+}
+
+static __always_inline void _kernel_fpu_end(struct kernel_fpu *state, int flags)
+{
+       int mask = state->hdr.mask;
+
+       if (mask & flags)
+               __kernel_fpu_end(state, flags);
+       barrier();
+       WRITE_ONCE(current->thread.kfpu_flags, mask);
+}
+
+void __kernel_fpu_invalid_size(void);
+
+static __always_inline void kernel_fpu_check_size(int flags, unsigned int size)
+{
+       unsigned int cnt = 0;
+
+       if (flags & KERNEL_VXR_V0V7)
+               cnt += 8;
+       if (flags & KERNEL_VXR_V8V15)
+               cnt += 8;
+       if (flags & KERNEL_VXR_V16V23)
+               cnt += 8;
+       if (flags & KERNEL_VXR_V24V31)
+               cnt += 8;
+       if (cnt != size)
+               __kernel_fpu_invalid_size();
+}
+
+#define kernel_fpu_begin(state, flags)                                 \
+{                                                                      \
+       typeof(state) s = (state);                                      \
+       int _flags = (flags);                                           \
+                                                                       \
+       kernel_fpu_check_size(_flags, ARRAY_SIZE(s->vxrs));             \
+       _kernel_fpu_begin((struct kernel_fpu *)s, _flags);              \
+}
+
+#define kernel_fpu_end(state, flags)                                   \
+{                                                                      \
+       typeof(state) s = (state);                                      \
+       int _flags = (flags);                                           \
+                                                                       \
+       kernel_fpu_check_size(_flags, ARRAY_SIZE(s->vxrs));             \
+       _kernel_fpu_end((struct kernel_fpu *)s, _flags);                \
+}
+
+static inline void save_kernel_fpu_regs(struct thread_struct *thread)
+{
+       if (!thread->kfpu_flags)
+               return;
+       save_fpu_state(&thread->kfpu, thread->kfpu_flags);
+}
+
+static inline void restore_kernel_fpu_regs(struct thread_struct *thread)
+{
+       if (!thread->kfpu_flags)
+               return;
+       load_fpu_state(&thread->kfpu, thread->kfpu_flags);
+}
+
+static inline void convert_vx_to_fp(freg_t *fprs, __vector128 *vxrs)
+{
+       int i;
+
+       for (i = 0; i < __NUM_FPRS; i++)
+               fprs[i].ui = vxrs[i].high;
+}
+
+static inline void convert_fp_to_vx(__vector128 *vxrs, freg_t *fprs)
+{
+       int i;
+
+       for (i = 0; i < __NUM_FPRS; i++)
+               vxrs[i].high = fprs[i].ui;
+}
+
+static inline void fpregs_store(_s390_fp_regs *fpregs, struct fpu *fpu)
+{
+       fpregs->pad = 0;
+       fpregs->fpc = fpu->fpc;
+       convert_vx_to_fp((freg_t *)&fpregs->fprs, fpu->vxrs);
+}
+
+static inline void fpregs_load(_s390_fp_regs *fpregs, struct fpu *fpu)
+{
+       fpu->fpc = fpregs->fpc;
+       convert_fp_to_vx(fpu->vxrs, (freg_t *)&fpregs->fprs);
+}
+
+#endif /* _ASM_S390_FPU_H */
diff --git a/arch/s390/include/asm/fpu/api.h b/arch/s390/include/asm/fpu/api.h
deleted file mode 100644 (file)
index d6ca8bc..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * In-kernel FPU support functions
- *
- *
- * Consider these guidelines before using in-kernel FPU functions:
- *
- *  1. Use kernel_fpu_begin() and kernel_fpu_end() to enclose all in-kernel
- *     use of floating-point or vector registers and instructions.
- *
- *  2. For kernel_fpu_begin(), specify the vector register range you want to
- *     use with the KERNEL_VXR_* constants. Consider these usage guidelines:
- *
- *     a) If your function typically runs in process-context, use the lower
- *       half of the vector registers, for example, specify KERNEL_VXR_LOW.
- *     b) If your function typically runs in soft-irq or hard-irq context,
- *       prefer using the upper half of the vector registers, for example,
- *       specify KERNEL_VXR_HIGH.
- *
- *     If you adhere to these guidelines, an interrupted process context
- *     does not require to save and restore vector registers because of
- *     disjoint register ranges.
- *
- *     Also note that the __kernel_fpu_begin()/__kernel_fpu_end() functions
- *     includes logic to save and restore up to 16 vector registers at once.
- *
- *  3. You can nest kernel_fpu_begin()/kernel_fpu_end() by using different
- *     struct kernel_fpu states.  Vector registers that are in use by outer
- *     levels are saved and restored.  You can minimize the save and restore
- *     effort by choosing disjoint vector register ranges.
- *
- *  5. To use vector floating-point instructions, specify the KERNEL_FPC
- *     flag to save and restore floating-point controls in addition to any
- *     vector register range.
- *
- *  6. To use floating-point registers and instructions only, specify the
- *     KERNEL_FPR flag.  This flag triggers a save and restore of vector
- *     registers V0 to V15 and floating-point controls.
- *
- * Copyright IBM Corp. 2015
- * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
- */
-
-#ifndef _ASM_S390_FPU_API_H
-#define _ASM_S390_FPU_API_H
-
-#include <linux/preempt.h>
-#include <asm/asm-extable.h>
-#include <asm/fpu/internal.h>
-
-void save_fpu_regs(void);
-void load_fpu_regs(void);
-void __load_fpu_regs(void);
-
-/**
- * sfpc_safe - Set floating point control register safely.
- * @fpc: new value for floating point control register
- *
- * Set floating point control register. This may lead to an exception,
- * since a saved value may have been modified by user space (ptrace,
- * signal return, kvm registers) to an invalid value. In such a case
- * set the floating point control register to zero.
- */
-static inline void sfpc_safe(u32 fpc)
-{
-       asm volatile("\n"
-               "0:     sfpc    %[fpc]\n"
-               "1:     nopr    %%r7\n"
-               ".pushsection .fixup, \"ax\"\n"
-               "2:     lghi    %[fpc],0\n"
-               "       jg      0b\n"
-               ".popsection\n"
-               EX_TABLE(1b, 2b)
-               : [fpc] "+d" (fpc)
-               : : "memory");
-}
-
-#define KERNEL_FPC             1
-#define KERNEL_VXR_V0V7                2
-#define KERNEL_VXR_V8V15       4
-#define KERNEL_VXR_V16V23      8
-#define KERNEL_VXR_V24V31      16
-
-#define KERNEL_VXR_LOW         (KERNEL_VXR_V0V7|KERNEL_VXR_V8V15)
-#define KERNEL_VXR_MID         (KERNEL_VXR_V8V15|KERNEL_VXR_V16V23)
-#define KERNEL_VXR_HIGH                (KERNEL_VXR_V16V23|KERNEL_VXR_V24V31)
-
-#define KERNEL_VXR             (KERNEL_VXR_LOW|KERNEL_VXR_HIGH)
-#define KERNEL_FPR             (KERNEL_FPC|KERNEL_VXR_LOW)
-
-struct kernel_fpu;
-
-/*
- * Note the functions below must be called with preemption disabled.
- * Do not enable preemption before calling __kernel_fpu_end() to prevent
- * an corruption of an existing kernel FPU state.
- *
- * Prefer using the kernel_fpu_begin()/kernel_fpu_end() pair of functions.
- */
-void __kernel_fpu_begin(struct kernel_fpu *state, u32 flags);
-void __kernel_fpu_end(struct kernel_fpu *state, u32 flags);
-
-
-static inline void kernel_fpu_begin(struct kernel_fpu *state, u32 flags)
-{
-       preempt_disable();
-       state->mask = S390_lowcore.fpu_flags;
-       if (!test_cpu_flag(CIF_FPU))
-               /* Save user space FPU state and register contents */
-               save_fpu_regs();
-       else if (state->mask & flags)
-               /* Save FPU/vector register in-use by the kernel */
-               __kernel_fpu_begin(state, flags);
-       S390_lowcore.fpu_flags |= flags;
-}
-
-static inline void kernel_fpu_end(struct kernel_fpu *state, u32 flags)
-{
-       S390_lowcore.fpu_flags = state->mask;
-       if (state->mask & flags)
-               /* Restore FPU/vector register in-use by the kernel */
-               __kernel_fpu_end(state, flags);
-       preempt_enable();
-}
-
-#endif /* _ASM_S390_FPU_API_H */
diff --git a/arch/s390/include/asm/fpu/internal.h b/arch/s390/include/asm/fpu/internal.h
deleted file mode 100644 (file)
index d511c4c..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * FPU state and register content conversion primitives
- *
- * Copyright IBM Corp. 2015
- * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
- */
-
-#ifndef _ASM_S390_FPU_INTERNAL_H
-#define _ASM_S390_FPU_INTERNAL_H
-
-#include <linux/string.h>
-#include <asm/facility.h>
-#include <asm/fpu/types.h>
-
-static inline bool cpu_has_vx(void)
-{
-       return likely(test_facility(129));
-}
-
-static inline void save_vx_regs(__vector128 *vxrs)
-{
-       asm volatile(
-               "       la      1,%0\n"
-               "       .word   0xe70f,0x1000,0x003e\n" /* vstm 0,15,0(1) */
-               "       .word   0xe70f,0x1100,0x0c3e\n" /* vstm 16,31,256(1) */
-               : "=Q" (*(struct vx_array *) vxrs) : : "1");
-}
-
-static inline void convert_vx_to_fp(freg_t *fprs, __vector128 *vxrs)
-{
-       int i;
-
-       for (i = 0; i < __NUM_FPRS; i++)
-               fprs[i].ui = vxrs[i].high;
-}
-
-static inline void convert_fp_to_vx(__vector128 *vxrs, freg_t *fprs)
-{
-       int i;
-
-       for (i = 0; i < __NUM_FPRS; i++)
-               vxrs[i].high = fprs[i].ui;
-}
-
-static inline void fpregs_store(_s390_fp_regs *fpregs, struct fpu *fpu)
-{
-       fpregs->pad = 0;
-       fpregs->fpc = fpu->fpc;
-       if (cpu_has_vx())
-               convert_vx_to_fp((freg_t *)&fpregs->fprs, fpu->vxrs);
-       else
-               memcpy((freg_t *)&fpregs->fprs, fpu->fprs,
-                      sizeof(fpregs->fprs));
-}
-
-static inline void fpregs_load(_s390_fp_regs *fpregs, struct fpu *fpu)
-{
-       fpu->fpc = fpregs->fpc;
-       if (cpu_has_vx())
-               convert_fp_to_vx(fpu->vxrs, (freg_t *)&fpregs->fprs);
-       else
-               memcpy(fpu->fprs, (freg_t *)&fpregs->fprs,
-                      sizeof(fpregs->fprs));
-}
-
-#endif /* _ASM_S390_FPU_INTERNAL_H */
diff --git a/arch/s390/include/asm/fpu/types.h b/arch/s390/include/asm/fpu/types.h
deleted file mode 100644 (file)
index d889e94..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * FPU data structures
- *
- * Copyright IBM Corp. 2015
- * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
- */
-
-#ifndef _ASM_S390_FPU_TYPES_H
-#define _ASM_S390_FPU_TYPES_H
-
-#include <asm/sigcontext.h>
-
-struct fpu {
-       __u32 fpc;              /* Floating-point control */
-       void *regs;             /* Pointer to the current save area */
-       union {
-               /* Floating-point register save area */
-               freg_t fprs[__NUM_FPRS];
-               /* Vector register save area */
-               __vector128 vxrs[__NUM_VXRS];
-       };
-};
-
-/* VX array structure for address operand constraints in inline assemblies */
-struct vx_array { __vector128 _[__NUM_VXRS]; };
-
-/* In-kernel FPU state structure */
-struct kernel_fpu {
-       u32         mask;
-       u32         fpc;
-       union {
-               freg_t fprs[__NUM_FPRS];
-               __vector128 vxrs[__NUM_VXRS];
-       };
-};
-
-#endif /* _ASM_S390_FPU_TYPES_H */
index 52664105a473f97b923fb104c2e0c279b4b02cef..95990461888fcaee7759af29874071207797ad74 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/mmu_notifier.h>
 #include <asm/debug.h>
 #include <asm/cpu.h>
-#include <asm/fpu/api.h>
+#include <asm/fpu.h>
 #include <asm/isc.h>
 #include <asm/guarded_storage.h>
 
@@ -743,7 +743,6 @@ struct kvm_vcpu_arch {
        struct kvm_s390_sie_block *vsie_block;
        unsigned int      host_acrs[NUM_ACRS];
        struct gs_cb      *host_gscb;
-       struct fpu        host_fpregs;
        struct kvm_s390_local_interrupt local_int;
        struct hrtimer    ckc_timer;
        struct kvm_s390_pgm_info pgm;
@@ -765,6 +764,8 @@ struct kvm_vcpu_arch {
        __u64 cputm_start;
        bool gs_enabled;
        bool skey_enabled;
+       /* Indicator if the access registers have been loaded from guest */
+       bool acrs_loaded;
        struct kvm_s390_pv_vcpu pv;
        union diag318_info diag318_info;
 };
index 5dc1b63450065bc5f02e30f4567715e2aece1648..8c5f168575399383368b72ce5f80b768fadf9351 100644 (file)
@@ -157,7 +157,7 @@ struct lowcore {
        __s32   preempt_count;                  /* 0x03a8 */
        __u32   spinlock_lockval;               /* 0x03ac */
        __u32   spinlock_index;                 /* 0x03b0 */
-       __u32   fpu_flags;                      /* 0x03b4 */
+       __u8    pad_0x03b4[0x03b8-0x03b4];      /* 0x03b4 */
        __u64   percpu_offset;                  /* 0x03b8 */
        __u8    pad_0x03c0[0x03c8-0x03c0];      /* 0x03c0 */
        __u64   machine_flags;                  /* 0x03c8 */
index 73b9c3bf377f886411b687992024217e4371e08b..ded9548d11d92535c4a27cf8d72d11bd680cdd68 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/const.h>
 #include <asm/types.h>
 
-#define _PAGE_SHIFT    12
+#define _PAGE_SHIFT    CONFIG_PAGE_SHIFT
 #define _PAGE_SIZE     (_AC(1, UL) << _PAGE_SHIFT)
 #define _PAGE_MASK     (~(_PAGE_SIZE - 1))
 
index 7d1888e3dee6a670f1ec25cc2ac71640f06fd5b6..3f609565734b553157f6626ecc64e18d89423d91 100644 (file)
@@ -16,7 +16,7 @@ struct qpaci_info_block {
        u64 header;
        struct {
                u64 : 8;
-               u64 num_cc : 8; /* # of supported crypto counters */
+               u64 num_cc : 8;         /* # of supported crypto counters */
                u64 : 9;
                u64 num_nnpa : 7;       /* # of supported NNPA counters */
                u64 : 32;
@@ -81,4 +81,5 @@ enum paievt_mode {
        PAI_MODE_COUNTING,
 };
 
+#define PAI_SAVE_AREA(x)       ((x)->hw.event_base)
 #endif
index e91cd6bbc330d960996eb0b0f9148e0a818ba3ef..30820a649e6e7cfbba67a4aae4aa41d06c523693 100644 (file)
@@ -122,6 +122,7 @@ struct zpci_dev {
        struct rcu_head rcu;
        struct hotplug_slot hotplug_slot;
 
+       struct mutex state_lock;        /* protect state changes */
        enum zpci_state state;
        u32             fid;            /* function ID, used by sclp */
        u32             fh;             /* function handle, used by insn's */
@@ -142,7 +143,6 @@ struct zpci_dev {
        u8              reserved        : 2;
        unsigned int    devfn;          /* DEVFN part of the RID*/
 
-       struct mutex lock;
        u8 pfip[CLP_PFIP_NR_SEGMENTS];  /* pci function internal path */
        u32 uid;                        /* user defined id */
        u8 util_str[CLP_UTIL_STR_LEN];  /* utility string */
@@ -170,6 +170,7 @@ struct zpci_dev {
        u64             dma_mask;       /* DMA address space mask */
 
        /* Function measurement block */
+       struct mutex fmb_lock;
        struct zpci_fmb *fmb;
        u16             fmb_update;     /* update interval */
        u16             fmb_length;
index 9e41a74fce9ac64fdf9de24f4e421f69e506d280..e747b067f8dbbf34c7ee0e3922c82325838d2a43 100644 (file)
@@ -22,6 +22,7 @@ enum reserved_range_type {
        RR_DECOMPRESSOR,
        RR_INITRD,
        RR_VMLINUX,
+       RR_RELOC,
        RR_AMODE31,
        RR_IPLREPORT,
        RR_CERT_COMP_LIST,
index c0b6e74d899a495d4579c1ea60f6e4d72e33921c..7cf00cf8fb0bc6197721987037c5f53ded7870bf 100644 (file)
 #include <linux/bits.h>
 
 #define CIF_NOHZ_DELAY         2       /* delay HZ disable for a tick */
-#define CIF_FPU                        3       /* restore FPU registers */
 #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_FPU               BIT(CIF_FPU)
 #define _CIF_ENABLED_WAIT      BIT(CIF_ENABLED_WAIT)
 #define _CIF_MCCK_GUEST                BIT(CIF_MCCK_GUEST)
 #define _CIF_DEDICATED_CPU     BIT(CIF_DEDICATED_CPU)
 #include <linux/cpumask.h>
 #include <linux/linkage.h>
 #include <linux/irqflags.h>
+#include <asm/fpu-types.h>
 #include <asm/cpu.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/setup.h>
 #include <asm/runtime_instr.h>
-#include <asm/fpu/types.h>
-#include <asm/fpu/internal.h>
 #include <asm/irqflags.h>
 
 typedef long (*sys_call_ptr_t)(struct pt_regs *regs);
@@ -169,6 +166,8 @@ struct thread_struct {
        unsigned int gmap_write_flag;           /* gmap fault write indication */
        unsigned int gmap_int_code;             /* int code of last gmap fault */
        unsigned int gmap_pfault;               /* signal of a pending guest pfault */
+       int ufpu_flags;                         /* user fpu flags */
+       int kfpu_flags;                         /* kernel fpu flags */
 
        /* Per-thread information related to debugging */
        struct per_regs per_user;               /* User specified PER registers */
@@ -184,7 +183,8 @@ struct thread_struct {
        struct gs_cb *gs_cb;                    /* Current guarded storage cb */
        struct gs_cb *gs_bc_cb;                 /* Broadcast guarded storage cb */
        struct pgm_tdb trap_tdb;                /* Transaction abort diagnose block */
-       struct fpu fpu;                         /* FP and VX register save area */
+       struct fpu ufpu;                        /* User FP and VX register save area */
+       struct fpu kfpu;                        /* Kernel FP and VX register save area */
 };
 
 /* Flag to disable transactions. */
@@ -203,7 +203,6 @@ typedef struct thread_struct thread_struct;
 
 #define INIT_THREAD {                                                  \
        .ksp = sizeof(init_stack) + (unsigned long) &init_stack,        \
-       .fpu.regs = (void *) init_task.thread.fpu.fprs,                 \
        .last_break = 1,                                                \
 }
 
index d28bf8fb279959409397b60e82086e0fa56e34d2..788bc4467445c9da9471cf5037bcf2887f1303e8 100644 (file)
@@ -203,6 +203,10 @@ static inline int test_and_clear_pt_regs_flag(struct pt_regs *regs, int flag)
        return ret;
 }
 
+struct task_struct;
+
+void update_cr_regs(struct task_struct *task);
+
 /*
  * These are defined as per linux/ptrace.h, which see.
  */
index 31ec4f545e036a26bfc0d8cc7fb8163fdd2c93a5..433fde85b14ea902308cdf5bf83583c7305473b1 100644 (file)
@@ -4,7 +4,6 @@
 
 #include <linux/uaccess.h>
 #include <linux/ptrace.h>
-#include <asm/switch_to.h>
 
 struct stack_frame_user {
        unsigned long back_chain;
diff --git a/arch/s390/include/asm/switch_to.h b/arch/s390/include/asm/switch_to.h
deleted file mode 100644 (file)
index c61b2cc..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright IBM Corp. 1999, 2009
- *
- * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
- */
-
-#ifndef __ASM_SWITCH_TO_H
-#define __ASM_SWITCH_TO_H
-
-#include <linux/thread_info.h>
-#include <asm/fpu/api.h>
-#include <asm/ptrace.h>
-#include <asm/guarded_storage.h>
-
-extern struct task_struct *__switch_to(void *, void *);
-extern void update_cr_regs(struct task_struct *task);
-
-static inline void save_access_regs(unsigned int *acrs)
-{
-       typedef struct { int _[NUM_ACRS]; } acrstype;
-
-       asm volatile("stam 0,15,%0" : "=Q" (*(acrstype *)acrs));
-}
-
-static inline void restore_access_regs(unsigned int *acrs)
-{
-       typedef struct { int _[NUM_ACRS]; } acrstype;
-
-       asm volatile("lam 0,15,%0" : : "Q" (*(acrstype *)acrs));
-}
-
-#define switch_to(prev, next, last) do {                               \
-       /* save_fpu_regs() sets the CIF_FPU flag, which enforces        \
-        * a restore of the floating point / vector registers as        \
-        * soon as the next task returns to user space                  \
-        */                                                             \
-       save_fpu_regs();                                                \
-       save_access_regs(&prev->thread.acrs[0]);                        \
-       save_ri_cb(prev->thread.ri_cb);                                 \
-       save_gs_cb(prev->thread.gs_cb);                                 \
-       update_cr_regs(next);                                           \
-       restore_access_regs(&next->thread.acrs[0]);                     \
-       restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);          \
-       restore_gs_cb(next->thread.gs_cb);                              \
-       prev = __switch_to(prev, next);                                 \
-} while (0)
-
-#endif /* __ASM_SWITCH_TO_H */
index 73ee8914266629559ad11053f79984ac49b4b97e..0e2b40ef69b049c5e79ab2e31811e1e6e6ef2475 100644 (file)
@@ -3,7 +3,6 @@
 #define __S390_ASM_VDSO_DATA_H
 
 #include <linux/types.h>
-#include <vdso/datapage.h>
 
 struct arch_vdso_data {
        __s64 tod_steering_delta;
diff --git a/arch/s390/include/asm/vx-insn.h b/arch/s390/include/asm/vx-insn.h
deleted file mode 100644 (file)
index 8c188f1..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Support for Vector Instructions
- *
- * This wrapper header file allows to use the vector instruction macros in
- * both assembler files as well as in inline assemblies in C files.
- */
-
-#ifndef __ASM_S390_VX_INSN_H
-#define __ASM_S390_VX_INSN_H
-
-#include <asm/vx-insn-asm.h>
-
-#ifndef __ASSEMBLY__
-
-asm(".include \"asm/vx-insn-asm.h\"\n");
-
-#endif /* __ASSEMBLY__ */
-#endif /* __ASM_S390_VX_INSN_H */
index 56254fa06f990614179c1f357f7c9f28afafc7cb..4f266903022091921be3fd97c200f4210627a948 100644 (file)
@@ -166,5 +166,6 @@ int populate_cache_leaves(unsigned int cpu)
                        ci_leaf_init(this_leaf++, pvt, ctype, level, cpu);
                }
        }
+       this_cpu_ci->cpu_map_populated = true;
        return 0;
 }
index f8fc6c25d0510b1a813c422368cedf917eae089b..1942e2a9f8db26bb2d00132d478bbd51ea709301 100644 (file)
 #include <linux/tty.h>
 #include <linux/personality.h>
 #include <linux/binfmts.h>
+#include <asm/access-regs.h>
 #include <asm/ucontext.h>
 #include <linux/uaccess.h>
 #include <asm/lowcore.h>
-#include <asm/switch_to.h>
 #include <asm/vdso.h>
-#include <asm/fpu/api.h>
+#include <asm/fpu.h>
 #include "compat_linux.h"
 #include "compat_ptrace.h"
 #include "entry.h"
@@ -56,7 +56,7 @@ typedef struct
 static void store_sigregs(void)
 {
        save_access_regs(current->thread.acrs);
-       save_fpu_regs();
+       save_user_fpu_regs();
 }
 
 /* Load registers after signal return */
@@ -79,7 +79,7 @@ static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
                user_sregs.regs.gprs[i] = (__u32) regs->gprs[i];
        memcpy(&user_sregs.regs.acrs, current->thread.acrs,
               sizeof(user_sregs.regs.acrs));
-       fpregs_store((_s390_fp_regs *) &user_sregs.fpregs, &current->thread.fpu);
+       fpregs_store((_s390_fp_regs *) &user_sregs.fpregs, &current->thread.ufpu);
        if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs32)))
                return -EFAULT;
        return 0;
@@ -113,7 +113,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
                regs->gprs[i] = (__u64) user_sregs.regs.gprs[i];
        memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
               sizeof(current->thread.acrs));
-       fpregs_load((_s390_fp_regs *) &user_sregs.fpregs, &current->thread.fpu);
+       fpregs_load((_s390_fp_regs *)&user_sregs.fpregs, &current->thread.ufpu);
 
        clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */
        return 0;
@@ -136,11 +136,11 @@ static int save_sigregs_ext32(struct pt_regs *regs,
        /* Save vector registers to signal stack */
        if (cpu_has_vx()) {
                for (i = 0; i < __NUM_VXRS_LOW; i++)
-                       vxrs[i] = current->thread.fpu.vxrs[i].low;
+                       vxrs[i] = current->thread.ufpu.vxrs[i].low;
                if (__copy_to_user(&sregs_ext->vxrs_low, vxrs,
                                   sizeof(sregs_ext->vxrs_low)) ||
                    __copy_to_user(&sregs_ext->vxrs_high,
-                                  current->thread.fpu.vxrs + __NUM_VXRS_LOW,
+                                  current->thread.ufpu.vxrs + __NUM_VXRS_LOW,
                                   sizeof(sregs_ext->vxrs_high)))
                        return -EFAULT;
        }
@@ -165,12 +165,12 @@ static int restore_sigregs_ext32(struct pt_regs *regs,
        if (cpu_has_vx()) {
                if (__copy_from_user(vxrs, &sregs_ext->vxrs_low,
                                     sizeof(sregs_ext->vxrs_low)) ||
-                   __copy_from_user(current->thread.fpu.vxrs + __NUM_VXRS_LOW,
+                   __copy_from_user(current->thread.ufpu.vxrs + __NUM_VXRS_LOW,
                                     &sregs_ext->vxrs_high,
                                     sizeof(sregs_ext->vxrs_high)))
                        return -EFAULT;
                for (i = 0; i < __NUM_VXRS_LOW; i++)
-                       current->thread.fpu.vxrs[i].low = vxrs[i];
+                       current->thread.ufpu.vxrs[i].low = vxrs[i];
        }
        return 0;
 }
@@ -184,7 +184,7 @@ COMPAT_SYSCALL_DEFINE0(sigreturn)
        if (get_compat_sigset(&set, (compat_sigset_t __user *)frame->sc.oldmask))
                goto badframe;
        set_current_blocked(&set);
-       save_fpu_regs();
+       save_user_fpu_regs();
        if (restore_sigregs32(regs, &frame->sregs))
                goto badframe;
        if (restore_sigregs_ext32(regs, &frame->sregs_ext))
@@ -207,7 +207,7 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
        set_current_blocked(&set);
        if (compat_restore_altstack(&frame->uc.uc_stack))
                goto badframe;
-       save_fpu_regs();
+       save_user_fpu_regs();
        if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
                goto badframe;
        if (restore_sigregs_ext32(regs, &frame->uc.uc_mcontext_ext))
index 5c46c26593054a679e9cddd74885d7cfd67d540a..d09ebb6f52625ef6b5021131cc18faedc75ca374 100644 (file)
@@ -22,7 +22,7 @@
 #include <asm/ipl.h>
 #include <asm/sclp.h>
 #include <asm/maccess.h>
-#include <asm/fpu/api.h>
+#include <asm/fpu.h>
 
 #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
 #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
index 92fdc35f028c7984129954eb35547e0569d3712a..8dee9aa0ec95b463397addfc0df299dad58730f0 100644 (file)
@@ -146,12 +146,41 @@ void notrace diag_stat_inc_norecursion(enum diag_stat_enum nr)
 }
 EXPORT_SYMBOL(diag_stat_inc_norecursion);
 
+/*
+ * Diagnose 0c: Pseudo Timer
+ */
+void diag0c(struct hypfs_diag0c_entry *data)
+{
+       diag_stat_inc(DIAG_STAT_X00C);
+       diag_amode31_ops.diag0c(virt_to_phys(data));
+}
+
 /*
  * Diagnose 14: Input spool file manipulation
+ *
+ * The subcode parameter determines the type of the first parameter rx.
+ * Currently used are the following 3 subcommands:
+ * 0x0:   Read the Next Spool File Buffer (Data Record)
+ * 0x28:  Position a Spool File to the Designated Record
+ * 0xfff: Retrieve Next File Descriptor
+ *
+ * For subcommands 0x0 and 0xfff, the value of the first parameter is
+ * a virtual address of a memory buffer and needs virtual to physical
+ * address translation. For other subcommands the rx parameter is not
+ * a virtual address.
  */
 int diag14(unsigned long rx, unsigned long ry1, unsigned long subcode)
 {
        diag_stat_inc(DIAG_STAT_X014);
+       switch (subcode) {
+       case 0x0:
+       case 0xfff:
+               rx = virt_to_phys((void *)rx);
+               break;
+       default:
+               /* Do nothing */
+               break;
+       }
        return diag_amode31_ops.diag14(rx, ry1, subcode);
 }
 EXPORT_SYMBOL(diag14);
@@ -265,6 +294,6 @@ EXPORT_SYMBOL(diag224);
 int diag26c(void *req, void *resp, enum diag26c_sc subcode)
 {
        diag_stat_inc(DIAG_STAT_X26C);
-       return diag_amode31_ops.diag26c(req, resp, subcode);
+       return diag_amode31_ops.diag26c(virt_to_phys(req), virt_to_phys(resp), subcode);
 }
 EXPORT_SYMBOL(diag26c);
index 2345ea332b97e21c99442d4e79883510bc9ae679..c666271433fb0ff38421be7f55393daf9302f769 100644 (file)
 #include <linux/kernel.h>
 #include <asm/asm-extable.h>
 #include <linux/memblock.h>
+#include <asm/access-regs.h>
 #include <asm/diag.h>
 #include <asm/ebcdic.h>
+#include <asm/fpu.h>
 #include <asm/ipl.h>
 #include <asm/lowcore.h>
 #include <asm/processor.h>
@@ -31,7 +33,6 @@
 #include <asm/sclp.h>
 #include <asm/facility.h>
 #include <asm/boot_data.h>
-#include <asm/switch_to.h>
 #include "entry.h"
 
 #define decompressor_handled_param(param)                      \
index 49a11f6dd7ae9a695bfda2e18523a625de81f6ed..fc5277eab554bb4f315bacc87017f8ae95558f81 100644 (file)
@@ -24,7 +24,7 @@
 #include <asm/page.h>
 #include <asm/sigp.h>
 #include <asm/irq.h>
-#include <asm/vx-insn.h>
+#include <asm/fpu-insn.h>
 #include <asm/setup.h>
 #include <asm/nmi.h>
 #include <asm/nospec-insn.h>
@@ -171,13 +171,13 @@ _LPP_OFFSET       = __LC_LPP
        nop     0
 
 /*
- * Scheduler resume function, called by switch_to
- *  gpr2 = (task_struct *) prev
- *  gpr3 = (task_struct *) next
+ * Scheduler resume function, called by __switch_to
+ *  gpr2 = (task_struct *)prev
+ *  gpr3 = (task_struct *)next
  * Returns:
  *  gpr2 = prev
  */
-SYM_FUNC_START(__switch_to)
+SYM_FUNC_START(__switch_to_asm)
        stmg    %r6,%r15,__SF_GPRS(%r15)        # store gprs of prev task
        lghi    %r4,__TASK_stack
        lghi    %r1,__TASK_thread
@@ -193,7 +193,7 @@ SYM_FUNC_START(__switch_to)
        lmg     %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
        ALTERNATIVE "nop", "lpp _LPP_OFFSET", 40
        BR_EX   %r14
-SYM_FUNC_END(__switch_to)
+SYM_FUNC_END(__switch_to_asm)
 
 #if IS_ENABLED(CONFIG_KVM)
 /*
@@ -220,8 +220,6 @@ SYM_FUNC_START(__sie64a)
        oi      __SIE_PROG0C+3(%r14),1          # we are going into SIE now
        tm      __SIE_PROG20+3(%r14),3          # last exit...
        jnz     .Lsie_skip
-       TSTMSK  __LC_CPU_FLAGS,_CIF_FPU
-       jo      .Lsie_skip                      # exit if fp/vx regs changed
        lg      %r14,__SF_SIE_CONTROL_PHYS(%r15)        # get sie block phys addr
        BPEXIT  __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
 .Lsie_entry:
@@ -489,16 +487,11 @@ SYM_FUNC_END(psw_idle)
  */
 SYM_CODE_START(mcck_int_handler)
        BPOFF
-       la      %r1,4095                # validate r1
-       spt     __LC_CPU_TIMER_SAVE_AREA-4095(%r1)      # validate cpu timer
-       LBEAR   __LC_LAST_BREAK_SAVE_AREA-4095(%r1)             # validate bear
-       lmg     %r0,%r15,__LC_GPREGS_SAVE_AREA          # validate gprs
        lmg     %r8,%r9,__LC_MCK_OLD_PSW
        TSTMSK  __LC_MCCK_CODE,MCCK_CODE_SYSTEM_DAMAGE
        jo      .Lmcck_panic            # yes -> rest of mcck code invalid
        TSTMSK  __LC_MCCK_CODE,MCCK_CODE_CR_VALID
        jno     .Lmcck_panic            # control registers invalid -> panic
-       lctlg   %c0,%c15,__LC_CREGS_SAVE_AREA           # validate ctl regs
        ptlb
        lghi    %r14,__LC_CPU_TIMER_SAVE_AREA
        mvc     __LC_MCCK_ENTER_TIMER(8),0(%r14)
index 9f41853f36b934bc8dd0675cd2bbe57e17377b2b..21969520f947d42a3d631bc59d8c4786853eb6ee 100644 (file)
@@ -19,6 +19,7 @@ void mcck_int_handler(void);
 void restart_int_handler(void);
 void early_pgm_check_handler(void);
 
+struct task_struct *__switch_to_asm(struct task_struct *prev, struct task_struct *next);
 void __ret_from_fork(struct task_struct *prev, struct pt_regs *regs);
 void __do_pgm_check(struct pt_regs *regs);
 void __do_syscall(struct pt_regs *regs, int per_trap);
index a4f3449cc814162b9972faa67e33481b8a42a65f..fa90bbdc5ef9467c70dcba01f11e2d2ed273e115 100644 (file)
 #include <linux/kernel.h>
 #include <linux/cpu.h>
 #include <linux/sched.h>
-#include <asm/fpu/types.h>
-#include <asm/fpu/api.h>
-#include <asm/vx-insn.h>
+#include <asm/fpu.h>
 
-void __kernel_fpu_begin(struct kernel_fpu *state, u32 flags)
+void __kernel_fpu_begin(struct kernel_fpu *state, int flags)
 {
+       __vector128 *vxrs = state->vxrs;
+       int mask;
+
        /*
         * Limit the save to the FPU/vector registers already
-        * in use by the previous context
+        * in use by the previous context.
         */
-       flags &= state->mask;
-
+       flags &= state->hdr.mask;
        if (flags & KERNEL_FPC)
-               /* Save floating point control */
-               asm volatile("stfpc %0" : "=Q" (state->fpc));
-
+               fpu_stfpc(&state->hdr.fpc);
        if (!cpu_has_vx()) {
-               if (flags & KERNEL_VXR_V0V7) {
-                       /* Save floating-point registers */
-                       asm volatile("std 0,%0" : "=Q" (state->fprs[0]));
-                       asm volatile("std 1,%0" : "=Q" (state->fprs[1]));
-                       asm volatile("std 2,%0" : "=Q" (state->fprs[2]));
-                       asm volatile("std 3,%0" : "=Q" (state->fprs[3]));
-                       asm volatile("std 4,%0" : "=Q" (state->fprs[4]));
-                       asm volatile("std 5,%0" : "=Q" (state->fprs[5]));
-                       asm volatile("std 6,%0" : "=Q" (state->fprs[6]));
-                       asm volatile("std 7,%0" : "=Q" (state->fprs[7]));
-                       asm volatile("std 8,%0" : "=Q" (state->fprs[8]));
-                       asm volatile("std 9,%0" : "=Q" (state->fprs[9]));
-                       asm volatile("std 10,%0" : "=Q" (state->fprs[10]));
-                       asm volatile("std 11,%0" : "=Q" (state->fprs[11]));
-                       asm volatile("std 12,%0" : "=Q" (state->fprs[12]));
-                       asm volatile("std 13,%0" : "=Q" (state->fprs[13]));
-                       asm volatile("std 14,%0" : "=Q" (state->fprs[14]));
-                       asm volatile("std 15,%0" : "=Q" (state->fprs[15]));
-               }
+               if (flags & KERNEL_VXR_LOW)
+                       save_fp_regs_vx(vxrs);
                return;
        }
-
-       /* Test and save vector registers */
-       asm volatile (
-               /*
-                * Test if any vector register must be saved and, if so,
-                * test if all register can be saved.
-                */
-               "       la      1,%[vxrs]\n"    /* load save area */
-               "       tmll    %[m],30\n"      /* KERNEL_VXR */
-               "       jz      7f\n"           /* no work -> done */
-               "       jo      5f\n"           /* -> save V0..V31 */
-               /*
-                * Test for special case KERNEL_FPU_MID only. In this
-                * case a vstm V8..V23 is the best instruction
-                */
-               "       chi     %[m],12\n"      /* KERNEL_VXR_MID */
-               "       jne     0f\n"           /* -> save V8..V23 */
-               "       VSTM    8,23,128,1\n"   /* vstm %v8,%v23,128(%r1) */
-               "       j       7f\n"
-               /* Test and save the first half of 16 vector registers */
-               "0:     tmll    %[m],6\n"       /* KERNEL_VXR_LOW */
-               "       jz      3f\n"           /* -> KERNEL_VXR_HIGH */
-               "       jo      2f\n"           /* 11 -> save V0..V15 */
-               "       brc     2,1f\n"         /* 10 -> save V8..V15 */
-               "       VSTM    0,7,0,1\n"      /* vstm %v0,%v7,0(%r1) */
-               "       j       3f\n"
-               "1:     VSTM    8,15,128,1\n"   /* vstm %v8,%v15,128(%r1) */
-               "       j       3f\n"
-               "2:     VSTM    0,15,0,1\n"     /* vstm %v0,%v15,0(%r1) */
-               /* Test and save the second half of 16 vector registers */
-               "3:     tmll    %[m],24\n"      /* KERNEL_VXR_HIGH */
-               "       jz      7f\n"
-               "       jo      6f\n"           /* 11 -> save V16..V31 */
-               "       brc     2,4f\n"         /* 10 -> save V24..V31 */
-               "       VSTM    16,23,256,1\n"  /* vstm %v16,%v23,256(%r1) */
-               "       j       7f\n"
-               "4:     VSTM    24,31,384,1\n"  /* vstm %v24,%v31,384(%r1) */
-               "       j       7f\n"
-               "5:     VSTM    0,15,0,1\n"     /* vstm %v0,%v15,0(%r1) */
-               "6:     VSTM    16,31,256,1\n"  /* vstm %v16,%v31,256(%r1) */
-               "7:"
-               : [vxrs] "=Q" (*(struct vx_array *) &state->vxrs)
-               : [m] "d" (flags)
-               : "1", "cc");
+       mask = flags & KERNEL_VXR;
+       if (mask == KERNEL_VXR) {
+               vxrs += fpu_vstm(0, 15, vxrs);
+               vxrs += fpu_vstm(16, 31, vxrs);
+               return;
+       }
+       if (mask == KERNEL_VXR_MID) {
+               vxrs += fpu_vstm(8, 23, vxrs);
+               return;
+       }
+       mask = flags & KERNEL_VXR_LOW;
+       if (mask) {
+               if (mask == KERNEL_VXR_LOW)
+                       vxrs += fpu_vstm(0, 15, vxrs);
+               else if (mask == KERNEL_VXR_V0V7)
+                       vxrs += fpu_vstm(0, 7, vxrs);
+               else
+                       vxrs += fpu_vstm(8, 15, vxrs);
+       }
+       mask = flags & KERNEL_VXR_HIGH;
+       if (mask) {
+               if (mask == KERNEL_VXR_HIGH)
+                       vxrs += fpu_vstm(16, 31, vxrs);
+               else if (mask == KERNEL_VXR_V16V23)
+                       vxrs += fpu_vstm(16, 23, vxrs);
+               else
+                       vxrs += fpu_vstm(24, 31, vxrs);
+       }
 }
 EXPORT_SYMBOL(__kernel_fpu_begin);
 
-void __kernel_fpu_end(struct kernel_fpu *state, u32 flags)
+void __kernel_fpu_end(struct kernel_fpu *state, int flags)
 {
+       __vector128 *vxrs = state->vxrs;
+       int mask;
+
        /*
         * Limit the restore to the FPU/vector registers of the
-        * previous context that have been overwritte by the
-        * current context
+        * previous context that have been overwritten by the
+        * current context.
         */
-       flags &= state->mask;
-
+       flags &= state->hdr.mask;
        if (flags & KERNEL_FPC)
-               /* Restore floating-point controls */
-               asm volatile("lfpc %0" : : "Q" (state->fpc));
-
+               fpu_lfpc(&state->hdr.fpc);
        if (!cpu_has_vx()) {
-               if (flags & KERNEL_VXR_V0V7) {
-                       /* Restore floating-point registers */
-                       asm volatile("ld 0,%0" : : "Q" (state->fprs[0]));
-                       asm volatile("ld 1,%0" : : "Q" (state->fprs[1]));
-                       asm volatile("ld 2,%0" : : "Q" (state->fprs[2]));
-                       asm volatile("ld 3,%0" : : "Q" (state->fprs[3]));
-                       asm volatile("ld 4,%0" : : "Q" (state->fprs[4]));
-                       asm volatile("ld 5,%0" : : "Q" (state->fprs[5]));
-                       asm volatile("ld 6,%0" : : "Q" (state->fprs[6]));
-                       asm volatile("ld 7,%0" : : "Q" (state->fprs[7]));
-                       asm volatile("ld 8,%0" : : "Q" (state->fprs[8]));
-                       asm volatile("ld 9,%0" : : "Q" (state->fprs[9]));
-                       asm volatile("ld 10,%0" : : "Q" (state->fprs[10]));
-                       asm volatile("ld 11,%0" : : "Q" (state->fprs[11]));
-                       asm volatile("ld 12,%0" : : "Q" (state->fprs[12]));
-                       asm volatile("ld 13,%0" : : "Q" (state->fprs[13]));
-                       asm volatile("ld 14,%0" : : "Q" (state->fprs[14]));
-                       asm volatile("ld 15,%0" : : "Q" (state->fprs[15]));
-               }
+               if (flags & KERNEL_VXR_LOW)
+                       load_fp_regs_vx(vxrs);
                return;
        }
-
-       /* Test and restore (load) vector registers */
-       asm volatile (
-               /*
-                * Test if any vector register must be loaded and, if so,
-                * test if all registers can be loaded at once.
-                */
-               "       la      1,%[vxrs]\n"    /* load restore area */
-               "       tmll    %[m],30\n"      /* KERNEL_VXR */
-               "       jz      7f\n"           /* no work -> done */
-               "       jo      5f\n"           /* -> restore V0..V31 */
-               /*
-                * Test for special case KERNEL_FPU_MID only. In this
-                * case a vlm V8..V23 is the best instruction
-                */
-               "       chi     %[m],12\n"      /* KERNEL_VXR_MID */
-               "       jne     0f\n"           /* -> restore V8..V23 */
-               "       VLM     8,23,128,1\n"   /* vlm %v8,%v23,128(%r1) */
-               "       j       7f\n"
-               /* Test and restore the first half of 16 vector registers */
-               "0:     tmll    %[m],6\n"       /* KERNEL_VXR_LOW */
-               "       jz      3f\n"           /* -> KERNEL_VXR_HIGH */
-               "       jo      2f\n"           /* 11 -> restore V0..V15 */
-               "       brc     2,1f\n"         /* 10 -> restore V8..V15 */
-               "       VLM     0,7,0,1\n"      /* vlm %v0,%v7,0(%r1) */
-               "       j       3f\n"
-               "1:     VLM     8,15,128,1\n"   /* vlm %v8,%v15,128(%r1) */
-               "       j       3f\n"
-               "2:     VLM     0,15,0,1\n"     /* vlm %v0,%v15,0(%r1) */
-               /* Test and restore the second half of 16 vector registers */
-               "3:     tmll    %[m],24\n"      /* KERNEL_VXR_HIGH */
-               "       jz      7f\n"
-               "       jo      6f\n"           /* 11 -> restore V16..V31 */
-               "       brc     2,4f\n"         /* 10 -> restore V24..V31 */
-               "       VLM     16,23,256,1\n"  /* vlm %v16,%v23,256(%r1) */
-               "       j       7f\n"
-               "4:     VLM     24,31,384,1\n"  /* vlm %v24,%v31,384(%r1) */
-               "       j       7f\n"
-               "5:     VLM     0,15,0,1\n"     /* vlm %v0,%v15,0(%r1) */
-               "6:     VLM     16,31,256,1\n"  /* vlm %v16,%v31,256(%r1) */
-               "7:"
-               : [vxrs] "=Q" (*(struct vx_array *) &state->vxrs)
-               : [m] "d" (flags)
-               : "1", "cc");
+       mask = flags & KERNEL_VXR;
+       if (mask == KERNEL_VXR) {
+               vxrs += fpu_vlm(0, 15, vxrs);
+               vxrs += fpu_vlm(16, 31, vxrs);
+               return;
+       }
+       if (mask == KERNEL_VXR_MID) {
+               vxrs += fpu_vlm(8, 23, vxrs);
+               return;
+       }
+       mask = flags & KERNEL_VXR_LOW;
+       if (mask) {
+               if (mask == KERNEL_VXR_LOW)
+                       vxrs += fpu_vlm(0, 15, vxrs);
+               else if (mask == KERNEL_VXR_V0V7)
+                       vxrs += fpu_vlm(0, 7, vxrs);
+               else
+                       vxrs += fpu_vlm(8, 15, vxrs);
+       }
+       mask = flags & KERNEL_VXR_HIGH;
+       if (mask) {
+               if (mask == KERNEL_VXR_HIGH)
+                       vxrs += fpu_vlm(16, 31, vxrs);
+               else if (mask == KERNEL_VXR_V16V23)
+                       vxrs += fpu_vlm(16, 23, vxrs);
+               else
+                       vxrs += fpu_vlm(24, 31, vxrs);
+       }
 }
 EXPORT_SYMBOL(__kernel_fpu_end);
 
-void __load_fpu_regs(void)
+void load_fpu_state(struct fpu *state, int flags)
 {
-       unsigned long *regs = current->thread.fpu.regs;
-       struct fpu *state = &current->thread.fpu;
+       __vector128 *vxrs = &state->vxrs[0];
+       int mask;
 
-       sfpc_safe(state->fpc);
-       if (likely(cpu_has_vx())) {
-               asm volatile("lgr       1,%0\n"
-                            "VLM       0,15,0,1\n"
-                            "VLM       16,31,256,1\n"
-                            :
-                            : "d" (regs)
-                            : "1", "cc", "memory");
-       } else {
-               asm volatile("ld 0,%0" : : "Q" (regs[0]));
-               asm volatile("ld 1,%0" : : "Q" (regs[1]));
-               asm volatile("ld 2,%0" : : "Q" (regs[2]));
-               asm volatile("ld 3,%0" : : "Q" (regs[3]));
-               asm volatile("ld 4,%0" : : "Q" (regs[4]));
-               asm volatile("ld 5,%0" : : "Q" (regs[5]));
-               asm volatile("ld 6,%0" : : "Q" (regs[6]));
-               asm volatile("ld 7,%0" : : "Q" (regs[7]));
-               asm volatile("ld 8,%0" : : "Q" (regs[8]));
-               asm volatile("ld 9,%0" : : "Q" (regs[9]));
-               asm volatile("ld 10,%0" : : "Q" (regs[10]));
-               asm volatile("ld 11,%0" : : "Q" (regs[11]));
-               asm volatile("ld 12,%0" : : "Q" (regs[12]));
-               asm volatile("ld 13,%0" : : "Q" (regs[13]));
-               asm volatile("ld 14,%0" : : "Q" (regs[14]));
-               asm volatile("ld 15,%0" : : "Q" (regs[15]));
+       if (flags & KERNEL_FPC)
+               fpu_lfpc(&state->fpc);
+       if (!cpu_has_vx()) {
+               if (flags & KERNEL_VXR_V0V7)
+                       load_fp_regs_vx(state->vxrs);
+               return;
+       }
+       mask = flags & KERNEL_VXR;
+       if (mask == KERNEL_VXR) {
+               fpu_vlm(0, 15, &vxrs[0]);
+               fpu_vlm(16, 31, &vxrs[16]);
+               return;
+       }
+       if (mask == KERNEL_VXR_MID) {
+               fpu_vlm(8, 23, &vxrs[8]);
+               return;
+       }
+       mask = flags & KERNEL_VXR_LOW;
+       if (mask) {
+               if (mask == KERNEL_VXR_LOW)
+                       fpu_vlm(0, 15, &vxrs[0]);
+               else if (mask == KERNEL_VXR_V0V7)
+                       fpu_vlm(0, 7, &vxrs[0]);
+               else
+                       fpu_vlm(8, 15, &vxrs[8]);
+       }
+       mask = flags & KERNEL_VXR_HIGH;
+       if (mask) {
+               if (mask == KERNEL_VXR_HIGH)
+                       fpu_vlm(16, 31, &vxrs[16]);
+               else if (mask == KERNEL_VXR_V16V23)
+                       fpu_vlm(16, 23, &vxrs[16]);
+               else
+                       fpu_vlm(24, 31, &vxrs[24]);
        }
-       clear_cpu_flag(CIF_FPU);
-}
-
-void load_fpu_regs(void)
-{
-       raw_local_irq_disable();
-       __load_fpu_regs();
-       raw_local_irq_enable();
 }
-EXPORT_SYMBOL(load_fpu_regs);
 
-void save_fpu_regs(void)
+void save_fpu_state(struct fpu *state, int flags)
 {
-       unsigned long flags, *regs;
-       struct fpu *state;
-
-       local_irq_save(flags);
+       __vector128 *vxrs = &state->vxrs[0];
+       int mask;
 
-       if (test_cpu_flag(CIF_FPU))
-               goto out;
-
-       state = &current->thread.fpu;
-       regs = current->thread.fpu.regs;
-
-       asm volatile("stfpc %0" : "=Q" (state->fpc));
-       if (likely(cpu_has_vx())) {
-               asm volatile("lgr       1,%0\n"
-                            "VSTM      0,15,0,1\n"
-                            "VSTM      16,31,256,1\n"
-                            :
-                            : "d" (regs)
-                            : "1", "cc", "memory");
-       } else {
-               asm volatile("std 0,%0" : "=Q" (regs[0]));
-               asm volatile("std 1,%0" : "=Q" (regs[1]));
-               asm volatile("std 2,%0" : "=Q" (regs[2]));
-               asm volatile("std 3,%0" : "=Q" (regs[3]));
-               asm volatile("std 4,%0" : "=Q" (regs[4]));
-               asm volatile("std 5,%0" : "=Q" (regs[5]));
-               asm volatile("std 6,%0" : "=Q" (regs[6]));
-               asm volatile("std 7,%0" : "=Q" (regs[7]));
-               asm volatile("std 8,%0" : "=Q" (regs[8]));
-               asm volatile("std 9,%0" : "=Q" (regs[9]));
-               asm volatile("std 10,%0" : "=Q" (regs[10]));
-               asm volatile("std 11,%0" : "=Q" (regs[11]));
-               asm volatile("std 12,%0" : "=Q" (regs[12]));
-               asm volatile("std 13,%0" : "=Q" (regs[13]));
-               asm volatile("std 14,%0" : "=Q" (regs[14]));
-               asm volatile("std 15,%0" : "=Q" (regs[15]));
+       if (flags & KERNEL_FPC)
+               fpu_stfpc(&state->fpc);
+       if (!cpu_has_vx()) {
+               if (flags & KERNEL_VXR_LOW)
+                       save_fp_regs_vx(state->vxrs);
+               return;
+       }
+       mask = flags & KERNEL_VXR;
+       if (mask == KERNEL_VXR) {
+               fpu_vstm(0, 15, &vxrs[0]);
+               fpu_vstm(16, 31, &vxrs[16]);
+               return;
+       }
+       if (mask == KERNEL_VXR_MID) {
+               fpu_vstm(8, 23, &vxrs[8]);
+               return;
+       }
+       mask = flags & KERNEL_VXR_LOW;
+       if (mask) {
+               if (mask == KERNEL_VXR_LOW)
+                       fpu_vstm(0, 15, &vxrs[0]);
+               else if (mask == KERNEL_VXR_V0V7)
+                       fpu_vstm(0, 7, &vxrs[0]);
+               else
+                       fpu_vstm(8, 15, &vxrs[8]);
+       }
+       mask = flags & KERNEL_VXR_HIGH;
+       if (mask) {
+               if (mask == KERNEL_VXR_HIGH)
+                       fpu_vstm(16, 31, &vxrs[16]);
+               else if (mask == KERNEL_VXR_V16V23)
+                       fpu_vstm(16, 23, &vxrs[16]);
+               else
+                       fpu_vstm(24, 31, &vxrs[24]);
        }
-       set_cpu_flag(CIF_FPU);
-out:
-       local_irq_restore(flags);
 }
-EXPORT_SYMBOL(save_fpu_regs);
+EXPORT_SYMBOL(save_fpu_state);
index ba75f6bee77423be0f9a54e0afdaa88cbb342728..1486350a417751736b9bc934bd424fa9efc3de15 100644 (file)
@@ -1941,8 +1941,7 @@ static void dump_reipl_run(struct shutdown_trigger *trigger)
            reipl_type == IPL_TYPE_UNKNOWN)
                os_info_flags |= OS_INFO_FLAG_REIPL_CLEAR;
        os_info_entry_add(OS_INFO_FLAGS_ENTRY, &os_info_flags, sizeof(os_info_flags));
-       csum = (__force unsigned int)
-              csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0);
+       csum = (__force unsigned int)cksm(reipl_block_actual, reipl_block_actual->hdr.len, 0);
        abs_lc = get_abs_lowcore();
        abs_lc->ipib = __pa(reipl_block_actual);
        abs_lc->ipib_checksum = csum;
index aa22ffc16bcd3d5e2467e7093204f682a036e42b..c5d0c1cf984bb8e2bb0014bc4f695a72e34afd5f 100644 (file)
 #include <linux/reboot.h>
 #include <linux/ftrace.h>
 #include <linux/debug_locks.h>
+#include <asm/guarded_storage.h>
 #include <asm/pfault.h>
 #include <asm/cio.h>
+#include <asm/fpu.h>
 #include <asm/setup.h>
 #include <asm/smp.h>
 #include <asm/ipl.h>
@@ -26,7 +28,6 @@
 #include <asm/os_info.h>
 #include <asm/set_memory.h>
 #include <asm/stacktrace.h>
-#include <asm/switch_to.h>
 #include <asm/nmi.h>
 #include <asm/sclp.h>
 
index 9ad44c26d1a2884adc75bb7969c0988f3b896caf..c77382a673257abcdae4c64fe03a94f0aedfb0f0 100644 (file)
 #include <linux/export.h>
 #include <asm/lowcore.h>
 #include <asm/ctlreg.h>
+#include <asm/fpu.h>
 #include <asm/smp.h>
 #include <asm/stp.h>
 #include <asm/cputime.h>
 #include <asm/nmi.h>
 #include <asm/crw.h>
-#include <asm/switch_to.h>
 #include <asm/asm-offsets.h>
 #include <asm/pai.h>
-#include <asm/vx-insn.h>
-#include <asm/fpu/api.h>
 
 struct mcck_struct {
        unsigned int kill_task : 1;
@@ -204,133 +202,63 @@ void s390_handle_mcck(void)
        }
 }
 
-/*
- * returns 0 if register contents could be validated
- * returns 1 otherwise
+/**
+ * nmi_registers_valid - verify if registers are valid
+ * @mci: machine check interruption code
+ *
+ * Inspect a machine check interruption code and verify if all required
+ * registers are valid. For some registers the corresponding validity bit is
+ * ignored and the registers are set to the expected value.
+ * Returns true if all registers are valid, otherwise false.
  */
-static int notrace s390_validate_registers(union mci mci)
+static bool notrace nmi_registers_valid(union mci mci)
 {
-       struct mcesa *mcesa;
-       void *fpt_save_area;
        union ctlreg2 cr2;
-       int kill_task;
-       u64 zero;
-
-       kill_task = 0;
-       zero = 0;
-
-       if (!mci.gr || !mci.fp)
-               kill_task = 1;
-       fpt_save_area = &S390_lowcore.floating_pt_save_area;
-       if (!mci.fc) {
-               kill_task = 1;
-               asm volatile(
-                       "       lfpc    %0\n"
-                       :
-                       : "Q" (zero));
-       } else {
-               asm volatile(
-                       "       lfpc    %0\n"
-                       :
-                       : "Q" (S390_lowcore.fpt_creg_save_area));
-       }
 
-       mcesa = __va(S390_lowcore.mcesad & MCESA_ORIGIN_MASK);
-       if (!cpu_has_vx()) {
-               /* Validate floating point registers */
-               asm volatile(
-                       "       ld      0,0(%0)\n"
-                       "       ld      1,8(%0)\n"
-                       "       ld      2,16(%0)\n"
-                       "       ld      3,24(%0)\n"
-                       "       ld      4,32(%0)\n"
-                       "       ld      5,40(%0)\n"
-                       "       ld      6,48(%0)\n"
-                       "       ld      7,56(%0)\n"
-                       "       ld      8,64(%0)\n"
-                       "       ld      9,72(%0)\n"
-                       "       ld      10,80(%0)\n"
-                       "       ld      11,88(%0)\n"
-                       "       ld      12,96(%0)\n"
-                       "       ld      13,104(%0)\n"
-                       "       ld      14,112(%0)\n"
-                       "       ld      15,120(%0)\n"
-                       :
-                       : "a" (fpt_save_area)
-                       : "memory");
-       } else {
-               /* Validate vector registers */
-               union ctlreg0 cr0;
-
-               /*
-                * The vector validity must only be checked if not running a
-                * KVM guest. For KVM guests the machine check is forwarded by
-                * KVM and it is the responsibility of the guest to take
-                * appropriate actions. The host vector or FPU values have been
-                * saved by KVM and will be restored by KVM.
-                */
-               if (!mci.vr && !test_cpu_flag(CIF_MCCK_GUEST))
-                       kill_task = 1;
-               cr0.reg = S390_lowcore.cregs_save_area[0];
-               cr0.afp = cr0.vx = 1;
-               local_ctl_load(0, &cr0.reg);
-               asm volatile(
-                       "       la      1,%0\n"
-                       "       VLM     0,15,0,1\n"
-                       "       VLM     16,31,256,1\n"
-                       :
-                       : "Q" (*(struct vx_array *)mcesa->vector_save_area)
-                       : "1");
-               local_ctl_load(0, &S390_lowcore.cregs_save_area[0]);
-       }
-       /* Validate access registers */
-       asm volatile(
-               "       lam     0,15,0(%0)\n"
-               :
-               : "a" (&S390_lowcore.access_regs_save_area)
-               : "memory");
-       if (!mci.ar)
-               kill_task = 1;
-       /* Validate guarded storage registers */
-       cr2.reg = S390_lowcore.cregs_save_area[2];
-       if (cr2.gse) {
-               if (!mci.gs) {
-                       /*
-                        * 2 cases:
-                        * - machine check in kernel or userspace
-                        * - machine check while running SIE (KVM guest)
-                        * For kernel or userspace the userspace values of
-                        * guarded storage control can not be recreated, the
-                        * process must be terminated.
-                        * For SIE the guest values of guarded storage can not
-                        * be recreated. This is either due to a bug or due to
-                        * GS being disabled in the guest. The guest will be
-                        * notified by KVM code and the guests machine check
-                        * handling must take care of this.  The host values
-                        * are saved by KVM and are not affected.
-                        */
-                       if (!test_cpu_flag(CIF_MCCK_GUEST))
-                               kill_task = 1;
-               } else {
-                       load_gs_cb((struct gs_cb *)mcesa->guarded_storage_save_area);
-               }
-       }
        /*
-        * The getcpu vdso syscall reads CPU number from the programmable
+        * The getcpu vdso syscall reads the CPU number from the programmable
         * field of the TOD clock. Disregard the TOD programmable register
-        * validity bit and load the CPU number into the TOD programmable
-        * field unconditionally.
+        * validity bit and load the CPU number into the TOD programmable field
+        * unconditionally.
         */
        set_tod_programmable_field(raw_smp_processor_id());
-       /* Validate clock comparator register */
+       /*
+        * Set the clock comparator register to the next expected value.
+        */
        set_clock_comparator(S390_lowcore.clock_comparator);
-
+       if (!mci.gr || !mci.fp || !mci.fc)
+               return false;
+       /*
+        * The vector validity must only be checked if not running a
+        * KVM guest. For KVM guests the machine check is forwarded by
+        * KVM and it is the responsibility of the guest to take
+        * appropriate actions. The host vector or FPU values have been
+        * saved by KVM and will be restored by KVM.
+        */
+       if (!mci.vr && !test_cpu_flag(CIF_MCCK_GUEST))
+               return false;
+       if (!mci.ar)
+               return false;
+       /*
+        * Two cases for guarded storage registers:
+        * - machine check in kernel or userspace
+        * - machine check while running SIE (KVM guest)
+        * For kernel or userspace the userspace values of guarded storage
+        * control can not be recreated, the process must be terminated.
+        * For SIE the guest values of guarded storage can not be recreated.
+        * This is either due to a bug or due to GS being disabled in the
+        * guest. The guest will be notified by KVM code and the guests machine
+        * check handling must take care of this. The host values are saved by
+        * KVM and are not affected.
+        */
+       cr2.reg = S390_lowcore.cregs_save_area[2];
+       if (cr2.gse && !mci.gs && !test_cpu_flag(CIF_MCCK_GUEST))
+               return false;
        if (!mci.ms || !mci.pm || !mci.ia)
-               kill_task = 1;
-
-       return kill_task;
+               return false;
+       return true;
 }
-NOKPROBE_SYMBOL(s390_validate_registers);
+NOKPROBE_SYMBOL(nmi_registers_valid);
 
 /*
  * Backup the guest's machine check info to its description block
@@ -428,7 +356,7 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
                        s390_handle_damage();
                }
        }
-       if (s390_validate_registers(mci)) {
+       if (!nmi_registers_valid(mci)) {
                if (!user_mode(regs))
                        s390_handle_damage();
                /*
index 6e1824141b29eafc8d5b4adc56728c48b1af89ec..a801e6bd534178ce04bf161e3f2ff6e954d75e91 100644 (file)
@@ -29,7 +29,7 @@ static struct os_info os_info __page_aligned_data;
 u32 os_info_csum(struct os_info *os_info)
 {
        int size = sizeof(*os_info) - offsetof(struct os_info, version_major);
-       return (__force u32)csum_partial(&os_info->version_major, size, 0);
+       return (__force u32)cksm(&os_info->version_major, size, 0);
 }
 
 /*
@@ -49,7 +49,7 @@ void os_info_entry_add(int nr, void *ptr, u64 size)
 {
        os_info.entry[nr].addr = __pa(ptr);
        os_info.entry[nr].size = size;
-       os_info.entry[nr].csum = (__force u32)csum_partial(ptr, size, 0);
+       os_info.entry[nr].csum = (__force u32)cksm(ptr, size, 0);
        os_info.csum = os_info_csum(&os_info);
 }
 
@@ -98,7 +98,7 @@ static void os_info_old_alloc(int nr, int align)
                msg = "copy failed";
                goto fail_free;
        }
-       csum = (__force u32)csum_partial(buf_align, size, 0);
+       csum = (__force u32)cksm(buf_align, size, 0);
        if (csum != os_info_old->entry[nr].csum) {
                msg = "checksum failed";
                goto fail_free;
index bf8a672b15a41afd3a9e0384ad19f83eb8eadba1..823d652e3917f8653fe71bb5c67a72c2653cf6c3 100644 (file)
@@ -98,6 +98,7 @@ static void paicrypt_event_destroy(struct perf_event *event)
                            event->attr.config, event->cpu,
                            cpump->active_events, cpump->mode,
                            refcount_read(&cpump->refcnt));
+       free_page(PAI_SAVE_AREA(event));
        if (refcount_dec_and_test(&cpump->refcnt)) {
                debug_sprintf_event(cfm_dbg, 4, "%s page %#lx save %p\n",
                                    __func__, (unsigned long)cpump->page,
@@ -260,6 +261,7 @@ static int paicrypt_event_init(struct perf_event *event)
 {
        struct perf_event_attr *a = &event->attr;
        struct paicrypt_map *cpump;
+       int rc = 0;
 
        /* PAI crypto PMU registered as PERF_TYPE_RAW, check event type */
        if (a->type != PERF_TYPE_RAW && event->pmu->type != a->type)
@@ -274,10 +276,21 @@ static int paicrypt_event_init(struct perf_event *event)
        /* Allow only CRYPTO_ALL for sampling. */
        if (a->sample_period && a->config != PAI_CRYPTO_BASE)
                return -EINVAL;
+       /* Get a page to store last counter values for sampling */
+       if (a->sample_period) {
+               PAI_SAVE_AREA(event) = get_zeroed_page(GFP_KERNEL);
+               if (!PAI_SAVE_AREA(event)) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+       }
 
        cpump = paicrypt_busy(event);
-       if (IS_ERR(cpump))
-               return PTR_ERR(cpump);
+       if (IS_ERR(cpump)) {
+               free_page(PAI_SAVE_AREA(event));
+               rc = PTR_ERR(cpump);
+               goto out;
+       }
 
        event->destroy = paicrypt_event_destroy;
 
@@ -293,7 +306,8 @@ static int paicrypt_event_init(struct perf_event *event)
        }
 
        static_branch_inc(&pai_key);
-       return 0;
+out:
+       return rc;
 }
 
 static void paicrypt_read(struct perf_event *event)
@@ -310,20 +324,15 @@ static void paicrypt_read(struct perf_event *event)
 
 static void paicrypt_start(struct perf_event *event, int flags)
 {
+       struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr);
+       struct paicrypt_map *cpump = mp->mapptr;
        u64 sum;
 
-       /* Event initialization sets last_tag to 0. When later on the events
-        * are deleted and re-added, do not reset the event count value to zero.
-        * Events are added, deleted and re-added when 2 or more events
-        * are active at the same time.
-        */
        if (!event->attr.sample_period) {       /* Counting */
-               if (!event->hw.last_tag) {
-                       event->hw.last_tag = 1;
-                       sum = paicrypt_getall(event);   /* Get current value */
-                       local64_set(&event->hw.prev_count, sum);
-               }
+               sum = paicrypt_getall(event);   /* Get current value */
+               local64_set(&event->hw.prev_count, sum);
        } else {                                /* Sampling */
+               cpump->event = event;
                perf_sched_cb_inc(event->pmu);
        }
 }
@@ -339,7 +348,6 @@ static int paicrypt_add(struct perf_event *event, int flags)
                WRITE_ONCE(S390_lowcore.ccd, ccd);
                local_ctl_set_bit(0, CR0_CRYPTOGRAPHY_COUNTER_BIT);
        }
-       cpump->event = event;
        if (flags & PERF_EF_START)
                paicrypt_start(event, PERF_EF_RELOAD);
        event->hw.state = 0;
@@ -367,23 +375,34 @@ static void paicrypt_del(struct perf_event *event, int flags)
        }
 }
 
-/* Create raw data and save it in buffer. Returns number of bytes copied.
- * Saves only positive counter entries of the form
+/* Create raw data and save it in buffer. Calculate the delta for each
+ * counter between this invocation and the last invocation.
+ * Returns number of bytes copied.
+ * Saves only entries with positive counter difference of the form
  * 2 bytes: Number of counter
  * 8 bytes: Value of counter
  */
 static size_t paicrypt_copy(struct pai_userdata *userdata, unsigned long *page,
-                           bool exclude_user, bool exclude_kernel)
+                           unsigned long *page_old, bool exclude_user,
+                           bool exclude_kernel)
 {
        int i, outidx = 0;
 
        for (i = 1; i <= paicrypt_cnt; i++) {
-               u64 val = 0;
+               u64 val = 0, val_old = 0;
 
-               if (!exclude_kernel)
+               if (!exclude_kernel) {
                        val += paicrypt_getctr(page, i, true);
-               if (!exclude_user)
+                       val_old += paicrypt_getctr(page_old, i, true);
+               }
+               if (!exclude_user) {
                        val += paicrypt_getctr(page, i, false);
+                       val_old += paicrypt_getctr(page_old, i, false);
+               }
+               if (val >= val_old)
+                       val -= val_old;
+               else
+                       val = (~0ULL - val_old) + val + 1;
                if (val) {
                        userdata[outidx].num = i;
                        userdata[outidx].value = val;
@@ -426,8 +445,8 @@ static int paicrypt_push_sample(size_t rawsize, struct paicrypt_map *cpump,
 
        overflow = perf_event_overflow(event, &data, &regs);
        perf_event_update_userpage(event);
-       /* Clear lowcore page after read */
-       memset(cpump->page, 0, PAGE_SIZE);
+       /* Save crypto counter lowcore page after reading event data. */
+       memcpy((void *)PAI_SAVE_AREA(event), cpump->page, PAGE_SIZE);
        return overflow;
 }
 
@@ -443,6 +462,7 @@ static int paicrypt_have_sample(void)
        if (!event)             /* No event active */
                return 0;
        rawsize = paicrypt_copy(cpump->save, cpump->page,
+                               (unsigned long *)PAI_SAVE_AREA(event),
                                cpump->event->attr.exclude_user,
                                cpump->event->attr.exclude_kernel);
        if (rawsize)                    /* No incremented counters */
@@ -694,6 +714,12 @@ static int __init attr_event_init_one(struct attribute **attrs, int num)
 {
        struct perf_pmu_events_attr *pa;
 
+       /* Index larger than array_size, no counter name available */
+       if (num >= ARRAY_SIZE(paicrypt_ctrnames)) {
+               attrs[num] = NULL;
+               return 0;
+       }
+
        pa = kzalloc(sizeof(*pa), GFP_KERNEL);
        if (!pa)
                return -ENOMEM;
@@ -714,14 +740,13 @@ static int __init attr_event_init(void)
        struct attribute **attrs;
        int ret, i;
 
-       attrs = kmalloc_array(ARRAY_SIZE(paicrypt_ctrnames) + 1, sizeof(*attrs),
-                             GFP_KERNEL);
+       attrs = kmalloc_array(paicrypt_cnt + 2, sizeof(*attrs), GFP_KERNEL);
        if (!attrs)
                return -ENOMEM;
-       for (i = 0; i < ARRAY_SIZE(paicrypt_ctrnames); i++) {
+       for (i = 0; i <= paicrypt_cnt; i++) {
                ret = attr_event_init_one(attrs, i);
                if (ret) {
-                       attr_event_free(attrs, i - 1);
+                       attr_event_free(attrs, i);
                        return ret;
                }
        }
@@ -742,8 +767,10 @@ static int __init paicrypt_init(void)
        paicrypt_cnt = ib.num_cc;
        if (paicrypt_cnt == 0)
                return 0;
-       if (paicrypt_cnt >= PAI_CRYPTO_MAXCTR)
-               paicrypt_cnt = PAI_CRYPTO_MAXCTR - 1;
+       if (paicrypt_cnt >= PAI_CRYPTO_MAXCTR) {
+               pr_err("Too many PMU pai_crypto counters %d\n", paicrypt_cnt);
+               return -E2BIG;
+       }
 
        rc = attr_event_init();         /* Export known PAI crypto events */
        if (rc) {
index af7f2b538c8fd47a19f73029264462bd6c4fdcbd..616a25606cd63dcda97a0b781c88b55dc86f0032 100644 (file)
@@ -120,6 +120,7 @@ static void paiext_event_destroy(struct perf_event *event)
        struct paiext_mapptr *mp = per_cpu_ptr(paiext_root.mapptr, event->cpu);
        struct paiext_map *cpump = mp->mapptr;
 
+       free_page(PAI_SAVE_AREA(event));
        mutex_lock(&paiext_reserve_mutex);
        cpump->event = NULL;
        if (refcount_dec_and_test(&cpump->refcnt))      /* Last reference gone */
@@ -202,7 +203,6 @@ static int paiext_alloc(struct perf_event_attr *a, struct perf_event *event)
        }
 
        rc = 0;
-       cpump->event = event;
 
 undo:
        if (rc) {
@@ -256,10 +256,18 @@ static int paiext_event_init(struct perf_event *event)
        /* Prohibit exclude_user event selection */
        if (a->exclude_user)
                return -EINVAL;
+       /* Get a page to store last counter values for sampling */
+       if (a->sample_period) {
+               PAI_SAVE_AREA(event) = get_zeroed_page(GFP_KERNEL);
+               if (!PAI_SAVE_AREA(event))
+                       return -ENOMEM;
+       }
 
        rc = paiext_alloc(a, event);
-       if (rc)
+       if (rc) {
+               free_page(PAI_SAVE_AREA(event));
                return rc;
+       }
        event->destroy = paiext_event_destroy;
 
        if (a->sample_period) {
@@ -319,15 +327,15 @@ static void paiext_read(struct perf_event *event)
 
 static void paiext_start(struct perf_event *event, int flags)
 {
+       struct paiext_mapptr *mp = this_cpu_ptr(paiext_root.mapptr);
+       struct paiext_map *cpump = mp->mapptr;
        u64 sum;
 
        if (!event->attr.sample_period) {       /* Counting */
-               if (!event->hw.last_tag) {
-                       event->hw.last_tag = 1;
-                       sum = paiext_getall(event);     /* Get current value */
-                       local64_set(&event->hw.prev_count, sum);
-               }
+               sum = paiext_getall(event);     /* Get current value */
+               local64_set(&event->hw.prev_count, sum);
        } else {                                /* Sampling */
+               cpump->event = event;
                perf_sched_cb_inc(event->pmu);
        }
 }
@@ -346,7 +354,6 @@ static int paiext_add(struct perf_event *event, int flags)
                debug_sprintf_event(paiext_dbg, 4, "%s 1508 %llx acc %llx\n",
                                    __func__, S390_lowcore.aicd, pcb->acc);
        }
-       cpump->event = event;
        if (flags & PERF_EF_START)
                paiext_start(event, PERF_EF_RELOAD);
        event->hw.state = 0;
@@ -384,13 +391,19 @@ static void paiext_del(struct perf_event *event, int flags)
  * 2 bytes: Number of counter
  * 8 bytes: Value of counter
  */
-static size_t paiext_copy(struct pai_userdata *userdata, unsigned long *area)
+static size_t paiext_copy(struct pai_userdata *userdata, unsigned long *area,
+                         unsigned long *area_old)
 {
        int i, outidx = 0;
 
        for (i = 1; i <= paiext_cnt; i++) {
                u64 val = paiext_getctr(area, i);
+               u64 val_old = paiext_getctr(area_old, i);
 
+               if (val >= val_old)
+                       val -= val_old;
+               else
+                       val = (~0ULL - val_old) + val + 1;
                if (val) {
                        userdata[outidx].num = i;
                        userdata[outidx].value = val;
@@ -446,8 +459,9 @@ static int paiext_push_sample(size_t rawsize, struct paiext_map *cpump,
 
        overflow = perf_event_overflow(event, &data, &regs);
        perf_event_update_userpage(event);
-       /* Clear lowcore area after read */
-       memset(cpump->area, 0, PAIE1_CTRBLOCK_SZ);
+       /* Save NNPA lowcore area after read in event */
+       memcpy((void *)PAI_SAVE_AREA(event), cpump->area,
+              PAIE1_CTRBLOCK_SZ);
        return overflow;
 }
 
@@ -462,7 +476,8 @@ static int paiext_have_sample(void)
 
        if (!event)
                return 0;
-       rawsize = paiext_copy(cpump->save, cpump->area);
+       rawsize = paiext_copy(cpump->save, cpump->area,
+                             (unsigned long *)PAI_SAVE_AREA(event));
        if (rawsize)                    /* Incremented counters */
                rc = paiext_push_sample(rawsize, cpump, event);
        return rc;
@@ -584,6 +599,12 @@ static int __init attr_event_init_one(struct attribute **attrs, int num)
 {
        struct perf_pmu_events_attr *pa;
 
+       /* Index larger than array_size, no counter name available */
+       if (num >= ARRAY_SIZE(paiext_ctrnames)) {
+               attrs[num] = NULL;
+               return 0;
+       }
+
        pa = kzalloc(sizeof(*pa), GFP_KERNEL);
        if (!pa)
                return -ENOMEM;
@@ -604,14 +625,13 @@ static int __init attr_event_init(void)
        struct attribute **attrs;
        int ret, i;
 
-       attrs = kmalloc_array(ARRAY_SIZE(paiext_ctrnames) + 1, sizeof(*attrs),
-                             GFP_KERNEL);
+       attrs = kmalloc_array(paiext_cnt + 2, sizeof(*attrs), GFP_KERNEL);
        if (!attrs)
                return -ENOMEM;
-       for (i = 0; i < ARRAY_SIZE(paiext_ctrnames); i++) {
+       for (i = 0; i <= paiext_cnt; i++) {
                ret = attr_event_init_one(attrs, i);
                if (ret) {
-                       attr_event_free(attrs, i - 1);
+                       attr_event_free(attrs, i);
                        return ret;
                }
        }
index 3d93656bd94890f4a5209e2eb9e76deb35e25d1d..a6b058ee4a36c0f097958723f6e34bc09623ca6e 100644 (file)
@@ -5,8 +5,7 @@
 #include <linux/errno.h>
 #include <linux/bug.h>
 #include <asm/ptrace.h>
-#include <asm/fpu/api.h>
-#include <asm/fpu/types.h>
+#include <asm/fpu.h>
 
 u64 perf_reg_value(struct pt_regs *regs, int idx)
 {
@@ -20,10 +19,7 @@ u64 perf_reg_value(struct pt_regs *regs, int idx)
                        return 0;
 
                idx -= PERF_REG_S390_FP0;
-               if (cpu_has_vx())
-                       fp = *(freg_t *)(current->thread.fpu.vxrs + idx);
-               else
-                       fp = current->thread.fpu.fprs[idx];
+               fp = *(freg_t *)(current->thread.ufpu.vxrs + idx);
                return fp.ui;
        }
 
@@ -65,6 +61,6 @@ void perf_get_regs_user(struct perf_regs *regs_user,
         */
        regs_user->regs = task_pt_regs(current);
        if (user_mode(regs_user->regs))
-               save_fpu_regs();
+               save_user_fpu_regs();
        regs_user->abi = perf_reg_abi(current);
 }
index 4e3b366589fb6a7484b866faf786dc976dbbffa3..dd456b4758611ce178236b0680f56d1fc7e78294 100644 (file)
 #include <linux/init_task.h>
 #include <linux/entry-common.h>
 #include <linux/io.h>
+#include <asm/guarded_storage.h>
+#include <asm/access-regs.h>
+#include <asm/switch_to.h>
 #include <asm/cpu_mf.h>
 #include <asm/processor.h>
+#include <asm/ptrace.h>
 #include <asm/vtimer.h>
 #include <asm/exec.h>
+#include <asm/fpu.h>
 #include <asm/irq.h>
 #include <asm/nmi.h>
 #include <asm/smp.h>
 #include <asm/stacktrace.h>
-#include <asm/switch_to.h>
 #include <asm/runtime_instr.h>
 #include <asm/unwind.h>
 #include "entry.h"
@@ -84,13 +88,13 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
        /*
         * Save the floating-point or vector register state of the current
-        * task and set the CIF_FPU flag to lazy restore the FPU register
+        * task and set the TIF_FPU flag to lazy restore the FPU register
         * state when returning to user space.
         */
-       save_fpu_regs();
+       save_user_fpu_regs();
 
        *dst = *src;
-       dst->thread.fpu.regs = dst->thread.fpu.fprs;
+       dst->thread.kfpu_flags = 0;
 
        /*
         * Don't transfer over the runtime instrumentation or the guarded
@@ -186,8 +190,23 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
 
 void execve_tail(void)
 {
-       current->thread.fpu.fpc = 0;
-       asm volatile("sfpc %0" : : "d" (0));
+       current->thread.ufpu.fpc = 0;
+       fpu_sfpc(0);
+}
+
+struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next)
+{
+       save_user_fpu_regs();
+       save_kernel_fpu_regs(&prev->thread);
+       save_access_regs(&prev->thread.acrs[0]);
+       save_ri_cb(prev->thread.ri_cb);
+       save_gs_cb(prev->thread.gs_cb);
+       update_cr_regs(next);
+       restore_kernel_fpu_regs(&next->thread);
+       restore_access_regs(&next->thread.acrs[0]);
+       restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);
+       restore_gs_cb(next->thread.gs_cb);
+       return __switch_to_asm(prev, next);
 }
 
 unsigned long __get_wchan(struct task_struct *p)
index f1897a8bb221078cf3b0da87c1d614241e0544b9..1cfed8b710b8c81f41350b1167a17886be30584a 100644 (file)
 #include <linux/seccomp.h>
 #include <linux/compat.h>
 #include <trace/syscall.h>
+#include <asm/guarded_storage.h>
+#include <asm/access-regs.h>
 #include <asm/page.h>
 #include <linux/uaccess.h>
 #include <asm/unistd.h>
-#include <asm/switch_to.h>
 #include <asm/runtime_instr.h>
 #include <asm/facility.h>
-#include <asm/fpu/api.h>
+#include <asm/fpu.h>
 
 #include "entry.h"
 
@@ -246,22 +247,15 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr)
                /*
                 * floating point control reg. is in the thread structure
                 */
-               tmp = child->thread.fpu.fpc;
+               tmp = child->thread.ufpu.fpc;
                tmp <<= BITS_PER_LONG - 32;
 
        } else if (addr < offsetof(struct user, regs.fp_regs) + sizeof(s390_fp_regs)) {
                /*
-                * floating point regs. are either in child->thread.fpu
-                * or the child->thread.fpu.vxrs array
+                * floating point regs. are in the child->thread.ufpu.vxrs array
                 */
                offset = addr - offsetof(struct user, regs.fp_regs.fprs);
-               if (cpu_has_vx())
-                       tmp = *(addr_t *)
-                              ((addr_t) child->thread.fpu.vxrs + 2*offset);
-               else
-                       tmp = *(addr_t *)
-                              ((addr_t) child->thread.fpu.fprs + offset);
-
+               tmp = *(addr_t *)((addr_t)child->thread.ufpu.vxrs + 2 * offset);
        } else if (addr < offsetof(struct user, regs.per_info) + sizeof(per_struct)) {
                /*
                 * Handle access to the per_info structure.
@@ -395,21 +389,14 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
                 */
                if ((unsigned int)data != 0)
                        return -EINVAL;
-               child->thread.fpu.fpc = data >> (BITS_PER_LONG - 32);
+               child->thread.ufpu.fpc = data >> (BITS_PER_LONG - 32);
 
        } else if (addr < offsetof(struct user, regs.fp_regs) + sizeof(s390_fp_regs)) {
                /*
-                * floating point regs. are either in child->thread.fpu
-                * or the child->thread.fpu.vxrs array
+                * floating point regs. are in the child->thread.ufpu.vxrs array
                 */
                offset = addr - offsetof(struct user, regs.fp_regs.fprs);
-               if (cpu_has_vx())
-                       *(addr_t *)((addr_t)
-                               child->thread.fpu.vxrs + 2*offset) = data;
-               else
-                       *(addr_t *)((addr_t)
-                               child->thread.fpu.fprs + offset) = data;
-
+               *(addr_t *)((addr_t)child->thread.ufpu.vxrs + 2 * offset) = data;
        } else if (addr < offsetof(struct user, regs.per_info) + sizeof(per_struct)) {
                /*
                 * Handle access to the per_info structure.
@@ -622,21 +609,14 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr)
                /*
                 * floating point control reg. is in the thread structure
                 */
-               tmp = child->thread.fpu.fpc;
+               tmp = child->thread.ufpu.fpc;
 
        } else if (addr < offsetof(struct compat_user, regs.fp_regs) + sizeof(s390_fp_regs)) {
                /*
-                * floating point regs. are either in child->thread.fpu
-                * or the child->thread.fpu.vxrs array
+                * floating point regs. are in the child->thread.ufpu.vxrs array
                 */
                offset = addr - offsetof(struct compat_user, regs.fp_regs.fprs);
-               if (cpu_has_vx())
-                       tmp = *(__u32 *)
-                              ((addr_t) child->thread.fpu.vxrs + 2*offset);
-               else
-                       tmp = *(__u32 *)
-                              ((addr_t) child->thread.fpu.fprs + offset);
-
+               tmp = *(__u32 *)((addr_t)child->thread.ufpu.vxrs + 2 * offset);
        } else if (addr < offsetof(struct compat_user, regs.per_info) + sizeof(struct compat_per_struct_kernel)) {
                /*
                 * Handle access to the per_info structure.
@@ -748,21 +728,14 @@ static int __poke_user_compat(struct task_struct *child,
                /*
                 * floating point control reg. is in the thread structure
                 */
-               child->thread.fpu.fpc = data;
+               child->thread.ufpu.fpc = data;
 
        } else if (addr < offsetof(struct compat_user, regs.fp_regs) + sizeof(s390_fp_regs)) {
                /*
-                * floating point regs. are either in child->thread.fpu
-                * or the child->thread.fpu.vxrs array
+                * floating point regs. are in the child->thread.ufpu.vxrs array
                 */
                offset = addr - offsetof(struct compat_user, regs.fp_regs.fprs);
-               if (cpu_has_vx())
-                       *(__u32 *)((addr_t)
-                               child->thread.fpu.vxrs + 2*offset) = tmp;
-               else
-                       *(__u32 *)((addr_t)
-                               child->thread.fpu.fprs + offset) = tmp;
-
+               *(__u32 *)((addr_t)child->thread.ufpu.vxrs + 2 * offset) = tmp;
        } else if (addr < offsetof(struct compat_user, regs.per_info) + sizeof(struct compat_per_struct_kernel)) {
                /*
                 * Handle access to the per_info structure.
@@ -893,10 +866,10 @@ static int s390_fpregs_get(struct task_struct *target,
        _s390_fp_regs fp_regs;
 
        if (target == current)
-               save_fpu_regs();
+               save_user_fpu_regs();
 
-       fp_regs.fpc = target->thread.fpu.fpc;
-       fpregs_store(&fp_regs, &target->thread.fpu);
+       fp_regs.fpc = target->thread.ufpu.fpc;
+       fpregs_store(&fp_regs, &target->thread.ufpu);
 
        return membuf_write(&to, &fp_regs, sizeof(fp_regs));
 }
@@ -910,22 +883,17 @@ static int s390_fpregs_set(struct task_struct *target,
        freg_t fprs[__NUM_FPRS];
 
        if (target == current)
-               save_fpu_regs();
-
-       if (cpu_has_vx())
-               convert_vx_to_fp(fprs, target->thread.fpu.vxrs);
-       else
-               memcpy(&fprs, target->thread.fpu.fprs, sizeof(fprs));
-
+               save_user_fpu_regs();
+       convert_vx_to_fp(fprs, target->thread.ufpu.vxrs);
        if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) {
-               u32 ufpc[2] = { target->thread.fpu.fpc, 0 };
+               u32 ufpc[2] = { target->thread.ufpu.fpc, 0 };
                rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ufpc,
                                        0, offsetof(s390_fp_regs, fprs));
                if (rc)
                        return rc;
                if (ufpc[1] != 0)
                        return -EINVAL;
-               target->thread.fpu.fpc = ufpc[0];
+               target->thread.ufpu.fpc = ufpc[0];
        }
 
        if (rc == 0 && count > 0)
@@ -933,12 +901,7 @@ static int s390_fpregs_set(struct task_struct *target,
                                        fprs, offsetof(s390_fp_regs, fprs), -1);
        if (rc)
                return rc;
-
-       if (cpu_has_vx())
-               convert_fp_to_vx(target->thread.fpu.vxrs, fprs);
-       else
-               memcpy(target->thread.fpu.fprs, &fprs, sizeof(fprs));
-
+       convert_fp_to_vx(target->thread.ufpu.vxrs, fprs);
        return rc;
 }
 
@@ -988,9 +951,9 @@ static int s390_vxrs_low_get(struct task_struct *target,
        if (!cpu_has_vx())
                return -ENODEV;
        if (target == current)
-               save_fpu_regs();
+               save_user_fpu_regs();
        for (i = 0; i < __NUM_VXRS_LOW; i++)
-               vxrs[i] = target->thread.fpu.vxrs[i].low;
+               vxrs[i] = target->thread.ufpu.vxrs[i].low;
        return membuf_write(&to, vxrs, sizeof(vxrs));
 }
 
@@ -1005,15 +968,15 @@ static int s390_vxrs_low_set(struct task_struct *target,
        if (!cpu_has_vx())
                return -ENODEV;
        if (target == current)
-               save_fpu_regs();
+               save_user_fpu_regs();
 
        for (i = 0; i < __NUM_VXRS_LOW; i++)
-               vxrs[i] = target->thread.fpu.vxrs[i].low;
+               vxrs[i] = target->thread.ufpu.vxrs[i].low;
 
        rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1);
        if (rc == 0)
                for (i = 0; i < __NUM_VXRS_LOW; i++)
-                       target->thread.fpu.vxrs[i].low = vxrs[i];
+                       target->thread.ufpu.vxrs[i].low = vxrs[i];
 
        return rc;
 }
@@ -1025,8 +988,8 @@ static int s390_vxrs_high_get(struct task_struct *target,
        if (!cpu_has_vx())
                return -ENODEV;
        if (target == current)
-               save_fpu_regs();
-       return membuf_write(&to, target->thread.fpu.vxrs + __NUM_VXRS_LOW,
+               save_user_fpu_regs();
+       return membuf_write(&to, target->thread.ufpu.vxrs + __NUM_VXRS_LOW,
                            __NUM_VXRS_HIGH * sizeof(__vector128));
 }
 
@@ -1040,10 +1003,10 @@ static int s390_vxrs_high_set(struct task_struct *target,
        if (!cpu_has_vx())
                return -ENODEV;
        if (target == current)
-               save_fpu_regs();
+               save_user_fpu_regs();
 
        rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                               target->thread.fpu.vxrs + __NUM_VXRS_LOW, 0, -1);
+                               target->thread.ufpu.vxrs + __NUM_VXRS_LOW, 0, -1);
        return rc;
 }
 
index d1f3b56e7afc2b9b6326451ae446c73a9c1ce1c7..24ed33f044ec39720b11f83a5a925303d8c983a2 100644 (file)
@@ -504,12 +504,12 @@ static void __init setup_resources(void)
        int j;
        u64 i;
 
-       code_resource.start = (unsigned long) _text;
-       code_resource.end = (unsigned long) _etext - 1;
-       data_resource.start = (unsigned long) _etext;
-       data_resource.end = (unsigned long) _edata - 1;
-       bss_resource.start = (unsigned long) __bss_start;
-       bss_resource.end = (unsigned long) __bss_stop - 1;
+       code_resource.start = __pa_symbol(_text);
+       code_resource.end = __pa_symbol(_etext) - 1;
+       data_resource.start = __pa_symbol(_etext);
+       data_resource.end = __pa_symbol(_edata) - 1;
+       bss_resource.start = __pa_symbol(__bss_start);
+       bss_resource.end = __pa_symbol(__bss_stop) - 1;
 
        for_each_mem_range(i, &start, &end) {
                res = memblock_alloc(sizeof(*res), 8);
index 43e9661cd715ceb5baea7b8261d6787f5cd3217c..6c2cb345402ff617232070ce9fd2e5bf67a707ce 100644 (file)
@@ -30,8 +30,8 @@
 #include <linux/compat.h>
 #include <asm/ucontext.h>
 #include <linux/uaccess.h>
+#include <asm/access-regs.h>
 #include <asm/lowcore.h>
-#include <asm/switch_to.h>
 #include <asm/vdso.h>
 #include "entry.h"
 
@@ -109,7 +109,7 @@ struct rt_sigframe
 static void store_sigregs(void)
 {
        save_access_regs(current->thread.acrs);
-       save_fpu_regs();
+       save_user_fpu_regs();
 }
 
 /* Load registers after signal return */
@@ -131,7 +131,7 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
        memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
        memcpy(&user_sregs.regs.acrs, current->thread.acrs,
               sizeof(user_sregs.regs.acrs));
-       fpregs_store(&user_sregs.fpregs, &current->thread.fpu);
+       fpregs_store(&user_sregs.fpregs, &current->thread.ufpu);
        if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs)))
                return -EFAULT;
        return 0;
@@ -165,7 +165,7 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
        memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
               sizeof(current->thread.acrs));
 
-       fpregs_load(&user_sregs.fpregs, &current->thread.fpu);
+       fpregs_load(&user_sregs.fpregs, &current->thread.ufpu);
 
        clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */
        return 0;
@@ -181,11 +181,11 @@ static int save_sigregs_ext(struct pt_regs *regs,
        /* Save vector registers to signal stack */
        if (cpu_has_vx()) {
                for (i = 0; i < __NUM_VXRS_LOW; i++)
-                       vxrs[i] = current->thread.fpu.vxrs[i].low;
+                       vxrs[i] = current->thread.ufpu.vxrs[i].low;
                if (__copy_to_user(&sregs_ext->vxrs_low, vxrs,
                                   sizeof(sregs_ext->vxrs_low)) ||
                    __copy_to_user(&sregs_ext->vxrs_high,
-                                  current->thread.fpu.vxrs + __NUM_VXRS_LOW,
+                                  current->thread.ufpu.vxrs + __NUM_VXRS_LOW,
                                   sizeof(sregs_ext->vxrs_high)))
                        return -EFAULT;
        }
@@ -202,12 +202,12 @@ static int restore_sigregs_ext(struct pt_regs *regs,
        if (cpu_has_vx()) {
                if (__copy_from_user(vxrs, &sregs_ext->vxrs_low,
                                     sizeof(sregs_ext->vxrs_low)) ||
-                   __copy_from_user(current->thread.fpu.vxrs + __NUM_VXRS_LOW,
+                   __copy_from_user(current->thread.ufpu.vxrs + __NUM_VXRS_LOW,
                                     &sregs_ext->vxrs_high,
                                     sizeof(sregs_ext->vxrs_high)))
                        return -EFAULT;
                for (i = 0; i < __NUM_VXRS_LOW; i++)
-                       current->thread.fpu.vxrs[i].low = vxrs[i];
+                       current->thread.ufpu.vxrs[i].low = vxrs[i];
        }
        return 0;
 }
@@ -222,7 +222,7 @@ SYSCALL_DEFINE0(sigreturn)
        if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
                goto badframe;
        set_current_blocked(&set);
-       save_fpu_regs();
+       save_user_fpu_regs();
        if (restore_sigregs(regs, &frame->sregs))
                goto badframe;
        if (restore_sigregs_ext(regs, &frame->sregs_ext))
@@ -246,7 +246,7 @@ SYSCALL_DEFINE0(rt_sigreturn)
        set_current_blocked(&set);
        if (restore_altstack(&frame->uc.uc_stack))
                goto badframe;
-       save_fpu_regs();
+       save_user_fpu_regs();
        if (restore_sigregs(regs, &frame->uc.uc_mcontext))
                goto badframe;
        if (restore_sigregs_ext(regs, &frame->uc.uc_mcontext_ext))
index c39d9f0d4b1c61cffa8284aceb347c5f8fedb959..0324649aae0a3e7348639bb1c33fb22fc19be783 100644 (file)
 #include <linux/sched/task_stack.h>
 #include <linux/crash_dump.h>
 #include <linux/kprobes.h>
+#include <asm/access-regs.h>
 #include <asm/asm-offsets.h>
 #include <asm/ctlreg.h>
 #include <asm/pfault.h>
 #include <asm/diag.h>
-#include <asm/switch_to.h>
 #include <asm/facility.h>
+#include <asm/fpu.h>
 #include <asm/ipl.h>
 #include <asm/setup.h>
 #include <asm/irq.h>
index f6f8f498c9be3959a433ffd7c1241ed6af663a2c..1b1be3110cfc111e71ecf06d2c513700a63b59aa 100644 (file)
@@ -20,7 +20,7 @@
 #include <asm/sysinfo.h>
 #include <asm/cpcmd.h>
 #include <asm/topology.h>
-#include <asm/fpu/api.h>
+#include <asm/fpu.h>
 
 int topology_max_mnest;
 
@@ -426,9 +426,9 @@ subsys_initcall(create_proc_service_level);
  */
 void s390_adjust_jiffies(void)
 {
+       DECLARE_KERNEL_FPU_ONSTACK16(fpu);
        struct sysinfo_1_2_2 *info;
        unsigned long capability;
-       struct kernel_fpu fpu;
 
        info = (void *) get_zeroed_page(GFP_KERNEL);
        if (!info)
@@ -447,21 +447,14 @@ void s390_adjust_jiffies(void)
                 * point division ..
                 */
                kernel_fpu_begin(&fpu, KERNEL_FPR);
-               asm volatile(
-                       "       sfpc    %3\n"
-                       "       l       %0,%1\n"
-                       "       tmlh    %0,0xff80\n"
-                       "       jnz     0f\n"
-                       "       cefbr   %%f2,%0\n"
-                       "       j       1f\n"
-                       "0:     le      %%f2,%1\n"
-                       "1:     cefbr   %%f0,%2\n"
-                       "       debr    %%f0,%%f2\n"
-                       "       cgebr   %0,5,%%f0\n"
-                       : "=&d" (capability)
-                       : "Q" (info->capability), "d" (10000000), "d" (0)
-                       : "cc"
-                       );
+               fpu_sfpc(0);
+               if (info->capability & 0xff800000)
+                       fpu_ldgr(2, info->capability);
+               else
+                       fpu_cefbr(2, info->capability);
+               fpu_cefbr(0, 10000000);
+               fpu_debr(0, 2);
+               capability = fpu_cgebr(0, 5);
                kernel_fpu_end(&fpu, KERNEL_FPR);
        } else
                /*
index 14c6d25c035f4a11018a1f0fa636a8b09c1aea27..c0a70efa2426d8a5bfc974253da744f8d744efeb 100644 (file)
@@ -90,7 +90,7 @@ SYM_FUNC_START(_diag26c_amode31)
 SYM_FUNC_END(_diag26c_amode31)
 
 /*
- * void _diag0c_amode31(struct hypfs_diag0c_entry *entry)
+ * void _diag0c_amode31(unsigned long rx)
  */
 SYM_FUNC_START(_diag0c_amode31)
        sam31
index 14abad953c0252e63fc34ce5dbc3c3a6c7d6e390..fb9f31f36628137ba7d3636606c44d54d3cb984a 100644 (file)
@@ -251,8 +251,8 @@ static struct clocksource clocksource_tod = {
        .rating         = 400,
        .read           = read_tod_clock,
        .mask           = CLOCKSOURCE_MASK(64),
-       .mult           = 1000,
-       .shift          = 12,
+       .mult           = 4096000,
+       .shift          = 24,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
        .vdso_clock_mode = VDSO_CLOCKMODE_TOD,
 };
@@ -716,7 +716,7 @@ out_unlock:
 /*
  * STP subsys sysfs interface functions
  */
-static struct bus_type stp_subsys = {
+static const struct bus_type stp_subsys = {
        .name           = "stp",
        .dev_name       = "stp",
 };
index 46dac4540ca8e1ee8e72e1ae399a955f13644cf4..52578b5cecbd93e4bc656aec612dac07c7ae105d 100644 (file)
@@ -28,8 +28,8 @@
 #include <linux/cpu.h>
 #include <linux/entry-common.h>
 #include <asm/asm-extable.h>
-#include <asm/fpu/api.h>
 #include <asm/vtime.h>
+#include <asm/fpu.h>
 #include "entry.h"
 
 static inline void __user *get_trap_ip(struct pt_regs *regs)
@@ -201,8 +201,8 @@ static void vector_exception(struct pt_regs *regs)
        }
 
        /* get vector interrupt code from fpc */
-       save_fpu_regs();
-       vic = (current->thread.fpu.fpc & 0xf00) >> 8;
+       save_user_fpu_regs();
+       vic = (current->thread.ufpu.fpc & 0xf00) >> 8;
        switch (vic) {
        case 1: /* invalid vector operation */
                si_code = FPE_FLTINV;
@@ -227,9 +227,9 @@ static void vector_exception(struct pt_regs *regs)
 
 static void data_exception(struct pt_regs *regs)
 {
-       save_fpu_regs();
-       if (current->thread.fpu.fpc & FPC_DXC_MASK)
-               do_fp_trap(regs, current->thread.fpu.fpc);
+       save_user_fpu_regs();
+       if (current->thread.ufpu.fpc & FPC_DXC_MASK)
+               do_fp_trap(regs, current->thread.ufpu.fpc);
        else
                do_trap(regs, SIGILL, ILL_ILLOPN, "data exception");
 }
index b88345ef8bd9ed627a14065e2efbd534ccf20173..5b0633ea8d93d1f088c0d54897afded431157a19 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/kdebug.h>
 #include <linux/sched/task_stack.h>
 
-#include <asm/switch_to.h>
 #include <asm/facility.h>
 #include <asm/kprobes.h>
 #include <asm/dis.h>
index bbaefd84f15e4f37efeee0123d0be9ef122f8886..a45b3a4c91db0f46a9518c47dd9356cf74907b71 100644 (file)
@@ -25,10 +25,7 @@ extern char vdso32_start[], vdso32_end[];
 
 static struct vm_special_mapping vvar_mapping;
 
-static union {
-       struct vdso_data        data[CS_BASES];
-       u8                      page[PAGE_SIZE];
-} vdso_data_store __page_aligned_data;
+static union vdso_data_store vdso_data_store __page_aligned_data;
 
 struct vdso_data *vdso_data = vdso_data_store.data;
 
index caec7db6f96684493f50b9638ea7e2acf851eba5..b12a274cbb4737e0f9f302cc2cb17e351ed14e91 100644 (file)
@@ -22,7 +22,7 @@ KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS))
 KBUILD_CFLAGS_32 := $(filter-out -mno-pic-data-is-text-relative,$(KBUILD_CFLAGS_32))
 KBUILD_CFLAGS_32 += -m31 -fPIC -shared -fno-common -fno-builtin
 
-LDFLAGS_vdso32.so.dbg += -fPIC -shared -soname=linux-vdso32.so.1 \
+LDFLAGS_vdso32.so.dbg += -shared -soname=linux-vdso32.so.1 \
        --hash-style=both --build-id=sha1 -melf_s390 -T
 
 $(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32)
index edf5ff1debe109987312a74658122cb2eb0a7298..65b9513a5a0ee2a7e3508a1d919f826c4b4184ca 100644 (file)
@@ -9,7 +9,6 @@
 
 OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390")
 OUTPUT_ARCH(s390:31-bit)
-ENTRY(_start)
 
 SECTIONS
 {
index e3c9085f8fa72b07523477a3cd314f45d26c368e..ef9832726097256f572b7ef88819a1e149eae059 100644 (file)
@@ -25,8 +25,9 @@ KBUILD_AFLAGS_64 += -m64
 
 KBUILD_CFLAGS_64 := $(filter-out -m64,$(KBUILD_CFLAGS))
 KBUILD_CFLAGS_64 := $(filter-out -mno-pic-data-is-text-relative,$(KBUILD_CFLAGS_64))
+KBUILD_CFLAGS_64 := $(filter-out -munaligned-symbols,$(KBUILD_CFLAGS_64))
 KBUILD_CFLAGS_64 += -m64 -fPIC -fno-common -fno-builtin
-ldflags-y := -fPIC -shared -soname=linux-vdso64.so.1 \
+ldflags-y := -shared -soname=linux-vdso64.so.1 \
             --hash-style=both --build-id=sha1 -T
 
 $(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_64)
index 4461ea151e49a16d5a2000e4fbf8b29a354f5763..37e2a505e81dbde8a8954a6883e6a60f8fa81b0f 100644 (file)
@@ -9,7 +9,6 @@
 
 OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
 OUTPUT_ARCH(s390:64-bit)
-ENTRY(_start)
 
 SECTIONS
 {
index e32ef446f45115faede66cc0d11c32d9440eb73b..48de296e8905c1bef0ad7059aa92666656adc8b1 100644 (file)
@@ -59,6 +59,14 @@ SECTIONS
        } :text = 0x0700
 
        RO_DATA(PAGE_SIZE)
+       .data.rel.ro : {
+               *(.data.rel.ro .data.rel.ro.*)
+       }
+       .got : {
+               __got_start = .;
+               *(.got)
+               __got_end = .;
+       }
 
        . = ALIGN(PAGE_SIZE);
        _sdata = .;             /* Start of data section */
@@ -73,6 +81,9 @@ SECTIONS
        __end_ro_after_init = .;
 
        RW_DATA(0x100, PAGE_SIZE, THREAD_SIZE)
+       .data.rel : {
+               *(.data.rel*)
+       }
        BOOT_DATA_PRESERVED
 
        . = ALIGN(8);
@@ -181,6 +192,7 @@ SECTIONS
 
        PERCPU_SECTION(0x100)
 
+#ifdef CONFIG_PIE_BUILD
        .dynsym ALIGN(8) : {
                __dynsym_start = .;
                *(.dynsym)
@@ -191,6 +203,19 @@ SECTIONS
                *(.rela*)
                __rela_dyn_end = .;
        }
+       .dynamic ALIGN(8) : {
+               *(.dynamic)
+       }
+       .dynstr ALIGN(8) : {
+               *(.dynstr)
+       }
+#endif
+       .hash ALIGN(8) : {
+               *(.hash)
+       }
+       .gnu.hash ALIGN(8) : {
+               *(.gnu.hash)
+       }
 
        . = ALIGN(PAGE_SIZE);
        __init_end = .;         /* freed after init ends here */
@@ -214,9 +239,14 @@ SECTIONS
                QUAD(__boot_data_preserved_start)               /* bootdata_preserved_off */
                QUAD(__boot_data_preserved_end -
                     __boot_data_preserved_start)               /* bootdata_preserved_size */
+#ifdef CONFIG_PIE_BUILD
                QUAD(__dynsym_start)                            /* dynsym_start */
                QUAD(__rela_dyn_start)                          /* rela_dyn_start */
                QUAD(__rela_dyn_end)                            /* rela_dyn_end */
+#else
+               QUAD(__got_start)                               /* got_start */
+               QUAD(__got_end)                                 /* got_end */
+#endif
                QUAD(_eamode31 - _samode31)                     /* amode31_size */
                QUAD(init_mm)
                QUAD(swapper_pg_dir)
@@ -235,6 +265,30 @@ SECTIONS
        DWARF_DEBUG
        ELF_DETAILS
 
+       /*
+        * Make sure that the .got.plt is either completely empty or it
+        * contains only the three reserved double words.
+        */
+       .got.plt : {
+               *(.got.plt)
+       }
+       ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, "Unexpected GOT/PLT entries detected!")
+
+       /*
+        * Sections that should stay zero sized, which is safer to
+        * explicitly check instead of blindly discarding.
+        */
+       .plt : {
+               *(.plt) *(.plt.*) *(.iplt) *(.igot .igot.plt)
+       }
+       ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!")
+#ifndef CONFIG_PIE_BUILD
+       .rela.dyn : {
+               *(.rela.*) *(.rela_*)
+       }
+       ASSERT(SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations (.rela) detected!")
+#endif
+
        /* Sections to be discarded */
        DISCARDS
        /DISCARD/ : {
index 5bfcc50c1a682893b9add045508fcbb3d4526338..ee863566910b1576179e4c41548c44456be73c65 100644 (file)
 #include <linux/err.h>
 #include <linux/pgtable.h>
 #include <linux/bitfield.h>
+#include <asm/access-regs.h>
 #include <asm/fault.h>
 #include <asm/gmap.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
-#include <asm/switch_to.h>
 
 union asce {
        unsigned long val;
@@ -391,7 +391,8 @@ static int ar_translation(struct kvm_vcpu *vcpu, union asce *asce, u8 ar,
        if (ar >= NUM_ACRS)
                return -EINVAL;
 
-       save_access_regs(vcpu->run->s.regs.acrs);
+       if (vcpu->arch.acrs_loaded)
+               save_access_regs(vcpu->run->s.regs.acrs);
        alet.val = vcpu->run->s.regs.acrs[ar];
 
        if (ar == 0 || alet.val == 0) {
index fc4007cc067a688d7ce73e8911f50cc88a688507..dc721d50a942f8e5090ca63e04160455b5327d6d 100644 (file)
 #include <linux/slab.h>
 #include <linux/bitmap.h>
 #include <linux/vmalloc.h>
+#include <asm/access-regs.h>
 #include <asm/asm-offsets.h>
 #include <asm/dis.h>
 #include <linux/uaccess.h>
 #include <asm/sclp.h>
 #include <asm/isc.h>
 #include <asm/gmap.h>
-#include <asm/switch_to.h>
 #include <asm/nmi.h>
 #include <asm/airq.h>
 #include <asm/tpi.h>
@@ -584,7 +584,7 @@ static int __write_machine_check(struct kvm_vcpu *vcpu,
 
        mci.val = mchk->mcic;
        /* take care of lazy register loading */
-       save_fpu_regs();
+       kvm_s390_fpu_store(vcpu->run);
        save_access_regs(vcpu->run->s.regs.acrs);
        if (MACHINE_HAS_GS && vcpu->arch.gs_enabled)
                save_gs_cb(current->thread.gs_cb);
@@ -648,7 +648,7 @@ static int __write_machine_check(struct kvm_vcpu *vcpu,
        }
        rc |= write_guest_lc(vcpu, __LC_GPREGS_SAVE_AREA,
                             vcpu->run->s.regs.gprs, 128);
-       rc |= put_guest_lc(vcpu, current->thread.fpu.fpc,
+       rc |= put_guest_lc(vcpu, vcpu->run->s.regs.fpc,
                           (u32 __user *) __LC_FP_CREG_SAVE_AREA);
        rc |= put_guest_lc(vcpu, vcpu->arch.sie_block->todpr,
                           (u32 __user *) __LC_TOD_PROGREG_SAVE_AREA);
index ea63ac76988914d85bdfb7fdbe7bd209f4066741..b11bb8e780a107206c5fe8867199bdcaf6e33a3b 100644 (file)
 #include <linux/pgtable.h>
 #include <linux/mmu_notifier.h>
 
+#include <asm/access-regs.h>
 #include <asm/asm-offsets.h>
 #include <asm/lowcore.h>
 #include <asm/stp.h>
 #include <asm/gmap.h>
 #include <asm/nmi.h>
-#include <asm/switch_to.h>
 #include <asm/isc.h>
 #include <asm/sclp.h>
 #include <asm/cpacf.h>
 #include <asm/timex.h>
+#include <asm/fpu.h>
 #include <asm/ap.h>
 #include <asm/uv.h>
-#include <asm/fpu/api.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
 #include "pci.h"
@@ -3951,6 +3951,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
                                    KVM_SYNC_ARCH0 |
                                    KVM_SYNC_PFAULT |
                                    KVM_SYNC_DIAG318;
+       vcpu->arch.acrs_loaded = false;
        kvm_s390_set_prefix(vcpu, 0);
        if (test_kvm_facility(vcpu->kvm, 64))
                vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB;
@@ -4829,8 +4830,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
                               vcpu->run->s.regs.gprs,
                               sizeof(sie_page->pv_grregs));
                }
-               if (test_cpu_flag(CIF_FPU))
-                       load_fpu_regs();
                exit_reason = sie64a(vcpu->arch.sie_block,
                                     vcpu->run->s.regs.gprs);
                if (kvm_s390_pv_cpu_is_protected(vcpu)) {
@@ -4951,16 +4950,8 @@ static void sync_regs(struct kvm_vcpu *vcpu)
        }
        save_access_regs(vcpu->arch.host_acrs);
        restore_access_regs(vcpu->run->s.regs.acrs);
-       /* save host (userspace) fprs/vrs */
-       save_fpu_regs();
-       vcpu->arch.host_fpregs.fpc = current->thread.fpu.fpc;
-       vcpu->arch.host_fpregs.regs = current->thread.fpu.regs;
-       if (cpu_has_vx())
-               current->thread.fpu.regs = vcpu->run->s.regs.vrs;
-       else
-               current->thread.fpu.regs = vcpu->run->s.regs.fprs;
-       current->thread.fpu.fpc = vcpu->run->s.regs.fpc;
-
+       vcpu->arch.acrs_loaded = true;
+       kvm_s390_fpu_load(vcpu->run);
        /* Sync fmt2 only data */
        if (likely(!kvm_s390_pv_cpu_is_protected(vcpu))) {
                sync_regs_fmt2(vcpu);
@@ -5021,12 +5012,8 @@ static void store_regs(struct kvm_vcpu *vcpu)
        kvm_run->s.regs.pfc = vcpu->arch.pfault_compare;
        save_access_regs(vcpu->run->s.regs.acrs);
        restore_access_regs(vcpu->arch.host_acrs);
-       /* Save guest register state */
-       save_fpu_regs();
-       vcpu->run->s.regs.fpc = current->thread.fpu.fpc;
-       /* Restore will be done lazily at return */
-       current->thread.fpu.fpc = vcpu->arch.host_fpregs.fpc;
-       current->thread.fpu.regs = vcpu->arch.host_fpregs.regs;
+       vcpu->arch.acrs_loaded = false;
+       kvm_s390_fpu_store(vcpu->run);
        if (likely(!kvm_s390_pv_cpu_is_protected(vcpu)))
                store_regs_fmt2(vcpu);
 }
@@ -5034,6 +5021,7 @@ static void store_regs(struct kvm_vcpu *vcpu)
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *kvm_run = vcpu->run;
+       DECLARE_KERNEL_FPU_ONSTACK32(fpu);
        int rc;
 
        /*
@@ -5075,6 +5063,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                goto out;
        }
 
+       kernel_fpu_begin(&fpu, KERNEL_FPC | KERNEL_VXR);
        sync_regs(vcpu);
        enable_cpu_timer_accounting(vcpu);
 
@@ -5098,6 +5087,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 
        disable_cpu_timer_accounting(vcpu);
        store_regs(vcpu);
+       kernel_fpu_end(&fpu, KERNEL_FPC | KERNEL_VXR);
 
        kvm_sigset_deactivate(vcpu);
 
@@ -5172,8 +5162,7 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
         * switch in the run ioctl. Let's update our copies before we save
         * it into the save area
         */
-       save_fpu_regs();
-       vcpu->run->s.regs.fpc = current->thread.fpu.fpc;
+       kvm_s390_fpu_store(vcpu->run);
        save_access_regs(vcpu->run->s.regs.acrs);
 
        return kvm_s390_store_status_unloaded(vcpu, addr);
index a7ea80cfa445e1a9929b2b36ccd4d7c88a0eb2bc..111eb5c7478409c4af5c8c3e8f76c730b1b5406c 100644 (file)
 #include <asm/processor.h>
 #include <asm/sclp.h>
 
+static inline void kvm_s390_fpu_store(struct kvm_run *run)
+{
+       fpu_stfpc(&run->s.regs.fpc);
+       if (cpu_has_vx())
+               save_vx_regs((__vector128 *)&run->s.regs.vrs);
+       else
+               save_fp_regs((freg_t *)&run->s.regs.fprs);
+}
+
+static inline void kvm_s390_fpu_load(struct kvm_run *run)
+{
+       fpu_lfpc_safe(&run->s.regs.fpc);
+       if (cpu_has_vx())
+               load_vx_regs((__vector128 *)&run->s.regs.vrs);
+       else
+               load_fp_regs((freg_t *)&run->s.regs.fprs);
+}
+
 /* Transactional Memory Execution related macros */
 #define IS_TE_ENABLED(vcpu)    ((vcpu->arch.sie_block->ecb & ECB_TE))
 #define TDB_FORMAT1            1
index 3af3bd20ac7b8f075e08b85b34f7e257f4687eeb..b2c9f010f0fefd6744289d03a7f1e7c294b791e6 100644 (file)
@@ -18,7 +18,6 @@
 #include <asm/sclp.h>
 #include <asm/nmi.h>
 #include <asm/dis.h>
-#include <asm/fpu/api.h>
 #include <asm/facility.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
@@ -1149,8 +1148,6 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
         */
        vcpu->arch.sie_block->prog0c |= PROG_IN_SIE;
        barrier();
-       if (test_cpu_flag(CIF_FPU))
-               load_fpu_regs();
        if (!kvm_s390_vcpu_sie_inhibited(vcpu))
                rc = sie64a(scb_s, vcpu->run->s.regs.gprs);
        barrier();
index 7c50eca85ca40b02432c82b5e41b391e5eafd5c0..90eac15ea62aaf22b2984e09c7ce4a2b3bc6f504 100644 (file)
@@ -4,6 +4,7 @@
 #
 
 lib-y += delay.o string.o uaccess.o find.o spinlock.o tishift.o
+lib-y += csum-partial.o
 obj-y += mem.o xor.o
 lib-$(CONFIG_KPROBES) += probes.o
 lib-$(CONFIG_UPROBES) += probes.o
diff --git a/arch/s390/lib/csum-partial.c b/arch/s390/lib/csum-partial.c
new file mode 100644 (file)
index 0000000..458abd9
--- /dev/null
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/export.h>
+#include <asm/checksum.h>
+#include <asm/fpu.h>
+
+/*
+ * Computes the checksum of a memory block at src, length len,
+ * and adds in "sum" (32-bit). If copy is true copies to dst.
+ *
+ * Returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic.
+ *
+ * This function must be called with even lengths, except
+ * for the last fragment, which may be odd.
+ *
+ * It's best to have src and dst aligned on a 64-bit boundary.
+ */
+static __always_inline __wsum csum_copy(void *dst, const void *src, int len, __wsum sum, bool copy)
+{
+       DECLARE_KERNEL_FPU_ONSTACK8(vxstate);
+
+       if (!cpu_has_vx()) {
+               if (copy)
+                       memcpy(dst, src, len);
+               return cksm(dst, len, sum);
+       }
+       kernel_fpu_begin(&vxstate, KERNEL_VXR_V16V23);
+       fpu_vlvgf(16, (__force u32)sum, 1);
+       fpu_vzero(17);
+       fpu_vzero(18);
+       fpu_vzero(19);
+       while (len >= 64) {
+               fpu_vlm(20, 23, src);
+               if (copy) {
+                       fpu_vstm(20, 23, dst);
+                       dst += 64;
+               }
+               fpu_vcksm(16, 20, 16);
+               fpu_vcksm(17, 21, 17);
+               fpu_vcksm(18, 22, 18);
+               fpu_vcksm(19, 23, 19);
+               src += 64;
+               len -= 64;
+       }
+       while (len >= 32) {
+               fpu_vlm(20, 21, src);
+               if (copy) {
+                       fpu_vstm(20, 21, dst);
+                       dst += 32;
+               }
+               fpu_vcksm(16, 20, 16);
+               fpu_vcksm(17, 21, 17);
+               src += 32;
+               len -= 32;
+       }
+       while (len >= 16) {
+               fpu_vl(20, src);
+               if (copy) {
+                       fpu_vst(20, dst);
+                       dst += 16;
+               }
+               fpu_vcksm(16, 20, 16);
+               src += 16;
+               len -= 16;
+       }
+       if (len) {
+               fpu_vll(20, len - 1, src);
+               if (copy)
+                       fpu_vstl(20, len - 1, dst);
+               fpu_vcksm(16, 20, 16);
+       }
+       fpu_vcksm(18, 19, 18);
+       fpu_vcksm(16, 17, 16);
+       fpu_vcksm(16, 18, 16);
+       sum = (__force __wsum)fpu_vlgvf(16, 1);
+       kernel_fpu_end(&vxstate, KERNEL_VXR_V16V23);
+       return sum;
+}
+
+__wsum csum_partial(const void *buff, int len, __wsum sum)
+{
+       return csum_copy(NULL, buff, len, sum, false);
+}
+EXPORT_SYMBOL(csum_partial);
+
+__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
+{
+       return csum_copy(dst, src, len, 0, true);
+}
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
index e41869f5cc95df0931bdab5d3c6b601c71b2de2c..282fefe107a246e0716892f1166706870a47a275 100644 (file)
@@ -136,7 +136,7 @@ dcss_diag(int *func, void *parameter,
        unsigned long rx, ry;
        int rc;
 
-       rx = (unsigned long) parameter;
+       rx = virt_to_phys(parameter);
        ry = (unsigned long) *func;
 
        diag_stat_inc(DIAG_STAT_X064);
@@ -178,7 +178,7 @@ query_segment_type (struct dcss_segment *seg)
 
        /* initialize diag input parameters */
        qin->qopcode = DCSS_FINDSEGA;
-       qin->qoutptr = (unsigned long) qout;
+       qin->qoutptr = virt_to_phys(qout);
        qin->qoutlen = sizeof(struct qout64);
        memcpy (qin->qname, seg->dcss_name, 8);
 
index fc9a7dc26c5ed710037923565bb8ab35814b621b..b14fc0887654d28376081f5b4c77b0751109c149 100644 (file)
@@ -71,6 +71,15 @@ 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)
+{
+       if (!(current->flags & PF_RANDOMIZE))
+               return 0;
+       if (filp || (flags & MAP_SHARED))
+               return MMAP_ALIGN_MASK << PAGE_SHIFT;
+       return 0;
+}
+
 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
                                     unsigned long len, unsigned long pgoff,
                                     unsigned long flags)
@@ -97,10 +106,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
        info.length = len;
        info.low_limit = mm->mmap_base;
        info.high_limit = TASK_SIZE;
-       if (filp || (flags & MAP_SHARED))
-               info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT;
-       else
-               info.align_mask = 0;
+       info.align_mask = get_align_mask(filp, flags);
        info.align_offset = pgoff << PAGE_SHIFT;
        addr = vm_unmapped_area(&info);
        if (offset_in_page(addr))
@@ -138,10 +144,7 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp, unsigned long ad
        info.length = len;
        info.low_limit = PAGE_SIZE;
        info.high_limit = mm->mmap_base;
-       if (filp || (flags & MAP_SHARED))
-               info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT;
-       else
-               info.align_mask = 0;
+       info.align_mask = get_align_mask(filp, flags);
        info.align_offset = pgoff << PAGE_SHIFT;
        addr = vm_unmapped_area(&info);
 
index 676ac74026a82b578f857e2426a501abdec014c7..26afde0d1ed34c7e6792502c1498d679d915288e 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/jump_label.h>
 #include <linux/pci.h>
 #include <linux/printk.h>
+#include <linux/lockdep.h>
 
 #include <asm/isc.h>
 #include <asm/airq.h>
@@ -252,7 +253,7 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 /* combine single writes by using store-block insn */
 void __iowrite64_copy(void __iomem *to, const void *from, size_t count)
 {
-       zpci_memcpy_toio(to, from, count);
+       zpci_memcpy_toio(to, from, count * 8);
 }
 
 void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
@@ -730,12 +731,12 @@ EXPORT_SYMBOL_GPL(zpci_disable_device);
  * equivalent to its state during boot when first probing a driver.
  * Consequently after reset the PCI function requires re-initialization via the
  * common PCI code including re-enabling IRQs via pci_alloc_irq_vectors()
- * and enabling the function via e.g.pci_enablde_device_flags().The caller
+ * and enabling the function via e.g. pci_enable_device_flags(). The caller
  * must guard against concurrent reset attempts.
  *
  * In most cases this function should not be called directly but through
  * pci_reset_function() or pci_reset_bus() which handle the save/restore and
- * locking.
+ * locking - asserted by lockdep.
  *
  * Return: 0 on success and an error value otherwise
  */
@@ -744,6 +745,7 @@ int zpci_hot_reset_device(struct zpci_dev *zdev)
        u8 status;
        int rc;
 
+       lockdep_assert_held(&zdev->state_lock);
        zpci_dbg(3, "rst fid:%x, fh:%x\n", zdev->fid, zdev->fh);
        if (zdev_enabled(zdev)) {
                /* Disables device access, DMAs and IRQs (reset state) */
@@ -806,7 +808,8 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
        zdev->state =  state;
 
        kref_init(&zdev->kref);
-       mutex_init(&zdev->lock);
+       mutex_init(&zdev->state_lock);
+       mutex_init(&zdev->fmb_lock);
        mutex_init(&zdev->kzdev_lock);
 
        rc = zpci_init_iommu(zdev);
@@ -870,6 +873,10 @@ int zpci_deconfigure_device(struct zpci_dev *zdev)
 {
        int rc;
 
+       lockdep_assert_held(&zdev->state_lock);
+       if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
+               return 0;
+
        if (zdev->zbus->bus)
                zpci_bus_remove_device(zdev, false);
 
@@ -889,7 +896,7 @@ int zpci_deconfigure_device(struct zpci_dev *zdev)
 }
 
 /**
- * zpci_device_reserved() - Mark device as resverved
+ * zpci_device_reserved() - Mark device as reserved
  * @zdev: the zpci_dev that was reserved
  *
  * Handle the case that a given zPCI function was reserved by another system.
@@ -899,8 +906,6 @@ int zpci_deconfigure_device(struct zpci_dev *zdev)
  */
 void zpci_device_reserved(struct zpci_dev *zdev)
 {
-       if (zdev->has_hp_slot)
-               zpci_exit_slot(zdev);
        /*
         * Remove device from zpci_list as it is going away. This also
         * makes sure we ignore subsequent zPCI events for this device.
@@ -918,6 +923,9 @@ void zpci_release_device(struct kref *kref)
        struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref);
        int ret;
 
+       if (zdev->has_hp_slot)
+               zpci_exit_slot(zdev);
+
        if (zdev->zbus->bus)
                zpci_bus_remove_device(zdev, false);
 
index 6dde2263c79d1f57274e016e5867fe3a09ed473c..2cb5043a997d53b47d2d1513ab98636494399720 100644 (file)
@@ -91,9 +91,9 @@ static int pci_perf_show(struct seq_file *m, void *v)
        if (!zdev)
                return 0;
 
-       mutex_lock(&zdev->lock);
+       mutex_lock(&zdev->fmb_lock);
        if (!zdev->fmb) {
-               mutex_unlock(&zdev->lock);
+               mutex_unlock(&zdev->fmb_lock);
                seq_puts(m, "FMB statistics disabled\n");
                return 0;
        }
@@ -130,7 +130,7 @@ static int pci_perf_show(struct seq_file *m, void *v)
        }
 
        pci_sw_counter_show(m);
-       mutex_unlock(&zdev->lock);
+       mutex_unlock(&zdev->fmb_lock);
        return 0;
 }
 
@@ -148,7 +148,7 @@ static ssize_t pci_perf_seq_write(struct file *file, const char __user *ubuf,
        if (rc)
                return rc;
 
-       mutex_lock(&zdev->lock);
+       mutex_lock(&zdev->fmb_lock);
        switch (val) {
        case 0:
                rc = zpci_fmb_disable_device(zdev);
@@ -157,7 +157,7 @@ static ssize_t pci_perf_seq_write(struct file *file, const char __user *ubuf,
                rc = zpci_fmb_enable_device(zdev);
                break;
        }
-       mutex_unlock(&zdev->lock);
+       mutex_unlock(&zdev->fmb_lock);
        return rc ? rc : count;
 }
 
index 4d9773ef9e0a856e8a21b1ca46174e653daa6360..dbe95ec5917e57f79a55033a1768c8945079cf6a 100644 (file)
@@ -267,6 +267,7 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
        zpci_err_hex(ccdf, sizeof(*ccdf));
 
        if (zdev) {
+               mutex_lock(&zdev->state_lock);
                zpci_update_fh(zdev, ccdf->fh);
                if (zdev->zbus->bus)
                        pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
@@ -294,6 +295,8 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
        }
        pci_dev_put(pdev);
 no_pdev:
+       if (zdev)
+               mutex_unlock(&zdev->state_lock);
        zpci_zdev_put(zdev);
 }
 
@@ -326,6 +329,10 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
 
        zpci_dbg(3, "avl fid:%x, fh:%x, pec:%x\n",
                 ccdf->fid, ccdf->fh, ccdf->pec);
+
+       if (existing_zdev)
+               mutex_lock(&zdev->state_lock);
+
        switch (ccdf->pec) {
        case 0x0301: /* Reserved|Standby -> Configured */
                if (!zdev) {
@@ -348,7 +355,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
                break;
        case 0x0303: /* Deconfiguration requested */
                if (zdev) {
-                       /* The event may have been queued before we confirgured
+                       /* The event may have been queued before we configured
                         * the device.
                         */
                        if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
@@ -359,7 +366,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
                break;
        case 0x0304: /* Configured -> Standby|Reserved */
                if (zdev) {
-                       /* The event may have been queued before we confirgured
+                       /* The event may have been queued before we configured
                         * the device.:
                         */
                        if (zdev->state == ZPCI_FN_STATE_CONFIGURED)
@@ -383,8 +390,10 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
        default:
                break;
        }
-       if (existing_zdev)
+       if (existing_zdev) {
+               mutex_unlock(&zdev->state_lock);
                zpci_zdev_put(zdev);
+       }
 }
 
 void zpci_event_availability(void *data)
index 8a7abac5181645d6635ed95e1f5706942948c642..a0b872b74fe39af3cdf5a58f2fbbca01f516235c 100644 (file)
@@ -49,6 +49,39 @@ static ssize_t mio_enabled_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(mio_enabled);
 
+static int _do_recover(struct pci_dev *pdev, struct zpci_dev *zdev)
+{
+       u8 status;
+       int ret;
+
+       pci_stop_and_remove_bus_device(pdev);
+       if (zdev_enabled(zdev)) {
+               ret = zpci_disable_device(zdev);
+               /*
+                * Due to a z/VM vs LPAR inconsistency in the error
+                * state the FH may indicate an enabled device but
+                * disable says the device is already disabled don't
+                * treat it as an error here.
+                */
+               if (ret == -EINVAL)
+                       ret = 0;
+               if (ret)
+                       return ret;
+       }
+
+       ret = zpci_enable_device(zdev);
+       if (ret)
+               return ret;
+
+       if (zdev->dma_table) {
+               ret = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
+                                        virt_to_phys(zdev->dma_table), &status);
+               if (ret)
+                       zpci_disable_device(zdev);
+       }
+       return ret;
+}
+
 static ssize_t recover_store(struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
@@ -56,7 +89,6 @@ static ssize_t recover_store(struct device *dev, struct device_attribute *attr,
        struct pci_dev *pdev = to_pci_dev(dev);
        struct zpci_dev *zdev = to_zpci(pdev);
        int ret = 0;
-       u8 status;
 
        /* Can't use device_remove_self() here as that would lead us to lock
         * the pci_rescan_remove_lock while holding the device' kernfs lock.
@@ -70,6 +102,12 @@ static ssize_t recover_store(struct device *dev, struct device_attribute *attr,
         */
        kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
        WARN_ON_ONCE(!kn);
+
+       /* Device needs to be configured and state must not change */
+       mutex_lock(&zdev->state_lock);
+       if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
+               goto out;
+
        /* device_remove_file() serializes concurrent calls ignoring all but
         * the first
         */
@@ -82,35 +120,13 @@ static ssize_t recover_store(struct device *dev, struct device_attribute *attr,
         */
        pci_lock_rescan_remove();
        if (pci_dev_is_added(pdev)) {
-               pci_stop_and_remove_bus_device(pdev);
-               if (zdev_enabled(zdev)) {
-                       ret = zpci_disable_device(zdev);
-                       /*
-                        * Due to a z/VM vs LPAR inconsistency in the error
-                        * state the FH may indicate an enabled device but
-                        * disable says the device is already disabled don't
-                        * treat it as an error here.
-                        */
-                       if (ret == -EINVAL)
-                               ret = 0;
-                       if (ret)
-                               goto out;
-               }
-
-               ret = zpci_enable_device(zdev);
-               if (ret)
-                       goto out;
-
-               if (zdev->dma_table) {
-                       ret = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
-                                                virt_to_phys(zdev->dma_table), &status);
-                       if (ret)
-                               zpci_disable_device(zdev);
-               }
+               ret = _do_recover(pdev, zdev);
        }
-out:
        pci_rescan_bus(zdev->zbus->bus);
        pci_unlock_rescan_remove();
+
+out:
+       mutex_unlock(&zdev->state_lock);
        if (kn)
                sysfs_unbreak_active_protection(kn);
        return ret ? ret : count;
index ea62f37b79ef2adfd71d77c73800e1f8498f51bb..e6af51d9d1835511e075ef5c4034314881565180 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 gen_facilities
 gen_opcode_table
+relocs
index f9dd47ff9ac4515de9347ce9593e4c9ed4d409c8..f2862364fb4221526708416a1ffc97cfaf810c65 100644 (file)
@@ -25,3 +25,8 @@ $(kapi)/facility-defs.h: $(obj)/gen_facilities FORCE
 
 $(kapi)/dis-defs.h: $(obj)/gen_opcode_table FORCE
        $(call filechk,dis-defs.h)
+
+hostprogs      += relocs
+PHONY          += relocs
+relocs: $(obj)/relocs
+       @:
diff --git a/arch/s390/tools/relocs.c b/arch/s390/tools/relocs.c
new file mode 100644 (file)
index 0000000..30a732c
--- /dev/null
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <elf.h>
+#include <byteswap.h>
+#define USE_BSD
+#include <endian.h>
+
+#define ELF_BITS 64
+
+#define ELF_MACHINE            EM_S390
+#define ELF_MACHINE_NAME       "IBM S/390"
+#define SHT_REL_TYPE           SHT_RELA
+#define Elf_Rel                        Elf64_Rela
+
+#define ELF_CLASS              ELFCLASS64
+#define ELF_ENDIAN             ELFDATA2MSB
+#define ELF_R_SYM(val)         ELF64_R_SYM(val)
+#define ELF_R_TYPE(val)                ELF64_R_TYPE(val)
+#define ELF_ST_TYPE(o)         ELF64_ST_TYPE(o)
+#define ELF_ST_BIND(o)         ELF64_ST_BIND(o)
+#define ELF_ST_VISIBILITY(o)   ELF64_ST_VISIBILITY(o)
+
+#define ElfW(type)             _ElfW(ELF_BITS, type)
+#define _ElfW(bits, type)      __ElfW(bits, type)
+#define __ElfW(bits, type)     Elf##bits##_##type
+
+#define Elf_Addr               ElfW(Addr)
+#define Elf_Ehdr               ElfW(Ehdr)
+#define Elf_Phdr               ElfW(Phdr)
+#define Elf_Shdr               ElfW(Shdr)
+#define Elf_Sym                        ElfW(Sym)
+
+static Elf_Ehdr                ehdr;
+static unsigned long   shnum;
+static unsigned int    shstrndx;
+
+struct relocs {
+       uint32_t        *offset;
+       unsigned long   count;
+       unsigned long   size;
+};
+
+static struct relocs relocs64;
+#define FMT PRIu64
+
+struct section {
+       Elf_Shdr        shdr;
+       struct section  *link;
+       Elf_Rel         *reltab;
+};
+
+static struct section *secs;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define le16_to_cpu(val)       (val)
+#define le32_to_cpu(val)       (val)
+#define le64_to_cpu(val)       (val)
+#define be16_to_cpu(val)       bswap_16(val)
+#define be32_to_cpu(val)       bswap_32(val)
+#define be64_to_cpu(val)       bswap_64(val)
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define le16_to_cpu(val)       bswap_16(val)
+#define le32_to_cpu(val)       bswap_32(val)
+#define le64_to_cpu(val)       bswap_64(val)
+#define be16_to_cpu(val)       (val)
+#define be32_to_cpu(val)       (val)
+#define be64_to_cpu(val)       (val)
+#endif
+
+static uint16_t elf16_to_cpu(uint16_t val)
+{
+       if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+               return le16_to_cpu(val);
+       else
+               return be16_to_cpu(val);
+}
+
+static uint32_t elf32_to_cpu(uint32_t val)
+{
+       if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+               return le32_to_cpu(val);
+       else
+               return be32_to_cpu(val);
+}
+
+#define elf_half_to_cpu(x)     elf16_to_cpu(x)
+#define elf_word_to_cpu(x)     elf32_to_cpu(x)
+
+static uint64_t elf64_to_cpu(uint64_t val)
+{
+       return be64_to_cpu(val);
+}
+
+#define elf_addr_to_cpu(x)     elf64_to_cpu(x)
+#define elf_off_to_cpu(x)      elf64_to_cpu(x)
+#define elf_xword_to_cpu(x)    elf64_to_cpu(x)
+
+static void die(char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       exit(1);
+}
+
+static void read_ehdr(FILE *fp)
+{
+       if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
+               die("Cannot read ELF header: %s\n", strerror(errno));
+       if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0)
+               die("No ELF magic\n");
+       if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
+               die("Not a %d bit executable\n", ELF_BITS);
+       if (ehdr.e_ident[EI_DATA] != ELF_ENDIAN)
+               die("ELF endian mismatch\n");
+       if (ehdr.e_ident[EI_VERSION] != EV_CURRENT)
+               die("Unknown ELF version\n");
+
+       /* Convert the fields to native endian */
+       ehdr.e_type      = elf_half_to_cpu(ehdr.e_type);
+       ehdr.e_machine   = elf_half_to_cpu(ehdr.e_machine);
+       ehdr.e_version   = elf_word_to_cpu(ehdr.e_version);
+       ehdr.e_entry     = elf_addr_to_cpu(ehdr.e_entry);
+       ehdr.e_phoff     = elf_off_to_cpu(ehdr.e_phoff);
+       ehdr.e_shoff     = elf_off_to_cpu(ehdr.e_shoff);
+       ehdr.e_flags     = elf_word_to_cpu(ehdr.e_flags);
+       ehdr.e_ehsize    = elf_half_to_cpu(ehdr.e_ehsize);
+       ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize);
+       ehdr.e_phnum     = elf_half_to_cpu(ehdr.e_phnum);
+       ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize);
+       ehdr.e_shnum     = elf_half_to_cpu(ehdr.e_shnum);
+       ehdr.e_shstrndx  = elf_half_to_cpu(ehdr.e_shstrndx);
+
+       shnum = ehdr.e_shnum;
+       shstrndx = ehdr.e_shstrndx;
+
+       if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN))
+               die("Unsupported ELF header type\n");
+       if (ehdr.e_machine != ELF_MACHINE)
+               die("Not for %s\n", ELF_MACHINE_NAME);
+       if (ehdr.e_version != EV_CURRENT)
+               die("Unknown ELF version\n");
+       if (ehdr.e_ehsize != sizeof(Elf_Ehdr))
+               die("Bad Elf header size\n");
+       if (ehdr.e_phentsize != sizeof(Elf_Phdr))
+               die("Bad program header entry\n");
+       if (ehdr.e_shentsize != sizeof(Elf_Shdr))
+               die("Bad section header entry\n");
+
+       if (shnum == SHN_UNDEF || shstrndx == SHN_XINDEX) {
+               Elf_Shdr shdr;
+
+               if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0)
+                       die("Seek to %" FMT " failed: %s\n", ehdr.e_shoff, strerror(errno));
+
+               if (fread(&shdr, sizeof(shdr), 1, fp) != 1)
+                       die("Cannot read initial ELF section header: %s\n", strerror(errno));
+
+               if (shnum == SHN_UNDEF)
+                       shnum = elf_xword_to_cpu(shdr.sh_size);
+
+               if (shstrndx == SHN_XINDEX)
+                       shstrndx = elf_word_to_cpu(shdr.sh_link);
+       }
+
+       if (shstrndx >= shnum)
+               die("String table index out of bounds\n");
+}
+
+static void read_shdrs(FILE *fp)
+{
+       Elf_Shdr shdr;
+       int i;
+
+       secs = calloc(shnum, sizeof(struct section));
+       if (!secs)
+               die("Unable to allocate %ld section headers\n", shnum);
+
+       if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0)
+               die("Seek to %" FMT " failed: %s\n", ehdr.e_shoff, strerror(errno));
+
+       for (i = 0; i < shnum; i++) {
+               struct section *sec = &secs[i];
+
+               if (fread(&shdr, sizeof(shdr), 1, fp) != 1) {
+                       die("Cannot read ELF section headers %d/%ld: %s\n",
+                           i, shnum, strerror(errno));
+               }
+
+               sec->shdr.sh_name      = elf_word_to_cpu(shdr.sh_name);
+               sec->shdr.sh_type      = elf_word_to_cpu(shdr.sh_type);
+               sec->shdr.sh_flags     = elf_xword_to_cpu(shdr.sh_flags);
+               sec->shdr.sh_addr      = elf_addr_to_cpu(shdr.sh_addr);
+               sec->shdr.sh_offset    = elf_off_to_cpu(shdr.sh_offset);
+               sec->shdr.sh_size      = elf_xword_to_cpu(shdr.sh_size);
+               sec->shdr.sh_link      = elf_word_to_cpu(shdr.sh_link);
+               sec->shdr.sh_info      = elf_word_to_cpu(shdr.sh_info);
+               sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign);
+               sec->shdr.sh_entsize   = elf_xword_to_cpu(shdr.sh_entsize);
+
+               if (sec->shdr.sh_link < shnum)
+                       sec->link = &secs[sec->shdr.sh_link];
+       }
+
+}
+
+static void read_relocs(FILE *fp)
+{
+       int i, j;
+
+       for (i = 0; i < shnum; i++) {
+               struct section *sec = &secs[i];
+
+               if (sec->shdr.sh_type != SHT_REL_TYPE)
+                       continue;
+
+               sec->reltab = malloc(sec->shdr.sh_size);
+               if (!sec->reltab)
+                       die("malloc of %" FMT " bytes for relocs failed\n", sec->shdr.sh_size);
+
+               if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0)
+                       die("Seek to %" FMT " failed: %s\n", sec->shdr.sh_offset, strerror(errno));
+
+               if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) != sec->shdr.sh_size)
+                       die("Cannot read symbol table: %s\n", strerror(errno));
+
+               for (j = 0; j < sec->shdr.sh_size / sizeof(Elf_Rel); j++) {
+                       Elf_Rel *rel = &sec->reltab[j];
+
+                       rel->r_offset = elf_addr_to_cpu(rel->r_offset);
+                       rel->r_info   = elf_xword_to_cpu(rel->r_info);
+#if (SHT_REL_TYPE == SHT_RELA)
+                       rel->r_addend = elf_xword_to_cpu(rel->r_addend);
+#endif
+               }
+       }
+}
+
+static void add_reloc(struct relocs *r, uint32_t offset)
+{
+       if (r->count == r->size) {
+               unsigned long newsize = r->size + 50000;
+               void *mem = realloc(r->offset, newsize * sizeof(r->offset[0]));
+
+               if (!mem)
+                       die("realloc of %ld entries for relocs failed\n", newsize);
+
+               r->offset = mem;
+               r->size = newsize;
+       }
+       r->offset[r->count++] = offset;
+}
+
+static int do_reloc(struct section *sec, Elf_Rel *rel)
+{
+       unsigned int r_type = ELF64_R_TYPE(rel->r_info);
+       ElfW(Addr) offset = rel->r_offset;
+
+       switch (r_type) {
+       case R_390_NONE:
+       case R_390_PC32:
+       case R_390_PC64:
+       case R_390_PC16DBL:
+       case R_390_PC32DBL:
+       case R_390_PLT32DBL:
+       case R_390_GOTENT:
+       case R_390_GOTPCDBL:
+       case R_390_GOTOFF64:
+               break;
+       case R_390_64:
+               add_reloc(&relocs64, offset);
+               break;
+       default:
+               die("Unsupported relocation type: %d\n", r_type);
+               break;
+       }
+
+       return 0;
+}
+
+static void walk_relocs(void)
+{
+       int i;
+
+       /* Walk through the relocations */
+       for (i = 0; i < shnum; i++) {
+               struct section *sec_applies;
+               int j;
+               struct section *sec = &secs[i];
+
+               if (sec->shdr.sh_type != SHT_REL_TYPE)
+                       continue;
+
+               sec_applies = &secs[sec->shdr.sh_info];
+               if (!(sec_applies->shdr.sh_flags & SHF_ALLOC))
+                       continue;
+
+               for (j = 0; j < sec->shdr.sh_size / sizeof(Elf_Rel); j++) {
+                       Elf_Rel *rel = &sec->reltab[j];
+
+                       do_reloc(sec, rel);
+               }
+       }
+}
+
+static int cmp_relocs(const void *va, const void *vb)
+{
+       const uint32_t *a, *b;
+
+       a = va; b = vb;
+       return (*a == *b) ? 0 : (*a > *b) ? 1 : -1;
+}
+
+static void sort_relocs(struct relocs *r)
+{
+       qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
+}
+
+static int print_reloc(uint32_t v)
+{
+       return fprintf(stdout, "\t.long 0x%08"PRIx32"\n", v) > 0 ? 0 : -1;
+}
+
+static void emit_relocs(void)
+{
+       int i;
+
+       walk_relocs();
+       sort_relocs(&relocs64);
+
+       printf(".section \".vmlinux.relocs_64\",\"a\"\n");
+       for (i = 0; i < relocs64.count; i++)
+               print_reloc(relocs64.offset[i]);
+}
+
+static void process(FILE *fp)
+{
+       read_ehdr(fp);
+       read_shdrs(fp);
+       read_relocs(fp);
+       emit_relocs();
+}
+
+static void usage(void)
+{
+       die("relocs vmlinux\n");
+}
+
+int main(int argc, char **argv)
+{
+       unsigned char e_ident[EI_NIDENT];
+       const char *fname;
+       FILE *fp;
+
+       fname = NULL;
+
+       if (argc != 2)
+               usage();
+
+       fname = argv[1];
+
+       fp = fopen(fname, "r");
+       if (!fp)
+               die("Cannot open %s: %s\n", fname, strerror(errno));
+
+       if (fread(&e_ident, 1, EI_NIDENT, fp) != EI_NIDENT)
+               die("Cannot read %s: %s", fname, strerror(errno));
+
+       rewind(fp);
+
+       process(fp);
+
+       fclose(fp);
+       return 0;
+}
index 62f4b9edcb985a3a1ce1b8c572a5763bccd312c3..f780b467e75d7c38316baf1a1beb8707f1fc6d91 100644 (file)
@@ -9,18 +9,7 @@
 #include <linux/const.h>
 
 /* PAGE_SHIFT determines the page size */
-#if defined(CONFIG_PAGE_SIZE_4KB)
-# define PAGE_SHIFT    12
-#elif defined(CONFIG_PAGE_SIZE_8KB)
-# define PAGE_SHIFT    13
-#elif defined(CONFIG_PAGE_SIZE_16KB)
-# define PAGE_SHIFT    14
-#elif defined(CONFIG_PAGE_SIZE_64KB)
-# define PAGE_SHIFT    16
-#else
-# error "Bogus kernel page size?"
-#endif
-
+#define PAGE_SHIFT     CONFIG_PAGE_SHIFT
 #define PAGE_SIZE      (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 #define PTE_MASK       PAGE_MASK
index 455311d9a5e9c9708753cb1cfac680c5fea5ca03..f32a1963ff0c5693da82fd234ebbc617fd8b27a5 100644 (file)
@@ -4,6 +4,9 @@ menu "Memory management options"
 config MMU
         bool "Support for memory management hardware"
        depends on !CPU_SH2
+       select HAVE_PAGE_SIZE_4KB
+       select HAVE_PAGE_SIZE_8KB if X2TLB
+       select HAVE_PAGE_SIZE_64KB if CPU_SH4
        default y
        help
          Some SH processors (such as SH-2/SH-2A) lack an MMU. In order to
@@ -13,6 +16,15 @@ config MMU
          turning this off will boot the kernel on these machines with the
          MMU implicitly switched off.
 
+config NOMMU
+       def_bool !MMU
+       select HAVE_PAGE_SIZE_4KB
+       select HAVE_PAGE_SIZE_8KB
+       select HAVE_PAGE_SIZE_16KB
+       select HAVE_PAGE_SIZE_64KB
+       help
+         On MMU-less systems, any of these page sizes can be selected
+
 config PAGE_OFFSET
        hex
        default "0x80000000" if MMU
@@ -147,36 +159,6 @@ config HAVE_SRAM_POOL
        bool
        select GENERIC_ALLOCATOR
 
-choice
-       prompt "Kernel page size"
-       default PAGE_SIZE_4KB
-
-config PAGE_SIZE_4KB
-       bool "4kB"
-       help
-         This is the default page size used by all SuperH CPUs.
-
-config PAGE_SIZE_8KB
-       bool "8kB"
-       depends on !MMU || X2TLB
-       help
-         This enables 8kB pages as supported by SH-X2 and later MMUs.
-
-config PAGE_SIZE_16KB
-       bool "16kB"
-       depends on !MMU
-       help
-         This enables 16kB pages on MMU-less SH systems.
-
-config PAGE_SIZE_64KB
-       bool "64kB"
-       depends on !MMU || CPU_SH4
-       help
-         This enables support for 64kB pages, possible on all SH-4
-         CPUs and later.
-
-endchoice
-
 choice
        prompt "HugeTLB page size"
        depends on HUGETLB_PAGE
index 204c43cb3d4356dfe37533701a2fc1f640208381..7e6bc6fff76b101d1b5d59eec7c91998e872280f 100644 (file)
@@ -58,6 +58,7 @@ config SPARC32
        select DMA_DIRECT_REMAP
        select GENERIC_ATOMIC64
        select HAVE_UID16
+       select HAVE_PAGE_SIZE_4KB
        select LOCK_MM_AND_FIND_VMA
        select OLD_SIGACTION
        select ZONE_DMA
@@ -75,6 +76,7 @@ config SPARC64
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE
        select HAVE_DYNAMIC_FTRACE
        select HAVE_FTRACE_MCOUNT_RECORD
+       select HAVE_PAGE_SIZE_8KB
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_CONTEXT_TRACKING_USER
        select HAVE_TIF_NOHZ
index 5f60359361312e4159b45d769c1afe81533ace1b..2a03daa68f2857df85df97b5b632d6154e76496f 100644 (file)
@@ -60,7 +60,7 @@ libs-y                 += arch/sparc/prom/
 libs-y                 += arch/sparc/lib/
 
 drivers-$(CONFIG_PM) += arch/sparc/power/
-drivers-$(CONFIG_FB) += arch/sparc/video/
+drivers-$(CONFIG_FB_CORE) += arch/sparc/video/
 
 boot := arch/sparc/boot
 
index 6be6f683f98f26f63befc79617d27236ab95cb22..9977c77374cd41ef55a7a3965a672fe6aa58bcc5 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <linux/const.h>
 
-#define PAGE_SHIFT   12
+#define PAGE_SHIFT   CONFIG_PAGE_SHIFT
 #define PAGE_SIZE    (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK    (~(PAGE_SIZE-1))
 
index 254dffd85fb147eb3e04b293812ded6df27e6f3a..e9bd24821c93db0f163112b8f4bdbd03b876cf2a 100644 (file)
@@ -4,8 +4,7 @@
 
 #include <linux/const.h>
 
-#define PAGE_SHIFT   13
-
+#define PAGE_SHIFT   CONFIG_PAGE_SHIFT
 #define PAGE_SIZE    (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK    (~(PAGE_SIZE-1))
 
index f3969a3600dbfe4931a18d95da4e2ee8fb53503f..a0cc9bb41a921cb3acd74c50a40f663bc042f2e3 100644 (file)
@@ -1206,10 +1206,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 {
 }
 
-void smp_prepare_boot_cpu(void)
-{
-}
-
 void __init smp_setup_processor_id(void)
 {
        if (tlb_type == spitfire)
index 6baddbd58e4db3fa82c9ba76fd5e0d571a7c4f48..d4d83f1702c61f09e3dceac24c494ecd1632f3e5 100644 (file)
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-obj-$(CONFIG_FB) += fbdev.o
+obj-$(CONFIG_FB_CORE) += fbdev.o
index b5e179360534631deb98b62891b927186b5086fe..93a5a8999b07ee620df45a94824fe587f58058e9 100644 (file)
@@ -20,6 +20,7 @@ config UML
        select HAVE_UID16
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DEBUG_BUGVERBOSE
+       select HAVE_PAGE_SIZE_4KB
        select NO_DMA if !UML_DMA_EMULATION
        select OF_EARLY_FLATTREE if OF
        select GENERIC_IRQ_SHOW
index 92ee2697ff398458c004ce4bc7515abfc0def5d4..63fc062add708cf8e09f5f23185478ef8b85a88a 100644 (file)
@@ -108,8 +108,6 @@ static inline void ubd_set_bit(__u64 bit, unsigned char *data)
 static DEFINE_MUTEX(ubd_lock);
 static DEFINE_MUTEX(ubd_mutex); /* replaces BKL, might not be needed */
 
-static int ubd_open(struct gendisk *disk, blk_mode_t mode);
-static void ubd_release(struct gendisk *disk);
 static int ubd_ioctl(struct block_device *bdev, blk_mode_t mode,
                     unsigned int cmd, unsigned long arg);
 static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
@@ -118,16 +116,11 @@ static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 
 static const struct block_device_operations ubd_blops = {
         .owner         = THIS_MODULE,
-        .open          = ubd_open,
-        .release       = ubd_release,
         .ioctl         = ubd_ioctl,
         .compat_ioctl  = blkdev_compat_ptr_ioctl,
        .getgeo         = ubd_getgeo,
 };
 
-/* Protected by ubd_lock */
-static struct gendisk *ubd_gendisk[MAX_DEV];
-
 #ifdef CONFIG_BLK_DEV_UBD_SYNC
 #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
                                         .cl = 1 })
@@ -155,7 +148,6 @@ struct ubd {
         * backing or the cow file. */
        char *file;
        char *serial;
-       int count;
        int fd;
        __u64 size;
        struct openflags boot_openflags;
@@ -165,7 +157,7 @@ struct ubd {
        unsigned no_trim:1;
        struct cow cow;
        struct platform_device pdev;
-       struct request_queue *queue;
+       struct gendisk *disk;
        struct blk_mq_tag_set tag_set;
        spinlock_t lock;
 };
@@ -181,7 +173,6 @@ struct ubd {
 #define DEFAULT_UBD { \
        .file =                 NULL, \
        .serial =               NULL, \
-       .count =                0, \
        .fd =                   -1, \
        .size =                 -1, \
        .boot_openflags =       OPEN_FLAGS, \
@@ -774,8 +765,6 @@ static int ubd_open_dev(struct ubd *ubd_dev)
        ubd_dev->fd = fd;
 
        if(ubd_dev->cow.file != NULL){
-               blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long));
-
                err = -ENOMEM;
                ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len);
                if(ubd_dev->cow.bitmap == NULL){
@@ -797,11 +786,6 @@ static int ubd_open_dev(struct ubd *ubd_dev)
                if(err < 0) goto error;
                ubd_dev->cow.fd = err;
        }
-       if (ubd_dev->no_trim == 0) {
-               blk_queue_max_discard_sectors(ubd_dev->queue, UBD_MAX_REQUEST);
-               blk_queue_max_write_zeroes_sectors(ubd_dev->queue, UBD_MAX_REQUEST);
-       }
-       blk_queue_flag_set(QUEUE_FLAG_NONROT, ubd_dev->queue);
        return 0;
  error:
        os_close_file(ubd_dev->fd);
@@ -851,27 +835,6 @@ static const struct attribute_group *ubd_attr_groups[] = {
        NULL,
 };
 
-static int ubd_disk_register(int major, u64 size, int unit,
-                            struct gendisk *disk)
-{
-       disk->major = major;
-       disk->first_minor = unit << UBD_SHIFT;
-       disk->minors = 1 << UBD_SHIFT;
-       disk->fops = &ubd_blops;
-       set_capacity(disk, size / 512);
-       sprintf(disk->disk_name, "ubd%c", 'a' + unit);
-
-       ubd_devs[unit].pdev.id   = unit;
-       ubd_devs[unit].pdev.name = DRIVER_NAME;
-       ubd_devs[unit].pdev.dev.release = ubd_device_release;
-       dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
-       platform_device_register(&ubd_devs[unit].pdev);
-
-       disk->private_data = &ubd_devs[unit];
-       disk->queue = ubd_devs[unit].queue;
-       return device_add_disk(&ubd_devs[unit].pdev.dev, disk, ubd_attr_groups);
-}
-
 #define ROUND_BLOCK(n) ((n + (SECTOR_SIZE - 1)) & (-SECTOR_SIZE))
 
 static const struct blk_mq_ops ubd_mq_ops = {
@@ -881,18 +844,36 @@ static const struct blk_mq_ops ubd_mq_ops = {
 static int ubd_add(int n, char **error_out)
 {
        struct ubd *ubd_dev = &ubd_devs[n];
+       struct queue_limits lim = {
+               .max_segments           = MAX_SG,
+               .seg_boundary_mask      = PAGE_SIZE - 1,
+       };
        struct gendisk *disk;
        int err = 0;
 
        if(ubd_dev->file == NULL)
                goto out;
 
+       if (ubd_dev->cow.file)
+               lim.max_hw_sectors = 8 * sizeof(long);
+       if (!ubd_dev->no_trim) {
+               lim.max_hw_discard_sectors = UBD_MAX_REQUEST;
+               lim.max_write_zeroes_sectors = UBD_MAX_REQUEST;
+       }
+
        err = ubd_file_size(ubd_dev, &ubd_dev->size);
        if(err < 0){
                *error_out = "Couldn't determine size of device's file";
                goto out;
        }
 
+       err = ubd_open_dev(ubd_dev);
+       if (err) {
+               pr_err("ubd%c: Can't open \"%s\": errno = %d\n",
+                       'a' + n, ubd_dev->file, -err);
+               goto out;
+       }
+
        ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
 
        ubd_dev->tag_set.ops = &ubd_mq_ops;
@@ -904,29 +885,43 @@ static int ubd_add(int n, char **error_out)
 
        err = blk_mq_alloc_tag_set(&ubd_dev->tag_set);
        if (err)
-               goto out;
+               goto out_close;
 
-       disk = blk_mq_alloc_disk(&ubd_dev->tag_set, ubd_dev);
+       disk = blk_mq_alloc_disk(&ubd_dev->tag_set, &lim, ubd_dev);
        if (IS_ERR(disk)) {
                err = PTR_ERR(disk);
                goto out_cleanup_tags;
        }
-       ubd_dev->queue = disk->queue;
 
-       blk_queue_write_cache(ubd_dev->queue, true, false);
-       blk_queue_max_segments(ubd_dev->queue, MAX_SG);
-       blk_queue_segment_boundary(ubd_dev->queue, PAGE_SIZE - 1);
-       err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, disk);
+       blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue);
+       blk_queue_write_cache(disk->queue, true, false);
+       disk->major = UBD_MAJOR;
+       disk->first_minor = n << UBD_SHIFT;
+       disk->minors = 1 << UBD_SHIFT;
+       disk->fops = &ubd_blops;
+       set_capacity(disk, ubd_dev->size / 512);
+       sprintf(disk->disk_name, "ubd%c", 'a' + n);
+       disk->private_data = ubd_dev;
+       set_disk_ro(disk, !ubd_dev->openflags.w);
+
+       ubd_dev->pdev.id = n;
+       ubd_dev->pdev.name = DRIVER_NAME;
+       ubd_dev->pdev.dev.release = ubd_device_release;
+       dev_set_drvdata(&ubd_dev->pdev.dev, ubd_dev);
+       platform_device_register(&ubd_dev->pdev);
+
+       err = device_add_disk(&ubd_dev->pdev.dev, disk, ubd_attr_groups);
        if (err)
                goto out_cleanup_disk;
 
-       ubd_gendisk[n] = disk;
        return 0;
 
 out_cleanup_disk:
        put_disk(disk);
 out_cleanup_tags:
        blk_mq_free_tag_set(&ubd_dev->tag_set);
+out_close:
+       ubd_close_dev(ubd_dev);
 out:
        return err;
 }
@@ -1012,7 +1007,6 @@ static int ubd_id(char **str, int *start_out, int *end_out)
 
 static int ubd_remove(int n, char **error_out)
 {
-       struct gendisk *disk = ubd_gendisk[n];
        struct ubd *ubd_dev;
        int err = -ENODEV;
 
@@ -1023,15 +1017,15 @@ static int ubd_remove(int n, char **error_out)
        if(ubd_dev->file == NULL)
                goto out;
 
-       /* you cannot remove a open disk */
-       err = -EBUSY;
-       if(ubd_dev->count > 0)
-               goto out;
+       if (ubd_dev->disk) {
+               /* you cannot remove a open disk */
+               err = -EBUSY;
+               if (disk_openers(ubd_dev->disk))
+                       goto out;
 
-       ubd_gendisk[n] = NULL;
-       if(disk != NULL){
-               del_gendisk(disk);
-               put_disk(disk);
+               del_gendisk(ubd_dev->disk);
+               ubd_close_dev(ubd_dev);
+               put_disk(ubd_dev->disk);
        }
 
        err = 0;
@@ -1153,37 +1147,6 @@ static int __init ubd_driver_init(void){
 
 device_initcall(ubd_driver_init);
 
-static int ubd_open(struct gendisk *disk, blk_mode_t mode)
-{
-       struct ubd *ubd_dev = disk->private_data;
-       int err = 0;
-
-       mutex_lock(&ubd_mutex);
-       if(ubd_dev->count == 0){
-               err = ubd_open_dev(ubd_dev);
-               if(err){
-                       printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
-                              disk->disk_name, ubd_dev->file, -err);
-                       goto out;
-               }
-       }
-       ubd_dev->count++;
-       set_disk_ro(disk, !ubd_dev->openflags.w);
-out:
-       mutex_unlock(&ubd_mutex);
-       return err;
-}
-
-static void ubd_release(struct gendisk *disk)
-{
-       struct ubd *ubd_dev = disk->private_data;
-
-       mutex_lock(&ubd_mutex);
-       if(--ubd_dev->count == 0)
-               ubd_close_dev(ubd_dev);
-       mutex_unlock(&ubd_mutex);
-}
-
 static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
                          __u64 *cow_offset, unsigned long *bitmap,
                          __u64 bitmap_offset, unsigned long *bitmap_words,
index 84866127d0747d03673bef416c699ad3fdad9599..9ef9a8aedfa661d9a8ca0e63102736c0c1e259b2 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/const.h>
 
 /* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT     12
+#define PAGE_SHIFT     CONFIG_PAGE_SHIFT
 #define PAGE_SIZE      (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
index 5a83da703e8766199f3123f0c915f8743a5e1847..6a1f36df6a181761d805d99279539874095f096a 100644 (file)
@@ -28,5 +28,7 @@ obj-y += net/
 
 obj-$(CONFIG_KEXEC_FILE) += purgatory/
 
+obj-y += virt/svm/
+
 # for cleaning
 subdir- += boot tools
index 5edec175b9bfc92dfac8832fc3600b843407828b..6290a040effaea4bd11b80af573636a38baf0ed8 100644 (file)
@@ -147,6 +147,7 @@ config X86
        select EDAC_ATOMIC_SCRUB
        select EDAC_SUPPORT
        select GENERIC_CLOCKEVENTS_BROADCAST    if X86_64 || (X86_32 && X86_LOCAL_APIC)
+       select GENERIC_CLOCKEVENTS_BROADCAST_IDLE       if GENERIC_CLOCKEVENTS_BROADCAST
        select GENERIC_CLOCKEVENTS_MIN_ADJUST
        select GENERIC_CMOS_UPDATE
        select GENERIC_CPU_AUTOPROBE
@@ -255,6 +256,7 @@ config X86
        select HAVE_NOINSTR_VALIDATION          if HAVE_OBJTOOL
        select HAVE_OBJTOOL                     if X86_64
        select HAVE_OPTPROBES
+       select HAVE_PAGE_SIZE_4KB
        select HAVE_PCSPKR_PLATFORM
        select HAVE_PERF_EVENTS
        select HAVE_PERF_EVENTS_NMI
@@ -496,6 +498,15 @@ config X86_CPU_RESCTRL
 
          Say N if unsure.
 
+config X86_FRED
+       bool "Flexible Return and Event Delivery"
+       depends on X86_64
+       help
+         When enabled, try to use Flexible Return and Event Delivery
+         instead of the legacy SYSCALL/SYSENTER/IDT architecture for
+         ring transitions and exception/interrupt handling if the
+         system supports.
+
 if X86_32
 config X86_BIGSMP
        bool "Support for big SMP systems with more than 8 CPUs"
@@ -1539,19 +1550,6 @@ config AMD_MEM_ENCRYPT
          This requires an AMD processor that supports Secure Memory
          Encryption (SME).
 
-config AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT
-       bool "Activate AMD Secure Memory Encryption (SME) by default"
-       depends on AMD_MEM_ENCRYPT
-       help
-         Say yes to have system memory encrypted by default if running on
-         an AMD processor that supports Secure Memory Encryption (SME).
-
-         If set to Y, then the encryption of system memory can be
-         deactivated with the mem_encrypt=off command line option.
-
-         If set to N, then the encryption of system memory can be
-         activated with the mem_encrypt=on command line option.
-
 # Common NUMA Features
 config NUMA
        bool "NUMA Memory Allocation and Scheduler Support"
@@ -2114,11 +2112,11 @@ config PHYSICAL_START
        help
          This gives the physical address where the kernel is loaded.
 
-         If kernel is a not relocatable (CONFIG_RELOCATABLE=n) then
-         bzImage will decompress itself to above physical address and
-         run from there. Otherwise, bzImage will run from the address where
-         it has been loaded by the boot loader and will ignore above physical
-         address.
+         If the kernel is not relocatable (CONFIG_RELOCATABLE=n) then bzImage
+         will decompress itself to above physical address and run from there.
+         Otherwise, bzImage will run from the address where it has been loaded
+         by the boot loader. The only exception is if it is loaded below the
+         above physical address, in which case it will relocate itself there.
 
          In normal kdump cases one does not have to set/change this option
          as now bzImage can be compiled as a completely relocatable image
@@ -2434,6 +2432,18 @@ source "kernel/livepatch/Kconfig"
 
 endmenu
 
+config CC_HAS_NAMED_AS
+       def_bool CC_IS_GCC && GCC_VERSION >= 120100
+
+config USE_X86_SEG_SUPPORT
+       def_bool y
+       depends on CC_HAS_NAMED_AS
+       #
+       # -fsanitize=kernel-address (KASAN) is at the moment incompatible
+       # with named address spaces - see GCC PR sanitizer/111736.
+       #
+       depends on !KASAN
+
 config CC_HAS_SLS
        def_bool $(cc-option,-mharden-sls=all)
 
@@ -2465,12 +2475,12 @@ config CALL_PADDING
 
 config FINEIBT
        def_bool y
-       depends on X86_KERNEL_IBT && CFI_CLANG && RETPOLINE
+       depends on X86_KERNEL_IBT && CFI_CLANG && MITIGATION_RETPOLINE
        select CALL_PADDING
 
 config HAVE_CALL_THUNKS
        def_bool y
-       depends on CC_HAS_ENTRY_PADDING && RETHUNK && OBJTOOL
+       depends on CC_HAS_ENTRY_PADDING && MITIGATION_RETHUNK && OBJTOOL
 
 config CALL_THUNKS
        def_bool n
@@ -2492,7 +2502,7 @@ menuconfig SPECULATION_MITIGATIONS
 
 if SPECULATION_MITIGATIONS
 
-config PAGE_TABLE_ISOLATION
+config MITIGATION_PAGE_TABLE_ISOLATION
        bool "Remove the kernel mapping in user mode"
        default y
        depends on (X86_64 || X86_PAE)
@@ -2503,7 +2513,7 @@ config PAGE_TABLE_ISOLATION
 
          See Documentation/arch/x86/pti.rst for more details.
 
-config RETPOLINE
+config MITIGATION_RETPOLINE
        bool "Avoid speculative indirect branches in kernel"
        select OBJTOOL if HAVE_OBJTOOL
        default y
@@ -2513,9 +2523,9 @@ config RETPOLINE
          branches. Requires a compiler with -mindirect-branch=thunk-extern
          support for full protection. The kernel may run slower.
 
-config RETHUNK
+config MITIGATION_RETHUNK
        bool "Enable return-thunks"
-       depends on RETPOLINE && CC_HAS_RETURN_THUNK
+       depends on MITIGATION_RETPOLINE && CC_HAS_RETURN_THUNK
        select OBJTOOL if HAVE_OBJTOOL
        default y if X86_64
        help
@@ -2524,14 +2534,14 @@ config RETHUNK
          Requires a compiler with -mfunction-return=thunk-extern
          support for full protection. The kernel may run slower.
 
-config CPU_UNRET_ENTRY
+config MITIGATION_UNRET_ENTRY
        bool "Enable UNRET on kernel entry"
-       depends on CPU_SUP_AMD && RETHUNK && X86_64
+       depends on CPU_SUP_AMD && MITIGATION_RETHUNK && X86_64
        default y
        help
          Compile the kernel with support for the retbleed=unret mitigation.
 
-config CALL_DEPTH_TRACKING
+config MITIGATION_CALL_DEPTH_TRACKING
        bool "Mitigate RSB underflow with call depth tracking"
        depends on CPU_SUP_INTEL && HAVE_CALL_THUNKS
        select HAVE_DYNAMIC_FTRACE_NO_PATCHABLE
@@ -2551,7 +2561,7 @@ config CALL_DEPTH_TRACKING
 
 config CALL_THUNKS_DEBUG
        bool "Enable call thunks and call depth tracking debugging"
-       depends on CALL_DEPTH_TRACKING
+       depends on MITIGATION_CALL_DEPTH_TRACKING
        select FUNCTION_ALIGNMENT_32B
        default n
        help
@@ -2562,14 +2572,14 @@ config CALL_THUNKS_DEBUG
          Only enable this when you are debugging call thunks as this
          creates a noticeable runtime overhead. If unsure say N.
 
-config CPU_IBPB_ENTRY
+config MITIGATION_IBPB_ENTRY
        bool "Enable IBPB on kernel entry"
        depends on CPU_SUP_AMD && X86_64
        default y
        help
          Compile the kernel with support for the retbleed=ibpb mitigation.
 
-config CPU_IBRS_ENTRY
+config MITIGATION_IBRS_ENTRY
        bool "Enable IBRS on kernel entry"
        depends on CPU_SUP_INTEL && X86_64
        default y
@@ -2578,14 +2588,14 @@ config CPU_IBRS_ENTRY
          This mitigates both spectre_v2 and retbleed at great cost to
          performance.
 
-config CPU_SRSO
+config MITIGATION_SRSO
        bool "Mitigate speculative RAS overflow on AMD"
-       depends on CPU_SUP_AMD && X86_64 && RETHUNK
+       depends on CPU_SUP_AMD && X86_64 && MITIGATION_RETHUNK
        default y
        help
          Enable the SRSO mitigation needed on AMD Zen1-4 machines.
 
-config SLS
+config MITIGATION_SLS
        bool "Mitigate Straight-Line-Speculation"
        depends on CC_HAS_SLS && X86_64
        select OBJTOOL if HAVE_OBJTOOL
@@ -2595,7 +2605,7 @@ config SLS
          against straight line speculation. The kernel image might be slightly
          larger.
 
-config GDS_FORCE_MITIGATION
+config MITIGATION_GDS_FORCE
        bool "Force GDS Mitigation"
        depends on CPU_SUP_INTEL
        default n
@@ -2614,6 +2624,17 @@ config GDS_FORCE_MITIGATION
 
          If in doubt, say N.
 
+config MITIGATION_RFDS
+       bool "RFDS Mitigation"
+       depends on CPU_SUP_INTEL
+       default y
+       help
+         Enable mitigation for Register File Data Sampling (RFDS) by default.
+         RFDS is a hardware vulnerability which affects Intel Atom CPUs. It
+         allows unprivileged speculative access to stale data previously
+         stored in floating point, vector and integer registers.
+         See also <file:Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst>
+
 endif
 
 config ARCH_HAS_ADD_PAGES
index 2264db14a25d3b034ffa93685d6353564d4a9225..1eccc2ee45fb7d4a7ad8f07b410339f3decbde13 100644 (file)
@@ -22,7 +22,7 @@ RETPOLINE_VDSO_CFLAGS := -mretpoline
 endif
 RETPOLINE_CFLAGS       += $(call cc-option,-mindirect-branch-cs-prefix)
 
-ifdef CONFIG_RETHUNK
+ifdef CONFIG_MITIGATION_RETHUNK
 RETHUNK_CFLAGS         := -mfunction-return=thunk-extern
 RETPOLINE_CFLAGS       += $(RETHUNK_CFLAGS)
 endif
@@ -53,6 +53,9 @@ REALMODE_CFLAGS += -fno-stack-protector
 REALMODE_CFLAGS += -Wno-address-of-packed-member
 REALMODE_CFLAGS += $(cc_stack_align4)
 REALMODE_CFLAGS += $(CLANG_FLAGS)
+ifdef CONFIG_CC_IS_CLANG
+REALMODE_CFLAGS += -Wno-gnu
+endif
 export REALMODE_CFLAGS
 
 # BITS is used as extension for files which are available in a 32 bit
@@ -112,13 +115,13 @@ ifeq ($(CONFIG_X86_32),y)
         # temporary until string.h is fixed
         KBUILD_CFLAGS += -ffreestanding
 
-        ifeq ($(CONFIG_STACKPROTECTOR),y)
-                ifeq ($(CONFIG_SMP),y)
+    ifeq ($(CONFIG_STACKPROTECTOR),y)
+        ifeq ($(CONFIG_SMP),y)
                        KBUILD_CFLAGS += -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard
-                else
+        else
                        KBUILD_CFLAGS += -mstack-protector-guard=global
-                endif
         endif
+    endif
 else
         BITS := 64
         UTS_MACHINE := x86_64
@@ -192,7 +195,7 @@ KBUILD_CFLAGS += -Wno-sign-compare
 KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
 
 # Avoid indirect branches in kernel to deal with Spectre
-ifdef CONFIG_RETPOLINE
+ifdef CONFIG_MITIGATION_RETPOLINE
   KBUILD_CFLAGS += $(RETPOLINE_CFLAGS)
   # Additionally, avoid generating expensive indirect jumps which
   # are subject to retpolines for small number of switch cases.
@@ -205,7 +208,7 @@ ifdef CONFIG_RETPOLINE
   endif
 endif
 
-ifdef CONFIG_SLS
+ifdef CONFIG_MITIGATION_SLS
   KBUILD_CFLAGS += -mharden-sls=all
 endif
 
@@ -296,12 +299,11 @@ install:
 
 vdso-install-$(CONFIG_X86_64)          += arch/x86/entry/vdso/vdso64.so.dbg
 vdso-install-$(CONFIG_X86_X32_ABI)     += arch/x86/entry/vdso/vdsox32.so.dbg
-vdso-install-$(CONFIG_X86_32)          += arch/x86/entry/vdso/vdso32.so.dbg
-vdso-install-$(CONFIG_IA32_EMULATION)  += arch/x86/entry/vdso/vdso32.so.dbg
+vdso-install-$(CONFIG_COMPAT_32)       += arch/x86/entry/vdso/vdso32.so.dbg
 
 archprepare: checkbin
 checkbin:
-ifdef CONFIG_RETPOLINE
+ifdef CONFIG_MITIGATION_RETPOLINE
 ifeq ($(RETPOLINE_CFLAGS),)
        @echo "You are building kernel with non-retpoline compiler." >&2
        @echo "Please update your compiler." >&2
index 18d15d1ce87d5993946c31579b006594e9c4e9da..f196b1d1ddf867b62161cb0528872526c82a693f 100644 (file)
@@ -5,6 +5,8 @@
 #include "../string.h"
 #include "efi.h"
 
+#include <asm/bootparam.h>
+
 #include <linux/numa.h>
 
 /*
index c1bb180973ea2a74eaf7b1788faeeba366643daa..e162d7f59cc5bdabfc129f68cb9e4ac79a29bb1e 100644 (file)
@@ -1,6 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "misc.h"
 
+#include <asm/bootparam.h>
+
 static unsigned long fs;
 static inline void set_fs(unsigned long seg)
 {
index 6edd034b0b30cb2df90937e06d30e125cf88268f..f2e50f9758e6cccebc1f380e6e1ee6e6c484e2a4 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "misc.h"
 
+#include <asm/bootparam.h>
+
 /**
  * efi_get_type - Given a pointer to boot_params, determine the type of EFI environment.
  *
index 866c0af8b5b9e2a6ae8b7de0a28e3c77f47f933d..b22300970f97daf8cf051a337c1ae96f6ebd3488 100644 (file)
@@ -97,15 +97,6 @@ typedef struct {
        u32 tables;
 } efi_system_table_32_t;
 
-/* kexec external ABI */
-struct efi_setup_data {
-       u64 fw_vendor;
-       u64 __unused;
-       u64 tables;
-       u64 smbios;
-       u64 reserved[8];
-};
-
 struct efi_unaccepted_memory {
        u32 version;
        u32 unit_size;
index d040080d7edbd6ba53b9556102ac732a4f90e8e3..909f2a35b60c5da423868732ee9b2c3aa2e45ccd 100644 (file)
@@ -8,8 +8,8 @@
  * Copyright (C)      2016  Kees Cook
  */
 
-/* No PAGE_TABLE_ISOLATION support needed either: */
-#undef CONFIG_PAGE_TABLE_ISOLATION
+/* No MITIGATION_PAGE_TABLE_ISOLATION support needed either: */
+#undef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 
 #include "error.h"
 #include "misc.h"
@@ -389,5 +389,5 @@ void do_boot_page_fault(struct pt_regs *regs, unsigned long error_code)
 
 void do_boot_nmi_trap(struct pt_regs *regs, unsigned long error_code)
 {
-       /* Empty handler to ignore NMI during early boot */
+       spurious_nmi_count++;
 }
index b99e08e6815b1a84ecb016fc53c18d5490e8a96d..408507e305be6142063344db327fefb65797deee 100644 (file)
@@ -52,6 +52,7 @@ struct port_io_ops pio_ops;
 
 memptr free_mem_ptr;
 memptr free_mem_end_ptr;
+int spurious_nmi_count;
 
 static char *vidmem;
 static int vidport;
@@ -164,21 +165,34 @@ void __putstr(const char *s)
        outb(0xff & (pos >> 1), vidport+1);
 }
 
-void __puthex(unsigned long value)
+static noinline void __putnum(unsigned long value, unsigned int base,
+                             int mindig)
 {
-       char alpha[2] = "0";
-       int bits;
+       char buf[8*sizeof(value)+1];
+       char *p;
 
-       for (bits = sizeof(value) * 8 - 4; bits >= 0; bits -= 4) {
-               unsigned long digit = (value >> bits) & 0xf;
+       p = buf + sizeof(buf);
+       *--p = '\0';
 
-               if (digit < 0xA)
-                       alpha[0] = '0' + digit;
-               else
-                       alpha[0] = 'a' + (digit - 0xA);
+       while (mindig-- > 0 || value) {
+               unsigned char digit = value % base;
+               digit += (digit >= 10) ? ('a'-10) : '0';
+               *--p = digit;
 
-               __putstr(alpha);
+               value /= base;
        }
+
+       __putstr(p);
+}
+
+void __puthex(unsigned long value)
+{
+       __putnum(value, 16, sizeof(value)*2);
+}
+
+void __putdec(unsigned long value)
+{
+       __putnum(value, 10, 1);
 }
 
 #ifdef CONFIG_X86_NEED_RELOCS
@@ -357,6 +371,19 @@ unsigned long decompress_kernel(unsigned char *outbuf, unsigned long virt_addr,
        return entry;
 }
 
+/*
+ * Set the memory encryption xloadflag based on the mem_encrypt= command line
+ * parameter, if provided.
+ */
+static void parse_mem_encrypt(struct setup_header *hdr)
+{
+       int on = cmdline_find_option_bool("mem_encrypt=on");
+       int off = cmdline_find_option_bool("mem_encrypt=off");
+
+       if (on > off)
+               hdr->xloadflags |= XLF_MEM_ENCRYPTION;
+}
+
 /*
  * The compressed kernel image (ZO), has been moved so that its position
  * is against the end of the buffer used to hold the uncompressed kernel
@@ -387,6 +414,8 @@ asmlinkage __visible void *extract_kernel(void *rmode, unsigned char *output)
        /* Clear flags intended for solely in-kernel use. */
        boot_params_ptr->hdr.loadflags &= ~KASLR_FLAG;
 
+       parse_mem_encrypt(&boot_params_ptr->hdr);
+
        sanitize_boot_params(boot_params_ptr);
 
        if (boot_params_ptr->screen_info.orig_video_mode == 7) {
@@ -493,6 +522,12 @@ asmlinkage __visible void *extract_kernel(void *rmode, unsigned char *output)
        /* Disable exception handling before booting the kernel */
        cleanup_exception_handling();
 
+       if (spurious_nmi_count) {
+               error_putstr("Spurious early NMIs ignored: ");
+               error_putdec(spurious_nmi_count);
+               error_putstr("\n");
+       }
+
        return output + entry_offset;
 }
 
index bc2f0f17fb90ec35f6e694ad38971e02a80c5fae..b353a7be380cb83608cd24067e418d7e7934d1a8 100644 (file)
@@ -59,12 +59,15 @@ extern char _head[], _end[];
 /* misc.c */
 extern memptr free_mem_ptr;
 extern memptr free_mem_end_ptr;
+extern int spurious_nmi_count;
 void *malloc(int size);
 void free(void *where);
 void __putstr(const char *s);
 void __puthex(unsigned long value);
+void __putdec(unsigned long value);
 #define error_putstr(__x)  __putstr(__x)
 #define error_puthex(__x)  __puthex(__x)
+#define error_putdec(__x)  __putdec(__x)
 
 #ifdef CONFIG_X86_VERBOSE_BOOTUP
 
index 51f957b24ba7a2babdd7c89d3b6cf0b070519691..c882e1f67af01c50a20bfe00a32138dc771ee88c 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "misc.h"
+#include <asm/bootparam.h>
 #include <asm/e820/types.h>
 #include <asm/processor.h>
 #include "pgtable.h"
index 454acd7a2dafff2a0d16cc2a0ddd61745b3fcf36..ec71846d28c9ed1230fc910954974aca73e51fcf 100644 (file)
@@ -12,6 +12,7 @@
  */
 #include "misc.h"
 
+#include <asm/bootparam.h>
 #include <asm/pgtable_types.h>
 #include <asm/sev.h>
 #include <asm/trapnr.h>
@@ -116,6 +117,9 @@ static bool fault_in_kernel_space(unsigned long address)
 #undef __init
 #define __init
 
+#undef __head
+#define __head
+
 #define __BOOT_COMPRESSED
 
 /* Basic instruction decoding support needed */
@@ -304,6 +308,10 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)
        if (result != ES_OK)
                goto finish;
 
+       result = vc_check_opcode_bytes(&ctxt, exit_code);
+       if (result != ES_OK)
+               goto finish;
+
        switch (exit_code) {
        case SVM_EXIT_RDTSC:
        case SVM_EXIT_RDTSCP:
@@ -365,7 +373,7 @@ static void enforce_vmpl0(void)
                                 MSR_AMD64_SNP_VMPL_SSS |               \
                                 MSR_AMD64_SNP_SECURE_TSC |             \
                                 MSR_AMD64_SNP_VMGEXIT_PARAM |          \
-                                MSR_AMD64_SNP_VMSA_REG_PROTECTION |    \
+                                MSR_AMD64_SNP_VMSA_REG_PROT |          \
                                 MSR_AMD64_SNP_RESERVED_BIT13 |         \
                                 MSR_AMD64_SNP_RESERVED_BIT15 |         \
                                 MSR_AMD64_SNP_RESERVED_MASK)
index a1bbedd989e42ed5f9e433f556613613094ae74d..b5c79f43359bcde2c4c3c5ed796e8780f7979774 100644 (file)
@@ -111,11 +111,7 @@ extra_header_fields:
        .long   salign                          # SizeOfHeaders
        .long   0                               # CheckSum
        .word   IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application)
-#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES
        .word   IMAGE_DLL_CHARACTERISTICS_NX_COMPAT     # DllCharacteristics
-#else
-       .word   0                               # DllCharacteristics
-#endif
 #ifdef CONFIG_X86_32
        .long   0                               # SizeOfStackReserve
        .long   0                               # SizeOfStackCommit
index eeec9986570ed05a5a0d686898139e26fcf0f228..d07be9d05cd03781072798e5802a5ef34d7a057a 100644 (file)
@@ -14,7 +14,7 @@
 #include <asm/processor.h>
 
 enum cc_vendor cc_vendor __ro_after_init = CC_VENDOR_NONE;
-static u64 cc_mask __ro_after_init;
+u64 cc_mask __ro_after_init;
 
 static bool noinstr intel_cc_platform_has(enum cc_attr attr)
 {
@@ -148,8 +148,3 @@ u64 cc_mkdec(u64 val)
        }
 }
 EXPORT_SYMBOL_GPL(cc_mkdec);
-
-__init void cc_set_mask(u64 mask)
-{
-       cc_mask = mask;
-}
index 73abbbdd26f87d73ea85b962f686ef178f06bad3..91801138b10bbffa44d6702dbcecdab5275fd034 100644 (file)
@@ -42,7 +42,7 @@ CONFIG_EFI_STUB=y
 CONFIG_HZ_1000=y
 CONFIG_KEXEC=y
 CONFIG_CRASH_DUMP=y
-# CONFIG_RETHUNK is not set
+# CONFIG_MITIGATION_RETHUNK is not set
 CONFIG_HIBERNATION=y
 CONFIG_PM_DEBUG=y
 CONFIG_PM_TRACE_RTC=y
index ca2fe186994b0a653a525583e18b90b0715f3fa7..c93e7f5c2a065233a04637702d5df401553ed6cc 100644 (file)
@@ -18,6 +18,9 @@ obj-y                         += vdso/
 obj-y                          += vsyscall/
 
 obj-$(CONFIG_PREEMPTION)       += thunk_$(BITS).o
+CFLAGS_entry_fred.o            += -fno-stack-protector
+CFLAGS_REMOVE_entry_fred.o     += -pg $(CC_FLAGS_FTRACE)
+obj-$(CONFIG_X86_FRED)         += entry_64_fred.o entry_fred.o
+
 obj-$(CONFIG_IA32_EMULATION)   += entry_64_compat.o syscall_32.o
 obj-$(CONFIG_X86_X32_ABI)      += syscall_x32.o
-
index 9f1d94790a54912cc431e9e39fc0a4a7e6069398..ea81770629eea62532f8f6429bc08cf6e3be7949 100644 (file)
@@ -65,7 +65,7 @@ For 32-bit we have the following conventions - kernel is built with
  * for assembly code:
  */
 
-.macro PUSH_REGS rdx=%rdx rcx=%rcx rax=%rax save_ret=0
+.macro PUSH_REGS rdx=%rdx rcx=%rcx rax=%rax save_ret=0 unwind_hint=1
        .if \save_ret
        pushq   %rsi            /* pt_regs->si */
        movq    8(%rsp), %rsi   /* temporarily store the return address in %rsi */
@@ -87,14 +87,17 @@ For 32-bit we have the following conventions - kernel is built with
        pushq   %r13            /* pt_regs->r13 */
        pushq   %r14            /* pt_regs->r14 */
        pushq   %r15            /* pt_regs->r15 */
+
+       .if \unwind_hint
        UNWIND_HINT_REGS
+       .endif
 
        .if \save_ret
        pushq   %rsi            /* return address on top of stack */
        .endif
 .endm
 
-.macro CLEAR_REGS
+.macro CLEAR_REGS clear_bp=1
        /*
         * Sanitize registers of values that a speculation attack might
         * otherwise want to exploit. The lower registers are likely clobbered
@@ -109,7 +112,9 @@ For 32-bit we have the following conventions - kernel is built with
        xorl    %r10d, %r10d    /* nospec r10 */
        xorl    %r11d, %r11d    /* nospec r11 */
        xorl    %ebx,  %ebx     /* nospec rbx */
+       .if \clear_bp
        xorl    %ebp,  %ebp     /* nospec rbp */
+       .endif
        xorl    %r12d, %r12d    /* nospec r12 */
        xorl    %r13d, %r13d    /* nospec r13 */
        xorl    %r14d, %r14d    /* nospec r14 */
@@ -117,9 +122,9 @@ For 32-bit we have the following conventions - kernel is built with
 
 .endm
 
-.macro PUSH_AND_CLEAR_REGS rdx=%rdx rcx=%rcx rax=%rax save_ret=0
-       PUSH_REGS rdx=\rdx, rcx=\rcx, rax=\rax, save_ret=\save_ret
-       CLEAR_REGS
+.macro PUSH_AND_CLEAR_REGS rdx=%rdx rcx=%rcx rax=%rax save_ret=0 clear_bp=1 unwind_hint=1
+       PUSH_REGS rdx=\rdx, rcx=\rcx, rax=\rax, save_ret=\save_ret unwind_hint=\unwind_hint
+       CLEAR_REGS clear_bp=\clear_bp
 .endm
 
 .macro POP_REGS pop_rdi=1
@@ -142,10 +147,10 @@ For 32-bit we have the following conventions - kernel is built with
        .endif
 .endm
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 
 /*
- * PAGE_TABLE_ISOLATION PGDs are 8k.  Flip bit 12 to switch between the two
+ * MITIGATION_PAGE_TABLE_ISOLATION PGDs are 8k.  Flip bit 12 to switch between the two
  * halves:
  */
 #define PTI_USER_PGTABLE_BIT           PAGE_SHIFT
@@ -160,7 +165,7 @@ For 32-bit we have the following conventions - kernel is built with
 
 .macro ADJUST_KERNEL_CR3 reg:req
        ALTERNATIVE "", "SET_NOFLUSH_BIT \reg", X86_FEATURE_PCID
-       /* Clear PCID and "PAGE_TABLE_ISOLATION bit", point CR3 at kernel pagetables: */
+       /* Clear PCID and "MITIGATION_PAGE_TABLE_ISOLATION bit", point CR3 at kernel pagetables: */
        andq    $(~PTI_USER_PGTABLE_AND_PCID_MASK), \reg
 .endm
 
@@ -173,7 +178,7 @@ For 32-bit we have the following conventions - kernel is built with
 .endm
 
 #define THIS_CPU_user_pcid_flush_mask   \
-       PER_CPU_VAR(cpu_tlbstate) + TLB_STATE_user_pcid_flush_mask
+       PER_CPU_VAR(cpu_tlbstate + TLB_STATE_user_pcid_flush_mask)
 
 .macro SWITCH_TO_USER_CR3 scratch_reg:req scratch_reg2:req
        mov     %cr3, \scratch_reg
@@ -239,17 +244,19 @@ For 32-bit we have the following conventions - kernel is built with
 .Ldone_\@:
 .endm
 
-.macro RESTORE_CR3 scratch_reg:req save_reg:req
+/* Restore CR3 from a kernel context. May restore a user CR3 value. */
+.macro PARANOID_RESTORE_CR3 scratch_reg:req save_reg:req
        ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI
 
-       ALTERNATIVE "jmp .Lwrcr3_\@", "", X86_FEATURE_PCID
-
        /*
-        * KERNEL pages can always resume with NOFLUSH as we do
-        * explicit flushes.
+        * If CR3 contained the kernel page tables at the paranoid exception
+        * entry, then there is nothing to restore as CR3 is not modified while
+        * handling the exception.
         */
        bt      $PTI_USER_PGTABLE_BIT, \save_reg
-       jnc     .Lnoflush_\@
+       jnc     .Lend_\@
+
+       ALTERNATIVE "jmp .Lwrcr3_\@", "", X86_FEATURE_PCID
 
        /*
         * Check if there's a pending flush for the user ASID we're
@@ -257,25 +264,17 @@ For 32-bit we have the following conventions - kernel is built with
         */
        movq    \save_reg, \scratch_reg
        andq    $(0x7FF), \scratch_reg
-       bt      \scratch_reg, THIS_CPU_user_pcid_flush_mask
-       jnc     .Lnoflush_\@
-
        btr     \scratch_reg, THIS_CPU_user_pcid_flush_mask
-       jmp     .Lwrcr3_\@
+       j     .Lwrcr3_\@
 
-.Lnoflush_\@:
        SET_NOFLUSH_BIT \save_reg
 
 .Lwrcr3_\@:
-       /*
-        * The CR3 write could be avoided when not changing its value,
-        * but would require a CR3 read *and* a scratch register.
-        */
        movq    \save_reg, %cr3
 .Lend_\@:
 .endm
 
-#else /* CONFIG_PAGE_TABLE_ISOLATION=n: */
+#else /* CONFIG_MITIGATION_PAGE_TABLE_ISOLATION=n: */
 
 .macro SWITCH_TO_KERNEL_CR3 scratch_reg:req
 .endm
@@ -285,7 +284,7 @@ For 32-bit we have the following conventions - kernel is built with
 .endm
 .macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req
 .endm
-.macro RESTORE_CR3 scratch_reg:req save_reg:req
+.macro PARANOID_RESTORE_CR3 scratch_reg:req save_reg:req
 .endm
 
 #endif
@@ -303,7 +302,7 @@ For 32-bit we have the following conventions - kernel is built with
  * Assumes x86_spec_ctrl_{base,current} to have SPEC_CTRL_IBRS set.
  */
 .macro IBRS_ENTER save_reg
-#ifdef CONFIG_CPU_IBRS_ENTRY
+#ifdef CONFIG_MITIGATION_IBRS_ENTRY
        ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
        movl    $MSR_IA32_SPEC_CTRL, %ecx
 
@@ -332,7 +331,7 @@ For 32-bit we have the following conventions - kernel is built with
  * regs. Must be called after the last RET.
  */
 .macro IBRS_EXIT save_reg
-#ifdef CONFIG_CPU_IBRS_ENTRY
+#ifdef CONFIG_MITIGATION_IBRS_ENTRY
        ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
        movl    $MSR_IA32_SPEC_CTRL, %ecx
 
@@ -426,3 +425,63 @@ For 32-bit we have the following conventions - kernel is built with
 .endm
 
 #endif /* CONFIG_SMP */
+
+#ifdef CONFIG_X86_64
+
+/* rdi:        arg1 ... normal C conventions. rax is saved/restored. */
+.macro THUNK name, func
+SYM_FUNC_START(\name)
+       pushq %rbp
+       movq %rsp, %rbp
+
+       pushq %rdi
+       pushq %rsi
+       pushq %rdx
+       pushq %rcx
+       pushq %rax
+       pushq %r8
+       pushq %r9
+       pushq %r10
+       pushq %r11
+
+       call \func
+
+       popq %r11
+       popq %r10
+       popq %r9
+       popq %r8
+       popq %rax
+       popq %rcx
+       popq %rdx
+       popq %rsi
+       popq %rdi
+       popq %rbp
+       RET
+SYM_FUNC_END(\name)
+       _ASM_NOKPROBE(\name)
+.endm
+
+#else /* CONFIG_X86_32 */
+
+/* put return address in eax (arg1) */
+.macro THUNK name, func, put_ret_addr_in_eax=0
+SYM_CODE_START_NOALIGN(\name)
+       pushl %eax
+       pushl %ecx
+       pushl %edx
+
+       .if \put_ret_addr_in_eax
+       /* Place EIP in the arg1 */
+       movl 3*4(%esp), %eax
+       .endif
+
+       call \func
+       popl %edx
+       popl %ecx
+       popl %eax
+       RET
+       _ASM_NOKPROBE(\name)
+SYM_CODE_END(\name)
+       .endm
+
+#endif
index 8c8d38f0cb1df0ee959e09c9f912ec1ab2afce40..d9feadffa972dadf0e2dcf5804ac50f9827d6c07 100644 (file)
@@ -6,6 +6,11 @@
 #include <linux/export.h>
 #include <linux/linkage.h>
 #include <asm/msr-index.h>
+#include <asm/unwind_hints.h>
+#include <asm/segment.h>
+#include <asm/cache.h>
+
+#include "calling.h"
 
 .pushsection .noinstr.text, "ax"
 
@@ -20,3 +25,24 @@ SYM_FUNC_END(entry_ibpb)
 EXPORT_SYMBOL_GPL(entry_ibpb);
 
 .popsection
+
+/*
+ * Define the VERW operand that is disguised as entry code so that
+ * it can be referenced with KPTI enabled. This ensure VERW can be
+ * used late in exit-to-user path after page tables are switched.
+ */
+.pushsection .entry.text, "ax"
+
+.align L1_CACHE_BYTES, 0xcc
+SYM_CODE_START_NOALIGN(mds_verw_sel)
+       UNWIND_HINT_UNDEFINED
+       ANNOTATE_NOENDBR
+       .word __KERNEL_DS
+.align L1_CACHE_BYTES, 0xcc
+SYM_CODE_END(mds_verw_sel);
+/* For KVM */
+EXPORT_SYMBOL_GPL(mds_verw_sel);
+
+.popsection
+
+THUNK warn_thunk_thunk, __warn_thunk
index c73047bf9f4bff9c4631c0eab383cedceda41918..d3a814efbff66318b8f2f750aa1d3a0906036aca 100644 (file)
 .macro CHECK_AND_APPLY_ESPFIX
 #ifdef CONFIG_X86_ESPFIX32
 #define GDT_ESPFIX_OFFSET (GDT_ENTRY_ESPFIX_SS * 8)
-#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + GDT_ESPFIX_OFFSET
+#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page + GDT_ESPFIX_OFFSET)
 
        ALTERNATIVE     "jmp .Lend_\@", "", X86_BUG_ESPFIX
 
@@ -649,10 +649,6 @@ SYM_CODE_START_LOCAL(asm_\cfunc)
 SYM_CODE_END(asm_\cfunc)
 .endm
 
-.macro idtentry_sysvec vector cfunc
-       idtentry \vector asm_\cfunc \cfunc has_error_code=0
-.endm
-
 /*
  * Include the defines which emit the idt entries which are shared
  * shared between 32 and 64 bit and emit the __irqentry_text_* markers
@@ -885,6 +881,7 @@ SYM_FUNC_START(entry_SYSENTER_32)
        BUG_IF_WRONG_CR3 no_user_check=1
        popfl
        popl    %eax
+       CLEAR_CPU_BUFFERS
 
        /*
         * Return back to the vDSO, which will pop ecx and edx.
@@ -954,6 +951,7 @@ restore_all_switch_stack:
 
        /* Restore user state */
        RESTORE_REGS pop=4                      # skip orig_eax/error_code
+       CLEAR_CPU_BUFFERS
 .Lirq_return:
        /*
         * ARCH_HAS_MEMBARRIER_SYNC_CORE rely on IRET core serialization
@@ -1146,6 +1144,7 @@ SYM_CODE_START(asm_exc_nmi)
 
        /* Not on SYSENTER stack. */
        call    exc_nmi
+       CLEAR_CPU_BUFFERS
        jmp     .Lnmi_return
 
 .Lnmi_from_sysenter_stack:
index c40f89ab1b4c70a18b632a50c1e659e3fd83cfa9..8af2a26b24f6a9783f9bb348cd67c15e1c3799c8 100644 (file)
@@ -161,6 +161,7 @@ syscall_return_via_sysret:
 SYM_INNER_LABEL(entry_SYSRETQ_unsafe_stack, SYM_L_GLOBAL)
        ANNOTATE_NOENDBR
        swapgs
+       CLEAR_CPU_BUFFERS
        sysretq
 SYM_INNER_LABEL(entry_SYSRETQ_end, SYM_L_GLOBAL)
        ANNOTATE_NOENDBR
@@ -190,7 +191,7 @@ SYM_FUNC_START(__switch_to_asm)
 
 #ifdef CONFIG_STACKPROTECTOR
        movq    TASK_stack_canary(%rsi), %rbx
-       movq    %rbx, PER_CPU_VAR(fixed_percpu_data) + FIXED_stack_canary
+       movq    %rbx, PER_CPU_VAR(fixed_percpu_data + FIXED_stack_canary)
 #endif
 
        /*
@@ -247,7 +248,13 @@ SYM_CODE_START(ret_from_fork_asm)
         * and unwind should work normally.
         */
        UNWIND_HINT_REGS
+
+#ifdef CONFIG_X86_FRED
+       ALTERNATIVE "jmp swapgs_restore_regs_and_return_to_usermode", \
+                   "jmp asm_fred_exit_user", X86_FEATURE_FRED
+#else
        jmp     swapgs_restore_regs_and_return_to_usermode
+#endif
 SYM_CODE_END(ret_from_fork_asm)
 .popsection
 
@@ -370,14 +377,6 @@ SYM_CODE_END(\asmsym)
        idtentry \vector asm_\cfunc \cfunc has_error_code=1
 .endm
 
-/*
- * System vectors which invoke their handlers directly and are not
- * going through the regular common device interrupt handling code.
- */
-.macro idtentry_sysvec vector cfunc
-       idtentry \vector asm_\cfunc \cfunc has_error_code=0
-.endm
-
 /**
  * idtentry_mce_db - Macro to generate entry stubs for #MC and #DB
  * @vector:            Vector number
@@ -562,7 +561,7 @@ SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
 #ifdef CONFIG_XEN_PV
        ALTERNATIVE "", "jmp xenpv_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV
 #endif
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
        ALTERNATIVE "", "jmp .Lpti_restore_regs_and_return_to_usermode", X86_FEATURE_PTI
 #endif
 
@@ -573,12 +572,13 @@ SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
 
 .Lswapgs_and_iret:
        swapgs
+       CLEAR_CPU_BUFFERS
        /* Assert that the IRET frame indicates user mode. */
        testb   $3, 8(%rsp)
        jnz     .Lnative_iret
        ud2
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 .Lpti_restore_regs_and_return_to_usermode:
        POP_REGS pop_rdi=0
 
@@ -723,6 +723,8 @@ native_irq_return_ldt:
         */
        popq    %rax                            /* Restore user RAX */
 
+       CLEAR_CPU_BUFFERS
+
        /*
         * RSP now points to an ordinary IRET frame, except that the page
         * is read-only and RSP[31:16] are preloaded with the userspace
@@ -968,14 +970,14 @@ SYM_CODE_START_LOCAL(paranoid_exit)
        IBRS_EXIT save_reg=%r15
 
        /*
-        * The order of operations is important. RESTORE_CR3 requires
+        * The order of operations is important. PARANOID_RESTORE_CR3 requires
         * kernel GSBASE.
         *
         * NB to anyone to try to optimize this code: this code does
         * not execute at all for exceptions from user mode. Those
         * exceptions go through error_return instead.
         */
-       RESTORE_CR3     scratch_reg=%rax save_reg=%r14
+       PARANOID_RESTORE_CR3 scratch_reg=%rax save_reg=%r14
 
        /* Handle the three GSBASE cases */
        ALTERNATIVE "jmp .Lparanoid_exit_checkgs", "", X86_FEATURE_FSGSBASE
@@ -1096,7 +1098,7 @@ SYM_CODE_END(error_return)
  *
  * Registers:
  *     %r14: Used to save/restore the CR3 of the interrupted context
- *           when PAGE_TABLE_ISOLATION is in use.  Do not clobber.
+ *           when MITIGATION_PAGE_TABLE_ISOLATION is in use.  Do not clobber.
  */
 SYM_CODE_START(asm_exc_nmi)
        UNWIND_HINT_IRET_ENTRY
@@ -1404,8 +1406,7 @@ end_repeat_nmi:
        /* Always restore stashed SPEC_CTRL value (see paranoid_entry) */
        IBRS_EXIT save_reg=%r15
 
-       /* Always restore stashed CR3 value (see paranoid_entry) */
-       RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
+       PARANOID_RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
 
        /*
         * The above invocation of paranoid_entry stored the GSBASE
@@ -1449,6 +1450,12 @@ nmi_restore:
        std
        movq    $0, 5*8(%rsp)           /* clear "NMI executing" */
 
+       /*
+        * Skip CLEAR_CPU_BUFFERS here, since it only helps in rare cases like
+        * NMI in kernel after user state is restored. For an unprivileged user
+        * these conditions are hard to meet.
+        */
+
        /*
         * iretq reads the "iret" frame and exits the NMI stack in a
         * single instruction.  We are returning to kernel mode, so this
@@ -1466,6 +1473,7 @@ SYM_CODE_START(entry_SYSCALL32_ignore)
        UNWIND_HINT_END_OF_STACK
        ENDBR
        mov     $-ENOSYS, %eax
+       CLEAR_CPU_BUFFERS
        sysretl
 SYM_CODE_END(entry_SYSCALL32_ignore)
 
index de94e2e84ecca927d9aa0e1ab99466466c163d44..eabf48c4d4b4c30367792f5d9a0b158a9ecf8a04 100644 (file)
@@ -270,6 +270,7 @@ SYM_INNER_LABEL(entry_SYSRETL_compat_unsafe_stack, SYM_L_GLOBAL)
        xorl    %r9d, %r9d
        xorl    %r10d, %r10d
        swapgs
+       CLEAR_CPU_BUFFERS
        sysretl
 SYM_INNER_LABEL(entry_SYSRETL_compat_end, SYM_L_GLOBAL)
        ANNOTATE_NOENDBR
diff --git a/arch/x86/entry/entry_64_fred.S b/arch/x86/entry/entry_64_fred.S
new file mode 100644 (file)
index 0000000..a02bc6f
--- /dev/null
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * The actual FRED entry points.
+ */
+
+#include <linux/export.h>
+
+#include <asm/asm.h>
+#include <asm/fred.h>
+#include <asm/segment.h>
+
+#include "calling.h"
+
+       .code64
+       .section .noinstr.text, "ax"
+
+.macro FRED_ENTER
+       UNWIND_HINT_END_OF_STACK
+       ENDBR
+       PUSH_AND_CLEAR_REGS
+       movq    %rsp, %rdi      /* %rdi -> pt_regs */
+.endm
+
+.macro FRED_EXIT
+       UNWIND_HINT_REGS
+       POP_REGS
+.endm
+
+/*
+ * The new RIP value that FRED event delivery establishes is
+ * IA32_FRED_CONFIG & ~FFFH for events that occur in ring 3.
+ * Thus the FRED ring 3 entry point must be 4K page aligned.
+ */
+       .align 4096
+
+SYM_CODE_START_NOALIGN(asm_fred_entrypoint_user)
+       FRED_ENTER
+       call    fred_entry_from_user
+SYM_INNER_LABEL(asm_fred_exit_user, SYM_L_GLOBAL)
+       FRED_EXIT
+1:     ERETU
+
+       _ASM_EXTABLE_TYPE(1b, asm_fred_entrypoint_user, EX_TYPE_ERETU)
+SYM_CODE_END(asm_fred_entrypoint_user)
+
+/*
+ * The new RIP value that FRED event delivery establishes is
+ * (IA32_FRED_CONFIG & ~FFFH) + 256 for events that occur in
+ * ring 0, i.e., asm_fred_entrypoint_user + 256.
+ */
+       .org asm_fred_entrypoint_user + 256, 0xcc
+SYM_CODE_START_NOALIGN(asm_fred_entrypoint_kernel)
+       FRED_ENTER
+       call    fred_entry_from_kernel
+       FRED_EXIT
+       ERETS
+SYM_CODE_END(asm_fred_entrypoint_kernel)
+
+#if IS_ENABLED(CONFIG_KVM_INTEL)
+SYM_FUNC_START(asm_fred_entry_from_kvm)
+       push %rbp
+       mov %rsp, %rbp
+
+       UNWIND_HINT_SAVE
+
+       /*
+        * Both IRQ and NMI from VMX can be handled on current task stack
+        * because there is no need to protect from reentrancy and the call
+        * stack leading to this helper is effectively constant and shallow
+        * (relatively speaking). Do the same when FRED is active, i.e., no
+        * need to check current stack level for a stack switch.
+        *
+        * Emulate the FRED-defined redzone and stack alignment.
+        */
+       sub $(FRED_CONFIG_REDZONE_AMOUNT << 6), %rsp
+       and $FRED_STACK_FRAME_RSP_MASK, %rsp
+
+       /*
+        * Start to push a FRED stack frame, which is always 64 bytes:
+        *
+        * +--------+-----------------+
+        * | Bytes  | Usage           |
+        * +--------+-----------------+
+        * | 63:56  | Reserved        |
+        * | 55:48  | Event Data      |
+        * | 47:40  | SS + Event Info |
+        * | 39:32  | RSP             |
+        * | 31:24  | RFLAGS          |
+        * | 23:16  | CS + Aux Info   |
+        * |  15:8  | RIP             |
+        * |   7:0  | Error Code      |
+        * +--------+-----------------+
+        */
+       push $0                         /* Reserved, must be 0 */
+       push $0                         /* Event data, 0 for IRQ/NMI */
+       push %rdi                       /* fred_ss handed in by the caller */
+       push %rbp
+       pushf
+       mov $__KERNEL_CS, %rax
+       push %rax
+
+       /*
+        * Unlike the IDT event delivery, FRED _always_ pushes an error code
+        * after pushing the return RIP, thus the CALL instruction CANNOT be
+        * used here to push the return RIP, otherwise there is no chance to
+        * push an error code before invoking the IRQ/NMI handler.
+        *
+        * Use LEA to get the return RIP and push it, then push an error code.
+        */
+       lea 1f(%rip), %rax
+       push %rax                               /* Return RIP */
+       push $0                                 /* Error code, 0 for IRQ/NMI */
+
+       PUSH_AND_CLEAR_REGS clear_bp=0 unwind_hint=0
+       movq %rsp, %rdi                         /* %rdi -> pt_regs */
+       call __fred_entry_from_kvm              /* Call the C entry point */
+       POP_REGS
+       ERETS
+1:
+       /*
+        * Objtool doesn't understand what ERETS does, this hint tells it that
+        * yes, we'll reach here and with what stack state. A save/restore pair
+        * isn't strictly needed, but it's the simplest form.
+        */
+       UNWIND_HINT_RESTORE
+       pop %rbp
+       RET
+
+SYM_FUNC_END(asm_fred_entry_from_kvm)
+EXPORT_SYMBOL_GPL(asm_fred_entry_from_kvm);
+#endif
diff --git a/arch/x86/entry/entry_fred.c b/arch/x86/entry/entry_fred.c
new file mode 100644 (file)
index 0000000..ac120cb
--- /dev/null
@@ -0,0 +1,294 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * The FRED specific kernel/user entry functions which are invoked from
+ * assembly code and dispatch to the associated handlers.
+ */
+#include <linux/kernel.h>
+#include <linux/kdebug.h>
+#include <linux/nospec.h>
+
+#include <asm/desc.h>
+#include <asm/fred.h>
+#include <asm/idtentry.h>
+#include <asm/syscall.h>
+#include <asm/trapnr.h>
+#include <asm/traps.h>
+
+/* FRED EVENT_TYPE_OTHER vector numbers */
+#define FRED_SYSCALL                   1
+#define FRED_SYSENTER                  2
+
+static noinstr void fred_bad_type(struct pt_regs *regs, unsigned long error_code)
+{
+       irqentry_state_t irq_state = irqentry_nmi_enter(regs);
+
+       instrumentation_begin();
+
+       /* Panic on events from a high stack level */
+       if (regs->fred_cs.sl > 0) {
+               pr_emerg("PANIC: invalid or fatal FRED event; event type %u "
+                        "vector %u error 0x%lx aux 0x%lx at %04x:%016lx\n",
+                        regs->fred_ss.type, regs->fred_ss.vector, regs->orig_ax,
+                        fred_event_data(regs), regs->cs, regs->ip);
+               die("invalid or fatal FRED event", regs, regs->orig_ax);
+               panic("invalid or fatal FRED event");
+       } else {
+               unsigned long flags = oops_begin();
+               int sig = SIGKILL;
+
+               pr_alert("BUG: invalid or fatal FRED event; event type %u "
+                        "vector %u error 0x%lx aux 0x%lx at %04x:%016lx\n",
+                        regs->fred_ss.type, regs->fred_ss.vector, regs->orig_ax,
+                        fred_event_data(regs), regs->cs, regs->ip);
+
+               if (__die("Invalid or fatal FRED event", regs, regs->orig_ax))
+                       sig = 0;
+
+               oops_end(flags, regs, sig);
+       }
+
+       instrumentation_end();
+       irqentry_nmi_exit(regs, irq_state);
+}
+
+static noinstr void fred_intx(struct pt_regs *regs)
+{
+       switch (regs->fred_ss.vector) {
+       /* Opcode 0xcd, 0x3, NOT INT3 (opcode 0xcc) */
+       case X86_TRAP_BP:
+               return exc_int3(regs);
+
+       /* Opcode 0xcd, 0x4, NOT INTO (opcode 0xce) */
+       case X86_TRAP_OF:
+               return exc_overflow(regs);
+
+#ifdef CONFIG_IA32_EMULATION
+       /* INT80 */
+       case IA32_SYSCALL_VECTOR:
+               if (ia32_enabled())
+                       return int80_emulation(regs);
+               fallthrough;
+#endif
+
+       default:
+               return exc_general_protection(regs, 0);
+       }
+}
+
+static __always_inline void fred_other(struct pt_regs *regs)
+{
+       /* The compiler can fold these conditions into a single test */
+       if (likely(regs->fred_ss.vector == FRED_SYSCALL && regs->fred_ss.lm)) {
+               regs->orig_ax = regs->ax;
+               regs->ax = -ENOSYS;
+               do_syscall_64(regs, regs->orig_ax);
+               return;
+       } else if (ia32_enabled() &&
+                  likely(regs->fred_ss.vector == FRED_SYSENTER && !regs->fred_ss.lm)) {
+               regs->orig_ax = regs->ax;
+               regs->ax = -ENOSYS;
+               do_fast_syscall_32(regs);
+               return;
+       } else {
+               exc_invalid_op(regs);
+               return;
+       }
+}
+
+#define SYSVEC(_vector, _function) [_vector - FIRST_SYSTEM_VECTOR] = fred_sysvec_##_function
+
+static idtentry_t sysvec_table[NR_SYSTEM_VECTORS] __ro_after_init = {
+       SYSVEC(ERROR_APIC_VECTOR,               error_interrupt),
+       SYSVEC(SPURIOUS_APIC_VECTOR,            spurious_apic_interrupt),
+       SYSVEC(LOCAL_TIMER_VECTOR,              apic_timer_interrupt),
+       SYSVEC(X86_PLATFORM_IPI_VECTOR,         x86_platform_ipi),
+
+       SYSVEC(RESCHEDULE_VECTOR,               reschedule_ipi),
+       SYSVEC(CALL_FUNCTION_SINGLE_VECTOR,     call_function_single),
+       SYSVEC(CALL_FUNCTION_VECTOR,            call_function),
+       SYSVEC(REBOOT_VECTOR,                   reboot),
+
+       SYSVEC(THRESHOLD_APIC_VECTOR,           threshold),
+       SYSVEC(DEFERRED_ERROR_VECTOR,           deferred_error),
+       SYSVEC(THERMAL_APIC_VECTOR,             thermal),
+
+       SYSVEC(IRQ_WORK_VECTOR,                 irq_work),
+
+       SYSVEC(POSTED_INTR_VECTOR,              kvm_posted_intr_ipi),
+       SYSVEC(POSTED_INTR_WAKEUP_VECTOR,       kvm_posted_intr_wakeup_ipi),
+       SYSVEC(POSTED_INTR_NESTED_VECTOR,       kvm_posted_intr_nested_ipi),
+};
+
+static bool fred_setup_done __initdata;
+
+void __init fred_install_sysvec(unsigned int sysvec, idtentry_t handler)
+{
+       if (WARN_ON_ONCE(sysvec < FIRST_SYSTEM_VECTOR))
+               return;
+
+       if (WARN_ON_ONCE(fred_setup_done))
+               return;
+
+       if (!WARN_ON_ONCE(sysvec_table[sysvec - FIRST_SYSTEM_VECTOR]))
+                sysvec_table[sysvec - FIRST_SYSTEM_VECTOR] = handler;
+}
+
+static noinstr void fred_handle_spurious_interrupt(struct pt_regs *regs)
+{
+       spurious_interrupt(regs, regs->fred_ss.vector);
+}
+
+void __init fred_complete_exception_setup(void)
+{
+       unsigned int vector;
+
+       for (vector = 0; vector < FIRST_EXTERNAL_VECTOR; vector++)
+               set_bit(vector, system_vectors);
+
+       for (vector = 0; vector < NR_SYSTEM_VECTORS; vector++) {
+               if (sysvec_table[vector])
+                       set_bit(vector + FIRST_SYSTEM_VECTOR, system_vectors);
+               else
+                       sysvec_table[vector] = fred_handle_spurious_interrupt;
+       }
+       fred_setup_done = true;
+}
+
+static noinstr void fred_extint(struct pt_regs *regs)
+{
+       unsigned int vector = regs->fred_ss.vector;
+       unsigned int index = array_index_nospec(vector - FIRST_SYSTEM_VECTOR,
+                                               NR_SYSTEM_VECTORS);
+
+       if (WARN_ON_ONCE(vector < FIRST_EXTERNAL_VECTOR))
+               return;
+
+       if (likely(vector >= FIRST_SYSTEM_VECTOR)) {
+               irqentry_state_t state = irqentry_enter(regs);
+
+               instrumentation_begin();
+               sysvec_table[index](regs);
+               instrumentation_end();
+               irqentry_exit(regs, state);
+       } else {
+               common_interrupt(regs, vector);
+       }
+}
+
+static noinstr void fred_hwexc(struct pt_regs *regs, unsigned long error_code)
+{
+       /* Optimize for #PF. That's the only exception which matters performance wise */
+       if (likely(regs->fred_ss.vector == X86_TRAP_PF))
+               return exc_page_fault(regs, error_code);
+
+       switch (regs->fred_ss.vector) {
+       case X86_TRAP_DE: return exc_divide_error(regs);
+       case X86_TRAP_DB: return fred_exc_debug(regs);
+       case X86_TRAP_BR: return exc_bounds(regs);
+       case X86_TRAP_UD: return exc_invalid_op(regs);
+       case X86_TRAP_NM: return exc_device_not_available(regs);
+       case X86_TRAP_DF: return exc_double_fault(regs, error_code);
+       case X86_TRAP_TS: return exc_invalid_tss(regs, error_code);
+       case X86_TRAP_NP: return exc_segment_not_present(regs, error_code);
+       case X86_TRAP_SS: return exc_stack_segment(regs, error_code);
+       case X86_TRAP_GP: return exc_general_protection(regs, error_code);
+       case X86_TRAP_MF: return exc_coprocessor_error(regs);
+       case X86_TRAP_AC: return exc_alignment_check(regs, error_code);
+       case X86_TRAP_XF: return exc_simd_coprocessor_error(regs);
+
+#ifdef CONFIG_X86_MCE
+       case X86_TRAP_MC: return fred_exc_machine_check(regs);
+#endif
+#ifdef CONFIG_INTEL_TDX_GUEST
+       case X86_TRAP_VE: return exc_virtualization_exception(regs);
+#endif
+#ifdef CONFIG_X86_CET
+       case X86_TRAP_CP: return exc_control_protection(regs, error_code);
+#endif
+       default: return fred_bad_type(regs, error_code);
+       }
+
+}
+
+static noinstr void fred_swexc(struct pt_regs *regs, unsigned long error_code)
+{
+       switch (regs->fred_ss.vector) {
+       case X86_TRAP_BP: return exc_int3(regs);
+       case X86_TRAP_OF: return exc_overflow(regs);
+       default: return fred_bad_type(regs, error_code);
+       }
+}
+
+__visible noinstr void fred_entry_from_user(struct pt_regs *regs)
+{
+       unsigned long error_code = regs->orig_ax;
+
+       /* Invalidate orig_ax so that syscall_get_nr() works correctly */
+       regs->orig_ax = -1;
+
+       switch (regs->fred_ss.type) {
+       case EVENT_TYPE_EXTINT:
+               return fred_extint(regs);
+       case EVENT_TYPE_NMI:
+               if (likely(regs->fred_ss.vector == X86_TRAP_NMI))
+                       return fred_exc_nmi(regs);
+               break;
+       case EVENT_TYPE_HWEXC:
+               return fred_hwexc(regs, error_code);
+       case EVENT_TYPE_SWINT:
+               return fred_intx(regs);
+       case EVENT_TYPE_PRIV_SWEXC:
+               if (likely(regs->fred_ss.vector == X86_TRAP_DB))
+                       return fred_exc_debug(regs);
+               break;
+       case EVENT_TYPE_SWEXC:
+               return fred_swexc(regs, error_code);
+       case EVENT_TYPE_OTHER:
+               return fred_other(regs);
+       default: break;
+       }
+
+       return fred_bad_type(regs, error_code);
+}
+
+__visible noinstr void fred_entry_from_kernel(struct pt_regs *regs)
+{
+       unsigned long error_code = regs->orig_ax;
+
+       /* Invalidate orig_ax so that syscall_get_nr() works correctly */
+       regs->orig_ax = -1;
+
+       switch (regs->fred_ss.type) {
+       case EVENT_TYPE_EXTINT:
+               return fred_extint(regs);
+       case EVENT_TYPE_NMI:
+               if (likely(regs->fred_ss.vector == X86_TRAP_NMI))
+                       return fred_exc_nmi(regs);
+               break;
+       case EVENT_TYPE_HWEXC:
+               return fred_hwexc(regs, error_code);
+       case EVENT_TYPE_PRIV_SWEXC:
+               if (likely(regs->fred_ss.vector == X86_TRAP_DB))
+                       return fred_exc_debug(regs);
+               break;
+       case EVENT_TYPE_SWEXC:
+               return fred_swexc(regs, error_code);
+       default: break;
+       }
+
+       return fred_bad_type(regs, error_code);
+}
+
+#if IS_ENABLED(CONFIG_KVM_INTEL)
+__visible noinstr void __fred_entry_from_kvm(struct pt_regs *regs)
+{
+       switch (regs->fred_ss.type) {
+       case EVENT_TYPE_EXTINT:
+               return fred_extint(regs);
+       case EVENT_TYPE_NMI:
+               return fred_exc_nmi(regs);
+       default:
+               WARN_ON_ONCE(1);
+       }
+}
+#endif
index 0103e103a6573adab040c4e41b588edcdf7a7ecd..da37f42f45498d8282f2ea805d04eec1bfbfaa44 100644 (file)
@@ -4,33 +4,15 @@
  * Copyright 2008 by Steven Rostedt, Red Hat, Inc
  *  (inspired by Andi Kleen's thunk_64.S)
  */
-       #include <linux/export.h>
-       #include <linux/linkage.h>
-       #include <asm/asm.h>
 
-       /* put return address in eax (arg1) */
-       .macro THUNK name, func, put_ret_addr_in_eax=0
-SYM_CODE_START_NOALIGN(\name)
-       pushl %eax
-       pushl %ecx
-       pushl %edx
+#include <linux/export.h>
+#include <linux/linkage.h>
+#include <asm/asm.h>
 
-       .if \put_ret_addr_in_eax
-       /* Place EIP in the arg1 */
-       movl 3*4(%esp), %eax
-       .endif
+#include "calling.h"
 
-       call \func
-       popl %edx
-       popl %ecx
-       popl %eax
-       RET
-       _ASM_NOKPROBE(\name)
-SYM_CODE_END(\name)
-       .endm
-
-       THUNK preempt_schedule_thunk, preempt_schedule
-       THUNK preempt_schedule_notrace_thunk, preempt_schedule_notrace
-       EXPORT_SYMBOL(preempt_schedule_thunk)
-       EXPORT_SYMBOL(preempt_schedule_notrace_thunk)
+THUNK preempt_schedule_thunk, preempt_schedule
+THUNK preempt_schedule_notrace_thunk, preempt_schedule_notrace
+EXPORT_SYMBOL(preempt_schedule_thunk)
+EXPORT_SYMBOL(preempt_schedule_notrace_thunk)
 
index 416b400f39dbb6b16694a6e76b22bb03e8834bc5..119ebdc3d362398092736e7132f16c0c89e97c5a 100644 (file)
@@ -9,39 +9,6 @@
 #include "calling.h"
 #include <asm/asm.h>
 
-       /* rdi: arg1 ... normal C conventions. rax is saved/restored. */
-       .macro THUNK name, func
-SYM_FUNC_START(\name)
-       pushq %rbp
-       movq %rsp, %rbp
-
-       pushq %rdi
-       pushq %rsi
-       pushq %rdx
-       pushq %rcx
-       pushq %rax
-       pushq %r8
-       pushq %r9
-       pushq %r10
-       pushq %r11
-
-       call \func
-
-       popq %r11
-       popq %r10
-       popq %r9
-       popq %r8
-       popq %rax
-       popq %rcx
-       popq %rdx
-       popq %rsi
-       popq %rdi
-       popq %rbp
-       RET
-SYM_FUNC_END(\name)
-       _ASM_NOKPROBE(\name)
-       .endm
-
 THUNK preempt_schedule_thunk, preempt_schedule
 THUNK preempt_schedule_notrace_thunk, preempt_schedule_notrace
 EXPORT_SYMBOL(preempt_schedule_thunk)
index b1b8dd1608f7ebd73510cb94e2866c09aac825b6..620f6257bbe9358ce918bbf35aff659b683a2149 100644 (file)
@@ -3,7 +3,7 @@
 # Building vDSO images for x86.
 #
 
-# Include the generic Makefile to check the built vdso.
+# Include the generic Makefile to check the built vDSO:
 include $(srctree)/lib/vdso/Makefile
 
 # Sanitizer runtimes are unavailable and cannot be linked here.
@@ -18,48 +18,39 @@ OBJECT_FILES_NON_STANDARD   := y
 # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
 KCOV_INSTRUMENT                := n
 
-VDSO64-$(CONFIG_X86_64)                := y
-VDSOX32-$(CONFIG_X86_X32_ABI)  := y
-VDSO32-$(CONFIG_X86_32)                := y
-VDSO32-$(CONFIG_IA32_EMULATION)        := y
-
-# files to link into the vdso
+# Files to link into the vDSO:
 vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o
 vobjs32-y := vdso32/note.o vdso32/system_call.o vdso32/sigreturn.o
 vobjs32-y += vdso32/vclock_gettime.o vdso32/vgetcpu.o
 vobjs-$(CONFIG_X86_SGX)        += vsgx.o
 
-# files to link into kernel
-obj-y                                  += vma.o extable.o
-KASAN_SANITIZE_vma.o                   := y
-UBSAN_SANITIZE_vma.o                   := y
-KCSAN_SANITIZE_vma.o                   := y
-OBJECT_FILES_NON_STANDARD_vma.o                := n
-OBJECT_FILES_NON_STANDARD_extable.o    := n
+# Files to link into the kernel:
+obj-y                                          += vma.o extable.o
+KASAN_SANITIZE_vma.o                           := y
+UBSAN_SANITIZE_vma.o                           := y
+KCSAN_SANITIZE_vma.o                           := y
+
+OBJECT_FILES_NON_STANDARD_vma.o                        := n
+OBJECT_FILES_NON_STANDARD_extable.o            := n
 
-# vDSO images to build
-vdso_img-$(VDSO64-y)           += 64
-vdso_img-$(VDSOX32-y)          += x32
-vdso_img-$(VDSO32-y)           += 32
+# vDSO images to build:
+obj-$(CONFIG_X86_64)                           += vdso-image-64.o
+obj-$(CONFIG_X86_X32_ABI)                      += vdso-image-x32.o
+obj-$(CONFIG_COMPAT_32)                                += vdso-image-32.o vdso32-setup.o
 
-obj-$(VDSO32-y)                                 += vdso32-setup.o
-OBJECT_FILES_NON_STANDARD_vdso32-setup.o := n
+OBJECT_FILES_NON_STANDARD_vdso-image-32.o      := n
+OBJECT_FILES_NON_STANDARD_vdso-image-64.o      := n
+OBJECT_FILES_NON_STANDARD_vdso32-setup.o       := n
 
-vobjs := $(foreach F,$(vobjs-y),$(obj)/$F)
-vobjs32 := $(foreach F,$(vobjs32-y),$(obj)/$F)
+vobjs := $(addprefix $(obj)/, $(vobjs-y))
+vobjs32 := $(addprefix $(obj)/, $(vobjs32-y))
 
 $(obj)/vdso.o: $(obj)/vdso.so
 
 targets += vdso.lds $(vobjs-y)
 targets += vdso32/vdso32.lds $(vobjs32-y)
 
-# Build the vDSO image C files and link them in.
-vdso_img_objs := $(vdso_img-y:%=vdso-image-%.o)
-vdso_img_cfiles := $(vdso_img-y:%=vdso-image-%.c)
-vdso_img_sodbg := $(vdso_img-y:%=vdso%.so.dbg)
-obj-y += $(vdso_img_objs)
-targets += $(vdso_img_cfiles)
-targets += $(vdso_img_sodbg) $(vdso_img-y:%=vdso%.so)
+targets += $(foreach x, 64 x32 32, vdso-image-$(x).c vdso$(x).so vdso$(x).so.dbg)
 
 CPPFLAGS_vdso.lds += -P -C
 
@@ -87,7 +78,7 @@ CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \
        -fno-omit-frame-pointer -foptimize-sibling-calls \
        -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
 
-ifdef CONFIG_RETPOLINE
+ifdef CONFIG_MITIGATION_RETPOLINE
 ifneq ($(RETPOLINE_VDSO_CFLAGS),)
   CFL += $(RETPOLINE_VDSO_CFLAGS)
 endif
@@ -123,7 +114,7 @@ VDSO_LDFLAGS_vdsox32.lds = -m elf32_x86_64 -soname linux-vdso.so.1 \
 vobjx32s-y := $(vobjs-y:.o=-x32.o)
 
 # same thing, but in the output directory
-vobjx32s := $(foreach F,$(vobjx32s-y),$(obj)/$F)
+vobjx32s := $(addprefix $(obj)/, $(vobjx32s-y))
 
 # Convert 64bit object file to x32 for x32 vDSO.
 quiet_cmd_x32 = X32     $@
@@ -164,7 +155,7 @@ KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls)
 KBUILD_CFLAGS_32 += -fno-omit-frame-pointer
 KBUILD_CFLAGS_32 += -DDISABLE_BRANCH_PROFILING
 
-ifdef CONFIG_RETPOLINE
+ifdef CONFIG_MITIGATION_RETPOLINE
 ifneq ($(RETPOLINE_VDSO_CFLAGS),)
   KBUILD_CFLAGS_32 += $(RETPOLINE_VDSO_CFLAGS)
 endif
@@ -190,5 +181,3 @@ GCOV_PROFILE := n
 
 quiet_cmd_vdso_and_check = VDSO    $@
       cmd_vdso_and_check = $(cmd_vdso); $(cmd_vdso_check)
-
-clean-files := vdso32.so vdso32.so.dbg vdso64* vdso-image-*.c vdsox32.so*
index 7645730dc228f960e69373f860ccfca811097a84..6d83ceb7f1badac96649b4397d3313d8a1dbaab9 100644 (file)
@@ -274,59 +274,6 @@ up_fail:
        return ret;
 }
 
-#ifdef CONFIG_X86_64
-/*
- * Put the vdso above the (randomized) stack with another randomized
- * offset.  This way there is no hole in the middle of address space.
- * To save memory make sure it is still in the same PTE as the stack
- * top.  This doesn't give that many random bits.
- *
- * Note that this algorithm is imperfect: the distribution of the vdso
- * start address within a PMD is biased toward the end.
- *
- * Only used for the 64-bit and x32 vdsos.
- */
-static unsigned long vdso_addr(unsigned long start, unsigned len)
-{
-       unsigned long addr, end;
-       unsigned offset;
-
-       /*
-        * Round up the start address.  It can start out unaligned as a result
-        * of stack start randomization.
-        */
-       start = PAGE_ALIGN(start);
-
-       /* Round the lowest possible end address up to a PMD boundary. */
-       end = (start + len + PMD_SIZE - 1) & PMD_MASK;
-       if (end >= DEFAULT_MAP_WINDOW)
-               end = DEFAULT_MAP_WINDOW;
-       end -= len;
-
-       if (end > start) {
-               offset = get_random_u32_below(((end - start) >> PAGE_SHIFT) + 1);
-               addr = start + (offset << PAGE_SHIFT);
-       } else {
-               addr = start;
-       }
-
-       /*
-        * Forcibly align the final address in case we have a hardware
-        * issue that requires alignment for performance reasons.
-        */
-       addr = align_vdso_addr(addr);
-
-       return addr;
-}
-
-static int map_vdso_randomized(const struct vdso_image *image)
-{
-       unsigned long addr = vdso_addr(current->mm->start_stack, image->size-image->sym_vvar_start);
-
-       return map_vdso(image, addr);
-}
-#endif
-
 int map_vdso_once(const struct vdso_image *image, unsigned long addr)
 {
        struct mm_struct *mm = current->mm;
@@ -369,7 +316,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
        if (!vdso64_enabled)
                return 0;
 
-       return map_vdso_randomized(&vdso_image_64);
+       return map_vdso(&vdso_image_64, 0);
 }
 
 #ifdef CONFIG_COMPAT
@@ -380,7 +327,7 @@ int compat_arch_setup_additional_pages(struct linux_binprm *bprm,
        if (x32) {
                if (!vdso64_enabled)
                        return 0;
-               return map_vdso_randomized(&vdso_image_x32);
+               return map_vdso(&vdso_image_x32, 0);
        }
 #endif
 #ifdef CONFIG_IA32_EMULATION
index e0ca8120aea87631200df447bcdf756abb317c5d..a3c0df11d0e6d8c36db77b59077fef711724b2db 100644 (file)
@@ -76,7 +76,7 @@ static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
        if (!show_unhandled_signals)
                return;
 
-       printk_ratelimited("%s%s[%d] %s ip:%lx cs:%lx sp:%lx ax:%lx si:%lx di:%lx\n",
+       printk_ratelimited("%s%s[%d] %s ip:%lx cs:%x sp:%lx ax:%lx si:%lx di:%lx\n",
                           level, current->comm, task_pid_nr(current),
                           message, regs->ip, regs->cs,
                           regs->sp, regs->ax, regs->si, regs->di);
index 81f6d8275b6bf2aab39ff40eac3fcf706192654b..69a3b02e50bb0cfbe2688769ad3a5ea72fd8e11f 100644 (file)
@@ -579,7 +579,7 @@ static void amd_pmu_cpu_starting(int cpu)
        if (!x86_pmu.amd_nb_constraints)
                return;
 
-       nb_id = topology_die_id(cpu);
+       nb_id = topology_amd_node_id(cpu);
        WARN_ON_ONCE(nb_id == BAD_APICID);
 
        for_each_online_cpu(i) {
index 5bf03c5758129569afdc394203033f95f0757c41..4ccb8fa483e613af8bade68e3718bda0e91acd38 100644 (file)
@@ -71,7 +71,7 @@ union amd_uncore_info {
 };
 
 struct amd_uncore {
-       union amd_uncore_info * __percpu info;
+       union amd_uncore_info  __percpu *info;
        struct amd_uncore_pmu *pmus;
        unsigned int num_pmus;
        bool init_done;
index 3804f21ab0494f90effb7399210524ba17c73b43..768d1414897fb1de72a9cb9abad354add11828a4 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/kvm_host.h>
 
 #include <asm/cpufeature.h>
+#include <asm/debugreg.h>
 #include <asm/hardirq.h>
 #include <asm/intel-family.h>
 #include <asm/intel_pt.h>
index 4b50a3a9818aec676d44da4db29fc5d4448757e1..326c8cd5aa2d2e587277207ee3f225ef7b0512a6 100644 (file)
@@ -834,7 +834,7 @@ static int __init cstate_init(void)
        }
 
        if (has_cstate_pkg) {
-               if (topology_max_die_per_package() > 1) {
+               if (topology_max_dies_per_package() > 1) {
                        err = perf_pmu_register(&cstate_pkg_pmu,
                                                "cstate_die", -1);
                } else {
index d49d661ec0a7d1b75d17d05b8c75a44e8d5122e7..2641ba620f12a51d4c5d71ceba3bd28557926bfb 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/sched/clock.h>
 
 #include <asm/cpu_entry_area.h>
+#include <asm/debugreg.h>
 #include <asm/perf_event.h>
 #include <asm/tlbflush.h>
 #include <asm/insn.h>
index 7927c0b832faa4eec31f53d3330c98b858cba249..258e2cdf28fadc8d84a0574b38c000de09df802d 100644 (file)
@@ -1893,7 +1893,7 @@ static int __init intel_uncore_init(void)
                return -ENODEV;
 
        __uncore_max_dies =
-               topology_max_packages() * topology_max_die_per_package();
+               topology_max_packages() * topology_max_dies_per_package();
 
        id = x86_match_cpu(intel_uncore_match);
        if (!id) {
index 56eea2c66cfb8cc7d9cc395e58c24a7319afc944..92da8aaa59660e2097423eee0f018bb1f195efd7 100644 (file)
@@ -1221,8 +1221,8 @@ void nhmex_uncore_cpu_init(void)
                uncore_nhmex = true;
        else
                nhmex_uncore_mbox.event_descs = wsmex_uncore_mbox_events;
-       if (nhmex_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
-               nhmex_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       if (nhmex_uncore_cbox.num_boxes > topology_num_cores_per_package())
+               nhmex_uncore_cbox.num_boxes = topology_num_cores_per_package();
        uncore_msr_uncores = nhmex_msr_uncores;
 }
 /* end of Nehalem-EX uncore support */
index 7fd4334e12a172d495bdf9353ac678f2a19f86f6..9462fd9f3b7abc2263c203651a89f01230bd3b51 100644 (file)
@@ -364,8 +364,8 @@ static struct intel_uncore_type *snb_msr_uncores[] = {
 void snb_uncore_cpu_init(void)
 {
        uncore_msr_uncores = snb_msr_uncores;
-       if (snb_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
-               snb_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       if (snb_uncore_cbox.num_boxes > topology_num_cores_per_package())
+               snb_uncore_cbox.num_boxes = topology_num_cores_per_package();
 }
 
 static void skl_uncore_msr_init_box(struct intel_uncore_box *box)
@@ -428,8 +428,8 @@ static struct intel_uncore_type *skl_msr_uncores[] = {
 void skl_uncore_cpu_init(void)
 {
        uncore_msr_uncores = skl_msr_uncores;
-       if (skl_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
-               skl_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       if (skl_uncore_cbox.num_boxes > topology_num_cores_per_package())
+               skl_uncore_cbox.num_boxes = topology_num_cores_per_package();
        snb_uncore_arb.ops = &skl_uncore_msr_ops;
 }
 
index a96496bef678bb5cc562092811e4a919340c3bf3..2eaf0f339849b66d0d8cc7800ed9e63e85ce4bbc 100644 (file)
@@ -1172,8 +1172,8 @@ static struct intel_uncore_type *snbep_msr_uncores[] = {
 
 void snbep_uncore_cpu_init(void)
 {
-       if (snbep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
-               snbep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       if (snbep_uncore_cbox.num_boxes > topology_num_cores_per_package())
+               snbep_uncore_cbox.num_boxes = topology_num_cores_per_package();
        uncore_msr_uncores = snbep_msr_uncores;
 }
 
@@ -1406,7 +1406,7 @@ static int topology_gidnid_map(int nodeid, u32 gidnid)
         */
        for (i = 0; i < 8; i++) {
                if (nodeid == GIDNIDMAP(gidnid, i)) {
-                       if (topology_max_die_per_package() > 1)
+                       if (topology_max_dies_per_package() > 1)
                                die_id = i;
                        else
                                die_id = topology_phys_to_logical_pkg(i);
@@ -1845,8 +1845,8 @@ static struct intel_uncore_type *ivbep_msr_uncores[] = {
 
 void ivbep_uncore_cpu_init(void)
 {
-       if (ivbep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
-               ivbep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       if (ivbep_uncore_cbox.num_boxes > topology_num_cores_per_package())
+               ivbep_uncore_cbox.num_boxes = topology_num_cores_per_package();
        uncore_msr_uncores = ivbep_msr_uncores;
 }
 
@@ -2917,8 +2917,8 @@ static bool hswep_has_limit_sbox(unsigned int device)
 
 void hswep_uncore_cpu_init(void)
 {
-       if (hswep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
-               hswep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       if (hswep_uncore_cbox.num_boxes > topology_num_cores_per_package())
+               hswep_uncore_cbox.num_boxes = topology_num_cores_per_package();
 
        /* Detect 6-8 core systems with only two SBOXes */
        if (hswep_has_limit_sbox(HSWEP_PCU_DID))
@@ -3280,8 +3280,8 @@ static struct event_constraint bdx_uncore_pcu_constraints[] = {
 
 void bdx_uncore_cpu_init(void)
 {
-       if (bdx_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
-               bdx_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       if (bdx_uncore_cbox.num_boxes > topology_num_cores_per_package())
+               bdx_uncore_cbox.num_boxes = topology_num_cores_per_package();
        uncore_msr_uncores = bdx_msr_uncores;
 
        /* Detect systems with no SBOXes */
index 8d98d468b97618b2646f43dd2a922db7677eb4b1..fb2b1961e5a33a190ab21ce6ea7d27026ffbc18e 100644 (file)
@@ -674,7 +674,7 @@ static const struct attribute_group *rapl_attr_update[] = {
 
 static int __init init_rapl_pmus(void)
 {
-       int maxdie = topology_max_packages() * topology_max_die_per_package();
+       int maxdie = topology_max_packages() * topology_max_dies_per_package();
        size_t size;
 
        size = sizeof(*rapl_pmus) + maxdie * sizeof(struct rapl_pmu *);
index 96e6c51515f50467efbf7cb77082c6b9d18cb8f6..edd2f35b2a5e100ce9662ceead612bc04c213f29 100644 (file)
 extern struct boot_params boot_params;
 static struct real_mode_header hv_vtl_real_mode_header;
 
+static bool __init hv_vtl_msi_ext_dest_id(void)
+{
+       return true;
+}
+
 void __init hv_vtl_init_platform(void)
 {
        pr_info("Linux runs in Hyper-V Virtual Trust Level\n");
@@ -26,8 +31,9 @@ void __init hv_vtl_init_platform(void)
        x86_init.timers.timer_init = x86_init_noop;
 
        /* Avoid searching for BIOS MP tables */
-       x86_init.mpparse.find_smp_config = x86_init_noop;
-       x86_init.mpparse.get_smp_config = x86_init_uint_noop;
+       x86_init.mpparse.find_mptable = x86_init_noop;
+       x86_init.mpparse.early_parse_smp_cfg = x86_init_noop;
+       x86_init.mpparse.parse_smp_cfg = x86_init_noop;
 
        x86_platform.get_wallclock = get_rtc_noop;
        x86_platform.set_wallclock = set_rtc_noop;
@@ -38,6 +44,8 @@ void __init hv_vtl_init_platform(void)
        x86_platform.legacy.warm_reset = 0;
        x86_platform.legacy.reserve_bios_regions = 0;
        x86_platform.legacy.devices.pnpbios = 0;
+
+       x86_init.hyper.msi_ext_dest_id = hv_vtl_msi_ext_dest_id;
 }
 
 static inline u64 hv_vtl_system_desc_base(struct ldttss_desc *desc)
index 7dcbf153ad7257c3fda712df91b3195efe522ab2..768d73de0d098afc5d7a9b6ea1e7c2747aab4feb 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/io.h>
 #include <asm/coco.h>
 #include <asm/mem_encrypt.h>
+#include <asm/set_memory.h>
 #include <asm/mshyperv.h>
 #include <asm/hypervisor.h>
 #include <asm/mtrr.h>
@@ -502,6 +503,31 @@ static int hv_mark_gpa_visibility(u16 count, const u64 pfn[],
                return -EFAULT;
 }
 
+/*
+ * When transitioning memory between encrypted and decrypted, the caller
+ * of set_memory_encrypted() or set_memory_decrypted() is responsible for
+ * ensuring that the memory isn't in use and isn't referenced while the
+ * transition is in progress.  The transition has multiple steps, and the
+ * memory is in an inconsistent state until all steps are complete. A
+ * reference while the state is inconsistent could result in an exception
+ * that can't be cleanly fixed up.
+ *
+ * But the Linux kernel load_unaligned_zeropad() mechanism could cause a
+ * stray reference that can't be prevented by the caller, so Linux has
+ * specific code to handle this case. But when the #VC and #VE exceptions
+ * routed to a paravisor, the specific code doesn't work. To avoid this
+ * problem, mark the pages as "not present" while the transition is in
+ * progress. If load_unaligned_zeropad() causes a stray reference, a normal
+ * page fault is generated instead of #VC or #VE, and the page-fault-based
+ * handlers for load_unaligned_zeropad() resolve the reference.  When the
+ * transition is complete, hv_vtom_set_host_visibility() marks the pages
+ * as "present" again.
+ */
+static bool hv_vtom_clear_present(unsigned long kbuffer, int pagecount, bool enc)
+{
+       return !set_memory_np(kbuffer, pagecount);
+}
+
 /*
  * hv_vtom_set_host_visibility - Set specified memory visible to host.
  *
@@ -515,16 +541,28 @@ static bool hv_vtom_set_host_visibility(unsigned long kbuffer, int pagecount, bo
        enum hv_mem_host_visibility visibility = enc ?
                        VMBUS_PAGE_NOT_VISIBLE : VMBUS_PAGE_VISIBLE_READ_WRITE;
        u64 *pfn_array;
+       phys_addr_t paddr;
+       void *vaddr;
        int ret = 0;
        bool result = true;
        int i, pfn;
 
        pfn_array = kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL);
-       if (!pfn_array)
-               return false;
+       if (!pfn_array) {
+               result = false;
+               goto err_set_memory_p;
+       }
 
        for (i = 0, pfn = 0; i < pagecount; i++) {
-               pfn_array[pfn] = virt_to_hvpfn((void *)kbuffer + i * HV_HYP_PAGE_SIZE);
+               /*
+                * Use slow_virt_to_phys() because the PRESENT bit has been
+                * temporarily cleared in the PTEs.  slow_virt_to_phys() works
+                * without the PRESENT bit while virt_to_hvpfn() or similar
+                * does not.
+                */
+               vaddr = (void *)kbuffer + (i * HV_HYP_PAGE_SIZE);
+               paddr = slow_virt_to_phys(vaddr);
+               pfn_array[pfn] = paddr >> HV_HYP_PAGE_SHIFT;
                pfn++;
 
                if (pfn == HV_MAX_MODIFY_GPA_REP_COUNT || i == pagecount - 1) {
@@ -538,14 +576,30 @@ static bool hv_vtom_set_host_visibility(unsigned long kbuffer, int pagecount, bo
                }
        }
 
- err_free_pfn_array:
+err_free_pfn_array:
        kfree(pfn_array);
+
+err_set_memory_p:
+       /*
+        * Set the PTE PRESENT bits again to revert what hv_vtom_clear_present()
+        * did. Do this even if there is an error earlier in this function in
+        * order to avoid leaving the memory range in a "broken" state. Setting
+        * the PRESENT bits shouldn't fail, but return an error if it does.
+        */
+       if (set_memory_p(kbuffer, pagecount))
+               result = false;
+
        return result;
 }
 
 static bool hv_vtom_tlb_flush_required(bool private)
 {
-       return true;
+       /*
+        * Since hv_vtom_clear_present() marks the PTEs as "not present"
+        * and flushes the TLB, they can't be in the TLB. That makes the
+        * flush controlled by this function redundant, so return "false".
+        */
+       return false;
 }
 
 static bool hv_vtom_cache_flush_required(void)
@@ -608,6 +662,7 @@ void __init hv_vtom_init(void)
        x86_platform.hyper.is_private_mmio = hv_is_private_mmio;
        x86_platform.guest.enc_cache_flush_required = hv_vtom_cache_flush_required;
        x86_platform.guest.enc_tlb_flush_required = hv_vtom_tlb_flush_required;
+       x86_platform.guest.enc_status_change_prepare = hv_vtom_clear_present;
        x86_platform.guest.enc_status_change_finish = hv_vtom_set_host_visibility;
 
        /* Set WB as the default cache mode. */
index 9d159b771dc814a123e77f85ca0793891d16a04d..94ce0f7c9d3a26cd2b766a60042a0b941b3fe0d2 100644 (file)
@@ -46,6 +46,10 @@ extern void x86_32_probe_apic(void);
 static inline void x86_32_probe_apic(void) { }
 #endif
 
+extern u32 cpuid_to_apicid[];
+
+#define CPU_ACPIID_INVALID     U32_MAX
+
 #ifdef CONFIG_X86_LOCAL_APIC
 
 extern int apic_verbosity;
@@ -54,8 +58,6 @@ extern int local_apic_timer_c2_ok;
 extern bool apic_is_disabled;
 extern unsigned int lapic_timer_period;
 
-extern u32 cpuid_to_apicid[];
-
 extern enum apic_intr_mode_id apic_intr_mode;
 enum apic_intr_mode_id {
        APIC_PIC,
@@ -169,6 +171,14 @@ extern bool apic_needs_pit(void);
 
 extern void apic_send_IPI_allbutself(unsigned int vector);
 
+extern void topology_register_apic(u32 apic_id, u32 acpi_id, bool present);
+extern void topology_register_boot_apic(u32 apic_id);
+extern int topology_hotplug_apic(u32 apic_id, u32 acpi_id);
+extern void topology_hotunplug_apic(unsigned int cpu);
+extern void topology_apply_cmdline_limits_early(void);
+extern void topology_init_possible_cpus(void);
+extern void topology_reset_possible_cpus_up(void);
+
 #else /* !CONFIG_X86_LOCAL_APIC */
 static inline void lapic_shutdown(void) { }
 #define local_apic_timer_c2_ok         1
@@ -183,6 +193,8 @@ static inline void apic_intr_mode_init(void) { }
 static inline void lapic_assign_system_vectors(void) { }
 static inline void lapic_assign_legacy_vector(unsigned int i, bool r) { }
 static inline bool apic_needs_pit(void) { return true; }
+static inline void topology_apply_cmdline_limits_early(void) { }
+static inline void topology_init_possible_cpus(void) { }
 #endif /* !CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_X86_X2APIC
@@ -289,16 +301,11 @@ struct apic {
        /* Probe, setup and smpboot functions */
        int     (*probe)(void);
        int     (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id);
-       bool    (*apic_id_registered)(void);
 
-       bool    (*check_apicid_used)(physid_mask_t *map, u32 apicid);
        void    (*init_apic_ldr)(void);
-       void    (*ioapic_phys_id_map)(physid_mask_t *phys_map, physid_mask_t *retmap);
        u32     (*cpu_present_to_apicid)(int mps_cpu);
-       u32     (*phys_pkg_id)(u32 cpuid_apic, int index_msb);
 
        u32     (*get_apic_id)(u32 id);
-       u32     (*set_apic_id)(u32 apicid);
 
        /* wakeup_secondary_cpu */
        int     (*wakeup_secondary_cpu)(u32 apicid, unsigned long start_eip);
@@ -527,7 +534,6 @@ extern int default_apic_id_valid(u32 apicid);
 extern u32 apic_default_calc_apicid(unsigned int cpu);
 extern u32 apic_flat_calc_apicid(unsigned int cpu);
 
-extern void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap);
 extern u32 default_cpu_present_to_apicid(int mps_cpu);
 
 void apic_send_nmi_to_offline_cpu(unsigned int cpu);
index b1a98fa38828e2589416fe4445ed001831009bb0..076bf8dee70264f63d2a4842bca4be9c5f587f7e 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/special_insns.h>
 #include <asm/preempt.h>
 #include <asm/asm.h>
+#include <asm/fred.h>
 #include <asm/gsseg.h>
 
 #ifndef CONFIG_X86_CMPXCHG64
index fbcfec4dc4ccd74d983d84ebad2c6b4d188bde1a..ca8eed1d496ab4630fd65a98d491da491f23e35e 100644 (file)
 
 #endif
 
+#ifndef __ASSEMBLY__
+#ifndef __pic__
+static __always_inline __pure void *rip_rel_ptr(void *p)
+{
+       asm("leaq %c1(%%rip), %0" : "=r"(p) : "i"(p));
+
+       return p;
+}
+#define RIP_REL_REF(var)       (*(typeof(&(var)))rip_rel_ptr(&(var)))
+#else
+#define RIP_REL_REF(var)       (var)
+#endif
+#endif
+
 /*
  * Macros to generate condition code outputs from inline assembly,
  * The output operand must be type "bool".
index 0216f63a366b54db7239f5689e3fa77b54d7f7a8..fe1e7e3cc844a84e08908e44094d020d2fa2107a 100644 (file)
@@ -33,7 +33,7 @@
  * Returns:
  *     0 - (index < size)
  */
-static inline unsigned long array_index_mask_nospec(unsigned long index,
+static __always_inline unsigned long array_index_mask_nospec(unsigned long index,
                unsigned long size)
 {
        unsigned long mask;
index 76c310b19b11d898db11cf498d7c82449bbf7dc2..fb7388bbc212f9b1435b47206ae586cf84505846 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef _ASM_X86_COCO_H
 #define _ASM_X86_COCO_H
 
+#include <asm/asm.h>
 #include <asm/types.h>
 
 enum cc_vendor {
@@ -12,7 +13,13 @@ enum cc_vendor {
 
 #ifdef CONFIG_ARCH_HAS_CC_PLATFORM
 extern enum cc_vendor cc_vendor;
-void cc_set_mask(u64 mask);
+extern u64 cc_mask;
+
+static inline void cc_set_mask(u64 mask)
+{
+       RIP_REL_REF(cc_mask) = mask;
+}
+
 u64 cc_mkenc(u64 val);
 u64 cc_mkdec(u64 val);
 #else
index f8f9a9b7939587b2b8f6e00794e94ea69e6a338a..aa30fd8cad7f5285534c9e4b24e2846d1429f480 100644 (file)
@@ -9,18 +9,10 @@
 #include <linux/percpu.h>
 #include <asm/ibt.h>
 
-#ifdef CONFIG_SMP
-
-extern void prefill_possible_map(void);
-
-#else /* CONFIG_SMP */
-
-static inline void prefill_possible_map(void) {}
-
+#ifndef CONFIG_SMP
 #define cpu_physical_id(cpu)                   boot_cpu_physical_apicid
 #define cpu_acpi_id(cpu)                       0
 #define safe_smp_processor_id()                        0
-
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_HOTPLUG_CPU
index fdf723b6f6d0ce9f6742ef3c67adce3c8d57c002..f0337f7bcf16255c7531b69a6134aa30e295ae3a 100644 (file)
@@ -95,7 +95,7 @@
 #define X86_FEATURE_SYSENTER32         ( 3*32+15) /* "" sysenter in IA32 userspace */
 #define X86_FEATURE_REP_GOOD           ( 3*32+16) /* REP microcode works well */
 #define X86_FEATURE_AMD_LBR_V2         ( 3*32+17) /* AMD Last Branch Record Extension Version 2 */
-/* FREE, was #define X86_FEATURE_LFENCE_RDTSC          ( 3*32+18) "" LFENCE synchronizes RDTSC */
+#define X86_FEATURE_CLEAR_CPU_BUF      ( 3*32+18) /* "" Clear CPU buffers using VERW */
 #define X86_FEATURE_ACC_POWER          ( 3*32+19) /* AMD Accumulated Power Mechanism */
 #define X86_FEATURE_NOPL               ( 3*32+20) /* The NOPL (0F 1F) instructions */
 #define X86_FEATURE_ALWAYS             ( 3*32+21) /* "" Always-present feature */
 #define X86_FEATURE_FZRM               (12*32+10) /* "" Fast zero-length REP MOVSB */
 #define X86_FEATURE_FSRS               (12*32+11) /* "" Fast short REP STOSB */
 #define X86_FEATURE_FSRC               (12*32+12) /* "" Fast short REP {CMPSB,SCASB} */
+#define X86_FEATURE_FRED               (12*32+17) /* Flexible Return and Event Delivery */
 #define X86_FEATURE_LKGS               (12*32+18) /* "" Load "kernel" (userspace) GS */
+#define X86_FEATURE_WRMSRNS            (12*32+19) /* "" Non-serializing WRMSR */
 #define X86_FEATURE_AMX_FP16           (12*32+21) /* "" AMX fp16 Support */
 #define X86_FEATURE_AVX_IFMA            (12*32+23) /* "" Support for VPMADD52[H,L]UQ */
 #define X86_FEATURE_LAM                        (12*32+26) /* Linear Address Masking */
 #define X86_FEATURE_SEV                        (19*32+ 1) /* AMD Secure Encrypted Virtualization */
 #define X86_FEATURE_VM_PAGE_FLUSH      (19*32+ 2) /* "" VM Page Flush MSR is supported */
 #define X86_FEATURE_SEV_ES             (19*32+ 3) /* AMD Secure Encrypted Virtualization - Encrypted State */
+#define X86_FEATURE_SEV_SNP            (19*32+ 4) /* AMD Secure Encrypted Virtualization - Secure Nested Paging */
 #define X86_FEATURE_V_TSC_AUX          (19*32+ 9) /* "" Virtual TSC_AUX */
 #define X86_FEATURE_SME_COHERENT       (19*32+10) /* "" AMD hardware-enforced cache coherency */
 #define X86_FEATURE_DEBUG_SWAP         (19*32+14) /* AMD SEV-ES full debug state swap support */
 /* BUG word 2 */
 #define X86_BUG_SRSO                   X86_BUG(1*32 + 0) /* AMD SRSO bug */
 #define X86_BUG_DIV0                   X86_BUG(1*32 + 1) /* AMD DIV0 speculation bug */
+#define X86_BUG_RFDS                   X86_BUG(1*32 + 2) /* CPU is vulnerable to Register File Data Sampling */
 #endif /* _ASM_X86_CPUFEATURES_H */
index 9bee3e7bf97363e1d9b76438e94b902c8e1baf92..6b122a31da065a22ed660b04f41160d66c705c18 100644 (file)
@@ -127,6 +127,42 @@ static inline unsigned int cpuid_edx(unsigned int op)
        return edx;
 }
 
+static inline void __cpuid_read(unsigned int leaf, unsigned int subleaf, u32 *regs)
+{
+       regs[CPUID_EAX] = leaf;
+       regs[CPUID_ECX] = subleaf;
+       __cpuid(regs + CPUID_EAX, regs + CPUID_EBX, regs + CPUID_ECX, regs + CPUID_EDX);
+}
+
+#define cpuid_subleaf(leaf, subleaf, regs) {           \
+       static_assert(sizeof(*(regs)) == 16);           \
+       __cpuid_read(leaf, subleaf, (u32 *)(regs));     \
+}
+
+#define cpuid_leaf(leaf, regs) {                       \
+       static_assert(sizeof(*(regs)) == 16);           \
+       __cpuid_read(leaf, 0, (u32 *)(regs));           \
+}
+
+static inline void __cpuid_read_reg(unsigned int leaf, unsigned int subleaf,
+                                   enum cpuid_regs_idx regidx, u32 *reg)
+{
+       u32 regs[4];
+
+       __cpuid_read(leaf, subleaf, regs);
+       *reg = regs[regidx];
+}
+
+#define cpuid_subleaf_reg(leaf, subleaf, regidx, reg) {                \
+       static_assert(sizeof(*(reg)) == 4);                     \
+       __cpuid_read_reg(leaf, subleaf, regidx, (u32 *)(reg));  \
+}
+
+#define cpuid_leaf_reg(leaf, regidx, reg) {                    \
+       static_assert(sizeof(*(reg)) == 4);                     \
+       __cpuid_read_reg(leaf, 0, regidx, (u32 *)(reg));        \
+}
+
 static __always_inline bool cpuid_function_is_indexed(u32 function)
 {
        switch (function) {
index dd4b67101bb7ed40013584f66cc80e805ea0ece1..bf5953883ec365377fec5979f6d5c34418ebba32 100644 (file)
@@ -18,7 +18,7 @@ struct pcpu_hot {
                        struct task_struct      *current_task;
                        int                     preempt_count;
                        int                     cpu_number;
-#ifdef CONFIG_CALL_DEPTH_TRACKING
+#ifdef CONFIG_MITIGATION_CALL_DEPTH_TRACKING
                        u64                     call_depth;
 #endif
                        unsigned long           top_of_stack;
@@ -37,8 +37,15 @@ static_assert(sizeof(struct pcpu_hot) == 64);
 
 DECLARE_PER_CPU_ALIGNED(struct pcpu_hot, pcpu_hot);
 
+/* const-qualified alias to pcpu_hot, aliased by linker. */
+DECLARE_PER_CPU_ALIGNED(const struct pcpu_hot __percpu_seg_override,
+                       const_pcpu_hot);
+
 static __always_inline struct task_struct *get_current(void)
 {
+       if (IS_ENABLED(CONFIG_USE_X86_SEG_SUPPORT))
+               return this_cpu_read_const(const_pcpu_hot.current_task);
+
        return this_cpu_read_stable(pcpu_hot.current_task);
 }
 
index 0cec92c430cc9d2fc24307c3e230a06e115c6fa8..fdbbbfec745aa58855641ae59e17a3a50fc2696a 100644 (file)
@@ -5,7 +5,9 @@
 #include <linux/bug.h>
 #include <linux/percpu.h>
 #include <uapi/asm/debugreg.h>
+
 #include <asm/cpufeature.h>
+#include <asm/msr.h>
 
 DECLARE_PER_CPU(unsigned long, cpu_dr7);
 
@@ -159,4 +161,26 @@ static inline unsigned long amd_get_dr_addr_mask(unsigned int dr)
 }
 #endif
 
+static inline unsigned long get_debugctlmsr(void)
+{
+       unsigned long debugctlmsr = 0;
+
+#ifndef CONFIG_X86_DEBUGCTLMSR
+       if (boot_cpu_data.x86 < 6)
+               return 0;
+#endif
+       rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
+
+       return debugctlmsr;
+}
+
+static inline void update_debugctlmsr(unsigned long debugctlmsr)
+{
+#ifndef CONFIG_X86_DEBUGCTLMSR
+       if (boot_cpu_data.x86 < 6)
+               return;
+#endif
+       wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
+}
+
 #endif /* _ASM_X86_DEBUGREG_H */
index ab97b22ac04a263ab78782a9d00f2237c98e0f20..62dc9f59ea768c2022cd4673d5b0e74d2c3d4ce6 100644 (file)
@@ -46,6 +46,7 @@ struct gdt_page {
 } __attribute__((aligned(PAGE_SIZE)));
 
 DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page);
+DECLARE_INIT_PER_CPU(gdt_page);
 
 /* Provide the original GDT */
 static inline struct desc_struct *get_cpu_gdt_rw(unsigned int cpu)
@@ -402,8 +403,6 @@ static inline void set_desc_limit(struct desc_struct *desc, unsigned long limit)
        desc->limit1 = (limit >> 16) & 0xf;
 }
 
-void alloc_intr_gate(unsigned int n, const void *addr);
-
 static inline void init_idt_data(struct idt_data *data, unsigned int n,
                                 const void *addr)
 {
index 702d93fdd10e8d44015cc687cb90106ae5bd422c..da4054fbf533e9d5884066b5fcbbd766822e3a1e 100644 (file)
 # define DISABLE_LA57  (1<<(X86_FEATURE_LA57 & 31))
 #endif
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 # define DISABLE_PTI           0
 #else
 # define DISABLE_PTI           (1 << (X86_FEATURE_PTI & 31))
 #endif
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
 # define DISABLE_RETPOLINE     0
 #else
 # define DISABLE_RETPOLINE     ((1 << (X86_FEATURE_RETPOLINE & 31)) | \
                                 (1 << (X86_FEATURE_RETPOLINE_LFENCE & 31)))
 #endif
 
-#ifdef CONFIG_RETHUNK
+#ifdef CONFIG_MITIGATION_RETHUNK
 # define DISABLE_RETHUNK       0
 #else
 # define DISABLE_RETHUNK       (1 << (X86_FEATURE_RETHUNK & 31))
 #endif
 
-#ifdef CONFIG_CPU_UNRET_ENTRY
+#ifdef CONFIG_MITIGATION_UNRET_ENTRY
 # define DISABLE_UNRET         0
 #else
 # define DISABLE_UNRET         (1 << (X86_FEATURE_UNRET & 31))
 #endif
 
-#ifdef CONFIG_CALL_DEPTH_TRACKING
+#ifdef CONFIG_MITIGATION_CALL_DEPTH_TRACKING
 # define DISABLE_CALL_DEPTH_TRACKING   0
 #else
 # define DISABLE_CALL_DEPTH_TRACKING   (1 << (X86_FEATURE_CALL_DEPTH & 31))
 #define DISABLE_IBT    (1 << (X86_FEATURE_IBT & 31))
 #endif
 
+#ifdef CONFIG_X86_FRED
+# define DISABLE_FRED  0
+#else
+# define DISABLE_FRED  (1 << (X86_FEATURE_FRED & 31))
+#endif
+
+#ifdef CONFIG_KVM_AMD_SEV
+#define DISABLE_SEV_SNP                0
+#else
+#define DISABLE_SEV_SNP                (1 << (X86_FEATURE_SEV_SNP & 31))
+#endif
+
 /*
  * Make sure to add features to the correct mask
  */
 #define DISABLED_MASK10        0
 #define DISABLED_MASK11        (DISABLE_RETPOLINE|DISABLE_RETHUNK|DISABLE_UNRET| \
                         DISABLE_CALL_DEPTH_TRACKING|DISABLE_USER_SHSTK)
-#define DISABLED_MASK12        (DISABLE_LAM)
+#define DISABLED_MASK12        (DISABLE_FRED|DISABLE_LAM)
 #define DISABLED_MASK13        0
 #define DISABLED_MASK14        0
 #define DISABLED_MASK15        0
                         DISABLE_ENQCMD)
 #define DISABLED_MASK17        0
 #define DISABLED_MASK18        (DISABLE_IBT)
-#define DISABLED_MASK19        0
+#define DISABLED_MASK19        (DISABLE_SEV_SNP)
 #define DISABLED_MASK20        0
 #define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 21)
 
index c4555b269a1b247430f50dcf5934855823e1eba6..1dc600fa3ba536e904027df726d4d33360f0fe77 100644 (file)
@@ -143,15 +143,6 @@ extern void efi_free_boot_services(void);
 void arch_efi_call_virt_setup(void);
 void arch_efi_call_virt_teardown(void);
 
-/* kexec external ABI */
-struct efi_setup_data {
-       u64 fw_vendor;
-       u64 __unused;
-       u64 tables;
-       u64 smbios;
-       u64 reserved[8];
-};
-
 extern u64 efi_setup;
 
 #ifdef CONFIG_EFI
@@ -418,8 +409,9 @@ extern int __init efi_memmap_split_count(efi_memory_desc_t *md,
 extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap,
                                     void *buf, struct efi_mem_range *mem);
 
-#define arch_ima_efi_boot_mode \
-       ({ extern struct boot_params boot_params; boot_params.secure_boot; })
+extern enum efi_secureboot_mode __x86_ima_efi_boot_mode(void);
+
+#define arch_ima_efi_boot_mode __x86_ima_efi_boot_mode()
 
 #ifdef CONFIG_EFI_RUNTIME_MAP
 int efi_get_runtime_map_size(void);
index 1e16bd5ac781d8ad734110278d6a47517b685f87..1fb83d47711f97da6f24d14f0bb3b1d9cab55240 100644 (file)
@@ -392,5 +392,4 @@ struct va_alignment {
 } ____cacheline_aligned;
 
 extern struct va_alignment va_align;
-extern unsigned long align_vdso_addr(unsigned long);
 #endif /* _ASM_X86_ELF_H */
index ce8f50192ae3e46da87fe3a24fc736b3b2fc3b21..7e523bb3d2d31a9a8ab9d32ca65a41b5b765c4c4 100644 (file)
@@ -91,7 +91,6 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
 
 static __always_inline void arch_exit_to_user_mode(void)
 {
-       mds_user_clear_cpu_buffers();
        amd_clear_divider();
 }
 #define arch_exit_to_user_mode arch_exit_to_user_mode
index fe6312045042f8ae605e18d2b87b1f25c1dfc510..7acf0383be8022351c9dd1166b3b578a5626954c 100644 (file)
@@ -64,6 +64,8 @@
 #define        EX_TYPE_UCOPY_LEN4              (EX_TYPE_UCOPY_LEN | EX_DATA_IMM(4))
 #define        EX_TYPE_UCOPY_LEN8              (EX_TYPE_UCOPY_LEN | EX_DATA_IMM(8))
 
-#define EX_TYPE_ZEROPAD                        20 /* longword load with zeropad on fault */
+#define        EX_TYPE_ZEROPAD                 20 /* longword load with zeropad on fault */
+
+#define        EX_TYPE_ERETU                   21
 
 #endif
index ca6e5e5f16b2eca0e02222956951c628b556ec50..c485f1944c5f86a0ab0ecad38ce0e5bb65569bb8 100644 (file)
@@ -37,10 +37,12 @@ extern void fpu_flush_thread(void);
  * The FPU context is only stored/restored for a user task and
  * PF_KTHREAD is used to distinguish between kernel and user threads.
  */
-static inline void switch_fpu_prepare(struct fpu *old_fpu, int cpu)
+static inline void switch_fpu_prepare(struct task_struct *old, int cpu)
 {
        if (cpu_feature_enabled(X86_FEATURE_FPU) &&
-           !(current->flags & (PF_KTHREAD | PF_USER_WORKER))) {
+           !(old->flags & (PF_KTHREAD | PF_USER_WORKER))) {
+               struct fpu *old_fpu = &old->thread.fpu;
+
                save_fpregs_to_fpstate(old_fpu);
                /*
                 * The save operation preserved register state, so the
@@ -60,10 +62,10 @@ static inline void switch_fpu_prepare(struct fpu *old_fpu, int cpu)
  * Delay loading of the complete FPU state until the return to userland.
  * PKRU is handled separately.
  */
-static inline void switch_fpu_finish(void)
+static inline void switch_fpu_finish(struct task_struct *new)
 {
        if (cpu_feature_enabled(X86_FEATURE_FPU))
-               set_thread_flag(TIF_NEED_FPU_LOAD);
+               set_tsk_thread_flag(new, TIF_NEED_FPU_LOAD);
 }
 
 #endif /* _ASM_X86_FPU_SCHED_H */
diff --git a/arch/x86/include/asm/fred.h b/arch/x86/include/asm/fred.h
new file mode 100644 (file)
index 0000000..e86c7ba
--- /dev/null
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Macros for Flexible Return and Event Delivery (FRED)
+ */
+
+#ifndef ASM_X86_FRED_H
+#define ASM_X86_FRED_H
+
+#include <linux/const.h>
+
+#include <asm/asm.h>
+#include <asm/trapnr.h>
+
+/*
+ * FRED event return instruction opcodes for ERET{S,U}; supported in
+ * binutils >= 2.41.
+ */
+#define ERETS                  _ASM_BYTES(0xf2,0x0f,0x01,0xca)
+#define ERETU                  _ASM_BYTES(0xf3,0x0f,0x01,0xca)
+
+/*
+ * RSP is aligned to a 64-byte boundary before used to push a new stack frame
+ */
+#define FRED_STACK_FRAME_RSP_MASK      _AT(unsigned long, (~0x3f))
+
+/*
+ * Used for the return address for call emulation during code patching,
+ * and measured in 64-byte cache lines.
+ */
+#define FRED_CONFIG_REDZONE_AMOUNT     1
+#define FRED_CONFIG_REDZONE            (_AT(unsigned long, FRED_CONFIG_REDZONE_AMOUNT) << 6)
+#define FRED_CONFIG_INT_STKLVL(l)      (_AT(unsigned long, l) << 9)
+#define FRED_CONFIG_ENTRYPOINT(p)      _AT(unsigned long, (p))
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_X86_FRED
+#include <linux/kernel.h>
+
+#include <asm/ptrace.h>
+
+struct fred_info {
+       /* Event data: CR2, DR6, ... */
+       unsigned long edata;
+       unsigned long resv;
+};
+
+/* Full format of the FRED stack frame */
+struct fred_frame {
+       struct pt_regs   regs;
+       struct fred_info info;
+};
+
+static __always_inline struct fred_info *fred_info(struct pt_regs *regs)
+{
+       return &container_of(regs, struct fred_frame, regs)->info;
+}
+
+static __always_inline unsigned long fred_event_data(struct pt_regs *regs)
+{
+       return fred_info(regs)->edata;
+}
+
+void asm_fred_entrypoint_user(void);
+void asm_fred_entrypoint_kernel(void);
+void asm_fred_entry_from_kvm(struct fred_ss);
+
+__visible void fred_entry_from_user(struct pt_regs *regs);
+__visible void fred_entry_from_kernel(struct pt_regs *regs);
+__visible void __fred_entry_from_kvm(struct pt_regs *regs);
+
+/* Can be called from noinstr code, thus __always_inline */
+static __always_inline void fred_entry_from_kvm(unsigned int type, unsigned int vector)
+{
+       struct fred_ss ss = {
+               .ss     =__KERNEL_DS,
+               .type   = type,
+               .vector = vector,
+               .nmi    = type == EVENT_TYPE_NMI,
+               .lm     = 1,
+       };
+
+       asm_fred_entry_from_kvm(ss);
+}
+
+void cpu_init_fred_exceptions(void);
+void fred_complete_exception_setup(void);
+
+#else /* CONFIG_X86_FRED */
+static __always_inline unsigned long fred_event_data(struct pt_regs *regs) { return 0; }
+static inline void cpu_init_fred_exceptions(void) { }
+static inline void fred_complete_exception_setup(void) { }
+static __always_inline void fred_entry_from_kvm(unsigned int type, unsigned int vector) { }
+#endif /* CONFIG_X86_FRED */
+#endif /* !__ASSEMBLY__ */
+
+#endif /* ASM_X86_FRED_H */
index 35cff5f2becf6bcbbdc34a890f29d3ba197e100d..9e7e8ca8e2997727d733cc5db3b64ac330e30bc8 100644 (file)
@@ -6,7 +6,7 @@
 
 #ifdef CONFIG_X86_64
 
-#include <asm/msr-index.h>
+#include <asm/msr.h>
 
 /*
  * Read/write a task's FSBASE or GSBASE. This returns the value that
index b02c3cd3c0f6564ad374602995c08d9082942744..edebf1020e0497ff0d424fc7b35c450cbd34e164 100644 (file)
@@ -16,8 +16,6 @@
 
 #include <asm/irq_vectors.h>
 
-#define IRQ_MATRIX_BITS                NR_VECTORS
-
 #ifndef __ASSEMBLY__
 
 #include <linux/percpu.h>
index c7ef6ea2fa993c78864f460dace8ef86ad246b16..4212c00c9708d49253d8ebe3699578f14476408a 100644 (file)
@@ -69,7 +69,7 @@ extern void ia32_pick_mmap_layout(struct mm_struct *mm);
 
 extern bool __ia32_enabled;
 
-static inline bool ia32_enabled(void)
+static __always_inline bool ia32_enabled(void)
 {
        return __ia32_enabled;
 }
@@ -81,7 +81,7 @@ static inline void ia32_disable(void)
 
 #else /* !CONFIG_IA32_EMULATION */
 
-static inline bool ia32_enabled(void)
+static __always_inline bool ia32_enabled(void)
 {
        return IS_ENABLED(CONFIG_X86_32);
 }
index 13639e57e1f8af4c24c0c656a9f0801516bf25f4..47d4c04d103df4eb824fef8297f0b77c39dee1c1 100644 (file)
 
 #include <asm/irq_stack.h>
 
+typedef void (*idtentry_t)(struct pt_regs *regs);
+
 /**
  * DECLARE_IDTENTRY - Declare functions for simple IDT entry points
  *                   No error code pushed by hardware
  * @vector:    Vector number (ignored for C)
  * @func:      Function name of the entry point
  *
- * Declares three functions:
+ * Declares four functions:
  * - The ASM entry point: asm_##func
  * - The XEN PV trap entry point: xen_##func (maybe unused)
+ * - The C handler called from the FRED event dispatcher (maybe unused)
  * - The C handler called from the ASM entry point
  *
  * Note: This is the C variant of DECLARE_IDTENTRY(). As the name says it
@@ -31,6 +34,7 @@
 #define DECLARE_IDTENTRY(vector, func)                                 \
        asmlinkage void asm_##func(void);                               \
        asmlinkage void xen_asm_##func(void);                           \
+       void fred_##func(struct pt_regs *regs);                         \
        __visible void func(struct pt_regs *regs)
 
 /**
@@ -137,6 +141,17 @@ static __always_inline void __##func(struct pt_regs *regs,         \
 #define DEFINE_IDTENTRY_RAW(func)                                      \
 __visible noinstr void func(struct pt_regs *regs)
 
+/**
+ * DEFINE_FREDENTRY_RAW - Emit code for raw FRED entry points
+ * @func:      Function name of the entry point
+ *
+ * @func is called from the FRED event dispatcher with interrupts disabled.
+ *
+ * See @DEFINE_IDTENTRY_RAW for further details.
+ */
+#define DEFINE_FREDENTRY_RAW(func)                                     \
+noinstr void fred_##func(struct pt_regs *regs)
+
 /**
  * DECLARE_IDTENTRY_RAW_ERRORCODE - Declare functions for raw IDT entry points
  *                                 Error code pushed by hardware
@@ -233,17 +248,27 @@ static noinline void __##func(struct pt_regs *regs, u32 vector)
 #define DEFINE_IDTENTRY_SYSVEC(func)                                   \
 static void __##func(struct pt_regs *regs);                            \
                                                                        \
+static __always_inline void instr_##func(struct pt_regs *regs)         \
+{                                                                      \
+       kvm_set_cpu_l1tf_flush_l1d();                                   \
+       run_sysvec_on_irqstack_cond(__##func, regs);                    \
+}                                                                      \
+                                                                       \
 __visible noinstr void func(struct pt_regs *regs)                      \
 {                                                                      \
        irqentry_state_t state = irqentry_enter(regs);                  \
                                                                        \
        instrumentation_begin();                                        \
-       kvm_set_cpu_l1tf_flush_l1d();                                   \
-       run_sysvec_on_irqstack_cond(__##func, regs);                    \
+       instr_##func (regs);                                            \
        instrumentation_end();                                          \
        irqentry_exit(regs, state);                                     \
 }                                                                      \
                                                                        \
+void fred_##func(struct pt_regs *regs)                                 \
+{                                                                      \
+       instr_##func (regs);                                            \
+}                                                                      \
+                                                                       \
 static noinline void __##func(struct pt_regs *regs)
 
 /**
@@ -260,19 +285,29 @@ static noinline void __##func(struct pt_regs *regs)
 #define DEFINE_IDTENTRY_SYSVEC_SIMPLE(func)                            \
 static __always_inline void __##func(struct pt_regs *regs);            \
                                                                        \
-__visible noinstr void func(struct pt_regs *regs)                      \
+static __always_inline void instr_##func(struct pt_regs *regs)         \
 {                                                                      \
-       irqentry_state_t state = irqentry_enter(regs);                  \
-                                                                       \
-       instrumentation_begin();                                        \
        __irq_enter_raw();                                              \
        kvm_set_cpu_l1tf_flush_l1d();                                   \
        __##func (regs);                                                \
        __irq_exit_raw();                                               \
+}                                                                      \
+                                                                       \
+__visible noinstr void func(struct pt_regs *regs)                      \
+{                                                                      \
+       irqentry_state_t state = irqentry_enter(regs);                  \
+                                                                       \
+       instrumentation_begin();                                        \
+       instr_##func (regs);                                            \
        instrumentation_end();                                          \
        irqentry_exit(regs, state);                                     \
 }                                                                      \
                                                                        \
+void fred_##func(struct pt_regs *regs)                                 \
+{                                                                      \
+       instr_##func (regs);                                            \
+}                                                                      \
+                                                                       \
 static __always_inline void __##func(struct pt_regs *regs)
 
 /**
@@ -410,17 +445,35 @@ __visible noinstr void func(struct pt_regs *regs,                 \
 /* C-Code mapping */
 #define DECLARE_IDTENTRY_NMI           DECLARE_IDTENTRY_RAW
 #define DEFINE_IDTENTRY_NMI            DEFINE_IDTENTRY_RAW
+#define DEFINE_FREDENTRY_NMI           DEFINE_FREDENTRY_RAW
 
 #ifdef CONFIG_X86_64
 #define DECLARE_IDTENTRY_MCE           DECLARE_IDTENTRY_IST
 #define DEFINE_IDTENTRY_MCE            DEFINE_IDTENTRY_IST
 #define DEFINE_IDTENTRY_MCE_USER       DEFINE_IDTENTRY_NOIST
+#define DEFINE_FREDENTRY_MCE           DEFINE_FREDENTRY_RAW
 
 #define DECLARE_IDTENTRY_DEBUG         DECLARE_IDTENTRY_IST
 #define DEFINE_IDTENTRY_DEBUG          DEFINE_IDTENTRY_IST
 #define DEFINE_IDTENTRY_DEBUG_USER     DEFINE_IDTENTRY_NOIST
+#define DEFINE_FREDENTRY_DEBUG         DEFINE_FREDENTRY_RAW
+#endif
+
+void idt_install_sysvec(unsigned int n, const void *function);
+
+#ifdef CONFIG_X86_FRED
+void fred_install_sysvec(unsigned int vector, const idtentry_t function);
+#else
+static inline void fred_install_sysvec(unsigned int vector, const idtentry_t function) { }
 #endif
 
+#define sysvec_install(vector, function) {                             \
+       if (cpu_feature_enabled(X86_FEATURE_FRED))                      \
+               fred_install_sysvec(vector, function);                  \
+       else                                                            \
+               idt_install_sysvec(vector, asm_##function);             \
+}
+
 #else /* !__ASSEMBLY__ */
 
 /*
@@ -447,7 +500,7 @@ __visible noinstr void func(struct pt_regs *regs,                   \
 
 /* System vector entries */
 #define DECLARE_IDTENTRY_SYSVEC(vector, func)                          \
-       idtentry_sysvec vector func
+       DECLARE_IDTENTRY(vector, func)
 
 #ifdef CONFIG_X86_64
 # define DECLARE_IDTENTRY_MCE(vector, func)                            \
@@ -655,23 +708,36 @@ DECLARE_IDTENTRY(RESCHEDULE_VECTOR,                       sysvec_reschedule_ipi);
 DECLARE_IDTENTRY_SYSVEC(REBOOT_VECTOR,                 sysvec_reboot);
 DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_SINGLE_VECTOR,   sysvec_call_function_single);
 DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_VECTOR,          sysvec_call_function);
+#else
+# define fred_sysvec_reschedule_ipi                    NULL
+# define fred_sysvec_reboot                            NULL
+# define fred_sysvec_call_function_single              NULL
+# define fred_sysvec_call_function                     NULL
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
 # ifdef CONFIG_X86_MCE_THRESHOLD
 DECLARE_IDTENTRY_SYSVEC(THRESHOLD_APIC_VECTOR,         sysvec_threshold);
+# else
+# define fred_sysvec_threshold                         NULL
 # endif
 
 # ifdef CONFIG_X86_MCE_AMD
 DECLARE_IDTENTRY_SYSVEC(DEFERRED_ERROR_VECTOR,         sysvec_deferred_error);
+# else
+# define fred_sysvec_deferred_error                    NULL
 # endif
 
 # ifdef CONFIG_X86_THERMAL_VECTOR
 DECLARE_IDTENTRY_SYSVEC(THERMAL_APIC_VECTOR,           sysvec_thermal);
+# else
+# define fred_sysvec_thermal                           NULL
 # endif
 
 # ifdef CONFIG_IRQ_WORK
 DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR,               sysvec_irq_work);
+# else
+# define fred_sysvec_irq_work                          NULL
 # endif
 #endif
 
@@ -679,12 +745,16 @@ DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR,          sysvec_irq_work);
 DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_VECTOR,            sysvec_kvm_posted_intr_ipi);
 DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_WAKEUP_VECTOR,     sysvec_kvm_posted_intr_wakeup_ipi);
 DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR,     sysvec_kvm_posted_intr_nested_ipi);
+#else
+# define fred_sysvec_kvm_posted_intr_ipi               NULL
+# define fred_sysvec_kvm_posted_intr_wakeup_ipi                NULL
+# define fred_sysvec_kvm_posted_intr_nested_ipi                NULL
 #endif
 
 #if IS_ENABLED(CONFIG_HYPERV)
 DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR,    sysvec_hyperv_callback);
 DECLARE_IDTENTRY_SYSVEC(HYPERV_REENLIGHTENMENT_VECTOR, sysvec_hyperv_reenlightenment);
-DECLARE_IDTENTRY_SYSVEC(HYPERV_STIMER0_VECTOR, sysvec_hyperv_stimer0);
+DECLARE_IDTENTRY_SYSVEC(HYPERV_STIMER0_VECTOR,         sysvec_hyperv_stimer0);
 #endif
 
 #if IS_ENABLED(CONFIG_ACRN_GUEST)
index 3814a9263d64eaa7b7ceeb696582b5584699940b..294cd2a40818129a1032f24b7d3ba89a99258e23 100644 (file)
@@ -379,7 +379,7 @@ static inline void iosubmit_cmds512(void __iomem *dst, const void *src,
        const u8 *end = from + count * 64;
 
        while (from < end) {
-               movdir64b(dst, from);
+               movdir64b_io(dst, from);
                from += 64;
        }
 }
index 51c782600e0260054ffab6121a0afbcede078de0..0d806513c4b32a103a6f36c2286bd9dc4deec091 100644 (file)
@@ -140,7 +140,6 @@ extern void mask_ioapic_entries(void);
 extern int restore_ioapic_entries(void);
 
 extern void setup_ioapic_ids_from_mpc(void);
-extern void setup_ioapic_ids_from_mpc_nocheck(void);
 
 extern int mp_find_ioapic(u32 gsi);
 extern int mp_find_ioapic_pin(int ioapic, u32 gsi);
index 2fd52b65deac104c97cd5b4dc30360633b7568aa..3be2451e7bc857683ab4aa9481d010c9a79eb137 100644 (file)
@@ -10,6 +10,7 @@ extern int force_iommu, no_iommu;
 extern int iommu_detected;
 extern int iommu_merge;
 extern int panic_on_overflow;
+extern bool amd_iommu_snp_en;
 
 #ifdef CONFIG_SWIOTLB
 extern bool x86_swiotlb_enable;
index c9f6a6c5de3cf6c72f53a62e25c0c548df85b28e..91ca9a9ee3a2b26a964254202c53ffb5ca544d3a 100644 (file)
@@ -25,7 +25,6 @@
 
 #include <asm/page.h>
 #include <asm/ptrace.h>
-#include <asm/bootparam.h>
 
 struct kimage;
 
index 378ed944b849fb0448a13bd7f12a7a542ab7e388..ab24ce2079889b8687651a22b48bcd64addde031 100644 (file)
@@ -138,6 +138,7 @@ KVM_X86_OP(complete_emulated_msr)
 KVM_X86_OP(vcpu_deliver_sipi_vector)
 KVM_X86_OP_OPTIONAL_RET0(vcpu_get_apicv_inhibit_reasons);
 KVM_X86_OP_OPTIONAL(get_untagged_addr)
+KVM_X86_OP_OPTIONAL(alloc_apic_backing_page)
 
 #undef KVM_X86_OP
 #undef KVM_X86_OP_OPTIONAL
index d271ba20a0b214104a1f11832a1007f5bb35190e..18cbde14cf81091b880f018548800515c9a20a7c 100644 (file)
@@ -1796,6 +1796,7 @@ struct kvm_x86_ops {
        unsigned long (*vcpu_get_apicv_inhibit_reasons)(struct kvm_vcpu *vcpu);
 
        gva_t (*get_untagged_addr)(struct kvm_vcpu *vcpu, gva_t gva, unsigned int flags);
+       void *(*alloc_apic_backing_page)(struct kvm_vcpu *vcpu);
 };
 
 struct kvm_x86_nested_ops {
index 511b350691876dc1572183f60c282f22423494fc..f163176d6f7ffc580f0bc6f342ec741ebecaa9a5 100644 (file)
@@ -4,8 +4,6 @@
 
 #include <linux/percpu.h>
 
-extern struct clocksource kvm_clock;
-
 DECLARE_PER_CPU(struct pvclock_vsyscall_time_info *, hv_clock_per_cpu);
 
 static __always_inline struct pvclock_vcpu_time_info *this_cpu_pvti(void)
index 571fe4d2d2328c3b4899faf8085e0181403ed003..dc31b13b87a0d17020aaf2d3915da366b1b62d59 100644 (file)
 
 #ifdef __ASSEMBLY__
 
-#if defined(CONFIG_RETHUNK) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
+#if defined(CONFIG_MITIGATION_RETHUNK) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
 #define RET    jmp __x86_return_thunk
-#else /* CONFIG_RETPOLINE */
-#ifdef CONFIG_SLS
+#else /* CONFIG_MITIGATION_RETPOLINE */
+#ifdef CONFIG_MITIGATION_SLS
 #define RET    ret; int3
 #else
 #define RET    ret
 #endif
-#endif /* CONFIG_RETPOLINE */
+#endif /* CONFIG_MITIGATION_RETPOLINE */
 
 #else /* __ASSEMBLY__ */
 
-#if defined(CONFIG_RETHUNK) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
+#if defined(CONFIG_MITIGATION_RETHUNK) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
 #define ASM_RET        "jmp __x86_return_thunk\n\t"
-#else /* CONFIG_RETPOLINE */
-#ifdef CONFIG_SLS
+#else /* CONFIG_MITIGATION_RETPOLINE */
+#ifdef CONFIG_MITIGATION_SLS
 #define ASM_RET        "ret; int3\n\t"
 #else
 #define ASM_RET        "ret\n\t"
 #endif
-#endif /* CONFIG_RETPOLINE */
+#endif /* CONFIG_MITIGATION_RETPOLINE */
 
 #endif /* __ASSEMBLY__ */
 
index 73dba8b9444308d603e5e5db6b76d412aea6b3b5..59aa966dc2127c61be2e3bbe443516a54e70c725 100644 (file)
@@ -131,8 +131,20 @@ static inline bool local_try_cmpxchg(local_t *l, long *old, long new)
                                 (typeof(l->a.counter) *) old, new);
 }
 
-/* Always has a lock prefix */
-#define local_xchg(l, n) (xchg(&((l)->a.counter), (n)))
+/*
+ * Implement local_xchg using CMPXCHG instruction without the LOCK prefix.
+ * XCHG is expensive due to the implied LOCK prefix.  The processor
+ * cannot prefetch cachelines if XCHG is used.
+ */
+static __always_inline long
+local_xchg(local_t *l, long n)
+{
+       long c = local_read(l);
+
+       do { } while (!local_try_cmpxchg(l, &c, n));
+
+       return c;
+}
 
 /**
  * local_add_unless - add unless the number is already a given value
index 359ada486fa92da37dfe77b1958a066612a42e4b..f922b682b9b4c54fa5acad68c248c7345f9f38bb 100644 (file)
@@ -15,7 +15,8 @@
 #include <linux/init.h>
 #include <linux/cc_platform.h>
 
-#include <asm/bootparam.h>
+#include <asm/asm.h>
+struct boot_params;
 
 #ifdef CONFIG_X86_MEM_ENCRYPT
 void __init mem_encrypt_init(void);
@@ -46,8 +47,8 @@ void __init sme_unmap_bootdata(char *real_mode_data);
 
 void __init sme_early_init(void);
 
-void __init sme_encrypt_kernel(struct boot_params *bp);
-void __init sme_enable(struct boot_params *bp);
+void sme_encrypt_kernel(struct boot_params *bp);
+void sme_enable(struct boot_params *bp);
 
 int __init early_set_memory_decrypted(unsigned long vaddr, unsigned long size);
 int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size);
@@ -58,6 +59,11 @@ void __init mem_encrypt_free_decrypted_mem(void);
 
 void __init sev_es_init_vc_handling(void);
 
+static inline u64 sme_get_me_mask(void)
+{
+       return RIP_REL_REF(sme_me_mask);
+}
+
 #define __bss_decrypted __section(".bss..decrypted")
 
 #else  /* !CONFIG_AMD_MEM_ENCRYPT */
@@ -75,8 +81,8 @@ static inline void __init sme_unmap_bootdata(char *real_mode_data) { }
 
 static inline void __init sme_early_init(void) { }
 
-static inline void __init sme_encrypt_kernel(struct boot_params *bp) { }
-static inline void __init sme_enable(struct boot_params *bp) { }
+static inline void sme_encrypt_kernel(struct boot_params *bp) { }
+static inline void sme_enable(struct boot_params *bp) { }
 
 static inline void sev_es_init_vc_handling(void) { }
 
@@ -89,6 +95,8 @@ early_set_mem_enc_dec_hypercall(unsigned long vaddr, unsigned long size, bool en
 
 static inline void mem_encrypt_free_decrypted_mem(void) { }
 
+static inline u64 sme_get_me_mask(void) { return 0; }
+
 #define __bss_decrypted
 
 #endif /* CONFIG_AMD_MEM_ENCRYPT */
@@ -106,11 +114,6 @@ void add_encrypt_protection_map(void);
 
 extern char __start_bss_decrypted[], __end_bss_decrypted[], __start_bss_decrypted_unused[];
 
-static inline u64 sme_get_me_mask(void)
-{
-       return sme_me_mask;
-}
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __X86_MEM_ENCRYPT_H__ */
index 4b0f98a8d338d5c56371e4af161ae335cde7528a..c72c7ff78fcdc141e965910a89565a06a2a13027 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef _ASM_X86_MPSPEC_H
 #define _ASM_X86_MPSPEC_H
 
+#include <linux/types.h>
 
 #include <asm/mpspec_def.h>
 #include <asm/x86_init.h>
@@ -46,70 +47,31 @@ extern int smp_found_config;
 # define smp_found_config 0
 #endif
 
-static inline void get_smp_config(void)
-{
-       x86_init.mpparse.get_smp_config(0);
-}
-
-static inline void early_get_smp_config(void)
-{
-       x86_init.mpparse.get_smp_config(1);
-}
-
-static inline void find_smp_config(void)
-{
-       x86_init.mpparse.find_smp_config();
-}
-
 #ifdef CONFIG_X86_MPPARSE
 extern void e820__memblock_alloc_reserved_mpc_new(void);
 extern int enable_update_mptable;
-extern void default_find_smp_config(void);
-extern void default_get_smp_config(unsigned int early);
+extern void mpparse_find_mptable(void);
+extern void mpparse_parse_early_smp_config(void);
+extern void mpparse_parse_smp_config(void);
 #else
 static inline void e820__memblock_alloc_reserved_mpc_new(void) { }
-#define enable_update_mptable 0
-#define default_find_smp_config x86_init_noop
-#define default_get_smp_config x86_init_uint_noop
+#define enable_update_mptable          0
+#define mpparse_find_mptable           x86_init_noop
+#define mpparse_parse_early_smp_config x86_init_noop
+#define mpparse_parse_smp_config       x86_init_noop
 #endif
 
-int generic_processor_info(int apicid);
+extern DECLARE_BITMAP(phys_cpu_present_map, MAX_LOCAL_APIC);
 
-#define PHYSID_ARRAY_SIZE      BITS_TO_LONGS(MAX_LOCAL_APIC)
-
-struct physid_mask {
-       unsigned long mask[PHYSID_ARRAY_SIZE];
-};
-
-typedef struct physid_mask physid_mask_t;
-
-#define physid_set(physid, map)                        set_bit(physid, (map).mask)
-#define physid_isset(physid, map)              test_bit(physid, (map).mask)
-
-#define physids_or(dst, src1, src2)                                    \
-       bitmap_or((dst).mask, (src1).mask, (src2).mask, MAX_LOCAL_APIC)
-
-#define physids_clear(map)                                     \
-       bitmap_zero((map).mask, MAX_LOCAL_APIC)
-
-#define physids_empty(map)                                     \
-       bitmap_empty((map).mask, MAX_LOCAL_APIC)
-
-static inline void physids_promote(unsigned long physids, physid_mask_t *map)
+static inline void reset_phys_cpu_present_map(u32 apicid)
 {
-       physids_clear(*map);
-       map->mask[0] = physids;
+       bitmap_zero(phys_cpu_present_map, MAX_LOCAL_APIC);
+       set_bit(apicid, phys_cpu_present_map);
 }
 
-static inline void physid_set_mask_of_physid(int physid, physid_mask_t *map)
+static inline void copy_phys_cpu_present_map(unsigned long *dst)
 {
-       physids_clear(*map);
-       physid_set(physid, *map);
+       bitmap_copy(dst, phys_cpu_present_map, MAX_LOCAL_APIC);
 }
 
-#define PHYSID_MASK_ALL                { {[0 ... PHYSID_ARRAY_SIZE-1] = ~0UL} }
-#define PHYSID_MASK_NONE       { {[0 ... PHYSID_ARRAY_SIZE-1] = 0UL} }
-
-extern physid_mask_t phys_cpu_present_map;
-
 #endif /* _ASM_X86_MPSPEC_H */
index f1bd7b91b3c63735738825f15cd3c82fca7579ce..05956bd8bacf50e35f463c13720a38735fe8b1b5 100644 (file)
 #define EFER_FFXSR             (1<<_EFER_FFXSR)
 #define EFER_AUTOIBRS          (1<<_EFER_AUTOIBRS)
 
-/* Intel MSRs. Some also available on other CPUs */
+/* FRED MSRs */
+#define MSR_IA32_FRED_RSP0     0x1cc                   /* Level 0 stack pointer */
+#define MSR_IA32_FRED_RSP1     0x1cd                   /* Level 1 stack pointer */
+#define MSR_IA32_FRED_RSP2     0x1ce                   /* Level 2 stack pointer */
+#define MSR_IA32_FRED_RSP3     0x1cf                   /* Level 3 stack pointer */
+#define MSR_IA32_FRED_STKLVLS  0x1d0                   /* Exception stack levels */
+#define MSR_IA32_FRED_SSP0     MSR_IA32_PL0_SSP        /* Level 0 shadow stack pointer */
+#define MSR_IA32_FRED_SSP1     0x1d1                   /* Level 1 shadow stack pointer */
+#define MSR_IA32_FRED_SSP2     0x1d2                   /* Level 2 shadow stack pointer */
+#define MSR_IA32_FRED_SSP3     0x1d3                   /* Level 3 shadow stack pointer */
+#define MSR_IA32_FRED_CONFIG   0x1d4                   /* Entrypoint and interrupt stack level */
 
+/* Intel MSRs. Some also available on other CPUs */
 #define MSR_TEST_CTRL                          0x00000033
 #define MSR_TEST_CTRL_SPLIT_LOCK_DETECT_BIT    29
 #define MSR_TEST_CTRL_SPLIT_LOCK_DETECT                BIT(MSR_TEST_CTRL_SPLIT_LOCK_DETECT_BIT)
                                                 * CPU is not vulnerable to Gather
                                                 * Data Sampling (GDS).
                                                 */
+#define ARCH_CAP_RFDS_NO               BIT(27) /*
+                                                * Not susceptible to Register
+                                                * File Data Sampling.
+                                                */
+#define ARCH_CAP_RFDS_CLEAR            BIT(28) /*
+                                                * VERW clears CPU Register
+                                                * File.
+                                                */
 
 #define ARCH_CAP_XAPIC_DISABLE         BIT(21) /*
                                                 * IA32_XAPIC_DISABLE_STATUS MSR
 #define MSR_AMD64_SEV_ES_GHCB          0xc0010130
 #define MSR_AMD64_SEV                  0xc0010131
 #define MSR_AMD64_SEV_ENABLED_BIT      0
-#define MSR_AMD64_SEV_ES_ENABLED_BIT   1
-#define MSR_AMD64_SEV_SNP_ENABLED_BIT  2
 #define MSR_AMD64_SEV_ENABLED          BIT_ULL(MSR_AMD64_SEV_ENABLED_BIT)
+#define MSR_AMD64_SEV_ES_ENABLED_BIT   1
 #define MSR_AMD64_SEV_ES_ENABLED       BIT_ULL(MSR_AMD64_SEV_ES_ENABLED_BIT)
+#define MSR_AMD64_SEV_SNP_ENABLED_BIT  2
 #define MSR_AMD64_SEV_SNP_ENABLED      BIT_ULL(MSR_AMD64_SEV_SNP_ENABLED_BIT)
-
-/* SNP feature bits enabled by the hypervisor */
-#define MSR_AMD64_SNP_VTOM                     BIT_ULL(3)
-#define MSR_AMD64_SNP_REFLECT_VC               BIT_ULL(4)
-#define MSR_AMD64_SNP_RESTRICTED_INJ           BIT_ULL(5)
-#define MSR_AMD64_SNP_ALT_INJ                  BIT_ULL(6)
-#define MSR_AMD64_SNP_DEBUG_SWAP               BIT_ULL(7)
-#define MSR_AMD64_SNP_PREVENT_HOST_IBS         BIT_ULL(8)
-#define MSR_AMD64_SNP_BTB_ISOLATION            BIT_ULL(9)
-#define MSR_AMD64_SNP_VMPL_SSS                 BIT_ULL(10)
-#define MSR_AMD64_SNP_SECURE_TSC               BIT_ULL(11)
-#define MSR_AMD64_SNP_VMGEXIT_PARAM            BIT_ULL(12)
-#define MSR_AMD64_SNP_IBS_VIRT                 BIT_ULL(14)
-#define MSR_AMD64_SNP_VMSA_REG_PROTECTION      BIT_ULL(16)
-#define MSR_AMD64_SNP_SMT_PROTECTION           BIT_ULL(17)
-
-/* SNP feature bits reserved for future use. */
-#define MSR_AMD64_SNP_RESERVED_BIT13           BIT_ULL(13)
-#define MSR_AMD64_SNP_RESERVED_BIT15           BIT_ULL(15)
-#define MSR_AMD64_SNP_RESERVED_MASK            GENMASK_ULL(63, 18)
+#define MSR_AMD64_SNP_VTOM_BIT         3
+#define MSR_AMD64_SNP_VTOM             BIT_ULL(MSR_AMD64_SNP_VTOM_BIT)
+#define MSR_AMD64_SNP_REFLECT_VC_BIT   4
+#define MSR_AMD64_SNP_REFLECT_VC       BIT_ULL(MSR_AMD64_SNP_REFLECT_VC_BIT)
+#define MSR_AMD64_SNP_RESTRICTED_INJ_BIT 5
+#define MSR_AMD64_SNP_RESTRICTED_INJ   BIT_ULL(MSR_AMD64_SNP_RESTRICTED_INJ_BIT)
+#define MSR_AMD64_SNP_ALT_INJ_BIT      6
+#define MSR_AMD64_SNP_ALT_INJ          BIT_ULL(MSR_AMD64_SNP_ALT_INJ_BIT)
+#define MSR_AMD64_SNP_DEBUG_SWAP_BIT   7
+#define MSR_AMD64_SNP_DEBUG_SWAP       BIT_ULL(MSR_AMD64_SNP_DEBUG_SWAP_BIT)
+#define MSR_AMD64_SNP_PREVENT_HOST_IBS_BIT 8
+#define MSR_AMD64_SNP_PREVENT_HOST_IBS BIT_ULL(MSR_AMD64_SNP_PREVENT_HOST_IBS_BIT)
+#define MSR_AMD64_SNP_BTB_ISOLATION_BIT        9
+#define MSR_AMD64_SNP_BTB_ISOLATION    BIT_ULL(MSR_AMD64_SNP_BTB_ISOLATION_BIT)
+#define MSR_AMD64_SNP_VMPL_SSS_BIT     10
+#define MSR_AMD64_SNP_VMPL_SSS         BIT_ULL(MSR_AMD64_SNP_VMPL_SSS_BIT)
+#define MSR_AMD64_SNP_SECURE_TSC_BIT   11
+#define MSR_AMD64_SNP_SECURE_TSC       BIT_ULL(MSR_AMD64_SNP_SECURE_TSC_BIT)
+#define MSR_AMD64_SNP_VMGEXIT_PARAM_BIT        12
+#define MSR_AMD64_SNP_VMGEXIT_PARAM    BIT_ULL(MSR_AMD64_SNP_VMGEXIT_PARAM_BIT)
+#define MSR_AMD64_SNP_RESERVED_BIT13   BIT_ULL(13)
+#define MSR_AMD64_SNP_IBS_VIRT_BIT     14
+#define MSR_AMD64_SNP_IBS_VIRT         BIT_ULL(MSR_AMD64_SNP_IBS_VIRT_BIT)
+#define MSR_AMD64_SNP_RESERVED_BIT15   BIT_ULL(15)
+#define MSR_AMD64_SNP_VMSA_REG_PROT_BIT        16
+#define MSR_AMD64_SNP_VMSA_REG_PROT    BIT_ULL(MSR_AMD64_SNP_VMSA_REG_PROT_BIT)
+#define MSR_AMD64_SNP_SMT_PROT_BIT     17
+#define MSR_AMD64_SNP_SMT_PROT         BIT_ULL(MSR_AMD64_SNP_SMT_PROT_BIT)
+#define MSR_AMD64_SNP_RESV_BIT         18
+#define MSR_AMD64_SNP_RESERVED_MASK    GENMASK_ULL(63, MSR_AMD64_SNP_RESV_BIT)
 
 #define MSR_AMD64_VIRT_SPEC_CTRL       0xc001011f
 
+#define MSR_AMD64_RMP_BASE             0xc0010132
+#define MSR_AMD64_RMP_END              0xc0010133
+
 /* AMD Collaborative Processor Performance Control MSRs */
 #define MSR_AMD_CPPC_CAP1              0xc00102b0
 #define MSR_AMD_CPPC_ENABLE            0xc00102b1
 #define MSR_K8_TOP_MEM1                        0xc001001a
 #define MSR_K8_TOP_MEM2                        0xc001001d
 #define MSR_AMD64_SYSCFG               0xc0010010
-#define MSR_AMD64_SYSCFG_MEM_ENCRYPT_BIT       23
+#define MSR_AMD64_SYSCFG_MEM_ENCRYPT_BIT 23
 #define MSR_AMD64_SYSCFG_MEM_ENCRYPT   BIT_ULL(MSR_AMD64_SYSCFG_MEM_ENCRYPT_BIT)
+#define MSR_AMD64_SYSCFG_SNP_EN_BIT    24
+#define MSR_AMD64_SYSCFG_SNP_EN                BIT_ULL(MSR_AMD64_SYSCFG_SNP_EN_BIT)
+#define MSR_AMD64_SYSCFG_SNP_VMPL_EN_BIT 25
+#define MSR_AMD64_SYSCFG_SNP_VMPL_EN   BIT_ULL(MSR_AMD64_SYSCFG_SNP_VMPL_EN_BIT)
+#define MSR_AMD64_SYSCFG_MFDM_BIT      19
+#define MSR_AMD64_SYSCFG_MFDM          BIT_ULL(MSR_AMD64_SYSCFG_MFDM_BIT)
+
 #define MSR_K8_INT_PENDING_MSG         0xc0010055
 /* C1E active bits in int pending message */
 #define K8_INTP_C1E_ACTIVE_MASK                0x18000000
index 65ec1965cd2810323ab71a8d5cb79851845237c4..d642037f9ed5d81d5af89986e19bf8c33c74c6c8 100644 (file)
 #include <uapi/asm/msr.h>
 #include <asm/shared/msr.h>
 
+#include <linux/percpu.h>
+
 struct msr_info {
-       u32 msr_no;
-       struct msr reg;
-       struct msr *msrs;
-       int err;
+       u32                     msr_no;
+       struct msr              reg;
+       struct msr __percpu     *msrs;
+       int                     err;
 };
 
 struct msr_regs_info {
@@ -97,6 +99,19 @@ static __always_inline void __wrmsr(unsigned int msr, u32 low, u32 high)
                     : : "c" (msr), "a"(low), "d" (high) : "memory");
 }
 
+/*
+ * WRMSRNS behaves exactly like WRMSR with the only difference being
+ * that it is not a serializing instruction by default.
+ */
+static __always_inline void __wrmsrns(u32 msr, u32 low, u32 high)
+{
+       /* Instruction opcode for WRMSRNS; supported in binutils >= 2.40. */
+       asm volatile("1: .byte 0x0f,0x01,0xc6\n"
+                    "2:\n"
+                    _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_WRMSR)
+                    : : "c" (msr), "a"(low), "d" (high));
+}
+
 #define native_rdmsr(msr, val1, val2)                  \
 do {                                                   \
        u64 __val = __rdmsr((msr));                     \
@@ -297,6 +312,11 @@ do {                                                       \
 
 #endif /* !CONFIG_PARAVIRT_XXL */
 
+static __always_inline void wrmsrns(u32 msr, u64 val)
+{
+       __wrmsrns(msr, val, val >> 32);
+}
+
 /*
  * 64-bit version of wrmsr_safe():
  */
@@ -305,8 +325,8 @@ static inline int wrmsrl_safe(u32 msr, u64 val)
        return wrmsr_safe(msr, (u32)val,  (u32)(val >> 32));
 }
 
-struct msr *msrs_alloc(void);
-void msrs_free(struct msr *msrs);
+struct msr __percpu *msrs_alloc(void);
+void msrs_free(struct msr __percpu *msrs);
 int msr_set_bit(u32 msr, u8 bit);
 int msr_clear_bit(u32 msr, u8 bit);
 
@@ -315,8 +335,8 @@ int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
 int rdmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 *q);
 int wrmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 q);
-void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs);
-void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs);
+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr __percpu *msrs);
+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr __percpu *msrs);
 int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
 int rdmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 *q);
@@ -345,14 +365,14 @@ static inline int wrmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 q)
        return 0;
 }
 static inline void rdmsr_on_cpus(const struct cpumask *m, u32 msr_no,
-                               struct msr *msrs)
+                               struct msr __percpu *msrs)
 {
-       rdmsr_on_cpu(0, msr_no, &(msrs[0].l), &(msrs[0].h));
+       rdmsr_on_cpu(0, msr_no, raw_cpu_ptr(&msrs->l), raw_cpu_ptr(&msrs->h));
 }
 static inline void wrmsr_on_cpus(const struct cpumask *m, u32 msr_no,
-                               struct msr *msrs)
+                               struct msr __percpu *msrs)
 {
-       wrmsr_on_cpu(0, msr_no, msrs[0].l, msrs[0].h);
+       wrmsr_on_cpu(0, msr_no, raw_cpu_read(msrs->l), raw_cpu_read(msrs->h));
 }
 static inline int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no,
                                    u32 *l, u32 *h)
index 5c5f1e56c4048db1a725b450e6f700b484d150d2..41a0ebb699ec64284832878191404a9cfa8ffbc4 100644 (file)
@@ -14,9 +14,6 @@ extern void release_perfctr_nmi(unsigned int);
 extern int reserve_evntsel_nmi(unsigned int);
 extern void release_evntsel_nmi(unsigned int);
 
-struct ctl_table;
-extern int proc_nmi_enabled(struct ctl_table *, int ,
-                       void __user *, size_t *, loff_t *);
 extern int unknown_nmi_panic;
 
 #endif /* CONFIG_X86_LOCAL_APIC */
index 262e65539f83c86d140552305c8a9d330b313c20..fc3a8a3c7ffeece5b1b418bda0fc4d124c83d62a 100644 (file)
 
 #ifdef CONFIG_CALL_THUNKS_DEBUG
 # define CALL_THUNKS_DEBUG_INC_CALLS                           \
-       incq    %gs:__x86_call_count;
+       incq    PER_CPU_VAR(__x86_call_count);
 # define CALL_THUNKS_DEBUG_INC_RETS                            \
-       incq    %gs:__x86_ret_count;
+       incq    PER_CPU_VAR(__x86_ret_count);
 # define CALL_THUNKS_DEBUG_INC_STUFFS                          \
-       incq    %gs:__x86_stuffs_count;
+       incq    PER_CPU_VAR(__x86_stuffs_count);
 # define CALL_THUNKS_DEBUG_INC_CTXSW                           \
-       incq    %gs:__x86_ctxsw_count;
+       incq    PER_CPU_VAR(__x86_ctxsw_count);
 #else
 # define CALL_THUNKS_DEBUG_INC_CALLS
 # define CALL_THUNKS_DEBUG_INC_RETS
 # define CALL_THUNKS_DEBUG_INC_CTXSW
 #endif
 
-#if defined(CONFIG_CALL_DEPTH_TRACKING) && !defined(COMPILE_OFFSETS)
+#if defined(CONFIG_MITIGATION_CALL_DEPTH_TRACKING) && !defined(COMPILE_OFFSETS)
 
 #include <asm/asm-offsets.h>
 
 #define CREDIT_CALL_DEPTH                                      \
        movq    $-1, PER_CPU_VAR(pcpu_hot + X86_call_depth);
 
-#define ASM_CREDIT_CALL_DEPTH                                  \
-       movq    $-1, PER_CPU_VAR(pcpu_hot + X86_call_depth);
-
 #define RESET_CALL_DEPTH                                       \
        xor     %eax, %eax;                                     \
        bts     $63, %rax;                                      \
        CALL_THUNKS_DEBUG_INC_CALLS
 
 #define INCREMENT_CALL_DEPTH                                   \
-       sarq    $5, %gs:pcpu_hot + X86_call_depth;              \
-       CALL_THUNKS_DEBUG_INC_CALLS
-
-#define ASM_INCREMENT_CALL_DEPTH                               \
        sarq    $5, PER_CPU_VAR(pcpu_hot + X86_call_depth);     \
        CALL_THUNKS_DEBUG_INC_CALLS
 
 #else
 #define CREDIT_CALL_DEPTH
-#define ASM_CREDIT_CALL_DEPTH
 #define RESET_CALL_DEPTH
-#define INCREMENT_CALL_DEPTH
-#define ASM_INCREMENT_CALL_DEPTH
 #define RESET_CALL_DEPTH_FROM_CALL
+#define INCREMENT_CALL_DEPTH
 #endif
 
 /*
        jnz     771b;                                   \
        /* barrier for jnz misprediction */             \
        lfence;                                         \
-       ASM_CREDIT_CALL_DEPTH                           \
+       CREDIT_CALL_DEPTH                               \
        CALL_THUNKS_DEBUG_INC_CTXSW
 #else
 /*
  */
 .macro VALIDATE_UNRET_END
 #if defined(CONFIG_NOINSTR_VALIDATION) && \
-       (defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_SRSO))
+       (defined(CONFIG_MITIGATION_UNRET_ENTRY) || defined(CONFIG_MITIGATION_SRSO))
        ANNOTATE_RETPOLINE_SAFE
        nop
 #endif
  * instruction irrespective of kCFI.
  */
 .macro JMP_NOSPEC reg:req
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
        __CS_PREFIX \reg
        jmp     __x86_indirect_thunk_\reg
 #else
 .endm
 
 .macro CALL_NOSPEC reg:req
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
        __CS_PREFIX \reg
        call    __x86_indirect_thunk_\reg
 #else
 .Lskip_rsb_\@:
 .endm
 
-#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_SRSO)
+#if defined(CONFIG_MITIGATION_UNRET_ENTRY) || defined(CONFIG_MITIGATION_SRSO)
 #define CALL_UNTRAIN_RET       "call entry_untrain_ret"
 #else
 #define CALL_UNTRAIN_RET       ""
  * where we have a stack but before any RET instruction.
  */
 .macro __UNTRAIN_RET ibpb_feature, call_depth_insns
-#if defined(CONFIG_RETHUNK) || defined(CONFIG_CPU_IBPB_ENTRY)
+#if defined(CONFIG_MITIGATION_RETHUNK) || defined(CONFIG_MITIGATION_IBPB_ENTRY)
        VALIDATE_UNRET_END
        ALTERNATIVE_3 "",                                               \
                      CALL_UNTRAIN_RET, X86_FEATURE_UNRET,              \
 
 
 .macro CALL_DEPTH_ACCOUNT
-#ifdef CONFIG_CALL_DEPTH_TRACKING
+#ifdef CONFIG_MITIGATION_CALL_DEPTH_TRACKING
        ALTERNATIVE "",                                                 \
-                   __stringify(ASM_INCREMENT_CALL_DEPTH), X86_FEATURE_CALL_DEPTH
+                   __stringify(INCREMENT_CALL_DEPTH), X86_FEATURE_CALL_DEPTH
 #endif
 .endm
 
+/*
+ * Macro to execute VERW instruction that mitigate transient data sampling
+ * attacks such as MDS. On affected systems a microcode update overloaded VERW
+ * instruction to also clear the CPU buffers. VERW clobbers CFLAGS.ZF.
+ *
+ * Note: Only the memory operand variant of VERW clears the CPU buffers.
+ */
+.macro CLEAR_CPU_BUFFERS
+       ALTERNATIVE "", __stringify(verw _ASM_RIP(mds_verw_sel)), X86_FEATURE_CLEAR_CPU_BUF
+.endm
+
 #else /* __ASSEMBLY__ */
 
 #define ANNOTATE_RETPOLINE_SAFE                                        \
@@ -328,19 +330,19 @@ extern retpoline_thunk_t __x86_indirect_thunk_array[];
 extern retpoline_thunk_t __x86_indirect_call_thunk_array[];
 extern retpoline_thunk_t __x86_indirect_jump_thunk_array[];
 
-#ifdef CONFIG_RETHUNK
+#ifdef CONFIG_MITIGATION_RETHUNK
 extern void __x86_return_thunk(void);
 #else
 static inline void __x86_return_thunk(void) {}
 #endif
 
-#ifdef CONFIG_CPU_UNRET_ENTRY
+#ifdef CONFIG_MITIGATION_UNRET_ENTRY
 extern void retbleed_return_thunk(void);
 #else
 static inline void retbleed_return_thunk(void) {}
 #endif
 
-#ifdef CONFIG_CPU_SRSO
+#ifdef CONFIG_MITIGATION_SRSO
 extern void srso_return_thunk(void);
 extern void srso_alias_return_thunk(void);
 #else
@@ -357,7 +359,9 @@ extern void entry_ibpb(void);
 
 extern void (*x86_return_thunk)(void);
 
-#ifdef CONFIG_CALL_DEPTH_TRACKING
+extern void __warn_thunk(void);
+
+#ifdef CONFIG_MITIGATION_CALL_DEPTH_TRACKING
 extern void call_depth_return_thunk(void);
 
 #define CALL_DEPTH_ACCOUNT                                     \
@@ -371,14 +375,14 @@ DECLARE_PER_CPU(u64, __x86_ret_count);
 DECLARE_PER_CPU(u64, __x86_stuffs_count);
 DECLARE_PER_CPU(u64, __x86_ctxsw_count);
 #endif
-#else /* !CONFIG_CALL_DEPTH_TRACKING */
+#else /* !CONFIG_MITIGATION_CALL_DEPTH_TRACKING */
 
 static inline void call_depth_return_thunk(void) {}
 #define CALL_DEPTH_ACCOUNT ""
 
-#endif /* CONFIG_CALL_DEPTH_TRACKING */
+#endif /* CONFIG_MITIGATION_CALL_DEPTH_TRACKING */
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
 
 #define GEN(reg) \
        extern retpoline_thunk_t __x86_indirect_thunk_ ## reg;
@@ -399,7 +403,7 @@ static inline void call_depth_return_thunk(void) {}
 
 /*
  * Inline asm uses the %V modifier which is only in newer GCC
- * which is ensured when CONFIG_RETPOLINE is defined.
+ * which is ensured when CONFIG_MITIGATION_RETPOLINE is defined.
  */
 # define CALL_NOSPEC                                           \
        ALTERNATIVE_2(                                          \
@@ -529,13 +533,14 @@ DECLARE_STATIC_KEY_FALSE(switch_to_cond_stibp);
 DECLARE_STATIC_KEY_FALSE(switch_mm_cond_ibpb);
 DECLARE_STATIC_KEY_FALSE(switch_mm_always_ibpb);
 
-DECLARE_STATIC_KEY_FALSE(mds_user_clear);
 DECLARE_STATIC_KEY_FALSE(mds_idle_clear);
 
 DECLARE_STATIC_KEY_FALSE(switch_mm_cond_l1d_flush);
 
 DECLARE_STATIC_KEY_FALSE(mmio_stale_data_clear);
 
+extern u16 mds_verw_sel;
+
 #include <asm/segment.h>
 
 /**
@@ -561,17 +566,6 @@ static __always_inline void mds_clear_cpu_buffers(void)
        asm volatile("verw %[ds]" : : [ds] "m" (ds) : "cc");
 }
 
-/**
- * mds_user_clear_cpu_buffers - Mitigation for MDS and TAA vulnerability
- *
- * Clear CPU buffers if the corresponding static key is enabled
- */
-static __always_inline void mds_user_clear_cpu_buffers(void)
-{
-       if (static_branch_likely(&mds_user_clear))
-               mds_clear_cpu_buffers();
-}
-
 /**
  * mds_idle_clear_cpu_buffers - Mitigation for MDS vulnerability
  *
index d18e5c332cb9f443b2279d0545779b67dcb7ec19..1b93ff80b43bcc229add1859fd5b14deb4e84b5d 100644 (file)
@@ -66,10 +66,14 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr,
  * virt_addr_valid(kaddr) returns true.
  */
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
-#define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
 extern bool __virt_addr_valid(unsigned long kaddr);
 #define virt_addr_valid(kaddr) __virt_addr_valid((unsigned long) (kaddr))
 
+static __always_inline void *pfn_to_kaddr(unsigned long pfn)
+{
+       return __va(pfn << PAGE_SHIFT);
+}
+
 static __always_inline u64 __canonical_address(u64 vaddr, u8 vaddr_bits)
 {
        return ((s64)vaddr << (64 - vaddr_bits)) >> (64 - vaddr_bits);
index 86bd4311daf8a5046e5fa4cb71979535667a2e3d..9da9c8a2f1df5daf4c71dace1f66111637c843d6 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/mem_encrypt.h>
 
 /* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT             12
+#define PAGE_SHIFT             CONFIG_PAGE_SHIFT
 #define PAGE_SIZE              (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK              (~(PAGE_SIZE-1))
 
index b40c462b4af36cce4256923f06285e28b062ca51..b3ab80a03365cf1de1b5332e76494644e98eb938 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/numa.h>
 #include <asm/io.h>
 #include <asm/memtype.h>
-#include <asm/x86_init.h>
 
 struct pci_sysdata {
        int             domain;         /* PCI domain */
@@ -124,16 +123,4 @@ cpumask_of_pcibus(const struct pci_bus *bus)
 }
 #endif
 
-struct pci_setup_rom {
-       struct setup_data data;
-       uint16_t vendor;
-       uint16_t devid;
-       uint64_t pcilen;
-       unsigned long segment;
-       unsigned long bus;
-       unsigned long device;
-       unsigned long function;
-       uint8_t romdata[];
-};
-
 #endif /* _ASM_X86_PCI_H */
index 5e01883eb51ee8e576e70db0577bfbe0c20c2e4f..44958ebaf626e20c970acaacaad012f93cba2671 100644 (file)
@@ -4,17 +4,21 @@
 
 #ifdef CONFIG_X86_64
 #define __percpu_seg           gs
+#define __percpu_rel           (%rip)
 #else
 #define __percpu_seg           fs
+#define __percpu_rel
 #endif
 
 #ifdef __ASSEMBLY__
 
 #ifdef CONFIG_SMP
-#define PER_CPU_VAR(var)       %__percpu_seg:var
-#else /* ! SMP */
-#define PER_CPU_VAR(var)       var
-#endif /* SMP */
+#define __percpu               %__percpu_seg:
+#else
+#define __percpu
+#endif
+
+#define PER_CPU_VAR(var)       __percpu(var)__percpu_rel
 
 #ifdef CONFIG_X86_64_SMP
 #define INIT_PER_CPU_VAR(var)  init_per_cpu__##var
 
 #else /* ...!ASSEMBLY */
 
+#include <linux/build_bug.h>
 #include <linux/stringify.h>
 #include <asm/asm.h>
 
 #ifdef CONFIG_SMP
+
+#ifdef CONFIG_CC_HAS_NAMED_AS
+
+#ifdef __CHECKER__
+#define __seg_gs               __attribute__((address_space(__seg_gs)))
+#define __seg_fs               __attribute__((address_space(__seg_fs)))
+#endif
+
+#ifdef CONFIG_X86_64
+#define __percpu_seg_override  __seg_gs
+#else
+#define __percpu_seg_override  __seg_fs
+#endif
+
+#define __percpu_prefix                ""
+
+#else /* CONFIG_CC_HAS_NAMED_AS */
+
+#define __percpu_seg_override
 #define __percpu_prefix                "%%"__stringify(__percpu_seg)":"
+
+#endif /* CONFIG_CC_HAS_NAMED_AS */
+
+#define __force_percpu_prefix  "%%"__stringify(__percpu_seg)":"
 #define __my_cpu_offset                this_cpu_read(this_cpu_off)
 
+#ifdef CONFIG_USE_X86_SEG_SUPPORT
+/*
+ * Efficient implementation for cases in which the compiler supports
+ * named address spaces.  Allows the compiler to perform additional
+ * optimizations that can save more instructions.
+ */
+#define arch_raw_cpu_ptr(ptr)                                  \
+({                                                             \
+       unsigned long tcp_ptr__;                                \
+       tcp_ptr__ = __raw_cpu_read(, this_cpu_off);             \
+                                                               \
+       tcp_ptr__ += (unsigned long)(ptr);                      \
+       (typeof(*(ptr)) __kernel __force *)tcp_ptr__;           \
+})
+#else /* CONFIG_USE_X86_SEG_SUPPORT */
 /*
  * Compared to the generic __my_cpu_offset version, the following
  * saves one instruction and avoids clobbering a temp register.
  */
-#define arch_raw_cpu_ptr(ptr)                          \
-({                                                     \
-       unsigned long tcp_ptr__;                        \
-       asm ("add " __percpu_arg(1) ", %0"              \
-            : "=r" (tcp_ptr__)                         \
-            : "m" (this_cpu_off), "0" (ptr));          \
-       (typeof(*(ptr)) __kernel __force *)tcp_ptr__;   \
+#define arch_raw_cpu_ptr(ptr)                                  \
+({                                                             \
+       unsigned long tcp_ptr__;                                \
+       asm ("mov " __percpu_arg(1) ", %0"                      \
+            : "=r" (tcp_ptr__)                                 \
+            : "m" (__my_cpu_var(this_cpu_off)));               \
+                                                               \
+       tcp_ptr__ += (unsigned long)(ptr);                      \
+       (typeof(*(ptr)) __kernel __force *)tcp_ptr__;           \
 })
-#else
+#endif /* CONFIG_USE_X86_SEG_SUPPORT */
+
+#define PER_CPU_VAR(var)       %__percpu_seg:(var)__percpu_rel
+
+#else /* CONFIG_SMP */
+#define __percpu_seg_override
 #define __percpu_prefix                ""
-#endif
+#define __force_percpu_prefix  ""
+
+#define PER_CPU_VAR(var)       (var)__percpu_rel
 
+#endif /* CONFIG_SMP */
+
+#define __my_cpu_type(var)     typeof(var) __percpu_seg_override
+#define __my_cpu_ptr(ptr)      (__my_cpu_type(*ptr) *)(uintptr_t)(ptr)
+#define __my_cpu_var(var)      (*__my_cpu_ptr(&var))
 #define __percpu_arg(x)                __percpu_prefix "%" #x
+#define __force_percpu_arg(x)  __force_percpu_prefix "%" #x
 
 /*
  * Initialized pointers to per-cpu variables needed for the boot
@@ -107,14 +165,14 @@ do {                                                                      \
                (void)pto_tmp__;                                        \
        }                                                               \
        asm qual(__pcpu_op2_##size(op, "%[val]", __percpu_arg([var]))   \
-           : [var] "+m" (_var)                                         \
+           : [var] "+m" (__my_cpu_var(_var))                           \
            : [val] __pcpu_reg_imm_##size(pto_val__));                  \
 } while (0)
 
 #define percpu_unary_op(size, qual, op, _var)                          \
 ({                                                                     \
        asm qual (__pcpu_op1_##size(op, __percpu_arg([var]))            \
-           : [var] "+m" (_var));                                       \
+           : [var] "+m" (__my_cpu_var(_var)));                         \
 })
 
 /*
@@ -144,16 +202,16 @@ do {                                                                      \
        __pcpu_type_##size pfo_val__;                                   \
        asm qual (__pcpu_op2_##size(op, __percpu_arg([var]), "%[val]")  \
            : [val] __pcpu_reg_##size("=", pfo_val__)                   \
-           : [var] "m" (_var));                                        \
+           : [var] "m" (__my_cpu_var(_var)));                          \
        (typeof(_var))(unsigned long) pfo_val__;                        \
 })
 
 #define percpu_stable_op(size, op, _var)                               \
 ({                                                                     \
        __pcpu_type_##size pfo_val__;                                   \
-       asm(__pcpu_op2_##size(op, __percpu_arg(P[var]), "%[val]")       \
+       asm(__pcpu_op2_##size(op, __force_percpu_arg(a[var]), "%[val]") \
            : [val] __pcpu_reg_##size("=", pfo_val__)                   \
-           : [var] "p" (&(_var)));                                     \
+           : [var] "i" (&(_var)));                                     \
        (typeof(_var))(unsigned long) pfo_val__;                        \
 })
 
@@ -166,7 +224,7 @@ do {                                                                        \
        asm qual (__pcpu_op2_##size("xadd", "%[tmp]",                   \
                                     __percpu_arg([var]))               \
                  : [tmp] __pcpu_reg_##size("+", paro_tmp__),           \
-                   [var] "+m" (_var)                                   \
+                   [var] "+m" (__my_cpu_var(_var))                     \
                  : : "memory");                                        \
        (typeof(_var))(unsigned long) (paro_tmp__ + _val);              \
 })
@@ -187,7 +245,7 @@ do {                                                                        \
                                    __percpu_arg([var]))                \
                  "\n\tjnz 1b"                                          \
                  : [oval] "=&a" (pxo_old__),                           \
-                   [var] "+m" (_var)                                   \
+                   [var] "+m" (__my_cpu_var(_var))                     \
                  : [nval] __pcpu_reg_##size(, pxo_new__)               \
                  : "memory");                                          \
        (typeof(_var))(unsigned long) pxo_old__;                        \
@@ -204,7 +262,7 @@ do {                                                                        \
        asm qual (__pcpu_op2_##size("cmpxchg", "%[nval]",               \
                                    __percpu_arg([var]))                \
                  : [oval] "+a" (pco_old__),                            \
-                   [var] "+m" (_var)                                   \
+                   [var] "+m" (__my_cpu_var(_var))                     \
                  : [nval] __pcpu_reg_##size(, pco_new__)               \
                  : "memory");                                          \
        (typeof(_var))(unsigned long) pco_old__;                        \
@@ -221,7 +279,7 @@ do {                                                                        \
                  CC_SET(z)                                             \
                  : CC_OUT(z) (success),                                \
                    [oval] "+a" (pco_old__),                            \
-                   [var] "+m" (_var)                                   \
+                   [var] "+m" (__my_cpu_var(_var))                     \
                  : [nval] __pcpu_reg_##size(, pco_new__)               \
                  : "memory");                                          \
        if (unlikely(!success))                                         \
@@ -244,7 +302,7 @@ do {                                                                        \
                                                                        \
        asm qual (ALTERNATIVE("call this_cpu_cmpxchg8b_emu",            \
                              "cmpxchg8b " __percpu_arg([var]), X86_FEATURE_CX8) \
-                 : [var] "+m" (_var),                                  \
+                 : [var] "+m" (__my_cpu_var(_var)),                    \
                    "+a" (old__.low),                                   \
                    "+d" (old__.high)                                   \
                  : "b" (new__.low),                                    \
@@ -276,7 +334,7 @@ do {                                                                        \
                              "cmpxchg8b " __percpu_arg([var]), X86_FEATURE_CX8) \
                  CC_SET(z)                                             \
                  : CC_OUT(z) (success),                                \
-                   [var] "+m" (_var),                                  \
+                   [var] "+m" (__my_cpu_var(_var)),                    \
                    "+a" (old__.low),                                   \
                    "+d" (old__.high)                                   \
                  : "b" (new__.low),                                    \
@@ -313,7 +371,7 @@ do {                                                                        \
                                                                        \
        asm qual (ALTERNATIVE("call this_cpu_cmpxchg16b_emu",           \
                              "cmpxchg16b " __percpu_arg([var]), X86_FEATURE_CX16) \
-                 : [var] "+m" (_var),                                  \
+                 : [var] "+m" (__my_cpu_var(_var)),                    \
                    "+a" (old__.low),                                   \
                    "+d" (old__.high)                                   \
                  : "b" (new__.low),                                    \
@@ -345,7 +403,7 @@ do {                                                                        \
                              "cmpxchg16b " __percpu_arg([var]), X86_FEATURE_CX16) \
                  CC_SET(z)                                             \
                  : CC_OUT(z) (success),                                \
-                   [var] "+m" (_var),                                  \
+                   [var] "+m" (__my_cpu_var(_var)),                    \
                    "+a" (old__.low),                                   \
                    "+d" (old__.high)                                   \
                  : "b" (new__.low),                                    \
@@ -366,9 +424,9 @@ do {                                                                        \
  * accessed while this_cpu_read_stable() allows the value to be cached.
  * this_cpu_read_stable() is more efficient and can be used if its value
  * is guaranteed to be valid across cpus.  The current users include
- * get_current() and get_thread_info() both of which are actually
- * per-thread variables implemented as per-cpu variables and thus
- * stable for the duration of the respective task.
+ * pcpu_hot.current_task and pcpu_hot.top_of_stack, both of which are
+ * actually per-thread variables implemented as per-CPU variables and
+ * thus stable for the duration of the respective task.
  */
 #define this_cpu_read_stable_1(pcp)    percpu_stable_op(1, "mov", pcp)
 #define this_cpu_read_stable_2(pcp)    percpu_stable_op(2, "mov", pcp)
@@ -376,13 +434,72 @@ do {                                                                      \
 #define this_cpu_read_stable_8(pcp)    percpu_stable_op(8, "mov", pcp)
 #define this_cpu_read_stable(pcp)      __pcpu_size_call_return(this_cpu_read_stable_, pcp)
 
+#ifdef CONFIG_USE_X86_SEG_SUPPORT
+
+#define __raw_cpu_read(qual, pcp)                                      \
+({                                                                     \
+       *(qual __my_cpu_type(pcp) *)__my_cpu_ptr(&(pcp));               \
+})
+
+#define __raw_cpu_write(qual, pcp, val)                                        \
+do {                                                                   \
+       *(qual __my_cpu_type(pcp) *)__my_cpu_ptr(&(pcp)) = (val);       \
+} while (0)
+
+#define raw_cpu_read_1(pcp)            __raw_cpu_read(, pcp)
+#define raw_cpu_read_2(pcp)            __raw_cpu_read(, pcp)
+#define raw_cpu_read_4(pcp)            __raw_cpu_read(, pcp)
+#define raw_cpu_write_1(pcp, val)      __raw_cpu_write(, pcp, val)
+#define raw_cpu_write_2(pcp, val)      __raw_cpu_write(, pcp, val)
+#define raw_cpu_write_4(pcp, val)      __raw_cpu_write(, pcp, val)
+
+#define this_cpu_read_1(pcp)           __raw_cpu_read(volatile, pcp)
+#define this_cpu_read_2(pcp)           __raw_cpu_read(volatile, pcp)
+#define this_cpu_read_4(pcp)           __raw_cpu_read(volatile, pcp)
+#define this_cpu_write_1(pcp, val)     __raw_cpu_write(volatile, pcp, val)
+#define this_cpu_write_2(pcp, val)     __raw_cpu_write(volatile, pcp, val)
+#define this_cpu_write_4(pcp, val)     __raw_cpu_write(volatile, pcp, val)
+
+#ifdef CONFIG_X86_64
+#define raw_cpu_read_8(pcp)            __raw_cpu_read(, pcp)
+#define raw_cpu_write_8(pcp, val)      __raw_cpu_write(, pcp, val)
+
+#define this_cpu_read_8(pcp)           __raw_cpu_read(volatile, pcp)
+#define this_cpu_write_8(pcp, val)     __raw_cpu_write(volatile, pcp, val)
+#endif
+
+#define this_cpu_read_const(pcp)       __raw_cpu_read(, pcp)
+#else /* CONFIG_USE_X86_SEG_SUPPORT */
+
 #define raw_cpu_read_1(pcp)            percpu_from_op(1, , "mov", pcp)
 #define raw_cpu_read_2(pcp)            percpu_from_op(2, , "mov", pcp)
 #define raw_cpu_read_4(pcp)            percpu_from_op(4, , "mov", pcp)
-
 #define raw_cpu_write_1(pcp, val)      percpu_to_op(1, , "mov", (pcp), val)
 #define raw_cpu_write_2(pcp, val)      percpu_to_op(2, , "mov", (pcp), val)
 #define raw_cpu_write_4(pcp, val)      percpu_to_op(4, , "mov", (pcp), val)
+
+#define this_cpu_read_1(pcp)           percpu_from_op(1, volatile, "mov", pcp)
+#define this_cpu_read_2(pcp)           percpu_from_op(2, volatile, "mov", pcp)
+#define this_cpu_read_4(pcp)           percpu_from_op(4, volatile, "mov", pcp)
+#define this_cpu_write_1(pcp, val)     percpu_to_op(1, volatile, "mov", (pcp), val)
+#define this_cpu_write_2(pcp, val)     percpu_to_op(2, volatile, "mov", (pcp), val)
+#define this_cpu_write_4(pcp, val)     percpu_to_op(4, volatile, "mov", (pcp), val)
+
+#ifdef CONFIG_X86_64
+#define raw_cpu_read_8(pcp)            percpu_from_op(8, , "mov", pcp)
+#define raw_cpu_write_8(pcp, val)      percpu_to_op(8, , "mov", (pcp), val)
+
+#define this_cpu_read_8(pcp)           percpu_from_op(8, volatile, "mov", pcp)
+#define this_cpu_write_8(pcp, val)     percpu_to_op(8, volatile, "mov", (pcp), val)
+#endif
+
+/*
+ * The generic per-cpu infrastrucutre is not suitable for
+ * reading const-qualified variables.
+ */
+#define this_cpu_read_const(pcp)       ({ BUILD_BUG(); (typeof(pcp))0; })
+#endif /* CONFIG_USE_X86_SEG_SUPPORT */
+
 #define raw_cpu_add_1(pcp, val)                percpu_add_op(1, , (pcp), val)
 #define raw_cpu_add_2(pcp, val)                percpu_add_op(2, , (pcp), val)
 #define raw_cpu_add_4(pcp, val)                percpu_add_op(4, , (pcp), val)
@@ -408,12 +525,6 @@ do {                                                                       \
 #define raw_cpu_xchg_2(pcp, val)       raw_percpu_xchg_op(pcp, val)
 #define raw_cpu_xchg_4(pcp, val)       raw_percpu_xchg_op(pcp, val)
 
-#define this_cpu_read_1(pcp)           percpu_from_op(1, volatile, "mov", pcp)
-#define this_cpu_read_2(pcp)           percpu_from_op(2, volatile, "mov", pcp)
-#define this_cpu_read_4(pcp)           percpu_from_op(4, volatile, "mov", pcp)
-#define this_cpu_write_1(pcp, val)     percpu_to_op(1, volatile, "mov", (pcp), val)
-#define this_cpu_write_2(pcp, val)     percpu_to_op(2, volatile, "mov", (pcp), val)
-#define this_cpu_write_4(pcp, val)     percpu_to_op(4, volatile, "mov", (pcp), val)
 #define this_cpu_add_1(pcp, val)       percpu_add_op(1, volatile, (pcp), val)
 #define this_cpu_add_2(pcp, val)       percpu_add_op(2, volatile, (pcp), val)
 #define this_cpu_add_4(pcp, val)       percpu_add_op(4, volatile, (pcp), val)
@@ -452,8 +563,6 @@ do {                                                                        \
  * 32 bit must fall back to generic operations.
  */
 #ifdef CONFIG_X86_64
-#define raw_cpu_read_8(pcp)                    percpu_from_op(8, , "mov", pcp)
-#define raw_cpu_write_8(pcp, val)              percpu_to_op(8, , "mov", (pcp), val)
 #define raw_cpu_add_8(pcp, val)                        percpu_add_op(8, , (pcp), val)
 #define raw_cpu_and_8(pcp, val)                        percpu_to_op(8, , "and", (pcp), val)
 #define raw_cpu_or_8(pcp, val)                 percpu_to_op(8, , "or", (pcp), val)
@@ -462,8 +571,6 @@ do {                                                                        \
 #define raw_cpu_cmpxchg_8(pcp, oval, nval)     percpu_cmpxchg_op(8, , pcp, oval, nval)
 #define raw_cpu_try_cmpxchg_8(pcp, ovalp, nval)        percpu_try_cmpxchg_op(8, , pcp, ovalp, nval)
 
-#define this_cpu_read_8(pcp)                   percpu_from_op(8, volatile, "mov", pcp)
-#define this_cpu_write_8(pcp, val)             percpu_to_op(8, volatile, "mov", (pcp), val)
 #define this_cpu_add_8(pcp, val)               percpu_add_op(8, volatile, (pcp), val)
 #define this_cpu_and_8(pcp, val)               percpu_to_op(8, volatile, "and", (pcp), val)
 #define this_cpu_or_8(pcp, val)                        percpu_to_op(8, volatile, "or", (pcp), val)
@@ -494,7 +601,7 @@ static inline bool x86_this_cpu_variable_test_bit(int nr,
        asm volatile("btl "__percpu_arg(2)",%1"
                        CC_SET(c)
                        : CC_OUT(c) (oldbit)
-                       : "m" (*(unsigned long __percpu *)addr), "Ir" (nr));
+                       : "m" (*__my_cpu_ptr((unsigned long __percpu *)(addr))), "Ir" (nr));
 
        return oldbit;
 }
index 94de1a05aebaac302a6e75aa68fe0bf39de7a629..d65e338b6a5fca1593733cb817423cc91b3296df 100644 (file)
@@ -181,7 +181,7 @@ static inline u64 p4_clear_ht_bit(u64 config)
 static inline int p4_ht_active(void)
 {
 #ifdef CONFIG_SMP
-       return smp_num_siblings > 1;
+       return __max_threads_per_core > 1;
 #endif
        return 0;
 }
@@ -189,7 +189,7 @@ static inline int p4_ht_active(void)
 static inline int p4_ht_thread(int cpu)
 {
 #ifdef CONFIG_SMP
-       if (smp_num_siblings == 2)
+       if (__max_threads_per_core == 2)
                return cpu != cpumask_first(this_cpu_cpumask_var_ptr(cpu_sibling_map));
 #endif
        return 0;
index c7ec5bb88334eab119ccf78002be2e7679291113..dcd836b59bebd329c3d265b98e48ef6eb4c9e6fc 100644 (file)
@@ -34,7 +34,7 @@ static inline void paravirt_release_p4d(unsigned long pfn) {}
  */
 extern gfp_t __userpte_alloc_gfp;
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 /*
  * Instead of one PGD, we acquire two PGDs.  Being order-1, it is
  * both 8k in size and 8k-aligned.  That lets us just flip bit 12
index 9e7c0b719c3c11361b60f51cb79a553322afeb76..dabafba957ea6f2e1d5d6796da07427dab2f22ba 100644 (file)
@@ -52,7 +52,7 @@ static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd)
 
 static inline void native_set_pud(pud_t *pudp, pud_t pud)
 {
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
        pud.p4d.pgd = pti_set_user_pgtbl(&pudp->p4d.pgd, pud.p4d.pgd);
 #endif
        pxx_xchg64(pud, pudp, native_pud_val(pud));
index 9d077bca6a103ecfcbd02424483fd5971995bafd..df0f7d4a96f3284eb4ac9c0495b5a4ec8df27aa3 100644 (file)
@@ -909,7 +909,7 @@ static inline int is_new_memtype_allowed(u64 paddr, unsigned long size,
 pmd_t *populate_extra_pmd(unsigned long vaddr);
 pte_t *populate_extra_pte(unsigned long vaddr);
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 pgd_t __pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd);
 
 /*
@@ -923,12 +923,12 @@ static inline pgd_t pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd)
                return pgd;
        return __pti_set_user_pgtbl(pgdp, pgd);
 }
-#else   /* CONFIG_PAGE_TABLE_ISOLATION */
+#else   /* CONFIG_MITIGATION_PAGE_TABLE_ISOLATION */
 static inline pgd_t pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd)
 {
        return pgd;
 }
-#endif  /* CONFIG_PAGE_TABLE_ISOLATION */
+#endif  /* CONFIG_MITIGATION_PAGE_TABLE_ISOLATION */
 
 #endif /* __ASSEMBLY__ */
 
@@ -1131,7 +1131,7 @@ static inline int p4d_bad(p4d_t p4d)
 {
        unsigned long ignore_flags = _KERNPG_TABLE | _PAGE_USER;
 
-       if (IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION))
+       if (IS_ENABLED(CONFIG_MITIGATION_PAGE_TABLE_ISOLATION))
                ignore_flags |= _PAGE_NX;
 
        return (p4d_flags(p4d) & ~ignore_flags) != 0;
@@ -1177,7 +1177,7 @@ static inline int pgd_bad(pgd_t pgd)
        if (!pgtable_l5_enabled())
                return 0;
 
-       if (IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION))
+       if (IS_ENABLED(CONFIG_MITIGATION_PAGE_TABLE_ISOLATION))
                ignore_flags |= _PAGE_NX;
 
        return (pgd_flags(pgd) & ~ignore_flags) != _KERNPG_TABLE;
@@ -1422,9 +1422,9 @@ static inline bool pgdp_maps_userspace(void *__ptr)
 #define pgd_leaf       pgd_large
 static inline int pgd_large(pgd_t pgd) { return 0; }
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 /*
- * All top-level PAGE_TABLE_ISOLATION page tables are order-1 pages
+ * All top-level MITIGATION_PAGE_TABLE_ISOLATION page tables are order-1 pages
  * (8k-aligned and 8k in size).  The kernel one is at the beginning 4k and
  * the user one is in the last 4k.  To switch between them, you
  * just need to flip the 12th bit in their addresses.
@@ -1469,7 +1469,7 @@ static inline p4d_t *user_to_kernel_p4dp(p4d_t *p4dp)
 {
        return ptr_clear_bit(p4dp, PTI_PGTABLE_SWITCH_BIT);
 }
-#endif /* CONFIG_PAGE_TABLE_ISOLATION */
+#endif /* CONFIG_MITIGATION_PAGE_TABLE_ISOLATION */
 
 /*
  * clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
@@ -1484,7 +1484,7 @@ static inline p4d_t *user_to_kernel_p4dp(p4d_t *p4dp)
 static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
 {
        memcpy(dst, src, count * sizeof(pgd_t));
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
        if (!static_cpu_has(X86_FEATURE_PTI))
                return;
        /* Clone the user space pgd as well */
index 24af25b1551a56597c988019b90e545db52442ff..7e9db77231ac7f596182b2f259c2798fbaf20f30 100644 (file)
@@ -143,7 +143,8 @@ static inline void native_set_p4d(p4d_t *p4dp, p4d_t p4d)
 {
        pgd_t pgd;
 
-       if (pgtable_l5_enabled() || !IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION)) {
+       if (pgtable_l5_enabled() ||
+           !IS_ENABLED(CONFIG_MITIGATION_PAGE_TABLE_ISOLATION)) {
                WRITE_ONCE(*p4dp, p4d);
                return;
        }
index 38b54b992f32e3027c5fa066f9684900fdd348d5..9053dfe9fa03f947f0ad28c20eb6bfd45856f7d3 100644 (file)
@@ -21,9 +21,9 @@ typedef unsigned long pgprotval_t;
 typedef struct { pteval_t pte; } pte_t;
 typedef struct { pmdval_t pmd; } pmd_t;
 
-#ifdef CONFIG_X86_5LEVEL
 extern unsigned int __pgtable_l5_enabled;
 
+#ifdef CONFIG_X86_5LEVEL
 #ifdef USE_EARLY_PGTABLE_L5
 /*
  * cpu_feature_enabled() is not available in early boot code.
index af77235fded63b64ec99844778796a294cf29d0a..919909d8cb77e3d630af36bf7df00f10fc3765f2 100644 (file)
@@ -91,7 +91,7 @@ static __always_inline void __preempt_count_sub(int val)
  */
 static __always_inline bool __preempt_count_dec_and_test(void)
 {
-       return GEN_UNARY_RMWcc("decl", pcpu_hot.preempt_count, e,
+       return GEN_UNARY_RMWcc("decl", __my_cpu_var(pcpu_hot.preempt_count), e,
                               __percpu_arg([var]));
 }
 
index d8cccadc83a6fb3d512df090538ac6bd1df23318..e5f204b9b33dfaa92ed1b05faa6b604e50d5f2f3 100644 (file)
@@ -51,7 +51,7 @@
 #define CR3_NOFLUSH    0
 #endif
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 # define X86_CR3_PTI_PCID_USER_BIT     11
 #endif
 
index 26620d7642a9fcf9d4a822140a1dd009399ee16a..811548f131f4e30418bedfdf98f1f302fc06723d 100644 (file)
@@ -20,7 +20,6 @@ struct vm86;
 #include <asm/page.h>
 #include <asm/pgtable_types.h>
 #include <asm/percpu.h>
-#include <asm/msr.h>
 #include <asm/desc_defs.h>
 #include <asm/nops.h>
 #include <asm/special_insns.h>
@@ -100,6 +99,9 @@ struct cpuinfo_topology {
        u32                     logical_pkg_id;
        u32                     logical_die_id;
 
+       // AMD Node ID and Nodes per Package info
+       u32                     amd_node_id;
+
        // Cache level topology IDs
        u32                     llc_id;
        u32                     l2c_id;
@@ -119,8 +121,6 @@ struct cpuinfo_x86 {
 #endif
        __u8                    x86_virt_bits;
        __u8                    x86_phys_bits;
-       /* CPUID returned core id bits: */
-       __u8                    x86_coreid_bits;
        /* Max extended CPUID function supported: */
        __u32                   extended_cpuid_level;
        /* Maximum supported CPUID level, -1=no CPUID: */
@@ -148,8 +148,6 @@ struct cpuinfo_x86 {
        unsigned long           loops_per_jiffy;
        /* protected processor identification number */
        u64                     ppin;
-       /* cpuid returned max cores value: */
-       u16                     x86_max_cores;
        u16                     x86_clflush_size;
        /* number of cores as seen by the OS: */
        u16                     booted_cores;
@@ -186,13 +184,8 @@ extern struct cpuinfo_x86  new_cpu_data;
 extern __u32                   cpu_caps_cleared[NCAPINTS + NBUGINTS];
 extern __u32                   cpu_caps_set[NCAPINTS + NBUGINTS];
 
-#ifdef CONFIG_SMP
 DECLARE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
 #define cpu_data(cpu)          per_cpu(cpu_info, cpu)
-#else
-#define cpu_info               boot_cpu_data
-#define cpu_data(cpu)          boot_cpu_data
-#endif
 
 extern const struct seq_operations cpuinfo_op;
 
@@ -533,6 +526,9 @@ static __always_inline unsigned long current_top_of_stack(void)
         *  and around vm86 mode and sp0 on x86_64 is special because of the
         *  entry trampoline.
         */
+       if (IS_ENABLED(CONFIG_USE_X86_SEG_SUPPORT))
+               return this_cpu_read_const(const_pcpu_hot.top_of_stack);
+
        return this_cpu_read_stable(pcpu_hot.top_of_stack);
 }
 
@@ -555,7 +551,7 @@ static inline void load_sp0(unsigned long sp0)
 
 unsigned long __get_wchan(struct task_struct *p);
 
-extern void select_idle_routine(const struct cpuinfo_x86 *c);
+extern void select_idle_routine(void);
 extern void amd_e400_c1e_apic_setup(void);
 
 extern unsigned long           boot_option_idle_override;
@@ -576,28 +572,6 @@ extern void cpu_init(void);
 extern void cpu_init_exception_handling(void);
 extern void cr4_init(void);
 
-static inline unsigned long get_debugctlmsr(void)
-{
-       unsigned long debugctlmsr = 0;
-
-#ifndef CONFIG_X86_DEBUGCTLMSR
-       if (boot_cpu_data.x86 < 6)
-               return 0;
-#endif
-       rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
-
-       return debugctlmsr;
-}
-
-static inline void update_debugctlmsr(unsigned long debugctlmsr)
-{
-#ifndef CONFIG_X86_DEBUGCTLMSR
-       if (boot_cpu_data.x86 < 6)
-               return;
-#endif
-       wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
-}
-
 extern void set_task_blockstep(struct task_struct *task, bool on);
 
 /* Boot loader type from the setup header: */
@@ -664,8 +638,10 @@ static __always_inline void prefetchw(const void *x)
 #else
 extern unsigned long __end_init_task[];
 
-#define INIT_THREAD {                                                      \
-       .sp     = (unsigned long)&__end_init_task - sizeof(struct pt_regs), \
+#define INIT_THREAD {                                                  \
+       .sp     = (unsigned long)&__end_init_task -                     \
+                 TOP_OF_KERNEL_STACK_PADDING -                         \
+                 sizeof(struct pt_regs),                               \
 }
 
 extern unsigned long KSTK_ESP(struct task_struct *task);
@@ -704,12 +680,10 @@ static inline u32 per_cpu_l2c_id(unsigned int cpu)
 }
 
 #ifdef CONFIG_CPU_SUP_AMD
-extern u32 amd_get_nodes_per_socket(void);
 extern u32 amd_get_highest_perf(void);
 extern void amd_clear_divider(void);
 extern void amd_check_microcode(void);
 #else
-static inline u32 amd_get_nodes_per_socket(void)       { return 0; }
 static inline u32 amd_get_highest_perf(void)           { return 0; }
 static inline void amd_clear_divider(void)             { }
 static inline void amd_check_microcode(void)           { }
index 65dee24206240641172ad509e6e06358e6fcf41f..043758a2e627037f544022197d41b8a762e6e973 100644 (file)
@@ -23,11 +23,11 @@ extern int of_ioapic;
 extern u64 initial_dtb;
 extern void add_dtb(u64 data);
 void x86_of_pci_init(void);
-void x86_dtb_init(void);
+void x86_dtb_parse_smp_config(void);
 #else
 static inline void add_dtb(u64 data) { }
 static inline void x86_of_pci_init(void) { }
-static inline void x86_dtb_init(void) { }
+static inline void x86_dtb_parse_smp_config(void) { }
 #define of_ioapic 0
 #endif
 
index 07375b476c4fda6cfd89229826bf21e331ef5190..ab167c96b9ab474b33d778453db0bb550f42b0ac 100644 (file)
@@ -3,7 +3,7 @@
 #define _ASM_X86_PTI_H
 #ifndef __ASSEMBLY__
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 extern void pti_init(void);
 extern void pti_check_boottime_disable(void);
 extern void pti_finalize(void);
index f4db78b09c8f0be1e0a904394d48f0a45b246cc8..5a83fbd9bc0b44f5bac9a4b3447e3b52fc5e1abc 100644 (file)
@@ -56,18 +56,64 @@ struct pt_regs {
 
 #else /* __i386__ */
 
+struct fred_cs {
+               /* CS selector */
+       u64     cs      : 16,
+               /* Stack level at event time */
+               sl      :  2,
+               /* IBT in WAIT_FOR_ENDBRANCH state */
+               wfe     :  1,
+                       : 45;
+};
+
+struct fred_ss {
+               /* SS selector */
+       u64     ss      : 16,
+               /* STI state */
+               sti     :  1,
+               /* Set if syscall, sysenter or INT n */
+               swevent :  1,
+               /* Event is NMI type */
+               nmi     :  1,
+                       : 13,
+               /* Event vector */
+               vector  :  8,
+                       :  8,
+               /* Event type */
+               type    :  4,
+                       :  4,
+               /* Event was incident to enclave execution */
+               enclave :  1,
+               /* CPU was in long mode */
+               lm      :  1,
+               /*
+                * Nested exception during FRED delivery, not set
+                * for #DF.
+                */
+               nested  :  1,
+                       :  1,
+               /*
+                * The length of the instruction causing the event.
+                * Only set for INTO, INT1, INT3, INT n, SYSCALL
+                * and SYSENTER.  0 otherwise.
+                */
+               insnlen :  4;
+};
+
 struct pt_regs {
-/*
- * C ABI says these regs are callee-preserved. They aren't saved on kernel entry
- * unless syscall needs a complete, fully filled "struct pt_regs".
- */
+       /*
+        * C ABI says these regs are callee-preserved. They aren't saved on
+        * kernel entry unless syscall needs a complete, fully filled
+        * "struct pt_regs".
+        */
        unsigned long r15;
        unsigned long r14;
        unsigned long r13;
        unsigned long r12;
        unsigned long bp;
        unsigned long bx;
-/* These regs are callee-clobbered. Always saved on kernel entry. */
+
+       /* These regs are callee-clobbered. Always saved on kernel entry. */
        unsigned long r11;
        unsigned long r10;
        unsigned long r9;
@@ -77,18 +123,50 @@ struct pt_regs {
        unsigned long dx;
        unsigned long si;
        unsigned long di;
-/*
- * On syscall entry, this is syscall#. On CPU exception, this is error code.
- * On hw interrupt, it's IRQ number:
- */
+
+       /*
+        * orig_ax is used on entry for:
+        * - the syscall number (syscall, sysenter, int80)
+        * - error_code stored by the CPU on traps and exceptions
+        * - the interrupt number for device interrupts
+        *
+        * A FRED stack frame starts here:
+        *   1) It _always_ includes an error code;
+        *
+        *   2) The return frame for ERET[US] starts here, but
+        *      the content of orig_ax is ignored.
+        */
        unsigned long orig_ax;
-/* Return frame for iretq */
+
+       /* The IRETQ return frame starts here */
        unsigned long ip;
-       unsigned long cs;
+
+       union {
+               /* CS selector */
+               u16             cs;
+               /* The extended 64-bit data slot containing CS */
+               u64             csx;
+               /* The FRED CS extension */
+               struct fred_cs  fred_cs;
+       };
+
        unsigned long flags;
        unsigned long sp;
-       unsigned long ss;
-/* top of stack page */
+
+       union {
+               /* SS selector */
+               u16             ss;
+               /* The extended 64-bit data slot containing SS */
+               u64             ssx;
+               /* The FRED SS extension */
+               struct fred_ss  fred_ss;
+       };
+
+       /*
+        * Top of stack on IDT systems, while FRED systems have extra fields
+        * defined above for storing exception related information, e.g. CR2 or
+        * DR6.
+        */
 };
 
 #endif /* !__i386__ */
index 255a78d9d90672afb053875184d89b05bab52a0b..12dbd2588ca7ccdaa1ea641327b5cbf866f50a68 100644 (file)
@@ -7,6 +7,13 @@
 #include <linux/sched.h>
 #include <linux/jump_label.h>
 
+/*
+ * This value can never be a valid CLOSID, and is used when mapping a
+ * (closid, rmid) pair to an index and back. On x86 only the RMID is
+ * needed. The index is a software defined value.
+ */
+#define X86_RESCTRL_EMPTY_CLOSID         ((u32)~0)
+
 /**
  * struct resctrl_pqr_state - State cache for the PQR MSR
  * @cur_rmid:          The cached Resource Monitoring ID
@@ -31,10 +38,47 @@ struct resctrl_pqr_state {
 
 DECLARE_PER_CPU(struct resctrl_pqr_state, pqr_state);
 
+extern bool rdt_alloc_capable;
+extern bool rdt_mon_capable;
+
 DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
 DECLARE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
 DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key);
 
+static inline bool resctrl_arch_alloc_capable(void)
+{
+       return rdt_alloc_capable;
+}
+
+static inline void resctrl_arch_enable_alloc(void)
+{
+       static_branch_enable_cpuslocked(&rdt_alloc_enable_key);
+       static_branch_inc_cpuslocked(&rdt_enable_key);
+}
+
+static inline void resctrl_arch_disable_alloc(void)
+{
+       static_branch_disable_cpuslocked(&rdt_alloc_enable_key);
+       static_branch_dec_cpuslocked(&rdt_enable_key);
+}
+
+static inline bool resctrl_arch_mon_capable(void)
+{
+       return rdt_mon_capable;
+}
+
+static inline void resctrl_arch_enable_mon(void)
+{
+       static_branch_enable_cpuslocked(&rdt_mon_enable_key);
+       static_branch_inc_cpuslocked(&rdt_enable_key);
+}
+
+static inline void resctrl_arch_disable_mon(void)
+{
+       static_branch_disable_cpuslocked(&rdt_mon_enable_key);
+       static_branch_dec_cpuslocked(&rdt_enable_key);
+}
+
 /*
  * __resctrl_sched_in() - Writes the task's CLOSid/RMID to IA32_PQR_MSR
  *
@@ -88,12 +132,58 @@ static inline unsigned int resctrl_arch_round_mon_val(unsigned int val)
        return val * scale;
 }
 
+static inline void resctrl_arch_set_closid_rmid(struct task_struct *tsk,
+                                               u32 closid, u32 rmid)
+{
+       WRITE_ONCE(tsk->closid, closid);
+       WRITE_ONCE(tsk->rmid, rmid);
+}
+
+static inline bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
+{
+       return READ_ONCE(tsk->closid) == closid;
+}
+
+static inline bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 ignored,
+                                          u32 rmid)
+{
+       return READ_ONCE(tsk->rmid) == rmid;
+}
+
 static inline void resctrl_sched_in(struct task_struct *tsk)
 {
        if (static_branch_likely(&rdt_enable_key))
                __resctrl_sched_in(tsk);
 }
 
+static inline u32 resctrl_arch_system_num_rmid_idx(void)
+{
+       /* RMID are independent numbers for x86. num_rmid_idx == num_rmid */
+       return boot_cpu_data.x86_cache_max_rmid + 1;
+}
+
+static inline void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
+{
+       *rmid = idx;
+       *closid = X86_RESCTRL_EMPTY_CLOSID;
+}
+
+static inline u32 resctrl_arch_rmid_idx_encode(u32 ignored, u32 rmid)
+{
+       return rmid;
+}
+
+/* x86 can always read an rmid, nothing needs allocating */
+struct rdt_resource;
+static inline void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, int evtid)
+{
+       might_sleep();
+       return NULL;
+};
+
+static inline void resctrl_arch_mon_ctx_free(struct rdt_resource *r, int evtid,
+                                            void *ctx) { };
+
 void resctrl_cpu_detect(struct cpuinfo_x86 *c);
 
 #else
index a5e89641bd2dac7e9fa5e1ab548369836640908a..9aee31862b4a8b8cbf2242db991a5cbeb3d41e21 100644 (file)
@@ -47,6 +47,7 @@ int set_memory_uc(unsigned long addr, int numpages);
 int set_memory_wc(unsigned long addr, int numpages);
 int set_memory_wb(unsigned long addr, int numpages);
 int set_memory_np(unsigned long addr, int numpages);
+int set_memory_p(unsigned long addr, int numpages);
 int set_memory_4k(unsigned long addr, int numpages);
 int set_memory_encrypted(unsigned long addr, int numpages);
 int set_memory_decrypted(unsigned long addr, int numpages);
index 5c83729c8e71ff5a287095211829cf197365a728..e61e68d71cba04246d10f49951df4602e3ba9c3b 100644 (file)
@@ -48,7 +48,7 @@ extern unsigned long saved_video_mode;
 extern void reserve_standard_io_resources(void);
 extern void i386_reserve_resources(void);
 extern unsigned long __startup_64(unsigned long physaddr, struct boot_params *bp);
-extern void startup_64_setup_env(unsigned long physbase);
+extern void startup_64_setup_gdt_idt(void);
 extern void early_setup_idt(void);
 extern void __init do_early_exception(struct pt_regs *regs, int trapnr);
 
diff --git a/arch/x86/include/asm/setup_data.h b/arch/x86/include/asm/setup_data.h
new file mode 100644 (file)
index 0000000..77c5111
--- /dev/null
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_SETUP_DATA_H
+#define _ASM_X86_SETUP_DATA_H
+
+#include <uapi/asm/setup_data.h>
+
+#ifndef __ASSEMBLY__
+
+struct pci_setup_rom {
+       struct setup_data data;
+       uint16_t vendor;
+       uint16_t devid;
+       uint64_t pcilen;
+       unsigned long segment;
+       unsigned long bus;
+       unsigned long device;
+       unsigned long function;
+       uint8_t romdata[];
+};
+
+/* kexec external ABI */
+struct efi_setup_data {
+       u64 fw_vendor;
+       u64 __unused;
+       u64 tables;
+       u64 smbios;
+       u64 reserved[8];
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_X86_SETUP_DATA_H */
index 5b4a1ce3d36808b4ae0987547de69a534924d4bf..9477b4053bce2ccb9d6c1c0113fd6ee44bd34d50 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <asm/insn.h>
 #include <asm/sev-common.h>
-#include <asm/bootparam.h>
 #include <asm/coco.h>
 
 #define GHCB_PROTOCOL_MIN      1ULL
@@ -22,6 +21,8 @@
 
 #define        VMGEXIT()                       { asm volatile("rep; vmmcall\n\r"); }
 
+struct boot_params;
+
 enum es_result {
        ES_OK,                  /* All good */
        ES_UNSUPPORTED,         /* Requested operation not supported */
@@ -87,9 +88,23 @@ extern bool handle_vc_boot_ghcb(struct pt_regs *regs);
 /* Software defined (when rFlags.CF = 1) */
 #define PVALIDATE_FAIL_NOUPDATE                255
 
+/* RMUPDATE detected 4K page and 2MB page overlap. */
+#define RMPUPDATE_FAIL_OVERLAP         4
+
 /* RMP page size */
 #define RMP_PG_SIZE_4K                 0
 #define RMP_PG_SIZE_2M                 1
+#define RMP_TO_PG_LEVEL(level)         (((level) == RMP_PG_SIZE_4K) ? PG_LEVEL_4K : PG_LEVEL_2M)
+#define PG_LEVEL_TO_RMP(level)         (((level) == PG_LEVEL_4K) ? RMP_PG_SIZE_4K : RMP_PG_SIZE_2M)
+
+struct rmp_state {
+       u64 gpa;
+       u8 assigned;
+       u8 pagesize;
+       u8 immutable;
+       u8 rsvd;
+       u32 asid;
+} __packed;
 
 #define RMPADJUST_VMSA_PAGE_BIT                BIT(16)
 
@@ -199,20 +214,22 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate)
 struct snp_guest_request_ioctl;
 
 void setup_ghcb(void);
-void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr,
-                                        unsigned long npages);
-void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr,
-                                       unsigned long npages);
+void early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr,
+                                 unsigned long npages);
+void early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr,
+                                unsigned long npages);
 void __init snp_prep_memory(unsigned long paddr, unsigned int sz, enum psc_op op);
 void snp_set_memory_shared(unsigned long vaddr, unsigned long npages);
 void snp_set_memory_private(unsigned long vaddr, unsigned long npages);
 void snp_set_wakeup_secondary_cpu(void);
 bool snp_init(struct boot_params *bp);
-void __init __noreturn snp_abort(void);
+void __noreturn snp_abort(void);
 int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio);
 void snp_accept_memory(phys_addr_t start, phys_addr_t end);
 u64 snp_get_unsupported_features(u64 status);
 u64 sev_get_status(void);
+void kdump_sev_callback(void);
+void sev_show_status(void);
 #else
 static inline void sev_es_ist_enter(struct pt_regs *regs) { }
 static inline void sev_es_ist_exit(void) { }
@@ -241,6 +258,30 @@ static inline int snp_issue_guest_request(u64 exit_code, struct snp_req_data *in
 static inline void snp_accept_memory(phys_addr_t start, phys_addr_t end) { }
 static inline u64 snp_get_unsupported_features(u64 status) { return 0; }
 static inline u64 sev_get_status(void) { return 0; }
+static inline void kdump_sev_callback(void) { }
+static inline void sev_show_status(void) { }
+#endif
+
+#ifdef CONFIG_KVM_AMD_SEV
+bool snp_probe_rmptable_info(void);
+int snp_lookup_rmpentry(u64 pfn, bool *assigned, int *level);
+void snp_dump_hva_rmpentry(unsigned long address);
+int psmash(u64 pfn);
+int rmp_make_private(u64 pfn, u64 gpa, enum pg_level level, u32 asid, bool immutable);
+int rmp_make_shared(u64 pfn, enum pg_level level);
+void snp_leak_pages(u64 pfn, unsigned int npages);
+#else
+static inline bool snp_probe_rmptable_info(void) { return false; }
+static inline int snp_lookup_rmpentry(u64 pfn, bool *assigned, int *level) { return -ENODEV; }
+static inline void snp_dump_hva_rmpentry(unsigned long address) {}
+static inline int psmash(u64 pfn) { return -ENODEV; }
+static inline int rmp_make_private(u64 pfn, u64 gpa, enum pg_level level, u32 asid,
+                                  bool immutable)
+{
+       return -ENODEV;
+}
+static inline int rmp_make_shared(u64 pfn, enum pg_level level) { return -ENODEV; }
+static inline void snp_leak_pages(u64 pfn, unsigned int npages) {}
 #endif
 
 #endif
index 4fab2ed454f3ab86a636ec9d2ac1ed682d1de624..a35936b512fee639db9930fa64b543687edbf0b8 100644 (file)
@@ -8,9 +8,6 @@
 #include <asm/current.h>
 #include <asm/thread_info.h>
 
-extern int smp_num_siblings;
-extern unsigned int num_processors;
-
 DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
 DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_core_map);
 DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_die_map);
@@ -59,11 +56,6 @@ static inline void stop_other_cpus(void)
        smp_ops.stop_other_cpus(1);
 }
 
-static inline void smp_prepare_boot_cpu(void)
-{
-       smp_ops.smp_prepare_boot_cpu();
-}
-
 static inline void smp_prepare_cpus(unsigned int max_cpus)
 {
        smp_ops.smp_prepare_cpus(max_cpus);
@@ -110,7 +102,6 @@ void cpu_disable_common(void);
 void native_smp_prepare_boot_cpu(void);
 void smp_prepare_cpus_common(void);
 void native_smp_prepare_cpus(unsigned int max_cpus);
-void calculate_max_logical_packages(void);
 void native_smp_cpus_done(unsigned int max_cpus);
 int common_cpu_up(unsigned int cpunum, struct task_struct *tidle);
 int native_kick_ap(unsigned int cpu, struct task_struct *tidle);
@@ -174,8 +165,6 @@ static inline struct cpumask *cpu_llc_shared_mask(int cpu)
 }
 #endif /* CONFIG_SMP */
 
-extern unsigned disabled_cpus;
-
 #ifdef CONFIG_DEBUG_NMI_SELFTEST
 extern void nmi_selftest(void);
 #else
index c648502e453579e3d0deeb9033f2832d9a2fd2a1..658b690b2ccb7d627c6418b32cba5c3a7d959832 100644 (file)
@@ -96,4 +96,6 @@ static inline void speculative_store_bypass_ht_init(void) { }
 extern void speculation_ctrl_update(unsigned long tif);
 extern void speculation_ctrl_update_current(void);
 
+extern bool itlb_multihit_kvm_mitigation;
+
 #endif
index 48f8dd47cf6882ac9e3920d6e7105c0eff430528..2e9fc5c400cdc364a306f5d0f3c7dda305070627 100644 (file)
@@ -2,11 +2,11 @@
 #ifndef _ASM_X86_SPECIAL_INSNS_H
 #define _ASM_X86_SPECIAL_INSNS_H
 
-
 #ifdef __KERNEL__
-
 #include <asm/nops.h>
 #include <asm/processor-flags.h>
+
+#include <linux/errno.h>
 #include <linux/irqflags.h>
 #include <linux/jump_label.h>
 
@@ -224,10 +224,10 @@ static inline void serialize(void)
 }
 
 /* The dst parameter must be 64-bytes aligned */
-static inline void movdir64b(void __iomem *dst, const void *src)
+static inline void movdir64b(void *dst, const void *src)
 {
        const struct { char _[64]; } *__src = src;
-       struct { char _[64]; } __iomem *__dst = dst;
+       struct { char _[64]; } *__dst = dst;
 
        /*
         * MOVDIR64B %(rdx), rax.
@@ -245,6 +245,11 @@ static inline void movdir64b(void __iomem *dst, const void *src)
                     :  "m" (*__src), "a" (__dst), "d" (__src));
 }
 
+static inline void movdir64b_io(void __iomem *dst, const void *src)
+{
+       movdir64b((void __force *)dst, src);
+}
+
 /**
  * enqcmds - Enqueue a command in supervisor (CPL0) mode
  * @dst: destination, in MMIO space (must be 512-bit aligned)
index 343b722ccaf21d0654b5d7dc19596a4ef548a8e5..125c407e2abe6da21a05f8a644ecce501ed1c910 100644 (file)
@@ -46,7 +46,7 @@
 #define ARCH_DEFINE_STATIC_CALL_TRAMP(name, func)                      \
        __ARCH_DEFINE_STATIC_CALL_TRAMP(name, ".byte 0xe9; .long " #func " - (. + 4)")
 
-#ifdef CONFIG_RETHUNK
+#ifdef CONFIG_MITIGATION_RETHUNK
 #define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name)                       \
        __ARCH_DEFINE_STATIC_CALL_TRAMP(name, "jmp __x86_return_thunk")
 #else
index f42dbf17f52b0ee12ec74f34d1fb551743be0e6c..c3bd0c0758c9a4366181b0e83c52c83142475d84 100644 (file)
@@ -70,9 +70,13 @@ static inline void update_task_stack(struct task_struct *task)
 #ifdef CONFIG_X86_32
        this_cpu_write(cpu_tss_rw.x86_tss.sp1, task->thread.sp0);
 #else
-       /* Xen PV enters the kernel on the thread stack. */
-       if (cpu_feature_enabled(X86_FEATURE_XENPV))
+       if (cpu_feature_enabled(X86_FEATURE_FRED)) {
+               /* WRMSRNS is a baseline feature for FRED. */
+               wrmsrns(MSR_IA32_FRED_RSP0, (unsigned long)task_stack_page(task) + THREAD_SIZE);
+       } else if (cpu_feature_enabled(X86_FEATURE_XENPV)) {
+               /* Xen PV enters the kernel on the thread stack. */
                load_sp0(task_top_of_stack(task));
+       }
 #endif
 }
 
index 0b70653a98c1573a475edf808601cb1c33f9a45e..345aafbc19648865f7262b64e43d1ae5176aae4c 100644 (file)
@@ -15,6 +15,8 @@
 
 extern void text_poke_early(void *addr, const void *opcode, size_t len);
 
+extern void apply_relocation(u8 *buf, size_t len, u8 *dest, u8 *src, size_t src_len);
+
 /*
  * Clear and restore the kernel write-protection flag on the local CPU.
  * Allows the kernel to edit read-only pages.
index d63b02940747fad97cabfdb399b488d577d36529..12da7dfd5ef13b417eaae07d244edac620f5e8a2 100644 (file)
@@ -31,7 +31,9 @@
  * In vm86 mode, the hardware frame is much longer still, so add 16
  * bytes to make room for the real-mode segments.
  *
- * x86_64 has a fixed-length stack frame.
+ * x86-64 has a fixed-length stack frame, but it depends on whether
+ * or not FRED is enabled. Future versions of FRED might make this
+ * dynamic, but for now it is always 2 words longer.
  */
 #ifdef CONFIG_X86_32
 # ifdef CONFIG_VM86
 # else
 #  define TOP_OF_KERNEL_STACK_PADDING 8
 # endif
-#else
-# define TOP_OF_KERNEL_STACK_PADDING 0
+#else /* x86-64 */
+# ifdef CONFIG_X86_FRED
+#  define TOP_OF_KERNEL_STACK_PADDING (2 * 8)
+# else
+#  define TOP_OF_KERNEL_STACK_PADDING 0
+# endif
 #endif
 
 /*
index 5f87f6b9b09e74c1a6d01a38777bdc9856ac2f81..abe3a8f22cbd969898505b7550f9503f33bbae5e 100644 (file)
@@ -102,6 +102,35 @@ static inline void setup_node_to_cpumask_map(void) { }
 
 #include <asm-generic/topology.h>
 
+/* Topology information */
+enum x86_topology_domains {
+       TOPO_SMT_DOMAIN,
+       TOPO_CORE_DOMAIN,
+       TOPO_MODULE_DOMAIN,
+       TOPO_TILE_DOMAIN,
+       TOPO_DIE_DOMAIN,
+       TOPO_DIEGRP_DOMAIN,
+       TOPO_PKG_DOMAIN,
+       TOPO_MAX_DOMAIN,
+};
+
+struct x86_topology_system {
+       unsigned int    dom_shifts[TOPO_MAX_DOMAIN];
+       unsigned int    dom_size[TOPO_MAX_DOMAIN];
+};
+
+extern struct x86_topology_system x86_topo_system;
+
+static inline unsigned int topology_get_domain_size(enum x86_topology_domains dom)
+{
+       return x86_topo_system.dom_size[dom];
+}
+
+static inline unsigned int topology_get_domain_shift(enum x86_topology_domains dom)
+{
+       return dom == TOPO_SMT_DOMAIN ? 0 : x86_topo_system.dom_shifts[dom - 1];
+}
+
 extern const struct cpumask *cpu_coregroup_mask(int cpu);
 extern const struct cpumask *cpu_clustergroup_mask(int cpu);
 
@@ -112,7 +141,42 @@ extern const struct cpumask *cpu_clustergroup_mask(int cpu);
 #define topology_core_id(cpu)                  (cpu_data(cpu).topo.core_id)
 #define topology_ppin(cpu)                     (cpu_data(cpu).ppin)
 
-extern unsigned int __max_die_per_package;
+#define topology_amd_node_id(cpu)              (cpu_data(cpu).topo.amd_node_id)
+
+extern unsigned int __max_dies_per_package;
+extern unsigned int __max_logical_packages;
+extern unsigned int __max_threads_per_core;
+extern unsigned int __num_threads_per_package;
+extern unsigned int __num_cores_per_package;
+
+static inline unsigned int topology_max_packages(void)
+{
+       return __max_logical_packages;
+}
+
+static inline unsigned int topology_max_dies_per_package(void)
+{
+       return __max_dies_per_package;
+}
+
+static inline unsigned int topology_num_cores_per_package(void)
+{
+       return __num_cores_per_package;
+}
+
+static inline unsigned int topology_num_threads_per_package(void)
+{
+       return __num_threads_per_package;
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+int topology_get_logical_id(u32 apicid, enum x86_topology_domains at_level);
+#else
+static inline int topology_get_logical_id(u32 apicid, enum x86_topology_domains at_level)
+{
+       return 0;
+}
+#endif
 
 #ifdef CONFIG_SMP
 #define topology_cluster_id(cpu)               (cpu_data(cpu).topo.l2c_id)
@@ -121,12 +185,11 @@ extern unsigned int __max_die_per_package;
 #define topology_core_cpumask(cpu)             (per_cpu(cpu_core_map, cpu))
 #define topology_sibling_cpumask(cpu)          (per_cpu(cpu_sibling_map, cpu))
 
-extern unsigned int __max_logical_packages;
-#define topology_max_packages()                        (__max_logical_packages)
 
-static inline int topology_max_die_per_package(void)
+static inline int topology_phys_to_logical_pkg(unsigned int pkg)
 {
-       return __max_die_per_package;
+       return topology_get_logical_id(pkg << x86_topo_system.dom_shifts[TOPO_PKG_DOMAIN],
+                                      TOPO_PKG_DOMAIN);
 }
 
 extern int __max_smt_threads;
@@ -138,9 +201,12 @@ static inline int topology_max_smt_threads(void)
 
 #include <linux/cpu_smt.h>
 
-int topology_update_package_map(unsigned int apicid, unsigned int cpu);
-int topology_update_die_map(unsigned int dieid, unsigned int cpu);
-int topology_phys_to_logical_pkg(unsigned int pkg);
+extern unsigned int __amd_nodes_per_pkg;
+
+static inline unsigned int topology_amd_nodes_per_pkg(void)
+{
+       return __amd_nodes_per_pkg;
+}
 
 extern struct cpumask __cpu_primary_thread_mask;
 #define cpu_primary_thread_mask ((const struct cpumask *)&__cpu_primary_thread_mask)
@@ -153,16 +219,12 @@ static inline bool topology_is_primary_thread(unsigned int cpu)
 {
        return cpumask_test_cpu(cpu, cpu_primary_thread_mask);
 }
+
 #else /* CONFIG_SMP */
-#define topology_max_packages()                        (1)
-static inline int
-topology_update_package_map(unsigned int apicid, unsigned int cpu) { return 0; }
-static inline int
-topology_update_die_map(unsigned int dieid, unsigned int cpu) { return 0; }
 static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; }
-static inline int topology_max_die_per_package(void) { return 1; }
 static inline int topology_max_smt_threads(void) { return 1; }
 static inline bool topology_is_primary_thread(unsigned int cpu) { return true; }
+static inline unsigned int topology_amd_nodes_per_pkg(void) { return 1; }
 #endif /* !CONFIG_SMP */
 
 static inline void arch_fix_phys_package_id(int num, u32 slot)
index afa524325e558d281e9be0feb1b91cd3a7a488bc..a23a7b707b64e17077a83eae8ae23e4f3cd24a5b 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _ASM_X86_TRAP_PF_H
 #define _ASM_X86_TRAP_PF_H
 
+#include <linux/bits.h>
+
 /*
  * Page fault error code bits:
  *
  *   bit 5 ==                          1: protection keys block access
  *   bit 6 ==                          1: shadow stack access fault
  *   bit 15 ==                         1: SGX MMU page-fault
+ *   bit 31 ==                         1: fault was due to RMP violation
  */
 enum x86_pf_error_code {
-       X86_PF_PROT     =               1 << 0,
-       X86_PF_WRITE    =               1 << 1,
-       X86_PF_USER     =               1 << 2,
-       X86_PF_RSVD     =               1 << 3,
-       X86_PF_INSTR    =               1 << 4,
-       X86_PF_PK       =               1 << 5,
-       X86_PF_SHSTK    =               1 << 6,
-       X86_PF_SGX      =               1 << 15,
+       X86_PF_PROT     =               BIT(0),
+       X86_PF_WRITE    =               BIT(1),
+       X86_PF_USER     =               BIT(2),
+       X86_PF_RSVD     =               BIT(3),
+       X86_PF_INSTR    =               BIT(4),
+       X86_PF_PK       =               BIT(5),
+       X86_PF_SHSTK    =               BIT(6),
+       X86_PF_SGX      =               BIT(15),
+       X86_PF_RMP      =               BIT(31),
 };
 
 #endif /* _ASM_X86_TRAP_PF_H */
index f5d2325aa0b749db0b6743adb85c94cb0f303624..8d1154cdf7875c923645e3b5f5bf111ce9ffd1f0 100644 (file)
@@ -2,6 +2,18 @@
 #ifndef _ASM_X86_TRAPNR_H
 #define _ASM_X86_TRAPNR_H
 
+/*
+ * Event type codes used by FRED, Intel VT-x and AMD SVM
+ */
+#define EVENT_TYPE_EXTINT      0       // External interrupt
+#define EVENT_TYPE_RESERVED    1
+#define EVENT_TYPE_NMI         2       // NMI
+#define EVENT_TYPE_HWEXC       3       // Hardware originated traps, exceptions
+#define EVENT_TYPE_SWINT       4       // INT n
+#define EVENT_TYPE_PRIV_SWEXC  5       // INT1
+#define EVENT_TYPE_SWEXC       6       // INTO, INT3
+#define EVENT_TYPE_OTHER       7       // FRED SYSCALL/SYSENTER, VT-x MTF
+
 /* Interrupts/Exceptions */
 
 #define X86_TRAP_DE             0      /* Divide-by-zero */
index 594fce0ca744398f0086f43582f66fe870b12fa9..405efb3e4996e7f1b8a65e2be4454c94eea07288 100644 (file)
@@ -5,8 +5,9 @@
 #ifndef _ASM_X86_TSC_H
 #define _ASM_X86_TSC_H
 
-#include <asm/processor.h>
 #include <asm/cpufeature.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
 
 /*
  * Standard way to access the cycle counter.
index f2c02e4469ccc3db6265b2e36a6bd336f5e822fc..04789f45ab2b2ffb063045cb00c50b4974dfde49 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/alternative.h>
 #include <asm/cpufeatures.h>
 #include <asm/page.h>
+#include <asm/percpu.h>
 
 #ifdef CONFIG_ADDRESS_MASKING
 /*
  */
 static inline unsigned long __untagged_addr(unsigned long addr)
 {
-       /*
-        * Refer tlbstate_untag_mask directly to avoid RIP-relative relocation
-        * in alternative instructions. The relocation gets wrong when gets
-        * copied to the target place.
-        */
        asm (ALTERNATIVE("",
-                        "and %%gs:tlbstate_untag_mask, %[addr]\n\t", X86_FEATURE_LAM)
-            : [addr] "+r" (addr) : "m" (tlbstate_untag_mask));
+                        "and " __percpu_arg([mask]) ", %[addr]", X86_FEATURE_LAM)
+            : [addr] "+r" (addr)
+            : [mask] "m" (__my_cpu_var(tlbstate_untag_mask)));
 
        return addr;
 }
@@ -54,7 +51,7 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm,
  * half and a user half.  When cast to a signed type, user pointers
  * are positive and kernel pointers are negative.
  */
-#define valid_user_address(x) ((long)(x) >= 0)
+#define valid_user_address(x) ((__force long)(x) >= 0)
 
 /*
  * User pointers can have tag bits on x86-64.  This scheme tolerates
@@ -87,8 +84,9 @@ static inline bool __access_ok(const void __user *ptr, unsigned long size)
        if (__builtin_constant_p(size <= PAGE_SIZE) && size <= PAGE_SIZE) {
                return valid_user_address(ptr);
        } else {
-               unsigned long sum = size + (unsigned long)ptr;
-               return valid_user_address(sum) && sum >= (unsigned long)ptr;
+               unsigned long sum = size + (__force unsigned long)ptr;
+
+               return valid_user_address(sum) && sum >= (__force unsigned long)ptr;
        }
 }
 #define __access_ok __access_ok
index 0e73616b82f3469f47877e0cc56ca6b79f034173..4dba173630084f88cabc20216b03ed9c86a1a072 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/types.h>
 
 #include <uapi/asm/vmx.h>
+#include <asm/trapnr.h>
 #include <asm/vmxfeatures.h>
 
 #define VMCS_CONTROL_BIT(x)    BIT(VMX_FEATURE_##x & 0x1f)
@@ -374,14 +375,14 @@ enum vmcs_field {
 #define VECTORING_INFO_DELIVER_CODE_MASK       INTR_INFO_DELIVER_CODE_MASK
 #define VECTORING_INFO_VALID_MASK              INTR_INFO_VALID_MASK
 
-#define INTR_TYPE_EXT_INTR              (0 << 8) /* external interrupt */
-#define INTR_TYPE_RESERVED              (1 << 8) /* reserved */
-#define INTR_TYPE_NMI_INTR             (2 << 8) /* NMI */
-#define INTR_TYPE_HARD_EXCEPTION       (3 << 8) /* processor exception */
-#define INTR_TYPE_SOFT_INTR             (4 << 8) /* software interrupt */
-#define INTR_TYPE_PRIV_SW_EXCEPTION    (5 << 8) /* ICE breakpoint - undocumented */
-#define INTR_TYPE_SOFT_EXCEPTION       (6 << 8) /* software exception */
-#define INTR_TYPE_OTHER_EVENT           (7 << 8) /* other event */
+#define INTR_TYPE_EXT_INTR             (EVENT_TYPE_EXTINT << 8)        /* external interrupt */
+#define INTR_TYPE_RESERVED             (EVENT_TYPE_RESERVED << 8)      /* reserved */
+#define INTR_TYPE_NMI_INTR             (EVENT_TYPE_NMI << 8)           /* NMI */
+#define INTR_TYPE_HARD_EXCEPTION       (EVENT_TYPE_HWEXC << 8)         /* processor exception */
+#define INTR_TYPE_SOFT_INTR            (EVENT_TYPE_SWINT << 8)         /* software interrupt */
+#define INTR_TYPE_PRIV_SW_EXCEPTION    (EVENT_TYPE_PRIV_SWEXC << 8)    /* ICE breakpoint */
+#define INTR_TYPE_SOFT_EXCEPTION       (EVENT_TYPE_SWEXC << 8)         /* software exception */
+#define INTR_TYPE_OTHER_EVENT          (EVENT_TYPE_OTHER << 8)         /* other event */
 
 /* GUEST_INTERRUPTIBILITY_INFO flags. */
 #define GUEST_INTR_STATE_STI           0x00000001
index ab60a71a8dcb98e62bccf3c045066df8f42f30f4..472f0263dbc6129c30636f149b94d5828ac300c6 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/seqlock.h>
 #include <uapi/asm/vsyscall.h>
+#include <asm/page_types.h>
 
 #ifdef CONFIG_X86_VSYSCALL_EMULATION
 extern void map_vsyscall(void);
@@ -24,4 +25,13 @@ static inline bool emulate_vsyscall(unsigned long error_code,
 }
 #endif
 
+/*
+ * The (legacy) vsyscall page is the long page in the kernel portion
+ * of the address space that has user-accessible permissions.
+ */
+static inline bool is_vsyscall_vaddr(unsigned long vaddr)
+{
+       return unlikely((vaddr & PAGE_MASK) == VSYSCALL_ADDR);
+}
+
 #endif /* _ASM_X86_VSYSCALL_H */
index c878616a18b85750c92f764f1895cafb0698dd85..b89b40f250e6f55c52cbd520bdbaeaff4eb77cf2 100644 (file)
@@ -2,8 +2,6 @@
 #ifndef _ASM_X86_PLATFORM_H
 #define _ASM_X86_PLATFORM_H
 
-#include <asm/bootparam.h>
-
 struct ghcb;
 struct mpc_bus;
 struct mpc_cpu;
@@ -15,13 +13,15 @@ struct irq_domain;
 /**
  * struct x86_init_mpparse - platform specific mpparse ops
  * @setup_ioapic_ids:          platform specific ioapic id override
- * @find_smp_config:           find the smp configuration
- * @get_smp_config:            get the smp configuration
+ * @find_mptable:              Find MPTABLE early to reserve the memory region
+ * @early_parse_smp_cfg:       Parse the SMP configuration data early before initmem_init()
+ * @parse_smp_cfg:             Parse the SMP configuration data
  */
 struct x86_init_mpparse {
        void (*setup_ioapic_ids)(void);
-       void (*find_smp_config)(void);
-       void (*get_smp_config)(unsigned int early);
+       void (*find_mptable)(void);
+       void (*early_parse_smp_cfg)(void);
+       void (*parse_smp_cfg)(void);
 };
 
 /**
index 01d19fc223463d17eb6dcef28c9ca471abfa7aa2..9b82eebd7add55e918d50a1e3a47e5300f29c222 100644 (file)
@@ -2,21 +2,7 @@
 #ifndef _ASM_X86_BOOTPARAM_H
 #define _ASM_X86_BOOTPARAM_H
 
-/* setup_data/setup_indirect types */
-#define SETUP_NONE                     0
-#define SETUP_E820_EXT                 1
-#define SETUP_DTB                      2
-#define SETUP_PCI                      3
-#define SETUP_EFI                      4
-#define SETUP_APPLE_PROPERTIES         5
-#define SETUP_JAILHOUSE                        6
-#define SETUP_CC_BLOB                  7
-#define SETUP_IMA                      8
-#define SETUP_RNG_SEED                 9
-#define SETUP_ENUM_MAX                 SETUP_RNG_SEED
-
-#define SETUP_INDIRECT                 (1<<31)
-#define SETUP_TYPE_MAX                 (SETUP_ENUM_MAX | SETUP_INDIRECT)
+#include <asm/setup_data.h>
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK       0x07FF
@@ -38,6 +24,7 @@
 #define XLF_EFI_KEXEC                  (1<<4)
 #define XLF_5LEVEL                     (1<<5)
 #define XLF_5LEVEL_ENABLED             (1<<6)
+#define XLF_MEM_ENCRYPTION             (1<<7)
 
 #ifndef __ASSEMBLY__
 
 #include <asm/ist.h>
 #include <video/edid.h>
 
-/* extensible setup data list node */
-struct setup_data {
-       __u64 next;
-       __u32 type;
-       __u32 len;
-       __u8 data[];
-};
-
-/* extensible setup indirect data node */
-struct setup_indirect {
-       __u32 type;
-       __u32 reserved;  /* Reserved, must be set to zero. */
-       __u64 len;
-       __u64 addr;
-};
-
 struct setup_header {
        __u8    setup_sects;
        __u16   root_flags;
@@ -136,51 +107,11 @@ struct efi_info {
  */
 #define E820_MAX_ENTRIES_ZEROPAGE 128
 
-/*
- * The E820 memory region entry of the boot protocol ABI:
- */
-struct boot_e820_entry {
-       __u64 addr;
-       __u64 size;
-       __u32 type;
-} __attribute__((packed));
-
 /*
  * Smallest compatible version of jailhouse_setup_data required by this kernel.
  */
 #define JAILHOUSE_SETUP_REQUIRED_VERSION       1
 
-/*
- * The boot loader is passing platform information via this Jailhouse-specific
- * setup data structure.
- */
-struct jailhouse_setup_data {
-       struct {
-               __u16   version;
-               __u16   compatible_version;
-       } __attribute__((packed)) hdr;
-       struct {
-               __u16   pm_timer_address;
-               __u16   num_cpus;
-               __u64   pci_mmconfig_base;
-               __u32   tsc_khz;
-               __u32   apic_khz;
-               __u8    standard_ioapic;
-               __u8    cpu_ids[255];
-       } __attribute__((packed)) v1;
-       struct {
-               __u32   flags;
-       } __attribute__((packed)) v2;
-} __attribute__((packed));
-
-/*
- * IMA buffer setup data information from the previous kernel during kexec
- */
-struct ima_setup_data {
-       __u64 addr;
-       __u64 size;
-} __attribute__((packed));
-
 /* The so-called "zeropage" */
 struct boot_params {
        struct screen_info screen_info;                 /* 0x000 */
index d898432947ff359a8d692faa1845488ff47f9180..f1a4adc782720b0f9317d0ef7f1abb03f5850f4c 100644 (file)
 #define X86_CR4_LAM_SUP_BIT    28 /* LAM for supervisor pointers */
 #define X86_CR4_LAM_SUP                _BITUL(X86_CR4_LAM_SUP_BIT)
 
+#ifdef __x86_64__
+#define X86_CR4_FRED_BIT       32 /* enable FRED kernel entry */
+#define X86_CR4_FRED           _BITUL(X86_CR4_FRED_BIT)
+#else
+#define X86_CR4_FRED           (0)
+#endif
+
 /*
  * x86-64 Task Priority Register, CR8
  */
diff --git a/arch/x86/include/uapi/asm/setup_data.h b/arch/x86/include/uapi/asm/setup_data.h
new file mode 100644 (file)
index 0000000..b111b0c
--- /dev/null
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_ASM_X86_SETUP_DATA_H
+#define _UAPI_ASM_X86_SETUP_DATA_H
+
+/* setup_data/setup_indirect types */
+#define SETUP_NONE                     0
+#define SETUP_E820_EXT                 1
+#define SETUP_DTB                      2
+#define SETUP_PCI                      3
+#define SETUP_EFI                      4
+#define SETUP_APPLE_PROPERTIES         5
+#define SETUP_JAILHOUSE                        6
+#define SETUP_CC_BLOB                  7
+#define SETUP_IMA                      8
+#define SETUP_RNG_SEED                 9
+#define SETUP_ENUM_MAX                 SETUP_RNG_SEED
+
+#define SETUP_INDIRECT                 (1<<31)
+#define SETUP_TYPE_MAX                 (SETUP_ENUM_MAX | SETUP_INDIRECT)
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+/* extensible setup data list node */
+struct setup_data {
+       __u64 next;
+       __u32 type;
+       __u32 len;
+       __u8 data[];
+};
+
+/* extensible setup indirect data node */
+struct setup_indirect {
+       __u32 type;
+       __u32 reserved;  /* Reserved, must be set to zero. */
+       __u64 len;
+       __u64 addr;
+};
+
+/*
+ * The E820 memory region entry of the boot protocol ABI:
+ */
+struct boot_e820_entry {
+       __u64 addr;
+       __u64 size;
+       __u32 type;
+} __attribute__((packed));
+
+/*
+ * The boot loader is passing platform information via this Jailhouse-specific
+ * setup data structure.
+ */
+struct jailhouse_setup_data {
+       struct {
+               __u16   version;
+               __u16   compatible_version;
+       } __attribute__((packed)) hdr;
+       struct {
+               __u16   pm_timer_address;
+               __u16   num_cpus;
+               __u64   pci_mmconfig_base;
+               __u32   tsc_khz;
+               __u32   apic_khz;
+               __u8    standard_ioapic;
+               __u8    cpu_ids[255];
+       } __attribute__((packed)) v1;
+       struct {
+               __u32   flags;
+       } __attribute__((packed)) v2;
+} __attribute__((packed));
+
+/*
+ * IMA buffer setup data information from the previous kernel during kexec
+ */
+struct ima_setup_data {
+       __u64 addr;
+       __u64 size;
+} __attribute__((packed));
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _UAPI_ASM_X86_SETUP_DATA_H */
index 0000325ab98f4dc7408d0f338aab42bf6850c367..d0c744cb2a0e2daf1d7f0f97dd6a6b06f7fe2a0c 100644 (file)
@@ -33,6 +33,7 @@ KASAN_SANITIZE_sev.o                                  := n
 KCSAN_SANITIZE := n
 KMSAN_SANITIZE_head$(BITS).o                           := n
 KMSAN_SANITIZE_nmi.o                                   := n
+KMSAN_SANITIZE_sev.o                                   := n
 
 # If instrumentation of the following files is enabled, boot hangs during
 # first second.
@@ -48,6 +49,7 @@ obj-y                 += platform-quirks.o
 obj-y                  += process_$(BITS).o signal.o signal_$(BITS).o
 obj-y                  += traps.o idt.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
 obj-y                  += time.o ioport.o dumpstack.o nmi.o
+obj-$(CONFIG_X86_FRED) += fred.o
 obj-$(CONFIG_MODIFY_LDT_SYSCALL)       += ldt.o
 obj-$(CONFIG_X86_KERNEL_IBT)           += ibt_selftest.o
 obj-y                  += setup.o x86_init.o i8259.o irqinit.o
index 85a3ce2a3666adf09af6c063d0cf0191ff427e01..4bf82dbd2a6b5a0b59ba201e397bd06cfdfdbe38 100644 (file)
@@ -164,35 +164,6 @@ static int __init acpi_parse_madt(struct acpi_table_header *table)
        return 0;
 }
 
-/**
- * acpi_register_lapic - register a local apic and generates a logic cpu number
- * @id: local apic id to register
- * @acpiid: ACPI id to register
- * @enabled: this cpu is enabled or not
- *
- * Returns the logic cpu number which maps to the local apic
- */
-static int acpi_register_lapic(int id, u32 acpiid, u8 enabled)
-{
-       int cpu;
-
-       if (id >= MAX_LOCAL_APIC) {
-               pr_info("skipped apicid that is too big\n");
-               return -EINVAL;
-       }
-
-       if (!enabled) {
-               ++disabled_cpus;
-               return -EINVAL;
-       }
-
-       cpu = generic_processor_info(id);
-       if (cpu >= 0)
-               early_per_cpu(x86_cpu_to_acpiid, cpu) = acpiid;
-
-       return cpu;
-}
-
 static bool __init acpi_is_processor_usable(u32 lapic_flags)
 {
        if (lapic_flags & ACPI_MADT_ENABLED)
@@ -254,7 +225,7 @@ acpi_parse_x2apic(union acpi_subtable_headers *header, const unsigned long end)
                return 0;
        }
 
-       acpi_register_lapic(apic_id, processor->uid, enabled);
+       topology_register_apic(apic_id, processor->uid, enabled);
 #else
        pr_warn("x2apic entry ignored\n");
 #endif
@@ -289,9 +260,9 @@ acpi_parse_lapic(union acpi_subtable_headers * header, const unsigned long end)
         * to not preallocating memory for all NR_CPUS
         * when we use CPU hotplug.
         */
-       acpi_register_lapic(processor->id,      /* APIC ID */
-                           processor->processor_id, /* ACPI ID */
-                           processor->lapic_flags & ACPI_MADT_ENABLED);
+       topology_register_apic(processor->id,   /* APIC ID */
+                              processor->processor_id, /* ACPI ID */
+                              processor->lapic_flags & ACPI_MADT_ENABLED);
 
        has_lapic_cpus = true;
        return 0;
@@ -309,9 +280,9 @@ acpi_parse_sapic(union acpi_subtable_headers *header, const unsigned long end)
 
        acpi_table_print_madt_entry(&header->common);
 
-       acpi_register_lapic((processor->id << 8) | processor->eid,/* APIC ID */
-                           processor->processor_id, /* ACPI ID */
-                           processor->lapic_flags & ACPI_MADT_ENABLED);
+       topology_register_apic((processor->id << 8) | processor->eid,/* APIC ID */
+                              processor->processor_id, /* ACPI ID */
+                              processor->lapic_flags & ACPI_MADT_ENABLED);
 
        return 0;
 }
@@ -844,12 +815,10 @@ static int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
        return 0;
 }
 
-int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id,
-                int *pcpu)
+int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu)
 {
-       int cpu;
+       int cpu = topology_hotplug_apic(physid, acpi_id);
 
-       cpu = acpi_register_lapic(physid, acpi_id, ACPI_MADT_ENABLED);
        if (cpu < 0) {
                pr_info("Unable to map lapic to logical cpu number\n");
                return cpu;
@@ -868,15 +837,11 @@ int acpi_unmap_cpu(int cpu)
 #ifdef CONFIG_ACPI_NUMA
        set_apicid_to_node(per_cpu(x86_cpu_to_apicid, cpu), NUMA_NO_NODE);
 #endif
-
-       per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID;
-       set_cpu_present(cpu, false);
-       num_processors--;
-
-       return (0);
+       topology_hotunplug_apic(cpu);
+       return 0;
 }
 EXPORT_SYMBOL(acpi_unmap_cpu);
-#endif                         /* CONFIG_ACPI_HOTPLUG_CPU */
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
 
 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
 {
index d5d8a352eafaa1b0bf77bd61a1f4edf444d9b23b..94ff83f3d3fe927dbd67a00f8ad2cb91eb276486 100644 (file)
@@ -17,7 +17,7 @@
         * Hooray, we are in Long 64-bit mode (but still running in low memory)
         */
 SYM_FUNC_START(wakeup_long64)
-       movq    saved_magic, %rax
+       movq    saved_magic(%rip), %rax
        movq    $0x123456789abcdef0, %rdx
        cmpq    %rdx, %rax
        je      2f
@@ -33,14 +33,14 @@ SYM_FUNC_START(wakeup_long64)
        movw    %ax, %es
        movw    %ax, %fs
        movw    %ax, %gs
-       movq    saved_rsp, %rsp
+       movq    saved_rsp(%rip), %rsp
 
-       movq    saved_rbx, %rbx
-       movq    saved_rdi, %rdi
-       movq    saved_rsi, %rsi
-       movq    saved_rbp, %rbp
+       movq    saved_rbx(%rip), %rbx
+       movq    saved_rdi(%rip), %rdi
+       movq    saved_rsi(%rip), %rsi
+       movq    saved_rbp(%rip), %rbp
 
-       movq    saved_rip, %rax
+       movq    saved_rip(%rip), %rax
        ANNOTATE_RETPOLINE_SAFE
        jmp     *%rax
 SYM_FUNC_END(wakeup_long64)
@@ -72,11 +72,11 @@ SYM_FUNC_START(do_suspend_lowlevel)
 
        movq    $.Lresume_point, saved_rip(%rip)
 
-       movq    %rsp, saved_rsp
-       movq    %rbp, saved_rbp
-       movq    %rbx, saved_rbx
-       movq    %rdi, saved_rdi
-       movq    %rsi, saved_rsi
+       movq    %rsp, saved_rsp(%rip)
+       movq    %rbp, saved_rbp(%rip)
+       movq    %rbx, saved_rbx(%rip)
+       movq    %rdi, saved_rdi(%rip)
+       movq    %rsi, saved_rsi(%rip)
 
        addq    $8, %rsp
        movl    $3, %edi
index 1d85cb7071cb21c84899477ec4a150d2fcc4da43..ff6e32ec8259c278a743da1482c2329cbf15a846 100644 (file)
@@ -45,7 +45,7 @@ EXPORT_SYMBOL_GPL(alternatives_patched);
 #define DA_ENDBR       0x08
 #define DA_SMP         0x10
 
-static unsigned int __initdata_or_module debug_alternative;
+static unsigned int debug_alternative;
 
 static int __init debug_alt(char *str)
 {
@@ -133,7 +133,7 @@ const unsigned char * const x86_nops[ASM_NOP_MAX+1] =
  * each single-byte NOPs). If @len to fill out is > ASM_NOP_MAX, pad with INT3 and
  * *jump* over instead of executing long and daft NOPs.
  */
-static void __init_or_module add_nop(u8 *instr, unsigned int len)
+static void add_nop(u8 *instr, unsigned int len)
 {
        u8 *target = instr + len;
 
@@ -206,7 +206,7 @@ static int skip_nops(u8 *instr, int offset, int len)
  * Optimize a sequence of NOPs, possibly preceded by an unconditional jump
  * to the end of the NOP sequence into a single NOP.
  */
-static bool __init_or_module
+static bool
 __optimize_nops(u8 *instr, size_t len, struct insn *insn, int *next, int *prev, int *target)
 {
        int i = *next - insn->length;
@@ -335,8 +335,7 @@ bool need_reloc(unsigned long offset, u8 *src, size_t src_len)
        return (target < src || target > src + src_len);
 }
 
-static void __init_or_module noinline
-apply_relocation(u8 *buf, size_t len, u8 *dest, u8 *src, size_t src_len)
+void apply_relocation(u8 *buf, size_t len, u8 *dest, u8 *src, size_t src_len)
 {
        int prev, target = 0;
 
@@ -545,7 +544,7 @@ static inline bool is_jcc32(struct insn *insn)
        return insn->opcode.bytes[0] == 0x0f && (insn->opcode.bytes[1] & 0xf0) == 0x80;
 }
 
-#if defined(CONFIG_RETPOLINE) && defined(CONFIG_OBJTOOL)
+#if defined(CONFIG_MITIGATION_RETPOLINE) && defined(CONFIG_OBJTOOL)
 
 /*
  * CALL/JMP *%\reg
@@ -709,8 +708,8 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
        /*
         * The compiler is supposed to EMIT an INT3 after every unconditional
         * JMP instruction due to AMD BTC. However, if the compiler is too old
-        * or SLS isn't enabled, we still need an INT3 after indirect JMPs
-        * even on Intel.
+        * or MITIGATION_SLS isn't enabled, we still need an INT3 after
+        * indirect JMPs even on Intel.
         */
        if (op == JMP32_INSN_OPCODE && i < insn->length)
                bytes[i++] = INT3_INSN_OPCODE;
@@ -770,7 +769,7 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
        }
 }
 
-#ifdef CONFIG_RETHUNK
+#ifdef CONFIG_MITIGATION_RETHUNK
 
 /*
  * Rewrite the compiler generated return thunk tail-calls.
@@ -843,14 +842,14 @@ void __init_or_module noinline apply_returns(s32 *start, s32 *end)
 }
 #else
 void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
-#endif /* CONFIG_RETHUNK */
+#endif /* CONFIG_MITIGATION_RETHUNK */
 
-#else /* !CONFIG_RETPOLINE || !CONFIG_OBJTOOL */
+#else /* !CONFIG_MITIGATION_RETPOLINE || !CONFIG_OBJTOOL */
 
 void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) { }
 void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
 
-#endif /* CONFIG_RETPOLINE && CONFIG_OBJTOOL */
+#endif /* CONFIG_MITIGATION_RETPOLINE && CONFIG_OBJTOOL */
 
 #ifdef CONFIG_X86_KERNEL_IBT
 
index 053f6dcc6b2c7026eb87c79f09b6d6a038aec628..5bf5f9fc5753a194fcc071b57af6184ad275a634 100644 (file)
@@ -386,7 +386,7 @@ struct resource *amd_get_mmconfig_range(struct resource *res)
 
 int amd_get_subcaches(int cpu)
 {
-       struct pci_dev *link = node_to_amd_nb(topology_die_id(cpu))->link;
+       struct pci_dev *link = node_to_amd_nb(topology_amd_node_id(cpu))->link;
        unsigned int mask;
 
        if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
@@ -400,7 +400,7 @@ int amd_get_subcaches(int cpu)
 int amd_set_subcaches(int cpu, unsigned long mask)
 {
        static unsigned int reset, ban;
-       struct amd_northbridge *nb = node_to_amd_nb(topology_die_id(cpu));
+       struct amd_northbridge *nb = node_to_amd_nb(topology_amd_node_id(cpu));
        unsigned int reg;
        int cuid;
 
index 4667bc4b00ab8ae2a6b53f49337baefa397b37a7..a42d8a6f7149588bc74213268733003bf7ccf470 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
 #include <linux/acpi_pmtmr.h>
+#include <linux/bitmap.h>
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/memblock.h>
 
 #include "local.h"
 
-unsigned int num_processors;
-
-unsigned disabled_cpus;
-
 /* Processor that is doing the boot up */
 u32 boot_cpu_physical_apicid __ro_after_init = BAD_APICID;
 EXPORT_SYMBOL_GPL(boot_cpu_physical_apicid);
 
 u8 boot_cpu_apic_version __ro_after_init;
 
-/*
- * Bitmask of physically existing CPUs:
- */
-physid_mask_t phys_cpu_present_map;
-
-/*
- * Processor to be disabled specified by kernel parameter
- * disable_cpu_apicid=<int>, mostly used for the kdump 2nd kernel to
- * avoid undefined behaviour caused by sending INIT from AP to BSP.
- */
-static u32 disabled_cpu_apicid __ro_after_init = BAD_APICID;
-
 /*
  * This variable controls which CPUs receive external NMIs.  By default,
  * external NMIs are delivered only to the BSP.
@@ -108,14 +93,6 @@ static inline bool apic_accessible(void)
        return x2apic_mode || apic_mmio_base;
 }
 
-/*
- * Map cpu index to physical APIC ID
- */
-DEFINE_EARLY_PER_CPU_READ_MOSTLY(u32, x86_cpu_to_apicid, BAD_APICID);
-DEFINE_EARLY_PER_CPU_READ_MOSTLY(u32, x86_cpu_to_acpiid, U32_MAX);
-EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_apicid);
-EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_acpiid);
-
 #ifdef CONFIG_X86_32
 /* Local APIC was disabled by the BIOS and enabled by the kernel */
 static int enabled_via_apicbase __ro_after_init;
@@ -261,16 +238,6 @@ u64 native_apic_icr_read(void)
        return icr1 | ((u64)icr2 << 32);
 }
 
-#ifdef CONFIG_X86_32
-/**
- * get_physical_broadcast - Get number of physical broadcast IDs
- */
-int get_physical_broadcast(void)
-{
-       return modern_apic() ? 0xff : 0xf;
-}
-#endif
-
 /**
  * lapic_get_maxlvt - get the maximum number of local vector table entries
  */
@@ -1549,9 +1516,6 @@ static void setup_local_APIC(void)
                apic_write(APIC_ESR, 0);
        }
 #endif
-       /* Validate that the APIC is registered if required */
-       BUG_ON(apic->apic_id_registered && !apic->apic_id_registered());
-
        /*
         * Intel recommends to set DFR, LDR and TPR before enabling
         * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
@@ -1690,8 +1654,6 @@ void apic_ap_setup(void)
        end_local_APIC_setup();
 }
 
-static __init void cpu_set_boot_apic(void);
-
 static __init void apic_read_boot_cpu_id(bool x2apic)
 {
        /*
@@ -1706,7 +1668,8 @@ static __init void apic_read_boot_cpu_id(bool x2apic)
                boot_cpu_physical_apicid = read_apic_id();
                boot_cpu_apic_version = GET_APIC_VERSION(apic_read(APIC_LVR));
        }
-       cpu_set_boot_apic();
+       topology_register_boot_apic(boot_cpu_physical_apicid);
+       x86_32_probe_bigsmp_early();
 }
 
 #ifdef CONFIG_X86_X2APIC
@@ -2091,7 +2054,6 @@ void __init init_apic_mappings(void)
                        pr_info("APIC: disable apic facility\n");
                        apic_disable();
                }
-               num_processors = 1;
        }
 }
 
@@ -2305,155 +2267,6 @@ void disconnect_bsp_APIC(int virt_wire_setup)
        apic_write(APIC_LVT1, value);
 }
 
-/*
- * The number of allocated logical CPU IDs. Since logical CPU IDs are allocated
- * contiguously, it equals to current allocated max logical CPU ID plus 1.
- * All allocated CPU IDs should be in the [0, nr_logical_cpuids) range,
- * so the maximum of nr_logical_cpuids is nr_cpu_ids.
- *
- * NOTE: Reserve 0 for BSP.
- */
-static int nr_logical_cpuids = 1;
-
-/*
- * Used to store mapping between logical CPU IDs and APIC IDs.
- */
-u32 cpuid_to_apicid[] = { [0 ... NR_CPUS - 1] = BAD_APICID, };
-
-bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
-{
-       return phys_id == (u64)cpuid_to_apicid[cpu];
-}
-
-#ifdef CONFIG_SMP
-static void cpu_mark_primary_thread(unsigned int cpu, unsigned int apicid)
-{
-       /* Isolate the SMT bit(s) in the APICID and check for 0 */
-       u32 mask = (1U << (fls(smp_num_siblings) - 1)) - 1;
-
-       if (smp_num_siblings == 1 || !(apicid & mask))
-               cpumask_set_cpu(cpu, &__cpu_primary_thread_mask);
-}
-
-/*
- * Due to the utter mess of CPUID evaluation smp_num_siblings is not valid
- * during early boot. Initialize the primary thread mask before SMP
- * bringup.
- */
-static int __init smp_init_primary_thread_mask(void)
-{
-       unsigned int cpu;
-
-       /*
-        * XEN/PV provides either none or useless topology information.
-        * Pretend that all vCPUs are primary threads.
-        */
-       if (xen_pv_domain()) {
-               cpumask_copy(&__cpu_primary_thread_mask, cpu_possible_mask);
-               return 0;
-       }
-
-       for (cpu = 0; cpu < nr_logical_cpuids; cpu++)
-               cpu_mark_primary_thread(cpu, cpuid_to_apicid[cpu]);
-       return 0;
-}
-early_initcall(smp_init_primary_thread_mask);
-#else
-static inline void cpu_mark_primary_thread(unsigned int cpu, unsigned int apicid) { }
-#endif
-
-/*
- * Should use this API to allocate logical CPU IDs to keep nr_logical_cpuids
- * and cpuid_to_apicid[] synchronized.
- */
-static int allocate_logical_cpuid(int apicid)
-{
-       int i;
-
-       /*
-        * cpuid <-> apicid mapping is persistent, so when a cpu is up,
-        * check if the kernel has allocated a cpuid for it.
-        */
-       for (i = 0; i < nr_logical_cpuids; i++) {
-               if (cpuid_to_apicid[i] == apicid)
-                       return i;
-       }
-
-       /* Allocate a new cpuid. */
-       if (nr_logical_cpuids >= nr_cpu_ids) {
-               WARN_ONCE(1, "APIC: NR_CPUS/possible_cpus limit of %u reached. "
-                            "Processor %d/0x%x and the rest are ignored.\n",
-                            nr_cpu_ids, nr_logical_cpuids, apicid);
-               return -EINVAL;
-       }
-
-       cpuid_to_apicid[nr_logical_cpuids] = apicid;
-       return nr_logical_cpuids++;
-}
-
-static void cpu_update_apic(int cpu, u32 apicid)
-{
-#if defined(CONFIG_SMP) || defined(CONFIG_X86_64)
-       early_per_cpu(x86_cpu_to_apicid, cpu) = apicid;
-#endif
-       set_cpu_possible(cpu, true);
-       physid_set(apicid, phys_cpu_present_map);
-       set_cpu_present(cpu, true);
-       num_processors++;
-
-       if (system_state != SYSTEM_BOOTING)
-               cpu_mark_primary_thread(cpu, apicid);
-}
-
-static __init void cpu_set_boot_apic(void)
-{
-       cpuid_to_apicid[0] = boot_cpu_physical_apicid;
-       cpu_update_apic(0, boot_cpu_physical_apicid);
-       x86_32_probe_bigsmp_early();
-}
-
-int generic_processor_info(int apicid)
-{
-       int cpu, max = nr_cpu_ids;
-
-       /* The boot CPU must be set before MADT/MPTABLE parsing happens */
-       if (cpuid_to_apicid[0] == BAD_APICID)
-               panic("Boot CPU APIC not registered yet\n");
-
-       if (apicid == boot_cpu_physical_apicid)
-               return 0;
-
-       if (disabled_cpu_apicid == apicid) {
-               int thiscpu = num_processors + disabled_cpus;
-
-               pr_warn("APIC: Disabling requested cpu. Processor %d/0x%x ignored.\n",
-                       thiscpu, apicid);
-
-               disabled_cpus++;
-               return -ENODEV;
-       }
-
-       if (num_processors >= nr_cpu_ids) {
-               int thiscpu = max + disabled_cpus;
-
-               pr_warn("APIC: NR_CPUS/possible_cpus limit of %i reached. "
-                       "Processor %d/0x%x ignored.\n", max, thiscpu, apicid);
-
-               disabled_cpus++;
-               return -EINVAL;
-       }
-
-       cpu = allocate_logical_cpuid(apicid);
-       if (cpu < 0) {
-               disabled_cpus++;
-               return -EINVAL;
-       }
-
-       cpu_update_apic(cpu, apicid);
-       return cpu;
-}
-
-
 void __irq_msi_compose_msg(struct irq_cfg *cfg, struct msi_msg *msg,
                           bool dmar)
 {
@@ -2496,10 +2309,7 @@ EXPORT_SYMBOL_GPL(x86_msi_msg_get_destid);
 
 static void __init apic_bsp_up_setup(void)
 {
-#ifdef CONFIG_X86_64
-       apic_write(APIC_ID, apic->set_apic_id(boot_cpu_physical_apicid));
-#endif
-       physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
+       reset_phys_cpu_present_map(boot_cpu_physical_apicid);
 }
 
 /**
@@ -2845,15 +2655,6 @@ static int __init lapic_insert_resource(void)
  */
 late_initcall(lapic_insert_resource);
 
-static int __init apic_set_disabled_cpu_apicid(char *arg)
-{
-       if (!arg || !get_option(&arg, &disabled_cpu_apicid))
-               return -EINVAL;
-
-       return 0;
-}
-early_param("disable_cpu_apicid", apic_set_disabled_cpu_apicid);
-
 static int __init apic_set_extnmi(char *arg)
 {
        if (!arg)
index 8a00141073ea81cfc72b6154e5d21821fcd01211..9ef3be866832cf2c9b96613a832c0eda1dbba547 100644 (file)
@@ -18,16 +18,6 @@ u32 apic_flat_calc_apicid(unsigned int cpu)
        return 1U << cpu;
 }
 
-bool default_check_apicid_used(physid_mask_t *map, u32 apicid)
-{
-       return physid_isset(apicid, *map);
-}
-
-void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
-{
-       *retmap = *phys_map;
-}
-
 u32 default_cpu_present_to_apicid(int mps_cpu)
 {
        if (mps_cpu < nr_cpu_ids && cpu_present(mps_cpu))
@@ -37,11 +27,6 @@ u32 default_cpu_present_to_apicid(int mps_cpu)
 }
 EXPORT_SYMBOL_GPL(default_cpu_present_to_apicid);
 
-bool default_apic_id_registered(void)
-{
-       return physid_isset(read_apic_id(), phys_cpu_present_map);
-}
-
 /*
  * Set up the logical destination ID when the APIC operates in logical
  * destination mode.
index b295a056a4fc5c026a4caa4edfccba7835721837..f37ad3392fec91d8c88022b26d555c84747702ac 100644 (file)
@@ -61,16 +61,6 @@ static u32 flat_get_apic_id(u32 x)
        return (x >> 24) & 0xFF;
 }
 
-static u32 set_apic_id(u32 id)
-{
-       return (id & 0xFF) << 24;
-}
-
-static u32 flat_phys_pkg_id(u32 initial_apic_id, int index_msb)
-{
-       return initial_apic_id >> index_msb;
-}
-
 static int flat_probe(void)
 {
        return 1;
@@ -80,7 +70,6 @@ static struct apic apic_flat __ro_after_init = {
        .name                           = "flat",
        .probe                          = flat_probe,
        .acpi_madt_oem_check            = flat_acpi_madt_oem_check,
-       .apic_id_registered             = default_apic_id_registered,
 
        .dest_mode_logical              = true,
 
@@ -88,11 +77,9 @@ static struct apic apic_flat __ro_after_init = {
 
        .init_apic_ldr                  = default_init_apic_ldr,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
-       .phys_pkg_id                    = flat_phys_pkg_id,
 
        .max_apic_id                    = 0xFE,
        .get_apic_id                    = flat_get_apic_id,
-       .set_apic_id                    = set_apic_id,
 
        .calc_dest_apicid               = apic_flat_calc_apicid,
 
@@ -151,18 +138,15 @@ static struct apic apic_physflat __ro_after_init = {
        .name                           = "physical flat",
        .probe                          = physflat_probe,
        .acpi_madt_oem_check            = physflat_acpi_madt_oem_check,
-       .apic_id_registered             = default_apic_id_registered,
 
        .dest_mode_logical              = false,
 
        .disable_esr                    = 0,
 
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
-       .phys_pkg_id                    = flat_phys_pkg_id,
 
        .max_apic_id                    = 0xFE,
        .get_apic_id                    = flat_get_apic_id,
-       .set_apic_id                    = set_apic_id,
 
        .calc_dest_apicid               = apic_default_calc_apicid,
 
index 9f1d553eb48f48eeea15c7eb4460b4d327ecb826..b5bb7a2e8340b20db3a04e3f4e1684e6c4404b45 100644 (file)
@@ -29,7 +29,6 @@ static void noop_send_IPI_self(int vector) { }
 static void noop_apic_icr_write(u32 low, u32 id) { }
 static int noop_wakeup_secondary_cpu(u32 apicid, unsigned long start_eip) { return -1; }
 static u64 noop_apic_icr_read(void) { return 0; }
-static u32 noop_phys_pkg_id(u32 cpuid_apic, int index_msb) { return 0; }
 static u32 noop_get_apic_id(u32 apicid) { return 0; }
 static void noop_apic_eoi(void) { }
 
@@ -51,12 +50,8 @@ struct apic apic_noop __ro_after_init = {
 
        .disable_esr                    = 0,
 
-       .check_apicid_used              = default_check_apicid_used,
-       .ioapic_phys_id_map             = default_ioapic_phys_id_map,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
 
-       .phys_pkg_id                    = noop_phys_pkg_id,
-
        .max_apic_id                    = 0xFE,
        .get_apic_id                    = noop_get_apic_id,
 
index 7d0c51b9d3bca8c29c44e2cb7694243b7bb6a678..16410f087b7af4f8390ee4973d9ee4bbd5679827 100644 (file)
@@ -38,11 +38,6 @@ static u32 numachip1_get_apic_id(u32 x)
        return id;
 }
 
-static u32 numachip1_set_apic_id(u32 id)
-{
-       return (id & 0xff) << 24;
-}
-
 static u32 numachip2_get_apic_id(u32 x)
 {
        u64 mcfg;
@@ -51,16 +46,6 @@ static u32 numachip2_get_apic_id(u32 x)
        return ((mcfg >> (28 - 8)) & 0xfff00) | (x >> 24);
 }
 
-static u32 numachip2_set_apic_id(u32 id)
-{
-       return id << 24;
-}
-
-static u32 numachip_phys_pkg_id(u32 initial_apic_id, int index_msb)
-{
-       return initial_apic_id >> index_msb;
-}
-
 static void numachip1_apic_icr_write(int apicid, unsigned int val)
 {
        write_lcsr(CSR_G3_EXT_IRQ_GEN, (apicid << 16) | val);
@@ -227,11 +212,9 @@ static const struct apic apic_numachip1 __refconst = {
        .disable_esr                    = 0,
 
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
-       .phys_pkg_id                    = numachip_phys_pkg_id,
 
        .max_apic_id                    = UINT_MAX,
        .get_apic_id                    = numachip1_get_apic_id,
-       .set_apic_id                    = numachip1_set_apic_id,
 
        .calc_dest_apicid               = apic_default_calc_apicid,
 
@@ -263,11 +246,9 @@ static const struct apic apic_numachip2 __refconst = {
        .disable_esr                    = 0,
 
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
-       .phys_pkg_id                    = numachip_phys_pkg_id,
 
        .max_apic_id                    = UINT_MAX,
        .get_apic_id                    = numachip2_get_apic_id,
-       .set_apic_id                    = numachip2_set_apic_id,
 
        .calc_dest_apicid               = apic_default_calc_apicid,
 
index 5a0d60b38e6bf098e0546c4b3dcf94011452bceb..9285d500d5b44d9059f4ebdf38f8ece6492973ed 100644 (file)
@@ -18,22 +18,6 @@ static u32 bigsmp_get_apic_id(u32 x)
        return (x >> 24) & 0xFF;
 }
 
-static bool bigsmp_check_apicid_used(physid_mask_t *map, u32 apicid)
-{
-       return false;
-}
-
-static void bigsmp_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
-{
-       /* For clustered we don't have a good way to do this yet - hack */
-       physids_promote(0xFFL, retmap);
-}
-
-static u32 bigsmp_phys_pkg_id(u32 cpuid_apic, int index_msb)
-{
-       return cpuid_apic >> index_msb;
-}
-
 static void bigsmp_send_IPI_allbutself(int vector)
 {
        default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
@@ -84,14 +68,10 @@ static struct apic apic_bigsmp __ro_after_init = {
 
        .disable_esr                    = 1,
 
-       .check_apicid_used              = bigsmp_check_apicid_used,
-       .ioapic_phys_id_map             = bigsmp_ioapic_phys_id_map,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
-       .phys_pkg_id                    = bigsmp_phys_pkg_id,
 
        .max_apic_id                    = 0xFE,
        .get_apic_id                    = bigsmp_get_apic_id,
-       .set_apic_id                    = NULL,
 
        .calc_dest_apicid               = apic_default_calc_apicid,
 
index 40c7cf180c2031d1b8fbe357aca6c464004fa0bf..477b740b2f267bf3f4880f0612936d9640b29673 100644 (file)
@@ -1458,20 +1458,20 @@ void restore_boot_irq_mode(void)
  *
  * by Matt Domsch <Matt_Domsch@dell.com>  Tue Dec 21 12:25:05 CST 1999
  */
-void __init setup_ioapic_ids_from_mpc_nocheck(void)
+static void __init setup_ioapic_ids_from_mpc_nocheck(void)
 {
+       DECLARE_BITMAP(phys_id_present_map, MAX_LOCAL_APIC);
+       const u32 broadcast_id = 0xF;
        union IO_APIC_reg_00 reg_00;
-       physid_mask_t phys_id_present_map;
-       int ioapic_idx;
-       int i;
        unsigned char old_id;
        unsigned long flags;
+       int ioapic_idx, i;
 
        /*
         * This is broken; anything with a real cpu count has to
         * circumvent this idiocy regardless.
         */
-       apic->ioapic_phys_id_map(&phys_cpu_present_map, &phys_id_present_map);
+       copy_phys_cpu_present_map(phys_id_present_map);
 
        /*
         * Set the IOAPIC ID to the value stored in the MPC table.
@@ -1484,11 +1484,10 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
 
                old_id = mpc_ioapic_id(ioapic_idx);
 
-               if (mpc_ioapic_id(ioapic_idx) >= get_physical_broadcast()) {
-                       printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
-                               ioapic_idx, mpc_ioapic_id(ioapic_idx));
-                       printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
-                               reg_00.bits.ID);
+               if (mpc_ioapic_id(ioapic_idx) >= broadcast_id) {
+                       pr_err(FW_BUG "IO-APIC#%d ID is %d in the MPC table!...\n",
+                              ioapic_idx, mpc_ioapic_id(ioapic_idx));
+                       pr_err("... fixing up to %d. (tell your hw vendor)\n", reg_00.bits.ID);
                        ioapics[ioapic_idx].mp_config.apicid = reg_00.bits.ID;
                }
 
@@ -1497,23 +1496,21 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
                 * system must have a unique ID or we get lots of nice
                 * 'stuck on smp_invalidate_needed IPI wait' messages.
                 */
-               if (apic->check_apicid_used(&phys_id_present_map,
-                                           mpc_ioapic_id(ioapic_idx))) {
-                       printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
-                               ioapic_idx, mpc_ioapic_id(ioapic_idx));
-                       for (i = 0; i < get_physical_broadcast(); i++)
-                               if (!physid_isset(i, phys_id_present_map))
+               if (test_bit(mpc_ioapic_id(ioapic_idx), phys_id_present_map)) {
+                       pr_err(FW_BUG "IO-APIC#%d ID %d is already used!...\n",
+                              ioapic_idx, mpc_ioapic_id(ioapic_idx));
+                       for (i = 0; i < broadcast_id; i++)
+                               if (!test_bit(i, phys_id_present_map))
                                        break;
-                       if (i >= get_physical_broadcast())
+                       if (i >= broadcast_id)
                                panic("Max APIC ID exceeded!\n");
-                       printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
-                               i);
-                       physid_set(i, phys_id_present_map);
+                       pr_err("... fixing up to %d. (tell your hw vendor)\n", i);
+                       set_bit(i, phys_id_present_map);
                        ioapics[ioapic_idx].mp_config.apicid = i;
                } else {
                        apic_printk(APIC_VERBOSE, "Setting %d in the phys_id_present_map\n",
                                    mpc_ioapic_id(ioapic_idx));
-                       physid_set(mpc_ioapic_id(ioapic_idx), phys_id_present_map);
+                       set_bit(mpc_ioapic_id(ioapic_idx), phys_id_present_map);
                }
 
                /*
@@ -2209,7 +2206,7 @@ static inline void __init check_timer(void)
         * 8259A.
         */
        if (pin1 == -1) {
-               panic_if_irq_remap("BIOS bug: timer not connected to IO-APIC");
+               panic_if_irq_remap(FW_BUG "Timer not connected to IO-APIC");
                pin1 = pin2;
                apic1 = apic2;
                no_pin1 = 1;
@@ -2354,7 +2351,7 @@ static int mp_irqdomain_create(int ioapic)
        fwspec.param_count = 1;
        fwspec.param[0] = mpc_ioapic_id(ioapic);
 
-       parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_ANY);
+       parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_GENERIC_MSI);
        if (!parent) {
                if (!cfg->dev)
                        irq_domain_free_fwnode(fn);
@@ -2494,56 +2491,41 @@ unsigned int arch_dynirq_lower_bound(unsigned int from)
 #ifdef CONFIG_X86_32
 static int io_apic_get_unique_id(int ioapic, int apic_id)
 {
+       static DECLARE_BITMAP(apic_id_map, MAX_LOCAL_APIC);
+       const u32 broadcast_id = 0xF;
        union IO_APIC_reg_00 reg_00;
-       static physid_mask_t apic_id_map = PHYSID_MASK_NONE;
-       physid_mask_t tmp;
        unsigned long flags;
        int i = 0;
 
-       /*
-        * The P4 platform supports up to 256 APIC IDs on two separate APIC
-        * buses (one for LAPICs, one for IOAPICs), where predecessors only
-        * supports up to 16 on one shared APIC bus.
-        *
-        * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full
-        *      advantage of new APIC bus architecture.
-        */
-
-       if (physids_empty(apic_id_map))
-               apic->ioapic_phys_id_map(&phys_cpu_present_map, &apic_id_map);
+       /* Initialize the ID map */
+       if (bitmap_empty(apic_id_map, MAX_LOCAL_APIC))
+               copy_phys_cpu_present_map(apic_id_map);
 
        raw_spin_lock_irqsave(&ioapic_lock, flags);
        reg_00.raw = io_apic_read(ioapic, 0);
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 
-       if (apic_id >= get_physical_broadcast()) {
-               printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying "
-                       "%d\n", ioapic, apic_id, reg_00.bits.ID);
+       if (apic_id >= broadcast_id) {
+               pr_warn("IOAPIC[%d]: Invalid apic_id %d, trying %d\n",
+                       ioapic, apic_id, reg_00.bits.ID);
                apic_id = reg_00.bits.ID;
        }
 
-       /*
-        * Every APIC in a system must have a unique ID or we get lots of nice
-        * 'stuck on smp_invalidate_needed IPI wait' messages.
-        */
-       if (apic->check_apicid_used(&apic_id_map, apic_id)) {
-
-               for (i = 0; i < get_physical_broadcast(); i++) {
-                       if (!apic->check_apicid_used(&apic_id_map, i))
+       /* Every APIC in a system must have a unique ID */
+       if (test_bit(apic_id, apic_id_map)) {
+               for (i = 0; i < broadcast_id; i++) {
+                       if (!test_bit(i, apic_id_map))
                                break;
                }
 
-               if (i == get_physical_broadcast())
+               if (i == broadcast_id)
                        panic("Max apic_id exceeded!\n");
 
-               printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, "
-                       "trying %d\n", ioapic, apic_id, i);
-
+               pr_warn("IOAPIC[%d]: apic_id %d already used, trying %d\n", ioapic, apic_id, i);
                apic_id = i;
        }
 
-       physid_set_mask_of_physid(apic_id, &tmp);
-       physids_or(apic_id_map, apic_id_map, tmp);
+       set_bit(apic_id, apic_id_map);
 
        if (reg_00.bits.ID != apic_id) {
                reg_00.bits.ID = apic_id;
@@ -2569,11 +2551,9 @@ static int io_apic_get_unique_id(int ioapic, int apic_id)
 
 static u8 io_apic_unique_id(int idx, u8 id)
 {
-       if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
-           !APIC_XAPIC(boot_cpu_apic_version))
+       if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && !APIC_XAPIC(boot_cpu_apic_version))
                return io_apic_get_unique_id(idx, id);
-       else
-               return id;
+       return id;
 }
 #else
 static u8 io_apic_unique_id(int idx, u8 id)
index 9ea6186ea88c2dc701bafb92dc50acb628dabf98..842fe28496beeb38e2628c622a8ec804851085a3 100644 (file)
@@ -16,8 +16,6 @@
 /* X2APIC */
 void __x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest);
 u32 x2apic_get_apic_id(u32 id);
-u32 x2apic_set_apic_id(u32 id);
-u32 x2apic_phys_pkg_id(u32 initial_apicid, int index_msb);
 
 void x2apic_send_IPI_all(int vector);
 void x2apic_send_IPI_allbutself(int vector);
@@ -63,9 +61,6 @@ void default_send_IPI_allbutself(int vector);
 void default_send_IPI_all(int vector);
 void default_send_IPI_self(int vector);
 
-bool default_apic_id_registered(void);
-bool default_check_apicid_used(physid_mask_t *map, u32 apicid);
-
 #ifdef CONFIG_X86_32
 void default_send_IPI_mask_sequence_logical(const struct cpumask *mask, int vector);
 void default_send_IPI_mask_allbutself_logical(const struct cpumask *mask, int vector);
index c0f78059f06acac05b67c3d619134b768fd9c3b3..f75ee345c02d080ab95b2f55639249f8d3237d26 100644 (file)
 
 #include "local.h"
 
-static u32 default_phys_pkg_id(u32 cpuid_apic, int index_msb)
-{
-       return cpuid_apic >> index_msb;
-}
-
 static u32 default_get_apic_id(u32 x)
 {
        unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));
@@ -43,17 +38,13 @@ static struct apic apic_default __ro_after_init = {
 
        .name                           = "default",
        .probe                          = probe_default,
-       .apic_id_registered             = default_apic_id_registered,
 
        .dest_mode_logical              = true,
 
        .disable_esr                    = 0,
 
-       .check_apicid_used              = default_check_apicid_used,
        .init_apic_ldr                  = default_init_apic_ldr,
-       .ioapic_phys_id_map             = default_ioapic_phys_id_map,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
-       .phys_pkg_id                    = default_phys_pkg_id,
 
        .max_apic_id                    = 0xFE,
        .get_apic_id                    = default_get_apic_id,
index 28a7d3f2312d21fc864ee67cd22b86a61983d649..567dbd2fe4b6978c0ffda146aa59e957bfb43919 100644 (file)
@@ -231,16 +231,12 @@ static struct apic apic_x2apic_cluster __ro_after_init = {
 
        .disable_esr                    = 0,
 
-       .check_apicid_used              = NULL,
        .init_apic_ldr                  = init_x2apic_ldr,
-       .ioapic_phys_id_map             = NULL,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
-       .phys_pkg_id                    = x2apic_phys_pkg_id,
 
        .max_apic_id                    = UINT_MAX,
        .x2apic_set_max_apicid          = true,
        .get_apic_id                    = x2apic_get_apic_id,
-       .set_apic_id                    = x2apic_set_apic_id,
 
        .calc_dest_apicid               = x2apic_calc_apicid,
 
index 409815a40668281923cfccf04e93ead53301d8e8..12d4c35547a6f928d14df005dbcbffb71eab4641 100644 (file)
@@ -129,16 +129,6 @@ u32 x2apic_get_apic_id(u32 id)
        return id;
 }
 
-u32 x2apic_set_apic_id(u32 id)
-{
-       return id;
-}
-
-u32 x2apic_phys_pkg_id(u32 initial_apicid, int index_msb)
-{
-       return initial_apicid >> index_msb;
-}
-
 static struct apic apic_x2apic_phys __ro_after_init = {
 
        .name                           = "physical x2apic",
@@ -150,12 +140,10 @@ static struct apic apic_x2apic_phys __ro_after_init = {
        .disable_esr                    = 0,
 
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
-       .phys_pkg_id                    = x2apic_phys_pkg_id,
 
        .max_apic_id                    = UINT_MAX,
        .x2apic_set_max_apicid          = true,
        .get_apic_id                    = x2apic_get_apic_id,
-       .set_apic_id                    = x2apic_set_apic_id,
 
        .calc_dest_apicid               = apic_default_calc_apicid,
 
index f1766b18dcd07d495be3b3b21c007b9f904a3180..7fef504ca508b7829b89a3ca2dad9be1e22860e9 100644 (file)
@@ -241,54 +241,20 @@ static void __init uv_tsc_check_sync(void)
        is_uv(UV3) ? sname.s3.field :           \
        undef)
 
-/* [Copied from arch/x86/kernel/cpu/topology.c:detect_extended_topology()] */
-
-#define SMT_LEVEL                      0       /* Leaf 0xb SMT level */
-#define INVALID_TYPE                   0       /* Leaf 0xb sub-leaf types */
-#define SMT_TYPE                       1
-#define CORE_TYPE                      2
-#define LEAFB_SUBTYPE(ecx)             (((ecx) >> 8) & 0xff)
-#define BITS_SHIFT_NEXT_LEVEL(eax)     ((eax) & 0x1f)
-
-static void set_x2apic_bits(void)
-{
-       unsigned int eax, ebx, ecx, edx, sub_index;
-       unsigned int sid_shift;
-
-       cpuid(0, &eax, &ebx, &ecx, &edx);
-       if (eax < 0xb) {
-               pr_info("UV: CPU does not have CPUID.11\n");
-               return;
-       }
-
-       cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
-       if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE)) {
-               pr_info("UV: CPUID.11 not implemented\n");
-               return;
-       }
-
-       sid_shift = BITS_SHIFT_NEXT_LEVEL(eax);
-       sub_index = 1;
-       do {
-               cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx);
-               if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
-                       sid_shift = BITS_SHIFT_NEXT_LEVEL(eax);
-                       break;
-               }
-               sub_index++;
-       } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
-
-       uv_cpuid.apicid_shift   = 0;
-       uv_cpuid.apicid_mask    = (~(-1 << sid_shift));
-       uv_cpuid.socketid_shift = sid_shift;
-}
-
 static void __init early_get_apic_socketid_shift(void)
 {
+       unsigned int sid_shift = topology_get_domain_shift(TOPO_PKG_DOMAIN);
+
        if (is_uv2_hub() || is_uv3_hub())
                uvh_apicid.v = uv_early_read_mmr(UVH_APICID);
 
-       set_x2apic_bits();
+       if (sid_shift) {
+               uv_cpuid.apicid_shift   = 0;
+               uv_cpuid.apicid_mask    = (~(-1 << sid_shift));
+               uv_cpuid.socketid_shift = sid_shift;
+       } else {
+               pr_info("UV: CPU does not have valid CPUID.11\n");
+       }
 
        pr_info("UV: apicid_shift:%d apicid_mask:0x%x\n", uv_cpuid.apicid_shift, uv_cpuid.apicid_mask);
        pr_info("UV: socketid_shift:%d pnode_mask:0x%x\n", uv_cpuid.socketid_shift, uv_cpuid.pnode_mask);
@@ -779,21 +745,6 @@ static void uv_send_IPI_all(int vector)
        uv_send_IPI_mask(cpu_online_mask, vector);
 }
 
-static u32 set_apic_id(u32 id)
-{
-       return id;
-}
-
-static unsigned int uv_read_apic_id(void)
-{
-       return x2apic_get_apic_id(apic_read(APIC_ID));
-}
-
-static u32 uv_phys_pkg_id(u32 initial_apicid, int index_msb)
-{
-       return uv_read_apic_id() >> index_msb;
-}
-
 static int uv_probe(void)
 {
        return apic == &apic_x2apic_uv_x;
@@ -810,11 +761,9 @@ static struct apic apic_x2apic_uv_x __ro_after_init = {
        .disable_esr                    = 0,
 
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
-       .phys_pkg_id                    = uv_phys_pkg_id,
 
        .max_apic_id                    = UINT_MAX,
        .get_apic_id                    = x2apic_get_apic_id,
-       .set_apic_id                    = set_apic_id,
 
        .calc_dest_apicid               = apic_default_calc_apicid,
 
index 76a5ced278c2aef9f28e29c237e9b27557a14e63..b37ab10957074fb60211db3ec21cf63a69b59609 100644 (file)
@@ -1055,35 +1055,6 @@ static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
        return APM_SUCCESS;
 }
 
-#if 0
-static int apm_get_battery_status(u_short which, u_short *status,
-                                 u_short *bat, u_short *life, u_short *nbat)
-{
-       u32 eax;
-       u32 ebx;
-       u32 ecx;
-       u32 edx;
-       u32 esi;
-
-       if (apm_info.connection_version < 0x0102) {
-               /* pretend we only have one battery. */
-               if (which != 1)
-                       return APM_BAD_DEVICE;
-               *nbat = 1;
-               return apm_get_power_status(status, bat, life);
-       }
-
-       if (apm_bios_call(APM_FUNC_GET_STATUS, (0x8000 | (which)), 0, &eax,
-                         &ebx, &ecx, &edx, &esi))
-               return (eax >> 8) & 0xff;
-       *status = ebx;
-       *bat = ecx;
-       *life = edx;
-       *nbat = esi;
-       return APM_SUCCESS;
-}
-#endif
-
 /**
  *     apm_engage_power_management     -       enable PM on a device
  *     @device: identity of device
index 6913b372ccf764e1345f33df8395f2ebb0eb206a..a98020bf31bb465c1444b49cd8a5c7ebe21f973b 100644 (file)
@@ -109,7 +109,7 @@ static void __used common(void)
        OFFSET(TSS_sp2, tss_struct, x86_tss.sp2);
        OFFSET(X86_top_of_stack, pcpu_hot, top_of_stack);
        OFFSET(X86_current_task, pcpu_hot, current_task);
-#ifdef CONFIG_CALL_DEPTH_TRACKING
+#ifdef CONFIG_MITIGATION_CALL_DEPTH_TRACKING
        OFFSET(X86_call_depth, pcpu_hot, call_depth);
 #endif
 #if IS_ENABLED(CONFIG_CRYPTO_ARIA_AESNI_AVX_X86_64)
index 64ad2ddea121940a99a8c55746986ef0b84c1c41..30335182b6b0ae6a4e474c7e93de93e1bd24b2f4 100644 (file)
@@ -24,6 +24,8 @@
 
 static int __initdata_or_module debug_callthunks;
 
+#define MAX_PATCH_LEN (255-1)
+
 #define prdbg(fmt, args...)                                    \
 do {                                                           \
        if (debug_callthunks)                                   \
@@ -42,8 +44,8 @@ DEFINE_PER_CPU(u64, __x86_call_count);
 DEFINE_PER_CPU(u64, __x86_ret_count);
 DEFINE_PER_CPU(u64, __x86_stuffs_count);
 DEFINE_PER_CPU(u64, __x86_ctxsw_count);
-EXPORT_SYMBOL_GPL(__x86_ctxsw_count);
-EXPORT_SYMBOL_GPL(__x86_call_count);
+EXPORT_PER_CPU_SYMBOL_GPL(__x86_ctxsw_count);
+EXPORT_PER_CPU_SYMBOL_GPL(__x86_call_count);
 #endif
 
 extern s32 __call_sites[], __call_sites_end[];
@@ -179,10 +181,15 @@ static const u8 nops[] = {
 static void *patch_dest(void *dest, bool direct)
 {
        unsigned int tsize = SKL_TMPL_SIZE;
+       u8 insn_buff[MAX_PATCH_LEN];
        u8 *pad = dest - tsize;
 
+       memcpy(insn_buff, skl_call_thunk_template, tsize);
+       apply_relocation(insn_buff, tsize, pad,
+                        skl_call_thunk_template, tsize);
+
        /* Already patched? */
-       if (!bcmp(pad, skl_call_thunk_template, tsize))
+       if (!bcmp(pad, insn_buff, tsize))
                return pad;
 
        /* Ensure there are nops */
@@ -192,9 +199,9 @@ static void *patch_dest(void *dest, bool direct)
        }
 
        if (direct)
-               memcpy(pad, skl_call_thunk_template, tsize);
+               memcpy(pad, insn_buff, tsize);
        else
-               text_poke_copy_locked(pad, skl_call_thunk_template, tsize, true);
+               text_poke_copy_locked(pad, insn_buff, tsize, true);
        return pad;
 }
 
@@ -290,20 +297,27 @@ void *callthunks_translate_call_dest(void *dest)
 static bool is_callthunk(void *addr)
 {
        unsigned int tmpl_size = SKL_TMPL_SIZE;
-       void *tmpl = skl_call_thunk_template;
+       u8 insn_buff[MAX_PATCH_LEN];
        unsigned long dest;
+       u8 *pad;
 
        dest = roundup((unsigned long)addr, CONFIG_FUNCTION_ALIGNMENT);
        if (!thunks_initialized || skip_addr((void *)dest))
                return false;
 
-       return !bcmp((void *)(dest - tmpl_size), tmpl, tmpl_size);
+       pad = (void *)(dest - tmpl_size);
+
+       memcpy(insn_buff, skl_call_thunk_template, tmpl_size);
+       apply_relocation(insn_buff, tmpl_size, pad,
+                        skl_call_thunk_template, tmpl_size);
+
+       return !bcmp(pad, insn_buff, tmpl_size);
 }
 
 int x86_call_depth_emit_accounting(u8 **pprog, void *func)
 {
        unsigned int tmpl_size = SKL_TMPL_SIZE;
-       void *tmpl = skl_call_thunk_template;
+       u8 insn_buff[MAX_PATCH_LEN];
 
        if (!thunks_initialized)
                return 0;
@@ -312,7 +326,11 @@ int x86_call_depth_emit_accounting(u8 **pprog, void *func)
        if (func && is_callthunk(func))
                return 0;
 
-       memcpy(*pprog, tmpl, tmpl_size);
+       memcpy(insn_buff, skl_call_thunk_template, tmpl_size);
+       apply_relocation(insn_buff, tmpl_size, *pprog,
+                        skl_call_thunk_template, tmpl_size);
+
+       memcpy(*pprog, insn_buff, tmpl_size);
        *pprog += tmpl_size;
        return tmpl_size;
 }
index 93eabf54403189c87b5bb3d05fe66d3d47a929a3..eb4dbcdf41f1d4c7b278815c5c47f30cd5532070 100644 (file)
@@ -17,7 +17,8 @@ KMSAN_SANITIZE_common.o := n
 # As above, instrumenting secondary CPU boot code causes boot hangs.
 KCSAN_SANITIZE_common.o := n
 
-obj-y                  := cacheinfo.o scattered.o topology.o
+obj-y                  := cacheinfo.o scattered.o
+obj-y                  += topology_common.o topology_ext.o topology_amd.o
 obj-y                  += common.o
 obj-y                  += rdrand.o
 obj-y                  += match.o
@@ -25,14 +26,16 @@ obj-y                       += bugs.o
 obj-y                  += aperfmperf.o
 obj-y                  += cpuid-deps.o
 obj-y                  += umwait.o
+obj-y                  += capflags.o powerflags.o
 
-obj-$(CONFIG_PROC_FS)  += proc.o
-obj-y += capflags.o powerflags.o
+obj-$(CONFIG_X86_LOCAL_APIC)           += topology.o
 
-obj-$(CONFIG_IA32_FEAT_CTL) += feat_ctl.o
+obj-$(CONFIG_PROC_FS)                  += proc.o
+
+obj-$(CONFIG_IA32_FEAT_CTL)            += feat_ctl.o
 ifdef CONFIG_CPU_SUP_INTEL
-obj-y                  += intel.o intel_pconfig.o tsx.o
-obj-$(CONFIG_PM)       += intel_epb.o
+obj-y                                  += intel.o intel_pconfig.o tsx.o
+obj-$(CONFIG_PM)                       += intel_epb.o
 endif
 obj-$(CONFIG_CPU_SUP_AMD)              += amd.o
 obj-$(CONFIG_CPU_SUP_HYGON)            += hygon.o
index bfeb18fad63f154ef8357ef75eec1b941b6b46dd..2c5b51aad91a03f0cc2b302087c383f0f882dbb4 100644 (file)
@@ -26,8 +26,8 @@ static u32 __init acrn_detect(void)
 
 static void __init acrn_init_platform(void)
 {
-       /* Setup the IDT for ACRN hypervisor callback */
-       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, asm_sysvec_acrn_hv_callback);
+       /* Install system interrupt handler for ACRN hypervisor callback */
+       sysvec_install(HYPERVISOR_CALLBACK_VECTOR, sysvec_acrn_hv_callback);
 
        x86_platform.calibrate_tsc = acrn_get_tsc_khz;
        x86_platform.calibrate_cpu = acrn_get_tsc_khz;
index f3abca334199d8eae235f1560f99448eb9675a27..3282a747b6458c104e7073292d565bbab9a4c077 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/delay.h>
 #include <asm/debugreg.h>
 #include <asm/resctrl.h>
+#include <asm/sev.h>
 
 #ifdef CONFIG_X86_64
 # include <asm/mmconfig.h>
 
 #include "cpu.h"
 
-/*
- * nodes_per_socket: Stores the number of nodes per socket.
- * Refer to Fam15h Models 00-0fh BKDG - CPUID Fn8000_001E_ECX
- * Node Identifiers[10:8]
- */
-static u32 nodes_per_socket = 1;
-
 static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
 {
        u32 gprs[8] = { 0 };
@@ -300,97 +294,6 @@ static int nearby_node(int apicid)
 }
 #endif
 
-/*
- * Fix up topo::core_id for pre-F17h systems to be in the
- * [0 .. cores_per_node - 1] range. Not really needed but
- * kept so as not to break existing setups.
- */
-static void legacy_fixup_core_id(struct cpuinfo_x86 *c)
-{
-       u32 cus_per_node;
-
-       if (c->x86 >= 0x17)
-               return;
-
-       cus_per_node = c->x86_max_cores / nodes_per_socket;
-       c->topo.core_id %= cus_per_node;
-}
-
-/*
- * Fixup core topology information for
- * (1) AMD multi-node processors
- *     Assumption: Number of cores in each internal node is the same.
- * (2) AMD processors supporting compute units
- */
-static void amd_get_topology(struct cpuinfo_x86 *c)
-{
-       /* get information required for multi-node processors */
-       if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
-               int err;
-               u32 eax, ebx, ecx, edx;
-
-               cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
-
-               c->topo.die_id  = ecx & 0xff;
-
-               if (c->x86 == 0x15)
-                       c->topo.cu_id = ebx & 0xff;
-
-               if (c->x86 >= 0x17) {
-                       c->topo.core_id = ebx & 0xff;
-
-                       if (smp_num_siblings > 1)
-                               c->x86_max_cores /= smp_num_siblings;
-               }
-
-               /*
-                * In case leaf B is available, use it to derive
-                * topology information.
-                */
-               err = detect_extended_topology(c);
-               if (!err)
-                       c->x86_coreid_bits = get_count_order(c->x86_max_cores);
-
-               cacheinfo_amd_init_llc_id(c);
-
-       } else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) {
-               u64 value;
-
-               rdmsrl(MSR_FAM10H_NODE_ID, value);
-               c->topo.die_id = value & 7;
-               c->topo.llc_id = c->topo.die_id;
-       } else
-               return;
-
-       if (nodes_per_socket > 1) {
-               set_cpu_cap(c, X86_FEATURE_AMD_DCM);
-               legacy_fixup_core_id(c);
-       }
-}
-
-/*
- * On a AMD dual core setup the lower bits of the APIC id distinguish the cores.
- * Assumes number of cores is a power of two.
- */
-static void amd_detect_cmp(struct cpuinfo_x86 *c)
-{
-       unsigned bits;
-
-       bits = c->x86_coreid_bits;
-       /* Low order bits define the core id (index of core in socket) */
-       c->topo.core_id = c->topo.initial_apicid & ((1 << bits)-1);
-       /* Convert the initial APIC ID into the socket ID */
-       c->topo.pkg_id = c->topo.initial_apicid >> bits;
-       /* use socket ID also for last level cache */
-       c->topo.llc_id = c->topo.die_id = c->topo.pkg_id;
-}
-
-u32 amd_get_nodes_per_socket(void)
-{
-       return nodes_per_socket;
-}
-EXPORT_SYMBOL_GPL(amd_get_nodes_per_socket);
-
 static void srat_detect_node(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_NUMA
@@ -442,32 +345,6 @@ static void srat_detect_node(struct cpuinfo_x86 *c)
 #endif
 }
 
-static void early_init_amd_mc(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-       unsigned bits, ecx;
-
-       /* Multi core CPU? */
-       if (c->extended_cpuid_level < 0x80000008)
-               return;
-
-       ecx = cpuid_ecx(0x80000008);
-
-       c->x86_max_cores = (ecx & 0xff) + 1;
-
-       /* CPU telling us the core id bits shift? */
-       bits = (ecx >> 12) & 0xF;
-
-       /* Otherwise recompute */
-       if (bits == 0) {
-               while ((1 << bits) < c->x86_max_cores)
-                       bits++;
-       }
-
-       c->x86_coreid_bits = bits;
-#endif
-}
-
 static void bsp_init_amd(struct cpuinfo_x86 *c)
 {
        if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) {
@@ -500,18 +377,6 @@ static void bsp_init_amd(struct cpuinfo_x86 *c)
        if (cpu_has(c, X86_FEATURE_MWAITX))
                use_mwaitx_delay();
 
-       if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
-               u32 ecx;
-
-               ecx = cpuid_ecx(0x8000001e);
-               __max_die_per_package = nodes_per_socket = ((ecx >> 8) & 7) + 1;
-       } else if (boot_cpu_has(X86_FEATURE_NODEID_MSR)) {
-               u64 value;
-
-               rdmsrl(MSR_FAM10H_NODE_ID, value);
-               __max_die_per_package = nodes_per_socket = ((value >> 3) & 7) + 1;
-       }
-
        if (!boot_cpu_has(X86_FEATURE_AMD_SSBD) &&
            !boot_cpu_has(X86_FEATURE_VIRT_SSBD) &&
            c->x86 >= 0x15 && c->x86 <= 0x17) {
@@ -587,6 +452,21 @@ static void bsp_init_amd(struct cpuinfo_x86 *c)
                break;
        }
 
+       if (cpu_has(c, X86_FEATURE_SEV_SNP)) {
+               /*
+                * RMP table entry format is not architectural and it can vary by processor
+                * and is defined by the per-processor PPR. Restrict SNP support on the
+                * known CPU model and family for which the RMP table entry format is
+                * currently defined for.
+                */
+               if (!boot_cpu_has(X86_FEATURE_ZEN3) &&
+                   !boot_cpu_has(X86_FEATURE_ZEN4) &&
+                   !boot_cpu_has(X86_FEATURE_ZEN5))
+                       setup_clear_cpu_cap(X86_FEATURE_SEV_SNP);
+               else if (!snp_probe_rmptable_info())
+                       setup_clear_cpu_cap(X86_FEATURE_SEV_SNP);
+       }
+
        return;
 
 warn:
@@ -605,8 +485,8 @@ static void early_detect_mem_encrypt(struct cpuinfo_x86 *c)
         *            SME feature (set in scattered.c).
         *            If the kernel has not enabled SME via any means then
         *            don't advertise the SME feature.
-        *   For SEV: If BIOS has not enabled SEV then don't advertise the
-        *            SEV and SEV_ES feature (set in scattered.c).
+        *   For SEV: If BIOS has not enabled SEV then don't advertise SEV and
+        *            any additional functionality based on it.
         *
         *   In all cases, since support for SME and SEV requires long mode,
         *   don't advertise the feature under CONFIG_X86_32.
@@ -641,6 +521,7 @@ clear_all:
 clear_sev:
                setup_clear_cpu_cap(X86_FEATURE_SEV);
                setup_clear_cpu_cap(X86_FEATURE_SEV_ES);
+               setup_clear_cpu_cap(X86_FEATURE_SEV_SNP);
        }
 }
 
@@ -649,8 +530,6 @@ static void early_init_amd(struct cpuinfo_x86 *c)
        u64 value;
        u32 dummy;
 
-       early_init_amd_mc(c);
-
        if (c->x86 >= 0xf)
                set_cpu_cap(c, X86_FEATURE_K8);
 
@@ -730,9 +609,6 @@ static void early_init_amd(struct cpuinfo_x86 *c)
                }
        }
 
-       if (cpu_has(c, X86_FEATURE_TOPOEXT))
-               smp_num_siblings = ((cpuid_ebx(0x8000001e) >> 8) & 0xff) + 1;
-
        if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && !cpu_has(c, X86_FEATURE_IBPB_BRTYPE)) {
                if (c->x86 == 0x17 && boot_cpu_has(X86_FEATURE_AMD_IBPB))
                        setup_force_cpu_cap(X86_FEATURE_IBPB_BRTYPE);
@@ -941,7 +817,7 @@ static void fix_erratum_1386(struct cpuinfo_x86 *c)
 
 void init_spectral_chicken(struct cpuinfo_x86 *c)
 {
-#ifdef CONFIG_CPU_UNRET_ENTRY
+#ifdef CONFIG_MITIGATION_UNRET_ENTRY
        u64 value;
 
        /*
@@ -969,7 +845,6 @@ static void init_amd_zen_common(void)
 
 static void init_amd_zen1(struct cpuinfo_x86 *c)
 {
-       init_amd_zen_common();
        fix_erratum_1386(c);
 
        /* Fix up CPUID bits, but only if not virtualised. */
@@ -1023,7 +898,6 @@ static void zen2_zenbleed_check(struct cpuinfo_x86 *c)
 
 static void init_amd_zen2(struct cpuinfo_x86 *c)
 {
-       init_amd_zen_common();
        init_spectral_chicken(c);
        fix_erratum_1386(c);
        zen2_zenbleed_check(c);
@@ -1031,8 +905,6 @@ static void init_amd_zen2(struct cpuinfo_x86 *c)
 
 static void init_amd_zen3(struct cpuinfo_x86 *c)
 {
-       init_amd_zen_common();
-
        if (!cpu_has(c, X86_FEATURE_HYPERVISOR)) {
                /*
                 * Zen3 (Fam19 model < 0x10) parts are not susceptible to
@@ -1046,15 +918,12 @@ static void init_amd_zen3(struct cpuinfo_x86 *c)
 
 static void init_amd_zen4(struct cpuinfo_x86 *c)
 {
-       init_amd_zen_common();
-
        if (!cpu_has(c, X86_FEATURE_HYPERVISOR))
                msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT);
 }
 
 static void init_amd_zen5(struct cpuinfo_x86 *c)
 {
-       init_amd_zen_common();
 }
 
 static void init_amd(struct cpuinfo_x86 *c)
@@ -1076,9 +945,6 @@ static void init_amd(struct cpuinfo_x86 *c)
        if (cpu_has(c, X86_FEATURE_FSRM))
                set_cpu_cap(c, X86_FEATURE_FSRS);
 
-       /* get apicid instead of initial apic id from cpuid */
-       c->topo.apicid = read_apic_id();
-
        /* K6s reports MCEs but don't actually have all the MSRs */
        if (c->x86 < 6)
                clear_cpu_cap(c, X86_FEATURE_MCE);
@@ -1094,6 +960,13 @@ static void init_amd(struct cpuinfo_x86 *c)
        case 0x16: init_amd_jg(c); break;
        }
 
+       /*
+        * Save up on some future enablement work and do common Zen
+        * settings.
+        */
+       if (c->x86 >= 0x17)
+               init_amd_zen_common();
+
        if (boot_cpu_has(X86_FEATURE_ZEN1))
                init_amd_zen1(c);
        else if (boot_cpu_has(X86_FEATURE_ZEN2))
@@ -1114,8 +987,6 @@ static void init_amd(struct cpuinfo_x86 *c)
 
        cpu_detect_cache_sizes(c);
 
-       amd_detect_cmp(c);
-       amd_get_topology(c);
        srat_detect_node(c);
 
        init_amd_cacheinfo(c);
index bb0ab8466b919809a861d7a2f979e132ad863289..e7ba936d798b8198f5837118d5bb33d40389ccc7 100644 (file)
@@ -56,7 +56,7 @@ EXPORT_SYMBOL_GPL(x86_spec_ctrl_base);
 
 /* The current value of the SPEC_CTRL MSR with task-specific bits set */
 DEFINE_PER_CPU(u64, x86_spec_ctrl_current);
-EXPORT_SYMBOL_GPL(x86_spec_ctrl_current);
+EXPORT_PER_CPU_SYMBOL_GPL(x86_spec_ctrl_current);
 
 u64 x86_pred_cmd __ro_after_init = PRED_CMD_IBPB;
 EXPORT_SYMBOL_GPL(x86_pred_cmd);
@@ -111,9 +111,6 @@ DEFINE_STATIC_KEY_FALSE(switch_mm_cond_ibpb);
 /* Control unconditional IBPB in switch_mm() */
 DEFINE_STATIC_KEY_FALSE(switch_mm_always_ibpb);
 
-/* Control MDS CPU buffer clear before returning to user space */
-DEFINE_STATIC_KEY_FALSE(mds_user_clear);
-EXPORT_SYMBOL_GPL(mds_user_clear);
 /* Control MDS CPU buffer clear before idling (halt, mwait) */
 DEFINE_STATIC_KEY_FALSE(mds_idle_clear);
 EXPORT_SYMBOL_GPL(mds_idle_clear);
@@ -252,7 +249,7 @@ static void __init mds_select_mitigation(void)
                if (!boot_cpu_has(X86_FEATURE_MD_CLEAR))
                        mds_mitigation = MDS_MITIGATION_VMWERV;
 
-               static_branch_enable(&mds_user_clear);
+               setup_force_cpu_cap(X86_FEATURE_CLEAR_CPU_BUF);
 
                if (!boot_cpu_has(X86_BUG_MSBDS_ONLY) &&
                    (mds_nosmt || cpu_mitigations_auto_nosmt()))
@@ -356,7 +353,7 @@ static void __init taa_select_mitigation(void)
         * For guests that can't determine whether the correct microcode is
         * present on host, enable the mitigation for UCODE_NEEDED as well.
         */
-       static_branch_enable(&mds_user_clear);
+       setup_force_cpu_cap(X86_FEATURE_CLEAR_CPU_BUF);
 
        if (taa_nosmt || cpu_mitigations_auto_nosmt())
                cpu_smt_disable(false);
@@ -424,7 +421,14 @@ static void __init mmio_select_mitigation(void)
         */
        if (boot_cpu_has_bug(X86_BUG_MDS) || (boot_cpu_has_bug(X86_BUG_TAA) &&
                                              boot_cpu_has(X86_FEATURE_RTM)))
-               static_branch_enable(&mds_user_clear);
+               setup_force_cpu_cap(X86_FEATURE_CLEAR_CPU_BUF);
+
+       /*
+        * X86_FEATURE_CLEAR_CPU_BUF could be enabled by other VERW based
+        * mitigations, disable KVM-only mitigation in that case.
+        */
+       if (boot_cpu_has(X86_FEATURE_CLEAR_CPU_BUF))
+               static_branch_disable(&mmio_stale_data_clear);
        else
                static_branch_enable(&mmio_stale_data_clear);
 
@@ -476,6 +480,57 @@ static int __init mmio_stale_data_parse_cmdline(char *str)
 }
 early_param("mmio_stale_data", mmio_stale_data_parse_cmdline);
 
+#undef pr_fmt
+#define pr_fmt(fmt)    "Register File Data Sampling: " fmt
+
+enum rfds_mitigations {
+       RFDS_MITIGATION_OFF,
+       RFDS_MITIGATION_VERW,
+       RFDS_MITIGATION_UCODE_NEEDED,
+};
+
+/* Default mitigation for Register File Data Sampling */
+static enum rfds_mitigations rfds_mitigation __ro_after_init =
+       IS_ENABLED(CONFIG_MITIGATION_RFDS) ? RFDS_MITIGATION_VERW : RFDS_MITIGATION_OFF;
+
+static const char * const rfds_strings[] = {
+       [RFDS_MITIGATION_OFF]                   = "Vulnerable",
+       [RFDS_MITIGATION_VERW]                  = "Mitigation: Clear Register File",
+       [RFDS_MITIGATION_UCODE_NEEDED]          = "Vulnerable: No microcode",
+};
+
+static void __init rfds_select_mitigation(void)
+{
+       if (!boot_cpu_has_bug(X86_BUG_RFDS) || cpu_mitigations_off()) {
+               rfds_mitigation = RFDS_MITIGATION_OFF;
+               return;
+       }
+       if (rfds_mitigation == RFDS_MITIGATION_OFF)
+               return;
+
+       if (x86_read_arch_cap_msr() & ARCH_CAP_RFDS_CLEAR)
+               setup_force_cpu_cap(X86_FEATURE_CLEAR_CPU_BUF);
+       else
+               rfds_mitigation = RFDS_MITIGATION_UCODE_NEEDED;
+}
+
+static __init int rfds_parse_cmdline(char *str)
+{
+       if (!str)
+               return -EINVAL;
+
+       if (!boot_cpu_has_bug(X86_BUG_RFDS))
+               return 0;
+
+       if (!strcmp(str, "off"))
+               rfds_mitigation = RFDS_MITIGATION_OFF;
+       else if (!strcmp(str, "on"))
+               rfds_mitigation = RFDS_MITIGATION_VERW;
+
+       return 0;
+}
+early_param("reg_file_data_sampling", rfds_parse_cmdline);
+
 #undef pr_fmt
 #define pr_fmt(fmt)     "" fmt
 
@@ -484,12 +539,12 @@ static void __init md_clear_update_mitigation(void)
        if (cpu_mitigations_off())
                return;
 
-       if (!static_key_enabled(&mds_user_clear))
+       if (!boot_cpu_has(X86_FEATURE_CLEAR_CPU_BUF))
                goto out;
 
        /*
-        * mds_user_clear is now enabled. Update MDS, TAA and MMIO Stale Data
-        * mitigation, if necessary.
+        * X86_FEATURE_CLEAR_CPU_BUF is now enabled. Update MDS, TAA and MMIO
+        * Stale Data mitigation, if necessary.
         */
        if (mds_mitigation == MDS_MITIGATION_OFF &&
            boot_cpu_has_bug(X86_BUG_MDS)) {
@@ -501,11 +556,19 @@ static void __init md_clear_update_mitigation(void)
                taa_mitigation = TAA_MITIGATION_VERW;
                taa_select_mitigation();
        }
-       if (mmio_mitigation == MMIO_MITIGATION_OFF &&
-           boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA)) {
+       /*
+        * MMIO_MITIGATION_OFF is not checked here so that mmio_stale_data_clear
+        * gets updated correctly as per X86_FEATURE_CLEAR_CPU_BUF state.
+        */
+       if (boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA)) {
                mmio_mitigation = MMIO_MITIGATION_VERW;
                mmio_select_mitigation();
        }
+       if (rfds_mitigation == RFDS_MITIGATION_OFF &&
+           boot_cpu_has_bug(X86_BUG_RFDS)) {
+               rfds_mitigation = RFDS_MITIGATION_VERW;
+               rfds_select_mitigation();
+       }
 out:
        if (boot_cpu_has_bug(X86_BUG_MDS))
                pr_info("MDS: %s\n", mds_strings[mds_mitigation]);
@@ -515,6 +578,8 @@ out:
                pr_info("MMIO Stale Data: %s\n", mmio_strings[mmio_mitigation]);
        else if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
                pr_info("MMIO Stale Data: Unknown: No mitigations\n");
+       if (boot_cpu_has_bug(X86_BUG_RFDS))
+               pr_info("Register File Data Sampling: %s\n", rfds_strings[rfds_mitigation]);
 }
 
 static void __init md_clear_select_mitigation(void)
@@ -522,11 +587,12 @@ static void __init md_clear_select_mitigation(void)
        mds_select_mitigation();
        taa_select_mitigation();
        mmio_select_mitigation();
+       rfds_select_mitigation();
 
        /*
-        * As MDS, TAA and MMIO Stale Data mitigations are inter-related, update
-        * and print their mitigation after MDS, TAA and MMIO Stale Data
-        * mitigation selection is done.
+        * As these mitigations are inter-related and rely on VERW instruction
+        * to clear the microarchitural buffers, update and print their status
+        * after mitigation selection is done for each of these vulnerabilities.
         */
        md_clear_update_mitigation();
 }
@@ -671,7 +737,7 @@ enum gds_mitigations {
        GDS_MITIGATION_HYPERVISOR,
 };
 
-#if IS_ENABLED(CONFIG_GDS_FORCE_MITIGATION)
+#if IS_ENABLED(CONFIG_MITIGATION_GDS_FORCE)
 static enum gds_mitigations gds_mitigation __ro_after_init = GDS_MITIGATION_FORCE;
 #else
 static enum gds_mitigations gds_mitigation __ro_after_init = GDS_MITIGATION_FULL;
@@ -982,10 +1048,10 @@ static void __init retbleed_select_mitigation(void)
                return;
 
        case RETBLEED_CMD_UNRET:
-               if (IS_ENABLED(CONFIG_CPU_UNRET_ENTRY)) {
+               if (IS_ENABLED(CONFIG_MITIGATION_UNRET_ENTRY)) {
                        retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
                } else {
-                       pr_err("WARNING: kernel not compiled with CPU_UNRET_ENTRY.\n");
+                       pr_err("WARNING: kernel not compiled with MITIGATION_UNRET_ENTRY.\n");
                        goto do_cmd_auto;
                }
                break;
@@ -994,24 +1060,24 @@ static void __init retbleed_select_mitigation(void)
                if (!boot_cpu_has(X86_FEATURE_IBPB)) {
                        pr_err("WARNING: CPU does not support IBPB.\n");
                        goto do_cmd_auto;
-               } else if (IS_ENABLED(CONFIG_CPU_IBPB_ENTRY)) {
+               } else if (IS_ENABLED(CONFIG_MITIGATION_IBPB_ENTRY)) {
                        retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
                } else {
-                       pr_err("WARNING: kernel not compiled with CPU_IBPB_ENTRY.\n");
+                       pr_err("WARNING: kernel not compiled with MITIGATION_IBPB_ENTRY.\n");
                        goto do_cmd_auto;
                }
                break;
 
        case RETBLEED_CMD_STUFF:
-               if (IS_ENABLED(CONFIG_CALL_DEPTH_TRACKING) &&
+               if (IS_ENABLED(CONFIG_MITIGATION_CALL_DEPTH_TRACKING) &&
                    spectre_v2_enabled == SPECTRE_V2_RETPOLINE) {
                        retbleed_mitigation = RETBLEED_MITIGATION_STUFF;
 
                } else {
-                       if (IS_ENABLED(CONFIG_CALL_DEPTH_TRACKING))
+                       if (IS_ENABLED(CONFIG_MITIGATION_CALL_DEPTH_TRACKING))
                                pr_err("WARNING: retbleed=stuff depends on spectre_v2=retpoline\n");
                        else
-                               pr_err("WARNING: kernel not compiled with CALL_DEPTH_TRACKING.\n");
+                               pr_err("WARNING: kernel not compiled with MITIGATION_CALL_DEPTH_TRACKING.\n");
 
                        goto do_cmd_auto;
                }
@@ -1021,9 +1087,10 @@ do_cmd_auto:
        case RETBLEED_CMD_AUTO:
                if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
                    boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
-                       if (IS_ENABLED(CONFIG_CPU_UNRET_ENTRY))
+                       if (IS_ENABLED(CONFIG_MITIGATION_UNRET_ENTRY))
                                retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
-                       else if (IS_ENABLED(CONFIG_CPU_IBPB_ENTRY) && boot_cpu_has(X86_FEATURE_IBPB))
+                       else if (IS_ENABLED(CONFIG_MITIGATION_IBPB_ENTRY) &&
+                                boot_cpu_has(X86_FEATURE_IBPB))
                                retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
                }
 
@@ -1102,7 +1169,7 @@ static enum spectre_v2_user_mitigation spectre_v2_user_stibp __ro_after_init =
 static enum spectre_v2_user_mitigation spectre_v2_user_ibpb __ro_after_init =
        SPECTRE_V2_USER_NONE;
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
 static bool spectre_v2_bad_module;
 
 bool retpoline_module_ok(bool has_retpoline)
@@ -1415,7 +1482,7 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
             cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC ||
             cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
             cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
-           !IS_ENABLED(CONFIG_RETPOLINE)) {
+           !IS_ENABLED(CONFIG_MITIGATION_RETPOLINE)) {
                pr_err("%s selected but not compiled in. Switching to AUTO select\n",
                       mitigation_options[i].option);
                return SPECTRE_V2_CMD_AUTO;
@@ -1438,7 +1505,7 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
                return SPECTRE_V2_CMD_AUTO;
        }
 
-       if (cmd == SPECTRE_V2_CMD_IBRS && !IS_ENABLED(CONFIG_CPU_IBRS_ENTRY)) {
+       if (cmd == SPECTRE_V2_CMD_IBRS && !IS_ENABLED(CONFIG_MITIGATION_IBRS_ENTRY)) {
                pr_err("%s selected but not compiled in. Switching to AUTO select\n",
                       mitigation_options[i].option);
                return SPECTRE_V2_CMD_AUTO;
@@ -1469,7 +1536,7 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
 
 static enum spectre_v2_mitigation __init spectre_v2_select_retpoline(void)
 {
-       if (!IS_ENABLED(CONFIG_RETPOLINE)) {
+       if (!IS_ENABLED(CONFIG_MITIGATION_RETPOLINE)) {
                pr_err("Kernel not compiled with retpoline; no mitigation available!");
                return SPECTRE_V2_NONE;
        }
@@ -1564,7 +1631,7 @@ static void __init spectre_v2_select_mitigation(void)
                        break;
                }
 
-               if (IS_ENABLED(CONFIG_CPU_IBRS_ENTRY) &&
+               if (IS_ENABLED(CONFIG_MITIGATION_IBRS_ENTRY) &&
                    boot_cpu_has_bug(X86_BUG_RETBLEED) &&
                    retbleed_cmd != RETBLEED_CMD_OFF &&
                    retbleed_cmd != RETBLEED_CMD_STUFF &&
@@ -2457,7 +2524,7 @@ static void __init srso_select_mitigation(void)
                break;
 
        case SRSO_CMD_SAFE_RET:
-               if (IS_ENABLED(CONFIG_CPU_SRSO)) {
+               if (IS_ENABLED(CONFIG_MITIGATION_SRSO)) {
                        /*
                         * Enable the return thunk for generated code
                         * like ftrace, static_call, etc.
@@ -2477,29 +2544,29 @@ static void __init srso_select_mitigation(void)
                        else
                                srso_mitigation = SRSO_MITIGATION_SAFE_RET_UCODE_NEEDED;
                } else {
-                       pr_err("WARNING: kernel not compiled with CPU_SRSO.\n");
+                       pr_err("WARNING: kernel not compiled with MITIGATION_SRSO.\n");
                }
                break;
 
        case SRSO_CMD_IBPB:
-               if (IS_ENABLED(CONFIG_CPU_IBPB_ENTRY)) {
+               if (IS_ENABLED(CONFIG_MITIGATION_IBPB_ENTRY)) {
                        if (has_microcode) {
                                setup_force_cpu_cap(X86_FEATURE_ENTRY_IBPB);
                                srso_mitigation = SRSO_MITIGATION_IBPB;
                        }
                } else {
-                       pr_err("WARNING: kernel not compiled with CPU_IBPB_ENTRY.\n");
+                       pr_err("WARNING: kernel not compiled with MITIGATION_IBPB_ENTRY.\n");
                }
                break;
 
        case SRSO_CMD_IBPB_ON_VMEXIT:
-               if (IS_ENABLED(CONFIG_CPU_SRSO)) {
+               if (IS_ENABLED(CONFIG_MITIGATION_SRSO)) {
                        if (!boot_cpu_has(X86_FEATURE_ENTRY_IBPB) && has_microcode) {
                                setup_force_cpu_cap(X86_FEATURE_IBPB_ON_VMEXIT);
                                srso_mitigation = SRSO_MITIGATION_IBPB_ON_VMEXIT;
                        }
                } else {
-                       pr_err("WARNING: kernel not compiled with CPU_SRSO.\n");
+                       pr_err("WARNING: kernel not compiled with MITIGATION_SRSO.\n");
                 }
                break;
        }
@@ -2615,6 +2682,11 @@ static ssize_t mmio_stale_data_show_state(char *buf)
                          sched_smt_active() ? "vulnerable" : "disabled");
 }
 
+static ssize_t rfds_show_state(char *buf)
+{
+       return sysfs_emit(buf, "%s\n", rfds_strings[rfds_mitigation]);
+}
+
 static char *stibp_state(void)
 {
        if (spectre_v2_in_eibrs_mode(spectre_v2_enabled) &&
@@ -2774,6 +2846,9 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
        case X86_BUG_GDS:
                return gds_show_state(buf);
 
+       case X86_BUG_RFDS:
+               return rfds_show_state(buf);
+
        default:
                break;
        }
@@ -2848,4 +2923,14 @@ ssize_t cpu_show_gds(struct device *dev, struct device_attribute *attr, char *bu
 {
        return cpu_show_common(dev, attr, buf, X86_BUG_GDS);
 }
+
+ssize_t cpu_show_reg_file_data_sampling(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return cpu_show_common(dev, attr, buf, X86_BUG_RFDS);
+}
 #endif
+
+void __warn_thunk(void)
+{
+       WARN_ONCE(1, "Unpatched return thunk in use. This should not happen!\n");
+}
index c131c412db89c58e820cdfa6758c4db6b59d3429..392d09c936d60c4d5775bca0b044fe738e0c9937 100644 (file)
@@ -301,7 +301,7 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
        eax->split.type = types[leaf];
        eax->split.level = levels[leaf];
        eax->split.num_threads_sharing = 0;
-       eax->split.num_cores_on_die = __this_cpu_read(cpu_info.x86_max_cores) - 1;
+       eax->split.num_cores_on_die = topology_num_cores_per_package();
 
 
        if (assoc == 0xffff)
@@ -595,7 +595,7 @@ static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
        if (index < 3)
                return;
 
-       node = topology_die_id(smp_processor_id());
+       node = topology_amd_node_id(smp_processor_id());
        this_leaf->nb = node_to_amd_nb(node);
        if (this_leaf->nb && !this_leaf->nb->l3_cache.indices)
                amd_calc_l3_indices(this_leaf->nb);
@@ -661,7 +661,7 @@ static int find_num_cache_leaves(struct cpuinfo_x86 *c)
        return i;
 }
 
-void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c)
+void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, u16 die_id)
 {
        /*
         * We may have multiple LLCs if L3 caches exist, so check if we
@@ -672,7 +672,7 @@ void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c)
 
        if (c->x86 < 0x17) {
                /* LLC is at the node level. */
-               c->topo.llc_id = c->topo.die_id;
+               c->topo.llc_id = die_id;
        } else if (c->x86 == 0x17 && c->x86_model <= 0x1F) {
                /*
                 * LLC is at the core complex level.
@@ -1118,15 +1118,16 @@ static void cache_cpu_init(void)
        unsigned long flags;
 
        local_irq_save(flags);
-       cache_disable();
 
-       if (memory_caching_control & CACHE_MTRR)
+       if (memory_caching_control & CACHE_MTRR) {
+               cache_disable();
                mtrr_generic_set_state();
+               cache_enable();
+       }
 
        if (memory_caching_control & CACHE_PAT)
                pat_cpu_init();
 
-       cache_enable();
        local_irq_restore(flags);
 }
 
index 345f7d905db677291f7f8eb9b33b692263afe447..a3b55db35c9612151b69b2ef559d93897cabf727 100644 (file)
@@ -128,10 +128,6 @@ static void init_centaur(struct cpuinfo_x86 *c)
 #endif
        early_init_centaur(c);
        init_intel_cacheinfo(c);
-       detect_num_cpu_cores(c);
-#ifdef CONFIG_X86_32
-       detect_ht(c);
-#endif
 
        if (c->cpuid_level > 9) {
                unsigned int eax = cpuid_eax(10);
index 0b97bcde70c6102a4b82b561c3256ec53b614770..ba8cf5e9ce5632aeaa9322899f5b5eaea3aab2e7 100644 (file)
@@ -61,6 +61,7 @@
 #include <asm/microcode.h>
 #include <asm/intel-family.h>
 #include <asm/cpu_device_id.h>
+#include <asm/fred.h>
 #include <asm/uv/uv.h>
 #include <asm/ia32.h>
 #include <asm/set_memory.h>
 
 #include "cpu.h"
 
+DEFINE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
+EXPORT_PER_CPU_SYMBOL(cpu_info);
+
 u32 elf_hwcap2 __read_mostly;
 
 /* Number of siblings per CPU package */
-int smp_num_siblings = 1;
-EXPORT_SYMBOL(smp_num_siblings);
+unsigned int __max_threads_per_core __ro_after_init = 1;
+EXPORT_SYMBOL(__max_threads_per_core);
+
+unsigned int __max_dies_per_package __ro_after_init = 1;
+EXPORT_SYMBOL(__max_dies_per_package);
+
+unsigned int __max_logical_packages __ro_after_init = 1;
+EXPORT_SYMBOL(__max_logical_packages);
+
+unsigned int __num_cores_per_package __ro_after_init = 1;
+EXPORT_SYMBOL(__num_cores_per_package);
+
+unsigned int __num_threads_per_package __ro_after_init = 1;
+EXPORT_SYMBOL(__num_threads_per_package);
 
 static struct ppin_info {
        int     feature;
@@ -382,9 +398,8 @@ out:
 }
 
 /* These bits should not change their value after CPU init is finished. */
-static const unsigned long cr4_pinned_mask =
-       X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP |
-       X86_CR4_FSGSBASE | X86_CR4_CET;
+static const unsigned long cr4_pinned_mask = X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP |
+                                            X86_CR4_FSGSBASE | X86_CR4_CET | X86_CR4_FRED;
 static DEFINE_STATIC_KEY_FALSE_RO(cr_pinning);
 static unsigned long cr4_pinned_bits __ro_after_init;
 
@@ -790,19 +805,6 @@ static void get_model_name(struct cpuinfo_x86 *c)
        *(s + 1) = '\0';
 }
 
-void detect_num_cpu_cores(struct cpuinfo_x86 *c)
-{
-       unsigned int eax, ebx, ecx, edx;
-
-       c->x86_max_cores = 1;
-       if (!IS_ENABLED(CONFIG_SMP) || c->cpuid_level < 4)
-               return;
-
-       cpuid_count(4, 0, &eax, &ebx, &ecx, &edx);
-       if (eax & 0x1f)
-               c->x86_max_cores = (eax >> 26) + 1;
-}
-
 void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
 {
        unsigned int n, dummy, ebx, ecx, edx, l2size;
@@ -864,51 +866,6 @@ static void cpu_detect_tlb(struct cpuinfo_x86 *c)
                tlb_lld_4m[ENTRIES], tlb_lld_1g[ENTRIES]);
 }
 
-int detect_ht_early(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-       u32 eax, ebx, ecx, edx;
-
-       if (!cpu_has(c, X86_FEATURE_HT))
-               return -1;
-
-       if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
-               return -1;
-
-       if (cpu_has(c, X86_FEATURE_XTOPOLOGY))
-               return -1;
-
-       cpuid(1, &eax, &ebx, &ecx, &edx);
-
-       smp_num_siblings = (ebx & 0xff0000) >> 16;
-       if (smp_num_siblings == 1)
-               pr_info_once("CPU0: Hyper-Threading is disabled\n");
-#endif
-       return 0;
-}
-
-void detect_ht(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-       int index_msb, core_bits;
-
-       if (detect_ht_early(c) < 0)
-               return;
-
-       index_msb = get_count_order(smp_num_siblings);
-       c->topo.pkg_id = apic->phys_pkg_id(c->topo.initial_apicid, index_msb);
-
-       smp_num_siblings = smp_num_siblings / c->x86_max_cores;
-
-       index_msb = get_count_order(smp_num_siblings);
-
-       core_bits = get_count_order(c->x86_max_cores);
-
-       c->topo.core_id = apic->phys_pkg_id(c->topo.initial_apicid, index_msb) &
-               ((1 << core_bits) - 1);
-#endif
-}
-
 static void get_cpu_vendor(struct cpuinfo_x86 *c)
 {
        char *v = c->x86_vendor_id;
@@ -1267,6 +1224,8 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
 #define SRSO           BIT(5)
 /* CPU is affected by GDS */
 #define GDS            BIT(6)
+/* CPU is affected by Register File Data Sampling */
+#define RFDS           BIT(7)
 
 static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
        VULNBL_INTEL_STEPPINGS(IVYBRIDGE,       X86_STEPPING_ANY,               SRBDS),
@@ -1294,9 +1253,18 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
        VULNBL_INTEL_STEPPINGS(TIGERLAKE,       X86_STEPPING_ANY,               GDS),
        VULNBL_INTEL_STEPPINGS(LAKEFIELD,       X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
        VULNBL_INTEL_STEPPINGS(ROCKETLAKE,      X86_STEPPING_ANY,               MMIO | RETBLEED | GDS),
-       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT,    X86_STEPPING_ANY,               MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_D,  X86_STEPPING_ANY,               MMIO),
-       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L,  X86_STEPPING_ANY,               MMIO | MMIO_SBDS),
+       VULNBL_INTEL_STEPPINGS(ALDERLAKE,       X86_STEPPING_ANY,               RFDS),
+       VULNBL_INTEL_STEPPINGS(ALDERLAKE_L,     X86_STEPPING_ANY,               RFDS),
+       VULNBL_INTEL_STEPPINGS(RAPTORLAKE,      X86_STEPPING_ANY,               RFDS),
+       VULNBL_INTEL_STEPPINGS(RAPTORLAKE_P,    X86_STEPPING_ANY,               RFDS),
+       VULNBL_INTEL_STEPPINGS(RAPTORLAKE_S,    X86_STEPPING_ANY,               RFDS),
+       VULNBL_INTEL_STEPPINGS(ATOM_GRACEMONT,  X86_STEPPING_ANY,               RFDS),
+       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT,    X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RFDS),
+       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_D,  X86_STEPPING_ANY,               MMIO | RFDS),
+       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L,  X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RFDS),
+       VULNBL_INTEL_STEPPINGS(ATOM_GOLDMONT,   X86_STEPPING_ANY,               RFDS),
+       VULNBL_INTEL_STEPPINGS(ATOM_GOLDMONT_D, X86_STEPPING_ANY,               RFDS),
+       VULNBL_INTEL_STEPPINGS(ATOM_GOLDMONT_PLUS, X86_STEPPING_ANY,            RFDS),
 
        VULNBL_AMD(0x15, RETBLEED),
        VULNBL_AMD(0x16, RETBLEED),
@@ -1330,6 +1298,24 @@ static bool arch_cap_mmio_immune(u64 ia32_cap)
                ia32_cap & ARCH_CAP_SBDR_SSDP_NO);
 }
 
+static bool __init vulnerable_to_rfds(u64 ia32_cap)
+{
+       /* The "immunity" bit trumps everything else: */
+       if (ia32_cap & ARCH_CAP_RFDS_NO)
+               return false;
+
+       /*
+        * VMMs set ARCH_CAP_RFDS_CLEAR for processors not in the blacklist to
+        * indicate that mitigation is needed because guest is running on a
+        * vulnerable hardware or may migrate to such hardware:
+        */
+       if (ia32_cap & ARCH_CAP_RFDS_CLEAR)
+               return true;
+
+       /* Only consult the blacklist when there is no enumeration: */
+       return cpu_matches(cpu_vuln_blacklist, RFDS);
+}
+
 static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
 {
        u64 ia32_cap = x86_read_arch_cap_msr();
@@ -1355,8 +1341,13 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
        /*
         * AMD's AutoIBRS is equivalent to Intel's eIBRS - use the Intel feature
         * flag and protect from vendor-specific bugs via the whitelist.
+        *
+        * Don't use AutoIBRS when SNP is enabled because it degrades host
+        * userspace indirect branch performance.
         */
-       if ((ia32_cap & ARCH_CAP_IBRS_ALL) || cpu_has(c, X86_FEATURE_AUTOIBRS)) {
+       if ((ia32_cap & ARCH_CAP_IBRS_ALL) ||
+           (cpu_has(c, X86_FEATURE_AUTOIBRS) &&
+            !cpu_feature_enabled(X86_FEATURE_SEV_SNP))) {
                setup_force_cpu_cap(X86_FEATURE_IBRS_ENHANCED);
                if (!cpu_matches(cpu_vuln_whitelist, NO_EIBRS_PBRSB) &&
                    !(ia32_cap & ARCH_CAP_PBRSB_NO))
@@ -1441,6 +1432,9 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
            boot_cpu_has(X86_FEATURE_AVX))
                setup_force_cpu_bug(X86_BUG_GDS);
 
+       if (vulnerable_to_rfds(ia32_cap))
+               setup_force_cpu_bug(X86_BUG_RFDS);
+
        if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN))
                return;
 
@@ -1589,8 +1583,11 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
                get_cpu_vendor(c);
                get_cpu_cap(c);
                setup_force_cpu_cap(X86_FEATURE_CPUID);
+               get_cpu_address_sizes(c);
                cpu_parse_early_param();
 
+               cpu_init_topology(c);
+
                if (this_cpu->c_early_init)
                        this_cpu->c_early_init(c);
 
@@ -1601,10 +1598,10 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
                        this_cpu->c_bsp_init(c);
        } else {
                setup_clear_cpu_cap(X86_FEATURE_CPUID);
+               get_cpu_address_sizes(c);
+               cpu_init_topology(c);
        }
 
-       get_cpu_address_sizes(c);
-
        setup_force_cpu_cap(X86_FEATURE_ALWAYS);
 
        cpu_set_bug_bits(c);
@@ -1748,18 +1745,6 @@ static void generic_identify(struct cpuinfo_x86 *c)
 
        get_cpu_address_sizes(c);
 
-       if (c->cpuid_level >= 0x00000001) {
-               c->topo.initial_apicid = (cpuid_ebx(1) >> 24) & 0xFF;
-#ifdef CONFIG_X86_32
-# ifdef CONFIG_SMP
-               c->topo.apicid = apic->phys_pkg_id(c->topo.initial_apicid, 0);
-# else
-               c->topo.apicid = c->topo.initial_apicid;
-# endif
-#endif
-               c->topo.pkg_id = c->topo.initial_apicid;
-       }
-
        get_model_name(c); /* Default name */
 
        /*
@@ -1780,29 +1765,6 @@ static void generic_identify(struct cpuinfo_x86 *c)
 #endif
 }
 
-/*
- * Validate that ACPI/mptables have the same information about the
- * effective APIC id and update the package map.
- */
-static void validate_apic_and_package_id(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-       unsigned int cpu = smp_processor_id();
-       u32 apicid;
-
-       apicid = apic->cpu_present_to_apicid(cpu);
-
-       if (apicid != c->topo.apicid) {
-               pr_err(FW_BUG "CPU%u: APIC id mismatch. Firmware: %x APIC: %x\n",
-                      cpu, apicid, c->topo.initial_apicid);
-       }
-       BUG_ON(topology_update_package_map(c->topo.pkg_id, cpu));
-       BUG_ON(topology_update_die_map(c->topo.die_id, cpu));
-#else
-       c->topo.logical_pkg_id = 0;
-#endif
-}
-
 /*
  * This does the hard work of actually picking apart the CPU stuff...
  */
@@ -1816,11 +1778,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
        c->x86_model = c->x86_stepping = 0;     /* So far unknown... */
        c->x86_vendor_id[0] = '\0'; /* Unset */
        c->x86_model_id[0] = '\0';  /* Unset */
-       c->x86_max_cores = 1;
-       c->x86_coreid_bits = 0;
-       c->topo.cu_id = 0xff;
-       c->topo.llc_id = BAD_APICID;
-       c->topo.l2c_id = BAD_APICID;
 #ifdef CONFIG_X86_64
        c->x86_clflush_size = 64;
        c->x86_phys_bits = 36;
@@ -1839,17 +1796,14 @@ static void identify_cpu(struct cpuinfo_x86 *c)
 
        generic_identify(c);
 
+       cpu_parse_topology(c);
+
        if (this_cpu->c_identify)
                this_cpu->c_identify(c);
 
        /* Clear/Set all flags overridden by options, after probe */
        apply_forced_caps(c);
 
-#ifdef CONFIG_X86_64
-       c->topo.apicid = apic->phys_pkg_id(c->topo.initial_apicid, 0);
-#endif
-
-
        /*
         * Set default APIC and TSC_DEADLINE MSR fencing flag. AMD and
         * Hygon will clear it in ->c_init() below.
@@ -1903,10 +1857,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
                                c->x86, c->x86_model);
        }
 
-#ifdef CONFIG_X86_64
-       detect_ht(c);
-#endif
-
        x86_init_rdrand(c);
        setup_pku(c);
        setup_cet(c);
@@ -1938,8 +1888,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
        /* Init Machine Check Exception if available. */
        mcheck_cpu_init(c);
 
-       select_idle_routine(c);
-
 #ifdef CONFIG_NUMA
        numa_add_cpu(smp_processor_id());
 #endif
@@ -1998,7 +1946,6 @@ void identify_secondary_cpu(struct cpuinfo_x86 *c)
 #ifdef CONFIG_X86_32
        enable_sep_cpu();
 #endif
-       validate_apic_and_package_id(c);
        x86_spec_ctrl_setup_ap();
        update_srbds_msr();
        if (boot_cpu_has_bug(X86_BUG_GDS))
@@ -2050,6 +1997,7 @@ DEFINE_PER_CPU_ALIGNED(struct pcpu_hot, pcpu_hot) = {
        .top_of_stack   = TOP_OF_INIT_STACK,
 };
 EXPORT_PER_CPU_SYMBOL(pcpu_hot);
+EXPORT_PER_CPU_SYMBOL(const_pcpu_hot);
 
 #ifdef CONFIG_X86_64
 DEFINE_PER_CPU_FIRST(struct fixed_percpu_data,
@@ -2067,10 +2015,8 @@ static void wrmsrl_cstar(unsigned long val)
                wrmsrl(MSR_CSTAR, val);
 }
 
-/* May not be marked __init: used by software suspend */
-void syscall_init(void)
+static inline void idt_syscall_init(void)
 {
-       wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
        wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
 
        if (ia32_enabled()) {
@@ -2104,6 +2050,23 @@ void syscall_init(void)
               X86_EFLAGS_AC|X86_EFLAGS_ID);
 }
 
+/* May not be marked __init: used by software suspend */
+void syscall_init(void)
+{
+       /* The default user and kernel segments */
+       wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
+
+       /*
+        * Except the IA32_STAR MSR, there is NO need to setup SYSCALL and
+        * SYSENTER MSRs for FRED, because FRED uses the ring 3 FRED
+        * entrypoint for SYSCALL and SYSENTER, and ERETU is the only legit
+        * instruction to return to ring 3 (both sysexit and sysret cause
+        * #UD when FRED is enabled).
+        */
+       if (!cpu_feature_enabled(X86_FEATURE_FRED))
+               idt_syscall_init();
+}
+
 #else  /* CONFIG_X86_64 */
 
 #ifdef CONFIG_STACKPROTECTOR
@@ -2207,8 +2170,9 @@ void cpu_init_exception_handling(void)
        /* paranoid_entry() gets the CPU number from the GDT */
        setup_getcpu(cpu);
 
-       /* IST vectors need TSS to be set up. */
-       tss_setup_ist(tss);
+       /* For IDT mode, IST vectors need to be set in TSS. */
+       if (!cpu_feature_enabled(X86_FEATURE_FRED))
+               tss_setup_ist(tss);
        tss_setup_io_bitmap(tss);
        set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss);
 
@@ -2217,8 +2181,10 @@ void cpu_init_exception_handling(void)
        /* GHCB needs to be setup to handle #VC. */
        setup_ghcb();
 
-       /* Finally load the IDT */
-       load_current_idt();
+       if (cpu_feature_enabled(X86_FEATURE_FRED))
+               cpu_init_fred_exceptions();
+       else
+               load_current_idt();
 }
 
 /*
@@ -2343,11 +2309,13 @@ void __init arch_cpu_finalize_init(void)
 {
        identify_boot_cpu();
 
+       select_idle_routine();
+
        /*
         * identify_boot_cpu() initialized SMT support information, let the
         * core code know.
         */
-       cpu_smt_set_num_threads(smp_num_siblings, smp_num_siblings);
+       cpu_smt_set_num_threads(__max_threads_per_core, __max_threads_per_core);
 
        if (!IS_ENABLED(CONFIG_SMP)) {
                pr_info("CPU: ");
index 885281ae79a54c91172445f995519ab156113861..ea9e07d57c8dd2d694d78769ea8729d0dda63dbd 100644 (file)
@@ -2,6 +2,11 @@
 #ifndef ARCH_X86_CPU_H
 #define ARCH_X86_CPU_H
 
+#include <asm/cpu.h>
+#include <asm/topology.h>
+
+#include "topology.h"
+
 /* attempt to consolidate cpu attributes */
 struct cpu_dev {
        const char      *c_vendor;
@@ -71,14 +76,9 @@ extern void init_intel_cacheinfo(struct cpuinfo_x86 *c);
 extern void init_amd_cacheinfo(struct cpuinfo_x86 *c);
 extern void init_hygon_cacheinfo(struct cpuinfo_x86 *c);
 
-extern void detect_num_cpu_cores(struct cpuinfo_x86 *c);
-extern int detect_extended_topology_early(struct cpuinfo_x86 *c);
-extern int detect_extended_topology(struct cpuinfo_x86 *c);
-extern int detect_ht_early(struct cpuinfo_x86 *c);
-extern void detect_ht(struct cpuinfo_x86 *c);
 extern void check_null_seg_clears_base(struct cpuinfo_x86 *c);
 
-void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c);
+void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, u16 die_id);
 void cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 *c);
 
 unsigned int aperfmperf_get_khz(int cpu);
@@ -96,4 +96,5 @@ static inline bool spectre_v2_in_eibrs_mode(enum spectre_v2_mitigation mode)
               mode == SPECTRE_V2_EIBRS_RETPOLINE ||
               mode == SPECTRE_V2_EIBRS_LFENCE;
 }
+
 #endif /* ARCH_X86_CPU_H */
index e462c1d3800a6cb47c7d486a2a684278fd4cca1e..b7174209d855c634a701aaf489372b087f464006 100644 (file)
@@ -82,6 +82,8 @@ static const struct cpuid_dep cpuid_deps[] = {
        { X86_FEATURE_XFD,                      X86_FEATURE_XGETBV1   },
        { X86_FEATURE_AMX_TILE,                 X86_FEATURE_XFD       },
        { X86_FEATURE_SHSTK,                    X86_FEATURE_XSAVES    },
+       { X86_FEATURE_FRED,                     X86_FEATURE_LKGS      },
+       { X86_FEATURE_FRED,                     X86_FEATURE_WRMSRNS   },
        {}
 };
 
index 0c179d684b3b6ae3a7cef05b77b1f4cdfa5bf136..3baf3e43583472e9d6b9ee931d91acf48303b42e 100644 (file)
@@ -5,6 +5,8 @@
 #include <asm/apic.h>
 #include <asm/processor.h>
 
+#include "cpu.h"
+
 static int cpu_debug_show(struct seq_file *m, void *p)
 {
        unsigned long cpu = (unsigned long)m->private;
@@ -24,9 +26,12 @@ static int cpu_debug_show(struct seq_file *m, void *p)
        seq_printf(m, "logical_die_id:      %u\n", c->topo.logical_die_id);
        seq_printf(m, "llc_id:              %u\n", c->topo.llc_id);
        seq_printf(m, "l2c_id:              %u\n", c->topo.l2c_id);
-       seq_printf(m, "max_cores:           %u\n", c->x86_max_cores);
-       seq_printf(m, "max_die_per_pkg:     %u\n", __max_die_per_package);
-       seq_printf(m, "smp_num_siblings:    %u\n", smp_num_siblings);
+       seq_printf(m, "amd_node_id:         %u\n", c->topo.amd_node_id);
+       seq_printf(m, "amd_nodes_per_pkg:   %u\n", topology_amd_nodes_per_pkg());
+       seq_printf(m, "num_threads:         %u\n", __num_threads_per_package);
+       seq_printf(m, "num_cores:           %u\n", __num_cores_per_package);
+       seq_printf(m, "max_dies_per_pkg:    %u\n", __max_dies_per_package);
+       seq_printf(m, "max_threads_per_core:%u\n", __max_threads_per_core);
        return 0;
 }
 
@@ -42,12 +47,48 @@ static const struct file_operations dfs_cpu_ops = {
        .release        = single_release,
 };
 
+static int dom_debug_show(struct seq_file *m, void *p)
+{
+       static const char *domain_names[TOPO_MAX_DOMAIN] = {
+               [TOPO_SMT_DOMAIN]       = "Thread",
+               [TOPO_CORE_DOMAIN]      = "Core",
+               [TOPO_MODULE_DOMAIN]    = "Module",
+               [TOPO_TILE_DOMAIN]      = "Tile",
+               [TOPO_DIE_DOMAIN]       = "Die",
+               [TOPO_DIEGRP_DOMAIN]    = "DieGrp",
+               [TOPO_PKG_DOMAIN]       = "Package",
+       };
+       unsigned int dom, nthreads = 1;
+
+       for (dom = 0; dom < TOPO_MAX_DOMAIN; dom++) {
+               nthreads *= x86_topo_system.dom_size[dom];
+               seq_printf(m, "domain: %-10s shift: %u dom_size: %5u max_threads: %5u\n",
+                          domain_names[dom], x86_topo_system.dom_shifts[dom],
+                          x86_topo_system.dom_size[dom], nthreads);
+       }
+       return 0;
+}
+
+static int dom_debug_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dom_debug_show, inode->i_private);
+}
+
+static const struct file_operations dfs_dom_ops = {
+       .open           = dom_debug_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static __init int cpu_init_debugfs(void)
 {
        struct dentry *dir, *base = debugfs_create_dir("topo", arch_debugfs_dir);
        unsigned long id;
        char name[24];
 
+       debugfs_create_file("domains", 0444, base, NULL, &dfs_dom_ops);
+
        dir = debugfs_create_dir("cpus", base);
        for_each_possible_cpu(id) {
                sprintf(name, "%lu", id);
index f0cd95502faaee2e31705903e0ea34ea30761bdc..c5191b06f9f21b5ca79da96a3d5d6792d95deffe 100644 (file)
 
 #include "cpu.h"
 
-#define APICID_SOCKET_ID_BIT 6
-
-/*
- * nodes_per_socket: Stores the number of nodes per socket.
- * Refer to CPUID Fn8000_001E_ECX Node Identifiers[10:8]
- */
-static u32 nodes_per_socket = 1;
-
 #ifdef CONFIG_NUMA
 /*
  * To workaround broken NUMA config.  Read the comment in
@@ -49,80 +41,6 @@ static int nearby_node(int apicid)
 }
 #endif
 
-static void hygon_get_topology_early(struct cpuinfo_x86 *c)
-{
-       if (cpu_has(c, X86_FEATURE_TOPOEXT))
-               smp_num_siblings = ((cpuid_ebx(0x8000001e) >> 8) & 0xff) + 1;
-}
-
-/*
- * Fixup core topology information for
- * (1) Hygon multi-node processors
- *     Assumption: Number of cores in each internal node is the same.
- * (2) Hygon processors supporting compute units
- */
-static void hygon_get_topology(struct cpuinfo_x86 *c)
-{
-       /* get information required for multi-node processors */
-       if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
-               int err;
-               u32 eax, ebx, ecx, edx;
-
-               cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
-
-               c->topo.die_id  = ecx & 0xff;
-
-               c->topo.core_id = ebx & 0xff;
-
-               if (smp_num_siblings > 1)
-                       c->x86_max_cores /= smp_num_siblings;
-
-               /*
-                * In case leaf B is available, use it to derive
-                * topology information.
-                */
-               err = detect_extended_topology(c);
-               if (!err)
-                       c->x86_coreid_bits = get_count_order(c->x86_max_cores);
-
-               /*
-                * Socket ID is ApicId[6] for the processors with model <= 0x3
-                * when running on host.
-                */
-               if (!boot_cpu_has(X86_FEATURE_HYPERVISOR) && c->x86_model <= 0x3)
-                       c->topo.pkg_id = c->topo.apicid >> APICID_SOCKET_ID_BIT;
-
-               cacheinfo_hygon_init_llc_id(c);
-       } else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) {
-               u64 value;
-
-               rdmsrl(MSR_FAM10H_NODE_ID, value);
-               c->topo.die_id = value & 7;
-               c->topo.llc_id = c->topo.die_id;
-       } else
-               return;
-
-       if (nodes_per_socket > 1)
-               set_cpu_cap(c, X86_FEATURE_AMD_DCM);
-}
-
-/*
- * On Hygon setup the lower bits of the APIC id distinguish the cores.
- * Assumes number of cores is a power of two.
- */
-static void hygon_detect_cmp(struct cpuinfo_x86 *c)
-{
-       unsigned int bits;
-
-       bits = c->x86_coreid_bits;
-       /* Low order bits define the core id (index of core in socket) */
-       c->topo.core_id = c->topo.initial_apicid & ((1 << bits)-1);
-       /* Convert the initial APIC ID into the socket ID */
-       c->topo.pkg_id = c->topo.initial_apicid >> bits;
-       /* Use package ID also for last level cache */
-       c->topo.llc_id = c->topo.die_id = c->topo.pkg_id;
-}
-
 static void srat_detect_node(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_NUMA
@@ -173,32 +91,6 @@ static void srat_detect_node(struct cpuinfo_x86 *c)
 #endif
 }
 
-static void early_init_hygon_mc(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-       unsigned int bits, ecx;
-
-       /* Multi core CPU? */
-       if (c->extended_cpuid_level < 0x80000008)
-               return;
-
-       ecx = cpuid_ecx(0x80000008);
-
-       c->x86_max_cores = (ecx & 0xff) + 1;
-
-       /* CPU telling us the core id bits shift? */
-       bits = (ecx >> 12) & 0xF;
-
-       /* Otherwise recompute */
-       if (bits == 0) {
-               while ((1 << bits) < c->x86_max_cores)
-                       bits++;
-       }
-
-       c->x86_coreid_bits = bits;
-#endif
-}
-
 static void bsp_init_hygon(struct cpuinfo_x86 *c)
 {
        if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) {
@@ -212,18 +104,6 @@ static void bsp_init_hygon(struct cpuinfo_x86 *c)
        if (cpu_has(c, X86_FEATURE_MWAITX))
                use_mwaitx_delay();
 
-       if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
-               u32 ecx;
-
-               ecx = cpuid_ecx(0x8000001e);
-               __max_die_per_package = nodes_per_socket = ((ecx >> 8) & 7) + 1;
-       } else if (boot_cpu_has(X86_FEATURE_NODEID_MSR)) {
-               u64 value;
-
-               rdmsrl(MSR_FAM10H_NODE_ID, value);
-               __max_die_per_package = nodes_per_socket = ((value >> 3) & 7) + 1;
-       }
-
        if (!boot_cpu_has(X86_FEATURE_AMD_SSBD) &&
            !boot_cpu_has(X86_FEATURE_VIRT_SSBD)) {
                /*
@@ -242,8 +122,6 @@ static void early_init_hygon(struct cpuinfo_x86 *c)
 {
        u32 dummy;
 
-       early_init_hygon_mc(c);
-
        set_cpu_cap(c, X86_FEATURE_K8);
 
        rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);
@@ -284,8 +162,6 @@ static void early_init_hygon(struct cpuinfo_x86 *c)
         * we can set it unconditionally.
         */
        set_cpu_cap(c, X86_FEATURE_VMMCALL);
-
-       hygon_get_topology_early(c);
 }
 
 static void init_hygon(struct cpuinfo_x86 *c)
@@ -302,9 +178,6 @@ static void init_hygon(struct cpuinfo_x86 *c)
 
        set_cpu_cap(c, X86_FEATURE_REP_GOOD);
 
-       /* get apicid instead of initial apic id from cpuid */
-       c->topo.apicid = read_apic_id();
-
        /*
         * XXX someone from Hygon needs to confirm this DTRT
         *
@@ -316,8 +189,6 @@ static void init_hygon(struct cpuinfo_x86 *c)
 
        cpu_detect_cache_sizes(c);
 
-       hygon_detect_cmp(c);
-       hygon_get_topology(c);
        srat_detect_node(c);
 
        init_hygon_cacheinfo(c);
index a927a8fc962448035f041c8b17f45ffb6bb9e079..be30d7fa2e66bc0cf0e76d21c2767c127ce8ed82 100644 (file)
@@ -184,6 +184,90 @@ static bool bad_spectre_microcode(struct cpuinfo_x86 *c)
        return false;
 }
 
+#define MSR_IA32_TME_ACTIVATE          0x982
+
+/* Helpers to access TME_ACTIVATE MSR */
+#define TME_ACTIVATE_LOCKED(x)         (x & 0x1)
+#define TME_ACTIVATE_ENABLED(x)                (x & 0x2)
+
+#define TME_ACTIVATE_POLICY(x)         ((x >> 4) & 0xf)        /* Bits 7:4 */
+#define TME_ACTIVATE_POLICY_AES_XTS_128        0
+
+#define TME_ACTIVATE_KEYID_BITS(x)     ((x >> 32) & 0xf)       /* Bits 35:32 */
+
+#define TME_ACTIVATE_CRYPTO_ALGS(x)    ((x >> 48) & 0xffff)    /* Bits 63:48 */
+#define TME_ACTIVATE_CRYPTO_AES_XTS_128        1
+
+/* Values for mktme_status (SW only construct) */
+#define MKTME_ENABLED                  0
+#define MKTME_DISABLED                 1
+#define MKTME_UNINITIALIZED            2
+static int mktme_status = MKTME_UNINITIALIZED;
+
+static void detect_tme_early(struct cpuinfo_x86 *c)
+{
+       u64 tme_activate, tme_policy, tme_crypto_algs;
+       int keyid_bits = 0, nr_keyids = 0;
+       static u64 tme_activate_cpu0 = 0;
+
+       rdmsrl(MSR_IA32_TME_ACTIVATE, tme_activate);
+
+       if (mktme_status != MKTME_UNINITIALIZED) {
+               if (tme_activate != tme_activate_cpu0) {
+                       /* Broken BIOS? */
+                       pr_err_once("x86/tme: configuration is inconsistent between CPUs\n");
+                       pr_err_once("x86/tme: MKTME is not usable\n");
+                       mktme_status = MKTME_DISABLED;
+
+                       /* Proceed. We may need to exclude bits from x86_phys_bits. */
+               }
+       } else {
+               tme_activate_cpu0 = tme_activate;
+       }
+
+       if (!TME_ACTIVATE_LOCKED(tme_activate) || !TME_ACTIVATE_ENABLED(tme_activate)) {
+               pr_info_once("x86/tme: not enabled by BIOS\n");
+               mktme_status = MKTME_DISABLED;
+               return;
+       }
+
+       if (mktme_status != MKTME_UNINITIALIZED)
+               goto detect_keyid_bits;
+
+       pr_info("x86/tme: enabled by BIOS\n");
+
+       tme_policy = TME_ACTIVATE_POLICY(tme_activate);
+       if (tme_policy != TME_ACTIVATE_POLICY_AES_XTS_128)
+               pr_warn("x86/tme: Unknown policy is active: %#llx\n", tme_policy);
+
+       tme_crypto_algs = TME_ACTIVATE_CRYPTO_ALGS(tme_activate);
+       if (!(tme_crypto_algs & TME_ACTIVATE_CRYPTO_AES_XTS_128)) {
+               pr_err("x86/mktme: No known encryption algorithm is supported: %#llx\n",
+                               tme_crypto_algs);
+               mktme_status = MKTME_DISABLED;
+       }
+detect_keyid_bits:
+       keyid_bits = TME_ACTIVATE_KEYID_BITS(tme_activate);
+       nr_keyids = (1UL << keyid_bits) - 1;
+       if (nr_keyids) {
+               pr_info_once("x86/mktme: enabled by BIOS\n");
+               pr_info_once("x86/mktme: %d KeyIDs available\n", nr_keyids);
+       } else {
+               pr_info_once("x86/mktme: disabled by BIOS\n");
+       }
+
+       if (mktme_status == MKTME_UNINITIALIZED) {
+               /* MKTME is usable */
+               mktme_status = MKTME_ENABLED;
+       }
+
+       /*
+        * KeyID bits effectively lower the number of physical address
+        * bits.  Update cpuinfo_x86::x86_phys_bits accordingly.
+        */
+       c->x86_phys_bits -= keyid_bits;
+}
+
 static void early_init_intel(struct cpuinfo_x86 *c)
 {
        u64 misc_enable;
@@ -317,11 +401,11 @@ static void early_init_intel(struct cpuinfo_x86 *c)
        check_memory_type_self_snoop_errata(c);
 
        /*
-        * Get the number of SMT siblings early from the extended topology
-        * leaf, if available. Otherwise try the legacy SMT detection.
+        * Adjust the number of physical bits early because it affects the
+        * valid bits of the MTRR mask registers.
         */
-       if (detect_extended_topology_early(c) < 0)
-               detect_ht_early(c);
+       if (cpu_has(c, X86_FEATURE_TME))
+               detect_tme_early(c);
 }
 
 static void bsp_init_intel(struct cpuinfo_x86 *c)
@@ -482,90 +566,6 @@ static void srat_detect_node(struct cpuinfo_x86 *c)
 #endif
 }
 
-#define MSR_IA32_TME_ACTIVATE          0x982
-
-/* Helpers to access TME_ACTIVATE MSR */
-#define TME_ACTIVATE_LOCKED(x)         (x & 0x1)
-#define TME_ACTIVATE_ENABLED(x)                (x & 0x2)
-
-#define TME_ACTIVATE_POLICY(x)         ((x >> 4) & 0xf)        /* Bits 7:4 */
-#define TME_ACTIVATE_POLICY_AES_XTS_128        0
-
-#define TME_ACTIVATE_KEYID_BITS(x)     ((x >> 32) & 0xf)       /* Bits 35:32 */
-
-#define TME_ACTIVATE_CRYPTO_ALGS(x)    ((x >> 48) & 0xffff)    /* Bits 63:48 */
-#define TME_ACTIVATE_CRYPTO_AES_XTS_128        1
-
-/* Values for mktme_status (SW only construct) */
-#define MKTME_ENABLED                  0
-#define MKTME_DISABLED                 1
-#define MKTME_UNINITIALIZED            2
-static int mktme_status = MKTME_UNINITIALIZED;
-
-static void detect_tme(struct cpuinfo_x86 *c)
-{
-       u64 tme_activate, tme_policy, tme_crypto_algs;
-       int keyid_bits = 0, nr_keyids = 0;
-       static u64 tme_activate_cpu0 = 0;
-
-       rdmsrl(MSR_IA32_TME_ACTIVATE, tme_activate);
-
-       if (mktme_status != MKTME_UNINITIALIZED) {
-               if (tme_activate != tme_activate_cpu0) {
-                       /* Broken BIOS? */
-                       pr_err_once("x86/tme: configuration is inconsistent between CPUs\n");
-                       pr_err_once("x86/tme: MKTME is not usable\n");
-                       mktme_status = MKTME_DISABLED;
-
-                       /* Proceed. We may need to exclude bits from x86_phys_bits. */
-               }
-       } else {
-               tme_activate_cpu0 = tme_activate;
-       }
-
-       if (!TME_ACTIVATE_LOCKED(tme_activate) || !TME_ACTIVATE_ENABLED(tme_activate)) {
-               pr_info_once("x86/tme: not enabled by BIOS\n");
-               mktme_status = MKTME_DISABLED;
-               return;
-       }
-
-       if (mktme_status != MKTME_UNINITIALIZED)
-               goto detect_keyid_bits;
-
-       pr_info("x86/tme: enabled by BIOS\n");
-
-       tme_policy = TME_ACTIVATE_POLICY(tme_activate);
-       if (tme_policy != TME_ACTIVATE_POLICY_AES_XTS_128)
-               pr_warn("x86/tme: Unknown policy is active: %#llx\n", tme_policy);
-
-       tme_crypto_algs = TME_ACTIVATE_CRYPTO_ALGS(tme_activate);
-       if (!(tme_crypto_algs & TME_ACTIVATE_CRYPTO_AES_XTS_128)) {
-               pr_err("x86/mktme: No known encryption algorithm is supported: %#llx\n",
-                               tme_crypto_algs);
-               mktme_status = MKTME_DISABLED;
-       }
-detect_keyid_bits:
-       keyid_bits = TME_ACTIVATE_KEYID_BITS(tme_activate);
-       nr_keyids = (1UL << keyid_bits) - 1;
-       if (nr_keyids) {
-               pr_info_once("x86/mktme: enabled by BIOS\n");
-               pr_info_once("x86/mktme: %d KeyIDs available\n", nr_keyids);
-       } else {
-               pr_info_once("x86/mktme: disabled by BIOS\n");
-       }
-
-       if (mktme_status == MKTME_UNINITIALIZED) {
-               /* MKTME is usable */
-               mktme_status = MKTME_ENABLED;
-       }
-
-       /*
-        * KeyID bits effectively lower the number of physical address
-        * bits.  Update cpuinfo_x86::x86_phys_bits accordingly.
-        */
-       c->x86_phys_bits -= keyid_bits;
-}
-
 static void init_cpuid_fault(struct cpuinfo_x86 *c)
 {
        u64 msr;
@@ -603,24 +603,6 @@ static void init_intel(struct cpuinfo_x86 *c)
 
        intel_workarounds(c);
 
-       /*
-        * Detect the extended topology information if available. This
-        * will reinitialise the initial_apicid which will be used
-        * in init_intel_cacheinfo()
-        */
-       detect_extended_topology(c);
-
-       if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) {
-               /*
-                * let's use the legacy cpuid vector 0x1 and 0x4 for topology
-                * detection.
-                */
-               detect_num_cpu_cores(c);
-#ifdef CONFIG_X86_32
-               detect_ht(c);
-#endif
-       }
-
        init_intel_cacheinfo(c);
 
        if (c->cpuid_level > 9) {
@@ -702,9 +684,6 @@ static void init_intel(struct cpuinfo_x86 *c)
 
        init_ia32_feat_ctl(c);
 
-       if (cpu_has(c, X86_FEATURE_TME))
-               detect_tme(c);
-
        init_intel_misc_features(c);
 
        split_lock_init();
index 0771a905b2868085028747572c066c2d99df36a3..5be2b1790282671fc1934c700ea111a524759f86 100644 (file)
@@ -7,6 +7,8 @@
  * Author:
  *     Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
  */
+#include <linux/bug.h>
+#include <linux/limits.h>
 
 #include <asm/cpufeature.h>
 #include <asm/intel_pconfig.h>
index 2b46eb0fdf3acd1e044ebb85707652c0af85e54d..9a0133ef7e20ab60e36fa1d3f2e89382767f3f23 100644 (file)
@@ -1231,7 +1231,7 @@ static int threshold_create_bank(struct threshold_bank **bp, unsigned int cpu,
                return -ENODEV;
 
        if (is_shared_bank(bank)) {
-               nb = node_to_amd_nb(topology_die_id(cpu));
+               nb = node_to_amd_nb(topology_amd_node_id(cpu));
 
                /* threshold descriptor already initialized on this node? */
                if (nb && nb->bank4) {
@@ -1335,7 +1335,7 @@ static void threshold_remove_bank(struct threshold_bank *bank)
                 * The last CPU on this node using the shared bank is going
                 * away, remove that bank now.
                 */
-               nb = node_to_amd_nb(topology_die_id(smp_processor_id()));
+               nb = node_to_amd_nb(topology_amd_node_id(smp_processor_id()));
                nb->bank4 = NULL;
        }
 
index bc39252bc54f2ec8a834961639d180b3f84c13ac..b5cc557cfc3736708d96be6372f34c9ad0be85e4 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/hardirq.h>
 #include <linux/kexec.h>
 
+#include <asm/fred.h>
 #include <asm/intel-family.h>
 #include <asm/processor.h>
 #include <asm/traps.h>
@@ -2166,6 +2167,31 @@ DEFINE_IDTENTRY_MCE_USER(exc_machine_check)
        exc_machine_check_user(regs);
        local_db_restore(dr7);
 }
+
+#ifdef CONFIG_X86_FRED
+/*
+ * When occurred on different ring level, i.e., from user or kernel
+ * context, #MCE needs to be handled on different stack: User #MCE
+ * on current task stack, while kernel #MCE on a dedicated stack.
+ *
+ * This is exactly how FRED event delivery invokes an exception
+ * handler: ring 3 event on level 0 stack, i.e., current task stack;
+ * ring 0 event on the #MCE dedicated stack specified in the
+ * IA32_FRED_STKLVLS MSR. So unlike IDT, the FRED machine check entry
+ * stub doesn't do stack switch.
+ */
+DEFINE_FREDENTRY_MCE(exc_machine_check)
+{
+       unsigned long dr7;
+
+       dr7 = local_db_save();
+       if (user_mode(regs))
+               exc_machine_check_user(regs);
+       else
+               exc_machine_check_kernel(regs);
+       local_db_restore(dr7);
+}
+#endif
 #else
 /* 32bit unified entry point */
 DEFINE_IDTENTRY_RAW(exc_machine_check)
@@ -2431,7 +2457,7 @@ static void mce_enable_ce(void *all)
                __mcheck_cpu_init_timer();
 }
 
-static struct bus_type mce_subsys = {
+static const struct bus_type mce_subsys = {
        .name           = "machinecheck",
        .dev_name       = "machinecheck",
 };
index 72f0695c3dc1dd86055785e11b16bff16ea1c87a..94953d749475d025dd64efe5414a4cdbf83a63e4 100644 (file)
@@ -430,11 +430,9 @@ static void trigger_thr_int(void *info)
 
 static u32 get_nbc_for_node(int node_id)
 {
-       struct cpuinfo_x86 *c = &boot_cpu_data;
        u32 cores_per_node;
 
-       cores_per_node = (c->x86_max_cores * smp_num_siblings) / amd_get_nodes_per_socket();
-
+       cores_per_node = topology_num_threads_per_package() / topology_amd_nodes_per_pkg();
        return cores_per_node * node_id;
 }
 
@@ -543,8 +541,8 @@ static void do_inject(void)
        if (boot_cpu_has(X86_FEATURE_AMD_DCM) &&
            b == 4 &&
            boot_cpu_data.x86 < 0x17) {
-               toggle_nb_mca_mst_cpu(topology_die_id(cpu));
-               cpu = get_nbc_for_node(topology_die_id(cpu));
+               toggle_nb_mca_mst_cpu(topology_amd_node_id(cpu));
+               cpu = get_nbc_for_node(topology_amd_node_id(cpu));
        }
 
        cpus_read_lock();
index 857e608af641ad88f956a687a1c789f012c0c95b..5f0414452b67e298aa6c330c79a38dd4b05d7290 100644 (file)
@@ -641,7 +641,7 @@ static __init void calc_llc_size_per_core(struct cpuinfo_x86 *c)
 {
        u64 llc_size = c->x86_cache_size * 1024ULL;
 
-       do_div(llc_size, c->x86_max_cores);
+       do_div(llc_size, topology_num_cores_per_package());
        llc_size_per_core = (unsigned int)llc_size;
 }
 
index 01fa06dd06b66c9324c670e4847c0d503dbd5691..45e0e70e238cf31a0e51024d0f88505b6a6ce9c4 100644 (file)
@@ -539,19 +539,18 @@ static void __init ms_hyperv_init_platform(void)
         */
        x86_platform.apic_post_init = hyperv_init;
        hyperv_setup_mmu_ops();
-       /* Setup the IDT for hypervisor callback */
-       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, asm_sysvec_hyperv_callback);
 
-       /* Setup the IDT for reenlightenment notifications */
+       /* Install system interrupt handler for hypervisor callback */
+       sysvec_install(HYPERVISOR_CALLBACK_VECTOR, sysvec_hyperv_callback);
+
+       /* Install system interrupt handler for reenlightenment notifications */
        if (ms_hyperv.features & HV_ACCESS_REENLIGHTENMENT) {
-               alloc_intr_gate(HYPERV_REENLIGHTENMENT_VECTOR,
-                               asm_sysvec_hyperv_reenlightenment);
+               sysvec_install(HYPERV_REENLIGHTENMENT_VECTOR, sysvec_hyperv_reenlightenment);
        }
 
-       /* Setup the IDT for stimer0 */
+       /* Install system interrupt handler for stimer0 */
        if (ms_hyperv.misc_features & HV_STIMER_DIRECT_MODE_AVAILABLE) {
-               alloc_intr_gate(HYPERV_STIMER0_VECTOR,
-                               asm_sysvec_hyperv_stimer0);
+               sysvec_install(HYPERV_STIMER0_VECTOR, sysvec_hyperv_stimer0);
        }
 
 # ifdef CONFIG_SMP
index d3524778a54517557a22064c0d3b7d1bf97b3394..422a4ddc2ab7c9408f1d2d21433fea7f320c6f85 100644 (file)
@@ -108,6 +108,9 @@ static inline void k8_check_syscfg_dram_mod_en(void)
              (boot_cpu_data.x86 >= 0x0f)))
                return;
 
+       if (cpu_feature_enabled(X86_FEATURE_SEV_SNP))
+               return;
+
        rdmsr(MSR_AMD64_SYSCFG, lo, hi);
        if (lo & K8_MTRRFIXRANGE_DRAM_MODIFY) {
                pr_err(FW_WARN "MTRR: CPU %u: SYSCFG[MtrrFixDramModEn]"
index 26a427fa84eab5f90d12e26ebe2bf0e8f013b735..eeac00d20926e78e97543c269e9f78a91d64fc2e 100644 (file)
@@ -6,6 +6,7 @@
  * Authors: Fenghua Yu <fenghua.yu@intel.com>,
  *          H. Peter Anvin <hpa@linux.intel.com>
  */
+#include <linux/printk.h>
 
 #include <asm/processor.h>
 #include <asm/archrandom.h>
index 19e0681f04356d6b184014003e23cc5cec3980f6..83e40341583e6fa655e0531f0e8a8480d8567ba8 100644 (file)
@@ -16,6 +16,7 @@
 
 #define pr_fmt(fmt)    "resctrl: " fmt
 
+#include <linux/cpu.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/cacheinfo.h>
 #include <asm/resctrl.h>
 #include "internal.h"
 
-/* Mutex to protect rdtgroup access. */
-DEFINE_MUTEX(rdtgroup_mutex);
+/*
+ * rdt_domain structures are kfree()d when their last CPU goes offline,
+ * and allocated when the first CPU in a new domain comes online.
+ * The rdt_resource's domain list is updated when this happens. Readers of
+ * the domain list must either take cpus_read_lock(), or rely on an RCU
+ * read-side critical section, to avoid observing concurrent modification.
+ * All writers take this mutex:
+ */
+static DEFINE_MUTEX(domain_list_lock);
 
 /*
  * The cached resctrl_pqr_state is strictly per CPU and can never be
@@ -136,15 +144,15 @@ static inline void cache_alloc_hsw_probe(void)
 {
        struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_L3];
        struct rdt_resource *r  = &hw_res->r_resctrl;
-       u32 l, h, max_cbm = BIT_MASK(20) - 1;
+       u64 max_cbm = BIT_ULL_MASK(20) - 1, l3_cbm_0;
 
-       if (wrmsr_safe(MSR_IA32_L3_CBM_BASE, max_cbm, 0))
+       if (wrmsrl_safe(MSR_IA32_L3_CBM_BASE, max_cbm))
                return;
 
-       rdmsr(MSR_IA32_L3_CBM_BASE, l, h);
+       rdmsrl(MSR_IA32_L3_CBM_BASE, l3_cbm_0);
 
        /* If all the bits were set in MSR, return success */
-       if (l != max_cbm)
+       if (l3_cbm_0 != max_cbm)
                return;
 
        hw_res->num_closid = 4;
@@ -231,9 +239,7 @@ static bool __get_mem_config_intel(struct rdt_resource *r)
 static bool __rdt_get_mem_config_amd(struct rdt_resource *r)
 {
        struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
-       union cpuid_0x10_3_eax eax;
-       union cpuid_0x10_x_edx edx;
-       u32 ebx, ecx, subleaf;
+       u32 eax, ebx, ecx, edx, subleaf;
 
        /*
         * Query CPUID_Fn80000020_EDX_x01 for MBA and
@@ -241,9 +247,9 @@ static bool __rdt_get_mem_config_amd(struct rdt_resource *r)
         */
        subleaf = (r->rid == RDT_RESOURCE_SMBA) ? 2 :  1;
 
-       cpuid_count(0x80000020, subleaf, &eax.full, &ebx, &ecx, &edx.full);
-       hw_res->num_closid = edx.split.cos_max + 1;
-       r->default_ctrl = MAX_MBA_BW_AMD;
+       cpuid_count(0x80000020, subleaf, &eax, &ebx, &ecx, &edx);
+       hw_res->num_closid = edx + 1;
+       r->default_ctrl = 1 << eax;
 
        /* AMD does not use delay */
        r->membw.delay_linear = false;
@@ -512,6 +518,8 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
        struct rdt_domain *d;
        int err;
 
+       lockdep_assert_held(&domain_list_lock);
+
        d = rdt_find_domain(r, id, &add_pos);
        if (IS_ERR(d)) {
                pr_warn("Couldn't find cache id for CPU %d\n", cpu);
@@ -545,11 +553,12 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
                return;
        }
 
-       list_add_tail(&d->list, add_pos);
+       list_add_tail_rcu(&d->list, add_pos);
 
        err = resctrl_online_domain(r, d);
        if (err) {
-               list_del(&d->list);
+               list_del_rcu(&d->list);
+               synchronize_rcu();
                domain_free(hw_dom);
        }
 }
@@ -560,6 +569,8 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
        struct rdt_hw_domain *hw_dom;
        struct rdt_domain *d;
 
+       lockdep_assert_held(&domain_list_lock);
+
        d = rdt_find_domain(r, id, NULL);
        if (IS_ERR_OR_NULL(d)) {
                pr_warn("Couldn't find cache id for CPU %d\n", cpu);
@@ -570,7 +581,8 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
        cpumask_clear_cpu(cpu, &d->cpu_mask);
        if (cpumask_empty(&d->cpu_mask)) {
                resctrl_offline_domain(r, d);
-               list_del(&d->list);
+               list_del_rcu(&d->list);
+               synchronize_rcu();
 
                /*
                 * rdt_domain "d" is going to be freed below, so clear
@@ -582,73 +594,47 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
 
                return;
        }
-
-       if (r == &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl) {
-               if (is_mbm_enabled() && cpu == d->mbm_work_cpu) {
-                       cancel_delayed_work(&d->mbm_over);
-                       mbm_setup_overflow_handler(d, 0);
-               }
-               if (is_llc_occupancy_enabled() && cpu == d->cqm_work_cpu &&
-                   has_busy_rmid(r, d)) {
-                       cancel_delayed_work(&d->cqm_limbo);
-                       cqm_setup_limbo_handler(d, 0);
-               }
-       }
 }
 
 static void clear_closid_rmid(int cpu)
 {
        struct resctrl_pqr_state *state = this_cpu_ptr(&pqr_state);
 
-       state->default_closid = 0;
-       state->default_rmid = 0;
-       state->cur_closid = 0;
-       state->cur_rmid = 0;
-       wrmsr(MSR_IA32_PQR_ASSOC, 0, 0);
+       state->default_closid = RESCTRL_RESERVED_CLOSID;
+       state->default_rmid = RESCTRL_RESERVED_RMID;
+       state->cur_closid = RESCTRL_RESERVED_CLOSID;
+       state->cur_rmid = RESCTRL_RESERVED_RMID;
+       wrmsr(MSR_IA32_PQR_ASSOC, RESCTRL_RESERVED_RMID,
+             RESCTRL_RESERVED_CLOSID);
 }
 
-static int resctrl_online_cpu(unsigned int cpu)
+static int resctrl_arch_online_cpu(unsigned int cpu)
 {
        struct rdt_resource *r;
 
-       mutex_lock(&rdtgroup_mutex);
+       mutex_lock(&domain_list_lock);
        for_each_capable_rdt_resource(r)
                domain_add_cpu(cpu, r);
-       /* The cpu is set in default rdtgroup after online. */
-       cpumask_set_cpu(cpu, &rdtgroup_default.cpu_mask);
+       mutex_unlock(&domain_list_lock);
+
        clear_closid_rmid(cpu);
-       mutex_unlock(&rdtgroup_mutex);
+       resctrl_online_cpu(cpu);
 
        return 0;
 }
 
-static void clear_childcpus(struct rdtgroup *r, unsigned int cpu)
-{
-       struct rdtgroup *cr;
-
-       list_for_each_entry(cr, &r->mon.crdtgrp_list, mon.crdtgrp_list) {
-               if (cpumask_test_and_clear_cpu(cpu, &cr->cpu_mask)) {
-                       break;
-               }
-       }
-}
-
-static int resctrl_offline_cpu(unsigned int cpu)
+static int resctrl_arch_offline_cpu(unsigned int cpu)
 {
-       struct rdtgroup *rdtgrp;
        struct rdt_resource *r;
 
-       mutex_lock(&rdtgroup_mutex);
+       resctrl_offline_cpu(cpu);
+
+       mutex_lock(&domain_list_lock);
        for_each_capable_rdt_resource(r)
                domain_remove_cpu(cpu, r);
-       list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
-               if (cpumask_test_and_clear_cpu(cpu, &rdtgrp->cpu_mask)) {
-                       clear_childcpus(rdtgrp, cpu);
-                       break;
-               }
-       }
+       mutex_unlock(&domain_list_lock);
+
        clear_closid_rmid(cpu);
-       mutex_unlock(&rdtgroup_mutex);
 
        return 0;
 }
@@ -968,7 +954,8 @@ static int __init resctrl_late_init(void)
 
        state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
                                  "x86/resctrl/cat:online:",
-                                 resctrl_online_cpu, resctrl_offline_cpu);
+                                 resctrl_arch_online_cpu,
+                                 resctrl_arch_offline_cpu);
        if (state < 0)
                return state;
 
@@ -992,8 +979,14 @@ late_initcall(resctrl_late_init);
 
 static void __exit resctrl_exit(void)
 {
+       struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
+
        cpuhp_remove_state(rdt_online);
+
        rdtgroup_exit();
+
+       if (r->mon_capable)
+               rdt_put_mon_l3_config();
 }
 
 __exitcall(resctrl_exit);
index beccb0e87ba7416651ca839c29e822dfd5542e78..7997b47743a210d6d437976bb53d667d0df92f21 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/kernfs.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/tick.h>
+
 #include "internal.h"
 
 /*
@@ -210,6 +212,9 @@ static int parse_line(char *line, struct resctrl_schema *s,
        struct rdt_domain *d;
        unsigned long dom_id;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP &&
            (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA)) {
                rdt_last_cmd_puts("Cannot pseudo-lock MBA resource\n");
@@ -314,6 +319,9 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
        struct rdt_domain *d;
        u32 idx;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
                return -ENOMEM;
 
@@ -379,11 +387,9 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
                return -EINVAL;
        buf[nbytes - 1] = '\0';
 
-       cpus_read_lock();
        rdtgrp = rdtgroup_kn_lock_live(of->kn);
        if (!rdtgrp) {
                rdtgroup_kn_unlock(of->kn);
-               cpus_read_unlock();
                return -ENOENT;
        }
        rdt_last_cmd_clear();
@@ -445,7 +451,6 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
 out:
        rdt_staged_configs_clear();
        rdtgroup_kn_unlock(of->kn);
-       cpus_read_unlock();
        return ret ?: nbytes;
 }
 
@@ -465,6 +470,9 @@ static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int clo
        bool sep = false;
        u32 ctrl_val;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        seq_printf(s, "%*s:", max_name_width, schema->name);
        list_for_each_entry(dom, &r->domains, list) {
                if (sep)
@@ -522,12 +530,24 @@ int rdtgroup_schemata_show(struct kernfs_open_file *of,
        return ret;
 }
 
+static int smp_mon_event_count(void *arg)
+{
+       mon_event_count(arg);
+
+       return 0;
+}
+
 void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
                    struct rdt_domain *d, struct rdtgroup *rdtgrp,
                    int evtid, int first)
 {
+       int cpu;
+
+       /* When picking a CPU from cpu_mask, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        /*
-        * setup the parameters to send to the IPI to read the data.
+        * Setup the parameters to pass to mon_event_count() to read the data.
         */
        rr->rgrp = rdtgrp;
        rr->evtid = evtid;
@@ -535,8 +555,26 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
        rr->d = d;
        rr->val = 0;
        rr->first = first;
+       rr->arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, evtid);
+       if (IS_ERR(rr->arch_mon_ctx)) {
+               rr->err = -EINVAL;
+               return;
+       }
+
+       cpu = cpumask_any_housekeeping(&d->cpu_mask, RESCTRL_PICK_ANY_CPU);
+
+       /*
+        * cpumask_any_housekeeping() prefers housekeeping CPUs, but
+        * are all the CPUs nohz_full? If yes, pick a CPU to IPI.
+        * MPAM's resctrl_arch_rmid_read() is unable to read the
+        * counters on some platforms if its called in IRQ context.
+        */
+       if (tick_nohz_full_cpu(cpu))
+               smp_call_function_any(&d->cpu_mask, mon_event_count, rr, 1);
+       else
+               smp_call_on_cpu(cpu, smp_mon_event_count, rr, false);
 
-       smp_call_function_any(&d->cpu_mask, mon_event_count, rr, 1);
+       resctrl_arch_mon_ctx_free(r, evtid, rr->arch_mon_ctx);
 }
 
 int rdtgroup_mondata_show(struct seq_file *m, void *arg)
index a4f1aa15f0a2a8d38de404aa4cb539359f3bbe8c..c99f26ebe7a6537a7cd43274701ac4f489648081 100644 (file)
@@ -7,6 +7,9 @@
 #include <linux/kernfs.h>
 #include <linux/fs_context.h>
 #include <linux/jump_label.h>
+#include <linux/tick.h>
+
+#include <asm/resctrl.h>
 
 #define L3_QOS_CDP_ENABLE              0x01ULL
 
@@ -18,7 +21,6 @@
 #define MBM_OVERFLOW_INTERVAL          1000
 #define MAX_MBA_BW                     100u
 #define MBA_IS_LINEAR                  0x4
-#define MAX_MBA_BW_AMD                 0x800
 #define MBM_CNTR_WIDTH_OFFSET_AMD      20
 
 #define RMID_VAL_ERROR                 BIT_ULL(63)
 /* Max event bits supported */
 #define MAX_EVT_CONFIG_BITS            GENMASK(6, 0)
 
+/**
+ * cpumask_any_housekeeping() - Choose any CPU in @mask, preferring those that
+ *                             aren't marked nohz_full
+ * @mask:      The mask to pick a CPU from.
+ * @exclude_cpu:The CPU to avoid picking.
+ *
+ * Returns a CPU from @mask, but not @exclude_cpu. If there are housekeeping
+ * CPUs that don't use nohz_full, these are preferred. Pass
+ * RESCTRL_PICK_ANY_CPU to avoid excluding any CPUs.
+ *
+ * When a CPU is excluded, returns >= nr_cpu_ids if no CPUs are available.
+ */
+static inline unsigned int
+cpumask_any_housekeeping(const struct cpumask *mask, int exclude_cpu)
+{
+       unsigned int cpu, hk_cpu;
+
+       if (exclude_cpu == RESCTRL_PICK_ANY_CPU)
+               cpu = cpumask_any(mask);
+       else
+               cpu = cpumask_any_but(mask, exclude_cpu);
+
+       if (!IS_ENABLED(CONFIG_NO_HZ_FULL))
+               return cpu;
+
+       /* If the CPU picked isn't marked nohz_full nothing more needs doing. */
+       if (cpu < nr_cpu_ids && !tick_nohz_full_cpu(cpu))
+               return cpu;
+
+       /* Try to find a CPU that isn't nohz_full to use in preference */
+       hk_cpu = cpumask_nth_andnot(0, mask, tick_nohz_full_mask);
+       if (hk_cpu == exclude_cpu)
+               hk_cpu = cpumask_nth_andnot(1, mask, tick_nohz_full_mask);
+
+       if (hk_cpu < nr_cpu_ids)
+               cpu = hk_cpu;
+
+       return cpu;
+}
+
 struct rdt_fs_context {
        struct kernfs_fs_context        kfc;
        bool                            enable_cdpl2;
@@ -69,9 +111,6 @@ static inline struct rdt_fs_context *rdt_fc2context(struct fs_context *fc)
        return container_of(kfc, struct rdt_fs_context, kfc);
 }
 
-DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
-DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key);
-
 /**
  * struct mon_evt - Entry in the event list of a resource
  * @evtid:             event id
@@ -112,12 +151,12 @@ struct rmid_read {
        bool                    first;
        int                     err;
        u64                     val;
+       void                    *arch_mon_ctx;
 };
 
-extern bool rdt_alloc_capable;
-extern bool rdt_mon_capable;
 extern unsigned int rdt_mon_features;
 extern struct list_head resctrl_schema_all;
+extern bool resctrl_mounted;
 
 enum rdt_group_type {
        RDTCTRL_GROUP = 0,
@@ -296,14 +335,10 @@ struct rftype {
  * struct mbm_state - status for each MBM counter in each domain
  * @prev_bw_bytes: Previous bytes value read for bandwidth calculation
  * @prev_bw:   The most recent bandwidth in MBps
- * @delta_bw:  Difference between the current and previous bandwidth
- * @delta_comp:        Indicates whether to compute the delta_bw
  */
 struct mbm_state {
        u64     prev_bw_bytes;
        u32     prev_bw;
-       u32     delta_bw;
-       bool    delta_comp;
 };
 
 /**
@@ -395,6 +430,8 @@ struct rdt_parse_data {
  * @msr_update:                Function pointer to update QOS MSRs
  * @mon_scale:         cqm counter * mon_scale = occupancy in bytes
  * @mbm_width:         Monitor width, to detect and correct for overflow.
+ * @mbm_cfg_mask:      Bandwidth sources that can be tracked when Bandwidth
+ *                     Monitoring Event Configuration (BMEC) is supported.
  * @cdp_enabled:       CDP state of this resource
  *
  * Members of this structure are either private to the architecture
@@ -409,6 +446,7 @@ struct rdt_hw_resource {
                                 struct rdt_resource *r);
        unsigned int            mon_scale;
        unsigned int            mbm_width;
+       unsigned int            mbm_cfg_mask;
        bool                    cdp_enabled;
 };
 
@@ -426,8 +464,6 @@ extern struct mutex rdtgroup_mutex;
 
 extern struct rdt_hw_resource rdt_resources_all[];
 extern struct rdtgroup rdtgroup_default;
-DECLARE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
-
 extern struct dentry *debugfs_resctrl;
 
 enum resctrl_res_level {
@@ -543,9 +579,10 @@ void rdtgroup_pseudo_lock_remove(struct rdtgroup *rdtgrp);
 struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r);
 int closids_supported(void);
 void closid_free(int closid);
-int alloc_rmid(void);
-void free_rmid(u32 rmid);
+int alloc_rmid(u32 closid);
+void free_rmid(u32 closid, u32 rmid);
 int rdt_get_mon_l3_config(struct rdt_resource *r);
+void __exit rdt_put_mon_l3_config(void);
 bool __init rdt_cpu_has(int flag);
 void mon_event_count(void *info);
 int rdtgroup_mondata_show(struct seq_file *m, void *arg);
@@ -553,17 +590,21 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
                    struct rdt_domain *d, struct rdtgroup *rdtgrp,
                    int evtid, int first);
 void mbm_setup_overflow_handler(struct rdt_domain *dom,
-                               unsigned long delay_ms);
+                               unsigned long delay_ms,
+                               int exclude_cpu);
 void mbm_handle_overflow(struct work_struct *work);
 void __init intel_rdt_mbm_apply_quirk(void);
 bool is_mba_sc(struct rdt_resource *r);
-void cqm_setup_limbo_handler(struct rdt_domain *dom, unsigned long delay_ms);
+void cqm_setup_limbo_handler(struct rdt_domain *dom, unsigned long delay_ms,
+                            int exclude_cpu);
 void cqm_handle_limbo(struct work_struct *work);
-bool has_busy_rmid(struct rdt_resource *r, struct rdt_domain *d);
+bool has_busy_rmid(struct rdt_domain *d);
 void __check_limbo(struct rdt_domain *d, bool force_free);
 void rdt_domain_reconfigure_cdp(struct rdt_resource *r);
 void __init thread_throttle_mode_init(void);
 void __init mbm_config_rftype_init(const char *config);
 void rdt_staged_configs_clear(void);
+bool closid_allocated(unsigned int closid);
+int resctrl_find_cleanest_closid(void);
 
 #endif /* _ASM_X86_RESCTRL_INTERNAL_H */
index f136ac046851c87339386968e56301d70069e20c..c34a35ec0f031a188fc29424bdef31cd54fa597d 100644 (file)
@@ -15,6 +15,7 @@
  * Software Developer Manual June 2016, volume 3, section 17.17.
  */
 
+#include <linux/cpu.h>
 #include <linux/module.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
 
 #include "internal.h"
 
+/**
+ * struct rmid_entry - dirty tracking for all RMID.
+ * @closid:    The CLOSID for this entry.
+ * @rmid:      The RMID for this entry.
+ * @busy:      The number of domains with cached data using this RMID.
+ * @list:      Member of the rmid_free_lru list when busy == 0.
+ *
+ * Depending on the architecture the correct monitor is accessed using
+ * both @closid and @rmid, or @rmid only.
+ *
+ * Take the rdtgroup_mutex when accessing.
+ */
 struct rmid_entry {
+       u32                             closid;
        u32                             rmid;
        int                             busy;
        struct list_head                list;
@@ -37,6 +51,13 @@ struct rmid_entry {
  */
 static LIST_HEAD(rmid_free_lru);
 
+/*
+ * @closid_num_dirty_rmid    The number of dirty RMID each CLOSID has.
+ *     Only allocated when CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID is defined.
+ *     Indexed by CLOSID. Protected by rdtgroup_mutex.
+ */
+static u32 *closid_num_dirty_rmid;
+
 /*
  * @rmid_limbo_count - count of currently unused but (potentially)
  *     dirty RMIDs.
@@ -136,12 +157,29 @@ static inline u64 get_corrected_mbm_count(u32 rmid, unsigned long val)
        return val;
 }
 
-static inline struct rmid_entry *__rmid_entry(u32 rmid)
+/*
+ * x86 and arm64 differ in their handling of monitoring.
+ * x86's RMID are independent numbers, there is only one source of traffic
+ * with an RMID value of '1'.
+ * arm64's PMG extends the PARTID/CLOSID space, there are multiple sources of
+ * traffic with a PMG value of '1', one for each CLOSID, meaning the RMID
+ * value is no longer unique.
+ * To account for this, resctrl uses an index. On x86 this is just the RMID,
+ * on arm64 it encodes the CLOSID and RMID. This gives a unique number.
+ *
+ * The domain's rmid_busy_llc and rmid_ptrs[] are sized by index. The arch code
+ * must accept an attempt to read every index.
+ */
+static inline struct rmid_entry *__rmid_entry(u32 idx)
 {
        struct rmid_entry *entry;
+       u32 closid, rmid;
+
+       entry = &rmid_ptrs[idx];
+       resctrl_arch_rmid_idx_decode(idx, &closid, &rmid);
 
-       entry = &rmid_ptrs[rmid];
-       WARN_ON(entry->rmid != rmid);
+       WARN_ON_ONCE(entry->closid != closid);
+       WARN_ON_ONCE(entry->rmid != rmid);
 
        return entry;
 }
@@ -190,7 +228,8 @@ static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_domain *hw_dom,
 }
 
 void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d,
-                            u32 rmid, enum resctrl_event_id eventid)
+                            u32 unused, u32 rmid,
+                            enum resctrl_event_id eventid)
 {
        struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
        struct arch_mbm_state *am;
@@ -230,7 +269,8 @@ static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr, unsigned int width)
 }
 
 int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d,
-                          u32 rmid, enum resctrl_event_id eventid, u64 *val)
+                          u32 unused, u32 rmid, enum resctrl_event_id eventid,
+                          u64 *val, void *ignored)
 {
        struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
        struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
@@ -238,6 +278,8 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d,
        u64 msr_val, chunks;
        int ret;
 
+       resctrl_arch_rmid_read_context_check();
+
        if (!cpumask_test_cpu(smp_processor_id(), &d->cpu_mask))
                return -EINVAL;
 
@@ -260,6 +302,17 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d,
        return 0;
 }
 
+static void limbo_release_entry(struct rmid_entry *entry)
+{
+       lockdep_assert_held(&rdtgroup_mutex);
+
+       rmid_limbo_count--;
+       list_add_tail(&entry->list, &rmid_free_lru);
+
+       if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID))
+               closid_num_dirty_rmid[entry->closid]--;
+}
+
 /*
  * Check the RMIDs that are marked as busy for this domain. If the
  * reported LLC occupancy is below the threshold clear the busy bit and
@@ -269,11 +322,20 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d,
 void __check_limbo(struct rdt_domain *d, bool force_free)
 {
        struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
+       u32 idx_limit = resctrl_arch_system_num_rmid_idx();
        struct rmid_entry *entry;
-       u32 crmid = 1, nrmid;
+       u32 idx, cur_idx = 1;
+       void *arch_mon_ctx;
        bool rmid_dirty;
        u64 val = 0;
 
+       arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, QOS_L3_OCCUP_EVENT_ID);
+       if (IS_ERR(arch_mon_ctx)) {
+               pr_warn_ratelimited("Failed to allocate monitor context: %ld",
+                                   PTR_ERR(arch_mon_ctx));
+               return;
+       }
+
        /*
         * Skip RMID 0 and start from RMID 1 and check all the RMIDs that
         * are marked as busy for occupancy < threshold. If the occupancy
@@ -281,53 +343,125 @@ void __check_limbo(struct rdt_domain *d, bool force_free)
         * RMID and move it to the free list when the counter reaches 0.
         */
        for (;;) {
-               nrmid = find_next_bit(d->rmid_busy_llc, r->num_rmid, crmid);
-               if (nrmid >= r->num_rmid)
+               idx = find_next_bit(d->rmid_busy_llc, idx_limit, cur_idx);
+               if (idx >= idx_limit)
                        break;
 
-               entry = __rmid_entry(nrmid);
-
-               if (resctrl_arch_rmid_read(r, d, entry->rmid,
-                                          QOS_L3_OCCUP_EVENT_ID, &val)) {
+               entry = __rmid_entry(idx);
+               if (resctrl_arch_rmid_read(r, d, entry->closid, entry->rmid,
+                                          QOS_L3_OCCUP_EVENT_ID, &val,
+                                          arch_mon_ctx)) {
                        rmid_dirty = true;
                } else {
                        rmid_dirty = (val >= resctrl_rmid_realloc_threshold);
                }
 
                if (force_free || !rmid_dirty) {
-                       clear_bit(entry->rmid, d->rmid_busy_llc);
-                       if (!--entry->busy) {
-                               rmid_limbo_count--;
-                               list_add_tail(&entry->list, &rmid_free_lru);
-                       }
+                       clear_bit(idx, d->rmid_busy_llc);
+                       if (!--entry->busy)
+                               limbo_release_entry(entry);
                }
-               crmid = nrmid + 1;
+               cur_idx = idx + 1;
        }
+
+       resctrl_arch_mon_ctx_free(r, QOS_L3_OCCUP_EVENT_ID, arch_mon_ctx);
 }
 
-bool has_busy_rmid(struct rdt_resource *r, struct rdt_domain *d)
+bool has_busy_rmid(struct rdt_domain *d)
 {
-       return find_first_bit(d->rmid_busy_llc, r->num_rmid) != r->num_rmid;
+       u32 idx_limit = resctrl_arch_system_num_rmid_idx();
+
+       return find_first_bit(d->rmid_busy_llc, idx_limit) != idx_limit;
+}
+
+static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
+{
+       struct rmid_entry *itr;
+       u32 itr_idx, cmp_idx;
+
+       if (list_empty(&rmid_free_lru))
+               return rmid_limbo_count ? ERR_PTR(-EBUSY) : ERR_PTR(-ENOSPC);
+
+       list_for_each_entry(itr, &rmid_free_lru, list) {
+               /*
+                * Get the index of this free RMID, and the index it would need
+                * to be if it were used with this CLOSID.
+                * If the CLOSID is irrelevant on this architecture, the two
+                * index values are always the same on every entry and thus the
+                * very first entry will be returned.
+                */
+               itr_idx = resctrl_arch_rmid_idx_encode(itr->closid, itr->rmid);
+               cmp_idx = resctrl_arch_rmid_idx_encode(closid, itr->rmid);
+
+               if (itr_idx == cmp_idx)
+                       return itr;
+       }
+
+       return ERR_PTR(-ENOSPC);
+}
+
+/**
+ * resctrl_find_cleanest_closid() - Find a CLOSID where all the associated
+ *                                  RMID are clean, or the CLOSID that has
+ *                                  the most clean RMID.
+ *
+ * MPAM's equivalent of RMID are per-CLOSID, meaning a freshly allocated CLOSID
+ * may not be able to allocate clean RMID. To avoid this the allocator will
+ * choose the CLOSID with the most clean RMID.
+ *
+ * When the CLOSID and RMID are independent numbers, the first free CLOSID will
+ * be returned.
+ */
+int resctrl_find_cleanest_closid(void)
+{
+       u32 cleanest_closid = ~0;
+       int i = 0;
+
+       lockdep_assert_held(&rdtgroup_mutex);
+
+       if (!IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID))
+               return -EIO;
+
+       for (i = 0; i < closids_supported(); i++) {
+               int num_dirty;
+
+               if (closid_allocated(i))
+                       continue;
+
+               num_dirty = closid_num_dirty_rmid[i];
+               if (num_dirty == 0)
+                       return i;
+
+               if (cleanest_closid == ~0)
+                       cleanest_closid = i;
+
+               if (num_dirty < closid_num_dirty_rmid[cleanest_closid])
+                       cleanest_closid = i;
+       }
+
+       if (cleanest_closid == ~0)
+               return -ENOSPC;
+
+       return cleanest_closid;
 }
 
 /*
- * As of now the RMIDs allocation is global.
- * However we keep track of which packages the RMIDs
- * are used to optimize the limbo list management.
+ * For MPAM the RMID value is not unique, and has to be considered with
+ * the CLOSID. The (CLOSID, RMID) pair is allocated on all domains, which
+ * allows all domains to be managed by a single free list.
+ * Each domain also has a rmid_busy_llc to reduce the work of the limbo handler.
  */
-int alloc_rmid(void)
+int alloc_rmid(u32 closid)
 {
        struct rmid_entry *entry;
 
        lockdep_assert_held(&rdtgroup_mutex);
 
-       if (list_empty(&rmid_free_lru))
-               return rmid_limbo_count ? -EBUSY : -ENOSPC;
+       entry = resctrl_find_free_rmid(closid);
+       if (IS_ERR(entry))
+               return PTR_ERR(entry);
 
-       entry = list_first_entry(&rmid_free_lru,
-                                struct rmid_entry, list);
        list_del(&entry->list);
-
        return entry->rmid;
 }
 
@@ -335,47 +469,50 @@ static void add_rmid_to_limbo(struct rmid_entry *entry)
 {
        struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
        struct rdt_domain *d;
-       int cpu, err;
-       u64 val = 0;
+       u32 idx;
+
+       lockdep_assert_held(&rdtgroup_mutex);
+
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
+       idx = resctrl_arch_rmid_idx_encode(entry->closid, entry->rmid);
 
        entry->busy = 0;
-       cpu = get_cpu();
        list_for_each_entry(d, &r->domains, list) {
-               if (cpumask_test_cpu(cpu, &d->cpu_mask)) {
-                       err = resctrl_arch_rmid_read(r, d, entry->rmid,
-                                                    QOS_L3_OCCUP_EVENT_ID,
-                                                    &val);
-                       if (err || val <= resctrl_rmid_realloc_threshold)
-                               continue;
-               }
-
                /*
                 * For the first limbo RMID in the domain,
                 * setup up the limbo worker.
                 */
-               if (!has_busy_rmid(r, d))
-                       cqm_setup_limbo_handler(d, CQM_LIMBOCHECK_INTERVAL);
-               set_bit(entry->rmid, d->rmid_busy_llc);
+               if (!has_busy_rmid(d))
+                       cqm_setup_limbo_handler(d, CQM_LIMBOCHECK_INTERVAL,
+                                               RESCTRL_PICK_ANY_CPU);
+               set_bit(idx, d->rmid_busy_llc);
                entry->busy++;
        }
-       put_cpu();
 
-       if (entry->busy)
-               rmid_limbo_count++;
-       else
-               list_add_tail(&entry->list, &rmid_free_lru);
+       rmid_limbo_count++;
+       if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID))
+               closid_num_dirty_rmid[entry->closid]++;
 }
 
-void free_rmid(u32 rmid)
+void free_rmid(u32 closid, u32 rmid)
 {
+       u32 idx = resctrl_arch_rmid_idx_encode(closid, rmid);
        struct rmid_entry *entry;
 
-       if (!rmid)
-               return;
-
        lockdep_assert_held(&rdtgroup_mutex);
 
-       entry = __rmid_entry(rmid);
+       /*
+        * Do not allow the default rmid to be free'd. Comparing by index
+        * allows architectures that ignore the closid parameter to avoid an
+        * unnecessary check.
+        */
+       if (idx == resctrl_arch_rmid_idx_encode(RESCTRL_RESERVED_CLOSID,
+                                               RESCTRL_RESERVED_RMID))
+               return;
+
+       entry = __rmid_entry(idx);
 
        if (is_llc_occupancy_enabled())
                add_rmid_to_limbo(entry);
@@ -383,33 +520,36 @@ void free_rmid(u32 rmid)
                list_add_tail(&entry->list, &rmid_free_lru);
 }
 
-static struct mbm_state *get_mbm_state(struct rdt_domain *d, u32 rmid,
-                                      enum resctrl_event_id evtid)
+static struct mbm_state *get_mbm_state(struct rdt_domain *d, u32 closid,
+                                      u32 rmid, enum resctrl_event_id evtid)
 {
+       u32 idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+
        switch (evtid) {
        case QOS_L3_MBM_TOTAL_EVENT_ID:
-               return &d->mbm_total[rmid];
+               return &d->mbm_total[idx];
        case QOS_L3_MBM_LOCAL_EVENT_ID:
-               return &d->mbm_local[rmid];
+               return &d->mbm_local[idx];
        default:
                return NULL;
        }
 }
 
-static int __mon_event_count(u32 rmid, struct rmid_read *rr)
+static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr)
 {
        struct mbm_state *m;
        u64 tval = 0;
 
        if (rr->first) {
-               resctrl_arch_reset_rmid(rr->r, rr->d, rmid, rr->evtid);
-               m = get_mbm_state(rr->d, rmid, rr->evtid);
+               resctrl_arch_reset_rmid(rr->r, rr->d, closid, rmid, rr->evtid);
+               m = get_mbm_state(rr->d, closid, rmid, rr->evtid);
                if (m)
                        memset(m, 0, sizeof(struct mbm_state));
                return 0;
        }
 
-       rr->err = resctrl_arch_rmid_read(rr->r, rr->d, rmid, rr->evtid, &tval);
+       rr->err = resctrl_arch_rmid_read(rr->r, rr->d, closid, rmid, rr->evtid,
+                                        &tval, rr->arch_mon_ctx);
        if (rr->err)
                return rr->err;
 
@@ -421,6 +561,7 @@ static int __mon_event_count(u32 rmid, struct rmid_read *rr)
 /*
  * mbm_bw_count() - Update bw count from values previously read by
  *                 __mon_event_count().
+ * @closid:    The closid used to identify the cached mbm_state.
  * @rmid:      The rmid used to identify the cached mbm_state.
  * @rr:                The struct rmid_read populated by __mon_event_count().
  *
@@ -429,9 +570,10 @@ static int __mon_event_count(u32 rmid, struct rmid_read *rr)
  * __mon_event_count() is compared with the chunks value from the previous
  * invocation. This must be called once per second to maintain values in MBps.
  */
-static void mbm_bw_count(u32 rmid, struct rmid_read *rr)
+static void mbm_bw_count(u32 closid, u32 rmid, struct rmid_read *rr)
 {
-       struct mbm_state *m = &rr->d->mbm_local[rmid];
+       u32 idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+       struct mbm_state *m = &rr->d->mbm_local[idx];
        u64 cur_bw, bytes, cur_bytes;
 
        cur_bytes = rr->val;
@@ -440,14 +582,11 @@ static void mbm_bw_count(u32 rmid, struct rmid_read *rr)
 
        cur_bw = bytes / SZ_1M;
 
-       if (m->delta_comp)
-               m->delta_bw = abs(cur_bw - m->prev_bw);
-       m->delta_comp = false;
        m->prev_bw = cur_bw;
 }
 
 /*
- * This is called via IPI to read the CQM/MBM counters
+ * This is scheduled by mon_event_read() to read the CQM/MBM counters
  * on a domain.
  */
 void mon_event_count(void *info)
@@ -459,7 +598,7 @@ void mon_event_count(void *info)
 
        rdtgrp = rr->rgrp;
 
-       ret = __mon_event_count(rdtgrp->mon.rmid, rr);
+       ret = __mon_event_count(rdtgrp->closid, rdtgrp->mon.rmid, rr);
 
        /*
         * For Ctrl groups read data from child monitor groups and
@@ -470,7 +609,8 @@ void mon_event_count(void *info)
 
        if (rdtgrp->type == RDTCTRL_GROUP) {
                list_for_each_entry(entry, head, mon.crdtgrp_list) {
-                       if (__mon_event_count(entry->mon.rmid, rr) == 0)
+                       if (__mon_event_count(entry->closid, entry->mon.rmid,
+                                             rr) == 0)
                                ret = 0;
                }
        }
@@ -520,9 +660,9 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm)
 {
        u32 closid, rmid, cur_msr_val, new_msr_val;
        struct mbm_state *pmbm_data, *cmbm_data;
-       u32 cur_bw, delta_bw, user_bw;
        struct rdt_resource *r_mba;
        struct rdt_domain *dom_mba;
+       u32 cur_bw, user_bw, idx;
        struct list_head *head;
        struct rdtgroup *entry;
 
@@ -533,7 +673,8 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm)
 
        closid = rgrp->closid;
        rmid = rgrp->mon.rmid;
-       pmbm_data = &dom_mbm->mbm_local[rmid];
+       idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+       pmbm_data = &dom_mbm->mbm_local[idx];
 
        dom_mba = get_domain_from_cpu(smp_processor_id(), r_mba);
        if (!dom_mba) {
@@ -543,7 +684,6 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm)
 
        cur_bw = pmbm_data->prev_bw;
        user_bw = dom_mba->mbps_val[closid];
-       delta_bw = pmbm_data->delta_bw;
 
        /* MBA resource doesn't support CDP */
        cur_msr_val = resctrl_arch_get_config(r_mba, dom_mba, closid, CDP_NONE);
@@ -555,52 +695,35 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm)
        list_for_each_entry(entry, head, mon.crdtgrp_list) {
                cmbm_data = &dom_mbm->mbm_local[entry->mon.rmid];
                cur_bw += cmbm_data->prev_bw;
-               delta_bw += cmbm_data->delta_bw;
        }
 
        /*
         * Scale up/down the bandwidth linearly for the ctrl group.  The
         * bandwidth step is the bandwidth granularity specified by the
         * hardware.
-        *
-        * The delta_bw is used when increasing the bandwidth so that we
-        * dont alternately increase and decrease the control values
-        * continuously.
-        *
-        * For ex: consider cur_bw = 90MBps, user_bw = 100MBps and if
-        * bandwidth step is 20MBps(> user_bw - cur_bw), we would keep
-        * switching between 90 and 110 continuously if we only check
-        * cur_bw < user_bw.
+        * Always increase throttling if current bandwidth is above the
+        * target set by user.
+        * But avoid thrashing up and down on every poll by checking
+        * whether a decrease in throttling is likely to push the group
+        * back over target. E.g. if currently throttling to 30% of bandwidth
+        * on a system with 10% granularity steps, check whether moving to
+        * 40% would go past the limit by multiplying current bandwidth by
+        * "(30 + 10) / 30".
         */
        if (cur_msr_val > r_mba->membw.min_bw && user_bw < cur_bw) {
                new_msr_val = cur_msr_val - r_mba->membw.bw_gran;
        } else if (cur_msr_val < MAX_MBA_BW &&
-                  (user_bw > (cur_bw + delta_bw))) {
+                  (user_bw > (cur_bw * (cur_msr_val + r_mba->membw.min_bw) / cur_msr_val))) {
                new_msr_val = cur_msr_val + r_mba->membw.bw_gran;
        } else {
                return;
        }
 
        resctrl_arch_update_one(r_mba, dom_mba, closid, CDP_NONE, new_msr_val);
-
-       /*
-        * Delta values are updated dynamically package wise for each
-        * rdtgrp every time the throttle MSR changes value.
-        *
-        * This is because (1)the increase in bandwidth is not perfectly
-        * linear and only "approximately" linear even when the hardware
-        * says it is linear.(2)Also since MBA is a core specific
-        * mechanism, the delta values vary based on number of cores used
-        * by the rdtgrp.
-        */
-       pmbm_data->delta_comp = true;
-       list_for_each_entry(entry, head, mon.crdtgrp_list) {
-               cmbm_data = &dom_mbm->mbm_local[entry->mon.rmid];
-               cmbm_data->delta_comp = true;
-       }
 }
 
-static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, int rmid)
+static void mbm_update(struct rdt_resource *r, struct rdt_domain *d,
+                      u32 closid, u32 rmid)
 {
        struct rmid_read rr;
 
@@ -615,12 +738,28 @@ static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, int rmid)
        if (is_mbm_total_enabled()) {
                rr.evtid = QOS_L3_MBM_TOTAL_EVENT_ID;
                rr.val = 0;
-               __mon_event_count(rmid, &rr);
+               rr.arch_mon_ctx = resctrl_arch_mon_ctx_alloc(rr.r, rr.evtid);
+               if (IS_ERR(rr.arch_mon_ctx)) {
+                       pr_warn_ratelimited("Failed to allocate monitor context: %ld",
+                                           PTR_ERR(rr.arch_mon_ctx));
+                       return;
+               }
+
+               __mon_event_count(closid, rmid, &rr);
+
+               resctrl_arch_mon_ctx_free(rr.r, rr.evtid, rr.arch_mon_ctx);
        }
        if (is_mbm_local_enabled()) {
                rr.evtid = QOS_L3_MBM_LOCAL_EVENT_ID;
                rr.val = 0;
-               __mon_event_count(rmid, &rr);
+               rr.arch_mon_ctx = resctrl_arch_mon_ctx_alloc(rr.r, rr.evtid);
+               if (IS_ERR(rr.arch_mon_ctx)) {
+                       pr_warn_ratelimited("Failed to allocate monitor context: %ld",
+                                           PTR_ERR(rr.arch_mon_ctx));
+                       return;
+               }
+
+               __mon_event_count(closid, rmid, &rr);
 
                /*
                 * Call the MBA software controller only for the
@@ -628,7 +767,9 @@ static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, int rmid)
                 * the software controller explicitly.
                 */
                if (is_mba_sc(NULL))
-                       mbm_bw_count(rmid, &rr);
+                       mbm_bw_count(closid, rmid, &rr);
+
+               resctrl_arch_mon_ctx_free(rr.r, rr.evtid, rr.arch_mon_ctx);
        }
 }
 
@@ -639,106 +780,193 @@ static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, int rmid)
 void cqm_handle_limbo(struct work_struct *work)
 {
        unsigned long delay = msecs_to_jiffies(CQM_LIMBOCHECK_INTERVAL);
-       int cpu = smp_processor_id();
-       struct rdt_resource *r;
        struct rdt_domain *d;
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
 
-       r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
        d = container_of(work, struct rdt_domain, cqm_limbo.work);
 
        __check_limbo(d, false);
 
-       if (has_busy_rmid(r, d))
-               schedule_delayed_work_on(cpu, &d->cqm_limbo, delay);
+       if (has_busy_rmid(d)) {
+               d->cqm_work_cpu = cpumask_any_housekeeping(&d->cpu_mask,
+                                                          RESCTRL_PICK_ANY_CPU);
+               schedule_delayed_work_on(d->cqm_work_cpu, &d->cqm_limbo,
+                                        delay);
+       }
 
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
 }
 
-void cqm_setup_limbo_handler(struct rdt_domain *dom, unsigned long delay_ms)
+/**
+ * cqm_setup_limbo_handler() - Schedule the limbo handler to run for this
+ *                             domain.
+ * @dom:           The domain the limbo handler should run for.
+ * @delay_ms:      How far in the future the handler should run.
+ * @exclude_cpu:   Which CPU the handler should not run on,
+ *                RESCTRL_PICK_ANY_CPU to pick any CPU.
+ */
+void cqm_setup_limbo_handler(struct rdt_domain *dom, unsigned long delay_ms,
+                            int exclude_cpu)
 {
        unsigned long delay = msecs_to_jiffies(delay_ms);
        int cpu;
 
-       cpu = cpumask_any(&dom->cpu_mask);
+       cpu = cpumask_any_housekeeping(&dom->cpu_mask, exclude_cpu);
        dom->cqm_work_cpu = cpu;
 
-       schedule_delayed_work_on(cpu, &dom->cqm_limbo, delay);
+       if (cpu < nr_cpu_ids)
+               schedule_delayed_work_on(cpu, &dom->cqm_limbo, delay);
 }
 
 void mbm_handle_overflow(struct work_struct *work)
 {
        unsigned long delay = msecs_to_jiffies(MBM_OVERFLOW_INTERVAL);
        struct rdtgroup *prgrp, *crgrp;
-       int cpu = smp_processor_id();
        struct list_head *head;
        struct rdt_resource *r;
        struct rdt_domain *d;
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
 
-       if (!static_branch_likely(&rdt_mon_enable_key))
+       /*
+        * If the filesystem has been unmounted this work no longer needs to
+        * run.
+        */
+       if (!resctrl_mounted || !resctrl_arch_mon_capable())
                goto out_unlock;
 
        r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
        d = container_of(work, struct rdt_domain, mbm_over.work);
 
        list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) {
-               mbm_update(r, d, prgrp->mon.rmid);
+               mbm_update(r, d, prgrp->closid, prgrp->mon.rmid);
 
                head = &prgrp->mon.crdtgrp_list;
                list_for_each_entry(crgrp, head, mon.crdtgrp_list)
-                       mbm_update(r, d, crgrp->mon.rmid);
+                       mbm_update(r, d, crgrp->closid, crgrp->mon.rmid);
 
                if (is_mba_sc(NULL))
                        update_mba_bw(prgrp, d);
        }
 
-       schedule_delayed_work_on(cpu, &d->mbm_over, delay);
+       /*
+        * Re-check for housekeeping CPUs. This allows the overflow handler to
+        * move off a nohz_full CPU quickly.
+        */
+       d->mbm_work_cpu = cpumask_any_housekeeping(&d->cpu_mask,
+                                                  RESCTRL_PICK_ANY_CPU);
+       schedule_delayed_work_on(d->mbm_work_cpu, &d->mbm_over, delay);
 
 out_unlock:
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
 }
 
-void mbm_setup_overflow_handler(struct rdt_domain *dom, unsigned long delay_ms)
+/**
+ * mbm_setup_overflow_handler() - Schedule the overflow handler to run for this
+ *                                domain.
+ * @dom:           The domain the overflow handler should run for.
+ * @delay_ms:      How far in the future the handler should run.
+ * @exclude_cpu:   Which CPU the handler should not run on,
+ *                RESCTRL_PICK_ANY_CPU to pick any CPU.
+ */
+void mbm_setup_overflow_handler(struct rdt_domain *dom, unsigned long delay_ms,
+                               int exclude_cpu)
 {
        unsigned long delay = msecs_to_jiffies(delay_ms);
        int cpu;
 
-       if (!static_branch_likely(&rdt_mon_enable_key))
+       /*
+        * When a domain comes online there is no guarantee the filesystem is
+        * mounted. If not, there is no need to catch counter overflow.
+        */
+       if (!resctrl_mounted || !resctrl_arch_mon_capable())
                return;
-       cpu = cpumask_any(&dom->cpu_mask);
+       cpu = cpumask_any_housekeeping(&dom->cpu_mask, exclude_cpu);
        dom->mbm_work_cpu = cpu;
-       schedule_delayed_work_on(cpu, &dom->mbm_over, delay);
+
+       if (cpu < nr_cpu_ids)
+               schedule_delayed_work_on(cpu, &dom->mbm_over, delay);
 }
 
 static int dom_data_init(struct rdt_resource *r)
 {
+       u32 idx_limit = resctrl_arch_system_num_rmid_idx();
+       u32 num_closid = resctrl_arch_get_num_closid(r);
        struct rmid_entry *entry = NULL;
-       int i, nr_rmids;
+       int err = 0, i;
+       u32 idx;
+
+       mutex_lock(&rdtgroup_mutex);
+       if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID)) {
+               u32 *tmp;
+
+               /*
+                * If the architecture hasn't provided a sanitised value here,
+                * this may result in larger arrays than necessary. Resctrl will
+                * use a smaller system wide value based on the resources in
+                * use.
+                */
+               tmp = kcalloc(num_closid, sizeof(*tmp), GFP_KERNEL);
+               if (!tmp) {
+                       err = -ENOMEM;
+                       goto out_unlock;
+               }
 
-       nr_rmids = r->num_rmid;
-       rmid_ptrs = kcalloc(nr_rmids, sizeof(struct rmid_entry), GFP_KERNEL);
-       if (!rmid_ptrs)
-               return -ENOMEM;
+               closid_num_dirty_rmid = tmp;
+       }
+
+       rmid_ptrs = kcalloc(idx_limit, sizeof(struct rmid_entry), GFP_KERNEL);
+       if (!rmid_ptrs) {
+               if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID)) {
+                       kfree(closid_num_dirty_rmid);
+                       closid_num_dirty_rmid = NULL;
+               }
+               err = -ENOMEM;
+               goto out_unlock;
+       }
 
-       for (i = 0; i < nr_rmids; i++) {
+       for (i = 0; i < idx_limit; i++) {
                entry = &rmid_ptrs[i];
                INIT_LIST_HEAD(&entry->list);
 
-               entry->rmid = i;
+               resctrl_arch_rmid_idx_decode(i, &entry->closid, &entry->rmid);
                list_add_tail(&entry->list, &rmid_free_lru);
        }
 
        /*
-        * RMID 0 is special and is always allocated. It's used for all
-        * tasks that are not monitored.
+        * RESCTRL_RESERVED_CLOSID and RESCTRL_RESERVED_RMID are special and
+        * are always allocated. These are used for the rdtgroup_default
+        * control group, which will be setup later in rdtgroup_init().
         */
-       entry = __rmid_entry(0);
+       idx = resctrl_arch_rmid_idx_encode(RESCTRL_RESERVED_CLOSID,
+                                          RESCTRL_RESERVED_RMID);
+       entry = __rmid_entry(idx);
        list_del(&entry->list);
 
-       return 0;
+out_unlock:
+       mutex_unlock(&rdtgroup_mutex);
+
+       return err;
+}
+
+static void __exit dom_data_exit(void)
+{
+       mutex_lock(&rdtgroup_mutex);
+
+       if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID)) {
+               kfree(closid_num_dirty_rmid);
+               closid_num_dirty_rmid = NULL;
+       }
+
+       kfree(rmid_ptrs);
+       rmid_ptrs = NULL;
+
+       mutex_unlock(&rdtgroup_mutex);
 }
 
 static struct mon_evt llc_occupancy_event = {
@@ -813,6 +1041,12 @@ int __init rdt_get_mon_l3_config(struct rdt_resource *r)
                return ret;
 
        if (rdt_cpu_has(X86_FEATURE_BMEC)) {
+               u32 eax, ebx, ecx, edx;
+
+               /* Detect list of bandwidth sources that can be tracked */
+               cpuid_count(0x80000020, 3, &eax, &ebx, &ecx, &edx);
+               hw_res->mbm_cfg_mask = ecx & MAX_EVT_CONFIG_BITS;
+
                if (rdt_cpu_has(X86_FEATURE_CQM_MBM_TOTAL)) {
                        mbm_total_event.configurable = true;
                        mbm_config_rftype_init("mbm_total_bytes_config");
@@ -830,6 +1064,11 @@ int __init rdt_get_mon_l3_config(struct rdt_resource *r)
        return 0;
 }
 
+void __exit rdt_put_mon_l3_config(void)
+{
+       dom_data_exit();
+}
+
 void __init intel_rdt_mbm_apply_quirk(void)
 {
        int cf_index;
index 8f559eeae08ed5845c291cd4142d748a3e2cca5c..884b88e2514130a89762a9cb93203e558e47425b 100644 (file)
@@ -581,7 +581,7 @@ static int rdtgroup_locksetup_user_restrict(struct rdtgroup *rdtgrp)
        if (ret)
                goto err_cpus;
 
-       if (rdt_mon_capable) {
+       if (resctrl_arch_mon_capable()) {
                ret = rdtgroup_kn_mode_restrict(rdtgrp, "mon_groups");
                if (ret)
                        goto err_cpus_list;
@@ -628,7 +628,7 @@ static int rdtgroup_locksetup_user_restore(struct rdtgroup *rdtgrp)
        if (ret)
                goto err_cpus;
 
-       if (rdt_mon_capable) {
+       if (resctrl_arch_mon_capable()) {
                ret = rdtgroup_kn_mode_restore(rdtgrp, "mon_groups", 0777);
                if (ret)
                        goto err_cpus_list;
@@ -752,7 +752,7 @@ int rdtgroup_locksetup_enter(struct rdtgroup *rdtgrp)
         * anymore when this group would be used for pseudo-locking. This
         * is safe to call on platforms not capable of monitoring.
         */
-       free_rmid(rdtgrp->mon.rmid);
+       free_rmid(rdtgrp->closid, rdtgrp->mon.rmid);
 
        ret = 0;
        goto out;
@@ -776,8 +776,8 @@ int rdtgroup_locksetup_exit(struct rdtgroup *rdtgrp)
 {
        int ret;
 
-       if (rdt_mon_capable) {
-               ret = alloc_rmid();
+       if (resctrl_arch_mon_capable()) {
+               ret = alloc_rmid(rdtgrp->closid);
                if (ret < 0) {
                        rdt_last_cmd_puts("Out of RMIDs\n");
                        return ret;
@@ -787,7 +787,7 @@ int rdtgroup_locksetup_exit(struct rdtgroup *rdtgrp)
 
        ret = rdtgroup_locksetup_user_restore(rdtgrp);
        if (ret) {
-               free_rmid(rdtgrp->mon.rmid);
+               free_rmid(rdtgrp->closid, rdtgrp->mon.rmid);
                return ret;
        }
 
@@ -844,6 +844,9 @@ bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_domain *d)
        struct rdt_domain *d_i;
        bool ret = false;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        if (!zalloc_cpumask_var(&cpu_with_psl, GFP_KERNEL))
                return true;
 
index 69a1de92384ab26a4b7eef9063e857121a7f4f1d..011e17efb1a66e5b003fee07b53c13633f9f0f58 100644 (file)
 DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
 DEFINE_STATIC_KEY_FALSE(rdt_mon_enable_key);
 DEFINE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
+
+/* Mutex to protect rdtgroup access. */
+DEFINE_MUTEX(rdtgroup_mutex);
+
 static struct kernfs_root *rdt_root;
 struct rdtgroup rdtgroup_default;
 LIST_HEAD(rdt_all_groups);
@@ -42,6 +46,9 @@ LIST_HEAD(rdt_all_groups);
 /* list of entries for the schemata file */
 LIST_HEAD(resctrl_schema_all);
 
+/* The filesystem can only be mounted once. */
+bool resctrl_mounted;
+
 /* Kernel fs node for "info" directory under root */
 static struct kernfs_node *kn_info;
 
@@ -102,7 +109,7 @@ void rdt_staged_configs_clear(void)
  *
  * Using a global CLOSID across all resources has some advantages and
  * some drawbacks:
- * + We can simply set "current->closid" to assign a task to a resource
+ * + We can simply set current's closid to assign a task to a resource
  *   group.
  * + Context switch code can avoid extra memory references deciding which
  *   CLOSID to load into the PQR_ASSOC MSR
@@ -111,7 +118,7 @@ void rdt_staged_configs_clear(void)
  * - Our choices on how to configure each resource become progressively more
  *   limited as the number of resources grows.
  */
-static int closid_free_map;
+static unsigned long closid_free_map;
 static int closid_free_map_len;
 
 int closids_supported(void)
@@ -130,26 +137,39 @@ static void closid_init(void)
 
        closid_free_map = BIT_MASK(rdt_min_closid) - 1;
 
-       /* CLOSID 0 is always reserved for the default group */
-       closid_free_map &= ~1;
+       /* RESCTRL_RESERVED_CLOSID is always reserved for the default group */
+       __clear_bit(RESCTRL_RESERVED_CLOSID, &closid_free_map);
        closid_free_map_len = rdt_min_closid;
 }
 
 static int closid_alloc(void)
 {
-       u32 closid = ffs(closid_free_map);
+       int cleanest_closid;
+       u32 closid;
 
-       if (closid == 0)
-               return -ENOSPC;
-       closid--;
-       closid_free_map &= ~(1 << closid);
+       lockdep_assert_held(&rdtgroup_mutex);
+
+       if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID)) {
+               cleanest_closid = resctrl_find_cleanest_closid();
+               if (cleanest_closid < 0)
+                       return cleanest_closid;
+               closid = cleanest_closid;
+       } else {
+               closid = ffs(closid_free_map);
+               if (closid == 0)
+                       return -ENOSPC;
+               closid--;
+       }
+       __clear_bit(closid, &closid_free_map);
 
        return closid;
 }
 
 void closid_free(int closid)
 {
-       closid_free_map |= 1 << closid;
+       lockdep_assert_held(&rdtgroup_mutex);
+
+       __set_bit(closid, &closid_free_map);
 }
 
 /**
@@ -159,9 +179,11 @@ void closid_free(int closid)
  * Return: true if @closid is currently associated with a resource group,
  * false if @closid is free
  */
-static bool closid_allocated(unsigned int closid)
+bool closid_allocated(unsigned int closid)
 {
-       return (closid_free_map & (1 << closid)) == 0;
+       lockdep_assert_held(&rdtgroup_mutex);
+
+       return !test_bit(closid, &closid_free_map);
 }
 
 /**
@@ -559,14 +581,26 @@ static void update_task_closid_rmid(struct task_struct *t)
                _update_task_closid_rmid(t);
 }
 
+static bool task_in_rdtgroup(struct task_struct *tsk, struct rdtgroup *rdtgrp)
+{
+       u32 closid, rmid = rdtgrp->mon.rmid;
+
+       if (rdtgrp->type == RDTCTRL_GROUP)
+               closid = rdtgrp->closid;
+       else if (rdtgrp->type == RDTMON_GROUP)
+               closid = rdtgrp->mon.parent->closid;
+       else
+               return false;
+
+       return resctrl_arch_match_closid(tsk, closid) &&
+              resctrl_arch_match_rmid(tsk, closid, rmid);
+}
+
 static int __rdtgroup_move_task(struct task_struct *tsk,
                                struct rdtgroup *rdtgrp)
 {
        /* If the task is already in rdtgrp, no need to move the task. */
-       if ((rdtgrp->type == RDTCTRL_GROUP && tsk->closid == rdtgrp->closid &&
-            tsk->rmid == rdtgrp->mon.rmid) ||
-           (rdtgrp->type == RDTMON_GROUP && tsk->rmid == rdtgrp->mon.rmid &&
-            tsk->closid == rdtgrp->mon.parent->closid))
+       if (task_in_rdtgroup(tsk, rdtgrp))
                return 0;
 
        /*
@@ -577,19 +611,19 @@ static int __rdtgroup_move_task(struct task_struct *tsk,
         * For monitor groups, can move the tasks only from
         * their parent CTRL group.
         */
-
-       if (rdtgrp->type == RDTCTRL_GROUP) {
-               WRITE_ONCE(tsk->closid, rdtgrp->closid);
-               WRITE_ONCE(tsk->rmid, rdtgrp->mon.rmid);
-       } else if (rdtgrp->type == RDTMON_GROUP) {
-               if (rdtgrp->mon.parent->closid == tsk->closid) {
-                       WRITE_ONCE(tsk->rmid, rdtgrp->mon.rmid);
-               } else {
-                       rdt_last_cmd_puts("Can't move task to different control group\n");
-                       return -EINVAL;
-               }
+       if (rdtgrp->type == RDTMON_GROUP &&
+           !resctrl_arch_match_closid(tsk, rdtgrp->mon.parent->closid)) {
+               rdt_last_cmd_puts("Can't move task to different control group\n");
+               return -EINVAL;
        }
 
+       if (rdtgrp->type == RDTMON_GROUP)
+               resctrl_arch_set_closid_rmid(tsk, rdtgrp->mon.parent->closid,
+                                            rdtgrp->mon.rmid);
+       else
+               resctrl_arch_set_closid_rmid(tsk, rdtgrp->closid,
+                                            rdtgrp->mon.rmid);
+
        /*
         * Ensure the task's closid and rmid are written before determining if
         * the task is current that will decide if it will be interrupted.
@@ -611,14 +645,15 @@ static int __rdtgroup_move_task(struct task_struct *tsk,
 
 static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
 {
-       return (rdt_alloc_capable &&
-              (r->type == RDTCTRL_GROUP) && (t->closid == r->closid));
+       return (resctrl_arch_alloc_capable() && (r->type == RDTCTRL_GROUP) &&
+               resctrl_arch_match_closid(t, r->closid));
 }
 
 static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
 {
-       return (rdt_mon_capable &&
-              (r->type == RDTMON_GROUP) && (t->rmid == r->mon.rmid));
+       return (resctrl_arch_mon_capable() && (r->type == RDTMON_GROUP) &&
+               resctrl_arch_match_rmid(t, r->mon.parent->closid,
+                                       r->mon.rmid));
 }
 
 /**
@@ -853,7 +888,7 @@ int proc_resctrl_show(struct seq_file *s, struct pid_namespace *ns,
        mutex_lock(&rdtgroup_mutex);
 
        /* Return empty if resctrl has not been mounted. */
-       if (!static_branch_unlikely(&rdt_enable_key)) {
+       if (!resctrl_mounted) {
                seq_puts(s, "res:\nmon:\n");
                goto unlock;
        }
@@ -869,7 +904,7 @@ int proc_resctrl_show(struct seq_file *s, struct pid_namespace *ns,
                    rdtg->mode != RDT_MODE_EXCLUSIVE)
                        continue;
 
-               if (rdtg->closid != tsk->closid)
+               if (!resctrl_arch_match_closid(tsk, rdtg->closid))
                        continue;
 
                seq_printf(s, "res:%s%s\n", (rdtg == &rdtgroup_default) ? "/" : "",
@@ -877,7 +912,8 @@ int proc_resctrl_show(struct seq_file *s, struct pid_namespace *ns,
                seq_puts(s, "mon:");
                list_for_each_entry(crg, &rdtg->mon.crdtgrp_list,
                                    mon.crdtgrp_list) {
-                       if (tsk->rmid != crg->mon.rmid)
+                       if (!resctrl_arch_match_rmid(tsk, crg->mon.parent->closid,
+                                                    crg->mon.rmid))
                                continue;
                        seq_printf(s, "%s", crg->kn->name);
                        break;
@@ -982,6 +1018,7 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
        bool sep = false;
        u32 ctrl_val;
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
        hw_shareable = r->cache.shareable_bits;
        list_for_each_entry(dom, &r->domains, list) {
@@ -1042,6 +1079,7 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of,
        }
        seq_putc(seq, '\n');
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
        return 0;
 }
 
@@ -1297,6 +1335,9 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp)
        struct rdt_domain *d;
        u32 ctrl;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        list_for_each_entry(s, &resctrl_schema_all, list) {
                r = s->res;
                if (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA)
@@ -1561,6 +1602,7 @@ static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid
        struct rdt_domain *dom;
        bool sep = false;
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
 
        list_for_each_entry(dom, &r->domains, list) {
@@ -1577,6 +1619,7 @@ static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid
        seq_puts(s, "\n");
 
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
 
        return 0;
 }
@@ -1614,17 +1657,10 @@ static void mon_event_config_write(void *info)
        wrmsr(MSR_IA32_EVT_CFG_BASE + index, mon_info->mon_config, 0);
 }
 
-static int mbm_config_write_domain(struct rdt_resource *r,
-                                  struct rdt_domain *d, u32 evtid, u32 val)
+static void mbm_config_write_domain(struct rdt_resource *r,
+                                   struct rdt_domain *d, u32 evtid, u32 val)
 {
        struct mon_config_info mon_info = {0};
-       int ret = 0;
-
-       /* mon_config cannot be more than the supported set of events */
-       if (val > MAX_EVT_CONFIG_BITS) {
-               rdt_last_cmd_puts("Invalid event configuration\n");
-               return -EINVAL;
-       }
 
        /*
         * Read the current config value first. If both are the same then
@@ -1633,7 +1669,7 @@ static int mbm_config_write_domain(struct rdt_resource *r,
        mon_info.evtid = evtid;
        mondata_config_read(d, &mon_info);
        if (mon_info.mon_config == val)
-               goto out;
+               return;
 
        mon_info.mon_config = val;
 
@@ -1656,17 +1692,17 @@ static int mbm_config_write_domain(struct rdt_resource *r,
         * mbm_local and mbm_total counts for all the RMIDs.
         */
        resctrl_arch_reset_rmid_all(r, d);
-
-out:
-       return ret;
 }
 
 static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid)
 {
+       struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
        char *dom_str = NULL, *id_str;
        unsigned long dom_id, val;
        struct rdt_domain *d;
-       int ret = 0;
+
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
 
 next:
        if (!tok || tok[0] == '\0')
@@ -1686,11 +1722,16 @@ next:
                return -EINVAL;
        }
 
+       /* Value from user cannot be more than the supported set of events */
+       if ((val & hw_res->mbm_cfg_mask) != val) {
+               rdt_last_cmd_printf("Invalid event configuration: max valid mask is 0x%02x\n",
+                                   hw_res->mbm_cfg_mask);
+               return -EINVAL;
+       }
+
        list_for_each_entry(d, &r->domains, list) {
                if (d->id == dom_id) {
-                       ret = mbm_config_write_domain(r, d, evtid, val);
-                       if (ret)
-                               return -EINVAL;
+                       mbm_config_write_domain(r, d, evtid, val);
                        goto next;
                }
        }
@@ -1709,6 +1750,7 @@ static ssize_t mbm_total_bytes_config_write(struct kernfs_open_file *of,
        if (nbytes == 0 || buf[nbytes - 1] != '\n')
                return -EINVAL;
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
 
        rdt_last_cmd_clear();
@@ -1718,6 +1760,7 @@ static ssize_t mbm_total_bytes_config_write(struct kernfs_open_file *of,
        ret = mon_config_write(r, buf, QOS_L3_MBM_TOTAL_EVENT_ID);
 
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
 
        return ret ?: nbytes;
 }
@@ -1733,6 +1776,7 @@ static ssize_t mbm_local_bytes_config_write(struct kernfs_open_file *of,
        if (nbytes == 0 || buf[nbytes - 1] != '\n')
                return -EINVAL;
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
 
        rdt_last_cmd_clear();
@@ -1742,6 +1786,7 @@ static ssize_t mbm_local_bytes_config_write(struct kernfs_open_file *of,
        ret = mon_config_write(r, buf, QOS_L3_MBM_LOCAL_EVENT_ID);
 
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
 
        return ret ?: nbytes;
 }
@@ -2218,6 +2263,9 @@ static int set_cache_qos_cfg(int level, bool enable)
        struct rdt_domain *d;
        int cpu;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        if (level == RDT_RESOURCE_L3)
                update = l3_qos_cfg_update;
        else if (level == RDT_RESOURCE_L2)
@@ -2417,6 +2465,7 @@ struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn)
 
        rdtgroup_kn_get(rdtgrp, kn);
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
 
        /* Was this group deleted while we waited? */
@@ -2434,6 +2483,8 @@ void rdtgroup_kn_unlock(struct kernfs_node *kn)
                return;
 
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
+
        rdtgroup_kn_put(rdtgrp, kn);
 }
 
@@ -2584,7 +2635,7 @@ static int rdt_get_tree(struct fs_context *fc)
        /*
         * resctrl file system can only be mounted once.
         */
-       if (static_branch_unlikely(&rdt_enable_key)) {
+       if (resctrl_mounted) {
                ret = -EBUSY;
                goto out;
        }
@@ -2605,7 +2656,7 @@ static int rdt_get_tree(struct fs_context *fc)
 
        closid_init();
 
-       if (rdt_mon_capable)
+       if (resctrl_arch_mon_capable())
                flags |= RFTYPE_MON;
 
        ret = rdtgroup_add_files(rdtgroup_default.kn, flags);
@@ -2618,7 +2669,7 @@ static int rdt_get_tree(struct fs_context *fc)
        if (ret < 0)
                goto out_schemata_free;
 
-       if (rdt_mon_capable) {
+       if (resctrl_arch_mon_capable()) {
                ret = mongroup_create_dir(rdtgroup_default.kn,
                                          &rdtgroup_default, "mon_groups",
                                          &kn_mongrp);
@@ -2640,18 +2691,19 @@ static int rdt_get_tree(struct fs_context *fc)
        if (ret < 0)
                goto out_psl;
 
-       if (rdt_alloc_capable)
-               static_branch_enable_cpuslocked(&rdt_alloc_enable_key);
-       if (rdt_mon_capable)
-               static_branch_enable_cpuslocked(&rdt_mon_enable_key);
+       if (resctrl_arch_alloc_capable())
+               resctrl_arch_enable_alloc();
+       if (resctrl_arch_mon_capable())
+               resctrl_arch_enable_mon();
 
-       if (rdt_alloc_capable || rdt_mon_capable)
-               static_branch_enable_cpuslocked(&rdt_enable_key);
+       if (resctrl_arch_alloc_capable() || resctrl_arch_mon_capable())
+               resctrl_mounted = true;
 
        if (is_mbm_enabled()) {
                r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
                list_for_each_entry(dom, &r->domains, list)
-                       mbm_setup_overflow_handler(dom, MBM_OVERFLOW_INTERVAL);
+                       mbm_setup_overflow_handler(dom, MBM_OVERFLOW_INTERVAL,
+                                                  RESCTRL_PICK_ANY_CPU);
        }
 
        goto out;
@@ -2659,10 +2711,10 @@ static int rdt_get_tree(struct fs_context *fc)
 out_psl:
        rdt_pseudo_lock_release();
 out_mondata:
-       if (rdt_mon_capable)
+       if (resctrl_arch_mon_capable())
                kernfs_remove(kn_mondata);
 out_mongrp:
-       if (rdt_mon_capable)
+       if (resctrl_arch_mon_capable())
                kernfs_remove(kn_mongrp);
 out_info:
        kernfs_remove(kn_info);
@@ -2765,6 +2817,9 @@ static int reset_all_ctrls(struct rdt_resource *r)
        struct rdt_domain *d;
        int i;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
                return -ENOMEM;
 
@@ -2810,8 +2865,8 @@ static void rdt_move_group_tasks(struct rdtgroup *from, struct rdtgroup *to,
        for_each_process_thread(p, t) {
                if (!from || is_closid_match(t, from) ||
                    is_rmid_match(t, from)) {
-                       WRITE_ONCE(t->closid, to->closid);
-                       WRITE_ONCE(t->rmid, to->mon.rmid);
+                       resctrl_arch_set_closid_rmid(t, to->closid,
+                                                    to->mon.rmid);
 
                        /*
                         * Order the closid/rmid stores above before the loads
@@ -2842,7 +2897,7 @@ static void free_all_child_rdtgrp(struct rdtgroup *rdtgrp)
 
        head = &rdtgrp->mon.crdtgrp_list;
        list_for_each_entry_safe(sentry, stmp, head, mon.crdtgrp_list) {
-               free_rmid(sentry->mon.rmid);
+               free_rmid(sentry->closid, sentry->mon.rmid);
                list_del(&sentry->mon.crdtgrp_list);
 
                if (atomic_read(&sentry->waitcount) != 0)
@@ -2882,7 +2937,7 @@ static void rmdir_all_sub(void)
                cpumask_or(&rdtgroup_default.cpu_mask,
                           &rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);
 
-               free_rmid(rdtgrp->mon.rmid);
+               free_rmid(rdtgrp->closid, rdtgrp->mon.rmid);
 
                kernfs_remove(rdtgrp->kn);
                list_del(&rdtgrp->rdtgroup_list);
@@ -2917,9 +2972,11 @@ static void rdt_kill_sb(struct super_block *sb)
        rdtgroup_default.mode = RDT_MODE_SHAREABLE;
        schemata_list_destroy();
        rdtgroup_destroy_root();
-       static_branch_disable_cpuslocked(&rdt_alloc_enable_key);
-       static_branch_disable_cpuslocked(&rdt_mon_enable_key);
-       static_branch_disable_cpuslocked(&rdt_enable_key);
+       if (resctrl_arch_alloc_capable())
+               resctrl_arch_disable_alloc();
+       if (resctrl_arch_mon_capable())
+               resctrl_arch_disable_mon();
+       resctrl_mounted = false;
        kernfs_kill_sb(sb);
        mutex_unlock(&rdtgroup_mutex);
        cpus_read_unlock();
@@ -3047,6 +3104,9 @@ static int mkdir_mondata_subdir_alldom(struct kernfs_node *parent_kn,
        struct rdt_domain *dom;
        int ret;
 
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
+
        list_for_each_entry(dom, &r->domains, list) {
                ret = mkdir_mondata_subdir(parent_kn, dom, r, prgrp);
                if (ret)
@@ -3293,6 +3353,36 @@ out:
        return ret;
 }
 
+static int mkdir_rdt_prepare_rmid_alloc(struct rdtgroup *rdtgrp)
+{
+       int ret;
+
+       if (!resctrl_arch_mon_capable())
+               return 0;
+
+       ret = alloc_rmid(rdtgrp->closid);
+       if (ret < 0) {
+               rdt_last_cmd_puts("Out of RMIDs\n");
+               return ret;
+       }
+       rdtgrp->mon.rmid = ret;
+
+       ret = mkdir_mondata_all(rdtgrp->kn, rdtgrp, &rdtgrp->mon.mon_data_kn);
+       if (ret) {
+               rdt_last_cmd_puts("kernfs subdir error\n");
+               free_rmid(rdtgrp->closid, rdtgrp->mon.rmid);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void mkdir_rdt_prepare_rmid_free(struct rdtgroup *rgrp)
+{
+       if (resctrl_arch_mon_capable())
+               free_rmid(rgrp->closid, rgrp->mon.rmid);
+}
+
 static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
                             const char *name, umode_t mode,
                             enum rdt_group_type rtype, struct rdtgroup **r)
@@ -3353,7 +3443,7 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
 
        if (rtype == RDTCTRL_GROUP) {
                files = RFTYPE_BASE | RFTYPE_CTRL;
-               if (rdt_mon_capable)
+               if (resctrl_arch_mon_capable())
                        files |= RFTYPE_MON;
        } else {
                files = RFTYPE_BASE | RFTYPE_MON;
@@ -3365,29 +3455,11 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
                goto out_destroy;
        }
 
-       if (rdt_mon_capable) {
-               ret = alloc_rmid();
-               if (ret < 0) {
-                       rdt_last_cmd_puts("Out of RMIDs\n");
-                       goto out_destroy;
-               }
-               rdtgrp->mon.rmid = ret;
-
-               ret = mkdir_mondata_all(kn, rdtgrp, &rdtgrp->mon.mon_data_kn);
-               if (ret) {
-                       rdt_last_cmd_puts("kernfs subdir error\n");
-                       goto out_idfree;
-               }
-       }
-       kernfs_activate(kn);
-
        /*
         * The caller unlocks the parent_kn upon success.
         */
        return 0;
 
-out_idfree:
-       free_rmid(rdtgrp->mon.rmid);
 out_destroy:
        kernfs_put(rdtgrp->kn);
        kernfs_remove(rdtgrp->kn);
@@ -3401,7 +3473,6 @@ out_unlock:
 static void mkdir_rdt_prepare_clean(struct rdtgroup *rgrp)
 {
        kernfs_remove(rgrp->kn);
-       free_rmid(rgrp->mon.rmid);
        rdtgroup_remove(rgrp);
 }
 
@@ -3423,12 +3494,21 @@ static int rdtgroup_mkdir_mon(struct kernfs_node *parent_kn,
        prgrp = rdtgrp->mon.parent;
        rdtgrp->closid = prgrp->closid;
 
+       ret = mkdir_rdt_prepare_rmid_alloc(rdtgrp);
+       if (ret) {
+               mkdir_rdt_prepare_clean(rdtgrp);
+               goto out_unlock;
+       }
+
+       kernfs_activate(rdtgrp->kn);
+
        /*
         * Add the rdtgrp to the list of rdtgrps the parent
         * ctrl_mon group has to track.
         */
        list_add_tail(&rdtgrp->mon.crdtgrp_list, &prgrp->mon.crdtgrp_list);
 
+out_unlock:
        rdtgroup_kn_unlock(parent_kn);
        return ret;
 }
@@ -3459,13 +3539,20 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
        ret = 0;
 
        rdtgrp->closid = closid;
+
+       ret = mkdir_rdt_prepare_rmid_alloc(rdtgrp);
+       if (ret)
+               goto out_closid_free;
+
+       kernfs_activate(rdtgrp->kn);
+
        ret = rdtgroup_init_alloc(rdtgrp);
        if (ret < 0)
-               goto out_id_free;
+               goto out_rmid_free;
 
        list_add(&rdtgrp->rdtgroup_list, &rdt_all_groups);
 
-       if (rdt_mon_capable) {
+       if (resctrl_arch_mon_capable()) {
                /*
                 * Create an empty mon_groups directory to hold the subset
                 * of tasks and cpus to monitor.
@@ -3481,7 +3568,9 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
 
 out_del_list:
        list_del(&rdtgrp->rdtgroup_list);
-out_id_free:
+out_rmid_free:
+       mkdir_rdt_prepare_rmid_free(rdtgrp);
+out_closid_free:
        closid_free(closid);
 out_common_fail:
        mkdir_rdt_prepare_clean(rdtgrp);
@@ -3518,14 +3607,14 @@ static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
         * allocation is supported, add a control and monitoring
         * subdirectory
         */
-       if (rdt_alloc_capable && parent_kn == rdtgroup_default.kn)
+       if (resctrl_arch_alloc_capable() && parent_kn == rdtgroup_default.kn)
                return rdtgroup_mkdir_ctrl_mon(parent_kn, name, mode);
 
        /*
         * If RDT monitoring is supported and the parent directory is a valid
         * "mon_groups" directory, add a monitoring subdirectory.
         */
-       if (rdt_mon_capable && is_mon_groups(parent_kn, name))
+       if (resctrl_arch_mon_capable() && is_mon_groups(parent_kn, name))
                return rdtgroup_mkdir_mon(parent_kn, name, mode);
 
        return -EPERM;
@@ -3550,7 +3639,7 @@ static int rdtgroup_rmdir_mon(struct rdtgroup *rdtgrp, cpumask_var_t tmpmask)
        update_closid_rmid(tmpmask, NULL);
 
        rdtgrp->flags = RDT_DELETED;
-       free_rmid(rdtgrp->mon.rmid);
+       free_rmid(rdtgrp->closid, rdtgrp->mon.rmid);
 
        /*
         * Remove the rdtgrp from the parent ctrl_mon group's list
@@ -3596,8 +3685,8 @@ static int rdtgroup_rmdir_ctrl(struct rdtgroup *rdtgrp, cpumask_var_t tmpmask)
        cpumask_or(tmpmask, tmpmask, &rdtgrp->cpu_mask);
        update_closid_rmid(tmpmask, NULL);
 
+       free_rmid(rdtgrp->closid, rdtgrp->mon.rmid);
        closid_free(rdtgrp->closid);
-       free_rmid(rdtgrp->mon.rmid);
 
        rdtgroup_ctrl_remove(rdtgrp);
 
@@ -3829,8 +3918,8 @@ static void __init rdtgroup_setup_default(void)
 {
        mutex_lock(&rdtgroup_mutex);
 
-       rdtgroup_default.closid = 0;
-       rdtgroup_default.mon.rmid = 0;
+       rdtgroup_default.closid = RESCTRL_RESERVED_CLOSID;
+       rdtgroup_default.mon.rmid = RESCTRL_RESERVED_RMID;
        rdtgroup_default.type = RDTCTRL_GROUP;
        INIT_LIST_HEAD(&rdtgroup_default.mon.crdtgrp_list);
 
@@ -3848,24 +3937,24 @@ static void domain_destroy_mon_state(struct rdt_domain *d)
 
 void resctrl_offline_domain(struct rdt_resource *r, struct rdt_domain *d)
 {
-       lockdep_assert_held(&rdtgroup_mutex);
+       mutex_lock(&rdtgroup_mutex);
 
        if (supports_mba_mbps() && r->rid == RDT_RESOURCE_MBA)
                mba_sc_domain_destroy(r, d);
 
        if (!r->mon_capable)
-               return;
+               goto out_unlock;
 
        /*
         * If resctrl is mounted, remove all the
         * per domain monitor data directories.
         */
-       if (static_branch_unlikely(&rdt_mon_enable_key))
+       if (resctrl_mounted && resctrl_arch_mon_capable())
                rmdir_mondata_subdir_allrdtgrp(r, d->id);
 
        if (is_mbm_enabled())
                cancel_delayed_work(&d->mbm_over);
-       if (is_llc_occupancy_enabled() && has_busy_rmid(r, d)) {
+       if (is_llc_occupancy_enabled() && has_busy_rmid(d)) {
                /*
                 * When a package is going down, forcefully
                 * decrement rmid->ebusy. There is no way to know
@@ -3879,20 +3968,24 @@ void resctrl_offline_domain(struct rdt_resource *r, struct rdt_domain *d)
        }
 
        domain_destroy_mon_state(d);
+
+out_unlock:
+       mutex_unlock(&rdtgroup_mutex);
 }
 
 static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_domain *d)
 {
+       u32 idx_limit = resctrl_arch_system_num_rmid_idx();
        size_t tsize;
 
        if (is_llc_occupancy_enabled()) {
-               d->rmid_busy_llc = bitmap_zalloc(r->num_rmid, GFP_KERNEL);
+               d->rmid_busy_llc = bitmap_zalloc(idx_limit, GFP_KERNEL);
                if (!d->rmid_busy_llc)
                        return -ENOMEM;
        }
        if (is_mbm_total_enabled()) {
                tsize = sizeof(*d->mbm_total);
-               d->mbm_total = kcalloc(r->num_rmid, tsize, GFP_KERNEL);
+               d->mbm_total = kcalloc(idx_limit, tsize, GFP_KERNEL);
                if (!d->mbm_total) {
                        bitmap_free(d->rmid_busy_llc);
                        return -ENOMEM;
@@ -3900,7 +3993,7 @@ static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_domain *d)
        }
        if (is_mbm_local_enabled()) {
                tsize = sizeof(*d->mbm_local);
-               d->mbm_local = kcalloc(r->num_rmid, tsize, GFP_KERNEL);
+               d->mbm_local = kcalloc(idx_limit, tsize, GFP_KERNEL);
                if (!d->mbm_local) {
                        bitmap_free(d->rmid_busy_llc);
                        kfree(d->mbm_total);
@@ -3913,34 +4006,97 @@ static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_domain *d)
 
 int resctrl_online_domain(struct rdt_resource *r, struct rdt_domain *d)
 {
-       int err;
+       int err = 0;
 
-       lockdep_assert_held(&rdtgroup_mutex);
+       mutex_lock(&rdtgroup_mutex);
 
-       if (supports_mba_mbps() && r->rid == RDT_RESOURCE_MBA)
+       if (supports_mba_mbps() && r->rid == RDT_RESOURCE_MBA) {
                /* RDT_RESOURCE_MBA is never mon_capable */
-               return mba_sc_domain_allocate(r, d);
+               err = mba_sc_domain_allocate(r, d);
+               goto out_unlock;
+       }
 
        if (!r->mon_capable)
-               return 0;
+               goto out_unlock;
 
        err = domain_setup_mon_state(r, d);
        if (err)
-               return err;
+               goto out_unlock;
 
        if (is_mbm_enabled()) {
                INIT_DELAYED_WORK(&d->mbm_over, mbm_handle_overflow);
-               mbm_setup_overflow_handler(d, MBM_OVERFLOW_INTERVAL);
+               mbm_setup_overflow_handler(d, MBM_OVERFLOW_INTERVAL,
+                                          RESCTRL_PICK_ANY_CPU);
        }
 
        if (is_llc_occupancy_enabled())
                INIT_DELAYED_WORK(&d->cqm_limbo, cqm_handle_limbo);
 
-       /* If resctrl is mounted, add per domain monitor data directories. */
-       if (static_branch_unlikely(&rdt_mon_enable_key))
+       /*
+        * If the filesystem is not mounted then only the default resource group
+        * exists. Creation of its directories is deferred until mount time
+        * by rdt_get_tree() calling mkdir_mondata_all().
+        * If resctrl is mounted, add per domain monitor data directories.
+        */
+       if (resctrl_mounted && resctrl_arch_mon_capable())
                mkdir_mondata_subdir_allrdtgrp(r, d);
 
-       return 0;
+out_unlock:
+       mutex_unlock(&rdtgroup_mutex);
+
+       return err;
+}
+
+void resctrl_online_cpu(unsigned int cpu)
+{
+       mutex_lock(&rdtgroup_mutex);
+       /* The CPU is set in default rdtgroup after online. */
+       cpumask_set_cpu(cpu, &rdtgroup_default.cpu_mask);
+       mutex_unlock(&rdtgroup_mutex);
+}
+
+static void clear_childcpus(struct rdtgroup *r, unsigned int cpu)
+{
+       struct rdtgroup *cr;
+
+       list_for_each_entry(cr, &r->mon.crdtgrp_list, mon.crdtgrp_list) {
+               if (cpumask_test_and_clear_cpu(cpu, &cr->cpu_mask))
+                       break;
+       }
+}
+
+void resctrl_offline_cpu(unsigned int cpu)
+{
+       struct rdt_resource *l3 = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
+       struct rdtgroup *rdtgrp;
+       struct rdt_domain *d;
+
+       mutex_lock(&rdtgroup_mutex);
+       list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
+               if (cpumask_test_and_clear_cpu(cpu, &rdtgrp->cpu_mask)) {
+                       clear_childcpus(rdtgrp, cpu);
+                       break;
+               }
+       }
+
+       if (!l3->mon_capable)
+               goto out_unlock;
+
+       d = get_domain_from_cpu(cpu, l3);
+       if (d) {
+               if (is_mbm_enabled() && cpu == d->mbm_work_cpu) {
+                       cancel_delayed_work(&d->mbm_over);
+                       mbm_setup_overflow_handler(d, 0, cpu);
+               }
+               if (is_llc_occupancy_enabled() && cpu == d->cqm_work_cpu &&
+                   has_busy_rmid(d)) {
+                       cancel_delayed_work(&d->cqm_limbo);
+                       cqm_setup_limbo_handler(d, 0, cpu);
+               }
+       }
+
+out_unlock:
+       mutex_unlock(&rdtgroup_mutex);
 }
 
 /*
index dc136703566f3fb97cc77fde581a373a8688c909..3259b1d4fefe3c370e0d57e697388fa8468e6fff 100644 (file)
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
 /*
- * Check for extended topology enumeration cpuid leaf 0xb and if it
- * exists, use it for populating initial_apicid and cpu topology
- * detection.
+ * CPU/APIC topology
+ *
+ * The APIC IDs describe the system topology in multiple domain levels.
+ * The CPUID topology parser provides the information which part of the
+ * APIC ID is associated to the individual levels:
+ *
+ * [PACKAGE][DIEGRP][DIE][TILE][MODULE][CORE][THREAD]
+ *
+ * The root space contains the package (socket) IDs.
+ *
+ * Not enumerated levels consume 0 bits space, but conceptually they are
+ * always represented. If e.g. only CORE and THREAD levels are enumerated
+ * then the DIE, MODULE and TILE have the same physical ID as the PACKAGE.
+ *
+ * If SMT is not supported, then the THREAD domain is still used. It then
+ * has the same physical ID as the CORE domain and is the only child of
+ * the core domain.
+ *
+ * This allows a unified view on the system independent of the enumerated
+ * domain levels without requiring any conditionals in the code.
  */
-
+#define pr_fmt(fmt) "CPU topo: " fmt
 #include <linux/cpu.h>
+
+#include <xen/xen.h>
+
 #include <asm/apic.h>
-#include <asm/memtype.h>
-#include <asm/processor.h>
+#include <asm/hypervisor.h>
+#include <asm/io_apic.h>
+#include <asm/mpspec.h>
+#include <asm/smp.h>
 
 #include "cpu.h"
 
-/* leaf 0xb SMT level */
-#define SMT_LEVEL      0
+/*
+ * Map cpu index to physical APIC ID
+ */
+DEFINE_EARLY_PER_CPU_READ_MOSTLY(u32, x86_cpu_to_apicid, BAD_APICID);
+DEFINE_EARLY_PER_CPU_READ_MOSTLY(u32, x86_cpu_to_acpiid, CPU_ACPIID_INVALID);
+EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_apicid);
+EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_acpiid);
 
-/* extended topology sub-leaf types */
-#define INVALID_TYPE   0
-#define SMT_TYPE       1
-#define CORE_TYPE      2
-#define DIE_TYPE       5
+/* Bitmap of physically present CPUs. */
+DECLARE_BITMAP(phys_cpu_present_map, MAX_LOCAL_APIC) __read_mostly;
 
-#define LEAFB_SUBTYPE(ecx)             (((ecx) >> 8) & 0xff)
-#define BITS_SHIFT_NEXT_LEVEL(eax)     ((eax) & 0x1f)
-#define LEVEL_MAX_SIBLINGS(ebx)                ((ebx) & 0xffff)
+/* Used for CPU number allocation and parallel CPU bringup */
+u32 cpuid_to_apicid[] __ro_after_init = { [0 ... NR_CPUS - 1] = BAD_APICID, };
+
+/* Bitmaps to mark registered APICs at each topology domain */
+static struct { DECLARE_BITMAP(map, MAX_LOCAL_APIC); } apic_maps[TOPO_MAX_DOMAIN] __ro_after_init;
+
+/*
+ * Keep track of assigned, disabled and rejected CPUs. Present assigned
+ * with 1 as CPU #0 is reserved for the boot CPU.
+ */
+static struct {
+       unsigned int            nr_assigned_cpus;
+       unsigned int            nr_disabled_cpus;
+       unsigned int            nr_rejected_cpus;
+       u32                     boot_cpu_apic_id;
+       u32                     real_bsp_apic_id;
+} topo_info __ro_after_init = {
+       .nr_assigned_cpus       = 1,
+       .boot_cpu_apic_id       = BAD_APICID,
+       .real_bsp_apic_id       = BAD_APICID,
+};
 
-unsigned int __max_die_per_package __read_mostly = 1;
-EXPORT_SYMBOL(__max_die_per_package);
+#define domain_weight(_dom)    bitmap_weight(apic_maps[_dom].map, MAX_LOCAL_APIC)
+
+bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
+{
+       return phys_id == (u64)cpuid_to_apicid[cpu];
+}
 
 #ifdef CONFIG_SMP
+static void cpu_mark_primary_thread(unsigned int cpu, unsigned int apicid)
+{
+       if (!(apicid & (__max_threads_per_core - 1)))
+               cpumask_set_cpu(cpu, &__cpu_primary_thread_mask);
+}
+#else
+static inline void cpu_mark_primary_thread(unsigned int cpu, unsigned int apicid) { }
+#endif
+
 /*
- * Check if given CPUID extended topology "leaf" is implemented
+ * Convert the APIC ID to a domain level ID by masking out the low bits
+ * below the domain level @dom.
  */
-static int check_extended_topology_leaf(int leaf)
+static inline u32 topo_apicid(u32 apicid, enum x86_topology_domains dom)
+{
+       if (dom == TOPO_SMT_DOMAIN)
+               return apicid;
+       return apicid & (UINT_MAX << x86_topo_system.dom_shifts[dom - 1]);
+}
+
+static int topo_lookup_cpuid(u32 apic_id)
 {
-       unsigned int eax, ebx, ecx, edx;
+       int i;
 
-       cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
+       /* CPU# to APICID mapping is persistent once it is established */
+       for (i = 0; i < topo_info.nr_assigned_cpus; i++) {
+               if (cpuid_to_apicid[i] == apic_id)
+                       return i;
+       }
+       return -ENODEV;
+}
 
-       if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
-               return -1;
+static __init int topo_get_cpunr(u32 apic_id)
+{
+       int cpu = topo_lookup_cpuid(apic_id);
 
-       return 0;
+       if (cpu >= 0)
+               return cpu;
+
+       return topo_info.nr_assigned_cpus++;
 }
-/*
- * Return best CPUID Extended Topology Leaf supported
+
+static void topo_set_cpuids(unsigned int cpu, u32 apic_id, u32 acpi_id)
+{
+#if defined(CONFIG_SMP) || defined(CONFIG_X86_64)
+       early_per_cpu(x86_cpu_to_apicid, cpu) = apic_id;
+       early_per_cpu(x86_cpu_to_acpiid, cpu) = acpi_id;
+#endif
+       set_cpu_possible(cpu, true);
+       set_cpu_present(cpu, true);
+}
+
+static __init bool check_for_real_bsp(u32 apic_id)
+{
+       /*
+        * There is no real good way to detect whether this a kdump()
+        * kernel, but except on the Voyager SMP monstrosity which is not
+        * longer supported, the real BSP APIC ID is the first one which is
+        * enumerated by firmware. That allows to detect whether the boot
+        * CPU is the real BSP. If it is not, then do not register the APIC
+        * because sending INIT to the real BSP would reset the whole
+        * system.
+        *
+        * The first APIC ID which is enumerated by firmware is detectable
+        * because the boot CPU APIC ID is registered before that without
+        * invoking this code.
+        */
+       if (topo_info.real_bsp_apic_id != BAD_APICID)
+               return false;
+
+       if (apic_id == topo_info.boot_cpu_apic_id) {
+               topo_info.real_bsp_apic_id = apic_id;
+               return false;
+       }
+
+       pr_warn("Boot CPU APIC ID not the first enumerated APIC ID: %x > %x\n",
+               topo_info.boot_cpu_apic_id, apic_id);
+       pr_warn("Crash kernel detected. Disabling real BSP to prevent machine INIT\n");
+
+       topo_info.real_bsp_apic_id = apic_id;
+       return true;
+}
+
+static unsigned int topo_unit_count(u32 lvlid, enum x86_topology_domains at_level,
+                                   unsigned long *map)
+{
+       unsigned int id, end, cnt = 0;
+
+       /* Calculate the exclusive end */
+       end = lvlid + (1U << x86_topo_system.dom_shifts[at_level]);
+
+       /* Unfortunately there is no bitmap_weight_range() */
+       for (id = find_next_bit(map, end, lvlid); id < end; id = find_next_bit(map, end, ++id))
+               cnt++;
+       return cnt;
+}
+
+static __init void topo_register_apic(u32 apic_id, u32 acpi_id, bool present)
+{
+       int cpu, dom;
+
+       if (present) {
+               set_bit(apic_id, phys_cpu_present_map);
+
+               /*
+                * Double registration is valid in case of the boot CPU
+                * APIC because that is registered before the enumeration
+                * of the APICs via firmware parsers or VM guest
+                * mechanisms.
+                */
+               if (apic_id == topo_info.boot_cpu_apic_id)
+                       cpu = 0;
+               else
+                       cpu = topo_get_cpunr(apic_id);
+
+               cpuid_to_apicid[cpu] = apic_id;
+               topo_set_cpuids(cpu, apic_id, acpi_id);
+       } else {
+               u32 pkgid = topo_apicid(apic_id, TOPO_PKG_DOMAIN);
+
+               /*
+                * Check for present APICs in the same package when running
+                * on bare metal. Allow the bogosity in a guest.
+                */
+               if (hypervisor_is_type(X86_HYPER_NATIVE) &&
+                   topo_unit_count(pkgid, TOPO_PKG_DOMAIN, phys_cpu_present_map)) {
+                       pr_info_once("Ignoring hot-pluggable APIC ID %x in present package.\n",
+                                    apic_id);
+                       topo_info.nr_rejected_cpus++;
+                       return;
+               }
+
+               topo_info.nr_disabled_cpus++;
+       }
+
+       /* Register present and possible CPUs in the domain maps */
+       for (dom = TOPO_SMT_DOMAIN; dom < TOPO_MAX_DOMAIN; dom++)
+               set_bit(topo_apicid(apic_id, dom), apic_maps[dom].map);
+}
+
+/**
+ * topology_register_apic - Register an APIC in early topology maps
+ * @apic_id:   The APIC ID to set up
+ * @acpi_id:   The ACPI ID associated to the APIC
+ * @present:   True if the corresponding CPU is present
  */
-static int detect_extended_topology_leaf(struct cpuinfo_x86 *c)
+void __init topology_register_apic(u32 apic_id, u32 acpi_id, bool present)
 {
-       if (c->cpuid_level >= 0x1f) {
-               if (check_extended_topology_leaf(0x1f) == 0)
-                       return 0x1f;
+       if (apic_id >= MAX_LOCAL_APIC) {
+               pr_err_once("APIC ID %x exceeds kernel limit of: %x\n", apic_id, MAX_LOCAL_APIC - 1);
+               topo_info.nr_rejected_cpus++;
+               return;
+       }
+
+       if (check_for_real_bsp(apic_id)) {
+               topo_info.nr_rejected_cpus++;
+               return;
        }
 
-       if (c->cpuid_level >= 0xb) {
-               if (check_extended_topology_leaf(0xb) == 0)
-                       return 0xb;
+       /* CPU numbers exhausted? */
+       if (apic_id != topo_info.boot_cpu_apic_id && topo_info.nr_assigned_cpus >= nr_cpu_ids) {
+               pr_warn_once("CPU limit of %d reached. Ignoring further CPUs\n", nr_cpu_ids);
+               topo_info.nr_rejected_cpus++;
+               return;
        }
 
-       return -1;
+       topo_register_apic(apic_id, acpi_id, present);
+}
+
+/**
+ * topology_register_boot_apic - Register the boot CPU APIC
+ * @apic_id:   The APIC ID to set up
+ *
+ * Separate so CPU #0 can be assigned
+ */
+void __init topology_register_boot_apic(u32 apic_id)
+{
+       WARN_ON_ONCE(topo_info.boot_cpu_apic_id != BAD_APICID);
+
+       topo_info.boot_cpu_apic_id = apic_id;
+       topo_register_apic(apic_id, CPU_ACPIID_INVALID, true);
+}
+
+/**
+ * topology_get_logical_id - Retrieve the logical ID at a given topology domain level
+ * @apicid:            The APIC ID for which to lookup the logical ID
+ * @at_level:          The topology domain level to use
+ *
+ * @apicid must be a full APIC ID, not the normalized variant. It's valid to have
+ * all bits below the domain level specified by @at_level to be clear. So both
+ * real APIC IDs and backshifted normalized APIC IDs work correctly.
+ *
+ * Returns:
+ *  - >= 0:    The requested logical ID
+ *  - -ERANGE: @apicid is out of range
+ *  - -ENODEV: @apicid is not registered
+ */
+int topology_get_logical_id(u32 apicid, enum x86_topology_domains at_level)
+{
+       /* Remove the bits below @at_level to get the proper level ID of @apicid */
+       unsigned int lvlid = topo_apicid(apicid, at_level);
+
+       if (lvlid >= MAX_LOCAL_APIC)
+               return -ERANGE;
+       if (!test_bit(lvlid, apic_maps[at_level].map))
+               return -ENODEV;
+       /* Get the number of set bits before @lvlid. */
+       return bitmap_weight(apic_maps[at_level].map, lvlid);
+}
+EXPORT_SYMBOL_GPL(topology_get_logical_id);
+
+/**
+ * topology_unit_count - Retrieve the count of specified units at a given topology domain level
+ * @apicid:            The APIC ID which specifies the search range
+ * @which_units:       The domain level specifying the units to count
+ * @at_level:          The domain level at which @which_units have to be counted
+ *
+ * This returns the number of possible units according to the enumerated
+ * information.
+ *
+ * E.g. topology_count_units(apicid, TOPO_CORE_DOMAIN, TOPO_PKG_DOMAIN)
+ * counts the number of possible cores in the package to which @apicid
+ * belongs.
+ *
+ * @at_level must obviously be greater than @which_level to produce useful
+ * results.  If @at_level is equal to @which_units the result is
+ * unsurprisingly 1. If @at_level is less than @which_units the results
+ * is by definition undefined and the function returns 0.
+ */
+unsigned int topology_unit_count(u32 apicid, enum x86_topology_domains which_units,
+                                enum x86_topology_domains at_level)
+{
+       /* Remove the bits below @at_level to get the proper level ID of @apicid */
+       unsigned int lvlid = topo_apicid(apicid, at_level);
+
+       if (lvlid >= MAX_LOCAL_APIC)
+               return 0;
+       if (!test_bit(lvlid, apic_maps[at_level].map))
+               return 0;
+       if (which_units > at_level)
+               return 0;
+       if (which_units == at_level)
+               return 1;
+       return topo_unit_count(lvlid, at_level, apic_maps[which_units].map);
+}
+
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+/**
+ * topology_hotplug_apic - Handle a physical hotplugged APIC after boot
+ * @apic_id:   The APIC ID to set up
+ * @acpi_id:   The ACPI ID associated to the APIC
+ */
+int topology_hotplug_apic(u32 apic_id, u32 acpi_id)
+{
+       int cpu;
+
+       if (apic_id >= MAX_LOCAL_APIC)
+               return -EINVAL;
+
+       /* Reject if the APIC ID was not registered during enumeration. */
+       if (!test_bit(apic_id, apic_maps[TOPO_SMT_DOMAIN].map))
+               return -ENODEV;
+
+       cpu = topo_lookup_cpuid(apic_id);
+       if (cpu < 0)
+               return -ENOSPC;
+
+       set_bit(apic_id, phys_cpu_present_map);
+       topo_set_cpuids(cpu, apic_id, acpi_id);
+       cpu_mark_primary_thread(cpu, apic_id);
+       return cpu;
+}
+
+/**
+ * topology_hotunplug_apic - Remove a physical hotplugged APIC after boot
+ * @cpu:       The CPU number for which the APIC ID is removed
+ */
+void topology_hotunplug_apic(unsigned int cpu)
+{
+       u32 apic_id = cpuid_to_apicid[cpu];
+
+       if (apic_id == BAD_APICID)
+               return;
+
+       per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID;
+       clear_bit(apic_id, phys_cpu_present_map);
+       set_cpu_present(cpu, false);
 }
 #endif
 
-int detect_extended_topology_early(struct cpuinfo_x86 *c)
+#ifdef CONFIG_X86_LOCAL_APIC
+static unsigned int max_possible_cpus __initdata = NR_CPUS;
+
+/**
+ * topology_apply_cmdline_limits_early - Apply topology command line limits early
+ *
+ * Ensure that command line limits are in effect before firmware parsing
+ * takes place.
+ */
+void __init topology_apply_cmdline_limits_early(void)
 {
-#ifdef CONFIG_SMP
-       unsigned int eax, ebx, ecx, edx;
-       int leaf;
+       unsigned int possible = nr_cpu_ids;
 
-       leaf = detect_extended_topology_leaf(c);
-       if (leaf < 0)
-               return -1;
+       /* 'maxcpus=0' 'nosmp' 'nolapic' 'disableapic' 'noapic' */
+       if (!setup_max_cpus || ioapic_is_disabled || apic_is_disabled)
+               possible = 1;
 
-       set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
+       /* 'possible_cpus=N' */
+       possible = min_t(unsigned int, max_possible_cpus, possible);
+
+       if (possible < nr_cpu_ids) {
+               pr_info("Limiting to %u possible CPUs\n", possible);
+               set_nr_cpu_ids(possible);
+       }
+}
 
-       cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
+static __init bool restrict_to_up(void)
+{
+       if (!smp_found_config || ioapic_is_disabled)
+               return true;
        /*
-        * initial apic id, which also represents 32-bit extended x2apic id.
+        * XEN PV is special as it does not advertise the local APIC
+        * properly, but provides a fake topology for it so that the
+        * infrastructure works. So don't apply the restrictions vs. APIC
+        * here.
         */
-       c->topo.initial_apicid = edx;
-       smp_num_siblings = max_t(int, smp_num_siblings, LEVEL_MAX_SIBLINGS(ebx));
-#endif
-       return 0;
+       if (xen_pv_domain())
+               return false;
+
+       return apic_is_disabled;
 }
 
-/*
- * Check for extended topology enumeration cpuid leaf, and if it
- * exists, use it for populating initial_apicid and cpu topology
- * detection.
- */
-int detect_extended_topology(struct cpuinfo_x86 *c)
+void __init topology_init_possible_cpus(void)
 {
-#ifdef CONFIG_SMP
-       unsigned int eax, ebx, ecx, edx, sub_index;
-       unsigned int ht_mask_width, core_plus_mask_width, die_plus_mask_width;
-       unsigned int core_select_mask, core_level_siblings;
-       unsigned int die_select_mask, die_level_siblings;
-       unsigned int pkg_mask_width;
-       bool die_level_present = false;
-       int leaf;
-
-       leaf = detect_extended_topology_leaf(c);
-       if (leaf < 0)
-               return -1;
+       unsigned int assigned = topo_info.nr_assigned_cpus;
+       unsigned int disabled = topo_info.nr_disabled_cpus;
+       unsigned int cnta, cntb, cpu, allowed = 1;
+       unsigned int total = assigned + disabled;
+       u32 apicid, firstid;
+
+       if (!restrict_to_up()) {
+               if (WARN_ON_ONCE(assigned > nr_cpu_ids)) {
+                       disabled += assigned - nr_cpu_ids;
+                       assigned = nr_cpu_ids;
+               }
+               allowed = min_t(unsigned int, total, nr_cpu_ids);
+       }
+
+       if (total > allowed)
+               pr_warn("%u possible CPUs exceed the limit of %u\n", total, allowed);
+
+       assigned = min_t(unsigned int, allowed, assigned);
+       disabled = allowed - assigned;
 
+       topo_info.nr_assigned_cpus = assigned;
+       topo_info.nr_disabled_cpus = disabled;
+
+       total_cpus = allowed;
+       set_nr_cpu_ids(allowed);
+
+       cnta = domain_weight(TOPO_PKG_DOMAIN);
+       cntb = domain_weight(TOPO_DIE_DOMAIN);
+       __max_logical_packages = cnta;
+       __max_dies_per_package = 1U << (get_count_order(cntb) - get_count_order(cnta));
+
+       pr_info("Max. logical packages: %3u\n", cnta);
+       pr_info("Max. logical dies:     %3u\n", cntb);
+       pr_info("Max. dies per package: %3u\n", __max_dies_per_package);
+
+       cnta = domain_weight(TOPO_CORE_DOMAIN);
+       cntb = domain_weight(TOPO_SMT_DOMAIN);
        /*
-        * Populate HT related information from sub-leaf level 0.
+        * Can't use order delta here as order(cnta) can be equal
+        * order(cntb) even if cnta != cntb.
         */
-       cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
-       c->topo.initial_apicid = edx;
-       core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
-       smp_num_siblings = max_t(int, smp_num_siblings, LEVEL_MAX_SIBLINGS(ebx));
-       core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
-       die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
-       pkg_mask_width = die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
-
-       sub_index = 1;
-       while (true) {
-               cpuid_count(leaf, sub_index, &eax, &ebx, &ecx, &edx);
+       __max_threads_per_core = DIV_ROUND_UP(cntb, cnta);
+       pr_info("Max. threads per core: %3u\n", __max_threads_per_core);
 
-               /*
-                * Check for the Core type in the implemented sub leaves.
-                */
-               if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
-                       core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
-                       core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
-                       die_level_siblings = core_level_siblings;
-                       die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
-               }
-               if (LEAFB_SUBTYPE(ecx) == DIE_TYPE) {
-                       die_level_present = true;
-                       die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
-                       die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
-               }
+       firstid = find_first_bit(apic_maps[TOPO_SMT_DOMAIN].map, MAX_LOCAL_APIC);
+       __num_cores_per_package = topology_unit_count(firstid, TOPO_CORE_DOMAIN, TOPO_PKG_DOMAIN);
+       pr_info("Num. cores per package:   %3u\n", __num_cores_per_package);
+       __num_threads_per_package = topology_unit_count(firstid, TOPO_SMT_DOMAIN, TOPO_PKG_DOMAIN);
+       pr_info("Num. threads per package: %3u\n", __num_threads_per_package);
 
-               if (LEAFB_SUBTYPE(ecx) != INVALID_TYPE)
-                       pkg_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
-               else
-                       break;
+       pr_info("Allowing %u present CPUs plus %u hotplug CPUs\n", assigned, disabled);
+       if (topo_info.nr_rejected_cpus)
+               pr_info("Rejected CPUs %u\n", topo_info.nr_rejected_cpus);
 
-               sub_index++;
+       init_cpu_present(cpumask_of(0));
+       init_cpu_possible(cpumask_of(0));
+
+       /* Assign CPU numbers to non-present CPUs */
+       for (apicid = 0; disabled; disabled--, apicid++) {
+               apicid = find_next_andnot_bit(apic_maps[TOPO_SMT_DOMAIN].map, phys_cpu_present_map,
+                                             MAX_LOCAL_APIC, apicid);
+               if (apicid >= MAX_LOCAL_APIC)
+                       break;
+               cpuid_to_apicid[topo_info.nr_assigned_cpus++] = apicid;
        }
 
-       core_select_mask = (~(-1 << pkg_mask_width)) >> ht_mask_width;
-       die_select_mask = (~(-1 << die_plus_mask_width)) >>
-                               core_plus_mask_width;
+       for (cpu = 0; cpu < allowed; cpu++) {
+               apicid = cpuid_to_apicid[cpu];
 
-       c->topo.core_id = apic->phys_pkg_id(c->topo.initial_apicid,
-                               ht_mask_width) & core_select_mask;
+               set_cpu_possible(cpu, true);
 
-       if (die_level_present) {
-               c->topo.die_id = apic->phys_pkg_id(c->topo.initial_apicid,
-                                       core_plus_mask_width) & die_select_mask;
+               if (apicid == BAD_APICID)
+                       continue;
+
+               cpu_mark_primary_thread(cpu, apicid);
+               set_cpu_present(cpu, test_bit(apicid, phys_cpu_present_map));
        }
+}
 
-       c->topo.pkg_id = apic->phys_pkg_id(c->topo.initial_apicid, pkg_mask_width);
-       /*
-        * Reinit the apicid, now that we have extended initial_apicid.
-        */
-       c->topo.apicid = apic->phys_pkg_id(c->topo.initial_apicid, 0);
+/*
+ * Late SMP disable after sizing CPU masks when APIC/IOAPIC setup failed.
+ */
+void __init topology_reset_possible_cpus_up(void)
+{
+       init_cpu_present(cpumask_of(0));
+       init_cpu_possible(cpumask_of(0));
 
-       c->x86_max_cores = (core_level_siblings / smp_num_siblings);
-       __max_die_per_package = (die_level_siblings / core_level_siblings);
-#endif
+       bitmap_zero(phys_cpu_present_map, MAX_LOCAL_APIC);
+       if (topo_info.boot_cpu_apic_id != BAD_APICID)
+               set_bit(topo_info.boot_cpu_apic_id, phys_cpu_present_map);
+}
+
+static int __init setup_possible_cpus(char *str)
+{
+       get_option(&str, &max_possible_cpus);
        return 0;
 }
+early_param("possible_cpus", setup_possible_cpus);
+#endif
diff --git a/arch/x86/kernel/cpu/topology.h b/arch/x86/kernel/cpu/topology.h
new file mode 100644 (file)
index 0000000..3732629
--- /dev/null
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ARCH_X86_TOPOLOGY_H
+#define ARCH_X86_TOPOLOGY_H
+
+struct topo_scan {
+       struct cpuinfo_x86      *c;
+       unsigned int            dom_shifts[TOPO_MAX_DOMAIN];
+       unsigned int            dom_ncpus[TOPO_MAX_DOMAIN];
+
+       /* Legacy CPUID[1]:EBX[23:16] number of logical processors */
+       unsigned int            ebx1_nproc_shift;
+
+       /* AMD specific node ID which cannot be mapped into APIC space. */
+       u16                     amd_nodes_per_pkg;
+       u16                     amd_node_id;
+};
+
+void cpu_init_topology(struct cpuinfo_x86 *c);
+void cpu_parse_topology(struct cpuinfo_x86 *c);
+void topology_set_dom(struct topo_scan *tscan, enum x86_topology_domains dom,
+                     unsigned int shift, unsigned int ncpus);
+bool cpu_parse_topology_ext(struct topo_scan *tscan);
+void cpu_parse_topology_amd(struct topo_scan *tscan);
+void cpu_topology_fixup_amd(struct topo_scan *tscan);
+
+static inline u32 topo_shift_apicid(u32 apicid, enum x86_topology_domains dom)
+{
+       if (dom == TOPO_SMT_DOMAIN)
+               return apicid;
+       return apicid >> x86_topo_system.dom_shifts[dom - 1];
+}
+
+static inline u32 topo_relative_domain_id(u32 apicid, enum x86_topology_domains dom)
+{
+       if (dom != TOPO_SMT_DOMAIN)
+               apicid >>= x86_topo_system.dom_shifts[dom - 1];
+       return apicid & (x86_topo_system.dom_size[dom] - 1);
+}
+
+static inline u32 topo_domain_mask(enum x86_topology_domains dom)
+{
+       return (1U << x86_topo_system.dom_shifts[dom]) - 1;
+}
+
+/*
+ * Update a domain level after the fact without propagating. Used to fixup
+ * broken CPUID enumerations.
+ */
+static inline void topology_update_dom(struct topo_scan *tscan, enum x86_topology_domains dom,
+                                      unsigned int shift, unsigned int ncpus)
+{
+       tscan->dom_shifts[dom] = shift;
+       tscan->dom_ncpus[dom] = ncpus;
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+unsigned int topology_unit_count(u32 apicid, enum x86_topology_domains which_units,
+                                enum x86_topology_domains at_level);
+#else
+static inline unsigned int topology_unit_count(u32 apicid, enum x86_topology_domains which_units,
+                                              enum x86_topology_domains at_level)
+{
+       return 1;
+}
+#endif
+
+#endif /* ARCH_X86_TOPOLOGY_H */
diff --git a/arch/x86/kernel/cpu/topology_amd.c b/arch/x86/kernel/cpu/topology_amd.c
new file mode 100644 (file)
index 0000000..1a8b3ad
--- /dev/null
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/cpu.h>
+
+#include <asm/apic.h>
+#include <asm/memtype.h>
+#include <asm/processor.h>
+
+#include "cpu.h"
+
+static bool parse_8000_0008(struct topo_scan *tscan)
+{
+       struct {
+               // ecx
+               u32     cpu_nthreads            :  8, // Number of physical threads - 1
+                                               :  4, // Reserved
+                       apicid_coreid_len       :  4, // Number of thread core ID bits (shift) in APIC ID
+                       perf_tsc_len            :  2, // Performance time-stamp counter size
+                                               : 14; // Reserved
+       } ecx;
+       unsigned int sft;
+
+       if (tscan->c->extended_cpuid_level < 0x80000008)
+               return false;
+
+       cpuid_leaf_reg(0x80000008, CPUID_ECX, &ecx);
+
+       /* If the thread bits are 0, then get the shift value from ecx.cpu_nthreads */
+       sft = ecx.apicid_coreid_len;
+       if (!sft)
+               sft = get_count_order(ecx.cpu_nthreads + 1);
+
+       topology_set_dom(tscan, TOPO_SMT_DOMAIN, sft, ecx.cpu_nthreads + 1);
+       return true;
+}
+
+static void store_node(struct topo_scan *tscan, unsigned int nr_nodes, u16 node_id)
+{
+       /*
+        * Starting with Fam 17h the DIE domain could probably be used to
+        * retrieve the node info on AMD/HYGON. Analysis of CPUID dumps
+        * suggests it's the topmost bit(s) of the CPU cores area, but
+        * that's guess work and neither enumerated nor documented.
+        *
+        * Up to Fam 16h this does not work at all and the legacy node ID
+        * has to be used.
+        */
+       tscan->amd_nodes_per_pkg = nr_nodes;
+       tscan->amd_node_id = node_id;
+}
+
+static bool parse_8000_001e(struct topo_scan *tscan, bool has_0xb)
+{
+       struct {
+               // eax
+               u32     ext_apic_id             : 32; // Extended APIC ID
+               // ebx
+               u32     core_id                 :  8, // Unique per-socket logical core unit ID
+                       core_nthreads           :  8, // #Threads per core (zero-based)
+                                               : 16; // Reserved
+               // ecx
+               u32     node_id                 :  8, // Node (die) ID of invoking logical CPU
+                       nnodes_per_socket       :  3, // #nodes in invoking logical CPU's package/socket
+                                               : 21; // Reserved
+               // edx
+               u32                             : 32; // Reserved
+       } leaf;
+
+       if (!boot_cpu_has(X86_FEATURE_TOPOEXT))
+               return false;
+
+       cpuid_leaf(0x8000001e, &leaf);
+
+       tscan->c->topo.initial_apicid = leaf.ext_apic_id;
+
+       /*
+        * If leaf 0xb is available, then SMT shift is set already. If not
+        * take it from ecx.threads_per_core and use topo_update_dom() -
+        * topology_set_dom() would propagate and overwrite the already
+        * propagated CORE level.
+        */
+       if (!has_0xb) {
+               unsigned int nthreads = leaf.core_nthreads + 1;
+
+               topology_update_dom(tscan, TOPO_SMT_DOMAIN, get_count_order(nthreads), nthreads);
+       }
+
+       store_node(tscan, leaf.nnodes_per_socket + 1, leaf.node_id);
+
+       if (tscan->c->x86_vendor == X86_VENDOR_AMD) {
+               if (tscan->c->x86 == 0x15)
+                       tscan->c->topo.cu_id = leaf.core_id;
+
+               cacheinfo_amd_init_llc_id(tscan->c, leaf.node_id);
+       } else {
+               /*
+                * Package ID is ApicId[6..] on certain Hygon CPUs. See
+                * commit e0ceeae708ce for explanation. The topology info
+                * is screwed up: The package shift is always 6 and the
+                * node ID is bit [4:5].
+                */
+               if (!boot_cpu_has(X86_FEATURE_HYPERVISOR) && tscan->c->x86_model <= 0x3) {
+                       topology_set_dom(tscan, TOPO_CORE_DOMAIN, 6,
+                                        tscan->dom_ncpus[TOPO_CORE_DOMAIN]);
+               }
+               cacheinfo_hygon_init_llc_id(tscan->c);
+       }
+       return true;
+}
+
+static bool parse_fam10h_node_id(struct topo_scan *tscan)
+{
+       struct {
+               union {
+                       u64     node_id         :  3,
+                               nodes_per_pkg   :  3,
+                               unused          : 58;
+                       u64     msr;
+               };
+       } nid;
+
+       if (!boot_cpu_has(X86_FEATURE_NODEID_MSR))
+               return false;
+
+       rdmsrl(MSR_FAM10H_NODE_ID, nid.msr);
+       store_node(tscan, nid.nodes_per_pkg + 1, nid.node_id);
+       tscan->c->topo.llc_id = nid.node_id;
+       return true;
+}
+
+static void legacy_set_llc(struct topo_scan *tscan)
+{
+       unsigned int apicid = tscan->c->topo.initial_apicid;
+
+       /* parse_8000_0008() set everything up except llc_id */
+       tscan->c->topo.llc_id = apicid >> tscan->dom_shifts[TOPO_CORE_DOMAIN];
+}
+
+static void parse_topology_amd(struct topo_scan *tscan)
+{
+       bool has_0xb = false;
+
+       /*
+        * If the extended topology leaf 0x8000_001e is available
+        * try to get SMT and CORE shift from leaf 0xb first, then
+        * try to get the CORE shift from leaf 0x8000_0008.
+        */
+       if (cpu_feature_enabled(X86_FEATURE_TOPOEXT))
+               has_0xb = cpu_parse_topology_ext(tscan);
+
+       if (!has_0xb && !parse_8000_0008(tscan))
+               return;
+
+       /* Prefer leaf 0x8000001e if available */
+       if (parse_8000_001e(tscan, has_0xb))
+               return;
+
+       /* Try the NODEID MSR */
+       if (parse_fam10h_node_id(tscan))
+               return;
+
+       legacy_set_llc(tscan);
+}
+
+void cpu_parse_topology_amd(struct topo_scan *tscan)
+{
+       tscan->amd_nodes_per_pkg = 1;
+       parse_topology_amd(tscan);
+
+       if (tscan->amd_nodes_per_pkg > 1)
+               set_cpu_cap(tscan->c, X86_FEATURE_AMD_DCM);
+}
+
+void cpu_topology_fixup_amd(struct topo_scan *tscan)
+{
+       struct cpuinfo_x86 *c = tscan->c;
+
+       /*
+        * Adjust the core_id relative to the node when there is more than
+        * one node.
+        */
+       if (tscan->c->x86 < 0x17 && tscan->amd_nodes_per_pkg > 1)
+               c->topo.core_id %= tscan->dom_ncpus[TOPO_CORE_DOMAIN] / tscan->amd_nodes_per_pkg;
+}
diff --git a/arch/x86/kernel/cpu/topology_common.c b/arch/x86/kernel/cpu/topology_common.c
new file mode 100644 (file)
index 0000000..a50ae8d
--- /dev/null
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/cpu.h>
+
+#include <xen/xen.h>
+
+#include <asm/apic.h>
+#include <asm/processor.h>
+#include <asm/smp.h>
+
+#include "cpu.h"
+
+struct x86_topology_system x86_topo_system __ro_after_init;
+EXPORT_SYMBOL_GPL(x86_topo_system);
+
+unsigned int __amd_nodes_per_pkg __ro_after_init;
+EXPORT_SYMBOL_GPL(__amd_nodes_per_pkg);
+
+void topology_set_dom(struct topo_scan *tscan, enum x86_topology_domains dom,
+                     unsigned int shift, unsigned int ncpus)
+{
+       topology_update_dom(tscan, dom, shift, ncpus);
+
+       /* Propagate to the upper levels */
+       for (dom++; dom < TOPO_MAX_DOMAIN; dom++) {
+               tscan->dom_shifts[dom] = tscan->dom_shifts[dom - 1];
+               tscan->dom_ncpus[dom] = tscan->dom_ncpus[dom - 1];
+       }
+}
+
+static unsigned int __maybe_unused parse_num_cores_legacy(struct cpuinfo_x86 *c)
+{
+       struct {
+               u32     cache_type      :  5,
+                       unused          : 21,
+                       ncores          :  6;
+       } eax;
+
+       if (c->cpuid_level < 4)
+               return 1;
+
+       cpuid_subleaf_reg(4, 0, CPUID_EAX, &eax);
+       if (!eax.cache_type)
+               return 1;
+
+       return eax.ncores + 1;
+}
+
+static void parse_legacy(struct topo_scan *tscan)
+{
+       unsigned int cores, core_shift, smt_shift = 0;
+       struct cpuinfo_x86 *c = tscan->c;
+
+       cores = parse_num_cores_legacy(c);
+       core_shift = get_count_order(cores);
+
+       if (cpu_has(c, X86_FEATURE_HT)) {
+               if (!WARN_ON_ONCE(tscan->ebx1_nproc_shift < core_shift))
+                       smt_shift = tscan->ebx1_nproc_shift - core_shift;
+               /*
+                * The parser expects leaf 0xb/0x1f format, which means
+                * the number of logical processors at core level is
+                * counting threads.
+                */
+               core_shift += smt_shift;
+               cores <<= smt_shift;
+       }
+
+       topology_set_dom(tscan, TOPO_SMT_DOMAIN, smt_shift, 1U << smt_shift);
+       topology_set_dom(tscan, TOPO_CORE_DOMAIN, core_shift, cores);
+}
+
+static bool fake_topology(struct topo_scan *tscan)
+{
+       /*
+        * Preset the CORE level shift for CPUID less systems and XEN_PV,
+        * which has useless CPUID information.
+        */
+       topology_set_dom(tscan, TOPO_SMT_DOMAIN, 0, 1);
+       topology_set_dom(tscan, TOPO_CORE_DOMAIN, 0, 1);
+
+       return tscan->c->cpuid_level < 1;
+}
+
+static void parse_topology(struct topo_scan *tscan, bool early)
+{
+       const struct cpuinfo_topology topo_defaults = {
+               .cu_id                  = 0xff,
+               .llc_id                 = BAD_APICID,
+               .l2c_id                 = BAD_APICID,
+       };
+       struct cpuinfo_x86 *c = tscan->c;
+       struct {
+               u32     unused0         : 16,
+                       nproc           :  8,
+                       apicid          :  8;
+       } ebx;
+
+       c->topo = topo_defaults;
+
+       if (fake_topology(tscan))
+               return;
+
+       /* Preset Initial APIC ID from CPUID leaf 1 */
+       cpuid_leaf_reg(1, CPUID_EBX, &ebx);
+       c->topo.initial_apicid = ebx.apicid;
+
+       /*
+        * The initial invocation from early_identify_cpu() happens before
+        * the APIC is mapped or X2APIC enabled. For establishing the
+        * topology, that's not required. Use the initial APIC ID.
+        */
+       if (early)
+               c->topo.apicid = c->topo.initial_apicid;
+       else
+               c->topo.apicid = read_apic_id();
+
+       /* The above is sufficient for UP */
+       if (!IS_ENABLED(CONFIG_SMP))
+               return;
+
+       tscan->ebx1_nproc_shift = get_count_order(ebx.nproc);
+
+       switch (c->x86_vendor) {
+       case X86_VENDOR_AMD:
+               if (IS_ENABLED(CONFIG_CPU_SUP_AMD))
+                       cpu_parse_topology_amd(tscan);
+               break;
+       case X86_VENDOR_CENTAUR:
+       case X86_VENDOR_ZHAOXIN:
+               parse_legacy(tscan);
+               break;
+       case X86_VENDOR_INTEL:
+               if (!IS_ENABLED(CONFIG_CPU_SUP_INTEL) || !cpu_parse_topology_ext(tscan))
+                       parse_legacy(tscan);
+               break;
+       case X86_VENDOR_HYGON:
+               if (IS_ENABLED(CONFIG_CPU_SUP_HYGON))
+                       cpu_parse_topology_amd(tscan);
+               break;
+       }
+}
+
+static void topo_set_ids(struct topo_scan *tscan)
+{
+       struct cpuinfo_x86 *c = tscan->c;
+       u32 apicid = c->topo.apicid;
+
+       c->topo.pkg_id = topo_shift_apicid(apicid, TOPO_PKG_DOMAIN);
+       c->topo.die_id = topo_shift_apicid(apicid, TOPO_DIE_DOMAIN);
+
+       c->topo.logical_pkg_id = topology_get_logical_id(apicid, TOPO_PKG_DOMAIN);
+       c->topo.logical_die_id = topology_get_logical_id(apicid, TOPO_DIE_DOMAIN);
+
+       /* Package relative core ID */
+       c->topo.core_id = (apicid & topo_domain_mask(TOPO_PKG_DOMAIN)) >>
+               x86_topo_system.dom_shifts[TOPO_SMT_DOMAIN];
+
+       c->topo.amd_node_id = tscan->amd_node_id;
+
+       if (c->x86_vendor == X86_VENDOR_AMD)
+               cpu_topology_fixup_amd(tscan);
+}
+
+void cpu_parse_topology(struct cpuinfo_x86 *c)
+{
+       unsigned int dom, cpu = smp_processor_id();
+       struct topo_scan tscan = { .c = c, };
+
+       parse_topology(&tscan, false);
+
+       if (IS_ENABLED(CONFIG_X86_LOCAL_APIC)) {
+               if (c->topo.initial_apicid != c->topo.apicid) {
+                       pr_err(FW_BUG "CPU%4u: APIC ID mismatch. CPUID: 0x%04x APIC: 0x%04x\n",
+                              cpu, c->topo.initial_apicid, c->topo.apicid);
+               }
+
+               if (c->topo.apicid != cpuid_to_apicid[cpu]) {
+                       pr_err(FW_BUG "CPU%4u: APIC ID mismatch. Firmware: 0x%04x APIC: 0x%04x\n",
+                              cpu, cpuid_to_apicid[cpu], c->topo.apicid);
+               }
+       }
+
+       for (dom = TOPO_SMT_DOMAIN; dom < TOPO_MAX_DOMAIN; dom++) {
+               if (tscan.dom_shifts[dom] == x86_topo_system.dom_shifts[dom])
+                       continue;
+               pr_err(FW_BUG "CPU%d: Topology domain %u shift %u != %u\n", cpu, dom,
+                      tscan.dom_shifts[dom], x86_topo_system.dom_shifts[dom]);
+       }
+
+       topo_set_ids(&tscan);
+}
+
+void __init cpu_init_topology(struct cpuinfo_x86 *c)
+{
+       struct topo_scan tscan = { .c = c, };
+       unsigned int dom, sft;
+
+       parse_topology(&tscan, true);
+
+       /* Copy the shift values and calculate the unit sizes. */
+       memcpy(x86_topo_system.dom_shifts, tscan.dom_shifts, sizeof(x86_topo_system.dom_shifts));
+
+       dom = TOPO_SMT_DOMAIN;
+       x86_topo_system.dom_size[dom] = 1U << x86_topo_system.dom_shifts[dom];
+
+       for (dom++; dom < TOPO_MAX_DOMAIN; dom++) {
+               sft = x86_topo_system.dom_shifts[dom] - x86_topo_system.dom_shifts[dom - 1];
+               x86_topo_system.dom_size[dom] = 1U << sft;
+       }
+
+       topo_set_ids(&tscan);
+
+       /*
+        * AMD systems have Nodes per package which cannot be mapped to
+        * APIC ID.
+        */
+       __amd_nodes_per_pkg = tscan.amd_nodes_per_pkg;
+}
diff --git a/arch/x86/kernel/cpu/topology_ext.c b/arch/x86/kernel/cpu/topology_ext.c
new file mode 100644 (file)
index 0000000..e477228
--- /dev/null
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/cpu.h>
+
+#include <asm/apic.h>
+#include <asm/memtype.h>
+#include <asm/processor.h>
+
+#include "cpu.h"
+
+enum topo_types {
+       INVALID_TYPE            = 0,
+       SMT_TYPE                = 1,
+       CORE_TYPE               = 2,
+       MAX_TYPE_0B             = 3,
+       MODULE_TYPE             = 3,
+       TILE_TYPE               = 4,
+       DIE_TYPE                = 5,
+       DIEGRP_TYPE             = 6,
+       MAX_TYPE_1F             = 7,
+};
+
+/*
+ * Use a lookup table for the case that there are future types > 6 which
+ * describe an intermediate domain level which does not exist today.
+ */
+static const unsigned int topo_domain_map_0b_1f[MAX_TYPE_1F] = {
+       [SMT_TYPE]      = TOPO_SMT_DOMAIN,
+       [CORE_TYPE]     = TOPO_CORE_DOMAIN,
+       [MODULE_TYPE]   = TOPO_MODULE_DOMAIN,
+       [TILE_TYPE]     = TOPO_TILE_DOMAIN,
+       [DIE_TYPE]      = TOPO_DIE_DOMAIN,
+       [DIEGRP_TYPE]   = TOPO_DIEGRP_DOMAIN,
+};
+
+static inline bool topo_subleaf(struct topo_scan *tscan, u32 leaf, u32 subleaf,
+                               unsigned int *last_dom)
+{
+       unsigned int dom, maxtype;
+       const unsigned int *map;
+       struct {
+               // eax
+               u32     x2apic_shift    :  5, // Number of bits to shift APIC ID right
+                                             // for the topology ID at the next level
+                                       : 27; // Reserved
+               // ebx
+               u32     num_processors  : 16, // Number of processors at current level
+                                       : 16; // Reserved
+               // ecx
+               u32     level           :  8, // Current topology level. Same as sub leaf number
+                       type            :  8, // Level type. If 0, invalid
+                                       : 16; // Reserved
+               // edx
+               u32     x2apic_id       : 32; // X2APIC ID of the current logical processor
+       } sl;
+
+       switch (leaf) {
+       case 0x0b: maxtype = MAX_TYPE_0B; map = topo_domain_map_0b_1f; break;
+       case 0x1f: maxtype = MAX_TYPE_1F; map = topo_domain_map_0b_1f; break;
+       default: return false;
+       }
+
+       cpuid_subleaf(leaf, subleaf, &sl);
+
+       if (!sl.num_processors || sl.type == INVALID_TYPE)
+               return false;
+
+       if (sl.type >= maxtype) {
+               pr_err_once("Topology: leaf 0x%x:%d Unknown domain type %u\n",
+                           leaf, subleaf, sl.type);
+               /*
+                * It really would have been too obvious to make the domain
+                * type space sparse and leave a few reserved types between
+                * the points which might change instead of following the
+                * usual "this can be fixed in software" principle.
+                */
+               dom = *last_dom + 1;
+       } else {
+               dom = map[sl.type];
+               *last_dom = dom;
+       }
+
+       if (!dom) {
+               tscan->c->topo.initial_apicid = sl.x2apic_id;
+       } else if (tscan->c->topo.initial_apicid != sl.x2apic_id) {
+               pr_warn_once(FW_BUG "CPUID leaf 0x%x subleaf %d APIC ID mismatch %x != %x\n",
+                            leaf, subleaf, tscan->c->topo.initial_apicid, sl.x2apic_id);
+       }
+
+       topology_set_dom(tscan, dom, sl.x2apic_shift, sl.num_processors);
+       return true;
+}
+
+static bool parse_topology_leaf(struct topo_scan *tscan, u32 leaf)
+{
+       unsigned int last_dom;
+       u32 subleaf;
+
+       /* Read all available subleafs and populate the levels */
+       for (subleaf = 0, last_dom = 0; topo_subleaf(tscan, leaf, subleaf, &last_dom); subleaf++);
+
+       /* If subleaf 0 failed to parse, give up */
+       if (!subleaf)
+               return false;
+
+       /*
+        * There are machines in the wild which have shift 0 in the subleaf
+        * 0, but advertise 2 logical processors at that level. They are
+        * truly SMT.
+        */
+       if (!tscan->dom_shifts[TOPO_SMT_DOMAIN] && tscan->dom_ncpus[TOPO_SMT_DOMAIN] > 1) {
+               unsigned int sft = get_count_order(tscan->dom_ncpus[TOPO_SMT_DOMAIN]);
+
+               pr_warn_once(FW_BUG "CPUID leaf 0x%x subleaf 0 has shift level 0 but %u CPUs. Fixing it up.\n",
+                            leaf, tscan->dom_ncpus[TOPO_SMT_DOMAIN]);
+               topology_update_dom(tscan, TOPO_SMT_DOMAIN, sft, tscan->dom_ncpus[TOPO_SMT_DOMAIN]);
+       }
+
+       set_cpu_cap(tscan->c, X86_FEATURE_XTOPOLOGY);
+       return true;
+}
+
+bool cpu_parse_topology_ext(struct topo_scan *tscan)
+{
+       /* Intel: Try leaf 0x1F first. */
+       if (tscan->c->cpuid_level >= 0x1f && parse_topology_leaf(tscan, 0x1f))
+               return true;
+
+       /* Intel/AMD: Fall back to leaf 0xB if available */
+       return tscan->c->cpuid_level >= 0x0b && parse_topology_leaf(tscan, 0x0b);
+}
index 415564a6523b6e601bd4e51ae7e66aa5906a72be..90eba7eb53357153d4ad700a79bf0e7c4f9670f3 100644 (file)
@@ -71,10 +71,6 @@ static void init_zhaoxin(struct cpuinfo_x86 *c)
 {
        early_init_zhaoxin(c);
        init_intel_cacheinfo(c);
-       detect_num_cpu_cores(c);
-#ifdef CONFIG_X86_32
-       detect_ht(c);
-#endif
 
        if (c->cpuid_level > 9) {
                unsigned int eax = cpuid_eax(10);
index b6b044356f1b40599de1d41a1dfc5405ae2ca00c..e74d0c4286c14519728d6b62418ec627c8ef55db 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/vmalloc.h>
 #include <linux/memblock.h>
 
+#include <asm/bootparam.h>
 #include <asm/processor.h>
 #include <asm/hardirq.h>
 #include <asm/nmi.h>
@@ -40,6 +41,7 @@
 #include <asm/intel_pt.h>
 #include <asm/crash.h>
 #include <asm/cmdline.h>
+#include <asm/sev.h>
 
 /* Used while preparing memory map entries for second kernel */
 struct crash_memmap_data {
@@ -59,6 +61,8 @@ static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
         */
        cpu_emergency_stop_pt();
 
+       kdump_sev_callback();
+
        disable_local_APIC();
 }
 
index afd09924094eca5e444fd1beaf20c7e02f888e85..4aeafe63521b8367a644820e2858ef94730d8135 100644 (file)
@@ -136,7 +136,7 @@ static void __init dtb_cpu_setup(void)
                        pr_warn("%pOF: missing local APIC ID\n", dn);
                        continue;
                }
-               generic_processor_info(apic_id);
+               topology_register_apic(apic_id, CPU_ACPIID_INVALID, true);
        }
 }
 
@@ -302,7 +302,7 @@ void __init x86_flattree_get_config(void)
 }
 #endif
 
-void __init x86_dtb_init(void)
+void __init x86_dtb_parse_smp_config(void)
 {
        if (!of_have_populated_dt())
                return;
index f18ca44c904b747e68a3fdf0f7926a7025da71b7..44a91ef5a23b8e20247fd82d03aa2e046c147426 100644 (file)
@@ -410,7 +410,7 @@ static void __die_header(const char *str, struct pt_regs *regs, long err)
               IS_ENABLED(CONFIG_SMP)     ? " SMP"             : "",
               debug_pagealloc_enabled()  ? " DEBUG_PAGEALLOC" : "",
               IS_ENABLED(CONFIG_KASAN)   ? " KASAN"           : "",
-              IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION) ?
+              IS_ENABLED(CONFIG_MITIGATION_PAGE_TABLE_ISOLATION) ?
               (boot_cpu_has(X86_FEATURE_PTI) ? " PTI" : " NOPTI") : "");
 }
 NOKPROBE_SYMBOL(__die_header);
index fb8cf953380dab44a5426f78733a25452ade3b87..b66f540de054a72403dbe3b4a837d6b1e280610d 100644 (file)
@@ -1017,10 +1017,12 @@ void __init e820__reserve_setup_data(void)
                e820__range_update(pa_data, sizeof(*data)+data->len, E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
 
                /*
-                * SETUP_EFI and SETUP_IMA are supplied by kexec and do not need
-                * to be reserved.
+                * SETUP_EFI, SETUP_IMA and SETUP_RNG_SEED are supplied by
+                * kexec and do not need to be reserved.
                 */
-               if (data->type != SETUP_EFI && data->type != SETUP_IMA)
+               if (data->type != SETUP_EFI &&
+                   data->type != SETUP_IMA &&
+                   data->type != SETUP_RNG_SEED)
                        e820__range_update_kexec(pa_data,
                                                 sizeof(*data) + data->len,
                                                 E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
index 16f9814c9be02ccfb963b9581485de041427e2d2..6726e0473d0b40c0707660718effd047ea546d05 100644 (file)
@@ -106,6 +106,10 @@ void __init init_espfix_bsp(void)
        pgd_t *pgd;
        p4d_t *p4d;
 
+       /* FRED systems always restore the full value of %rsp */
+       if (cpu_feature_enabled(X86_FEATURE_FRED))
+               return;
+
        /* Install the espfix pud into the kernel page directory */
        pgd = &init_top_pgt[pgd_index(ESPFIX_BASE_ADDR)];
        p4d = p4d_alloc(&init_mm, pgd, ESPFIX_BASE_ADDR);
@@ -129,6 +133,10 @@ void init_espfix_ap(int cpu)
        void *stack_page;
        pteval_t ptemask;
 
+       /* FRED systems always restore the full value of %rsp */
+       if (cpu_feature_enabled(X86_FEATURE_FRED))
+               return;
+
        /* We only have to do this once... */
        if (likely(per_cpu(espfix_stack, cpu)))
                return;         /* Already initialized */
index a06b876bbf2d11a33e6dfb3d781c292a70884fbf..edbafc5940e33bc8d5df2a020d91d1855100f06b 100644 (file)
@@ -2,6 +2,8 @@
 /*
  * x86 FPU bug checks:
  */
+#include <linux/printk.h>
+
 #include <asm/cpufeature.h>
 #include <asm/fpu/api.h>
 
diff --git a/arch/x86/kernel/fred.c b/arch/x86/kernel/fred.c
new file mode 100644 (file)
index 0000000..4bcd879
--- /dev/null
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/kernel.h>
+
+#include <asm/desc.h>
+#include <asm/fred.h>
+#include <asm/tlbflush.h>
+#include <asm/traps.h>
+
+/* #DB in the kernel would imply the use of a kernel debugger. */
+#define FRED_DB_STACK_LEVEL            1UL
+#define FRED_NMI_STACK_LEVEL           2UL
+#define FRED_MC_STACK_LEVEL            2UL
+/*
+ * #DF is the highest level because a #DF means "something went wrong
+ * *while delivering an exception*." The number of cases for which that
+ * can happen with FRED is drastically reduced and basically amounts to
+ * "the stack you pointed me to is broken." Thus, always change stacks
+ * on #DF, which means it should be at the highest level.
+ */
+#define FRED_DF_STACK_LEVEL            3UL
+
+#define FRED_STKLVL(vector, lvl)       ((lvl) << (2 * (vector)))
+
+void cpu_init_fred_exceptions(void)
+{
+       /* When FRED is enabled by default, remove this log message */
+       pr_info("Initialize FRED on CPU%d\n", smp_processor_id());
+
+       wrmsrl(MSR_IA32_FRED_CONFIG,
+              /* Reserve for CALL emulation */
+              FRED_CONFIG_REDZONE |
+              FRED_CONFIG_INT_STKLVL(0) |
+              FRED_CONFIG_ENTRYPOINT(asm_fred_entrypoint_user));
+
+       /*
+        * The purpose of separate stacks for NMI, #DB and #MC *in the kernel*
+        * (remember that user space faults are always taken on stack level 0)
+        * is to avoid overflowing the kernel stack.
+        */
+       wrmsrl(MSR_IA32_FRED_STKLVLS,
+              FRED_STKLVL(X86_TRAP_DB,  FRED_DB_STACK_LEVEL) |
+              FRED_STKLVL(X86_TRAP_NMI, FRED_NMI_STACK_LEVEL) |
+              FRED_STKLVL(X86_TRAP_MC,  FRED_MC_STACK_LEVEL) |
+              FRED_STKLVL(X86_TRAP_DF,  FRED_DF_STACK_LEVEL));
+
+       /* The FRED equivalents to IST stacks... */
+       wrmsrl(MSR_IA32_FRED_RSP1, __this_cpu_ist_top_va(DB));
+       wrmsrl(MSR_IA32_FRED_RSP2, __this_cpu_ist_top_va(NMI));
+       wrmsrl(MSR_IA32_FRED_RSP3, __this_cpu_ist_top_va(DF));
+
+       /* Enable FRED */
+       cr4_set_bits(X86_CR4_FRED);
+       /* Any further IDT use is a bug */
+       idt_invalidate();
+
+       /* Use int $0x80 for 32-bit system calls in FRED mode */
+       setup_clear_cpu_cap(X86_FEATURE_SYSENTER32);
+       setup_clear_cpu_cap(X86_FEATURE_SYSCALL32);
+}
index 12df54ff0e817188d384affee8d98a515d6db471..70139d9d2e017316f7e7d015b52aeb86f7f1c580 100644 (file)
@@ -307,7 +307,8 @@ union ftrace_op_code_union {
        } __attribute__((packed));
 };
 
-#define RET_SIZE               (IS_ENABLED(CONFIG_RETPOLINE) ? 5 : 1 + IS_ENABLED(CONFIG_SLS))
+#define RET_SIZE \
+       (IS_ENABLED(CONFIG_MITIGATION_RETPOLINE) ? 5 : 1 + IS_ENABLED(CONFIG_MITIGATION_SLS))
 
 static unsigned long
 create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
index dc0956067944dc6332dc52a50756460e5b3ff69f..212e8e06aeba23231a1dced48da0cdfe1c729c86 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/cc_platform.h>
 #include <linux/pgtable.h>
 
+#include <asm/asm.h>
+#include <asm/page_64.h>
 #include <asm/processor.h>
 #include <asm/proto.h>
 #include <asm/smp.h>
@@ -67,42 +69,11 @@ unsigned long vmemmap_base __ro_after_init = __VMEMMAP_BASE_L4;
 EXPORT_SYMBOL(vmemmap_base);
 #endif
 
-/*
- * GDT used on the boot CPU before switching to virtual addresses.
- */
-static struct desc_struct startup_gdt[GDT_ENTRIES] __initdata = {
-       [GDT_ENTRY_KERNEL32_CS]         = GDT_ENTRY_INIT(DESC_CODE32, 0, 0xfffff),
-       [GDT_ENTRY_KERNEL_CS]           = GDT_ENTRY_INIT(DESC_CODE64, 0, 0xfffff),
-       [GDT_ENTRY_KERNEL_DS]           = GDT_ENTRY_INIT(DESC_DATA64, 0, 0xfffff),
-};
-
-/*
- * Address needs to be set at runtime because it references the startup_gdt
- * while the kernel still uses a direct mapping.
- */
-static struct desc_ptr startup_gdt_descr __initdata = {
-       .size = sizeof(startup_gdt)-1,
-       .address = 0,
-};
-
-static void __head *fixup_pointer(void *ptr, unsigned long physaddr)
-{
-       return ptr - (void *)_text + (void *)physaddr;
-}
-
-static unsigned long __head *fixup_long(void *ptr, unsigned long physaddr)
-{
-       return fixup_pointer(ptr, physaddr);
-}
-
-#ifdef CONFIG_X86_5LEVEL
-static unsigned int __head *fixup_int(void *ptr, unsigned long physaddr)
+static inline bool check_la57_support(void)
 {
-       return fixup_pointer(ptr, physaddr);
-}
+       if (!IS_ENABLED(CONFIG_X86_5LEVEL))
+               return false;
 
-static bool __head check_la57_support(unsigned long physaddr)
-{
        /*
         * 5-level paging is detected and enabled at kernel decompression
         * stage. Only check if it has been enabled there.
@@ -110,21 +81,8 @@ static bool __head check_la57_support(unsigned long physaddr)
        if (!(native_read_cr4() & X86_CR4_LA57))
                return false;
 
-       *fixup_int(&__pgtable_l5_enabled, physaddr) = 1;
-       *fixup_int(&pgdir_shift, physaddr) = 48;
-       *fixup_int(&ptrs_per_p4d, physaddr) = 512;
-       *fixup_long(&page_offset_base, physaddr) = __PAGE_OFFSET_BASE_L5;
-       *fixup_long(&vmalloc_base, physaddr) = __VMALLOC_BASE_L5;
-       *fixup_long(&vmemmap_base, physaddr) = __VMEMMAP_BASE_L5;
-
        return true;
 }
-#else
-static bool __head check_la57_support(unsigned long physaddr)
-{
-       return false;
-}
-#endif
 
 static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdval_t *pmd)
 {
@@ -173,23 +131,22 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv
  * doesn't have to generate PC-relative relocations when accessing globals from
  * that function. Clang actually does not generate them, which leads to
  * boot-time crashes. To work around this problem, every global pointer must
- * be adjusted using fixup_pointer().
+ * be accessed using RIP_REL_REF().
  */
 unsigned long __head __startup_64(unsigned long physaddr,
                                  struct boot_params *bp)
 {
-       unsigned long load_delta, *p;
+       pmd_t (*early_pgts)[PTRS_PER_PMD] = RIP_REL_REF(early_dynamic_pgts);
        unsigned long pgtable_flags;
+       unsigned long load_delta;
        pgdval_t *pgd;
        p4dval_t *p4d;
        pudval_t *pud;
        pmdval_t *pmd, pmd_entry;
-       pteval_t *mask_ptr;
        bool la57;
        int i;
-       unsigned int *next_pgt_ptr;
 
-       la57 = check_la57_support(physaddr);
+       la57 = check_la57_support();
 
        /* Is the address too large? */
        if (physaddr >> MAX_PHYSMEM_BITS)
@@ -200,6 +157,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
         * and the address I am actually running at.
         */
        load_delta = physaddr - (unsigned long)(_text - __START_KERNEL_map);
+       RIP_REL_REF(phys_base) = load_delta;
 
        /* Is the address not 2M aligned? */
        if (load_delta & ~PMD_MASK)
@@ -210,26 +168,21 @@ unsigned long __head __startup_64(unsigned long physaddr,
 
        /* Fixup the physical addresses in the page table */
 
-       pgd = fixup_pointer(early_top_pgt, physaddr);
-       p = pgd + pgd_index(__START_KERNEL_map);
-       if (la57)
-               *p = (unsigned long)level4_kernel_pgt;
-       else
-               *p = (unsigned long)level3_kernel_pgt;
-       *p += _PAGE_TABLE_NOENC - __START_KERNEL_map + load_delta;
+       pgd = &RIP_REL_REF(early_top_pgt)->pgd;
+       pgd[pgd_index(__START_KERNEL_map)] += load_delta;
 
        if (la57) {
-               p4d = fixup_pointer(level4_kernel_pgt, physaddr);
-               p4d[511] += load_delta;
+               p4d = (p4dval_t *)&RIP_REL_REF(level4_kernel_pgt);
+               p4d[MAX_PTRS_PER_P4D - 1] += load_delta;
+
+               pgd[pgd_index(__START_KERNEL_map)] = (pgdval_t)p4d | _PAGE_TABLE_NOENC;
        }
 
-       pud = fixup_pointer(level3_kernel_pgt, physaddr);
-       pud[510] += load_delta;
-       pud[511] += load_delta;
+       RIP_REL_REF(level3_kernel_pgt)[PTRS_PER_PUD - 2].pud += load_delta;
+       RIP_REL_REF(level3_kernel_pgt)[PTRS_PER_PUD - 1].pud += load_delta;
 
-       pmd = fixup_pointer(level2_fixmap_pgt, physaddr);
        for (i = FIXMAP_PMD_TOP; i > FIXMAP_PMD_TOP - FIXMAP_PMD_NUM; i--)
-               pmd[i] += load_delta;
+               RIP_REL_REF(level2_fixmap_pgt)[i].pmd += load_delta;
 
        /*
         * Set up the identity mapping for the switchover.  These
@@ -238,15 +191,14 @@ unsigned long __head __startup_64(unsigned long physaddr,
         * it avoids problems around wraparound.
         */
 
-       next_pgt_ptr = fixup_pointer(&next_early_pgt, physaddr);
-       pud = fixup_pointer(early_dynamic_pgts[(*next_pgt_ptr)++], physaddr);
-       pmd = fixup_pointer(early_dynamic_pgts[(*next_pgt_ptr)++], physaddr);
+       pud = &early_pgts[0]->pmd;
+       pmd = &early_pgts[1]->pmd;
+       RIP_REL_REF(next_early_pgt) = 2;
 
        pgtable_flags = _KERNPG_TABLE_NOENC + sme_get_me_mask();
 
        if (la57) {
-               p4d = fixup_pointer(early_dynamic_pgts[(*next_pgt_ptr)++],
-                                   physaddr);
+               p4d = &early_pgts[RIP_REL_REF(next_early_pgt)++]->pmd;
 
                i = (physaddr >> PGDIR_SHIFT) % PTRS_PER_PGD;
                pgd[i + 0] = (pgdval_t)p4d + pgtable_flags;
@@ -267,8 +219,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
 
        pmd_entry = __PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL;
        /* Filter out unsupported __PAGE_KERNEL_* bits: */
-       mask_ptr = fixup_pointer(&__supported_pte_mask, physaddr);
-       pmd_entry &= *mask_ptr;
+       pmd_entry &= RIP_REL_REF(__supported_pte_mask);
        pmd_entry += sme_get_me_mask();
        pmd_entry +=  physaddr;
 
@@ -294,7 +245,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
         * error, causing the BIOS to halt the system.
         */
 
-       pmd = fixup_pointer(level2_kernel_pgt, physaddr);
+       pmd = &RIP_REL_REF(level2_kernel_pgt)->pmd;
 
        /* invalidate pages before the kernel image */
        for (i = 0; i < pmd_index((unsigned long)_text); i++)
@@ -309,12 +260,6 @@ unsigned long __head __startup_64(unsigned long physaddr,
        for (; i < PTRS_PER_PMD; i++)
                pmd[i] &= ~_PAGE_PRESENT;
 
-       /*
-        * Fixup phys_base - remove the memory encryption mask to obtain
-        * the true physical address.
-        */
-       *fixup_long(&phys_base, physaddr) += load_delta - sme_get_me_mask();
-
        return sme_postprocess_startup(bp, pmd);
 }
 
@@ -486,6 +431,15 @@ asmlinkage __visible void __init __noreturn x86_64_start_kernel(char * real_mode
                                (__START_KERNEL & PGDIR_MASK)));
        BUILD_BUG_ON(__fix_to_virt(__end_of_fixed_addresses) <= MODULES_END);
 
+       if (check_la57_support()) {
+               __pgtable_l5_enabled    = 1;
+               pgdir_shift             = 48;
+               ptrs_per_p4d            = 512;
+               page_offset_base        = __PAGE_OFFSET_BASE_L5;
+               vmalloc_base            = __VMALLOC_BASE_L5;
+               vmemmap_base            = __VMEMMAP_BASE_L5;
+       }
+
        cr4_init_shadow();
 
        /* Kill off the identity-map trampoline */
@@ -569,62 +523,52 @@ void __init __noreturn x86_64_start_reservations(char *real_mode_data)
  */
 static gate_desc bringup_idt_table[NUM_EXCEPTION_VECTORS] __page_aligned_data;
 
-static struct desc_ptr bringup_idt_descr = {
-       .size           = (NUM_EXCEPTION_VECTORS * sizeof(gate_desc)) - 1,
-       .address        = 0, /* Set at runtime */
-};
-
-static void set_bringup_idt_handler(gate_desc *idt, int n, void *handler)
+/* This may run while still in the direct mapping */
+static void __head startup_64_load_idt(void *vc_handler)
 {
-#ifdef CONFIG_AMD_MEM_ENCRYPT
+       struct desc_ptr desc = {
+               .address = (unsigned long)&RIP_REL_REF(bringup_idt_table),
+               .size    = sizeof(bringup_idt_table) - 1,
+       };
        struct idt_data data;
-       gate_desc desc;
-
-       init_idt_data(&data, n, handler);
-       idt_init_desc(&desc, &data);
-       native_write_idt_entry(idt, n, &desc);
-#endif
-}
+       gate_desc idt_desc;
 
-/* This runs while still in the direct mapping */
-static void __head startup_64_load_idt(unsigned long physbase)
-{
-       struct desc_ptr *desc = fixup_pointer(&bringup_idt_descr, physbase);
-       gate_desc *idt = fixup_pointer(bringup_idt_table, physbase);
-
-
-       if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
-               void *handler;
-
-               /* VMM Communication Exception */
-               handler = fixup_pointer(vc_no_ghcb, physbase);
-               set_bringup_idt_handler(idt, X86_TRAP_VC, handler);
+       /* @vc_handler is set only for a VMM Communication Exception */
+       if (vc_handler) {
+               init_idt_data(&data, X86_TRAP_VC, vc_handler);
+               idt_init_desc(&idt_desc, &data);
+               native_write_idt_entry((gate_desc *)desc.address, X86_TRAP_VC, &idt_desc);
        }
 
-       desc->address = (unsigned long)idt;
-       native_load_idt(desc);
+       native_load_idt(&desc);
 }
 
 /* This is used when running on kernel addresses */
 void early_setup_idt(void)
 {
-       /* VMM Communication Exception */
+       void *handler = NULL;
+
        if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
                setup_ghcb();
-               set_bringup_idt_handler(bringup_idt_table, X86_TRAP_VC, vc_boot_ghcb);
+               handler = vc_boot_ghcb;
        }
 
-       bringup_idt_descr.address = (unsigned long)bringup_idt_table;
-       native_load_idt(&bringup_idt_descr);
+       startup_64_load_idt(handler);
 }
 
 /*
  * Setup boot CPU state needed before kernel switches to virtual addresses.
  */
-void __head startup_64_setup_env(unsigned long physbase)
+void __head startup_64_setup_gdt_idt(void)
 {
+       void *handler = NULL;
+
+       struct desc_ptr startup_gdt_descr = {
+               .address = (unsigned long)&RIP_REL_REF(init_per_cpu_var(gdt_page.gdt)),
+               .size    = GDT_SIZE - 1,
+       };
+
        /* Load GDT */
-       startup_gdt_descr.address = (unsigned long)fixup_pointer(startup_gdt, physbase);
        native_load_gdt(&startup_gdt_descr);
 
        /* New GDT is live - reload data segment registers */
@@ -632,5 +576,8 @@ void __head startup_64_setup_env(unsigned long physbase)
                     "movl %%eax, %%ss\n"
                     "movl %%eax, %%es\n" : : "a"(__KERNEL_DS) : "memory");
 
-       startup_64_load_idt(physbase);
+       if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT))
+               handler = &RIP_REL_REF(vc_no_ghcb);
+
+       startup_64_load_idt(handler);
 }
index 487ac57e2c81fbcdfc80ac67c40db2826c69ec05..b50f3641c4d6de0d576efca319432640cf83cd08 100644 (file)
@@ -414,7 +414,7 @@ __REFDATA
        .align 4
 SYM_DATA(initial_code,         .long i386_start_kernel)
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 #define        PGD_ALIGN       (2 * PAGE_SIZE)
 #define PTI_USER_PGD_FILL      1024
 #else
@@ -474,7 +474,7 @@ SYM_DATA_START(initial_page_table)
 # endif
        .align PAGE_SIZE                /* needs to be page-sized too */
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
        /*
         * PTI needs another page so sync_initial_pagetable() works correctly
         * and does not scribble over the data which is placed behind the
index d4918d03efb4b7765bff35d3e5f28a8c3a2bc99d..d8198fbd70e54ea9da8355614b7b05963acb6cdf 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/apicdef.h>
 #include <asm/fixmap.h>
 #include <asm/smp.h>
+#include <asm/thread_info.h>
 
 /*
  * We are not able to switch in one step to the final KERNEL ADDRESS SPACE
@@ -39,7 +40,6 @@ L4_START_KERNEL = l4_index(__START_KERNEL_map)
 
 L3_START_KERNEL = pud_index(__START_KERNEL_map)
 
-       .text
        __HEAD
        .code64
 SYM_CODE_START_NOALIGN(startup_64)
@@ -66,9 +66,7 @@ SYM_CODE_START_NOALIGN(startup_64)
        mov     %rsi, %r15
 
        /* Set up the stack for verify_cpu() */
-       leaq    (__end_init_task - PTREGS_SIZE)(%rip), %rsp
-
-       leaq    _text(%rip), %rdi
+       leaq    (__end_init_task - TOP_OF_KERNEL_STACK_PADDING - PTREGS_SIZE)(%rip), %rsp
 
        /* Setup GSBASE to allow stack canary access for C code */
        movl    $MSR_GS_BASE, %ecx
@@ -77,7 +75,7 @@ SYM_CODE_START_NOALIGN(startup_64)
        shrq    $32,  %rdx
        wrmsr
 
-       call    startup_64_setup_env
+       call    startup_64_setup_gdt_idt
 
        /* Now switch to __KERNEL_CS so IRET works reliably */
        pushq   $__KERNEL_CS
@@ -113,13 +111,11 @@ SYM_CODE_START_NOALIGN(startup_64)
        call    __startup_64
 
        /* Form the CR3 value being sure to include the CR3 modifier */
-       addq    $(early_top_pgt - __START_KERNEL_map), %rax
+       leaq    early_top_pgt(%rip), %rcx
+       addq    %rcx, %rax
 
 #ifdef CONFIG_AMD_MEM_ENCRYPT
        mov     %rax, %rdi
-       mov     %rax, %r14
-
-       addq    phys_base(%rip), %rdi
 
        /*
         * For SEV guests: Verify that the C-bit is correct. A malicious
@@ -128,17 +124,23 @@ SYM_CODE_START_NOALIGN(startup_64)
         * the next RET instruction.
         */
        call    sev_verify_cbit
+#endif
 
        /*
-        * Restore CR3 value without the phys_base which will be added
-        * below, before writing %cr3.
+        * Switch to early_top_pgt which still has the identity mappings
+        * present.
         */
-        mov    %r14, %rax
-#endif
+       movq    %rax, %cr3
 
-       jmp 1f
+       /* Branch to the common startup code at its kernel virtual address */
+       ANNOTATE_RETPOLINE_SAFE
+       jmp     *0f(%rip)
 SYM_CODE_END(startup_64)
 
+       __INITRODATA
+0:     .quad   common_startup_64
+
+       .text
 SYM_CODE_START(secondary_startup_64)
        UNWIND_HINT_END_OF_STACK
        ANNOTATE_NOENDBR
@@ -171,22 +173,39 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
        ANNOTATE_NOENDBR
 
        /* Clear %R15 which holds the boot_params pointer on the boot CPU */
-       xorq    %r15, %r15
+       xorl    %r15d, %r15d
+
+       /* Derive the runtime physical address of init_top_pgt[] */
+       movq    phys_base(%rip), %rax
+       addq    $(init_top_pgt - __START_KERNEL_map), %rax
 
        /*
         * Retrieve the modifier (SME encryption mask if SME is active) to be
         * added to the initial pgdir entry that will be programmed into CR3.
         */
 #ifdef CONFIG_AMD_MEM_ENCRYPT
-       movq    sme_me_mask, %rax
-#else
-       xorq    %rax, %rax
+       addq    sme_me_mask(%rip), %rax
 #endif
+       /*
+        * Switch to the init_top_pgt here, away from the trampoline_pgd and
+        * unmap the identity mapped ranges.
+        */
+       movq    %rax, %cr3
 
-       /* Form the CR3 value being sure to include the CR3 modifier */
-       addq    $(init_top_pgt - __START_KERNEL_map), %rax
-1:
+SYM_INNER_LABEL(common_startup_64, SYM_L_LOCAL)
+       UNWIND_HINT_END_OF_STACK
+       ANNOTATE_NOENDBR
 
+       /*
+        * Create a mask of CR4 bits to preserve. Omit PGE in order to flush
+        * global 1:1 translations from the TLBs.
+        *
+        * From the SDM:
+        * "If CR4.PGE is changing from 0 to 1, there were no global TLB
+        *  entries before the execution; if CR4.PGE is changing from 1 to 0,
+        *  there will be no global TLB entries after the execution."
+        */
+       movl    $(X86_CR4_PAE | X86_CR4_LA57), %edx
 #ifdef CONFIG_X86_MCE
        /*
         * Preserve CR4.MCE if the kernel will enable #MC support.
@@ -195,52 +214,20 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
         * configured will crash the system regardless of the CR4.MCE value set
         * here.
         */
-       movq    %cr4, %rcx
-       andl    $X86_CR4_MCE, %ecx
-#else
-       movl    $0, %ecx
+       orl     $X86_CR4_MCE, %edx
 #endif
+       movq    %cr4, %rcx
+       andl    %edx, %ecx
 
-       /* Enable PAE mode, PSE, PGE and LA57 */
-       orl     $(X86_CR4_PAE | X86_CR4_PSE | X86_CR4_PGE), %ecx
-#ifdef CONFIG_X86_5LEVEL
-       testb   $1, __pgtable_l5_enabled(%rip)
-       jz      1f
-       orl     $X86_CR4_LA57, %ecx
-1:
-#endif
+       /* Even if ignored in long mode, set PSE uniformly on all logical CPUs. */
+       btsl    $X86_CR4_PSE_BIT, %ecx
        movq    %rcx, %cr4
 
-       /* Setup early boot stage 4-/5-level pagetables. */
-       addq    phys_base(%rip), %rax
-
        /*
-        * Switch to new page-table
-        *
-        * For the boot CPU this switches to early_top_pgt which still has the
-        * identity mappings present. The secondary CPUs will switch to the
-        * init_top_pgt here, away from the trampoline_pgd and unmap the
-        * identity mapped ranges.
+        * Set CR4.PGE to re-enable global translations.
         */
-       movq    %rax, %cr3
-
-       /*
-        * Do a global TLB flush after the CR3 switch to make sure the TLB
-        * entries from the identity mapping are flushed.
-        */
-       movq    %cr4, %rcx
-       movq    %rcx, %rax
-       xorq    $X86_CR4_PGE, %rcx
+       btsl    $X86_CR4_PGE_BIT, %ecx
        movq    %rcx, %cr4
-       movq    %rax, %cr4
-
-       /* Ensure I am executing from virtual addresses */
-       movq    $1f, %rax
-       ANNOTATE_RETPOLINE_SAFE
-       jmp     *%rax
-1:
-       UNWIND_HINT_END_OF_STACK
-       ANNOTATE_NOENDBR // above
 
 #ifdef CONFIG_SMP
        /*
@@ -297,7 +284,7 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
 
 .Llookup_AP:
        /* EAX contains the APIC ID of the current CPU */
-       xorq    %rcx, %rcx
+       xorl    %ecx, %ecx
        leaq    cpuid_to_apicid(%rip), %rbx
 
 .Lfind_cpunr:
@@ -428,39 +415,10 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
        movq    %r15, %rdi
 
 .Ljump_to_C_code:
-       /*
-        * Jump to run C code and to be on a real kernel address.
-        * Since we are running on identity-mapped space we have to jump
-        * to the full 64bit address, this is only possible as indirect
-        * jump.  In addition we need to ensure %cs is set so we make this
-        * a far return.
-        *
-        * Note: do not change to far jump indirect with 64bit offset.
-        *
-        * AMD does not support far jump indirect with 64bit offset.
-        * AMD64 Architecture Programmer's Manual, Volume 3: states only
-        *      JMP FAR mem16:16 FF /5 Far jump indirect,
-        *              with the target specified by a far pointer in memory.
-        *      JMP FAR mem16:32 FF /5 Far jump indirect,
-        *              with the target specified by a far pointer in memory.
-        *
-        * Intel64 does support 64bit offset.
-        * Software Developer Manual Vol 2: states:
-        *      FF /5 JMP m16:16 Jump far, absolute indirect,
-        *              address given in m16:16
-        *      FF /5 JMP m16:32 Jump far, absolute indirect,
-        *              address given in m16:32.
-        *      REX.W + FF /5 JMP m16:64 Jump far, absolute indirect,
-        *              address given in m16:64.
-        */
-       pushq   $.Lafter_lret   # put return address on stack for unwinder
        xorl    %ebp, %ebp      # clear frame pointer
-       movq    initial_code(%rip), %rax
-       pushq   $__KERNEL_CS    # set correct cs
-       pushq   %rax            # target address in negative space
-       lretq
-.Lafter_lret:
-       ANNOTATE_NOENDBR
+       ANNOTATE_RETPOLINE_SAFE
+       callq   *initial_code(%rip)
+       ud2
 SYM_CODE_END(secondary_startup_64)
 
 #include "verify_cpu.S"
@@ -477,7 +435,7 @@ SYM_CODE_START(soft_restart_cpu)
        UNWIND_HINT_END_OF_STACK
 
        /* Find the idle task stack */
-       movq    PER_CPU_VAR(pcpu_hot) + X86_current_task, %rcx
+       movq    PER_CPU_VAR(pcpu_hot + X86_current_task), %rcx
        movq    TASK_threadsp(%rcx), %rsp
 
        jmp     .Ljump_to_C_code
@@ -622,7 +580,7 @@ SYM_CODE_END(vc_no_ghcb)
 #define SYM_DATA_START_PAGE_ALIGNED(name)                      \
        SYM_START(name, SYM_L_GLOBAL, .balign PAGE_SIZE)
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 /*
  * Each PGD needs to be 8k long and 8k aligned.  We do not
  * ever go out to userspace with these, so we do not
@@ -655,7 +613,8 @@ SYM_CODE_END(vc_no_ghcb)
        .balign 4
 
 SYM_DATA_START_PTI_ALIGNED(early_top_pgt)
-       .fill   512,8,0
+       .fill   511,8,0
+       .quad   level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC
        .fill   PTI_USER_PGD_FILL,8,0
 SYM_DATA_END(early_top_pgt)
 
index a38d0c93a66e825a38987a65fdd09ad97bbae2ec..c96ae8fee95e443b262c1083fe0a9f96e4e6a67c 100644 (file)
@@ -568,7 +568,7 @@ static struct irq_domain *hpet_create_irq_domain(int hpet_id)
        fwspec.param_count = 1;
        fwspec.param[0] = hpet_id;
 
-       parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_ANY);
+       parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_GENERIC_MSI);
        if (!parent) {
                irq_domain_free_fwnode(fn);
                kfree(domain_info);
index 660b601f1d6c33e9ad62ec2d12d860e92d4ea420..0cd53fa8c65d1d63ed4a11a7a2f7c88ba4122d51 100644 (file)
@@ -337,7 +337,7 @@ void idt_invalidate(void)
        load_idt(&idt);
 }
 
-void __init alloc_intr_gate(unsigned int n, const void *addr)
+void __init idt_install_sysvec(unsigned int n, const void *function)
 {
        if (WARN_ON(n < FIRST_SYSTEM_VECTOR))
                return;
@@ -346,5 +346,5 @@ void __init alloc_intr_gate(unsigned int n, const void *addr)
                return;
 
        if (!WARN_ON(test_and_set_bit(n, system_vectors)))
-               set_intr_gate(n, addr);
+               set_intr_gate(n, function);
 }
index c683666876f1c7026acf5b4d63b93381181e1801..f79c5edc0b892da8e3dff9afda2324ae0dae5944 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/setup.h>
 #include <asm/i8259.h>
 #include <asm/traps.h>
+#include <asm/fred.h>
 #include <asm/prom.h>
 
 /*
@@ -96,7 +97,11 @@ void __init native_init_IRQ(void)
        /* Execute any quirks before the call gates are initialised: */
        x86_init.irqs.pre_vector_init();
 
-       idt_setup_apic_and_irq_gates();
+       if (cpu_feature_enabled(X86_FEATURE_FRED))
+               fred_complete_exception_setup();
+       else
+               idt_setup_apic_and_irq_gates();
+
        lapic_assign_system_vectors();
 
        if (!acpi_ioapic && !of_ioapic && nr_legacy_irqs()) {
index 578d16fc040fa1eadf31344b81877c1ed343b2cf..df337860612d844c668b5dcda8c308fa0c61480c 100644 (file)
@@ -89,7 +89,7 @@ static void __init jailhouse_x2apic_init(void)
 #endif
 }
 
-static void __init jailhouse_get_smp_config(unsigned int early)
+static void __init jailhouse_parse_smp_config(void)
 {
        struct ioapic_domain_cfg ioapic_cfg = {
                .type = IOAPIC_DOMAIN_STRICT,
@@ -102,7 +102,7 @@ static void __init jailhouse_get_smp_config(unsigned int early)
        register_lapic_address(0xfee00000);
 
        for (cpu = 0; cpu < setup_data.v1.num_cpus; cpu++)
-               generic_processor_info(setup_data.v1.cpu_ids[cpu]);
+               topology_register_apic(setup_data.v1.cpu_ids[cpu], CPU_ACPIID_INVALID, true);
 
        smp_found_config = 1;
 
@@ -201,21 +201,23 @@ static void __init jailhouse_init_platform(void)
        struct setup_data header;
        void *mapping;
 
-       x86_init.irqs.pre_vector_init   = x86_init_noop;
-       x86_init.timers.timer_init      = jailhouse_timer_init;
-       x86_init.mpparse.get_smp_config = jailhouse_get_smp_config;
-       x86_init.pci.arch_init          = jailhouse_pci_arch_init;
+       x86_init.irqs.pre_vector_init           = x86_init_noop;
+       x86_init.timers.timer_init              = jailhouse_timer_init;
+       x86_init.mpparse.find_mptable           = x86_init_noop;
+       x86_init.mpparse.early_parse_smp_cfg    = x86_init_noop;
+       x86_init.mpparse.parse_smp_cfg          = jailhouse_parse_smp_config;
+       x86_init.pci.arch_init                  = jailhouse_pci_arch_init;
 
-       x86_platform.calibrate_cpu      = jailhouse_get_tsc;
-       x86_platform.calibrate_tsc      = jailhouse_get_tsc;
-       x86_platform.get_wallclock      = jailhouse_get_wallclock;
-       x86_platform.legacy.rtc         = 0;
-       x86_platform.legacy.warm_reset  = 0;
-       x86_platform.legacy.i8042       = X86_LEGACY_I8042_PLATFORM_ABSENT;
+       x86_platform.calibrate_cpu              = jailhouse_get_tsc;
+       x86_platform.calibrate_tsc              = jailhouse_get_tsc;
+       x86_platform.get_wallclock              = jailhouse_get_wallclock;
+       x86_platform.legacy.rtc                 = 0;
+       x86_platform.legacy.warm_reset          = 0;
+       x86_platform.legacy.i8042               = X86_LEGACY_I8042_PLATFORM_ABSENT;
 
-       legacy_pic                      = &null_legacy_pic;
+       legacy_pic                              = &null_legacy_pic;
 
-       machine_ops.emergency_restart   = jailhouse_no_restart;
+       machine_ops.emergency_restart           = jailhouse_no_restart;
 
        while (pa_data) {
                mapping = early_memremap(pa_data, sizeof(header));
index 2a422e00ed4b42f7921c238a47702d47bf8888c5..cde167b0ea92adb08115bb359b2284ea3e6acbe0 100644 (file)
@@ -503,7 +503,10 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
        kbuf.bufsz =  kernel_len - kern16_size;
        kbuf.memsz = PAGE_ALIGN(header->init_size);
        kbuf.buf_align = header->kernel_alignment;
-       kbuf.buf_min = MIN_KERNEL_LOAD_ADDR;
+       if (header->pref_address < MIN_KERNEL_LOAD_ADDR)
+               kbuf.buf_min = MIN_KERNEL_LOAD_ADDR;
+       else
+               kbuf.buf_min = header->pref_address;
        kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
        ret = kexec_add_buffer(&kbuf);
        if (ret)
index 517821b48391aadf63b49d42783dd7f09f5f2bfa..36d6809c6c9e1a74d879285bd835958087c1a5ee 100644 (file)
@@ -324,7 +324,7 @@ static int can_optimize(unsigned long paddr)
                 * However, the kernel built with retpolines or IBT has jump
                 * tables disabled so the check can be skipped altogether.
                 */
-               if (!IS_ENABLED(CONFIG_RETPOLINE) &&
+               if (!IS_ENABLED(CONFIG_MITIGATION_RETPOLINE) &&
                    !IS_ENABLED(CONFIG_X86_KERNEL_IBT) &&
                    insn_is_indirect_jump(&insn))
                        return 0;
index 428ee74002e1eac63d0e269510f536ba2644c3f7..101a7c1bf200859072037fd2da470441d27c053c 100644 (file)
@@ -830,7 +830,7 @@ static void __init kvm_guest_init(void)
 
        if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF_INT) && kvmapf) {
                static_branch_enable(&kvm_async_pf_enabled);
-               alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, asm_sysvec_kvm_asyncpf_interrupt);
+               sysvec_install(HYPERVISOR_CALLBACK_VECTOR, sysvec_kvm_asyncpf_interrupt);
        }
 
 #ifdef CONFIG_SMP
index 5bb395551c441ebc71c1e40ec355eac3f34dac69..5b2c15214a6bdcd9f4e62fce233fe2371efdbb81 100644 (file)
@@ -154,15 +154,15 @@ static int kvm_cs_enable(struct clocksource *cs)
        return 0;
 }
 
-struct clocksource kvm_clock = {
+static struct clocksource kvm_clock = {
        .name   = "kvm-clock",
        .read   = kvm_clock_get_cycles,
        .rating = 400,
        .mask   = CLOCKSOURCE_MASK(64),
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+       .id     = CSID_X86_KVM_CLK,
        .enable = kvm_cs_enable,
 };
-EXPORT_SYMBOL_GPL(kvm_clock);
 
 static void kvm_register_clock(char *txt)
 {
index 7a814b41402de551041f24e4fc96047d780d816c..0f19ef355f5f1ffb5eba0f5fd25351263ea9fd3b 100644 (file)
@@ -184,7 +184,7 @@ static struct ldt_struct *alloc_ldt_struct(unsigned int num_entries)
        return new_ldt;
 }
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 
 static void do_sanity_check(struct mm_struct *mm,
                            bool had_kernel_mapping,
@@ -377,7 +377,7 @@ static void unmap_ldt_struct(struct mm_struct *mm, struct ldt_struct *ldt)
        flush_tlb_mm_range(mm, va, va + nr_pages * PAGE_SIZE, PAGE_SHIFT, false);
 }
 
-#else /* !CONFIG_PAGE_TABLE_ISOLATION */
+#else /* !CONFIG_MITIGATION_PAGE_TABLE_ISOLATION */
 
 static int
 map_ldt_struct(struct mm_struct *mm, struct ldt_struct *ldt, int slot)
@@ -388,11 +388,11 @@ map_ldt_struct(struct mm_struct *mm, struct ldt_struct *ldt, int slot)
 static void unmap_ldt_struct(struct mm_struct *mm, struct ldt_struct *ldt)
 {
 }
-#endif /* CONFIG_PAGE_TABLE_ISOLATION */
+#endif /* CONFIG_MITIGATION_PAGE_TABLE_ISOLATION */
 
 static void free_ldt_pgtables(struct mm_struct *mm)
 {
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
        struct mmu_gather tlb;
        unsigned long start = LDT_BASE_ADDR;
        unsigned long end = LDT_END_ADDR;
index b223922248e9f0af271a0fa69b19afb495b9840f..1ccd30c8246faad1a2322081d030681ea8578288 100644 (file)
@@ -36,6 +36,8 @@
  * Checksum an MP configuration block.
  */
 
+static unsigned int num_procs __initdata;
+
 static int __init mpf_checksum(unsigned char *mp, int len)
 {
        int sum = 0;
@@ -50,16 +52,15 @@ static void __init MP_processor_info(struct mpc_cpu *m)
 {
        char *bootup_cpu = "";
 
-       if (!(m->cpuflag & CPU_ENABLED)) {
-               disabled_cpus++;
+       topology_register_apic(m->apicid, CPU_ACPIID_INVALID, m->cpuflag & CPU_ENABLED);
+       if (!(m->cpuflag & CPU_ENABLED))
                return;
-       }
 
        if (m->cpuflag & CPU_BOOTPROCESSOR)
                bootup_cpu = " (Bootup-CPU)";
 
        pr_info("Processor #%d%s\n", m->apicid, bootup_cpu);
-       generic_processor_info(m->apicid);
+       num_procs++;
 }
 
 #ifdef CONFIG_X86_IO_APIC
@@ -236,9 +237,9 @@ static int __init smp_read_mpc(struct mpc_table *mpc, unsigned early)
                }
        }
 
-       if (!num_processors)
+       if (!num_procs && !acpi_lapic)
                pr_err("MPTABLE: no processors registered!\n");
-       return num_processors;
+       return num_procs || acpi_lapic;
 }
 
 #ifdef CONFIG_X86_IO_APIC
@@ -473,7 +474,7 @@ static int __init check_physptr(struct mpf_intel *mpf, unsigned int early)
 /*
  * Scan the memory blocks for an SMP configuration block.
  */
-void __init default_get_smp_config(unsigned int early)
+static __init void mpparse_get_smp_config(unsigned int early)
 {
        struct mpf_intel *mpf;
 
@@ -529,8 +530,8 @@ void __init default_get_smp_config(unsigned int early)
        } else
                BUG();
 
-       if (!early)
-               pr_info("Processors: %d\n", num_processors);
+       if (!early && !acpi_lapic)
+               pr_info("Processors: %d\n", num_procs);
        /*
         * Only use the first configuration found.
         */
@@ -538,6 +539,16 @@ out:
        early_memunmap(mpf, sizeof(*mpf));
 }
 
+void __init mpparse_parse_early_smp_config(void)
+{
+       mpparse_get_smp_config(true);
+}
+
+void __init mpparse_parse_smp_config(void)
+{
+       mpparse_get_smp_config(false);
+}
+
 static void __init smp_reserve_memory(struct mpf_intel *mpf)
 {
        memblock_reserve(mpf->physptr, get_mpc_size(mpf->physptr));
@@ -587,7 +598,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length)
        return ret;
 }
 
-void __init default_find_smp_config(void)
+void __init mpparse_find_mptable(void)
 {
        unsigned int address;
 
index 17e955ab69feda933cca3708822f6f9f598e31bf..9a5b372c706fccb15aea2375a5424461a201d716 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/nospec-branch.h>
 #include <asm/microcode.h>
 #include <asm/sev.h>
+#include <asm/fred.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/nmi.h>
@@ -303,13 +304,13 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
 
        __this_cpu_add(nmi_stats.unknown, 1);
 
-       pr_emerg("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
-                reason, smp_processor_id());
+       pr_emerg_ratelimited("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
+                            reason, smp_processor_id());
 
        if (unknown_nmi_panic || panic_on_unrecovered_nmi)
                nmi_panic(regs, "NMI: Not continuing");
 
-       pr_emerg("Dazed and confused, but trying to continue\n");
+       pr_emerg_ratelimited("Dazed and confused, but trying to continue\n");
 }
 NOKPROBE_SYMBOL(unknown_nmi_error);
 
@@ -502,7 +503,7 @@ DEFINE_IDTENTRY_RAW(exc_nmi)
        if (IS_ENABLED(CONFIG_NMI_CHECK_CPU))
                raw_atomic_long_inc(&nsp->idt_calls);
 
-       if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id())) {
+       if (arch_cpu_is_offline(smp_processor_id())) {
                if (microcode_nmi_handler_enabled())
                        microcode_offline_nmi_handler();
                return;
@@ -563,9 +564,6 @@ nmi_restart:
        }
        if (this_cpu_dec_return(nmi_state))
                goto nmi_restart;
-
-       if (user_mode(regs))
-               mds_user_clear_cpu_buffers();
 }
 
 #if IS_ENABLED(CONFIG_KVM_INTEL)
@@ -639,7 +637,7 @@ void nmi_backtrace_stall_check(const struct cpumask *btp)
                        msgp = nmi_check_stall_msg[idx];
                        if (nsp->idt_ignored_snap != READ_ONCE(nsp->idt_ignored) && (idx & 0x1))
                                modp = ", but OK because ignore_nmis was set";
-                       if (nmi_seq & ~0x1)
+                       if (nmi_seq & 0x1)
                                msghp = " (CPU currently in NMI handler function)";
                        else if (nsp->idt_nmi_seq_snap + 1 == nmi_seq)
                                msghp = " (CPU exited one NMI handler function)";
@@ -651,6 +649,47 @@ void nmi_backtrace_stall_check(const struct cpumask *btp)
 
 #endif
 
+#ifdef CONFIG_X86_FRED
+/*
+ * With FRED, CR2/DR6 is pushed to #PF/#DB stack frame during FRED
+ * event delivery, i.e., there is no problem of transient states.
+ * And NMI unblocking only happens when the stack frame indicates
+ * that so should happen.
+ *
+ * Thus, the NMI entry stub for FRED is really straightforward and
+ * as simple as most exception handlers. As such, #DB is allowed
+ * during NMI handling.
+ */
+DEFINE_FREDENTRY_NMI(exc_nmi)
+{
+       irqentry_state_t irq_state;
+
+       if (arch_cpu_is_offline(smp_processor_id())) {
+               if (microcode_nmi_handler_enabled())
+                       microcode_offline_nmi_handler();
+               return;
+       }
+
+       /*
+        * Save CR2 for eventual restore to cover the case where the NMI
+        * hits the VMENTER/VMEXIT region where guest CR2 is life. This
+        * prevents guest state corruption in case that the NMI handler
+        * takes a page fault.
+        */
+       this_cpu_write(nmi_cr2, read_cr2());
+
+       irq_state = irqentry_nmi_enter(regs);
+
+       inc_irq_stat(__nmi_count);
+       default_do_nmi(regs);
+
+       irqentry_nmi_exit(regs, irq_state);
+
+       if (unlikely(this_cpu_read(nmi_cr2) != read_cr2()))
+               write_cr2(this_cpu_read(nmi_cr2));
+}
+#endif
+
 void stop_nmi(void)
 {
        ignore_nmis++;
index ab49ade31b0dc46616916d405c694ad6307fdd27..b8441147eb5e84bc6b75648a1228c16850cd5897 100644 (file)
@@ -845,31 +845,6 @@ void __noreturn stop_this_cpu(void *dummy)
        }
 }
 
-/*
- * AMD Erratum 400 aware idle routine. We handle it the same way as C3 power
- * states (local apic timer and TSC stop).
- *
- * XXX this function is completely buggered vs RCU and tracing.
- */
-static void amd_e400_idle(void)
-{
-       /*
-        * We cannot use static_cpu_has_bug() here because X86_BUG_AMD_APIC_C1E
-        * gets set after static_cpu_has() places have been converted via
-        * alternatives.
-        */
-       if (!boot_cpu_has_bug(X86_BUG_AMD_APIC_C1E)) {
-               default_idle();
-               return;
-       }
-
-       tick_broadcast_enter();
-
-       default_idle();
-
-       tick_broadcast_exit();
-}
-
 /*
  * Prefer MWAIT over HALT if MWAIT is supported, MWAIT_CPUID leaf
  * exists and whenever MONITOR/MWAIT extensions are present there is at
@@ -878,21 +853,22 @@ static void amd_e400_idle(void)
  * Do not prefer MWAIT if MONITOR instruction has a bug or idle=nomwait
  * is passed to kernel commandline parameter.
  */
-static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
+static __init bool prefer_mwait_c1_over_halt(void)
 {
+       const struct cpuinfo_x86 *c = &boot_cpu_data;
        u32 eax, ebx, ecx, edx;
 
-       /* User has disallowed the use of MWAIT. Fallback to HALT */
-       if (boot_option_idle_override == IDLE_NOMWAIT)
-               return 0;
+       /* If override is enforced on the command line, fall back to HALT. */
+       if (boot_option_idle_override != IDLE_NO_OVERRIDE)
+               return false;
 
        /* MWAIT is not supported on this platform. Fallback to HALT */
        if (!cpu_has(c, X86_FEATURE_MWAIT))
-               return 0;
+               return false;
 
-       /* Monitor has a bug. Fallback to HALT */
-       if (boot_cpu_has_bug(X86_BUG_MONITOR))
-               return 0;
+       /* Monitor has a bug or APIC stops in C1E. Fallback to HALT */
+       if (boot_cpu_has_bug(X86_BUG_MONITOR) || boot_cpu_has_bug(X86_BUG_AMD_APIC_C1E))
+               return false;
 
        cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
 
@@ -901,13 +877,13 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
         * with EAX=0, ECX=0.
         */
        if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED))
-               return 1;
+               return true;
 
        /*
         * If MWAIT extensions are available, there should be at least one
         * MWAIT C1 substate present.
         */
-       return (edx & MWAIT_C1_SUBSTATE_MASK);
+       return !!(edx & MWAIT_C1_SUBSTATE_MASK);
 }
 
 /*
@@ -933,26 +909,27 @@ static __cpuidle void mwait_idle(void)
        __current_clr_polling();
 }
 
-void select_idle_routine(const struct cpuinfo_x86 *c)
+void __init select_idle_routine(void)
 {
-#ifdef CONFIG_SMP
-       if (boot_option_idle_override == IDLE_POLL && smp_num_siblings > 1)
-               pr_warn_once("WARNING: polling idle and HT enabled, performance may degrade\n");
-#endif
-       if (x86_idle_set() || boot_option_idle_override == IDLE_POLL)
+       if (boot_option_idle_override == IDLE_POLL) {
+               if (IS_ENABLED(CONFIG_SMP) && __max_threads_per_core > 1)
+                       pr_warn_once("WARNING: polling idle and HT enabled, performance may degrade\n");
+               return;
+       }
+
+       /* Required to guard against xen_set_default_idle() */
+       if (x86_idle_set())
                return;
 
-       if (boot_cpu_has_bug(X86_BUG_AMD_E400)) {
-               pr_info("using AMD E400 aware idle routine\n");
-               static_call_update(x86_idle, amd_e400_idle);
-       } else if (prefer_mwait_c1_over_halt(c)) {
+       if (prefer_mwait_c1_over_halt()) {
                pr_info("using mwait in idle threads\n");
                static_call_update(x86_idle, mwait_idle);
        } else if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) {
                pr_info("using TDX aware idle routine\n");
                static_call_update(x86_idle, tdx_safe_halt);
-       } else
+       } else {
                static_call_update(x86_idle, default_idle);
+       }
 }
 
 void amd_e400_c1e_apic_setup(void)
@@ -985,7 +962,10 @@ void __init arch_post_acpi_subsys_init(void)
 
        if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
                mark_tsc_unstable("TSC halt in AMD C1E");
-       pr_info("System has AMD C1E enabled\n");
+
+       if (IS_ENABLED(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST_IDLE))
+               static_branch_enable(&arch_needs_tick_broadcast);
+       pr_info("System has AMD C1E erratum E400. Workaround enabled.\n");
 }
 
 static int __init idle_setup(char *str)
@@ -998,24 +978,14 @@ static int __init idle_setup(char *str)
                boot_option_idle_override = IDLE_POLL;
                cpu_idle_poll_ctrl(true);
        } else if (!strcmp(str, "halt")) {
-               /*
-                * When the boot option of idle=halt is added, halt is
-                * forced to be used for CPU idle. In such case CPU C2/C3
-                * won't be used again.
-                * To continue to load the CPU idle driver, don't touch
-                * the boot_option_idle_override.
-                */
-               static_call_update(x86_idle, default_idle);
+               /* 'idle=halt' HALT for idle. C-states are disabled. */
                boot_option_idle_override = IDLE_HALT;
        } else if (!strcmp(str, "nomwait")) {
-               /*
-                * If the boot option of "idle=nomwait" is added,
-                * it means that mwait will be disabled for CPU C1/C2/C3
-                * states.
-                */
+               /* 'idle=nomwait' disables MWAIT for idle */
                boot_option_idle_override = IDLE_NOMWAIT;
-       } else
-               return -1;
+       } else {
+               return -EINVAL;
+       }
 
        return 0;
 }
@@ -1030,7 +1000,10 @@ unsigned long arch_align_stack(unsigned long sp)
 
 unsigned long arch_randomize_brk(struct mm_struct *mm)
 {
-       return randomize_page(mm->brk, 0x02000000);
+       if (mmap_is_ia32())
+               return randomize_page(mm->brk, SZ_32M);
+
+       return randomize_page(mm->brk, SZ_1G);
 }
 
 /*
index 708c87b88cc150ee64145de90de938e0482afa3f..0917c7f25720be91372bacddb1a3032323b8996f 100644 (file)
@@ -156,13 +156,12 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 {
        struct thread_struct *prev = &prev_p->thread,
                             *next = &next_p->thread;
-       struct fpu *prev_fpu = &prev->fpu;
        int cpu = smp_processor_id();
 
        /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
 
-       if (!test_thread_flag(TIF_NEED_FPU_LOAD))
-               switch_fpu_prepare(prev_fpu, cpu);
+       if (!test_tsk_thread_flag(prev_p, TIF_NEED_FPU_LOAD))
+               switch_fpu_prepare(prev_p, cpu);
 
        /*
         * Save away %gs. No need to save %fs, as it was saved on the
@@ -209,7 +208,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 
        raw_cpu_write(pcpu_hot.current_task, next_p);
 
-       switch_fpu_finish();
+       switch_fpu_finish(next_p);
 
        /* Load the Intel cache allocation PQR MSR. */
        resctrl_sched_in(next_p);
index 33b268747bb7bbce00e1b12b8e00928ce7305acc..7062b84dd467d62ac1aed8c4fe4bdb86d5a7ac61 100644 (file)
@@ -56,6 +56,7 @@
 #include <asm/resctrl.h>
 #include <asm/unistd.h>
 #include <asm/fsgsbase.h>
+#include <asm/fred.h>
 #ifdef CONFIG_IA32_EMULATION
 /* Not included via unistd.h */
 #include <asm/unistd_32_ia32.h>
@@ -117,7 +118,7 @@ void __show_regs(struct pt_regs *regs, enum show_regs_mode mode,
 
        printk("%sFS:  %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n",
               log_lvl, fs, fsindex, gs, gsindex, shadowgs);
-       printk("%sCS:  %04lx DS: %04x ES: %04x CR0: %016lx\n",
+       printk("%sCS:  %04x DS: %04x ES: %04x CR0: %016lx\n",
                log_lvl, regs->cs, ds, es, cr0);
        printk("%sCR2: %016lx CR3: %016lx CR4: %016lx\n",
                log_lvl, cr2, cr3, cr4);
@@ -166,7 +167,29 @@ static noinstr unsigned long __rdgsbase_inactive(void)
 
        lockdep_assert_irqs_disabled();
 
-       if (!cpu_feature_enabled(X86_FEATURE_XENPV)) {
+       /*
+        * SWAPGS is no longer needed thus NOT allowed with FRED because
+        * FRED transitions ensure that an operating system can _always_
+        * operate with its own GS base address:
+        * - For events that occur in ring 3, FRED event delivery swaps
+        *   the GS base address with the IA32_KERNEL_GS_BASE MSR.
+        * - ERETU (the FRED transition that returns to ring 3) also swaps
+        *   the GS base address with the IA32_KERNEL_GS_BASE MSR.
+        *
+        * And the operating system can still setup the GS segment for a
+        * user thread without the need of loading a user thread GS with:
+        * - Using LKGS, available with FRED, to modify other attributes
+        *   of the GS segment without compromising its ability always to
+        *   operate with its own GS base address.
+        * - Accessing the GS segment base address for a user thread as
+        *   before using RDMSR or WRMSR on the IA32_KERNEL_GS_BASE MSR.
+        *
+        * Note, LKGS loads the GS base address into the IA32_KERNEL_GS_BASE
+        * MSR instead of the GS segment’s descriptor cache. As such, the
+        * operating system never changes its runtime GS base address.
+        */
+       if (!cpu_feature_enabled(X86_FEATURE_FRED) &&
+           !cpu_feature_enabled(X86_FEATURE_XENPV)) {
                native_swapgs();
                gsbase = rdgsbase();
                native_swapgs();
@@ -191,7 +214,8 @@ static noinstr void __wrgsbase_inactive(unsigned long gsbase)
 {
        lockdep_assert_irqs_disabled();
 
-       if (!cpu_feature_enabled(X86_FEATURE_XENPV)) {
+       if (!cpu_feature_enabled(X86_FEATURE_FRED) &&
+           !cpu_feature_enabled(X86_FEATURE_XENPV)) {
                native_swapgs();
                wrgsbase(gsbase);
                native_swapgs();
@@ -505,7 +529,7 @@ void x86_gsbase_write_task(struct task_struct *task, unsigned long gsbase)
 static void
 start_thread_common(struct pt_regs *regs, unsigned long new_ip,
                    unsigned long new_sp,
-                   unsigned int _cs, unsigned int _ss, unsigned int _ds)
+                   u16 _cs, u16 _ss, u16 _ds)
 {
        WARN_ON_ONCE(regs != current_pt_regs());
 
@@ -522,11 +546,36 @@ start_thread_common(struct pt_regs *regs, unsigned long new_ip,
        loadsegment(ds, _ds);
        load_gs_index(0);
 
-       regs->ip                = new_ip;
-       regs->sp                = new_sp;
-       regs->cs                = _cs;
-       regs->ss                = _ss;
-       regs->flags             = X86_EFLAGS_IF;
+       regs->ip        = new_ip;
+       regs->sp        = new_sp;
+       regs->csx       = _cs;
+       regs->ssx       = _ss;
+       /*
+        * Allow single-step trap and NMI when starting a new task, thus
+        * once the new task enters user space, single-step trap and NMI
+        * are both enabled immediately.
+        *
+        * Entering a new task is logically speaking a return from a
+        * system call (exec, fork, clone, etc.). As such, if ptrace
+        * enables single stepping a single step exception should be
+        * allowed to trigger immediately upon entering user space.
+        * This is not optional.
+        *
+        * NMI should *never* be disabled in user space. As such, this
+        * is an optional, opportunistic way to catch errors.
+        *
+        * Paranoia: High-order 48 bits above the lowest 16 bit SS are
+        * discarded by the legacy IRET instruction on all Intel, AMD,
+        * and Cyrix/Centaur/VIA CPUs, thus can be set unconditionally,
+        * even when FRED is not enabled. But we choose the safer side
+        * to use these bits only when FRED is enabled.
+        */
+       if (cpu_feature_enabled(X86_FEATURE_FRED)) {
+               regs->fred_ss.swevent   = true;
+               regs->fred_ss.nmi       = true;
+       }
+
+       regs->flags     = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
 }
 
 void
@@ -562,14 +611,13 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 {
        struct thread_struct *prev = &prev_p->thread;
        struct thread_struct *next = &next_p->thread;
-       struct fpu *prev_fpu = &prev->fpu;
        int cpu = smp_processor_id();
 
        WARN_ON_ONCE(IS_ENABLED(CONFIG_DEBUG_ENTRY) &&
                     this_cpu_read(pcpu_hot.hardirq_stack_inuse));
 
-       if (!test_thread_flag(TIF_NEED_FPU_LOAD))
-               switch_fpu_prepare(prev_fpu, cpu);
+       if (!test_tsk_thread_flag(prev_p, TIF_NEED_FPU_LOAD))
+               switch_fpu_prepare(prev_p, cpu);
 
        /* We must save %fs and %gs before load_TLS() because
         * %fs and %gs may be cleared by load_TLS().
@@ -623,7 +671,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
        raw_cpu_write(pcpu_hot.current_task, next_p);
        raw_cpu_write(pcpu_hot.top_of_stack, task_top_of_stack(next_p));
 
-       switch_fpu_finish();
+       switch_fpu_finish(next_p);
 
        /* Reload sp0. */
        update_task_stack(next_p);
index 84201071dfacd186da34cdca12cbda41a39eedf1..46d5a8c520ad4aa165b72036d43c62135e83f037 100644 (file)
@@ -970,10 +970,8 @@ void __init setup_arch(char **cmdline_p)
        high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
 #endif
 
-       /*
-        * Find and reserve possible boot-time SMP configuration:
-        */
-       find_smp_config();
+       /* Find and reserve MPTABLE area */
+       x86_init.mpparse.find_mptable();
 
        early_alloc_pgt_buf();
 
@@ -1090,7 +1088,9 @@ void __init setup_arch(char **cmdline_p)
 
        early_platform_quirks();
 
+       /* Some platforms need the APIC registered for NUMA configuration */
        early_acpi_boot_init();
+       x86_init.mpparse.early_parse_smp_cfg();
 
        x86_flattree_get_config();
 
@@ -1131,24 +1131,19 @@ void __init setup_arch(char **cmdline_p)
 
        early_quirks();
 
-       /*
-        * Read APIC and some other early information from ACPI tables.
-        */
-       acpi_boot_init();
-       x86_dtb_init();
+       topology_apply_cmdline_limits_early();
 
        /*
-        * get boot-time SMP configuration:
+        * Parse SMP configuration. Try ACPI first and then the platform
+        * specific parser.
         */
-       get_smp_config();
+       acpi_boot_init();
+       x86_init.mpparse.parse_smp_cfg();
 
-       /*
-        * Systems w/o ACPI and mptables might not have it mapped the local
-        * APIC yet, but prefill_possible_map() might need to access it.
-        */
+       /* Last opportunity to detect and map the local APIC */
        init_apic_mappings();
 
-       prefill_possible_map();
+       topology_init_possible_cpus();
 
        init_cpu_to_node();
        init_gi_nodes();
@@ -1211,6 +1206,16 @@ void __init i386_reserve_resources(void)
 
 #endif /* CONFIG_X86_32 */
 
+#ifndef CONFIG_SMP
+void __init smp_prepare_boot_cpu(void)
+{
+       struct cpuinfo_x86 *c = &cpu_data(0);
+
+       *c = boot_cpu_data;
+       c->initialized = true;
+}
+#endif
+
 static struct notifier_block kernel_offset_notifier = {
        .notifier_call = dump_kernel_offset
 };
index 1d24ec6799157be4080adc903b38394f8538b35b..8b04958da5e7d6c4bd096cffdaa4874e73433846 100644 (file)
@@ -9,12 +9,18 @@
  * and is included directly into both code-bases.
  */
 
+#include <asm/setup_data.h>
+
 #ifndef __BOOT_COMPRESSED
-#define error(v)       pr_err(v)
-#define has_cpuflag(f) boot_cpu_has(f)
+#define error(v)                       pr_err(v)
+#define has_cpuflag(f)                 boot_cpu_has(f)
+#define sev_printk(fmt, ...)           printk(fmt, ##__VA_ARGS__)
+#define sev_printk_rtl(fmt, ...)       printk_ratelimited(fmt, ##__VA_ARGS__)
 #else
 #undef WARN
 #define WARN(condition, format...) (!!(condition))
+#define sev_printk(fmt, ...)
+#define sev_printk_rtl(fmt, ...)
 #endif
 
 /* I/O parameters for CPUID-related helpers */
@@ -89,7 +95,8 @@ static bool __init sev_es_check_cpu_features(void)
        return true;
 }
 
-static void __noreturn sev_es_terminate(unsigned int set, unsigned int reason)
+static void __head __noreturn
+sev_es_terminate(unsigned int set, unsigned int reason)
 {
        u64 val = GHCB_MSR_TERM_REQ;
 
@@ -326,13 +333,7 @@ static int sev_cpuid_hv(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid
  */
 static const struct snp_cpuid_table *snp_cpuid_get_table(void)
 {
-       void *ptr;
-
-       asm ("lea cpuid_table_copy(%%rip), %0"
-            : "=r" (ptr)
-            : "p" (&cpuid_table_copy));
-
-       return ptr;
+       return &RIP_REL_REF(cpuid_table_copy);
 }
 
 /*
@@ -391,7 +392,7 @@ static u32 snp_cpuid_calc_xsave_size(u64 xfeatures_en, bool compacted)
        return xsave_size;
 }
 
-static bool
+static bool __head
 snp_cpuid_get_validated_func(struct cpuid_leaf *leaf)
 {
        const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();
@@ -528,7 +529,8 @@ static int snp_cpuid_postprocess(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
  * Returns -EOPNOTSUPP if feature not enabled. Any other non-zero return value
  * should be treated as fatal by caller.
  */
-static int snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
+static int __head
+snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf)
 {
        const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();
 
@@ -556,9 +558,9 @@ static int snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_le
                leaf->eax = leaf->ebx = leaf->ecx = leaf->edx = 0;
 
                /* Skip post-processing for out-of-range zero leafs. */
-               if (!(leaf->fn <= cpuid_std_range_max ||
-                     (leaf->fn >= 0x40000000 && leaf->fn <= cpuid_hyp_range_max) ||
-                     (leaf->fn >= 0x80000000 && leaf->fn <= cpuid_ext_range_max)))
+               if (!(leaf->fn <= RIP_REL_REF(cpuid_std_range_max) ||
+                     (leaf->fn >= 0x40000000 && leaf->fn <= RIP_REL_REF(cpuid_hyp_range_max)) ||
+                     (leaf->fn >= 0x80000000 && leaf->fn <= RIP_REL_REF(cpuid_ext_range_max))))
                        return 0;
        }
 
@@ -570,10 +572,11 @@ static int snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_le
  * page yet, so it only supports the MSR based communication with the
  * hypervisor and only the CPUID exit-code.
  */
-void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
+void __head do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
 {
        unsigned int subfn = lower_bits(regs->cx, 32);
        unsigned int fn = lower_bits(regs->ax, 32);
+       u16 opcode = *(unsigned short *)regs->ip;
        struct cpuid_leaf leaf;
        int ret;
 
@@ -581,6 +584,10 @@ void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
        if (exit_code != SVM_EXIT_CPUID)
                goto fail;
 
+       /* Is it really a CPUID insn? */
+       if (opcode != 0xa20f)
+               goto fail;
+
        leaf.fn = fn;
        leaf.subfn = subfn;
 
@@ -1016,7 +1023,8 @@ struct cc_setup_data {
  * Search for a Confidential Computing blob passed in as a setup_data entry
  * via the Linux Boot Protocol.
  */
-static struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp)
+static __head
+struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp)
 {
        struct cc_setup_data *sd = NULL;
        struct setup_data *hdr;
@@ -1043,7 +1051,7 @@ static struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp)
  * mapping needs to be updated in sync with all the changes to virtual memory
  * layout and related mapping facilities throughout the boot process.
  */
-static void __init setup_cpuid_table(const struct cc_blob_sev_info *cc_info)
+static void __head setup_cpuid_table(const struct cc_blob_sev_info *cc_info)
 {
        const struct snp_cpuid_table *cpuid_table_fw, *cpuid_table;
        int i;
@@ -1063,11 +1071,11 @@ static void __init setup_cpuid_table(const struct cc_blob_sev_info *cc_info)
                const struct snp_cpuid_fn *fn = &cpuid_table->fn[i];
 
                if (fn->eax_in == 0x0)
-                       cpuid_std_range_max = fn->eax;
+                       RIP_REL_REF(cpuid_std_range_max) = fn->eax;
                else if (fn->eax_in == 0x40000000)
-                       cpuid_hyp_range_max = fn->eax;
+                       RIP_REL_REF(cpuid_hyp_range_max) = fn->eax;
                else if (fn->eax_in == 0x80000000)
-                       cpuid_ext_range_max = fn->eax;
+                       RIP_REL_REF(cpuid_ext_range_max) = fn->eax;
        }
 }
 
@@ -1170,3 +1178,92 @@ static int vmgexit_psc(struct ghcb *ghcb, struct snp_psc_desc *desc)
 out:
        return ret;
 }
+
+static enum es_result vc_check_opcode_bytes(struct es_em_ctxt *ctxt,
+                                           unsigned long exit_code)
+{
+       unsigned int opcode = (unsigned int)ctxt->insn.opcode.value;
+       u8 modrm = ctxt->insn.modrm.value;
+
+       switch (exit_code) {
+
+       case SVM_EXIT_IOIO:
+       case SVM_EXIT_NPF:
+               /* handled separately */
+               return ES_OK;
+
+       case SVM_EXIT_CPUID:
+               if (opcode == 0xa20f)
+                       return ES_OK;
+               break;
+
+       case SVM_EXIT_INVD:
+               if (opcode == 0x080f)
+                       return ES_OK;
+               break;
+
+       case SVM_EXIT_MONITOR:
+               if (opcode == 0x010f && modrm == 0xc8)
+                       return ES_OK;
+               break;
+
+       case SVM_EXIT_MWAIT:
+               if (opcode == 0x010f && modrm == 0xc9)
+                       return ES_OK;
+               break;
+
+       case SVM_EXIT_MSR:
+               /* RDMSR */
+               if (opcode == 0x320f ||
+               /* WRMSR */
+                   opcode == 0x300f)
+                       return ES_OK;
+               break;
+
+       case SVM_EXIT_RDPMC:
+               if (opcode == 0x330f)
+                       return ES_OK;
+               break;
+
+       case SVM_EXIT_RDTSC:
+               if (opcode == 0x310f)
+                       return ES_OK;
+               break;
+
+       case SVM_EXIT_RDTSCP:
+               if (opcode == 0x010f && modrm == 0xf9)
+                       return ES_OK;
+               break;
+
+       case SVM_EXIT_READ_DR7:
+               if (opcode == 0x210f &&
+                   X86_MODRM_REG(ctxt->insn.modrm.value) == 7)
+                       return ES_OK;
+               break;
+
+       case SVM_EXIT_VMMCALL:
+               if (opcode == 0x010f && modrm == 0xd9)
+                       return ES_OK;
+
+               break;
+
+       case SVM_EXIT_WRITE_DR7:
+               if (opcode == 0x230f &&
+                   X86_MODRM_REG(ctxt->insn.modrm.value) == 7)
+                       return ES_OK;
+               break;
+
+       case SVM_EXIT_WBINVD:
+               if (opcode == 0x90f)
+                       return ES_OK;
+               break;
+
+       default:
+               break;
+       }
+
+       sev_printk(KERN_ERR "Wrong/unhandled opcode bytes: 0x%x, exit_code: 0x%lx, rIP: 0x%lx\n",
+                  opcode, exit_code, ctxt->regs->ip);
+
+       return ES_UNSUPPORTED;
+}
index c67285824e82676528ab8f33e2919bc021b197d2..b59b09c2f28406fc286066a2517eb178f36ad6ae 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/psp-sev.h>
 #include <uapi/linux/sev-guest.h>
 
+#include <asm/init.h>
 #include <asm/cpu_entry_area.h>
 #include <asm/stacktrace.h>
 #include <asm/sev.h>
 #define AP_INIT_CR0_DEFAULT            0x60000010
 #define AP_INIT_MXCSR_DEFAULT          0x1f80
 
+static const char * const sev_status_feat_names[] = {
+       [MSR_AMD64_SEV_ENABLED_BIT]             = "SEV",
+       [MSR_AMD64_SEV_ES_ENABLED_BIT]          = "SEV-ES",
+       [MSR_AMD64_SEV_SNP_ENABLED_BIT]         = "SEV-SNP",
+       [MSR_AMD64_SNP_VTOM_BIT]                = "vTom",
+       [MSR_AMD64_SNP_REFLECT_VC_BIT]          = "ReflectVC",
+       [MSR_AMD64_SNP_RESTRICTED_INJ_BIT]      = "RI",
+       [MSR_AMD64_SNP_ALT_INJ_BIT]             = "AI",
+       [MSR_AMD64_SNP_DEBUG_SWAP_BIT]          = "DebugSwap",
+       [MSR_AMD64_SNP_PREVENT_HOST_IBS_BIT]    = "NoHostIBS",
+       [MSR_AMD64_SNP_BTB_ISOLATION_BIT]       = "BTBIsol",
+       [MSR_AMD64_SNP_VMPL_SSS_BIT]            = "VmplSSS",
+       [MSR_AMD64_SNP_SECURE_TSC_BIT]          = "SecureTSC",
+       [MSR_AMD64_SNP_VMGEXIT_PARAM_BIT]       = "VMGExitParam",
+       [MSR_AMD64_SNP_IBS_VIRT_BIT]            = "IBSVirt",
+       [MSR_AMD64_SNP_VMSA_REG_PROT_BIT]       = "VMSARegProt",
+       [MSR_AMD64_SNP_SMT_PROT_BIT]            = "SMTProt",
+};
+
 /* For early boot hypervisor communication in SEV-ES enabled guests */
 static struct ghcb boot_ghcb_page __bss_decrypted __aligned(PAGE_SIZE);
 
@@ -682,8 +702,9 @@ static u64 __init get_jump_table_addr(void)
        return ret;
 }
 
-static void early_set_pages_state(unsigned long vaddr, unsigned long paddr,
-                                 unsigned long npages, enum psc_op op)
+static void __head
+early_set_pages_state(unsigned long vaddr, unsigned long paddr,
+                     unsigned long npages, enum psc_op op)
 {
        unsigned long paddr_end;
        u64 val;
@@ -739,7 +760,7 @@ e_term:
        sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC);
 }
 
-void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr,
+void __head early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr,
                                         unsigned long npages)
 {
        /*
@@ -748,7 +769,7 @@ void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long padd
         * This eliminates worries about jump tables or checking boot_cpu_data
         * in the cc_platform_has() function.
         */
-       if (!(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
+       if (!(RIP_REL_REF(sev_status) & MSR_AMD64_SEV_SNP_ENABLED))
                return;
 
         /*
@@ -767,7 +788,7 @@ void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr
         * This eliminates worries about jump tables or checking boot_cpu_data
         * in the cc_platform_has() function.
         */
-       if (!(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
+       if (!(RIP_REL_REF(sev_status) & MSR_AMD64_SEV_SNP_ENABLED))
                return;
 
         /* Ask hypervisor to mark the memory pages shared in the RMP table. */
@@ -1752,7 +1773,10 @@ static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt,
                                         struct ghcb *ghcb,
                                         unsigned long exit_code)
 {
-       enum es_result result;
+       enum es_result result = vc_check_opcode_bytes(ctxt, exit_code);
+
+       if (result != ES_OK)
+               return result;
 
        switch (exit_code) {
        case SVM_EXIT_READ_DR7:
@@ -2059,7 +2083,7 @@ fail:
  *
  * Scan for the blob in that order.
  */
-static __init struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp)
+static __head struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp)
 {
        struct cc_blob_sev_info *cc_info;
 
@@ -2085,7 +2109,7 @@ found_cc_info:
        return cc_info;
 }
 
-bool __init snp_init(struct boot_params *bp)
+bool __head snp_init(struct boot_params *bp)
 {
        struct cc_blob_sev_info *cc_info;
 
@@ -2107,7 +2131,7 @@ bool __init snp_init(struct boot_params *bp)
        return true;
 }
 
-void __init __noreturn snp_abort(void)
+void __head __noreturn snp_abort(void)
 {
        sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
 }
@@ -2262,3 +2286,29 @@ static int __init snp_init_platform_device(void)
        return 0;
 }
 device_initcall(snp_init_platform_device);
+
+void kdump_sev_callback(void)
+{
+       /*
+        * Do wbinvd() on remote CPUs when SNP is enabled in order to
+        * safely do SNP_SHUTDOWN on the local CPU.
+        */
+       if (cpu_feature_enabled(X86_FEATURE_SEV_SNP))
+               wbinvd();
+}
+
+void sev_show_status(void)
+{
+       int i;
+
+       pr_info("Status: ");
+       for (i = 0; i < MSR_AMD64_SNP_RESV_BIT; i++) {
+               if (sev_status & BIT_ULL(i)) {
+                       if (!sev_status_feat_names[i])
+                               continue;
+
+                       pr_cont("%s ", sev_status_feat_names[i]);
+               }
+       }
+       pr_cont("\n");
+}
index 3355e27c69ebf8b51be11d479f00795fd3935a19..1ab65f6c6ae7a159221b438a7acf5d0df4740618 100644 (file)
@@ -77,7 +77,7 @@ SYM_FUNC_START(sev_verify_cbit)
         * The check failed, prevent any forward progress to prevent ROP
         * attacks, invalidate the stack and go into a hlt loop.
         */
-       xorq    %rsp, %rsp
+       xorl    %esp, %esp
        subq    $0x1000, %rsp
 2:     hlt
        jmp 2b
index 96a771f9f930a6aba1b77967169808bce3b3eace..2908e063d7d830db32decbfefbd017fd05292700 100644 (file)
@@ -148,14 +148,16 @@ static int register_stop_handler(void)
 
 static void native_stop_other_cpus(int wait)
 {
-       unsigned int cpu = smp_processor_id();
+       unsigned int old_cpu, this_cpu;
        unsigned long flags, timeout;
 
        if (reboot_force)
                return;
 
        /* Only proceed if this is the first CPU to reach this code */
-       if (atomic_cmpxchg(&stopping_cpu, -1, cpu) != -1)
+       old_cpu = -1;
+       this_cpu = smp_processor_id();
+       if (!atomic_try_cmpxchg(&stopping_cpu, &old_cpu, this_cpu))
                return;
 
        /* For kexec, ensure that offline CPUs are out of MWAIT and in HLT */
@@ -186,7 +188,7 @@ static void native_stop_other_cpus(int wait)
         * NMIs.
         */
        cpumask_copy(&cpus_stop_mask, cpu_online_mask);
-       cpumask_clear_cpu(cpu, &cpus_stop_mask);
+       cpumask_clear_cpu(this_cpu, &cpus_stop_mask);
 
        if (!cpumask_empty(&cpus_stop_mask)) {
                apic_send_IPI_allbutself(REBOOT_VECTOR);
@@ -210,6 +212,8 @@ static void native_stop_other_cpus(int wait)
                 * CPUs to stop.
                 */
                if (!smp_no_nmi_ipi && !register_stop_handler()) {
+                       unsigned int cpu;
+
                        pr_emerg("Shutting down cpus with NMI\n");
 
                        for_each_cpu(cpu, &cpus_stop_mask)
index 3f57ce68a3f1ec9c6fe742c08a008d89f65f3f97..fe355c89f6c112a33d17966d8821b1ae20608055 100644 (file)
@@ -101,10 +101,6 @@ EXPORT_PER_CPU_SYMBOL(cpu_core_map);
 DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_die_map);
 EXPORT_PER_CPU_SYMBOL(cpu_die_map);
 
-/* Per CPU bogomips and other parameters */
-DEFINE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
-EXPORT_PER_CPU_SYMBOL(cpu_info);
-
 /* CPUs which are the primary SMT threads */
 struct cpumask __cpu_primary_thread_mask __read_mostly;
 
@@ -125,25 +121,6 @@ struct mwait_cpu_dead {
  */
 static DEFINE_PER_CPU_ALIGNED(struct mwait_cpu_dead, mwait_cpu_dead);
 
-/* Logical package management. */
-struct logical_maps {
-       u32     phys_pkg_id;
-       u32     phys_die_id;
-       u32     logical_pkg_id;
-       u32     logical_die_id;
-};
-
-/* Temporary workaround until the full topology mechanics is in place */
-static DEFINE_PER_CPU_READ_MOSTLY(struct logical_maps, logical_maps) = {
-       .phys_pkg_id    = U32_MAX,
-       .phys_die_id    = U32_MAX,
-};
-
-unsigned int __max_logical_packages __read_mostly;
-EXPORT_SYMBOL(__max_logical_packages);
-static unsigned int logical_packages __read_mostly;
-static unsigned int logical_die __read_mostly;
-
 /* Maximum number of SMT threads on any online core */
 int __read_mostly __max_smt_threads = 1;
 
@@ -336,103 +313,11 @@ static void notrace start_secondary(void *unused)
        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
 }
 
-/**
- * topology_phys_to_logical_pkg - Map a physical package id to a logical
- * @phys_pkg:  The physical package id to map
- *
- * Returns logical package id or -1 if not found
- */
-int topology_phys_to_logical_pkg(unsigned int phys_pkg)
-{
-       int cpu;
-
-       for_each_possible_cpu(cpu) {
-               if (per_cpu(logical_maps.phys_pkg_id, cpu) == phys_pkg)
-                       return per_cpu(logical_maps.logical_pkg_id, cpu);
-       }
-       return -1;
-}
-EXPORT_SYMBOL(topology_phys_to_logical_pkg);
-
-/**
- * topology_phys_to_logical_die - Map a physical die id to logical
- * @die_id:    The physical die id to map
- * @cur_cpu:   The CPU for which the mapping is done
- *
- * Returns logical die id or -1 if not found
- */
-static int topology_phys_to_logical_die(unsigned int die_id, unsigned int cur_cpu)
-{
-       int cpu, proc_id = cpu_data(cur_cpu).topo.pkg_id;
-
-       for_each_possible_cpu(cpu) {
-               if (per_cpu(logical_maps.phys_pkg_id, cpu) == proc_id &&
-                   per_cpu(logical_maps.phys_die_id, cpu) == die_id)
-                       return per_cpu(logical_maps.logical_die_id, cpu);
-       }
-       return -1;
-}
-
-/**
- * topology_update_package_map - Update the physical to logical package map
- * @pkg:       The physical package id as retrieved via CPUID
- * @cpu:       The cpu for which this is updated
- */
-int topology_update_package_map(unsigned int pkg, unsigned int cpu)
-{
-       int new;
-
-       /* Already available somewhere? */
-       new = topology_phys_to_logical_pkg(pkg);
-       if (new >= 0)
-               goto found;
-
-       new = logical_packages++;
-       if (new != pkg) {
-               pr_info("CPU %u Converting physical %u to logical package %u\n",
-                       cpu, pkg, new);
-       }
-found:
-       per_cpu(logical_maps.phys_pkg_id, cpu) = pkg;
-       per_cpu(logical_maps.logical_pkg_id, cpu) = new;
-       cpu_data(cpu).topo.logical_pkg_id = new;
-       return 0;
-}
-/**
- * topology_update_die_map - Update the physical to logical die map
- * @die:       The die id as retrieved via CPUID
- * @cpu:       The cpu for which this is updated
- */
-int topology_update_die_map(unsigned int die, unsigned int cpu)
-{
-       int new;
-
-       /* Already available somewhere? */
-       new = topology_phys_to_logical_die(die, cpu);
-       if (new >= 0)
-               goto found;
-
-       new = logical_die++;
-       if (new != die) {
-               pr_info("CPU %u Converting physical %u to logical die %u\n",
-                       cpu, die, new);
-       }
-found:
-       per_cpu(logical_maps.phys_die_id, cpu) = die;
-       per_cpu(logical_maps.logical_die_id, cpu) = new;
-       cpu_data(cpu).topo.logical_die_id = new;
-       return 0;
-}
-
 static void __init smp_store_boot_cpu_info(void)
 {
-       int id = 0; /* CPU 0 */
-       struct cpuinfo_x86 *c = &cpu_data(id);
+       struct cpuinfo_x86 *c = &cpu_data(0);
 
        *c = boot_cpu_data;
-       c->cpu_index = id;
-       topology_update_package_map(c->topo.pkg_id, id);
-       topology_update_die_map(c->topo.die_id, id);
        c->initialized = true;
 }
 
@@ -488,6 +373,7 @@ static bool match_smt(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
 
                if (c->topo.pkg_id == o->topo.pkg_id &&
                    c->topo.die_id == o->topo.die_id &&
+                   c->topo.amd_node_id == o->topo.amd_node_id &&
                    per_cpu_llc_id(cpu1) == per_cpu_llc_id(cpu2)) {
                        if (c->topo.core_id == o->topo.core_id)
                                return topology_sane(c, o, "smt");
@@ -509,10 +395,13 @@ static bool match_smt(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
 
 static bool match_die(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
 {
-       if (c->topo.pkg_id == o->topo.pkg_id &&
-           c->topo.die_id == o->topo.die_id)
-               return true;
-       return false;
+       if (c->topo.pkg_id != o->topo.pkg_id || c->topo.die_id != o->topo.die_id)
+               return false;
+
+       if (cpu_feature_enabled(X86_FEATURE_TOPOEXT) && topology_amd_nodes_per_pkg() > 1)
+               return c->topo.amd_node_id == o->topo.amd_node_id;
+
+       return true;
 }
 
 static bool match_l2c(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
@@ -670,8 +559,8 @@ static void __init build_sched_topology(void)
 
 void set_cpu_sibling_map(int cpu)
 {
-       bool has_smt = smp_num_siblings > 1;
-       bool has_mp = has_smt || boot_cpu_data.x86_max_cores > 1;
+       bool has_smt = __max_threads_per_core > 1;
+       bool has_mp = has_smt || topology_num_cores_per_package() > 1;
        struct cpuinfo_x86 *c = &cpu_data(cpu);
        struct cpuinfo_x86 *o;
        int i, threads;
@@ -1068,9 +957,13 @@ int native_kick_ap(unsigned int cpu, struct task_struct *tidle)
 
        pr_debug("++++++++++++++++++++=_---CPU UP  %u\n", cpu);
 
-       if (apicid == BAD_APICID || !physid_isset(apicid, phys_cpu_present_map) ||
-           !apic_id_valid(apicid)) {
-               pr_err("%s: bad cpu %d\n", __func__, cpu);
+       if (apicid == BAD_APICID || !apic_id_valid(apicid)) {
+               pr_err("CPU %u has invalid APIC ID %x. Aborting bringup\n", cpu, apicid);
+               return -EINVAL;
+       }
+
+       if (!test_bit(apicid, phys_cpu_present_map)) {
+               pr_err("CPU %u APIC ID %x is not present. Aborting bringup\n", cpu, apicid);
                return -EINVAL;
        }
 
@@ -1139,14 +1032,8 @@ static __init void disable_smp(void)
        pr_info("SMP disabled\n");
 
        disable_ioapic_support();
+       topology_reset_possible_cpus_up();
 
-       init_cpu_present(cpumask_of(0));
-       init_cpu_possible(cpumask_of(0));
-
-       if (smp_found_config)
-               physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
-       else
-               physid_set_mask_of_physid(0, &phys_cpu_present_map);
        cpumask_set_cpu(0, topology_sibling_cpumask(0));
        cpumask_set_cpu(0, topology_core_cpumask(0));
        cpumask_set_cpu(0, topology_die_cpumask(0));
@@ -1187,6 +1074,11 @@ void __init smp_prepare_cpus_common(void)
        set_cpu_sibling_map(0);
 }
 
+void __init smp_prepare_boot_cpu(void)
+{
+       smp_ops.smp_prepare_boot_cpu();
+}
+
 #ifdef CONFIG_X86_64
 /* Establish whether parallel bringup can be supported. */
 bool __init arch_cpuhp_init_parallel_bringup(void)
@@ -1265,102 +1157,16 @@ void __init native_smp_prepare_boot_cpu(void)
        native_pv_lock_init();
 }
 
-void __init calculate_max_logical_packages(void)
-{
-       int ncpus;
-
-       /*
-        * Today neither Intel nor AMD support heterogeneous systems so
-        * extrapolate the boot cpu's data to all packages.
-        */
-       ncpus = cpu_data(0).booted_cores * topology_max_smt_threads();
-       __max_logical_packages = DIV_ROUND_UP(total_cpus, ncpus);
-       pr_info("Max logical packages: %u\n", __max_logical_packages);
-}
-
 void __init native_smp_cpus_done(unsigned int max_cpus)
 {
        pr_debug("Boot done\n");
 
-       calculate_max_logical_packages();
        build_sched_topology();
        nmi_selftest();
        impress_friends();
        cache_aps_init();
 }
 
-static int __initdata setup_possible_cpus = -1;
-static int __init _setup_possible_cpus(char *str)
-{
-       get_option(&str, &setup_possible_cpus);
-       return 0;
-}
-early_param("possible_cpus", _setup_possible_cpus);
-
-
-/*
- * cpu_possible_mask should be static, it cannot change as cpu's
- * are onlined, or offlined. The reason is per-cpu data-structures
- * are allocated by some modules at init time, and don't expect to
- * do this dynamically on cpu arrival/departure.
- * cpu_present_mask on the other hand can change dynamically.
- * In case when cpu_hotplug is not compiled, then we resort to current
- * behaviour, which is cpu_possible == cpu_present.
- * - Ashok Raj
- *
- * Three ways to find out the number of additional hotplug CPUs:
- * - If the BIOS specified disabled CPUs in ACPI/mptables use that.
- * - The user can overwrite it with possible_cpus=NUM
- * - Otherwise don't reserve additional CPUs.
- * We do this because additional CPUs waste a lot of memory.
- * -AK
- */
-__init void prefill_possible_map(void)
-{
-       int i, possible;
-
-       i = setup_max_cpus ?: 1;
-       if (setup_possible_cpus == -1) {
-               possible = num_processors;
-#ifdef CONFIG_HOTPLUG_CPU
-               if (setup_max_cpus)
-                       possible += disabled_cpus;
-#else
-               if (possible > i)
-                       possible = i;
-#endif
-       } else
-               possible = setup_possible_cpus;
-
-       total_cpus = max_t(int, possible, num_processors + disabled_cpus);
-
-       /* nr_cpu_ids could be reduced via nr_cpus= */
-       if (possible > nr_cpu_ids) {
-               pr_warn("%d Processors exceeds NR_CPUS limit of %u\n",
-                       possible, nr_cpu_ids);
-               possible = nr_cpu_ids;
-       }
-
-#ifdef CONFIG_HOTPLUG_CPU
-       if (!setup_max_cpus)
-#endif
-       if (possible > i) {
-               pr_warn("%d Processors exceeds max_cpus limit of %u\n",
-                       possible, setup_max_cpus);
-               possible = i;
-       }
-
-       set_nr_cpu_ids(possible);
-
-       pr_info("Allowing %d CPUs, %d hotplug CPUs\n",
-               possible, max_t(int, possible - num_processors, 0));
-
-       reset_cpu_possible_mask();
-
-       for (i = 0; i < possible; i++)
-               set_cpu_possible(i, true);
-}
-
 /* correctly size the local cpu masks */
 void __init setup_cpu_local_masks(void)
 {
index 77a9316da43573de5f1a7a2e6f220a1190600862..4eefaac64c6cbabbd1a73ac714993ce831647792 100644 (file)
@@ -172,7 +172,7 @@ void arch_static_call_transform(void *site, void *tramp, void *func, bool tail)
 }
 EXPORT_SYMBOL_GPL(arch_static_call_transform);
 
-#ifdef CONFIG_RETHUNK
+#ifdef CONFIG_MITIGATION_RETHUNK
 /*
  * This is called by apply_returns() to fix up static call trampolines,
  * specifically ARCH_DEFINE_STATIC_CALL_NULL_TRAMP which is recorded as
index 8e2b2552b5eead37378e51c3a959c6756fc9ddc2..3e2952679b88591aa20b07976f14575292dfe489 100644 (file)
@@ -6,7 +6,9 @@
 #include <linux/sched/task_stack.h>
 #include <linux/mm.h>
 #include <linux/ptrace.h>
+
 #include <asm/desc.h>
+#include <asm/debugreg.h>
 #include <asm/mmu_context.h>
 
 unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs)
index c783aeb37dce3221827ca1da0350958ff9baddbd..cb9fa1d5c66f73c96fa9f6a18d785ddfda75bc25 100644 (file)
@@ -52,13 +52,6 @@ static unsigned long get_align_bits(void)
        return va_align.bits & get_align_mask();
 }
 
-unsigned long align_vdso_addr(unsigned long addr)
-{
-       unsigned long align_mask = get_align_mask();
-       addr = (addr + align_mask) & ~align_mask;
-       return addr | get_align_bits();
-}
-
 static int __init control_va_addr_alignment(char *str)
 {
        /* guard against enabling this on other CPU families */
index c3b2f863acf0f3f28c7402c86de8cbaa47eb930c..4fa0b17e5043aa81070fe7716cda5518f808957c 100644 (file)
@@ -51,6 +51,7 @@
 #include <asm/ftrace.h>
 #include <asm/traps.h>
 #include <asm/desc.h>
+#include <asm/fred.h>
 #include <asm/fpu/api.h>
 #include <asm/cpu.h>
 #include <asm/cpu_entry_area.h>
@@ -773,7 +774,7 @@ DEFINE_IDTENTRY_RAW(exc_int3)
  */
 asmlinkage __visible noinstr struct pt_regs *sync_regs(struct pt_regs *eregs)
 {
-       struct pt_regs *regs = (struct pt_regs *)this_cpu_read(pcpu_hot.top_of_stack) - 1;
+       struct pt_regs *regs = (struct pt_regs *)current_top_of_stack() - 1;
        if (regs != eregs)
                *regs = *eregs;
        return regs;
@@ -791,7 +792,7 @@ asmlinkage __visible noinstr struct pt_regs *vc_switch_off_ist(struct pt_regs *r
         * trust it and switch to the current kernel stack
         */
        if (ip_within_syscall_gap(regs)) {
-               sp = this_cpu_read(pcpu_hot.top_of_stack);
+               sp = current_top_of_stack();
                goto sync;
        }
 
@@ -935,8 +936,7 @@ static bool notify_debug(struct pt_regs *regs, unsigned long *dr6)
        return false;
 }
 
-static __always_inline void exc_debug_kernel(struct pt_regs *regs,
-                                            unsigned long dr6)
+static noinstr void exc_debug_kernel(struct pt_regs *regs, unsigned long dr6)
 {
        /*
         * Disable breakpoints during exception handling; recursive exceptions
@@ -948,6 +948,11 @@ static __always_inline void exc_debug_kernel(struct pt_regs *regs,
         *
         * Entry text is excluded for HW_BP_X and cpu_entry_area, which
         * includes the entry stack is excluded for everything.
+        *
+        * For FRED, nested #DB should just work fine. But when a watchpoint or
+        * breakpoint is set in the code path which is executed by #DB handler,
+        * it results in an endless recursion and stack overflow. Thus we stay
+        * with the IDT approach, i.e., save DR7 and disable #DB.
         */
        unsigned long dr7 = local_db_save();
        irqentry_state_t irq_state = irqentry_nmi_enter(regs);
@@ -977,7 +982,8 @@ static __always_inline void exc_debug_kernel(struct pt_regs *regs,
         * Catch SYSENTER with TF set and clear DR_STEP. If this hit a
         * watchpoint at the same time then that will still be handled.
         */
-       if ((dr6 & DR_STEP) && is_sysenter_singlestep(regs))
+       if (!cpu_feature_enabled(X86_FEATURE_FRED) &&
+           (dr6 & DR_STEP) && is_sysenter_singlestep(regs))
                dr6 &= ~DR_STEP;
 
        /*
@@ -1009,8 +1015,7 @@ out:
        local_db_restore(dr7);
 }
 
-static __always_inline void exc_debug_user(struct pt_regs *regs,
-                                          unsigned long dr6)
+static noinstr void exc_debug_user(struct pt_regs *regs, unsigned long dr6)
 {
        bool icebp;
 
@@ -1094,6 +1099,34 @@ DEFINE_IDTENTRY_DEBUG_USER(exc_debug)
 {
        exc_debug_user(regs, debug_read_clear_dr6());
 }
+
+#ifdef CONFIG_X86_FRED
+/*
+ * When occurred on different ring level, i.e., from user or kernel
+ * context, #DB needs to be handled on different stack: User #DB on
+ * current task stack, while kernel #DB on a dedicated stack.
+ *
+ * This is exactly how FRED event delivery invokes an exception
+ * handler: ring 3 event on level 0 stack, i.e., current task stack;
+ * ring 0 event on the #DB dedicated stack specified in the
+ * IA32_FRED_STKLVLS MSR. So unlike IDT, the FRED debug exception
+ * entry stub doesn't do stack switch.
+ */
+DEFINE_FREDENTRY_DEBUG(exc_debug)
+{
+       /*
+        * FRED #DB stores DR6 on the stack in the format which
+        * debug_read_clear_dr6() returns for the IDT entry points.
+        */
+       unsigned long dr6 = fred_event_data(regs);
+
+       if (user_mode(regs))
+               exc_debug_user(regs, dr6);
+       else
+               exc_debug_kernel(regs, dr6);
+}
+#endif /* CONFIG_X86_FRED */
+
 #else
 /* 32 bit does not have separate entry points. */
 DEFINE_IDTENTRY_RAW(exc_debug)
@@ -1369,8 +1402,34 @@ DEFINE_IDTENTRY_SW(iret_error)
 }
 #endif
 
+/* Do not enable FRED by default yet. */
+static bool enable_fred __ro_after_init = false;
+
+#ifdef CONFIG_X86_FRED
+static int __init fred_setup(char *str)
+{
+       if (!str)
+               return -EINVAL;
+
+       if (!cpu_feature_enabled(X86_FEATURE_FRED))
+               return 0;
+
+       if (!strcmp(str, "on"))
+               enable_fred = true;
+       else if (!strcmp(str, "off"))
+               enable_fred = false;
+       else
+               pr_warn("invalid FRED option: 'fred=%s'\n", str);
+       return 0;
+}
+early_param("fred", fred_setup);
+#endif
+
 void __init trap_init(void)
 {
+       if (cpu_feature_enabled(X86_FEATURE_FRED) && !enable_fred)
+               setup_clear_cpu_cap(X86_FEATURE_FRED);
+
        /* Init cpu_entry_area before IST entries are set up */
        setup_cpu_entry_areas();
 
@@ -1379,7 +1438,10 @@ void __init trap_init(void)
 
        /* Initialize TSS before setting up traps so ISTs work */
        cpu_init_exception_handling();
+
        /* Setup traps as cpu_init() might #GP */
-       idt_setup_traps();
+       if (!cpu_feature_enabled(X86_FEATURE_FRED))
+               idt_setup_traps();
+
        cpu_init();
 }
index 15f97c0abc9d09e80bc67a21adf76103d2cefea1..5a69a49acc963f067675a1934ac5fde0ad56e95a 100644 (file)
@@ -53,7 +53,7 @@ static int __read_mostly tsc_force_recalibrate;
 static u32 art_to_tsc_numerator;
 static u32 art_to_tsc_denominator;
 static u64 art_to_tsc_offset;
-static struct clocksource *art_related_clocksource;
+static bool have_art;
 
 struct cyc2ns {
        struct cyc2ns_data data[2];     /*  0 + 2*16 = 32 */
@@ -652,7 +652,7 @@ success:
 }
 
 /**
- * native_calibrate_tsc
+ * native_calibrate_tsc - determine TSC frequency
  * Determine TSC frequency via CPUID, else return 0.
  */
 unsigned long native_calibrate_tsc(void)
@@ -1168,6 +1168,7 @@ static struct clocksource clocksource_tsc_early = {
        .mask                   = CLOCKSOURCE_MASK(64),
        .flags                  = CLOCK_SOURCE_IS_CONTINUOUS |
                                  CLOCK_SOURCE_MUST_VERIFY,
+       .id                     = CSID_X86_TSC_EARLY,
        .vdso_clock_mode        = VDSO_CLOCKMODE_TSC,
        .enable                 = tsc_cs_enable,
        .resume                 = tsc_resume,
@@ -1190,6 +1191,7 @@ static struct clocksource clocksource_tsc = {
                                  CLOCK_SOURCE_VALID_FOR_HRES |
                                  CLOCK_SOURCE_MUST_VERIFY |
                                  CLOCK_SOURCE_VERIFY_PERCPU,
+       .id                     = CSID_X86_TSC,
        .vdso_clock_mode        = VDSO_CLOCKMODE_TSC,
        .enable                 = tsc_cs_enable,
        .resume                 = tsc_resume,
@@ -1309,8 +1311,10 @@ struct system_counterval_t convert_art_to_tsc(u64 art)
        do_div(tmp, art_to_tsc_denominator);
        res += tmp + art_to_tsc_offset;
 
-       return (struct system_counterval_t) {.cs = art_related_clocksource,
-                       .cycles = res};
+       return (struct system_counterval_t) {
+               .cs_id  = have_art ? CSID_X86_TSC : CSID_GENERIC,
+               .cycles = res,
+       };
 }
 EXPORT_SYMBOL(convert_art_to_tsc);
 
@@ -1327,12 +1331,10 @@ EXPORT_SYMBOL(convert_art_to_tsc);
  * that this flag is set before conversion to TSC is attempted.
  *
  * Return:
- * struct system_counterval_t - system counter value with the pointer to the
- *     corresponding clocksource
- *     @cycles:        System counter value
- *     @cs:            Clocksource corresponding to system counter value. Used
- *                     by timekeeping code to verify comparability of two cycle
- *                     values.
+ * struct system_counterval_t - system counter value with the ID of the
+ *     corresponding clocksource:
+ *     cycles:         System counter value
+ *     cs_id:          The clocksource ID for validating comparability
  */
 
 struct system_counterval_t convert_art_ns_to_tsc(u64 art_ns)
@@ -1347,8 +1349,10 @@ struct system_counterval_t convert_art_ns_to_tsc(u64 art_ns)
        do_div(tmp, USEC_PER_SEC);
        res += tmp;
 
-       return (struct system_counterval_t) { .cs = art_related_clocksource,
-                                             .cycles = res};
+       return (struct system_counterval_t) {
+               .cs_id  = have_art ? CSID_X86_TSC : CSID_GENERIC,
+               .cycles = res,
+       };
 }
 EXPORT_SYMBOL(convert_art_ns_to_tsc);
 
@@ -1357,7 +1361,7 @@ static void tsc_refine_calibration_work(struct work_struct *work);
 static DECLARE_DELAYED_WORK(tsc_irqwork, tsc_refine_calibration_work);
 /**
  * tsc_refine_calibration_work - Further refine tsc freq calibration
- * @work - ignored.
+ * @work: ignored.
  *
  * This functions uses delayed work over a period of a
  * second to further refine the TSC freq value. Since this is
@@ -1455,7 +1459,7 @@ out:
                goto unreg;
 
        if (boot_cpu_has(X86_FEATURE_ART))
-               art_related_clocksource = &clocksource_tsc;
+               have_art = true;
        clocksource_register_khz(&clocksource_tsc, tsc_khz);
 unreg:
        clocksource_unregister(&clocksource_tsc_early);
@@ -1481,7 +1485,7 @@ static int __init init_tsc_clocksource(void)
         */
        if (boot_cpu_has(X86_FEATURE_TSC_KNOWN_FREQ)) {
                if (boot_cpu_has(X86_FEATURE_ART))
-                       art_related_clocksource = &clocksource_tsc;
+                       have_art = true;
                clocksource_register_khz(&clocksource_tsc, tsc_khz);
                clocksource_unregister(&clocksource_tsc_early);
 
index a349dbfc6d5ab47b2f8963bacd24915a963cb2a2..56451fd2099e718b6cf89fde074980042aa3096a 100644 (file)
@@ -46,6 +46,7 @@ ENTRY(phys_startup_64)
 #endif
 
 jiffies = jiffies_64;
+const_pcpu_hot = pcpu_hot;
 
 #if defined(CONFIG_X86_64)
 /*
@@ -132,7 +133,7 @@ SECTIONS
                LOCK_TEXT
                KPROBES_TEXT
                SOFTIRQENTRY_TEXT
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
                *(.text..__x86.indirect_thunk)
                *(.text..__x86.return_thunk)
 #endif
@@ -142,7 +143,7 @@ SECTIONS
                *(.text..__x86.rethunk_untrain)
                ENTRY_TEXT
 
-#ifdef CONFIG_CPU_SRSO
+#ifdef CONFIG_MITIGATION_SRSO
                /*
                 * See the comment above srso_alias_untrain_ret()'s
                 * definition.
@@ -267,7 +268,7 @@ SECTIONS
        }
 #endif
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
        /*
         * List of instructions that call/jmp/jcc to retpoline thunks
         * __x86_indirect_thunk_*(). These instructions can be patched along
@@ -504,11 +505,11 @@ INIT_PER_CPU(irq_stack_backing_store);
            "fixed_percpu_data is not at start of per-cpu area");
 #endif
 
-#ifdef CONFIG_CPU_UNRET_ENTRY
+#ifdef CONFIG_MITIGATION_UNRET_ENTRY
 . = ASSERT((retbleed_return_thunk & 0x3f) == 0, "retbleed_return_thunk not cacheline-aligned");
 #endif
 
-#ifdef CONFIG_CPU_SRSO
+#ifdef CONFIG_MITIGATION_SRSO
 . = ASSERT((srso_safe_ret & 0x3f) == 0, "srso_safe_ret not cacheline-aligned");
 /*
  * GNU ld cannot do XOR until 2.41.
index d3fc017705587de1f921c02f3da83edf6e73368f..73511332bb670074ddc83861b60c946e8e7004cd 100644 (file)
@@ -127,25 +127,12 @@ static void __init vsmp_cap_cpus(void)
 #endif
 }
 
-static u32 apicid_phys_pkg_id(u32 initial_apic_id, int index_msb)
-{
-       return read_apic_id() >> index_msb;
-}
-
-static void vsmp_apic_post_init(void)
-{
-       /* need to update phys_pkg_id */
-       apic->phys_pkg_id = apicid_phys_pkg_id;
-}
-
 void __init vsmp_init(void)
 {
        detect_vsmp_box();
        if (!is_vsmp_box())
                return;
 
-       x86_platform.apic_post_init = vsmp_apic_post_init;
-
        vsmp_cap_cpus();
 
        set_vsmp_ctl();
index a37ebd3b47736dfe55f5e7518df50e4135cdcfab..a42830dc151bc48af1362a3fbe8248ae63038b63 100644 (file)
@@ -70,8 +70,9 @@ struct x86_init_ops x86_init __initdata = {
 
        .mpparse = {
                .setup_ioapic_ids       = x86_init_noop,
-               .find_smp_config        = default_find_smp_config,
-               .get_smp_config         = default_get_smp_config,
+               .find_mptable           = mpparse_find_mptable,
+               .early_parse_smp_cfg    = mpparse_parse_early_smp_config,
+               .parse_smp_cfg          = mpparse_parse_smp_config,
        },
 
        .irqs = {
index 87e3da7b0439790dac6b35aa4f95e8e7573284d7..65ed14b6540bbebfb91e1d20d0c7627277da3f26 100644 (file)
@@ -80,9 +80,10 @@ config KVM_SW_PROTECTED_VM
        depends on KVM && X86_64
        select KVM_GENERIC_PRIVATE_MEM
        help
-         Enable support for KVM software-protected VMs.  Currently "protected"
-         means the VM can be backed with memory provided by
-         KVM_CREATE_GUEST_MEMFD.
+         Enable support for KVM software-protected VMs.  Currently, software-
+         protected VMs are purely a development and testing vehicle for
+         KVM_CREATE_GUEST_MEMFD.  Attempting to run a "real" VM workload as a
+         software-protected VM will fail miserably.
 
          If unsure, say "N".
 
index 3242f3da2457671bafde8d5ad7823c9a3d3a07be..1edf93ee33957826681f9dc2ec3d3caddaba0a29 100644 (file)
@@ -2815,7 +2815,10 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu, int timer_advance_ns)
 
        vcpu->arch.apic = apic;
 
-       apic->regs = (void *)get_zeroed_page(GFP_KERNEL_ACCOUNT);
+       if (kvm_x86_ops.alloc_apic_backing_page)
+               apic->regs = static_call(kvm_x86_alloc_apic_backing_page)(vcpu);
+       else
+               apic->regs = (void *)get_zeroed_page(GFP_KERNEL_ACCOUNT);
        if (!apic->regs) {
                printk(KERN_ERR "malloc apic regs error for vcpu %x\n",
                       vcpu->vcpu_id);
index 2d6cdeab1f8a3e78306148d44a4665a1d51d8b1e..9a905f10e10c6a83704870c558859ccc6d226925 100644 (file)
 #include <asm/cmpxchg.h>
 #include <asm/io.h>
 #include <asm/set_memory.h>
+#include <asm/spec-ctrl.h>
 #include <asm/vmx.h>
 
 #include "trace.h"
 
-extern bool itlb_multihit_kvm_mitigation;
-
 static bool nx_hugepage_mitigation_hard_disabled;
 
 int __read_mostly nx_huge_pages = -1;
@@ -263,7 +262,7 @@ static unsigned long get_guest_cr3(struct kvm_vcpu *vcpu)
 static inline unsigned long kvm_mmu_get_guest_pgd(struct kvm_vcpu *vcpu,
                                                  struct kvm_mmu *mmu)
 {
-       if (IS_ENABLED(CONFIG_RETPOLINE) && mmu->get_guest_pgd == get_guest_cr3)
+       if (IS_ENABLED(CONFIG_MITIGATION_RETPOLINE) && mmu->get_guest_pgd == get_guest_cr3)
                return kvm_read_cr3(vcpu);
 
        return mmu->get_guest_pgd(vcpu);
@@ -4405,6 +4404,31 @@ static int kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault,
        fault->mmu_seq = vcpu->kvm->mmu_invalidate_seq;
        smp_rmb();
 
+       /*
+        * Check for a relevant mmu_notifier invalidation event before getting
+        * the pfn from the primary MMU, and before acquiring mmu_lock.
+        *
+        * For mmu_lock, if there is an in-progress invalidation and the kernel
+        * allows preemption, the invalidation task may drop mmu_lock and yield
+        * in response to mmu_lock being contended, which is *very* counter-
+        * productive as this vCPU can't actually make forward progress until
+        * the invalidation completes.
+        *
+        * Retrying now can also avoid unnessary lock contention in the primary
+        * MMU, as the primary MMU doesn't necessarily hold a single lock for
+        * the duration of the invalidation, i.e. faulting in a conflicting pfn
+        * can cause the invalidation to take longer by holding locks that are
+        * needed to complete the invalidation.
+        *
+        * Do the pre-check even for non-preemtible kernels, i.e. even if KVM
+        * will never yield mmu_lock in response to contention, as this vCPU is
+        * *guaranteed* to need to retry, i.e. waiting until mmu_lock is held
+        * to detect retry guarantees the worst case latency for the vCPU.
+        */
+       if (fault->slot &&
+           mmu_invalidate_retry_gfn_unsafe(vcpu->kvm, fault->mmu_seq, fault->gfn))
+               return RET_PF_RETRY;
+
        ret = __kvm_faultin_pfn(vcpu, fault);
        if (ret != RET_PF_CONTINUE)
                return ret;
@@ -4415,6 +4439,18 @@ static int kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault,
        if (unlikely(!fault->slot))
                return kvm_handle_noslot_fault(vcpu, fault, access);
 
+       /*
+        * Check again for a relevant mmu_notifier invalidation event purely to
+        * avoid contending mmu_lock.  Most invalidations will be detected by
+        * the previous check, but checking is extremely cheap relative to the
+        * overall cost of failing to detect the invalidation until after
+        * mmu_lock is acquired.
+        */
+       if (mmu_invalidate_retry_gfn_unsafe(vcpu->kvm, fault->mmu_seq, fault->gfn)) {
+               kvm_release_pfn_clean(fault->pfn);
+               return RET_PF_RETRY;
+       }
+
        return RET_PF_CONTINUE;
 }
 
@@ -4442,6 +4478,11 @@ static bool is_page_fault_stale(struct kvm_vcpu *vcpu,
        if (!sp && kvm_test_request(KVM_REQ_MMU_FREE_OBSOLETE_ROOTS, vcpu))
                return true;
 
+       /*
+        * Check for a relevant mmu_notifier invalidation event one last time
+        * now that mmu_lock is held, as the "unsafe" checks performed without
+        * holding mmu_lock can get false negatives.
+        */
        return fault->slot &&
               mmu_invalidate_retry_gfn(vcpu->kvm, fault->mmu_seq, fault->gfn);
 }
index 0669a8a668cacd4d0be68affbecbb686524c5213..5390a591a5718cce422958210e3eb91f457bd169 100644 (file)
@@ -315,7 +315,7 @@ static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
        if (!prefetch)
                vcpu->stat.pf_taken++;
 
-       if (IS_ENABLED(CONFIG_RETPOLINE) && fault.is_tdp)
+       if (IS_ENABLED(CONFIG_MITIGATION_RETPOLINE) && fault.is_tdp)
                r = kvm_tdp_page_fault(vcpu, &fault);
        else
                r = vcpu->arch.mmu->page_fault(vcpu, &fault);
index dee62362a360ade493e0ca1d6ec19972ab70b72c..55b9a6d96bcfabdd886bd4043b9a7bf0aac8186f 100644 (file)
@@ -1181,7 +1181,7 @@ int svm_allocate_nested(struct vcpu_svm *svm)
        if (svm->nested.initialized)
                return 0;
 
-       vmcb02_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+       vmcb02_page = snp_safe_alloc_page(&svm->vcpu);
        if (!vmcb02_page)
                return -ENOMEM;
        svm->nested.vmcb02.ptr = page_address(vmcb02_page);
index f760106c31f8a58d2941dbabd82531b9779089fa..ae0ac12382b9278732fc89d4ef00a5f84866f8c0 100644 (file)
@@ -57,7 +57,7 @@ static bool sev_es_enabled = true;
 module_param_named(sev_es, sev_es_enabled, bool, 0444);
 
 /* enable/disable SEV-ES DebugSwap support */
-static bool sev_es_debug_swap_enabled = true;
+static bool sev_es_debug_swap_enabled = false;
 module_param_named(debug_swap, sev_es_debug_swap_enabled, bool, 0444);
 #else
 #define sev_enabled false
@@ -246,6 +246,7 @@ static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
 static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
 {
        struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       struct sev_platform_init_args init_args = {0};
        int asid, ret;
 
        if (kvm->created_vcpus)
@@ -262,7 +263,8 @@ static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
                goto e_no_asid;
        sev->asid = asid;
 
-       ret = sev_platform_init(&argp->error);
+       init_args.probe = false;
+       ret = sev_platform_init(&init_args);
        if (ret)
                goto e_free;
 
@@ -274,6 +276,7 @@ static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
        return 0;
 
 e_free:
+       argp->error = init_args.error;
        sev_asid_free(sev);
        sev->asid = 0;
 e_no_asid:
@@ -612,8 +615,11 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm)
        save->xss  = svm->vcpu.arch.ia32_xss;
        save->dr6  = svm->vcpu.arch.dr6;
 
-       if (sev_es_debug_swap_enabled)
+       if (sev_es_debug_swap_enabled) {
                save->sev_features |= SVM_SEV_FEAT_DEBUG_SWAP;
+               pr_warn_once("Enabling DebugSwap with KVM_SEV_ES_INIT. "
+                            "This will not work starting with Linux 6.10\n");
+       }
 
        pr_debug("Virtual Machine Save Area (VMSA):\n");
        print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, save, sizeof(*save), false);
@@ -1975,20 +1981,22 @@ int sev_mem_enc_register_region(struct kvm *kvm,
                goto e_free;
        }
 
-       region->uaddr = range->addr;
-       region->size = range->size;
-
-       list_add_tail(&region->list, &sev->regions_list);
-       mutex_unlock(&kvm->lock);
-
        /*
         * The guest may change the memory encryption attribute from C=0 -> C=1
         * or vice versa for this memory range. Lets make sure caches are
         * flushed to ensure that guest data gets written into memory with
-        * correct C-bit.
+        * correct C-bit.  Note, this must be done before dropping kvm->lock,
+        * as region and its array of pages can be freed by a different task
+        * once kvm->lock is released.
         */
        sev_clflush_pages(region->pages, region->npages);
 
+       region->uaddr = range->addr;
+       region->size = range->size;
+
+       list_add_tail(&region->list, &sev->regions_list);
+       mutex_unlock(&kvm->lock);
+
        return ret;
 
 e_free:
@@ -3160,3 +3168,35 @@ void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector)
 
        ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, 1);
 }
+
+struct page *snp_safe_alloc_page(struct kvm_vcpu *vcpu)
+{
+       unsigned long pfn;
+       struct page *p;
+
+       if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP))
+               return alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+
+       /*
+        * Allocate an SNP-safe page to workaround the SNP erratum where
+        * the CPU will incorrectly signal an RMP violation #PF if a
+        * hugepage (2MB or 1GB) collides with the RMP entry of a
+        * 2MB-aligned VMCB, VMSA, or AVIC backing page.
+        *
+        * Allocate one extra page, choose a page which is not
+        * 2MB-aligned, and free the other.
+        */
+       p = alloc_pages(GFP_KERNEL_ACCOUNT | __GFP_ZERO, 1);
+       if (!p)
+               return NULL;
+
+       split_page(p, 1);
+
+       pfn = page_to_pfn(p);
+       if (IS_ALIGNED(pfn, PTRS_PER_PMD))
+               __free_page(p++);
+       else
+               __free_page(p + 1);
+
+       return p;
+}
index e90b429c84f158bdd8d4348172d56eac1e80763b..272d5ed37ce77c25a2011a7c876640783049d510 100644 (file)
@@ -703,7 +703,7 @@ static int svm_cpu_init(int cpu)
        int ret = -ENOMEM;
 
        memset(sd, 0, sizeof(struct svm_cpu_data));
-       sd->save_area = alloc_page(GFP_KERNEL | __GFP_ZERO);
+       sd->save_area = snp_safe_alloc_page(NULL);
        if (!sd->save_area)
                return ret;
 
@@ -1421,7 +1421,7 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu)
        svm = to_svm(vcpu);
 
        err = -ENOMEM;
-       vmcb01_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+       vmcb01_page = snp_safe_alloc_page(vcpu);
        if (!vmcb01_page)
                goto out;
 
@@ -1430,7 +1430,7 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu)
                 * SEV-ES guests require a separate VMSA page used to contain
                 * the encrypted register state of the guest.
                 */
-               vmsa_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+               vmsa_page = snp_safe_alloc_page(vcpu);
                if (!vmsa_page)
                        goto error_free_vmcb_page;
 
@@ -3455,7 +3455,7 @@ int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code)
        if (!svm_check_exit_valid(exit_code))
                return svm_handle_invalid_exit(vcpu, exit_code);
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
        if (exit_code == SVM_EXIT_MSR)
                return msr_interception(vcpu);
        else if (exit_code == SVM_EXIT_VINTR)
@@ -4900,6 +4900,16 @@ static int svm_vm_init(struct kvm *kvm)
        return 0;
 }
 
+static void *svm_alloc_apic_backing_page(struct kvm_vcpu *vcpu)
+{
+       struct page *page = snp_safe_alloc_page(vcpu);
+
+       if (!page)
+               return NULL;
+
+       return page_address(page);
+}
+
 static struct kvm_x86_ops svm_x86_ops __initdata = {
        .name = KBUILD_MODNAME,
 
@@ -5031,6 +5041,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
 
        .vcpu_deliver_sipi_vector = svm_vcpu_deliver_sipi_vector,
        .vcpu_get_apicv_inhibit_reasons = avic_vcpu_get_apicv_inhibit_reasons,
+       .alloc_apic_backing_page = svm_alloc_apic_backing_page,
 };
 
 /*
index 8ef95139cd245572a530b83e68756834a619cf41..7f1fbd874c4582b0b6d3735b62c3c85de2021074 100644 (file)
@@ -694,6 +694,7 @@ void sev_es_vcpu_reset(struct vcpu_svm *svm);
 void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector);
 void sev_es_prepare_switch_to_guest(struct sev_es_save_area *hostsa);
 void sev_es_unmap_ghcb(struct vcpu_svm *svm);
+struct page *snp_safe_alloc_page(struct kvm_vcpu *vcpu);
 
 /* vmenter.S */
 
index 9499f9c6b07711bb1254ce574584ebc166d293fc..187018c424bfb4ba8cadfa71a0f4ec7d4c63d766 100644 (file)
@@ -207,7 +207,7 @@ SYM_FUNC_START(__svm_vcpu_run)
 7:     vmload %_ASM_AX
 8:
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
        /* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
        FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
 #endif
@@ -344,7 +344,7 @@ SYM_FUNC_START(__svm_sev_es_vcpu_run)
        /* Pop @svm to RDI, guest registers have been saved already. */
        pop %_ASM_DI
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
        /* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
        FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
 #endif
index a6216c8747291f4c8aeed534117fad1f3808acb8..315c7c2ba89b13437fe4c3cbb93d92f75bd8f3f1 100644 (file)
@@ -71,7 +71,7 @@ static int fixed_pmc_events[] = {
 static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
 {
        struct kvm_pmc *pmc;
-       u8 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl;
+       u64 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl;
        int i;
 
        pmu->fixed_ctr_ctrl = data;
index edc3f16cc1896f29e4eef46da685d22b4c31c668..6a9bfdfbb6e59b2e613385cd2ad46cc651a0eb28 100644 (file)
@@ -2,7 +2,10 @@
 #ifndef __KVM_X86_VMX_RUN_FLAGS_H
 #define __KVM_X86_VMX_RUN_FLAGS_H
 
-#define VMX_RUN_VMRESUME       (1 << 0)
-#define VMX_RUN_SAVE_SPEC_CTRL (1 << 1)
+#define VMX_RUN_VMRESUME_SHIFT         0
+#define VMX_RUN_SAVE_SPEC_CTRL_SHIFT   1
+
+#define VMX_RUN_VMRESUME               BIT(VMX_RUN_VMRESUME_SHIFT)
+#define VMX_RUN_SAVE_SPEC_CTRL         BIT(VMX_RUN_SAVE_SPEC_CTRL_SHIFT)
 
 #endif /* __KVM_X86_VMX_RUN_FLAGS_H */
index 906ecd001511355d0939e4e90a3994a7bd9809e3..2bfbf758d06110f49c71a22c1f54da9d9499669a 100644 (file)
@@ -139,7 +139,7 @@ SYM_FUNC_START(__vmx_vcpu_run)
        mov (%_ASM_SP), %_ASM_AX
 
        /* Check if vmlaunch or vmresume is needed */
-       test $VMX_RUN_VMRESUME, %ebx
+       bt   $VMX_RUN_VMRESUME_SHIFT, %ebx
 
        /* Load guest registers.  Don't clobber flags. */
        mov VCPU_RCX(%_ASM_AX), %_ASM_CX
@@ -161,8 +161,11 @@ SYM_FUNC_START(__vmx_vcpu_run)
        /* Load guest RAX.  This kills the @regs pointer! */
        mov VCPU_RAX(%_ASM_AX), %_ASM_AX
 
-       /* Check EFLAGS.ZF from 'test VMX_RUN_VMRESUME' above */
-       jz .Lvmlaunch
+       /* Clobbers EFLAGS.ZF */
+       CLEAR_CPU_BUFFERS
+
+       /* Check EFLAGS.CF from the VMX_RUN_VMRESUME bit test above. */
+       jnc .Lvmlaunch
 
        /*
         * After a successful VMRESUME/VMLAUNCH, control flow "magically"
index 1111d9d089038b2f17b372891a235222b74f87bf..305237dcba88f975809da40e7173594491128ccd 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/desc.h>
 #include <asm/fpu/api.h>
 #include <asm/fpu/xstate.h>
+#include <asm/fred.h>
 #include <asm/idtentry.h>
 #include <asm/io.h>
 #include <asm/irq_remapping.h>
@@ -388,7 +389,16 @@ static __always_inline void vmx_enable_fb_clear(struct vcpu_vmx *vmx)
 
 static void vmx_update_fb_clear_dis(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx)
 {
-       vmx->disable_fb_clear = (host_arch_capabilities & ARCH_CAP_FB_CLEAR_CTRL) &&
+       /*
+        * Disable VERW's behavior of clearing CPU buffers for the guest if the
+        * CPU isn't affected by MDS/TAA, and the host hasn't forcefully enabled
+        * the mitigation. Disabling the clearing behavior provides a
+        * performance boost for guests that aren't aware that manually clearing
+        * CPU buffers is unnecessary, at the cost of MSR accesses on VM-Entry
+        * and VM-Exit.
+        */
+       vmx->disable_fb_clear = !cpu_feature_enabled(X86_FEATURE_CLEAR_CPU_BUF) &&
+                               (host_arch_capabilities & ARCH_CAP_FB_CLEAR_CTRL) &&
                                !boot_cpu_has_bug(X86_BUG_MDS) &&
                                !boot_cpu_has_bug(X86_BUG_TAA);
 
@@ -6543,7 +6553,7 @@ static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
 
        if (exit_reason.basic >= kvm_vmx_max_exit_handlers)
                goto unexpected_vmexit;
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
        if (exit_reason.basic == EXIT_REASON_MSR_WRITE)
                return kvm_emulate_wrmsr(vcpu);
        else if (exit_reason.basic == EXIT_REASON_PREEMPTION_TIMER)
@@ -6960,14 +6970,16 @@ static void handle_external_interrupt_irqoff(struct kvm_vcpu *vcpu)
 {
        u32 intr_info = vmx_get_intr_info(vcpu);
        unsigned int vector = intr_info & INTR_INFO_VECTOR_MASK;
-       gate_desc *desc = (gate_desc *)host_idt_base + vector;
 
        if (KVM_BUG(!is_external_intr(intr_info), vcpu->kvm,
            "unexpected VM-Exit interrupt info: 0x%x", intr_info))
                return;
 
        kvm_before_interrupt(vcpu, KVM_HANDLING_IRQ);
-       vmx_do_interrupt_irqoff(gate_offset(desc));
+       if (cpu_feature_enabled(X86_FEATURE_FRED))
+               fred_entry_from_kvm(EVENT_TYPE_EXTINT, vector);
+       else
+               vmx_do_interrupt_irqoff(gate_offset((gate_desc *)host_idt_base + vector));
        kvm_after_interrupt(vcpu);
 
        vcpu->arch.at_instruction_boundary = true;
@@ -7224,11 +7236,14 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
 
        guest_state_enter_irqoff();
 
-       /* L1D Flush includes CPU buffer clear to mitigate MDS */
+       /*
+        * L1D Flush includes CPU buffer clear to mitigate MDS, but VERW
+        * mitigation for MDS is done late in VMentry and is still
+        * executed in spite of L1D Flush. This is because an extra VERW
+        * should not matter much after the big hammer L1D Flush.
+        */
        if (static_branch_unlikely(&vmx_l1d_should_flush))
                vmx_l1d_flush(vcpu);
-       else if (static_branch_unlikely(&mds_user_clear))
-               mds_clear_cpu_buffers();
        else if (static_branch_unlikely(&mmio_stale_data_clear) &&
                 kvm_arch_has_assigned_device(vcpu->kvm))
                mds_clear_cpu_buffers();
@@ -7260,7 +7275,10 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
        if ((u16)vmx->exit_reason.basic == EXIT_REASON_EXCEPTION_NMI &&
            is_nmi(vmx_get_intr_info(vcpu))) {
                kvm_before_interrupt(vcpu, KVM_HANDLING_NMI);
-               vmx_do_nmi_irqoff();
+               if (cpu_feature_enabled(X86_FEATURE_FRED))
+                       fred_entry_from_kvm(EVENT_TYPE_NMI, NMI_VECTOR);
+               else
+                       vmx_do_nmi_irqoff();
                kvm_after_interrupt(vcpu);
        }
 
index bf10a9073a0928aaccc9d929f78d48ffcbbc06b2..ffe580169c93f078532e3ddf953a2f9cf3bde627 100644 (file)
@@ -1623,7 +1623,8 @@ static bool kvm_is_immutable_feature_msr(u32 msr)
         ARCH_CAP_SKIP_VMENTRY_L1DFLUSH | ARCH_CAP_SSB_NO | ARCH_CAP_MDS_NO | \
         ARCH_CAP_PSCHANGE_MC_NO | ARCH_CAP_TSX_CTRL_MSR | ARCH_CAP_TAA_NO | \
         ARCH_CAP_SBDR_SSDP_NO | ARCH_CAP_FBSDP_NO | ARCH_CAP_PSDP_NO | \
-        ARCH_CAP_FB_CLEAR | ARCH_CAP_RRSBA | ARCH_CAP_PBRSB_NO | ARCH_CAP_GDS_NO)
+        ARCH_CAP_FB_CLEAR | ARCH_CAP_RRSBA | ARCH_CAP_PBRSB_NO | ARCH_CAP_GDS_NO | \
+        ARCH_CAP_RFDS_NO | ARCH_CAP_RFDS_CLEAR)
 
 static u64 kvm_get_arch_capabilities(void)
 {
@@ -1655,6 +1656,8 @@ static u64 kvm_get_arch_capabilities(void)
                data |= ARCH_CAP_SSB_NO;
        if (!boot_cpu_has_bug(X86_BUG_MDS))
                data |= ARCH_CAP_MDS_NO;
+       if (!boot_cpu_has_bug(X86_BUG_RFDS))
+               data |= ARCH_CAP_RFDS_NO;
 
        if (!boot_cpu_has(X86_FEATURE_RTM)) {
                /*
@@ -1704,22 +1707,17 @@ static int do_get_msr_feature(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
        struct kvm_msr_entry msr;
        int r;
 
+       /* Unconditionally clear the output for simplicity */
+       msr.data = 0;
        msr.index = index;
        r = kvm_get_msr_feature(&msr);
 
-       if (r == KVM_MSR_RET_INVALID) {
-               /* Unconditionally clear the output for simplicity */
-               *data = 0;
-               if (kvm_msr_ignored_check(index, 0, false))
-                       r = 0;
-       }
-
-       if (r)
-               return r;
+       if (r == KVM_MSR_RET_INVALID && kvm_msr_ignored_check(index, 0, false))
+               r = 0;
 
        *data = msr.data;
 
-       return 0;
+       return r;
 }
 
 static bool __kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
@@ -2511,7 +2509,7 @@ static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
 }
 
 #ifdef CONFIG_X86_64
-static inline int gtod_is_based_on_tsc(int mode)
+static inline bool gtod_is_based_on_tsc(int mode)
 {
        return mode == VDSO_CLOCKMODE_TSC || mode == VDSO_CLOCKMODE_HVCLOCK;
 }
@@ -4585,7 +4583,7 @@ static bool kvm_is_vm_type_supported(unsigned long type)
 {
        return type == KVM_X86_DEFAULT_VM ||
               (type == KVM_X86_SW_PROTECTED_VM &&
-               IS_ENABLED(CONFIG_KVM_SW_PROTECTED_VM) && tdp_enabled);
+               IS_ENABLED(CONFIG_KVM_SW_PROTECTED_VM) && tdp_mmu_enabled);
 }
 
 int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
@@ -5458,7 +5456,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
        if (events->flags & KVM_VCPUEVENT_VALID_NMI_PENDING) {
                vcpu->arch.nmi_pending = 0;
                atomic_set(&vcpu->arch.nmi_queued, events->nmi.pending);
-               kvm_make_request(KVM_REQ_NMI, vcpu);
+               if (events->nmi.pending)
+                       kvm_make_request(KVM_REQ_NMI, vcpu);
        }
        static_call(kvm_x86_set_nmi_mask)(vcpu, events->nmi.masked);
 
@@ -8011,6 +8010,16 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
 
        if (r < 0)
                return X86EMUL_UNHANDLEABLE;
+
+       /*
+        * Mark the page dirty _before_ checking whether or not the CMPXCHG was
+        * successful, as the old value is written back on failure.  Note, for
+        * live migration, this is unnecessarily conservative as CMPXCHG writes
+        * back the original value and the access is atomic, but KVM's ABI is
+        * that all writes are dirty logged, regardless of the value written.
+        */
+       kvm_vcpu_mark_page_dirty(vcpu, gpa_to_gfn(gpa));
+
        if (r)
                return X86EMUL_CMPXCHG_FAILED;
 
index ea3a28e7b613ccbda58490702c6609057412e4c0..6da73513f02668ab5c178b3f5a01668691b79403 100644 (file)
@@ -14,19 +14,6 @@ ifdef CONFIG_KCSAN
 CFLAGS_REMOVE_delay.o = $(CC_FLAGS_FTRACE)
 endif
 
-# Early boot use of cmdline; don't instrument it
-ifdef CONFIG_AMD_MEM_ENCRYPT
-KCOV_INSTRUMENT_cmdline.o := n
-KASAN_SANITIZE_cmdline.o  := n
-KCSAN_SANITIZE_cmdline.o  := n
-
-ifdef CONFIG_FUNCTION_TRACER
-CFLAGS_REMOVE_cmdline.o = -pg
-endif
-
-CFLAGS_cmdline.o := -fno-stack-protector -fno-jump-tables
-endif
-
 inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk
 inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt
 quiet_cmd_inat_tables = GEN     $@
@@ -49,7 +36,7 @@ lib-$(CONFIG_ARCH_HAS_COPY_MC) += copy_mc.o copy_mc_64.o
 lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o insn-eval.o
 lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
 lib-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
-lib-$(CONFIG_RETPOLINE) += retpoline.o
+lib-$(CONFIG_MITIGATION_RETPOLINE) += retpoline.o
 
 obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
 obj-y += iomem.o
index 6962df3157938d9936895d67d5b18806844fb761..4fb44894ad87593266f9de2b8c71ddbad2166cbe 100644 (file)
@@ -23,14 +23,14 @@ SYM_FUNC_START(this_cpu_cmpxchg16b_emu)
        cli
 
        /* if (*ptr == old) */
-       cmpq    PER_CPU_VAR(0(%rsi)), %rax
+       cmpq    __percpu (%rsi), %rax
        jne     .Lnot_same
-       cmpq    PER_CPU_VAR(8(%rsi)), %rdx
+       cmpq    __percpu 8(%rsi), %rdx
        jne     .Lnot_same
 
        /* *ptr = new */
-       movq    %rbx, PER_CPU_VAR(0(%rsi))
-       movq    %rcx, PER_CPU_VAR(8(%rsi))
+       movq    %rbx, __percpu (%rsi)
+       movq    %rcx, __percpu 8(%rsi)
 
        /* set ZF in EFLAGS to indicate success */
        orl     $X86_EFLAGS_ZF, (%rsp)
@@ -42,8 +42,8 @@ SYM_FUNC_START(this_cpu_cmpxchg16b_emu)
        /* *ptr != old */
 
        /* old = *ptr */
-       movq    PER_CPU_VAR(0(%rsi)), %rax
-       movq    PER_CPU_VAR(8(%rsi)), %rdx
+       movq    __percpu (%rsi), %rax
+       movq    __percpu 8(%rsi), %rdx
 
        /* clear ZF in EFLAGS to indicate failure */
        andl    $(~X86_EFLAGS_ZF), (%rsp)
index 873e4ef23e49578989634629b728d4c61bcd96b4..1c96be769adc3e98c87d63dc623ed21cf770129b 100644 (file)
@@ -24,12 +24,12 @@ SYM_FUNC_START(cmpxchg8b_emu)
        pushfl
        cli
 
-       cmpl    0(%esi), %eax
+       cmpl    (%esi), %eax
        jne     .Lnot_same
        cmpl    4(%esi), %edx
        jne     .Lnot_same
 
-       movl    %ebx, 0(%esi)
+       movl    %ebx, (%esi)
        movl    %ecx, 4(%esi)
 
        orl     $X86_EFLAGS_ZF, (%esp)
@@ -38,7 +38,7 @@ SYM_FUNC_START(cmpxchg8b_emu)
        RET
 
 .Lnot_same:
-       movl    0(%esi), %eax
+       movl    (%esi), %eax
        movl    4(%esi), %edx
 
        andl    $(~X86_EFLAGS_ZF), (%esp)
@@ -53,18 +53,30 @@ EXPORT_SYMBOL(cmpxchg8b_emu)
 
 #ifndef CONFIG_UML
 
+/*
+ * Emulate 'cmpxchg8b %fs:(%rsi)'
+ *
+ * Inputs:
+ * %esi : memory location to compare
+ * %eax : low 32 bits of old value
+ * %edx : high 32 bits of old value
+ * %ebx : low 32 bits of new value
+ * %ecx : high 32 bits of new value
+ *
+ * Notably this is not LOCK prefixed and is not safe against NMIs
+ */
 SYM_FUNC_START(this_cpu_cmpxchg8b_emu)
 
        pushfl
        cli
 
-       cmpl    PER_CPU_VAR(0(%esi)), %eax
+       cmpl    __percpu (%esi), %eax
        jne     .Lnot_same2
-       cmpl    PER_CPU_VAR(4(%esi)), %edx
+       cmpl    __percpu 4(%esi), %edx
        jne     .Lnot_same2
 
-       movl    %ebx, PER_CPU_VAR(0(%esi))
-       movl    %ecx, PER_CPU_VAR(4(%esi))
+       movl    %ebx, __percpu (%esi)
+       movl    %ecx, __percpu 4(%esi)
 
        orl     $X86_EFLAGS_ZF, (%esp)
 
@@ -72,8 +84,8 @@ SYM_FUNC_START(this_cpu_cmpxchg8b_emu)
        RET
 
 .Lnot_same2:
-       movl    PER_CPU_VAR(0(%esi)), %eax
-       movl    PER_CPU_VAR(4(%esi)), %edx
+       movl    __percpu (%esi), %eax
+       movl    __percpu 4(%esi), %edx
 
        andl    $(~X86_EFLAGS_ZF), (%esp)
 
index 558a605929db52f0bd05e8b547413d5d95e7eb90..98631c0e7a11f887307e484db9ae8bc643ffaa72 100644 (file)
@@ -1129,15 +1129,15 @@ static int get_eff_addr_modrm_16(struct insn *insn, struct pt_regs *regs,
  * get_eff_addr_sib() - Obtain referenced effective address via SIB
  * @insn:      Instruction. Must be valid.
  * @regs:      Register values as seen when entering kernel mode
- * @regoff:    Obtained operand offset, in pt_regs, associated with segment
+ * @base_offset: Obtained operand offset, in pt_regs, associated with segment
  * @eff_addr:  Obtained effective address
  *
  * Obtain the effective address referenced by the SIB byte of @insn. After
  * identifying the registers involved in the indexed, register-indirect memory
  * reference, its value is obtained from the operands in @regs. The computed
  * address is stored @eff_addr. Also, the register operand that indicates the
- * associated segment is stored in @regoff, this parameter can later be used to
- * determine such segment.
+ * associated segment is stored in @base_offset; this parameter can later be
+ * used to determine such segment.
  *
  * Returns:
  *
index 55e371cc69fd5d00670a08983335e3bddfff9571..1bb155a0955b3b851e9d0cccbfe0726c5759085d 100644 (file)
@@ -71,7 +71,7 @@ void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
        insn->kaddr = kaddr;
        insn->end_kaddr = kaddr + buf_len;
        insn->next_byte = kaddr;
-       insn->x86_64 = x86_64 ? 1 : 0;
+       insn->x86_64 = x86_64;
        insn->opnd_bytes = 4;
        if (x86_64)
                insn->addr_bytes = 8;
@@ -268,11 +268,9 @@ int insn_get_opcode(struct insn *insn)
        if (opcode->got)
                return 0;
 
-       if (!insn->prefixes.got) {
-               ret = insn_get_prefixes(insn);
-               if (ret)
-                       return ret;
-       }
+       ret = insn_get_prefixes(insn);
+       if (ret)
+               return ret;
 
        /* Get first opcode */
        op = get_next(insn_byte_t, insn);
@@ -339,11 +337,9 @@ int insn_get_modrm(struct insn *insn)
        if (modrm->got)
                return 0;
 
-       if (!insn->opcode.got) {
-               ret = insn_get_opcode(insn);
-               if (ret)
-                       return ret;
-       }
+       ret = insn_get_opcode(insn);
+       if (ret)
+               return ret;
 
        if (inat_has_modrm(insn->attr)) {
                mod = get_next(insn_byte_t, insn);
@@ -386,11 +382,9 @@ int insn_rip_relative(struct insn *insn)
        if (!insn->x86_64)
                return 0;
 
-       if (!modrm->got) {
-               ret = insn_get_modrm(insn);
-               if (ret)
-                       return 0;
-       }
+       ret = insn_get_modrm(insn);
+       if (ret)
+               return 0;
        /*
         * For rip-relative instructions, the mod field (top 2 bits)
         * is zero and the r/m field (bottom 3 bits) is 0x5.
@@ -417,11 +411,9 @@ int insn_get_sib(struct insn *insn)
        if (insn->sib.got)
                return 0;
 
-       if (!insn->modrm.got) {
-               ret = insn_get_modrm(insn);
-               if (ret)
-                       return ret;
-       }
+       ret = insn_get_modrm(insn);
+       if (ret)
+               return ret;
 
        if (insn->modrm.nbytes) {
                modrm = insn->modrm.bytes[0];
@@ -460,11 +452,9 @@ int insn_get_displacement(struct insn *insn)
        if (insn->displacement.got)
                return 0;
 
-       if (!insn->sib.got) {
-               ret = insn_get_sib(insn);
-               if (ret)
-                       return ret;
-       }
+       ret = insn_get_sib(insn);
+       if (ret)
+               return ret;
 
        if (insn->modrm.nbytes) {
                /*
@@ -628,11 +618,9 @@ int insn_get_immediate(struct insn *insn)
        if (insn->immediate.got)
                return 0;
 
-       if (!insn->displacement.got) {
-               ret = insn_get_displacement(insn);
-               if (ret)
-                       return ret;
-       }
+       ret = insn_get_displacement(insn);
+       if (ret)
+               return ret;
 
        if (inat_has_moffset(insn->attr)) {
                if (!__get_moffset(insn))
@@ -703,11 +691,9 @@ int insn_get_length(struct insn *insn)
        if (insn->length)
                return 0;
 
-       if (!insn->immediate.got) {
-               ret = insn_get_immediate(insn);
-               if (ret)
-                       return ret;
-       }
+       ret = insn_get_immediate(insn);
+       if (ret)
+               return ret;
 
        insn->length = (unsigned char)((unsigned long)insn->next_byte
                                     - (unsigned long)insn->kaddr);
index 40bbe56bde3256eadea3d68a01b6af713b943552..acd463d887e1c0bb384ca85aebc900b1461a6618 100644 (file)
@@ -9,10 +9,9 @@ static void __rdmsr_on_cpu(void *info)
 {
        struct msr_info *rv = info;
        struct msr *reg;
-       int this_cpu = raw_smp_processor_id();
 
        if (rv->msrs)
-               reg = per_cpu_ptr(rv->msrs, this_cpu);
+               reg = this_cpu_ptr(rv->msrs);
        else
                reg = &rv->reg;
 
@@ -23,10 +22,9 @@ static void __wrmsr_on_cpu(void *info)
 {
        struct msr_info *rv = info;
        struct msr *reg;
-       int this_cpu = raw_smp_processor_id();
 
        if (rv->msrs)
-               reg = per_cpu_ptr(rv->msrs, this_cpu);
+               reg = this_cpu_ptr(rv->msrs);
        else
                reg = &rv->reg;
 
@@ -97,7 +95,7 @@ int wrmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 q)
 EXPORT_SYMBOL(wrmsrl_on_cpu);
 
 static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
-                           struct msr *msrs,
+                           struct msr __percpu *msrs,
                            void (*msr_func) (void *info))
 {
        struct msr_info rv;
@@ -124,7 +122,7 @@ static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
  * @msrs:       array of MSR values
  *
  */
-void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr __percpu *msrs)
 {
        __rwmsr_on_cpus(mask, msr_no, msrs, __rdmsr_on_cpu);
 }
@@ -138,7 +136,7 @@ EXPORT_SYMBOL(rdmsr_on_cpus);
  * @msrs:       array of MSR values
  *
  */
-void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr __percpu *msrs)
 {
        __rwmsr_on_cpus(mask, msr_no, msrs, __wrmsr_on_cpu);
 }
index 47fd9bd6b91d8c2e69434a112b369e0d243c38d1..4bf4fad5b148ef37804e77f42d0676ca13823749 100644 (file)
@@ -6,9 +6,9 @@
 #define CREATE_TRACE_POINTS
 #include <asm/msr-trace.h>
 
-struct msr *msrs_alloc(void)
+struct msr __percpu *msrs_alloc(void)
 {
-       struct msr *msrs = NULL;
+       struct msr __percpu *msrs = NULL;
 
        msrs = alloc_percpu(struct msr);
        if (!msrs) {
@@ -20,7 +20,7 @@ struct msr *msrs_alloc(void)
 }
 EXPORT_SYMBOL(msrs_alloc);
 
-void msrs_free(struct msr *msrs)
+void msrs_free(struct msr __percpu *msrs)
 {
        free_percpu(msrs);
 }
index 7b2589877d065fd1e511ceb98e176a6bfd236b5e..721b528da9acee3e4eb2168bbd65ab7303a4db3a 100644 (file)
@@ -71,7 +71,7 @@ SYM_CODE_END(__x86_indirect_thunk_array)
 #include <asm/GEN-for-each-reg.h>
 #undef GEN
 
-#ifdef CONFIG_CALL_DEPTH_TRACKING
+#ifdef CONFIG_MITIGATION_CALL_DEPTH_TRACKING
 .macro CALL_THUNK reg
        .align RETPOLINE_THUNK_SIZE
 
@@ -127,7 +127,7 @@ SYM_CODE_END(__x86_indirect_jump_thunk_array)
 #undef GEN
 #endif
 
-#ifdef CONFIG_RETHUNK
+#ifdef CONFIG_MITIGATION_RETHUNK
 
 /*
  * Be careful here: that label cannot really be removed because in
@@ -138,7 +138,7 @@ SYM_CODE_END(__x86_indirect_jump_thunk_array)
  */
        .section .text..__x86.return_thunk
 
-#ifdef CONFIG_CPU_SRSO
+#ifdef CONFIG_MITIGATION_SRSO
 
 /*
  * srso_alias_untrain_ret() and srso_alias_safe_ret() are placed at
@@ -225,12 +225,12 @@ SYM_CODE_END(srso_return_thunk)
 
 #define JMP_SRSO_UNTRAIN_RET "jmp srso_untrain_ret"
 #define JMP_SRSO_ALIAS_UNTRAIN_RET "jmp srso_alias_untrain_ret"
-#else /* !CONFIG_CPU_SRSO */
+#else /* !CONFIG_MITIGATION_SRSO */
 #define JMP_SRSO_UNTRAIN_RET "ud2"
 #define JMP_SRSO_ALIAS_UNTRAIN_RET "ud2"
-#endif /* CONFIG_CPU_SRSO */
+#endif /* CONFIG_MITIGATION_SRSO */
 
-#ifdef CONFIG_CPU_UNRET_ENTRY
+#ifdef CONFIG_MITIGATION_UNRET_ENTRY
 
 /*
  * Some generic notes on the untraining sequences:
@@ -312,11 +312,11 @@ SYM_CODE_END(retbleed_return_thunk)
 SYM_FUNC_END(retbleed_untrain_ret)
 
 #define JMP_RETBLEED_UNTRAIN_RET "jmp retbleed_untrain_ret"
-#else /* !CONFIG_CPU_UNRET_ENTRY */
+#else /* !CONFIG_MITIGATION_UNRET_ENTRY */
 #define JMP_RETBLEED_UNTRAIN_RET "ud2"
-#endif /* CONFIG_CPU_UNRET_ENTRY */
+#endif /* CONFIG_MITIGATION_UNRET_ENTRY */
 
-#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_SRSO)
+#if defined(CONFIG_MITIGATION_UNRET_ENTRY) || defined(CONFIG_MITIGATION_SRSO)
 
 SYM_FUNC_START(entry_untrain_ret)
        ALTERNATIVE_2 JMP_RETBLEED_UNTRAIN_RET,                         \
@@ -325,9 +325,9 @@ SYM_FUNC_START(entry_untrain_ret)
 SYM_FUNC_END(entry_untrain_ret)
 __EXPORT_THUNK(entry_untrain_ret)
 
-#endif /* CONFIG_CPU_UNRET_ENTRY || CONFIG_CPU_SRSO */
+#endif /* CONFIG_MITIGATION_UNRET_ENTRY || CONFIG_MITIGATION_SRSO */
 
-#ifdef CONFIG_CALL_DEPTH_TRACKING
+#ifdef CONFIG_MITIGATION_CALL_DEPTH_TRACKING
 
        .align 64
 SYM_FUNC_START(call_depth_return_thunk)
@@ -359,7 +359,7 @@ SYM_FUNC_START(call_depth_return_thunk)
        int3
 SYM_FUNC_END(call_depth_return_thunk)
 
-#endif /* CONFIG_CALL_DEPTH_TRACKING */
+#endif /* CONFIG_MITIGATION_CALL_DEPTH_TRACKING */
 
 /*
  * This function name is magical and is used by -mfunction-return=thunk-extern
@@ -369,21 +369,18 @@ SYM_FUNC_END(call_depth_return_thunk)
  * 'JMP __x86_return_thunk' sites are changed to something else by
  * apply_returns().
  *
- * This should be converted eventually to call a warning function which
- * should scream loudly when the default return thunk is called after
- * alternatives have been applied.
- *
- * That warning function cannot BUG() because the bug splat cannot be
- * displayed in all possible configurations, leading to users not really
- * knowing why the machine froze.
+ * The ALTERNATIVE below adds a really loud warning to catch the case
+ * where the insufficient default return thunk ends up getting used for
+ * whatever reason like miscompilation or failure of
+ * objtool/alternatives/etc to patch all the return sites.
  */
 SYM_CODE_START(__x86_return_thunk)
        UNWIND_HINT_FUNC
        ANNOTATE_NOENDBR
-       ANNOTATE_UNRET_SAFE
-       ret
+       ALTERNATIVE __stringify(ANNOTATE_UNRET_SAFE; ret), \
+                  "jmp warn_thunk_thunk", X86_FEATURE_ALWAYS
        int3
 SYM_CODE_END(__x86_return_thunk)
 EXPORT_SYMBOL(__x86_return_thunk)
 
-#endif /* CONFIG_RETHUNK */
+#endif /* CONFIG_MITIGATION_RETHUNK */
index 5168ee0360b2461e90f51d3d8c6a8377e2c62cbd..12af572201a29fe8fe8cfe9c9796ddb26eabf330 100644 (file)
@@ -1051,8 +1051,8 @@ GrpTable: Grp6
 EndTable
 
 GrpTable: Grp7
-0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) | PCONFIG (101),(11B) | ENCLV (000),(11B)
-1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) | ENCLS (111),(11B)
+0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) | PCONFIG (101),(11B) | ENCLV (000),(11B) | WRMSRNS (110),(11B)
+1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) | ENCLS (111),(11B) | ERETU (F3),(010),(11B) | ERETS (F2),(010),(11B)
 2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) | ENCLU (111),(11B)
 3: LIDT Ms
 4: SMSW Mw/Rv
index c80febc44cd2feed47bf3c419accb98b12c1e38b..428048e73bd2e2326964f2565bc40df18d628ff5 100644 (file)
@@ -16,6 +16,7 @@ KASAN_SANITIZE_pgprot.o               := n
 KCSAN_SANITIZE := n
 # Avoid recursion by not calling KMSAN hooks for CEA code.
 KMSAN_SANITIZE_cpu_entry_area.o := n
+KMSAN_SANITIZE_mem_encrypt_identity.o := n
 
 ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_mem_encrypt.o            = -pg
@@ -60,7 +61,7 @@ obj-$(CONFIG_NUMA_EMU)                += numa_emulation.o
 
 obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o
 obj-$(CONFIG_RANDOMIZE_MEMORY)                 += kaslr.o
-obj-$(CONFIG_PAGE_TABLE_ISOLATION)             += pti.o
+obj-$(CONFIG_MITIGATION_PAGE_TABLE_ISOLATION)  += pti.o
 
 obj-$(CONFIG_X86_MEM_ENCRYPT)  += mem_encrypt.o
 obj-$(CONFIG_AMD_MEM_ENCRYPT)  += mem_encrypt_amd.o
index b3ca7d23e4b01c7ae719e954408c234d21d89cdf..9332b36a10915c1f93004541e03de0530ecd755c 100644 (file)
@@ -54,13 +54,11 @@ static __init int find_northbridge(void)
 
 int __init amd_numa_init(void)
 {
-       u64 start = PFN_PHYS(0);
+       unsigned int numnodes, cores, apicid;
+       u64 prevbase, start = PFN_PHYS(0);
        u64 end = PFN_PHYS(max_pfn);
-       unsigned numnodes;
-       u64 prevbase;
-       int i, j, nb;
        u32 nodeid, reg;
-       unsigned int bits, cores, apicid_base;
+       int i, j, nb;
 
        if (!early_pci_allowed())
                return -EINVAL;
@@ -158,26 +156,18 @@ int __init amd_numa_init(void)
                return -ENOENT;
 
        /*
-        * We seem to have valid NUMA configuration.  Map apicids to nodes
-        * using the coreid bits from early_identify_cpu.
+        * We seem to have valid NUMA configuration. Map apicids to nodes
+        * using the size of the core domain in the APIC space.
         */
-       bits = boot_cpu_data.x86_coreid_bits;
-       cores = 1 << bits;
-       apicid_base = 0;
+       cores = topology_get_domain_size(TOPO_CORE_DOMAIN);
 
-       /*
-        * get boot-time SMP configuration:
-        */
-       early_get_smp_config();
+       apicid = boot_cpu_physical_apicid;
+       if (apicid > 0)
+               pr_info("BSP APIC ID: %02x\n", apicid);
 
-       if (boot_cpu_physical_apicid > 0) {
-               pr_info("BSP APIC ID: %02x\n", boot_cpu_physical_apicid);
-               apicid_base = boot_cpu_physical_apicid;
+       for_each_node_mask(i, numa_nodes_parsed) {
+               for (j = 0; j < cores; j++, apicid++)
+                       set_apicid_to_node(apicid, i);
        }
-
-       for_each_node_mask(i, numa_nodes_parsed)
-               for (j = apicid_base; j < cores + apicid_base; j++)
-                       set_apicid_to_node((i << bits) + j, i);
-
        return 0;
 }
index b43301cb2a80ca0de4416d8bc51f423eee4a87d1..ae5c213a1cb0064a8a1a26d406aab70ebc031fc4 100644 (file)
@@ -22,7 +22,7 @@ static int ptdump_curknl_show(struct seq_file *m, void *v)
 
 DEFINE_SHOW_ATTRIBUTE(ptdump_curknl);
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 static int ptdump_curusr_show(struct seq_file *m, void *v)
 {
        if (current->mm->pgd)
@@ -54,7 +54,7 @@ static int __init pt_dump_debug_init(void)
        debugfs_create_file("current_kernel", 0400, dir, NULL,
                            &ptdump_curknl_fops);
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
        debugfs_create_file("current_user", 0400, dir, NULL,
                            &ptdump_curusr_fops);
 #endif
index e1b599ecbbc26d02c2de09a589f899f0eebca01d..b7b88c1d91ec4698685c9e2e8f49a2f06e343862 100644 (file)
@@ -408,7 +408,7 @@ void ptdump_walk_pgd_level_debugfs(struct seq_file *m, struct mm_struct *mm,
                                   bool user)
 {
        pgd_t *pgd = mm->pgd;
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
        if (user && boot_cpu_has(X86_FEATURE_PTI))
                pgd = kernel_to_user_pgdp(pgd);
 #endif
@@ -418,7 +418,7 @@ EXPORT_SYMBOL_GPL(ptdump_walk_pgd_level_debugfs);
 
 void ptdump_walk_user_pgd_level_checkwx(void)
 {
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
        pgd_t *pgd = INIT_PGD;
 
        if (!(__supported_pte_mask & _PAGE_NX) ||
index 271dcb2deabc31baf4789b347b42faf6394bed88..b522933bfa56e8afeeba6816dc3ca782f7111d77 100644 (file)
@@ -6,6 +6,7 @@
 #include <xen/xen.h>
 
 #include <asm/fpu/api.h>
+#include <asm/fred.h>
 #include <asm/sev.h>
 #include <asm/traps.h>
 #include <asm/kdebug.h>
@@ -223,6 +224,79 @@ static bool ex_handler_ucopy_len(const struct exception_table_entry *fixup,
        return ex_handler_uaccess(fixup, regs, trapnr, fault_address);
 }
 
+#ifdef CONFIG_X86_FRED
+static bool ex_handler_eretu(const struct exception_table_entry *fixup,
+                            struct pt_regs *regs, unsigned long error_code)
+{
+       struct pt_regs *uregs = (struct pt_regs *)(regs->sp - offsetof(struct pt_regs, orig_ax));
+       unsigned short ss = uregs->ss;
+       unsigned short cs = uregs->cs;
+
+       /*
+        * Move the NMI bit from the invalid stack frame, which caused ERETU
+        * to fault, to the fault handler's stack frame, thus to unblock NMI
+        * with the fault handler's ERETS instruction ASAP if NMI is blocked.
+        */
+       regs->fred_ss.nmi = uregs->fred_ss.nmi;
+
+       /*
+        * Sync event information to uregs, i.e., the ERETU return frame, but
+        * is it safe to write to the ERETU return frame which is just above
+        * current event stack frame?
+        *
+        * The RSP used by FRED to push a stack frame is not the value in %rsp,
+        * it is calculated from %rsp with the following 2 steps:
+        * 1) RSP = %rsp - (IA32_FRED_CONFIG & 0x1c0)   // Reserve N*64 bytes
+        * 2) RSP = RSP & ~0x3f         // Align to a 64-byte cache line
+        * when an event delivery doesn't trigger a stack level change.
+        *
+        * Here is an example with N*64 (N=1) bytes reserved:
+        *
+        *  64-byte cache line ==>  ______________
+        *                         |___Reserved___|
+        *                         |__Event_data__|
+        *                         |_____SS_______|
+        *                         |_____RSP______|
+        *                         |_____FLAGS____|
+        *                         |_____CS_______|
+        *                         |_____IP_______|
+        *  64-byte cache line ==> |__Error_code__| <== ERETU return frame
+        *                         |______________|
+        *                         |______________|
+        *                         |______________|
+        *                         |______________|
+        *                         |______________|
+        *                         |______________|
+        *                         |______________|
+        *  64-byte cache line ==> |______________| <== RSP after step 1) and 2)
+        *                         |___Reserved___|
+        *                         |__Event_data__|
+        *                         |_____SS_______|
+        *                         |_____RSP______|
+        *                         |_____FLAGS____|
+        *                         |_____CS_______|
+        *                         |_____IP_______|
+        *  64-byte cache line ==> |__Error_code__| <== ERETS return frame
+        *
+        * Thus a new FRED stack frame will always be pushed below a previous
+        * FRED stack frame ((N*64) bytes may be reserved between), and it is
+        * safe to write to a previous FRED stack frame as they never overlap.
+        */
+       fred_info(uregs)->edata = fred_event_data(regs);
+       uregs->ssx = regs->ssx;
+       uregs->fred_ss.ss = ss;
+       /* The NMI bit was moved away above */
+       uregs->fred_ss.nmi = 0;
+       uregs->csx = regs->csx;
+       uregs->fred_cs.sl = 0;
+       uregs->fred_cs.wfe = 0;
+       uregs->cs = cs;
+       uregs->orig_ax = error_code;
+
+       return ex_handler_default(fixup, regs);
+}
+#endif
+
 int ex_get_fixup_type(unsigned long ip)
 {
        const struct exception_table_entry *e = search_exception_tables(ip);
@@ -300,6 +374,10 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
                return ex_handler_ucopy_len(e, regs, trapnr, fault_addr, reg, imm);
        case EX_TYPE_ZEROPAD:
                return ex_handler_zeropad(e, regs, fault_addr);
+#ifdef CONFIG_X86_FRED
+       case EX_TYPE_ERETU:
+               return ex_handler_eretu(e, regs, error_code);
+#endif
        }
        BUG();
 }
index 679b09cfe241c72e7f85bd7bbd406d59a259bf2a..402e08f6b7ec9c78ec95826c8c7b3d5c06291632 100644 (file)
@@ -34,6 +34,8 @@
 #include <asm/kvm_para.h>              /* kvm_handle_async_pf          */
 #include <asm/vdso.h>                  /* fixup_vdso_exception()       */
 #include <asm/irq_stack.h>
+#include <asm/fred.h>
+#include <asm/sev.h>                   /* snp_dump_hva_rmpentry()      */
 
 #define CREATE_TRACE_POINTS
 #include <asm/trace/exceptions.h>
@@ -547,6 +549,7 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code, unsigned long ad
                 !(error_code & X86_PF_PROT) ? "not-present page" :
                 (error_code & X86_PF_RSVD)  ? "reserved bit violation" :
                 (error_code & X86_PF_PK)    ? "protection keys violation" :
+                (error_code & X86_PF_RMP)   ? "RMP violation" :
                                               "permissions violation");
 
        if (!(error_code & X86_PF_USER) && user_mode(regs)) {
@@ -579,6 +582,9 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code, unsigned long ad
        }
 
        dump_pagetable(address);
+
+       if (error_code & X86_PF_RMP)
+               snp_dump_hva_rmpentry(address);
 }
 
 static noinline void
@@ -798,15 +804,6 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code,
        show_opcodes(regs, loglvl);
 }
 
-/*
- * The (legacy) vsyscall page is the long page in the kernel portion
- * of the address space that has user-accessible permissions.
- */
-static bool is_vsyscall_vaddr(unsigned long vaddr)
-{
-       return unlikely((vaddr & PAGE_MASK) == VSYSCALL_ADDR);
-}
-
 static void
 __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
                       unsigned long address, u32 pkey, int si_code)
@@ -1302,21 +1299,14 @@ void do_user_addr_fault(struct pt_regs *regs,
                return;
        }
 
-       /*
-        * It's safe to allow irq's after cr2 has been saved and the
-        * vmalloc fault has been handled.
-        *
-        * User-mode registers count as a user access even for any
-        * potential system fault or CPU buglet:
-        */
-       if (user_mode(regs)) {
-               local_irq_enable();
-               flags |= FAULT_FLAG_USER;
-       } else {
-               if (regs->flags & X86_EFLAGS_IF)
-                       local_irq_enable();
+       /* Legacy check - remove this after verifying that it doesn't trigger */
+       if (WARN_ON_ONCE(!(regs->flags & X86_EFLAGS_IF))) {
+               bad_area_nosemaphore(regs, error_code, address);
+               return;
        }
 
+       local_irq_enable();
+
        perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
 
        /*
@@ -1332,6 +1322,14 @@ void do_user_addr_fault(struct pt_regs *regs,
        if (error_code & X86_PF_INSTR)
                flags |= FAULT_FLAG_INSTRUCTION;
 
+       /*
+        * We set FAULT_FLAG_USER based on the register state, not
+        * based on X86_PF_USER. User space accesses that cause
+        * system page faults are still user accesses.
+        */
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
+
 #ifdef CONFIG_X86_64
        /*
         * Faults in the vsyscall page might need emulation.  The
@@ -1518,8 +1516,10 @@ handle_page_fault(struct pt_regs *regs, unsigned long error_code,
 
 DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault)
 {
-       unsigned long address = read_cr2();
        irqentry_state_t state;
+       unsigned long address;
+
+       address = cpu_feature_enabled(X86_FEATURE_FRED) ? fred_event_data(regs) : read_cr2();
 
        prefetchw(&current->mm->mmap_lock);
 
index 968d7005f4a72454ccf8678967f040fe06f36ad6..f50cc210a981886e7d3a265b4d43ca16f47f6825 100644 (file)
@@ -26,18 +26,31 @@ static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
        for (; addr < end; addr = next) {
                pud_t *pud = pud_page + pud_index(addr);
                pmd_t *pmd;
+               bool use_gbpage;
 
                next = (addr & PUD_MASK) + PUD_SIZE;
                if (next > end)
                        next = end;
 
-               if (info->direct_gbpages) {
-                       pud_t pudval;
+               /* if this is already a gbpage, this portion is already mapped */
+               if (pud_large(*pud))
+                       continue;
+
+               /* Is using a gbpage allowed? */
+               use_gbpage = info->direct_gbpages;
 
-                       if (pud_present(*pud))
-                               continue;
+               /* Don't use gbpage if it maps more than the requested region. */
+               /* at the begining: */
+               use_gbpage &= ((addr & ~PUD_MASK) == 0);
+               /* ... or at the end: */
+               use_gbpage &= ((next & ~PUD_MASK) == 0);
+
+               /* Never overwrite existing mappings */
+               use_gbpage &= !pud_present(*pud);
+
+               if (use_gbpage) {
+                       pud_t pudval;
 
-                       addr &= PUD_MASK;
                        pudval = __pud((addr - info->offset) | info->page_flag);
                        set_pud(pud, pudval);
                        continue;
index 6993f026adec9d12a68cdbf3af3314336882f36f..42115ac079cfe617b76199a167c61e5b3c7de10f 100644 (file)
@@ -3,6 +3,8 @@
 #include <linux/uaccess.h>
 #include <linux/kernel.h>
 
+#include <asm/vsyscall.h>
+
 #ifdef CONFIG_X86_64
 bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size)
 {
@@ -15,6 +17,14 @@ bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size)
        if (vaddr < TASK_SIZE_MAX + PAGE_SIZE)
                return false;
 
+       /*
+        * Reading from the vsyscall page may cause an unhandled fault in
+        * certain cases.  Though it is at an address above TASK_SIZE_MAX, it is
+        * usually considered as a user space address.
+        */
+       if (is_vsyscall_vaddr(vaddr))
+               return false;
+
        /*
         * Allow everything during early boot before 'x86_virt_bits'
         * is initialized.  Needed for instruction decoding in early
index c290c55b632bd76e99385831c45748b7c7ada891..6f3b3e028718556667c1d86e8f56442eafc78dcc 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/mem_encrypt.h>
 #include <linux/virtio_anchor.h>
 
+#include <asm/sev.h>
+
 /* Override for DMA direct allocation check - ARCH_HAS_FORCE_DMA_UNENCRYPTED */
 bool force_dma_unencrypted(struct device *dev)
 {
@@ -42,38 +44,45 @@ bool force_dma_unencrypted(struct device *dev)
 
 static void print_mem_encrypt_feature_info(void)
 {
-       pr_info("Memory Encryption Features active:");
-
-       if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) {
-               pr_cont(" Intel TDX\n");
-               return;
-       }
+       pr_info("Memory Encryption Features active: ");
 
-       pr_cont(" AMD");
+       switch (cc_vendor) {
+       case CC_VENDOR_INTEL:
+               pr_cont("Intel TDX\n");
+               break;
+       case CC_VENDOR_AMD:
+               pr_cont("AMD");
 
-       /* Secure Memory Encryption */
-       if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)) {
+               /* Secure Memory Encryption */
+               if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)) {
                /*
                 * SME is mutually exclusive with any of the SEV
                 * features below.
-                */
-               pr_cont(" SME\n");
-               return;
-       }
+               */
+                       pr_cont(" SME\n");
+                       return;
+               }
 
-       /* Secure Encrypted Virtualization */
-       if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
-               pr_cont(" SEV");
+               /* Secure Encrypted Virtualization */
+               if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
+                       pr_cont(" SEV");
+
+               /* Encrypted Register State */
+               if (cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT))
+                       pr_cont(" SEV-ES");
 
-       /* Encrypted Register State */
-       if (cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT))
-               pr_cont(" SEV-ES");
+               /* Secure Nested Paging */
+               if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
+                       pr_cont(" SEV-SNP");
 
-       /* Secure Nested Paging */
-       if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
-               pr_cont(" SEV-SNP");
+               pr_cont("\n");
 
-       pr_cont("\n");
+               sev_show_status();
+
+               break;
+       default:
+               pr_cont("Unknown\n");
+       }
 }
 
 /* Architecture __weak replacement functions */
index d73aeb16417fcfbb99607c3bc2241962e3590948..64b5005d49e5770deb25961a66084dec7185537d 100644 (file)
@@ -41,9 +41,9 @@
 #include <linux/mem_encrypt.h>
 #include <linux/cc_platform.h>
 
+#include <asm/init.h>
 #include <asm/setup.h>
 #include <asm/sections.h>
-#include <asm/cmdline.h>
 #include <asm/coco.h>
 #include <asm/sev.h>
 
@@ -95,11 +95,7 @@ struct sme_populate_pgd_data {
  */
 static char sme_workarea[2 * PMD_SIZE] __section(".init.scratch");
 
-static char sme_cmdline_arg[] __initdata = "mem_encrypt";
-static char sme_cmdline_on[]  __initdata = "on";
-static char sme_cmdline_off[] __initdata = "off";
-
-static void __init sme_clear_pgd(struct sme_populate_pgd_data *ppd)
+static void __head sme_clear_pgd(struct sme_populate_pgd_data *ppd)
 {
        unsigned long pgd_start, pgd_end, pgd_size;
        pgd_t *pgd_p;
@@ -114,7 +110,7 @@ static void __init sme_clear_pgd(struct sme_populate_pgd_data *ppd)
        memset(pgd_p, 0, pgd_size);
 }
 
-static pud_t __init *sme_prepare_pgd(struct sme_populate_pgd_data *ppd)
+static pud_t __head *sme_prepare_pgd(struct sme_populate_pgd_data *ppd)
 {
        pgd_t *pgd;
        p4d_t *p4d;
@@ -151,7 +147,7 @@ static pud_t __init *sme_prepare_pgd(struct sme_populate_pgd_data *ppd)
        return pud;
 }
 
-static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd)
+static void __head sme_populate_pgd_large(struct sme_populate_pgd_data *ppd)
 {
        pud_t *pud;
        pmd_t *pmd;
@@ -167,7 +163,7 @@ static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd)
        set_pmd(pmd, __pmd(ppd->paddr | ppd->pmd_flags));
 }
 
-static void __init sme_populate_pgd(struct sme_populate_pgd_data *ppd)
+static void __head sme_populate_pgd(struct sme_populate_pgd_data *ppd)
 {
        pud_t *pud;
        pmd_t *pmd;
@@ -193,7 +189,7 @@ static void __init sme_populate_pgd(struct sme_populate_pgd_data *ppd)
                set_pte(pte, __pte(ppd->paddr | ppd->pte_flags));
 }
 
-static void __init __sme_map_range_pmd(struct sme_populate_pgd_data *ppd)
+static void __head __sme_map_range_pmd(struct sme_populate_pgd_data *ppd)
 {
        while (ppd->vaddr < ppd->vaddr_end) {
                sme_populate_pgd_large(ppd);
@@ -203,7 +199,7 @@ static void __init __sme_map_range_pmd(struct sme_populate_pgd_data *ppd)
        }
 }
 
-static void __init __sme_map_range_pte(struct sme_populate_pgd_data *ppd)
+static void __head __sme_map_range_pte(struct sme_populate_pgd_data *ppd)
 {
        while (ppd->vaddr < ppd->vaddr_end) {
                sme_populate_pgd(ppd);
@@ -213,7 +209,7 @@ static void __init __sme_map_range_pte(struct sme_populate_pgd_data *ppd)
        }
 }
 
-static void __init __sme_map_range(struct sme_populate_pgd_data *ppd,
+static void __head __sme_map_range(struct sme_populate_pgd_data *ppd,
                                   pmdval_t pmd_flags, pteval_t pte_flags)
 {
        unsigned long vaddr_end;
@@ -237,22 +233,22 @@ static void __init __sme_map_range(struct sme_populate_pgd_data *ppd,
        __sme_map_range_pte(ppd);
 }
 
-static void __init sme_map_range_encrypted(struct sme_populate_pgd_data *ppd)
+static void __head sme_map_range_encrypted(struct sme_populate_pgd_data *ppd)
 {
        __sme_map_range(ppd, PMD_FLAGS_ENC, PTE_FLAGS_ENC);
 }
 
-static void __init sme_map_range_decrypted(struct sme_populate_pgd_data *ppd)
+static void __head sme_map_range_decrypted(struct sme_populate_pgd_data *ppd)
 {
        __sme_map_range(ppd, PMD_FLAGS_DEC, PTE_FLAGS_DEC);
 }
 
-static void __init sme_map_range_decrypted_wp(struct sme_populate_pgd_data *ppd)
+static void __head sme_map_range_decrypted_wp(struct sme_populate_pgd_data *ppd)
 {
        __sme_map_range(ppd, PMD_FLAGS_DEC_WP, PTE_FLAGS_DEC_WP);
 }
 
-static unsigned long __init sme_pgtable_calc(unsigned long len)
+static unsigned long __head sme_pgtable_calc(unsigned long len)
 {
        unsigned long entries = 0, tables = 0;
 
@@ -289,7 +285,7 @@ static unsigned long __init sme_pgtable_calc(unsigned long len)
        return entries + tables;
 }
 
-void __init sme_encrypt_kernel(struct boot_params *bp)
+void __head sme_encrypt_kernel(struct boot_params *bp)
 {
        unsigned long workarea_start, workarea_end, workarea_len;
        unsigned long execute_start, execute_end, execute_len;
@@ -305,7 +301,8 @@ void __init sme_encrypt_kernel(struct boot_params *bp)
         * instrumentation or checking boot_cpu_data in the cc_platform_has()
         * function.
         */
-       if (!sme_get_me_mask() || sev_status & MSR_AMD64_SEV_ENABLED)
+       if (!sme_get_me_mask() ||
+           RIP_REL_REF(sev_status) & MSR_AMD64_SEV_ENABLED)
                return;
 
        /*
@@ -323,9 +320,8 @@ void __init sme_encrypt_kernel(struct boot_params *bp)
         *     memory from being cached.
         */
 
-       /* Physical addresses gives us the identity mapped virtual addresses */
-       kernel_start = __pa_symbol(_text);
-       kernel_end = ALIGN(__pa_symbol(_end), PMD_SIZE);
+       kernel_start = (unsigned long)RIP_REL_REF(_text);
+       kernel_end = ALIGN((unsigned long)RIP_REL_REF(_end), PMD_SIZE);
        kernel_len = kernel_end - kernel_start;
 
        initrd_start = 0;
@@ -342,14 +338,6 @@ void __init sme_encrypt_kernel(struct boot_params *bp)
        }
 #endif
 
-       /*
-        * We're running identity mapped, so we must obtain the address to the
-        * SME encryption workarea using rip-relative addressing.
-        */
-       asm ("lea sme_workarea(%%rip), %0"
-            : "=r" (workarea_start)
-            : "p" (sme_workarea));
-
        /*
         * Calculate required number of workarea bytes needed:
         *   executable encryption area size:
@@ -359,7 +347,7 @@ void __init sme_encrypt_kernel(struct boot_params *bp)
         *   pagetable structures for the encryption of the kernel
         *   pagetable structures for workarea (in case not currently mapped)
         */
-       execute_start = workarea_start;
+       execute_start = workarea_start = (unsigned long)RIP_REL_REF(sme_workarea);
        execute_end = execute_start + (PAGE_SIZE * 2) + PMD_SIZE;
        execute_len = execute_end - execute_start;
 
@@ -502,14 +490,11 @@ void __init sme_encrypt_kernel(struct boot_params *bp)
        native_write_cr3(__native_read_cr3());
 }
 
-void __init sme_enable(struct boot_params *bp)
+void __head sme_enable(struct boot_params *bp)
 {
-       const char *cmdline_ptr, *cmdline_arg, *cmdline_on, *cmdline_off;
        unsigned int eax, ebx, ecx, edx;
        unsigned long feature_mask;
-       bool active_by_default;
        unsigned long me_mask;
-       char buffer[16];
        bool snp;
        u64 msr;
 
@@ -543,15 +528,18 @@ void __init sme_enable(struct boot_params *bp)
        me_mask = 1UL << (ebx & 0x3f);
 
        /* Check the SEV MSR whether SEV or SME is enabled */
-       sev_status   = __rdmsr(MSR_AMD64_SEV);
-       feature_mask = (sev_status & MSR_AMD64_SEV_ENABLED) ? AMD_SEV_BIT : AMD_SME_BIT;
+       RIP_REL_REF(sev_status) = msr = __rdmsr(MSR_AMD64_SEV);
+       feature_mask = (msr & MSR_AMD64_SEV_ENABLED) ? AMD_SEV_BIT : AMD_SME_BIT;
 
        /* The SEV-SNP CC blob should never be present unless SEV-SNP is enabled. */
-       if (snp && !(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
+       if (snp && !(msr & MSR_AMD64_SEV_SNP_ENABLED))
                snp_abort();
 
        /* Check if memory encryption is enabled */
        if (feature_mask == AMD_SME_BIT) {
+               if (!(bp->hdr.xloadflags & XLF_MEM_ENCRYPTION))
+                       return;
+
                /*
                 * No SME if Hypervisor bit is set. This check is here to
                 * prevent a guest from trying to enable SME. For running as a
@@ -571,48 +559,10 @@ void __init sme_enable(struct boot_params *bp)
                msr = __rdmsr(MSR_AMD64_SYSCFG);
                if (!(msr & MSR_AMD64_SYSCFG_MEM_ENCRYPT))
                        return;
-       } else {
-               /* SEV state cannot be controlled by a command line option */
-               sme_me_mask = me_mask;
-               goto out;
        }
 
-       /*
-        * Fixups have not been applied to phys_base yet and we're running
-        * identity mapped, so we must obtain the address to the SME command
-        * line argument data using rip-relative addressing.
-        */
-       asm ("lea sme_cmdline_arg(%%rip), %0"
-            : "=r" (cmdline_arg)
-            : "p" (sme_cmdline_arg));
-       asm ("lea sme_cmdline_on(%%rip), %0"
-            : "=r" (cmdline_on)
-            : "p" (sme_cmdline_on));
-       asm ("lea sme_cmdline_off(%%rip), %0"
-            : "=r" (cmdline_off)
-            : "p" (sme_cmdline_off));
-
-       if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT))
-               active_by_default = true;
-       else
-               active_by_default = false;
-
-       cmdline_ptr = (const char *)((u64)bp->hdr.cmd_line_ptr |
-                                    ((u64)bp->ext_cmd_line_ptr << 32));
-
-       if (cmdline_find_option(cmdline_ptr, cmdline_arg, buffer, sizeof(buffer)) < 0)
-               return;
-
-       if (!strncmp(buffer, cmdline_on, sizeof(buffer)))
-               sme_me_mask = me_mask;
-       else if (!strncmp(buffer, cmdline_off, sizeof(buffer)))
-               sme_me_mask = 0;
-       else
-               sme_me_mask = active_by_default ? me_mask : 0;
-out:
-       if (sme_me_mask) {
-               physical_mask &= ~sme_me_mask;
-               cc_vendor = CC_VENDOR_AMD;
-               cc_set_mask(sme_me_mask);
-       }
+       RIP_REL_REF(sme_me_mask) = me_mask;
+       physical_mask &= ~me_mask;
+       cc_vendor = CC_VENDOR_AMD;
+       cc_set_mask(me_mask);
 }
index adc497b93f03746aca087a71233b806a5790bf96..65e9a6e391c046d1c18c32ffa0049082461a82dd 100644 (file)
@@ -934,7 +934,7 @@ static int __init cmp_memblk(const void *a, const void *b)
        const struct numa_memblk *ma = *(const struct numa_memblk **)a;
        const struct numa_memblk *mb = *(const struct numa_memblk **)b;
 
-       return ma->start - mb->start;
+       return (ma->start > mb->start) - (ma->start < mb->start);
 }
 
 static struct numa_memblk *numa_memblk_list[NR_NODE_MEMBLKS] __initdata;
@@ -944,14 +944,12 @@ static struct numa_memblk *numa_memblk_list[NR_NODE_MEMBLKS] __initdata;
  * @start: address to begin fill
  * @end: address to end fill
  *
- * Find and extend numa_meminfo memblks to cover the @start-@end
- * physical address range, such that the first memblk includes
- * @start, the last memblk includes @end, and any gaps in between
- * are filled.
+ * Find and extend numa_meminfo memblks to cover the physical
+ * address range @start-@end
  *
  * RETURNS:
  * 0             : Success
- * NUMA_NO_MEMBLK : No memblk exists in @start-@end range
+ * NUMA_NO_MEMBLK : No memblks exist in address range @start-@end
  */
 
 int __init numa_fill_memblks(u64 start, u64 end)
@@ -963,17 +961,14 @@ int __init numa_fill_memblks(u64 start, u64 end)
 
        /*
         * Create a list of pointers to numa_meminfo memblks that
-        * overlap start, end. Exclude (start == bi->end) since
-        * end addresses in both a CFMWS range and a memblk range
-        * are exclusive.
-        *
-        * This list of pointers is used to make in-place changes
-        * that fill out the numa_meminfo memblks.
+        * overlap start, end. The list is used to make in-place
+        * changes that fill out the numa_meminfo memblks.
         */
        for (int i = 0; i < mi->nr_blks; i++) {
                struct numa_memblk *bi = &mi->blk[i];
 
-               if (start < bi->end && end >= bi->start) {
+               if (memblock_addrs_overlap(start, end - start, bi->start,
+                                          bi->end - bi->start)) {
                        blk[count] = &mi->blk[i];
                        count++;
                }
index 0904d7e8e12608d231851a3bbcab788ddbdd2723..0d72183b5dd028ad83b98b38183af643ad3b21b5 100644 (file)
@@ -240,6 +240,8 @@ void pat_cpu_init(void)
        }
 
        wrmsrl(MSR_IA32_CR_PAT, pat_msr_val);
+
+       __flush_tlb_all();
 }
 
 /**
@@ -296,13 +298,8 @@ void __init pat_bp_init(void)
        /*
         * Xen PV doesn't allow to set PAT MSR, but all cache modes are
         * supported.
-        * When running as TDX guest setting the PAT MSR won't work either
-        * due to the requirement to set CR0.CD when doing so. Rely on
-        * firmware to have set the PAT MSR correctly.
         */
-       if (pat_disabled ||
-           cpu_feature_enabled(X86_FEATURE_XENPV) ||
-           cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) {
+       if (pat_disabled || cpu_feature_enabled(X86_FEATURE_XENPV)) {
                init_cache_modes(pat_msr_val);
                return;
        }
index e9b448d1b1b70f08dae6216250f02e783091a83a..e5b2985a7c5166faaf8c527c4dfbf0fdff6f80d2 100644 (file)
@@ -755,10 +755,14 @@ pmd_t *lookup_pmd_address(unsigned long address)
  * areas on 32-bit NUMA systems.  The percpu areas can
  * end up in this kind of memory, for instance.
  *
- * This could be optimized, but it is only intended to be
- * used at initialization time, and keeping it
- * unoptimized should increase the testing coverage for
- * the more obscure platforms.
+ * Note that as long as the PTEs are well-formed with correct PFNs, this
+ * works without checking the PRESENT bit in the leaf PTE.  This is unlike
+ * the similar vmalloc_to_page() and derivatives.  Callers may depend on
+ * this behavior.
+ *
+ * This could be optimized, but it is only used in paths that are not perf
+ * sensitive, and keeping it unoptimized should increase the testing coverage
+ * for the more obscure platforms.
  */
 phys_addr_t slow_virt_to_phys(void *__virt_addr)
 {
@@ -2041,17 +2045,12 @@ int set_mce_nospec(unsigned long pfn)
        return rc;
 }
 
-static int set_memory_p(unsigned long *addr, int numpages)
-{
-       return change_page_attr_set(addr, numpages, __pgprot(_PAGE_PRESENT), 0);
-}
-
 /* Restore full speculative operation to the pfn. */
 int clear_mce_nospec(unsigned long pfn)
 {
        unsigned long addr = (unsigned long) pfn_to_kaddr(pfn);
 
-       return set_memory_p(&addr, 1);
+       return set_memory_p(addr, 1);
 }
 EXPORT_SYMBOL_GPL(clear_mce_nospec);
 #endif /* CONFIG_X86_64 */
@@ -2104,6 +2103,11 @@ int set_memory_np_noalias(unsigned long addr, int numpages)
                                        CPA_NO_CHECK_ALIAS, NULL);
 }
 
+int set_memory_p(unsigned long addr, int numpages)
+{
+       return change_page_attr_set(&addr, numpages, __pgprot(_PAGE_PRESENT), 0);
+}
+
 int set_memory_4k(unsigned long addr, int numpages)
 {
        return change_page_attr_set_clr(&addr, numpages, __pgprot(0),
@@ -2153,7 +2157,7 @@ static int __set_memory_enc_pgtable(unsigned long addr, int numpages, bool enc)
 
        /* Notify hypervisor that we are about to set/clr encryption attribute. */
        if (!x86_platform.guest.enc_status_change_prepare(addr, numpages, enc))
-               return -EIO;
+               goto vmm_fail;
 
        ret = __change_page_attr_set_clr(&cpa, 1);
 
@@ -2166,13 +2170,20 @@ static int __set_memory_enc_pgtable(unsigned long addr, int numpages, bool enc)
         */
        cpa_flush(&cpa, 0);
 
+       if (ret)
+               return ret;
+
        /* Notify hypervisor that we have successfully set/clr encryption attribute. */
-       if (!ret) {
-               if (!x86_platform.guest.enc_status_change_finish(addr, numpages, enc))
-                       ret = -EIO;
-       }
+       if (!x86_platform.guest.enc_status_change_finish(addr, numpages, enc))
+               goto vmm_fail;
 
-       return ret;
+       return 0;
+
+vmm_fail:
+       WARN_ONCE(1, "CPA VMM failure to convert memory (addr=%p, numpages=%d) to %s.\n",
+                 (void *)addr, numpages, enc ? "private" : "shared");
+
+       return -EIO;
 }
 
 static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
index 0cbc1b8e8e3d10185e4e63ff3fab4e0057417f99..cceb779d882d882b4b0d7b80a2f3c6bc33a8e40b 100644 (file)
@@ -293,7 +293,7 @@ static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
        for (i = 0; i < PREALLOCATED_PMDS; i++)
                mop_up_one_pmd(mm, &pgdp[i]);
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 
        if (!boot_cpu_has(X86_FEATURE_PTI))
                return;
@@ -325,7 +325,7 @@ static void pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmds[])
        }
 }
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 static void pgd_prepopulate_user_pmd(struct mm_struct *mm,
                                     pgd_t *k_pgd, pmd_t *pmds[])
 {
index 5768d386efab6ece2029b9d6f797c54dc7491220..4af930947380c5378190ccd631290cdcf475a1a1 100644 (file)
 #define CR3_HW_ASID_BITS               12
 
 /*
- * When enabled, PAGE_TABLE_ISOLATION consumes a single bit for
+ * When enabled, MITIGATION_PAGE_TABLE_ISOLATION consumes a single bit for
  * user/kernel switches
  */
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 # define PTI_CONSUMED_PCID_BITS        1
 #else
 # define PTI_CONSUMED_PCID_BITS        0
@@ -114,7 +114,7 @@ static inline u16 kern_pcid(u16 asid)
 {
        VM_WARN_ON_ONCE(asid > MAX_ASID_AVAILABLE);
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
        /*
         * Make sure that the dynamic ASID space does not conflict with the
         * bit we are using to switch between user and kernel ASIDs.
@@ -149,7 +149,7 @@ static inline u16 kern_pcid(u16 asid)
 static inline u16 user_pcid(u16 asid)
 {
        u16 ret = kern_pcid(asid);
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
        ret |= 1 << X86_CR3_PTI_PCID_USER_BIT;
 #endif
        return ret;
@@ -262,7 +262,7 @@ static void choose_new_asid(struct mm_struct *next, u64 next_tlb_gen,
 static inline void invalidate_user_asid(u16 asid)
 {
        /* There is no user ASID if address space separation is off */
-       if (!IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION))
+       if (!IS_ENABLED(CONFIG_MITIGATION_PAGE_TABLE_ISOLATION))
                return;
 
        /*
index 919f647c740fb54f0fca4f4a16c5f614f9cf8521..f3b4716317c1aebc8efb03fb404c4aa92dc2e9cc 100644 (file)
@@ -553,7 +553,7 @@ static void emit_indirect_jump(u8 **pprog, int reg, u8 *ip)
                        emit_jump(&prog, &__x86_indirect_thunk_array[reg], ip);
        } else {
                EMIT2(0xFF, 0xE0 + reg);        /* jmp *%\reg */
-               if (IS_ENABLED(CONFIG_RETPOLINE) || IS_ENABLED(CONFIG_SLS))
+               if (IS_ENABLED(CONFIG_MITIGATION_RETPOLINE) || IS_ENABLED(CONFIG_MITIGATION_SLS))
                        EMIT1(0xCC);            /* int3 */
        }
 
@@ -568,7 +568,7 @@ static void emit_return(u8 **pprog, u8 *ip)
                emit_jump(&prog, x86_return_thunk, ip);
        } else {
                EMIT1(0xC3);            /* ret */
-               if (IS_ENABLED(CONFIG_SLS))
+               if (IS_ENABLED(CONFIG_MITIGATION_SLS))
                        EMIT1(0xCC);    /* int3 */
        }
 
index b18ce19981ece42e0e8ee1aee9ad6c7a8f1181ab..c10083a8e68e62df31960d724b3bc4c0baca6d06 100644 (file)
@@ -1273,7 +1273,7 @@ static int emit_jmp_edx(u8 **pprog, u8 *ip)
        u8 *prog = *pprog;
        int cnt = 0;
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
        EMIT1_off32(0xE9, (u8 *)__x86_indirect_thunk_edx - (ip + 5));
 #else
        EMIT2(0xFF, 0xE2);
index 40745664d92f3e77b2053d3565064834e55ec960..f32451bdcfdd5b2f28cd2cbb00eca4984b698f69 100644 (file)
@@ -135,13 +135,13 @@ static void sdv_pci_init(void)
  */
 void __init x86_ce4100_early_setup(void)
 {
-       x86_init.oem.arch_setup = sdv_arch_setup;
-       x86_init.resources.probe_roms = x86_init_noop;
-       x86_init.mpparse.get_smp_config = x86_init_uint_noop;
-       x86_init.mpparse.find_smp_config = x86_init_noop;
-       x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc_nocheck;
-       x86_init.pci.init = ce4100_pci_init;
-       x86_init.pci.init_irq = sdv_pci_init;
+       x86_init.oem.arch_setup                 = sdv_arch_setup;
+       x86_init.resources.probe_roms           = x86_init_noop;
+       x86_init.mpparse.find_mptable           = x86_init_noop;
+       x86_init.mpparse.early_parse_smp_cfg    = x86_init_noop;
+       x86_init.mpparse.parse_smp_cfg          = x86_dtb_parse_smp_config;
+       x86_init.pci.init                       = ce4100_pci_init;
+       x86_init.pci.init_irq                   = sdv_pci_init;
 
        /*
         * By default, the reboot method is ACPI which is supported by the
index e9f99c56f3ce625d0b568124091ff3281dd03b87..f090ec972d7b60c18e975a00a1aba8340290f0d4 100644 (file)
@@ -950,3 +950,8 @@ umode_t efi_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
        }
        return attr->mode;
 }
+
+enum efi_secureboot_mode __x86_ima_efi_boot_mode(void)
+{
+       return boot_params.secure_boot;
+}
index f4592dc7a1c193b4cbfad2a83ca237a6061b2f67..7be71c2cdc83ee5f73414a3f22c45c62d59e2970 100644 (file)
@@ -118,7 +118,8 @@ void __init x86_intel_mid_early_setup(void)
        machine_ops.emergency_restart  = intel_mid_reboot;
 
        /* Avoid searching for BIOS MP tables */
-       x86_init.mpparse.find_smp_config = x86_init_noop;
-       x86_init.mpparse.get_smp_config = x86_init_uint_noop;
+       x86_init.mpparse.find_mptable           = x86_init_noop;
+       x86_init.mpparse.early_parse_smp_cfg    = x86_init_noop;
+       x86_init.mpparse.parse_smp_cfg          = x86_init_noop;
        set_bit(MP_BUS_ISA, mp_bus_not_pci);
 }
index 00a92cb2c81474782146b801f56a5d5880c8afb7..944e0290f2c001810a16a2eee3c2e87a31ba48e0 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <xen/hvc-console.h>
 
+#include <asm/bootparam.h>
 #include <asm/io_apic.h>
 #include <asm/hypervisor.h>
 #include <asm/e820/api.h>
index 08aa0f25f12a0fb92b7f9002740c50a1c0f2ad9d..bc31863c5ee6389419cc24250f56d4b89e8ec0e4 100644 (file)
@@ -61,7 +61,7 @@ ifdef CONFIG_STACKPROTECTOR_STRONG
 PURGATORY_CFLAGS_REMOVE                += -fstack-protector-strong
 endif
 
-ifdef CONFIG_RETPOLINE
+ifdef CONFIG_MITIGATION_RETPOLINE
 PURGATORY_CFLAGS_REMOVE                += $(RETPOLINE_CFLAGS)
 endif
 
index c9f76fae902e4b2f4cd4268bda51a82e018c1d65..14d9c7daf90f4825e1b897aa80d442d1d7b3fa72 100644 (file)
        .text
        .code16
 
-.macro LOCK_AND_LOAD_REALMODE_ESP lock_pa=0
+.macro LOCK_AND_LOAD_REALMODE_ESP lock_pa=0 lock_rip=0
        /*
         * Make sure only one CPU fiddles with the realmode stack
         */
 .Llock_rm\@:
        .if \lock_pa
         lock btsl       $0, pa_tr_lock
+       .elseif \lock_rip
+        lock btsl       $0, tr_lock(%rip)
        .else
         lock btsl       $0, tr_lock
        .endif
@@ -220,6 +222,35 @@ SYM_CODE_START(trampoline_start64)
        lidt    tr_idt(%rip)
        lgdt    tr_gdt64(%rip)
 
+       /* Check if paging mode has to be changed */
+       movq    %cr4, %rax
+       xorl    tr_cr4(%rip), %eax
+       testl   $X86_CR4_LA57, %eax
+       jnz     .L_switch_paging
+
+       /* Paging mode is correct proceed in 64-bit mode */
+
+       LOCK_AND_LOAD_REALMODE_ESP lock_rip=1
+
+       movw    $__KERNEL_DS, %dx
+       movl    %edx, %ss
+       addl    $pa_real_mode_base, %esp
+       movl    %edx, %ds
+       movl    %edx, %es
+       movl    %edx, %fs
+       movl    %edx, %gs
+
+       movl    $pa_trampoline_pgd, %eax
+       movq    %rax, %cr3
+
+       pushq   $__KERNEL_CS
+       pushq   tr_start(%rip)
+       lretq
+.L_switch_paging:
+       /*
+        * To switch between 4- and 5-level paging modes, it is necessary
+        * to disable paging. This must be done in the compatibility mode.
+        */
        ljmpl   *tr_compat(%rip)
 SYM_CODE_END(trampoline_start64)
 
diff --git a/arch/x86/virt/svm/Makefile b/arch/x86/virt/svm/Makefile
new file mode 100644 (file)
index 0000000..ef2a31b
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_KVM_AMD_SEV) += sev.o
diff --git a/arch/x86/virt/svm/sev.c b/arch/x86/virt/svm/sev.c
new file mode 100644 (file)
index 0000000..cffe115
--- /dev/null
@@ -0,0 +1,560 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AMD SVM-SEV Host Support.
+ *
+ * Copyright (C) 2023 Advanced Micro Devices, Inc.
+ *
+ * Author: Ashish Kalra <ashish.kalra@amd.com>
+ *
+ */
+
+#include <linux/cc_platform.h>
+#include <linux/printk.h>
+#include <linux/mm_types.h>
+#include <linux/set_memory.h>
+#include <linux/memblock.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/cpumask.h>
+#include <linux/iommu.h>
+#include <linux/amd-iommu.h>
+
+#include <asm/sev.h>
+#include <asm/processor.h>
+#include <asm/setup.h>
+#include <asm/svm.h>
+#include <asm/smp.h>
+#include <asm/cpu.h>
+#include <asm/apic.h>
+#include <asm/cpuid.h>
+#include <asm/cmdline.h>
+#include <asm/iommu.h>
+
+/*
+ * The RMP entry format is not architectural. The format is defined in PPR
+ * Family 19h Model 01h, Rev B1 processor.
+ */
+struct rmpentry {
+       union {
+               struct {
+                       u64 assigned    : 1,
+                           pagesize    : 1,
+                           immutable   : 1,
+                           rsvd1       : 9,
+                           gpa         : 39,
+                           asid        : 10,
+                           vmsa        : 1,
+                           validated   : 1,
+                           rsvd2       : 1;
+               };
+               u64 lo;
+       };
+       u64 hi;
+} __packed;
+
+/*
+ * The first 16KB from the RMP_BASE is used by the processor for the
+ * bookkeeping, the range needs to be added during the RMP entry lookup.
+ */
+#define RMPTABLE_CPU_BOOKKEEPING_SZ    0x4000
+
+/* Mask to apply to a PFN to get the first PFN of a 2MB page */
+#define PFN_PMD_MASK   GENMASK_ULL(63, PMD_SHIFT - PAGE_SHIFT)
+
+static u64 probed_rmp_base, probed_rmp_size;
+static struct rmpentry *rmptable __ro_after_init;
+static u64 rmptable_max_pfn __ro_after_init;
+
+static LIST_HEAD(snp_leaked_pages_list);
+static DEFINE_SPINLOCK(snp_leaked_pages_list_lock);
+
+static unsigned long snp_nr_leaked_pages;
+
+#undef pr_fmt
+#define pr_fmt(fmt)    "SEV-SNP: " fmt
+
+static int __mfd_enable(unsigned int cpu)
+{
+       u64 val;
+
+       if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP))
+               return 0;
+
+       rdmsrl(MSR_AMD64_SYSCFG, val);
+
+       val |= MSR_AMD64_SYSCFG_MFDM;
+
+       wrmsrl(MSR_AMD64_SYSCFG, val);
+
+       return 0;
+}
+
+static __init void mfd_enable(void *arg)
+{
+       __mfd_enable(smp_processor_id());
+}
+
+static int __snp_enable(unsigned int cpu)
+{
+       u64 val;
+
+       if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP))
+               return 0;
+
+       rdmsrl(MSR_AMD64_SYSCFG, val);
+
+       val |= MSR_AMD64_SYSCFG_SNP_EN;
+       val |= MSR_AMD64_SYSCFG_SNP_VMPL_EN;
+
+       wrmsrl(MSR_AMD64_SYSCFG, val);
+
+       return 0;
+}
+
+static __init void snp_enable(void *arg)
+{
+       __snp_enable(smp_processor_id());
+}
+
+#define RMP_ADDR_MASK GENMASK_ULL(51, 13)
+
+bool snp_probe_rmptable_info(void)
+{
+       u64 max_rmp_pfn, calc_rmp_sz, rmp_sz, rmp_base, rmp_end;
+
+       rdmsrl(MSR_AMD64_RMP_BASE, rmp_base);
+       rdmsrl(MSR_AMD64_RMP_END, rmp_end);
+
+       if (!(rmp_base & RMP_ADDR_MASK) || !(rmp_end & RMP_ADDR_MASK)) {
+               pr_err("Memory for the RMP table has not been reserved by BIOS\n");
+               return false;
+       }
+
+       if (rmp_base > rmp_end) {
+               pr_err("RMP configuration not valid: base=%#llx, end=%#llx\n", rmp_base, rmp_end);
+               return false;
+       }
+
+       rmp_sz = rmp_end - rmp_base + 1;
+
+       /*
+        * Calculate the amount the memory that must be reserved by the BIOS to
+        * address the whole RAM, including the bookkeeping area. The RMP itself
+        * must also be covered.
+        */
+       max_rmp_pfn = max_pfn;
+       if (PHYS_PFN(rmp_end) > max_pfn)
+               max_rmp_pfn = PHYS_PFN(rmp_end);
+
+       calc_rmp_sz = (max_rmp_pfn << 4) + RMPTABLE_CPU_BOOKKEEPING_SZ;
+
+       if (calc_rmp_sz > rmp_sz) {
+               pr_err("Memory reserved for the RMP table does not cover full system RAM (expected 0x%llx got 0x%llx)\n",
+                      calc_rmp_sz, rmp_sz);
+               return false;
+       }
+
+       probed_rmp_base = rmp_base;
+       probed_rmp_size = rmp_sz;
+
+       pr_info("RMP table physical range [0x%016llx - 0x%016llx]\n",
+               probed_rmp_base, probed_rmp_base + probed_rmp_size - 1);
+
+       return true;
+}
+
+/*
+ * Do the necessary preparations which are verified by the firmware as
+ * described in the SNP_INIT_EX firmware command description in the SNP
+ * firmware ABI spec.
+ */
+static int __init snp_rmptable_init(void)
+{
+       void *rmptable_start;
+       u64 rmptable_size;
+       u64 val;
+
+       if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP))
+               return 0;
+
+       if (!amd_iommu_snp_en)
+               return 0;
+
+       if (!probed_rmp_size)
+               goto nosnp;
+
+       rmptable_start = memremap(probed_rmp_base, probed_rmp_size, MEMREMAP_WB);
+       if (!rmptable_start) {
+               pr_err("Failed to map RMP table\n");
+               return 1;
+       }
+
+       /*
+        * Check if SEV-SNP is already enabled, this can happen in case of
+        * kexec boot.
+        */
+       rdmsrl(MSR_AMD64_SYSCFG, val);
+       if (val & MSR_AMD64_SYSCFG_SNP_EN)
+               goto skip_enable;
+
+       memset(rmptable_start, 0, probed_rmp_size);
+
+       /* Flush the caches to ensure that data is written before SNP is enabled. */
+       wbinvd_on_all_cpus();
+
+       /* MtrrFixDramModEn must be enabled on all the CPUs prior to enabling SNP. */
+       on_each_cpu(mfd_enable, NULL, 1);
+
+       on_each_cpu(snp_enable, NULL, 1);
+
+skip_enable:
+       rmptable_start += RMPTABLE_CPU_BOOKKEEPING_SZ;
+       rmptable_size = probed_rmp_size - RMPTABLE_CPU_BOOKKEEPING_SZ;
+
+       rmptable = (struct rmpentry *)rmptable_start;
+       rmptable_max_pfn = rmptable_size / sizeof(struct rmpentry) - 1;
+
+       cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/rmptable_init:online", __snp_enable, NULL);
+
+       /*
+        * Setting crash_kexec_post_notifiers to 'true' to ensure that SNP panic
+        * notifier is invoked to do SNP IOMMU shutdown before kdump.
+        */
+       crash_kexec_post_notifiers = true;
+
+       return 0;
+
+nosnp:
+       setup_clear_cpu_cap(X86_FEATURE_SEV_SNP);
+       return -ENOSYS;
+}
+
+/*
+ * This must be called after the IOMMU has been initialized.
+ */
+device_initcall(snp_rmptable_init);
+
+static struct rmpentry *get_rmpentry(u64 pfn)
+{
+       if (WARN_ON_ONCE(pfn > rmptable_max_pfn))
+               return ERR_PTR(-EFAULT);
+
+       return &rmptable[pfn];
+}
+
+static struct rmpentry *__snp_lookup_rmpentry(u64 pfn, int *level)
+{
+       struct rmpentry *large_entry, *entry;
+
+       if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP))
+               return ERR_PTR(-ENODEV);
+
+       entry = get_rmpentry(pfn);
+       if (IS_ERR(entry))
+               return entry;
+
+       /*
+        * Find the authoritative RMP entry for a PFN. This can be either a 4K
+        * RMP entry or a special large RMP entry that is authoritative for a
+        * whole 2M area.
+        */
+       large_entry = get_rmpentry(pfn & PFN_PMD_MASK);
+       if (IS_ERR(large_entry))
+               return large_entry;
+
+       *level = RMP_TO_PG_LEVEL(large_entry->pagesize);
+
+       return entry;
+}
+
+int snp_lookup_rmpentry(u64 pfn, bool *assigned, int *level)
+{
+       struct rmpentry *e;
+
+       e = __snp_lookup_rmpentry(pfn, level);
+       if (IS_ERR(e))
+               return PTR_ERR(e);
+
+       *assigned = !!e->assigned;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snp_lookup_rmpentry);
+
+/*
+ * Dump the raw RMP entry for a particular PFN. These bits are documented in the
+ * PPR for a particular CPU model and provide useful information about how a
+ * particular PFN is being utilized by the kernel/firmware at the time certain
+ * unexpected events occur, such as RMP faults.
+ */
+static void dump_rmpentry(u64 pfn)
+{
+       u64 pfn_i, pfn_end;
+       struct rmpentry *e;
+       int level;
+
+       e = __snp_lookup_rmpentry(pfn, &level);
+       if (IS_ERR(e)) {
+               pr_err("Failed to read RMP entry for PFN 0x%llx, error %ld\n",
+                      pfn, PTR_ERR(e));
+               return;
+       }
+
+       if (e->assigned) {
+               pr_info("PFN 0x%llx, RMP entry: [0x%016llx - 0x%016llx]\n",
+                       pfn, e->lo, e->hi);
+               return;
+       }
+
+       /*
+        * If the RMP entry for a particular PFN is not in an assigned state,
+        * then it is sometimes useful to get an idea of whether or not any RMP
+        * entries for other PFNs within the same 2MB region are assigned, since
+        * those too can affect the ability to access a particular PFN in
+        * certain situations, such as when the PFN is being accessed via a 2MB
+        * mapping in the host page table.
+        */
+       pfn_i = ALIGN_DOWN(pfn, PTRS_PER_PMD);
+       pfn_end = pfn_i + PTRS_PER_PMD;
+
+       pr_info("PFN 0x%llx unassigned, dumping non-zero entries in 2M PFN region: [0x%llx - 0x%llx]\n",
+               pfn, pfn_i, pfn_end);
+
+       while (pfn_i < pfn_end) {
+               e = __snp_lookup_rmpentry(pfn_i, &level);
+               if (IS_ERR(e)) {
+                       pr_err("Error %ld reading RMP entry for PFN 0x%llx\n",
+                              PTR_ERR(e), pfn_i);
+                       pfn_i++;
+                       continue;
+               }
+
+               if (e->lo || e->hi)
+                       pr_info("PFN: 0x%llx, [0x%016llx - 0x%016llx]\n", pfn_i, e->lo, e->hi);
+               pfn_i++;
+       }
+}
+
+void snp_dump_hva_rmpentry(unsigned long hva)
+{
+       unsigned long paddr;
+       unsigned int level;
+       pgd_t *pgd;
+       pte_t *pte;
+
+       pgd = __va(read_cr3_pa());
+       pgd += pgd_index(hva);
+       pte = lookup_address_in_pgd(pgd, hva, &level);
+
+       if (!pte) {
+               pr_err("Can't dump RMP entry for HVA %lx: no PTE/PFN found\n", hva);
+               return;
+       }
+
+       paddr = PFN_PHYS(pte_pfn(*pte)) | (hva & ~page_level_mask(level));
+       dump_rmpentry(PHYS_PFN(paddr));
+}
+
+/*
+ * PSMASH a 2MB aligned page into 4K pages in the RMP table while preserving the
+ * Validated bit.
+ */
+int psmash(u64 pfn)
+{
+       unsigned long paddr = pfn << PAGE_SHIFT;
+       int ret;
+
+       if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP))
+               return -ENODEV;
+
+       if (!pfn_valid(pfn))
+               return -EINVAL;
+
+       /* Binutils version 2.36 supports the PSMASH mnemonic. */
+       asm volatile(".byte 0xF3, 0x0F, 0x01, 0xFF"
+                     : "=a" (ret)
+                     : "a" (paddr)
+                     : "memory", "cc");
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(psmash);
+
+/*
+ * If the kernel uses a 2MB or larger directmap mapping to write to an address,
+ * and that mapping contains any 4KB pages that are set to private in the RMP
+ * table, an RMP #PF will trigger and cause a host crash. Hypervisor code that
+ * owns the PFNs being transitioned will never attempt such a write, but other
+ * kernel tasks writing to other PFNs in the range may trigger these checks
+ * inadvertently due a large directmap mapping that happens to overlap such a
+ * PFN.
+ *
+ * Prevent this by splitting any 2MB+ mappings that might end up containing a
+ * mix of private/shared PFNs as a result of a subsequent RMPUPDATE for the
+ * PFN/rmp_level passed in.
+ *
+ * Note that there is no attempt here to scan all the RMP entries for the 2MB
+ * physical range, since it would only be worthwhile in determining if a
+ * subsequent RMPUPDATE for a 4KB PFN would result in all the entries being of
+ * the same shared/private state, thus avoiding the need to split the mapping.
+ * But that would mean the entries are currently in a mixed state, and so the
+ * mapping would have already been split as a result of prior transitions.
+ * And since the 4K split is only done if the mapping is 2MB+, and there isn't
+ * currently a mechanism in place to restore 2MB+ mappings, such a check would
+ * not provide any usable benefit.
+ *
+ * More specifics on how these checks are carried out can be found in APM
+ * Volume 2, "RMP and VMPL Access Checks".
+ */
+static int adjust_direct_map(u64 pfn, int rmp_level)
+{
+       unsigned long vaddr;
+       unsigned int level;
+       int npages, ret;
+       pte_t *pte;
+
+       /*
+        * pfn_to_kaddr() will return a vaddr only within the direct
+        * map range.
+        */
+       vaddr = (unsigned long)pfn_to_kaddr(pfn);
+
+       /* Only 4KB/2MB RMP entries are supported by current hardware. */
+       if (WARN_ON_ONCE(rmp_level > PG_LEVEL_2M))
+               return -EINVAL;
+
+       if (!pfn_valid(pfn))
+               return -EINVAL;
+
+       if (rmp_level == PG_LEVEL_2M &&
+           (!IS_ALIGNED(pfn, PTRS_PER_PMD) || !pfn_valid(pfn + PTRS_PER_PMD - 1)))
+               return -EINVAL;
+
+       /*
+        * If an entire 2MB physical range is being transitioned, then there is
+        * no risk of RMP #PFs due to write accesses from overlapping mappings,
+        * since even accesses from 1GB mappings will be treated as 2MB accesses
+        * as far as RMP table checks are concerned.
+        */
+       if (rmp_level == PG_LEVEL_2M)
+               return 0;
+
+       pte = lookup_address(vaddr, &level);
+       if (!pte || pte_none(*pte))
+               return 0;
+
+       if (level == PG_LEVEL_4K)
+               return 0;
+
+       npages = page_level_size(rmp_level) / PAGE_SIZE;
+       ret = set_memory_4k(vaddr, npages);
+       if (ret)
+               pr_warn("Failed to split direct map for PFN 0x%llx, ret: %d\n",
+                       pfn, ret);
+
+       return ret;
+}
+
+/*
+ * It is expected that those operations are seldom enough so that no mutual
+ * exclusion of updaters is needed and thus the overlap error condition below
+ * should happen very rarely and would get resolved relatively quickly by
+ * the firmware.
+ *
+ * If not, one could consider introducing a mutex or so here to sync concurrent
+ * RMP updates and thus diminish the amount of cases where firmware needs to
+ * lock 2M ranges to protect against concurrent updates.
+ *
+ * The optimal solution would be range locking to avoid locking disjoint
+ * regions unnecessarily but there's no support for that yet.
+ */
+static int rmpupdate(u64 pfn, struct rmp_state *state)
+{
+       unsigned long paddr = pfn << PAGE_SHIFT;
+       int ret, level;
+
+       if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP))
+               return -ENODEV;
+
+       level = RMP_TO_PG_LEVEL(state->pagesize);
+
+       if (adjust_direct_map(pfn, level))
+               return -EFAULT;
+
+       do {
+               /* Binutils version 2.36 supports the RMPUPDATE mnemonic. */
+               asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFE"
+                            : "=a" (ret)
+                            : "a" (paddr), "c" ((unsigned long)state)
+                            : "memory", "cc");
+       } while (ret == RMPUPDATE_FAIL_OVERLAP);
+
+       if (ret) {
+               pr_err("RMPUPDATE failed for PFN %llx, pg_level: %d, ret: %d\n",
+                      pfn, level, ret);
+               dump_rmpentry(pfn);
+               dump_stack();
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+/* Transition a page to guest-owned/private state in the RMP table. */
+int rmp_make_private(u64 pfn, u64 gpa, enum pg_level level, u32 asid, bool immutable)
+{
+       struct rmp_state state;
+
+       memset(&state, 0, sizeof(state));
+       state.assigned = 1;
+       state.asid = asid;
+       state.immutable = immutable;
+       state.gpa = gpa;
+       state.pagesize = PG_LEVEL_TO_RMP(level);
+
+       return rmpupdate(pfn, &state);
+}
+EXPORT_SYMBOL_GPL(rmp_make_private);
+
+/* Transition a page to hypervisor-owned/shared state in the RMP table. */
+int rmp_make_shared(u64 pfn, enum pg_level level)
+{
+       struct rmp_state state;
+
+       memset(&state, 0, sizeof(state));
+       state.pagesize = PG_LEVEL_TO_RMP(level);
+
+       return rmpupdate(pfn, &state);
+}
+EXPORT_SYMBOL_GPL(rmp_make_shared);
+
+void snp_leak_pages(u64 pfn, unsigned int npages)
+{
+       struct page *page = pfn_to_page(pfn);
+
+       pr_warn("Leaking PFN range 0x%llx-0x%llx\n", pfn, pfn + npages);
+
+       spin_lock(&snp_leaked_pages_list_lock);
+       while (npages--) {
+
+               /*
+                * Reuse the page's buddy list for chaining into the leaked
+                * pages list. This page should not be on a free list currently
+                * and is also unsafe to be added to a free list.
+                */
+               if (likely(!PageCompound(page)) ||
+
+                       /*
+                        * Skip inserting tail pages of compound page as
+                        * page->buddy_list of tail pages is not usable.
+                        */
+                   (PageHead(page) && compound_nr(page) <= npages))
+                       list_add_tail(&page->buddy_list, &snp_leaked_pages_list);
+
+               dump_rmpentry(pfn);
+               snp_nr_leaked_pages++;
+               pfn++;
+               page++;
+       }
+       spin_unlock(&snp_leaked_pages_list_lock);
+}
+EXPORT_SYMBOL_GPL(snp_leak_pages);
index 9dd5490b3318923b0810b89076697ab9b8b91d52..8b045dd25196b40bb7f73b48f2cce499fa70fa8c 100644 (file)
@@ -33,12 +33,6 @@ static unsigned int xen_io_apic_read(unsigned apic, unsigned reg)
        return 0xfd;
 }
 
-static u32 xen_set_apic_id(u32 x)
-{
-       WARN_ON(1);
-       return x;
-}
-
 static u32 xen_get_apic_id(u32 x)
 {
        return ((x)>>24) & 0xFFu;
@@ -49,20 +43,20 @@ static u32 xen_apic_read(u32 reg)
        struct xen_platform_op op = {
                .cmd = XENPF_get_cpuinfo,
                .interface_version = XENPF_INTERFACE_VERSION,
-               .u.pcpu_info.xen_cpuid = 0,
        };
-       int ret;
-
-       /* Shouldn't need this as APIC is turned off for PV, and we only
-        * get called on the bootup processor. But just in case. */
-       if (!xen_initial_domain() || smp_processor_id())
-               return 0;
+       int ret, cpu;
 
        if (reg == APIC_LVR)
                return 0x14;
        if (reg != APIC_ID)
                return 0;
 
+       cpu = smp_processor_id();
+       if (!xen_initial_domain())
+               return cpu ? cpuid_to_apicid[cpu] << 24 : 0;
+
+       op.u.pcpu_info.xen_cpuid = cpu;
+
        ret = HYPERVISOR_platform_op(&op);
        if (ret)
                op.u.pcpu_info.apic_id = BAD_APICID;
@@ -110,11 +104,6 @@ static int xen_madt_oem_check(char *oem_id, char *oem_table_id)
        return xen_pv_domain();
 }
 
-static u32 xen_phys_pkg_id(u32 initial_apic_id, int index_msb)
-{
-       return initial_apic_id >> index_msb;
-}
-
 static u32 xen_cpu_present_to_apicid(int cpu)
 {
        if (cpu_present(cpu))
@@ -133,11 +122,9 @@ static struct apic xen_pv_apic __ro_after_init = {
        .disable_esr                    = 0,
 
        .cpu_present_to_apicid          = xen_cpu_present_to_apicid,
-       .phys_pkg_id                    = xen_phys_pkg_id, /* detect_ht */
 
        .max_apic_id                    = UINT_MAX,
        .get_apic_id                    = xen_get_apic_id,
-       .set_apic_id                    = xen_set_apic_id,
 
        .calc_dest_apicid               = apic_flat_calc_apicid,
 
index 3f8c34707c50014d9364f0430728446e35059d8f..99a68fa71dbe403af34705d5425d886f1d6e49be 100644 (file)
@@ -168,7 +168,7 @@ static int xen_cpu_up_prepare_hvm(unsigned int cpu)
         */
        xen_uninit_lock_cpu(cpu);
 
-       if (cpu_acpi_id(cpu) != U32_MAX)
+       if (cpu_acpi_id(cpu) != CPU_ACPIID_INVALID)
                per_cpu(xen_vcpu_id, cpu) = cpu_acpi_id(cpu);
        else
                per_cpu(xen_vcpu_id, cpu) = cpu;
index aeb33e0a3f763370b00daf427063b2010f0bcf40..ace2eb054053f95e53ac43992d9b778335e68748 100644 (file)
@@ -200,6 +200,9 @@ static void __init xen_pv_init_platform(void)
                xen_set_mtrr_data();
        else
                mtrr_overwrite_state(NULL, 0, MTRR_TYPE_WRBACK);
+
+       /* Adjust nr_cpu_ids before "enumeration" happens */
+       xen_smp_count_cpus();
 }
 
 static void __init xen_pv_guest_late_init(void)
index ada3868c02c231d0f10863cabf71a076f003acb5..9e9db601bd52a9bf48a2e5ec4c936c0b7db93b39 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <xen/hvc-console.h>
 
+#include <asm/bootparam.h>
 #include <asm/io_apic.h>
 #include <asm/hypervisor.h>
 #include <asm/e820/api.h>
index 4b0d6fff88de5a544e2ef91a8c3f7c5fa1339aa5..935771726f9cbb19b910ba38c7babf81fd72bba8 100644 (file)
@@ -65,6 +65,8 @@ int xen_smp_intr_init(unsigned int cpu)
        char *resched_name, *callfunc_name, *debug_name;
 
        resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
+       if (!resched_name)
+               goto fail_mem;
        per_cpu(xen_resched_irq, cpu).name = resched_name;
        rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
                                    cpu,
@@ -77,6 +79,8 @@ int xen_smp_intr_init(unsigned int cpu)
        per_cpu(xen_resched_irq, cpu).irq = rc;
 
        callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
+       if (!callfunc_name)
+               goto fail_mem;
        per_cpu(xen_callfunc_irq, cpu).name = callfunc_name;
        rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
                                    cpu,
@@ -90,6 +94,9 @@ int xen_smp_intr_init(unsigned int cpu)
 
        if (!xen_fifo_events) {
                debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu);
+               if (!debug_name)
+                       goto fail_mem;
+
                per_cpu(xen_debug_irq, cpu).name = debug_name;
                rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu,
                                             xen_debug_interrupt,
@@ -101,6 +108,9 @@ int xen_smp_intr_init(unsigned int cpu)
        }
 
        callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu);
+       if (!callfunc_name)
+               goto fail_mem;
+
        per_cpu(xen_callfuncsingle_irq, cpu).name = callfunc_name;
        rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR,
                                    cpu,
@@ -114,6 +124,8 @@ int xen_smp_intr_init(unsigned int cpu)
 
        return 0;
 
+ fail_mem:
+       rc = -ENOMEM;
  fail:
        xen_smp_intr_free(cpu);
        return rc;
@@ -123,8 +135,6 @@ void __init xen_smp_cpus_done(unsigned int max_cpus)
 {
        if (xen_hvm_domain())
                native_smp_cpus_done(max_cpus);
-       else
-               calculate_max_logical_packages();
 }
 
 void xen_smp_send_reschedule(int cpu)
index c20cbb14c82bad72f5703297d49ac8aa775e4425..b8efdbc693f7a86820549e10428445150a04e592 100644 (file)
@@ -19,6 +19,7 @@ extern void xen_smp_intr_free(unsigned int cpu);
 int xen_smp_intr_init_pv(unsigned int cpu);
 void xen_smp_intr_free_pv(unsigned int cpu);
 
+void xen_smp_count_cpus(void);
 void xen_smp_cpus_done(unsigned int max_cpus);
 
 void xen_smp_send_reschedule(int cpu);
@@ -44,6 +45,7 @@ static inline int xen_smp_intr_init_pv(unsigned int cpu)
        return 0;
 }
 static inline void xen_smp_intr_free_pv(unsigned int cpu) {}
+static inline void xen_smp_count_cpus(void) { }
 #endif /* CONFIG_SMP */
 
 #endif
index a0f07bbfcd6e37134e33ec33229d1cf6fd37cc79..27d1a5b7f571a3487cfa68a037e51516a6b9b287 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/idtentry.h>
 #include <asm/desc.h>
 #include <asm/cpu.h>
+#include <asm/apic.h>
 #include <asm/io_apic.h>
 
 #include <xen/interface/xen.h>
@@ -73,7 +74,6 @@ static void cpu_bringup(void)
        }
        cpu = smp_processor_id();
        smp_store_cpu_info(cpu);
-       cpu_data(cpu).x86_max_cores = 1;
        set_cpu_sibling_map(cpu);
 
        speculative_store_bypass_ht_init();
@@ -149,39 +149,16 @@ int xen_smp_intr_init_pv(unsigned int cpu)
        return rc;
 }
 
-static void __init _get_smp_config(unsigned int early)
+static void __init xen_pv_smp_config(void)
 {
-       int i, rc;
-       unsigned int subtract = 0;
-
-       if (early)
-               return;
-
-       num_processors = 0;
-       disabled_cpus = 0;
-       for (i = 0; i < nr_cpu_ids; i++) {
-               rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
-               if (rc >= 0) {
-                       num_processors++;
-                       set_cpu_possible(i, true);
-               } else {
-                       set_cpu_possible(i, false);
-                       set_cpu_present(i, false);
-                       subtract++;
-               }
-       }
-#ifdef CONFIG_HOTPLUG_CPU
-       /* This is akin to using 'nr_cpus' on the Linux command line.
-        * Which is OK as when we use 'dom0_max_vcpus=X' we can only
-        * have up to X, while nr_cpu_ids is greater than X. This
-        * normally is not a problem, except when CPU hotplugging
-        * is involved and then there might be more than X CPUs
-        * in the guest - which will not work as there is no
-        * hypercall to expand the max number of VCPUs an already
-        * running guest has. So cap it up to X. */
-       if (subtract)
-               set_nr_cpu_ids(nr_cpu_ids - subtract);
-#endif
+       u32 apicid = 0;
+       int i;
+
+       topology_register_boot_apic(apicid++);
+
+       for (i = 1; i < nr_cpu_ids; i++)
+               topology_register_apic(apicid++, CPU_ACPIID_INVALID, true);
+
        /* Pretend to be a proper enumerated system */
        smp_found_config = 1;
 }
@@ -224,8 +201,6 @@ static void __init xen_pv_smp_prepare_cpus(unsigned int max_cpus)
 
        smp_prepare_cpus_common();
 
-       cpu_data(0).x86_max_cores = 1;
-
        speculative_store_bypass_ht_init();
 
        xen_pmu_init(0);
@@ -434,6 +409,20 @@ static irqreturn_t xen_irq_work_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+void __init xen_smp_count_cpus(void)
+{
+       unsigned int cpus;
+
+       for (cpus = 0; cpus < nr_cpu_ids; cpus++) {
+               if (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpus, NULL) < 0)
+                       break;
+       }
+
+       pr_info("Xen PV: Detected %u vCPUS\n", cpus);
+       if (cpus < nr_cpu_ids)
+               set_nr_cpu_ids(cpus);
+}
+
 static const struct smp_ops xen_smp_ops __initconst = {
        .smp_prepare_boot_cpu = xen_pv_smp_prepare_boot_cpu,
        .smp_prepare_cpus = xen_pv_smp_prepare_cpus,
@@ -458,6 +447,12 @@ void __init xen_smp_init(void)
        smp_ops = xen_smp_ops;
 
        /* Avoid searching for BIOS MP tables */
-       x86_init.mpparse.find_smp_config = x86_init_noop;
-       x86_init.mpparse.get_smp_config = _get_smp_config;
+       x86_init.mpparse.find_mptable           = x86_init_noop;
+       x86_init.mpparse.early_parse_smp_cfg    = x86_init_noop;
+
+       /* XEN/PV Dom0 has halfways sane topology information via CPUID/MADT */
+       if (xen_initial_domain())
+               x86_init.mpparse.parse_smp_cfg  = x86_init_noop;
+       else
+               x86_init.mpparse.parse_smp_cfg  = xen_pv_smp_config;
 }
index d97adab8420f4c248011e87d7c43417ad3b2ca6e..f7547807b0bd7311d375ed572b1b718538ecbf79 100644 (file)
@@ -2,7 +2,6 @@
 #include <linux/screen_info.h>
 #include <linux/init.h>
 
-#include <asm/bootparam.h>
 #include <asm/setup.h>
 
 #include <xen/interface/xen.h>
index 1a9cd18dfbd31208e5d1bcfa53f4a6e90bc81cf6..83189cf5cdce9361c6a878f1e8ce86e285ad9ba1 100644 (file)
@@ -28,7 +28,7 @@
  * non-zero.
  */
 SYM_FUNC_START(xen_irq_disable_direct)
-       movb $1, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_mask
+       movb $1, PER_CPU_VAR(xen_vcpu_info + XEN_vcpu_info_mask)
        RET
 SYM_FUNC_END(xen_irq_disable_direct)
 
@@ -69,7 +69,7 @@ SYM_FUNC_END(check_events)
 SYM_FUNC_START(xen_irq_enable_direct)
        FRAME_BEGIN
        /* Unmask events */
-       movb $0, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_mask
+       movb $0, PER_CPU_VAR(xen_vcpu_info + XEN_vcpu_info_mask)
 
        /*
         * Preempt here doesn't matter because that will deal with any
@@ -78,7 +78,7 @@ SYM_FUNC_START(xen_irq_enable_direct)
         */
 
        /* Test for pending */
-       testb $0xff, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_pending
+       testb $0xff, PER_CPU_VAR(xen_vcpu_info + XEN_vcpu_info_pending)
        jz 1f
 
        call check_events
@@ -97,7 +97,7 @@ SYM_FUNC_END(xen_irq_enable_direct)
  * x86 use opposite senses (mask vs enable).
  */
 SYM_FUNC_START(xen_save_fl_direct)
-       testb $0xff, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_mask
+       testb $0xff, PER_CPU_VAR(xen_vcpu_info + XEN_vcpu_info_mask)
        setz %ah
        addb %ah, %ah
        RET
@@ -113,7 +113,7 @@ SYM_FUNC_END(xen_read_cr2);
 
 SYM_FUNC_START(xen_read_cr2_direct)
        FRAME_BEGIN
-       _ASM_MOV PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_arch_cr2, %_ASM_AX
+       _ASM_MOV PER_CPU_VAR(xen_vcpu_info + XEN_vcpu_info_arch_cr2), %_ASM_AX
        FRAME_END
        RET
 SYM_FUNC_END(xen_read_cr2_direct);
index a0ea285878dbe168ce5bf8cea61d5c642c4d0b72..04101b984f24dab88bb020add4afe4774628e627 100644 (file)
@@ -49,7 +49,7 @@ SYM_CODE_START(startup_xen)
        ANNOTATE_NOENDBR
        cld
 
-       leaq    (__end_init_task - PTREGS_SIZE)(%rip), %rsp
+       leaq    (__end_init_task - TOP_OF_KERNEL_STACK_PADDING - PTREGS_SIZE)(%rip), %rsp
 
        /* Set up %gs.
         *
index 6f248d87e496aad36a83bbc4b64ee9bbe5050728..87ec35b3363be1c03a4128209db4bd9b3d535fea 100644 (file)
@@ -44,6 +44,7 @@ config XTENSA
        select HAVE_GCC_PLUGINS if GCC_VERSION >= 120000
        select HAVE_HW_BREAKPOINT if PERF_EVENTS
        select HAVE_IRQ_TIME_ACCOUNTING
+       select HAVE_PAGE_SIZE_4KB
        select HAVE_PCI
        select HAVE_PERF_EVENTS
        select HAVE_STACKPROTECTOR
index a77d04972eb92f86f6e85db919db10b009d5b6e6..4db56ef052d2235eb35ea712026615d0cf66859b 100644 (file)
@@ -22,7 +22,7 @@
  * PAGE_SHIFT determines the page size
  */
 
-#define PAGE_SHIFT     12
+#define PAGE_SHIFT     CONFIG_PAGE_SHIFT
 #define PAGE_SIZE      (__XTENSA_UL_CONST(1) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
index 178cf96ca10acb4cd70f8cd052e58503a9ee1494..defc67909a9c745a9794847a3b0bfbeb9ca74536 100644 (file)
@@ -264,16 +264,18 @@ static int __init simdisk_setup(struct simdisk *dev, int which,
                struct proc_dir_entry *procdir)
 {
        char tmp[2] = { '0' + which, 0 };
-       int err = -ENOMEM;
+       int err;
 
        dev->fd = -1;
        dev->filename = NULL;
        spin_lock_init(&dev->lock);
        dev->users = 0;
 
-       dev->gd = blk_alloc_disk(NUMA_NO_NODE);
-       if (!dev->gd)
+       dev->gd = blk_alloc_disk(NULL, NUMA_NO_NODE);
+       if (IS_ERR(dev->gd)) {
+               err = PTR_ERR(dev->gd);
                goto out;
+       }
        dev->gd->major = simdisk_major;
        dev->gd->first_minor = which;
        dev->gd->minors = SIMDISK_MINORS;
index e9f1b12bd75c7b0d4b2964995e8fbf70ac3c5c8e..e7adaaf1c21927a71d93e64817e22732fc72f2a3 100644 (file)
@@ -49,6 +49,12 @@ struct block_device *I_BDEV(struct inode *inode)
 }
 EXPORT_SYMBOL(I_BDEV);
 
+struct block_device *file_bdev(struct file *bdev_file)
+{
+       return I_BDEV(bdev_file->f_mapping->host);
+}
+EXPORT_SYMBOL(file_bdev);
+
 static void bdev_write_inode(struct block_device *bdev)
 {
        struct inode *inode = bdev->bd_inode;
@@ -368,24 +374,24 @@ static struct file_system_type bd_type = {
 };
 
 struct super_block *blockdev_superblock __ro_after_init;
+struct vfsmount *blockdev_mnt __ro_after_init;
 EXPORT_SYMBOL_GPL(blockdev_superblock);
 
 void __init bdev_cache_init(void)
 {
        int err;
-       static struct vfsmount *bd_mnt __ro_after_init;
 
        bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),
                        0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
-                               SLAB_MEM_SPREAD|SLAB_ACCOUNT|SLAB_PANIC),
+                               SLAB_ACCOUNT|SLAB_PANIC),
                        init_once);
        err = register_filesystem(&bd_type);
        if (err)
                panic("Cannot register bdev pseudo-fs");
-       bd_mnt = kern_mount(&bd_type);
-       if (IS_ERR(bd_mnt))
+       blockdev_mnt = kern_mount(&bd_type);
+       if (IS_ERR(blockdev_mnt))
                panic("Cannot create bdev pseudo-fs");
-       blockdev_superblock = bd_mnt->mnt_sb;   /* For writeback */
+       blockdev_superblock = blockdev_mnt->mnt_sb;   /* For writeback */
 }
 
 struct block_device *bdev_alloc(struct gendisk *disk, u8 partno)
@@ -696,6 +702,31 @@ out_blkdev_put:
        return ret;
 }
 
+int bdev_permission(dev_t dev, blk_mode_t mode, void *holder)
+{
+       int ret;
+
+       ret = devcgroup_check_permission(DEVCG_DEV_BLOCK,
+                       MAJOR(dev), MINOR(dev),
+                       ((mode & BLK_OPEN_READ) ? DEVCG_ACC_READ : 0) |
+                       ((mode & BLK_OPEN_WRITE) ? DEVCG_ACC_WRITE : 0));
+       if (ret)
+               return ret;
+
+       /* Blocking writes requires exclusive opener */
+       if (mode & BLK_OPEN_RESTRICT_WRITES && !holder)
+               return -EINVAL;
+
+       /*
+        * We're using error pointers to indicate to ->release() when we
+        * failed to open that block device. Also this doesn't make sense.
+        */
+       if (WARN_ON_ONCE(IS_ERR(holder)))
+               return -EINVAL;
+
+       return 0;
+}
+
 static void blkdev_put_part(struct block_device *part)
 {
        struct block_device *whole = bdev_whole(part);
@@ -775,83 +806,55 @@ static void bdev_claim_write_access(struct block_device *bdev, blk_mode_t mode)
                bdev->bd_writers++;
 }
 
-static void bdev_yield_write_access(struct block_device *bdev, blk_mode_t mode)
+static void bdev_yield_write_access(struct file *bdev_file)
 {
+       struct block_device *bdev;
+
        if (bdev_allow_write_mounted)
                return;
 
+       bdev = file_bdev(bdev_file);
        /* Yield exclusive or shared write access. */
-       if (mode & BLK_OPEN_RESTRICT_WRITES)
-               bdev_unblock_writes(bdev);
-       else if (mode & BLK_OPEN_WRITE)
-               bdev->bd_writers--;
+       if (bdev_file->f_mode & FMODE_WRITE) {
+               if (bdev_writes_blocked(bdev))
+                       bdev_unblock_writes(bdev);
+               else
+                       bdev->bd_writers--;
+       }
 }
 
 /**
- * bdev_open_by_dev - open a block device by device number
- * @dev: device number of block device to open
+ * bdev_open - open a block device
+ * @bdev: block device to open
  * @mode: open mode (BLK_OPEN_*)
  * @holder: exclusive holder identifier
  * @hops: holder operations
+ * @bdev_file: file for the block device
  *
- * Open the block device described by device number @dev. If @holder is not
- * %NULL, the block device is opened with exclusive access.  Exclusive opens may
- * nest for the same @holder.
- *
- * Use this interface ONLY if you really do not have anything better - i.e. when
- * you are behind a truly sucky interface and all you are given is a device
- * number.  Everything else should use bdev_open_by_path().
+ * Open the block device. If @holder is not %NULL, the block device is opened
+ * with exclusive access.  Exclusive opens may nest for the same @holder.
  *
  * CONTEXT:
  * Might sleep.
  *
  * RETURNS:
- * Handle with a reference to the block_device on success, ERR_PTR(-errno) on
- * failure.
+ * zero on success, -errno on failure.
  */
-struct bdev_handle *bdev_open_by_dev(dev_t dev, blk_mode_t mode, void *holder,
-                                    const struct blk_holder_ops *hops)
+int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder,
+             const struct blk_holder_ops *hops, struct file *bdev_file)
 {
-       struct bdev_handle *handle = kmalloc(sizeof(struct bdev_handle),
-                                            GFP_KERNEL);
-       struct block_device *bdev;
        bool unblock_events = true;
-       struct gendisk *disk;
+       struct gendisk *disk = bdev->bd_disk;
        int ret;
 
-       if (!handle)
-               return ERR_PTR(-ENOMEM);
-
-       ret = devcgroup_check_permission(DEVCG_DEV_BLOCK,
-                       MAJOR(dev), MINOR(dev),
-                       ((mode & BLK_OPEN_READ) ? DEVCG_ACC_READ : 0) |
-                       ((mode & BLK_OPEN_WRITE) ? DEVCG_ACC_WRITE : 0));
-       if (ret)
-               goto free_handle;
-
-       /* Blocking writes requires exclusive opener */
-       if (mode & BLK_OPEN_RESTRICT_WRITES && !holder) {
-               ret = -EINVAL;
-               goto free_handle;
-       }
-
-       bdev = blkdev_get_no_open(dev);
-       if (!bdev) {
-               ret = -ENXIO;
-               goto free_handle;
-       }
-       disk = bdev->bd_disk;
-
        if (holder) {
                mode |= BLK_OPEN_EXCL;
                ret = bd_prepare_to_claim(bdev, holder, hops);
                if (ret)
-                       goto put_blkdev;
+                       return ret;
        } else {
-               if (WARN_ON_ONCE(mode & BLK_OPEN_EXCL)) {
-                       ret = -EIO;
-                       goto put_blkdev;
-               }
+               if (WARN_ON_ONCE(mode & BLK_OPEN_EXCL))
+                       return -EIO;
        }
 
        disk_block_events(disk);
@@ -892,10 +895,16 @@ struct bdev_handle *bdev_open_by_dev(dev_t dev, blk_mode_t mode, void *holder,
 
        if (unblock_events)
                disk_unblock_events(disk);
-       handle->bdev = bdev;
-       handle->holder = holder;
-       handle->mode = mode;
-       return handle;
+
+       bdev_file->f_flags |= O_LARGEFILE;
+       bdev_file->f_mode |= FMODE_BUF_RASYNC | FMODE_CAN_ODIRECT;
+       if (bdev_nowait(bdev))
+               bdev_file->f_mode |= FMODE_NOWAIT;
+       bdev_file->f_mapping = bdev->bd_inode->i_mapping;
+       bdev_file->f_wb_err = filemap_sample_wb_err(bdev_file->f_mapping);
+       bdev_file->private_data = holder;
+
+       return 0;
 put_module:
        module_put(disk->fops->owner);
 abort_claiming:
@@ -903,36 +912,80 @@ abort_claiming:
                bd_abort_claiming(bdev, holder);
        mutex_unlock(&disk->open_mutex);
        disk_unblock_events(disk);
-put_blkdev:
-       blkdev_put_no_open(bdev);
-free_handle:
-       kfree(handle);
-       return ERR_PTR(ret);
+       return ret;
 }
-EXPORT_SYMBOL(bdev_open_by_dev);
 
-/**
- * bdev_open_by_path - open a block device by name
- * @path: path to the block device to open
- * @mode: open mode (BLK_OPEN_*)
- * @holder: exclusive holder identifier
- * @hops: holder operations
- *
- * Open the block device described by the device file at @path.  If @holder is
- * not %NULL, the block device is opened with exclusive access.  Exclusive opens
- * may nest for the same @holder.
- *
- * CONTEXT:
- * Might sleep.
+/*
+ * If BLK_OPEN_WRITE_IOCTL is set then this is a historical quirk
+ * associated with the floppy driver where it has allowed ioctls if the
+ * file was opened for writing, but does not allow reads or writes.
+ * Make sure that this quirk is reflected in @f_flags.
  *
- * RETURNS:
- * Handle with a reference to the block_device on success, ERR_PTR(-errno) on
- * failure.
+ * It can also happen if a block device is opened as O_RDWR | O_WRONLY.
  */
-struct bdev_handle *bdev_open_by_path(const char *path, blk_mode_t mode,
-               void *holder, const struct blk_holder_ops *hops)
+static unsigned blk_to_file_flags(blk_mode_t mode)
+{
+       unsigned int flags = 0;
+
+       if ((mode & (BLK_OPEN_READ | BLK_OPEN_WRITE)) ==
+           (BLK_OPEN_READ | BLK_OPEN_WRITE))
+               flags |= O_RDWR;
+       else if (mode & BLK_OPEN_WRITE_IOCTL)
+               flags |= O_RDWR | O_WRONLY;
+       else if (mode & BLK_OPEN_WRITE)
+               flags |= O_WRONLY;
+       else if (mode & BLK_OPEN_READ)
+               flags |= O_RDONLY; /* homeopathic, because O_RDONLY is 0 */
+       else
+               WARN_ON_ONCE(true);
+
+       if (mode & BLK_OPEN_NDELAY)
+               flags |= O_NDELAY;
+
+       return flags;
+}
+
+struct file *bdev_file_open_by_dev(dev_t dev, blk_mode_t mode, void *holder,
+                                  const struct blk_holder_ops *hops)
 {
-       struct bdev_handle *handle;
+       struct file *bdev_file;
+       struct block_device *bdev;
+       unsigned int flags;
+       int ret;
+
+       ret = bdev_permission(dev, mode, holder);
+       if (ret)
+               return ERR_PTR(ret);
+
+       bdev = blkdev_get_no_open(dev);
+       if (!bdev)
+               return ERR_PTR(-ENXIO);
+
+       flags = blk_to_file_flags(mode);
+       bdev_file = alloc_file_pseudo_noaccount(bdev->bd_inode,
+                       blockdev_mnt, "", flags | O_LARGEFILE, &def_blk_fops);
+       if (IS_ERR(bdev_file)) {
+               blkdev_put_no_open(bdev);
+               return bdev_file;
+       }
+       ihold(bdev->bd_inode);
+
+       ret = bdev_open(bdev, mode, holder, hops, bdev_file);
+       if (ret) {
+               /* We failed to open the block device. Let ->release() know. */
+               bdev_file->private_data = ERR_PTR(ret);
+               fput(bdev_file);
+               return ERR_PTR(ret);
+       }
+       return bdev_file;
+}
+EXPORT_SYMBOL(bdev_file_open_by_dev);
+
+struct file *bdev_file_open_by_path(const char *path, blk_mode_t mode,
+                                   void *holder,
+                                   const struct blk_holder_ops *hops)
+{
+       struct file *file;
        dev_t dev;
        int error;
 
@@ -940,22 +993,28 @@ struct bdev_handle *bdev_open_by_path(const char *path, blk_mode_t mode,
        if (error)
                return ERR_PTR(error);
 
-       handle = bdev_open_by_dev(dev, mode, holder, hops);
-       if (!IS_ERR(handle) && (mode & BLK_OPEN_WRITE) &&
-           bdev_read_only(handle->bdev)) {
-               bdev_release(handle);
-               return ERR_PTR(-EACCES);
+       file = bdev_file_open_by_dev(dev, mode, holder, hops);
+       if (!IS_ERR(file) && (mode & BLK_OPEN_WRITE)) {
+               if (bdev_read_only(file_bdev(file))) {
+                       fput(file);
+                       file = ERR_PTR(-EACCES);
+               }
        }
 
-       return handle;
+       return file;
 }
-EXPORT_SYMBOL(bdev_open_by_path);
+EXPORT_SYMBOL(bdev_file_open_by_path);
 
-void bdev_release(struct bdev_handle *handle)
+void bdev_release(struct file *bdev_file)
 {
-       struct block_device *bdev = handle->bdev;
+       struct block_device *bdev = file_bdev(bdev_file);
+       void *holder = bdev_file->private_data;
        struct gendisk *disk = bdev->bd_disk;
 
+       /* We failed to open that block device. */
+       if (IS_ERR(holder))
+               goto put_no_open;
+
        /*
         * Sync early if it looks like we're the last one.  If someone else
         * opens the block device between now and the decrement of bd_openers
@@ -967,10 +1026,10 @@ void bdev_release(struct bdev_handle *handle)
                sync_blockdev(bdev);
 
        mutex_lock(&disk->open_mutex);
-       bdev_yield_write_access(bdev, handle->mode);
+       bdev_yield_write_access(bdev_file);
 
-       if (handle->holder)
-               bd_end_claim(bdev, handle->holder);
+       if (holder)
+               bd_end_claim(bdev, holder);
 
        /*
         * Trigger event checking and tell drivers to flush MEDIA_CHANGE
@@ -986,10 +1045,9 @@ void bdev_release(struct bdev_handle *handle)
        mutex_unlock(&disk->open_mutex);
 
        module_put(disk->fops->owner);
+put_no_open:
        blkdev_put_no_open(bdev);
-       kfree(handle);
 }
-EXPORT_SYMBOL(bdev_release);
 
 /**
  * lookup_bdev() - Look up a struct block_device by name.
index 2c90e5de0acd94f9ba3f1920cede68856c8f66df..d442ee358fc2573e6873dec037e90998ddda7fdf 100644 (file)
@@ -127,7 +127,7 @@ static void bfqg_stats_update_group_wait_time(struct bfqg_stats *stats)
        if (!bfqg_stats_waiting(stats))
                return;
 
-       now = ktime_get_ns();
+       now = blk_time_get_ns();
        if (now > stats->start_group_wait_time)
                bfq_stat_add(&stats->group_wait_time,
                              now - stats->start_group_wait_time);
@@ -144,7 +144,7 @@ static void bfqg_stats_set_start_group_wait_time(struct bfq_group *bfqg,
                return;
        if (bfqg == curr_bfqg)
                return;
-       stats->start_group_wait_time = ktime_get_ns();
+       stats->start_group_wait_time = blk_time_get_ns();
        bfqg_stats_mark_waiting(stats);
 }
 
@@ -156,7 +156,7 @@ static void bfqg_stats_end_empty_time(struct bfqg_stats *stats)
        if (!bfqg_stats_empty(stats))
                return;
 
-       now = ktime_get_ns();
+       now = blk_time_get_ns();
        if (now > stats->start_empty_time)
                bfq_stat_add(&stats->empty_time,
                              now - stats->start_empty_time);
@@ -183,7 +183,7 @@ void bfqg_stats_set_start_empty_time(struct bfq_group *bfqg)
        if (bfqg_stats_empty(stats))
                return;
 
-       stats->start_empty_time = ktime_get_ns();
+       stats->start_empty_time = blk_time_get_ns();
        bfqg_stats_mark_empty(stats);
 }
 
@@ -192,7 +192,7 @@ void bfqg_stats_update_idle_time(struct bfq_group *bfqg)
        struct bfqg_stats *stats = &bfqg->stats;
 
        if (bfqg_stats_idling(stats)) {
-               u64 now = ktime_get_ns();
+               u64 now = blk_time_get_ns();
 
                if (now > stats->start_idle_time)
                        bfq_stat_add(&stats->idle_time,
@@ -205,7 +205,7 @@ void bfqg_stats_set_start_idle_time(struct bfq_group *bfqg)
 {
        struct bfqg_stats *stats = &bfqg->stats;
 
-       stats->start_idle_time = ktime_get_ns();
+       stats->start_idle_time = blk_time_get_ns();
        bfqg_stats_mark_idling(stats);
 }
 
@@ -242,7 +242,7 @@ void bfqg_stats_update_completion(struct bfq_group *bfqg, u64 start_time_ns,
                                  u64 io_start_time_ns, blk_opf_t opf)
 {
        struct bfqg_stats *stats = &bfqg->stats;
-       u64 now = ktime_get_ns();
+       u64 now = blk_time_get_ns();
 
        if (now > io_start_time_ns)
                blkg_rwstat_add(&stats->service_time, opf,
index 3cce6de464a7b7c1b506158d044b537510a3e6f8..4b88a54a9b76cba3bca954e50f509ff6028251ee 100644 (file)
@@ -1005,7 +1005,7 @@ static struct request *bfq_check_fifo(struct bfq_queue *bfqq,
 
        rq = rq_entry_fifo(bfqq->fifo.next);
 
-       if (rq == last || ktime_get_ns() < rq->fifo_time)
+       if (rq == last || blk_time_get_ns() < rq->fifo_time)
                return NULL;
 
        bfq_log_bfqq(bfqq->bfqd, bfqq, "check_fifo: returned %p", rq);
@@ -1829,7 +1829,7 @@ static void bfq_bfqq_handle_idle_busy_switch(struct bfq_data *bfqd,
                 * bfq_bfqq_update_budg_for_activation for
                 * details on the usage of the next variable.
                 */
-               arrived_in_time =  ktime_get_ns() <=
+               arrived_in_time =  blk_time_get_ns() <=
                        bfqq->ttime.last_end_request +
                        bfqd->bfq_slice_idle * 3;
        unsigned int act_idx = bfq_actuator_index(bfqd, rq->bio);
@@ -2208,7 +2208,7 @@ static void bfq_add_request(struct request *rq)
        struct request *next_rq, *prev;
        unsigned int old_wr_coeff = bfqq->wr_coeff;
        bool interactive = false;
-       u64 now_ns = ktime_get_ns();
+       u64 now_ns = blk_time_get_ns();
 
        bfq_log_bfqq(bfqd, bfqq, "add_request %d", rq_is_sync(rq));
        bfqq->queued[rq_is_sync(rq)]++;
@@ -2262,7 +2262,7 @@ static void bfq_add_request(struct request *rq)
                      bfqd->rqs_injected && bfqd->tot_rq_in_driver > 0)) &&
                    time_is_before_eq_jiffies(bfqq->decrease_time_jif +
                                              msecs_to_jiffies(10))) {
-                       bfqd->last_empty_occupied_ns = ktime_get_ns();
+                       bfqd->last_empty_occupied_ns = blk_time_get_ns();
                        /*
                         * Start the state machine for measuring the
                         * total service time of rq: setting
@@ -3294,7 +3294,7 @@ static void bfq_set_budget_timeout(struct bfq_data *bfqd,
        else
                timeout_coeff = bfqq->entity.weight / bfqq->entity.orig_weight;
 
-       bfqd->last_budget_start = ktime_get();
+       bfqd->last_budget_start = blk_time_get();
 
        bfqq->budget_timeout = jiffies +
                bfqd->bfq_timeout * timeout_coeff;
@@ -3394,7 +3394,7 @@ static void bfq_arm_slice_timer(struct bfq_data *bfqd)
        else if (bfqq->wr_coeff > 1)
                sl = max_t(u32, sl, 20ULL * NSEC_PER_MSEC);
 
-       bfqd->last_idling_start = ktime_get();
+       bfqd->last_idling_start = blk_time_get();
        bfqd->last_idling_start_jiffies = jiffies;
 
        hrtimer_start(&bfqd->idle_slice_timer, ns_to_ktime(sl),
@@ -3433,7 +3433,7 @@ static void bfq_reset_rate_computation(struct bfq_data *bfqd,
                                       struct request *rq)
 {
        if (rq != NULL) { /* new rq dispatch now, reset accordingly */
-               bfqd->last_dispatch = bfqd->first_dispatch = ktime_get_ns();
+               bfqd->last_dispatch = bfqd->first_dispatch = blk_time_get_ns();
                bfqd->peak_rate_samples = 1;
                bfqd->sequential_samples = 0;
                bfqd->tot_sectors_dispatched = bfqd->last_rq_max_size =
@@ -3590,7 +3590,7 @@ reset_computation:
  */
 static void bfq_update_peak_rate(struct bfq_data *bfqd, struct request *rq)
 {
-       u64 now_ns = ktime_get_ns();
+       u64 now_ns = blk_time_get_ns();
 
        if (bfqd->peak_rate_samples == 0) { /* first dispatch */
                bfq_log(bfqd, "update_peak_rate: goto reset, samples %d",
@@ -4162,7 +4162,7 @@ static bool bfq_bfqq_is_slow(struct bfq_data *bfqd, struct bfq_queue *bfqq,
        if (compensate)
                delta_ktime = bfqd->last_idling_start;
        else
-               delta_ktime = ktime_get();
+               delta_ktime = blk_time_get();
        delta_ktime = ktime_sub(delta_ktime, bfqd->last_budget_start);
        delta_usecs = ktime_to_us(delta_ktime);
 
@@ -5591,7 +5591,7 @@ static void bfq_init_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq,
                          struct bfq_io_cq *bic, pid_t pid, int is_sync,
                          unsigned int act_idx)
 {
-       u64 now_ns = ktime_get_ns();
+       u64 now_ns = blk_time_get_ns();
 
        bfqq->actuator_idx = act_idx;
        RB_CLEAR_NODE(&bfqq->entity.rb_node);
@@ -5903,7 +5903,7 @@ static void bfq_update_io_thinktime(struct bfq_data *bfqd,
         */
        if (bfqq->dispatched || bfq_bfqq_busy(bfqq))
                return;
-       elapsed = ktime_get_ns() - bfqq->ttime.last_end_request;
+       elapsed = blk_time_get_ns() - bfqq->ttime.last_end_request;
        elapsed = min_t(u64, elapsed, 2ULL * bfqd->bfq_slice_idle);
 
        ttime->ttime_samples = (7*ttime->ttime_samples + 256) / 8;
@@ -6194,7 +6194,7 @@ static bool __bfq_insert_request(struct bfq_data *bfqd, struct request *rq)
        bfq_add_request(rq);
        idle_timer_disabled = waiting && !bfq_bfqq_wait_request(bfqq);
 
-       rq->fifo_time = ktime_get_ns() + bfqd->bfq_fifo_expire[rq_is_sync(rq)];
+       rq->fifo_time = blk_time_get_ns() + bfqd->bfq_fifo_expire[rq_is_sync(rq)];
        list_add_tail(&rq->queuelist, &bfqq->fifo);
 
        bfq_rq_enqueued(bfqd, bfqq, rq);
@@ -6370,7 +6370,7 @@ static void bfq_completed_request(struct bfq_queue *bfqq, struct bfq_data *bfqd)
                bfq_weights_tree_remove(bfqq);
        }
 
-       now_ns = ktime_get_ns();
+       now_ns = blk_time_get_ns();
 
        bfqq->ttime.last_end_request = now_ns;
 
@@ -6585,7 +6585,7 @@ static void bfq_completed_request(struct bfq_queue *bfqq, struct bfq_data *bfqd)
 static void bfq_update_inject_limit(struct bfq_data *bfqd,
                                    struct bfq_queue *bfqq)
 {
-       u64 tot_time_ns = ktime_get_ns() - bfqd->last_empty_occupied_ns;
+       u64 tot_time_ns = blk_time_get_ns() - bfqd->last_empty_occupied_ns;
        unsigned int old_limit = bfqq->inject_limit;
 
        if (bfqq->last_serv_time_ns > 0 && bfqd->rqs_injected) {
index c9a16fba58b9c47f5424be9a8c7c6681d176b986..2e3e8e04961eaeaa04f9ec0470d15bbf64867191 100644 (file)
@@ -395,6 +395,7 @@ static blk_status_t bio_integrity_process(struct bio *bio,
        iter.tuple_size = bi->tuple_size;
        iter.seed = proc_iter->bi_sector;
        iter.prot_buf = bvec_virt(bip->bip_vec);
+       iter.pi_offset = bi->pi_offset;
 
        __bio_for_each_segment(bv, bio, bviter, *proc_iter) {
                void *kaddr = bvec_kmap_local(&bv);
index b9642a41f286e5bb52d841255aa9286c1449e83d..d24420ed1c4c6f20b80bc043cdf0378afcb43668 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/workqueue.h>
 #include <linux/cgroup.h>
 #include <linux/highmem.h>
-#include <linux/sched/sysctl.h>
 #include <linux/blk-crypto.h>
 #include <linux/xarray.h>
 
@@ -251,6 +250,7 @@ void bio_init(struct bio *bio, struct block_device *bdev, struct bio_vec *table,
        bio->bi_opf = opf;
        bio->bi_flags = 0;
        bio->bi_ioprio = 0;
+       bio->bi_write_hint = 0;
        bio->bi_status = 0;
        bio->bi_iter.bi_sector = 0;
        bio->bi_iter.bi_size = 0;
@@ -762,29 +762,31 @@ static inline void bio_put_percpu_cache(struct bio *bio)
        struct bio_alloc_cache *cache;
 
        cache = per_cpu_ptr(bio->bi_pool->cache, get_cpu());
-       if (READ_ONCE(cache->nr_irq) + cache->nr > ALLOC_CACHE_MAX) {
-               put_cpu();
-               bio_free(bio);
-               return;
-       }
+       if (READ_ONCE(cache->nr_irq) + cache->nr > ALLOC_CACHE_MAX)
+               goto out_free;
 
-       bio_uninit(bio);
-
-       if ((bio->bi_opf & REQ_POLLED) && !WARN_ON_ONCE(in_interrupt())) {
+       if (in_task()) {
+               bio_uninit(bio);
                bio->bi_next = cache->free_list;
+               /* Not necessary but helps not to iopoll already freed bios */
                bio->bi_bdev = NULL;
                cache->free_list = bio;
                cache->nr++;
-       } else {
-               unsigned long flags;
+       } else if (in_hardirq()) {
+               lockdep_assert_irqs_disabled();
 
-               local_irq_save(flags);
+               bio_uninit(bio);
                bio->bi_next = cache->free_list_irq;
                cache->free_list_irq = bio;
                cache->nr_irq++;
-               local_irq_restore(flags);
+       } else {
+               goto out_free;
        }
        put_cpu();
+       return;
+out_free:
+       put_cpu();
+       bio_free(bio);
 }
 
 /**
@@ -813,6 +815,7 @@ static int __bio_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp)
 {
        bio_set_flag(bio, BIO_CLONED);
        bio->bi_ioprio = bio_src->bi_ioprio;
+       bio->bi_write_hint = bio_src->bi_write_hint;
        bio->bi_iter = bio_src->bi_iter;
 
        if (bio->bi_bdev) {
@@ -1152,7 +1155,7 @@ void __bio_release_pages(struct bio *bio, bool mark_dirty)
 
        bio_for_each_folio_all(fi, bio) {
                struct page *page;
-               size_t done = 0;
+               size_t nr_pages;
 
                if (mark_dirty) {
                        folio_lock(fi.folio);
@@ -1160,10 +1163,11 @@ void __bio_release_pages(struct bio *bio, bool mark_dirty)
                        folio_unlock(fi.folio);
                }
                page = folio_page(fi.folio, fi.offset / PAGE_SIZE);
+               nr_pages = (fi.offset + fi.length - 1) / PAGE_SIZE -
+                          fi.offset / PAGE_SIZE + 1;
                do {
                        bio_release_page(bio, page++);
-                       done += PAGE_SIZE;
-               } while (done < fi.length);
+               } while (--nr_pages != 0);
        }
 }
 EXPORT_SYMBOL_GPL(__bio_release_pages);
@@ -1369,21 +1373,12 @@ int submit_bio_wait(struct bio *bio)
 {
        DECLARE_COMPLETION_ONSTACK_MAP(done,
                        bio->bi_bdev->bd_disk->lockdep_map);
-       unsigned long hang_check;
 
        bio->bi_private = &done;
        bio->bi_end_io = submit_bio_wait_endio;
        bio->bi_opf |= REQ_SYNC;
        submit_bio(bio);
-
-       /* Prevent hang_check timer from firing at us during very long I/O */
-       hang_check = sysctl_hung_task_timeout_secs;
-       if (hang_check)
-               while (!wait_for_completion_io_timeout(&done,
-                                       hang_check * (HZ/2)))
-                       ;
-       else
-               wait_for_completion_io(&done);
+       blk_wait_io(&done);
 
        return blk_status_to_errno(bio->bi_status);
 }
index ff93c385ba5afb6920b53fdbcf96bd5d3970d17a..bdbb557feb5a0ec949e7ac8cde0e87b6d4055f5b 100644 (file)
@@ -1846,7 +1846,7 @@ static void blkcg_maybe_throttle_blkg(struct blkcg_gq *blkg, bool use_memdelay)
 {
        unsigned long pflags;
        bool clamp;
-       u64 now = ktime_to_ns(ktime_get());
+       u64 now = blk_time_get_ns();
        u64 exp;
        u64 delay_nsec = 0;
        int tok;
index b927a4a0ad0301db43a6aad657c49c67f4cb880b..78b74106bf10c5cbadd655e2da6b2f21416c0622 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kthread.h>
 #include <linux/blk-mq.h>
 #include <linux/llist.h>
+#include "blk.h"
 
 struct blkcg_gq;
 struct blkg_policy_data;
index de771093b52687ae2431af36bf75b73ccaa1bbf0..a16b5abdbbf56f44611d34fd238c0ee3a00d72f5 100644 (file)
@@ -394,24 +394,34 @@ static void blk_timeout_work(struct work_struct *work)
 {
 }
 
-struct request_queue *blk_alloc_queue(int node_id)
+struct request_queue *blk_alloc_queue(struct queue_limits *lim, int node_id)
 {
        struct request_queue *q;
+       int error;
 
        q = kmem_cache_alloc_node(blk_requestq_cachep, GFP_KERNEL | __GFP_ZERO,
                                  node_id);
        if (!q)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        q->last_merge = NULL;
 
        q->id = ida_alloc(&blk_queue_ida, GFP_KERNEL);
-       if (q->id < 0)
+       if (q->id < 0) {
+               error = q->id;
                goto fail_q;
+       }
 
        q->stats = blk_alloc_queue_stats();
-       if (!q->stats)
+       if (!q->stats) {
+               error = -ENOMEM;
                goto fail_id;
+       }
+
+       error = blk_set_default_limits(lim);
+       if (error)
+               goto fail_stats;
+       q->limits = *lim;
 
        q->node = node_id;
 
@@ -425,6 +435,7 @@ struct request_queue *blk_alloc_queue(int node_id)
        mutex_init(&q->debugfs_mutex);
        mutex_init(&q->sysfs_lock);
        mutex_init(&q->sysfs_dir_lock);
+       mutex_init(&q->limits_lock);
        mutex_init(&q->rq_qos_mutex);
        spin_lock_init(&q->queue_lock);
 
@@ -435,12 +446,12 @@ struct request_queue *blk_alloc_queue(int node_id)
         * Init percpu_ref in atomic mode so that it's faster to shutdown.
         * See blk_register_queue() for details.
         */
-       if (percpu_ref_init(&q->q_usage_counter,
+       error = percpu_ref_init(&q->q_usage_counter,
                                blk_queue_usage_counter_release,
-                               PERCPU_REF_INIT_ATOMIC, GFP_KERNEL))
+                               PERCPU_REF_INIT_ATOMIC, GFP_KERNEL);
+       if (error)
                goto fail_stats;
 
-       blk_set_default_limits(&q->limits);
        q->nr_requests = BLKDEV_DEFAULT_RQ;
 
        return q;
@@ -451,7 +462,7 @@ fail_id:
        ida_free(&blk_queue_ida, q->id);
 fail_q:
        kmem_cache_free(blk_requestq_cachep, q);
-       return NULL;
+       return ERR_PTR(error);
 }
 
 /**
@@ -1083,6 +1094,7 @@ void blk_start_plug_nr_ios(struct blk_plug *plug, unsigned short nr_ios)
        if (tsk->plug)
                return;
 
+       plug->cur_ktime = 0;
        plug->mq_list = NULL;
        plug->cached_rq = NULL;
        plug->nr_ios = min_t(unsigned short, nr_ios, BLK_MAX_REQUEST_COUNT);
@@ -1182,6 +1194,8 @@ void __blk_flush_plug(struct blk_plug *plug, bool from_schedule)
         */
        if (unlikely(!rq_list_empty(plug->cached_rq)))
                blk_mq_free_plug_rqs(plug);
+
+       current->flags &= ~PF_BLOCK_TS;
 }
 
 /**
@@ -1229,8 +1243,7 @@ int __init blk_dev_init(void)
        if (!kblockd_workqueue)
                panic("Failed to create kblockd\n");
 
-       blk_requestq_cachep = kmem_cache_create("request_queue",
-                       sizeof(struct request_queue), 0, SLAB_PANIC, NULL);
+       blk_requestq_cachep = KMEM_CACHE(request_queue, SLAB_PANIC);
 
        blk_debugfs_root = debugfs_create_dir("block", NULL);
 
index e6468eab2681e9f827e9b86b3b21d24f6a6fe0a5..b1e7415f8439c45d04c49f7fbeb48891e0392027 100644 (file)
@@ -172,6 +172,7 @@ static struct bio *blk_crypto_fallback_clone_bio(struct bio *bio_src)
        if (bio_flagged(bio_src, BIO_REMAPPED))
                bio_set_flag(bio, BIO_REMAPPED);
        bio->bi_ioprio          = bio_src->bi_ioprio;
+       bio->bi_write_hint      = bio_src->bi_write_hint;
        bio->bi_iter.bi_sector  = bio_src->bi_iter.bi_sector;
        bio->bi_iter.bi_size    = bio_src->bi_iter.bi_size;
 
index 3f4d41952ef210929091ca29661b5da2be280d9c..b0f314f4bc1493db379e6a234c0b5381569827b2 100644 (file)
@@ -143,7 +143,7 @@ static void blk_account_io_flush(struct request *rq)
        part_stat_lock();
        part_stat_inc(part, ios[STAT_FLUSH]);
        part_stat_add(part, nsecs[STAT_FLUSH],
-                     ktime_get_ns() - rq->start_time_ns);
+                     blk_time_get_ns() - rq->start_time_ns);
        part_stat_unlock();
 }
 
index d4e9b4556d14b2ca9931b3123d5e1ba0884720ca..ccbeb6dfa87a4dc5f63a485cd0bec9e800704ff6 100644 (file)
@@ -370,6 +370,7 @@ void blk_integrity_register(struct gendisk *disk, struct blk_integrity *template
        bi->profile = template->profile ? template->profile : &nop_profile;
        bi->tuple_size = template->tuple_size;
        bi->tag_size = template->tag_size;
+       bi->pi_offset = template->pi_offset;
 
        blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, disk->queue);
 
index 04d44f0bcbc85d4898df728c8ceefb3f1b5bea39..9a85bfbbc45a018e941cd0b778ab612a54cdea09 100644 (file)
@@ -829,7 +829,7 @@ static int ioc_autop_idx(struct ioc *ioc, struct gendisk *disk)
 
        /* step up/down based on the vrate */
        vrate_pct = div64_u64(ioc->vtime_base_rate * 100, VTIME_PER_USEC);
-       now_ns = ktime_get_ns();
+       now_ns = blk_time_get_ns();
 
        if (p->too_fast_vrate_pct && p->too_fast_vrate_pct <= vrate_pct) {
                if (!ioc->autop_too_fast_at)
@@ -1044,7 +1044,7 @@ static void ioc_now(struct ioc *ioc, struct ioc_now *now)
        unsigned seq;
        u64 vrate;
 
-       now->now_ns = ktime_get();
+       now->now_ns = blk_time_get_ns();
        now->now = ktime_to_us(now->now_ns);
        vrate = atomic64_read(&ioc->vtime_rate);
 
@@ -2817,7 +2817,7 @@ static void ioc_rqos_done(struct rq_qos *rqos, struct request *rq)
                return;
        }
 
-       on_q_ns = ktime_get_ns() - rq->alloc_time_ns;
+       on_q_ns = blk_time_get_ns() - rq->alloc_time_ns;
        rq_wait_ns = rq->start_time_ns - rq->alloc_time_ns;
        size_nsec = div64_u64(calc_size_vtime_cost(rq, ioc), VTIME_PER_NSEC);
 
@@ -2900,7 +2900,7 @@ static int blk_iocost_init(struct gendisk *disk)
        ioc->vtime_base_rate = VTIME_PER_USEC;
        atomic64_set(&ioc->vtime_rate, VTIME_PER_USEC);
        seqcount_spinlock_init(&ioc->period_seqcount, &ioc->lock);
-       ioc->period_at = ktime_to_us(ktime_get());
+       ioc->period_at = ktime_to_us(blk_time_get());
        atomic64_set(&ioc->cur_period, 0);
        atomic_set(&ioc->hweight_gen, 0);
 
index c1a6aba1d59e4db829079071b591670859018217..ebb522788d9780f6d4b452b826f113957be02772 100644 (file)
@@ -609,7 +609,7 @@ static void blkcg_iolatency_done_bio(struct rq_qos *rqos, struct bio *bio)
        if (!iolat->blkiolat->enabled)
                return;
 
-       now = ktime_to_ns(ktime_get());
+       now = blk_time_get_ns();
        while (blkg && blkg->parent) {
                iolat = blkg_to_lat(blkg);
                if (!iolat) {
@@ -661,7 +661,7 @@ static void blkiolatency_timer_fn(struct timer_list *t)
        struct blk_iolatency *blkiolat = from_timer(blkiolat, t, timer);
        struct blkcg_gq *blkg;
        struct cgroup_subsys_state *pos_css;
-       u64 now = ktime_to_ns(ktime_get());
+       u64 now = blk_time_get_ns();
 
        rcu_read_lock();
        blkg_for_each_descendant_pre(blkg, pos_css,
@@ -985,7 +985,7 @@ static void iolatency_pd_init(struct blkg_policy_data *pd)
        struct blkcg_gq *blkg = lat_to_blkg(iolat);
        struct rq_qos *rqos = iolat_rq_qos(blkg->q);
        struct blk_iolatency *blkiolat = BLKIOLATENCY(rqos);
-       u64 now = ktime_to_ns(ktime_get());
+       u64 now = blk_time_get_ns();
        int cpu;
 
        if (blk_queue_nonrot(blkg->q))
index e59c3069e8351f7edf0d82c6a3b376a3029a994c..dc8e35d0a51d6de0d4c7bfb2d4ce2f8cbb91a5d1 100644 (file)
@@ -35,6 +35,26 @@ static sector_t bio_discard_limit(struct block_device *bdev, sector_t sector)
        return round_down(UINT_MAX, discard_granularity) >> SECTOR_SHIFT;
 }
 
+static void await_bio_endio(struct bio *bio)
+{
+       complete(bio->bi_private);
+       bio_put(bio);
+}
+
+/*
+ * await_bio_chain - ends @bio and waits for every chained bio to complete
+ */
+static void await_bio_chain(struct bio *bio)
+{
+       DECLARE_COMPLETION_ONSTACK_MAP(done,
+                       bio->bi_bdev->bd_disk->lockdep_map);
+
+       bio->bi_private = &done;
+       bio->bi_end_io = await_bio_endio;
+       bio_endio(bio);
+       blk_wait_io(&done);
+}
+
 int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
                sector_t nr_sects, gfp_t gfp_mask, struct bio **biop)
 {
@@ -77,6 +97,10 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
                 * is disabled.
                 */
                cond_resched();
+               if (fatal_signal_pending(current)) {
+                       await_bio_chain(bio);
+                       return -EINTR;
+               }
        }
 
        *biop = bio;
@@ -120,32 +144,33 @@ static int __blkdev_issue_write_zeroes(struct block_device *bdev,
                struct bio **biop, unsigned flags)
 {
        struct bio *bio = *biop;
-       unsigned int max_write_zeroes_sectors;
+       unsigned int max_sectors;
 
        if (bdev_read_only(bdev))
                return -EPERM;
 
-       /* Ensure that max_write_zeroes_sectors doesn't overflow bi_size */
-       max_write_zeroes_sectors = bdev_write_zeroes_sectors(bdev);
+       /* Ensure that max_sectors doesn't overflow bi_size */
+       max_sectors = bdev_write_zeroes_sectors(bdev);
 
-       if (max_write_zeroes_sectors == 0)
+       if (max_sectors == 0)
                return -EOPNOTSUPP;
 
        while (nr_sects) {
+               unsigned int len = min_t(sector_t, nr_sects, max_sectors);
+
                bio = blk_next_bio(bio, bdev, 0, REQ_OP_WRITE_ZEROES, gfp_mask);
                bio->bi_iter.bi_sector = sector;
                if (flags & BLKDEV_ZERO_NOUNMAP)
                        bio->bi_opf |= REQ_NOUNMAP;
 
-               if (nr_sects > max_write_zeroes_sectors) {
-                       bio->bi_iter.bi_size = max_write_zeroes_sectors << 9;
-                       nr_sects -= max_write_zeroes_sectors;
-                       sector += max_write_zeroes_sectors;
-               } else {
-                       bio->bi_iter.bi_size = nr_sects << 9;
-                       nr_sects = 0;
-               }
+               bio->bi_iter.bi_size = len << SECTOR_SHIFT;
+               nr_sects -= len;
+               sector += len;
                cond_resched();
+               if (fatal_signal_pending(current)) {
+                       await_bio_chain(bio);
+                       return -EINTR;
+               }
        }
 
        *biop = bio;
@@ -190,6 +215,10 @@ static int __blkdev_issue_zero_pages(struct block_device *bdev,
                                break;
                }
                cond_resched();
+               if (fatal_signal_pending(current)) {
+                       await_bio_chain(bio);
+                       return -EINTR;
+               }
        }
 
        *biop = bio;
@@ -280,7 +309,7 @@ retry:
                bio_put(bio);
        }
        blk_finish_plug(&plug);
-       if (ret && try_write_zeroes) {
+       if (ret && ret != -EINTR && try_write_zeroes) {
                if (!(flags & BLKDEV_ZERO_NOFALLBACK)) {
                        try_write_zeroes = false;
                        goto retry;
@@ -322,7 +351,7 @@ int blkdev_issue_secure_erase(struct block_device *bdev, sector_t sector,
                return -EPERM;
 
        blk_start_plug(&plug);
-       for (;;) {
+       while (nr_sects) {
                unsigned int len = min_t(sector_t, nr_sects, max_sectors);
 
                bio = blk_next_bio(bio, bdev, 0, REQ_OP_SECURE_ERASE, gfp);
@@ -331,12 +360,17 @@ int blkdev_issue_secure_erase(struct block_device *bdev, sector_t sector,
 
                sector += len;
                nr_sects -= len;
-               if (!nr_sects) {
-                       ret = submit_bio_wait(bio);
-                       bio_put(bio);
+               cond_resched();
+               if (fatal_signal_pending(current)) {
+                       await_bio_chain(bio);
+                       ret = -EINTR;
+                       bio = NULL;
                        break;
                }
-               cond_resched();
+       }
+       if (bio) {
+               ret = submit_bio_wait(bio);
+               bio_put(bio);
        }
        blk_finish_plug(&plug);
 
index 2d470cf2173e29c540161401bd566942f049f27c..2a06fd33039da6ad1cbb2b6d212c8662184788e0 100644 (file)
@@ -810,6 +810,10 @@ static struct request *attempt_merge(struct request_queue *q,
        if (rq_data_dir(req) != rq_data_dir(next))
                return NULL;
 
+       /* Don't merge requests with different write hints. */
+       if (req->write_hint != next->write_hint)
+               return NULL;
+
        if (req->ioprio != next->ioprio)
                return NULL;
 
@@ -937,6 +941,10 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
        if (!bio_crypt_rq_ctx_compatible(rq, bio))
                return false;
 
+       /* Don't merge requests with different write hints. */
+       if (rq->write_hint != bio->bi_write_hint)
+               return false;
+
        if (rq->ioprio != bio_prio(bio))
                return false;
 
index 2dc01551e27c7d1e50266e554fe4bb6d378a1482..555ada922cf06021124eb3170983fc308e8d2a38 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/llist.h>
 #include <linux/cpu.h>
 #include <linux/cache.h>
-#include <linux/sched/sysctl.h>
 #include <linux/sched/topology.h>
 #include <linux/sched/signal.h>
 #include <linux/delay.h>
@@ -322,7 +321,7 @@ void blk_rq_init(struct request_queue *q, struct request *rq)
        RB_CLEAR_NODE(&rq->rb_node);
        rq->tag = BLK_MQ_NO_TAG;
        rq->internal_tag = BLK_MQ_NO_TAG;
-       rq->start_time_ns = ktime_get_ns();
+       rq->start_time_ns = blk_time_get_ns();
        rq->part = NULL;
        blk_crypto_rq_set_defaults(rq);
 }
@@ -332,7 +331,7 @@ EXPORT_SYMBOL(blk_rq_init);
 static inline void blk_mq_rq_time_init(struct request *rq, u64 alloc_time_ns)
 {
        if (blk_mq_need_time_stamp(rq))
-               rq->start_time_ns = ktime_get_ns();
+               rq->start_time_ns = blk_time_get_ns();
        else
                rq->start_time_ns = 0;
 
@@ -443,7 +442,7 @@ static struct request *__blk_mq_alloc_requests(struct blk_mq_alloc_data *data)
 
        /* alloc_time includes depth and tag waits */
        if (blk_queue_rq_alloc_time(q))
-               alloc_time_ns = ktime_get_ns();
+               alloc_time_ns = blk_time_get_ns();
 
        if (data->cmd_flags & REQ_NOWAIT)
                data->flags |= BLK_MQ_REQ_NOWAIT;
@@ -628,7 +627,7 @@ struct request *blk_mq_alloc_request_hctx(struct request_queue *q,
 
        /* alloc_time includes depth and tag waits */
        if (blk_queue_rq_alloc_time(q))
-               alloc_time_ns = ktime_get_ns();
+               alloc_time_ns = blk_time_get_ns();
 
        /*
         * If the tag allocator sleeps we could get an allocation for a
@@ -1041,7 +1040,7 @@ static inline void __blk_mq_end_request_acct(struct request *rq, u64 now)
 inline void __blk_mq_end_request(struct request *rq, blk_status_t error)
 {
        if (blk_mq_need_time_stamp(rq))
-               __blk_mq_end_request_acct(rq, ktime_get_ns());
+               __blk_mq_end_request_acct(rq, blk_time_get_ns());
 
        blk_mq_finish_request(rq);
 
@@ -1084,7 +1083,7 @@ void blk_mq_end_request_batch(struct io_comp_batch *iob)
        u64 now = 0;
 
        if (iob->need_ts)
-               now = ktime_get_ns();
+               now = blk_time_get_ns();
 
        while ((rq = rq_list_pop(&iob->req_list)) != NULL) {
                prefetch(rq->bio);
@@ -1167,10 +1166,11 @@ static inline bool blk_mq_complete_need_ipi(struct request *rq)
        if (force_irqthreads())
                return false;
 
-       /* same CPU or cache domain?  Complete locally */
+       /* same CPU or cache domain and capacity?  Complete locally */
        if (cpu == rq->mq_ctx->cpu ||
            (!test_bit(QUEUE_FLAG_SAME_FORCE, &rq->q->queue_flags) &&
-            cpus_share_cache(cpu, rq->mq_ctx->cpu)))
+            cpus_share_cache(cpu, rq->mq_ctx->cpu) &&
+            cpus_equal_capacity(cpu, rq->mq_ctx->cpu)))
                return false;
 
        /* don't try to IPI to an offline CPU */
@@ -1254,7 +1254,7 @@ void blk_mq_start_request(struct request *rq)
 
        if (test_bit(QUEUE_FLAG_STATS, &q->queue_flags) &&
            !blk_rq_is_passthrough(rq)) {
-               rq->io_start_time_ns = ktime_get_ns();
+               rq->io_start_time_ns = blk_time_get_ns();
                rq->stats_sectors = blk_rq_sectors(rq);
                rq->rq_flags |= RQF_STATS;
                rq_qos_issue(q, rq);
@@ -1409,22 +1409,10 @@ blk_status_t blk_execute_rq(struct request *rq, bool at_head)
        blk_mq_insert_request(rq, at_head ? BLK_MQ_INSERT_AT_HEAD : 0);
        blk_mq_run_hw_queue(hctx, false);
 
-       if (blk_rq_is_poll(rq)) {
+       if (blk_rq_is_poll(rq))
                blk_rq_poll_completion(rq, &wait.done);
-       } else {
-               /*
-                * Prevent hang_check timer from firing at us during very long
-                * I/O
-                */
-               unsigned long hang_check = sysctl_hung_task_timeout_secs;
-
-               if (hang_check)
-                       while (!wait_for_completion_io_timeout(&wait.done,
-                                       hang_check * (HZ/2)))
-                               ;
-               else
-                       wait_for_completion_io(&wait.done);
-       }
+       else
+               blk_wait_io(&wait.done);
 
        return wait.ret;
 }
@@ -2584,6 +2572,7 @@ static void blk_mq_bio_to_request(struct request *rq, struct bio *bio,
                rq->cmd_flags |= REQ_FAILFAST_MASK;
 
        rq->__sector = bio->bi_iter.bi_sector;
+       rq->write_hint = bio->bi_write_hint;
        blk_rq_bio_prep(rq, bio, nr_segs);
 
        /* This can't fail, since GFP_NOIO includes __GFP_DIRECT_RECLAIM. */
@@ -2891,9 +2880,6 @@ static struct request *blk_mq_get_new_requests(struct request_queue *q,
        };
        struct request *rq;
 
-       if (blk_mq_attempt_bio_merge(q, bio, nsegs))
-               return NULL;
-
        rq_qos_throttle(q, bio);
 
        if (plug) {
@@ -2912,22 +2898,31 @@ static struct request *blk_mq_get_new_requests(struct request_queue *q,
 }
 
 /*
- * Check if we can use the passed on request for submitting the passed in bio,
- * and remove it from the request list if it can be used.
+ * Check if there is a suitable cached request and return it.
  */
-static bool blk_mq_use_cached_rq(struct request *rq, struct blk_plug *plug,
-               struct bio *bio)
+static struct request *blk_mq_peek_cached_request(struct blk_plug *plug,
+               struct request_queue *q, blk_opf_t opf)
 {
-       enum hctx_type type = blk_mq_get_hctx_type(bio->bi_opf);
-       enum hctx_type hctx_type = rq->mq_hctx->type;
+       enum hctx_type type = blk_mq_get_hctx_type(opf);
+       struct request *rq;
 
-       WARN_ON_ONCE(rq_list_peek(&plug->cached_rq) != rq);
+       if (!plug)
+               return NULL;
+       rq = rq_list_peek(&plug->cached_rq);
+       if (!rq || rq->q != q)
+               return NULL;
+       if (type != rq->mq_hctx->type &&
+           (type != HCTX_TYPE_READ || rq->mq_hctx->type != HCTX_TYPE_DEFAULT))
+               return NULL;
+       if (op_is_flush(rq->cmd_flags) != op_is_flush(opf))
+               return NULL;
+       return rq;
+}
 
-       if (type != hctx_type &&
-           !(type == HCTX_TYPE_READ && hctx_type == HCTX_TYPE_DEFAULT))
-               return false;
-       if (op_is_flush(rq->cmd_flags) != op_is_flush(bio->bi_opf))
-               return false;
+static void blk_mq_use_cached_rq(struct request *rq, struct blk_plug *plug,
+               struct bio *bio)
+{
+       WARN_ON_ONCE(rq_list_peek(&plug->cached_rq) != rq);
 
        /*
         * If any qos ->throttle() end up blocking, we will have flushed the
@@ -2940,7 +2935,6 @@ static bool blk_mq_use_cached_rq(struct request *rq, struct blk_plug *plug,
        blk_mq_rq_time_init(rq, 0);
        rq->cmd_flags = bio->bi_opf;
        INIT_LIST_HEAD(&rq->queuelist);
-       return true;
 }
 
 /**
@@ -2962,50 +2956,43 @@ void blk_mq_submit_bio(struct bio *bio)
        struct blk_plug *plug = blk_mq_plug(bio);
        const int is_sync = op_is_sync(bio->bi_opf);
        struct blk_mq_hw_ctx *hctx;
-       struct request *rq = NULL;
        unsigned int nr_segs = 1;
+       struct request *rq;
        blk_status_t ret;
 
        bio = blk_queue_bounce(bio, q);
 
-       if (plug) {
-               rq = rq_list_peek(&plug->cached_rq);
-               if (rq && rq->q != q)
-                       rq = NULL;
-       }
-       if (rq) {
-               if (unlikely(bio_may_exceed_limits(bio, &q->limits))) {
-                       bio = __bio_split_to_limits(bio, &q->limits, &nr_segs);
-                       if (!bio)
-                               return;
-               }
-               if (!bio_integrity_prep(bio))
-                       return;
-               if (blk_mq_attempt_bio_merge(q, bio, nr_segs))
-                       return;
-               if (blk_mq_use_cached_rq(rq, plug, bio))
-                       goto done;
-               percpu_ref_get(&q->q_usage_counter);
-       } else {
+       /*
+        * If the plug has a cached request for this queue, try use it.
+        *
+        * The cached request already holds a q_usage_counter reference and we
+        * don't have to acquire a new one if we use it.
+        */
+       rq = blk_mq_peek_cached_request(plug, q, bio->bi_opf);
+       if (!rq) {
                if (unlikely(bio_queue_enter(bio)))
                        return;
-               if (unlikely(bio_may_exceed_limits(bio, &q->limits))) {
-                       bio = __bio_split_to_limits(bio, &q->limits, &nr_segs);
-                       if (!bio)
-                               goto fail;
-               }
-               if (!bio_integrity_prep(bio))
-                       goto fail;
        }
 
-       rq = blk_mq_get_new_requests(q, plug, bio, nr_segs);
-       if (unlikely(!rq)) {
-fail:
-               blk_queue_exit(q);
-               return;
+       if (unlikely(bio_may_exceed_limits(bio, &q->limits))) {
+               bio = __bio_split_to_limits(bio, &q->limits, &nr_segs);
+               if (!bio)
+                       goto queue_exit;
+       }
+       if (!bio_integrity_prep(bio))
+               goto queue_exit;
+
+       if (blk_mq_attempt_bio_merge(q, bio, nr_segs))
+               goto queue_exit;
+
+       if (!rq) {
+               rq = blk_mq_get_new_requests(q, plug, bio, nr_segs);
+               if (unlikely(!rq))
+                       goto queue_exit;
+       } else {
+               blk_mq_use_cached_rq(rq, plug, bio);
        }
 
-done:
        trace_block_getrq(bio);
 
        rq_qos_track(q, rq, bio);
@@ -3036,6 +3023,15 @@ done:
        } else {
                blk_mq_run_dispatch_ops(q, blk_mq_try_issue_directly(hctx, rq));
        }
+       return;
+
+queue_exit:
+       /*
+        * Don't drop the queue reference if we were trying to use a cached
+        * request and thus didn't acquire one.
+        */
+       if (!rq)
+               blk_queue_exit(q);
 }
 
 #ifdef CONFIG_BLK_MQ_STACKING
@@ -3097,7 +3093,7 @@ blk_status_t blk_insert_cloned_request(struct request *rq)
        blk_mq_run_dispatch_ops(q,
                        ret = blk_mq_request_issue_directly(rq, true));
        if (ret)
-               blk_account_io_done(rq, ktime_get_ns());
+               blk_account_io_done(rq, blk_time_get_ns());
        return ret;
 }
 EXPORT_SYMBOL_GPL(blk_insert_cloned_request);
@@ -3175,6 +3171,7 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
        }
        rq->nr_phys_segments = rq_src->nr_phys_segments;
        rq->ioprio = rq_src->ioprio;
+       rq->write_hint = rq_src->write_hint;
 
        if (rq->bio && blk_crypto_rq_bio_prep(rq, rq->bio, gfp_mask) < 0)
                goto free_and_out;
@@ -4076,15 +4073,16 @@ void blk_mq_release(struct request_queue *q)
        blk_mq_sysfs_deinit(q);
 }
 
-static struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set,
-               void *queuedata)
+struct request_queue *blk_mq_alloc_queue(struct blk_mq_tag_set *set,
+               struct queue_limits *lim, void *queuedata)
 {
+       struct queue_limits default_lim = { };
        struct request_queue *q;
        int ret;
 
-       q = blk_alloc_queue(set->numa_node);
-       if (!q)
-               return ERR_PTR(-ENOMEM);
+       q = blk_alloc_queue(lim ? lim : &default_lim, set->numa_node);
+       if (IS_ERR(q))
+               return q;
        q->queuedata = queuedata;
        ret = blk_mq_init_allocated_queue(set, q);
        if (ret) {
@@ -4093,20 +4091,15 @@ static struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set,
        }
        return q;
 }
-
-struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
-{
-       return blk_mq_init_queue_data(set, NULL);
-}
-EXPORT_SYMBOL(blk_mq_init_queue);
+EXPORT_SYMBOL(blk_mq_alloc_queue);
 
 /**
  * blk_mq_destroy_queue - shutdown a request queue
  * @q: request queue to shutdown
  *
- * This shuts down a request queue allocated by blk_mq_init_queue(). All future
+ * This shuts down a request queue allocated by blk_mq_alloc_queue(). All future
  * requests will be failed with -ENODEV. The caller is responsible for dropping
- * the reference from blk_mq_init_queue() by calling blk_put_queue().
+ * the reference from blk_mq_alloc_queue() by calling blk_put_queue().
  *
  * Context: can sleep
  */
@@ -4127,13 +4120,14 @@ void blk_mq_destroy_queue(struct request_queue *q)
 }
 EXPORT_SYMBOL(blk_mq_destroy_queue);
 
-struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set, void *queuedata,
+struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set,
+               struct queue_limits *lim, void *queuedata,
                struct lock_class_key *lkclass)
 {
        struct request_queue *q;
        struct gendisk *disk;
 
-       q = blk_mq_init_queue_data(set, queuedata);
+       q = blk_mq_alloc_queue(set, lim, queuedata);
        if (IS_ERR(q))
                return ERR_CAST(q);
 
@@ -4387,7 +4381,7 @@ static void blk_mq_update_queue_map(struct blk_mq_tag_set *set)
        if (set->nr_maps == 1)
                set->map[HCTX_TYPE_DEFAULT].nr_queues = set->nr_hw_queues;
 
-       if (set->ops->map_queues && !is_kdump_kernel()) {
+       if (set->ops->map_queues) {
                int i;
 
                /*
@@ -4486,14 +4480,12 @@ int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
 
        /*
         * If a crashdump is active, then we are potentially in a very
-        * memory constrained environment. Limit us to 1 queue and
-        * 64 tags to prevent using too much memory.
+        * memory constrained environment. Limit us to  64 tags to prevent
+        * using too much memory.
         */
-       if (is_kdump_kernel()) {
-               set->nr_hw_queues = 1;
-               set->nr_maps = 1;
+       if (is_kdump_kernel())
                set->queue_depth = min(64U, set->queue_depth);
-       }
+
        /*
         * There is no use for more h/w queues than cpus if we just have
         * a single map
@@ -4523,7 +4515,7 @@ int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
                                                  GFP_KERNEL, set->numa_node);
                if (!set->map[i].mq_map)
                        goto out_free_mq_map;
-               set->map[i].nr_queues = is_kdump_kernel() ? 1 : set->nr_hw_queues;
+               set->map[i].nr_queues = set->nr_hw_queues;
        }
 
        blk_mq_update_queue_map(set);
index 06ea91e51b8b2e554e5ead222abf3ad1b3ded4ef..e160d56e8edaa19f2e9e72dacc2552fcc652244a 100644 (file)
@@ -25,53 +25,22 @@ void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
 }
 EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
 
-/**
- * blk_set_default_limits - reset limits to default values
- * @lim:  the queue_limits structure to reset
- *
- * Description:
- *   Returns a queue_limit struct to its default state.
- */
-void blk_set_default_limits(struct queue_limits *lim)
-{
-       lim->max_segments = BLK_MAX_SEGMENTS;
-       lim->max_discard_segments = 1;
-       lim->max_integrity_segments = 0;
-       lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
-       lim->virt_boundary_mask = 0;
-       lim->max_segment_size = BLK_MAX_SEGMENT_SIZE;
-       lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS;
-       lim->max_user_sectors = lim->max_dev_sectors = 0;
-       lim->chunk_sectors = 0;
-       lim->max_write_zeroes_sectors = 0;
-       lim->max_zone_append_sectors = 0;
-       lim->max_discard_sectors = 0;
-       lim->max_hw_discard_sectors = 0;
-       lim->max_secure_erase_sectors = 0;
-       lim->discard_granularity = 512;
-       lim->discard_alignment = 0;
-       lim->discard_misaligned = 0;
-       lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
-       lim->bounce = BLK_BOUNCE_NONE;
-       lim->alignment_offset = 0;
-       lim->io_opt = 0;
-       lim->misaligned = 0;
-       lim->zoned = false;
-       lim->zone_write_granularity = 0;
-       lim->dma_alignment = 511;
-}
-
 /**
  * blk_set_stacking_limits - set default limits for stacking devices
  * @lim:  the queue_limits structure to reset
  *
- * Description:
- *   Returns a queue_limit struct to its default state. Should be used
- *   by stacking drivers like DM that have no internal limits.
+ * Prepare queue limits for applying limits from underlying devices using
+ * blk_stack_limits().
  */
 void blk_set_stacking_limits(struct queue_limits *lim)
 {
-       blk_set_default_limits(lim);
+       memset(lim, 0, sizeof(*lim));
+       lim->logical_block_size = SECTOR_SIZE;
+       lim->physical_block_size = SECTOR_SIZE;
+       lim->io_min = SECTOR_SIZE;
+       lim->discard_granularity = SECTOR_SIZE;
+       lim->dma_alignment = SECTOR_SIZE - 1;
+       lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
 
        /* Inherit limits from component devices */
        lim->max_segments = USHRT_MAX;
@@ -82,9 +51,239 @@ void blk_set_stacking_limits(struct queue_limits *lim)
        lim->max_dev_sectors = UINT_MAX;
        lim->max_write_zeroes_sectors = UINT_MAX;
        lim->max_zone_append_sectors = UINT_MAX;
+       lim->max_user_discard_sectors = UINT_MAX;
 }
 EXPORT_SYMBOL(blk_set_stacking_limits);
 
+static void blk_apply_bdi_limits(struct backing_dev_info *bdi,
+               struct queue_limits *lim)
+{
+       /*
+        * For read-ahead of large files to be effective, we need to read ahead
+        * at least twice the optimal I/O size.
+        */
+       bdi->ra_pages = max(lim->io_opt * 2 / PAGE_SIZE, VM_READAHEAD_PAGES);
+       bdi->io_pages = lim->max_sectors >> PAGE_SECTORS_SHIFT;
+}
+
+static int blk_validate_zoned_limits(struct queue_limits *lim)
+{
+       if (!lim->zoned) {
+               if (WARN_ON_ONCE(lim->max_open_zones) ||
+                   WARN_ON_ONCE(lim->max_active_zones) ||
+                   WARN_ON_ONCE(lim->zone_write_granularity) ||
+                   WARN_ON_ONCE(lim->max_zone_append_sectors))
+                       return -EINVAL;
+               return 0;
+       }
+
+       if (WARN_ON_ONCE(!IS_ENABLED(CONFIG_BLK_DEV_ZONED)))
+               return -EINVAL;
+
+       if (lim->zone_write_granularity < lim->logical_block_size)
+               lim->zone_write_granularity = lim->logical_block_size;
+
+       if (lim->max_zone_append_sectors) {
+               /*
+                * The Zone Append size is limited by the maximum I/O size
+                * and the zone size given that it can't span zones.
+                */
+               lim->max_zone_append_sectors =
+                       min3(lim->max_hw_sectors,
+                            lim->max_zone_append_sectors,
+                            lim->chunk_sectors);
+       }
+
+       return 0;
+}
+
+/*
+ * Check that the limits in lim are valid, initialize defaults for unset
+ * values, and cap values based on others where needed.
+ */
+static int blk_validate_limits(struct queue_limits *lim)
+{
+       unsigned int max_hw_sectors;
+
+       /*
+        * Unless otherwise specified, default to 512 byte logical blocks and a
+        * physical block size equal to the logical block size.
+        */
+       if (!lim->logical_block_size)
+               lim->logical_block_size = SECTOR_SIZE;
+       if (lim->physical_block_size < lim->logical_block_size)
+               lim->physical_block_size = lim->logical_block_size;
+
+       /*
+        * The minimum I/O size defaults to the physical block size unless
+        * explicitly overridden.
+        */
+       if (lim->io_min < lim->physical_block_size)
+               lim->io_min = lim->physical_block_size;
+
+       /*
+        * max_hw_sectors has a somewhat weird default for historical reason,
+        * but driver really should set their own instead of relying on this
+        * value.
+        *
+        * The block layer relies on the fact that every driver can
+        * handle at lest a page worth of data per I/O, and needs the value
+        * aligned to the logical block size.
+        */
+       if (!lim->max_hw_sectors)
+               lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS;
+       if (WARN_ON_ONCE(lim->max_hw_sectors < PAGE_SECTORS))
+               return -EINVAL;
+       lim->max_hw_sectors = round_down(lim->max_hw_sectors,
+                       lim->logical_block_size >> SECTOR_SHIFT);
+
+       /*
+        * The actual max_sectors value is a complex beast and also takes the
+        * max_dev_sectors value (set by SCSI ULPs) and a user configurable
+        * value into account.  The ->max_sectors value is always calculated
+        * from these, so directly setting it won't have any effect.
+        */
+       max_hw_sectors = min_not_zero(lim->max_hw_sectors,
+                               lim->max_dev_sectors);
+       if (lim->max_user_sectors) {
+               if (lim->max_user_sectors > max_hw_sectors ||
+                   lim->max_user_sectors < PAGE_SIZE / SECTOR_SIZE)
+                       return -EINVAL;
+               lim->max_sectors = min(max_hw_sectors, lim->max_user_sectors);
+       } else {
+               lim->max_sectors = min(max_hw_sectors, BLK_DEF_MAX_SECTORS_CAP);
+       }
+       lim->max_sectors = round_down(lim->max_sectors,
+                       lim->logical_block_size >> SECTOR_SHIFT);
+
+       /*
+        * Random default for the maximum number of segments.  Driver should not
+        * rely on this and set their own.
+        */
+       if (!lim->max_segments)
+               lim->max_segments = BLK_MAX_SEGMENTS;
+
+       lim->max_discard_sectors =
+               min(lim->max_hw_discard_sectors, lim->max_user_discard_sectors);
+
+       if (!lim->max_discard_segments)
+               lim->max_discard_segments = 1;
+
+       if (lim->discard_granularity < lim->physical_block_size)
+               lim->discard_granularity = lim->physical_block_size;
+
+       /*
+        * By default there is no limit on the segment boundary alignment,
+        * but if there is one it can't be smaller than the page size as
+        * that would break all the normal I/O patterns.
+        */
+       if (!lim->seg_boundary_mask)
+               lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
+       if (WARN_ON_ONCE(lim->seg_boundary_mask < PAGE_SIZE - 1))
+               return -EINVAL;
+
+       /*
+        * Devices that require a virtual boundary do not support scatter/gather
+        * I/O natively, but instead require a descriptor list entry for each
+        * page (which might not be identical to the Linux PAGE_SIZE).  Because
+        * of that they are not limited by our notion of "segment size".
+        */
+       if (lim->virt_boundary_mask) {
+               if (WARN_ON_ONCE(lim->max_segment_size &&
+                                lim->max_segment_size != UINT_MAX))
+                       return -EINVAL;
+               lim->max_segment_size = UINT_MAX;
+       } else {
+               /*
+                * The maximum segment size has an odd historic 64k default that
+                * drivers probably should override.  Just like the I/O size we
+                * require drivers to at least handle a full page per segment.
+                */
+               if (!lim->max_segment_size)
+                       lim->max_segment_size = BLK_MAX_SEGMENT_SIZE;
+               if (WARN_ON_ONCE(lim->max_segment_size < PAGE_SIZE))
+                       return -EINVAL;
+       }
+
+       /*
+        * We require drivers to at least do logical block aligned I/O, but
+        * historically could not check for that due to the separate calls
+        * to set the limits.  Once the transition is finished the check
+        * below should be narrowed down to check the logical block size.
+        */
+       if (!lim->dma_alignment)
+               lim->dma_alignment = SECTOR_SIZE - 1;
+       if (WARN_ON_ONCE(lim->dma_alignment > PAGE_SIZE))
+               return -EINVAL;
+
+       if (lim->alignment_offset) {
+               lim->alignment_offset &= (lim->physical_block_size - 1);
+               lim->misaligned = 0;
+       }
+
+       return blk_validate_zoned_limits(lim);
+}
+
+/*
+ * Set the default limits for a newly allocated queue.  @lim contains the
+ * initial limits set by the driver, which could be no limit in which case
+ * all fields are cleared to zero.
+ */
+int blk_set_default_limits(struct queue_limits *lim)
+{
+       /*
+        * Most defaults are set by capping the bounds in blk_validate_limits,
+        * but max_user_discard_sectors is special and needs an explicit
+        * initialization to the max value here.
+        */
+       lim->max_user_discard_sectors = UINT_MAX;
+       return blk_validate_limits(lim);
+}
+
+/**
+ * queue_limits_commit_update - commit an atomic update of queue limits
+ * @q:         queue to update
+ * @lim:       limits to apply
+ *
+ * Apply the limits in @lim that were obtained from queue_limits_start_update()
+ * and updated by the caller to @q.
+ *
+ * Returns 0 if successful, else a negative error code.
+ */
+int queue_limits_commit_update(struct request_queue *q,
+               struct queue_limits *lim)
+       __releases(q->limits_lock)
+{
+       int error = blk_validate_limits(lim);
+
+       if (!error) {
+               q->limits = *lim;
+               if (q->disk)
+                       blk_apply_bdi_limits(q->disk->bdi, lim);
+       }
+       mutex_unlock(&q->limits_lock);
+       return error;
+}
+EXPORT_SYMBOL_GPL(queue_limits_commit_update);
+
+/**
+ * queue_limits_commit_set - apply queue limits to queue
+ * @q:         queue to update
+ * @lim:       limits to apply
+ *
+ * Apply the limits in @lim that were freshly initialized to @q.
+ * To update existing limits use queue_limits_start_update() and
+ * queue_limits_commit_update() instead.
+ *
+ * Returns 0 if successful, else a negative error code.
+ */
+int queue_limits_set(struct request_queue *q, struct queue_limits *lim)
+{
+       mutex_lock(&q->limits_lock);
+       return queue_limits_commit_update(q, lim);
+}
+EXPORT_SYMBOL_GPL(queue_limits_set);
+
 /**
  * blk_queue_bounce_limit - set bounce buffer limit for queue
  * @q: the request queue for the device
@@ -177,8 +376,11 @@ EXPORT_SYMBOL(blk_queue_chunk_sectors);
 void blk_queue_max_discard_sectors(struct request_queue *q,
                unsigned int max_discard_sectors)
 {
-       q->limits.max_hw_discard_sectors = max_discard_sectors;
-       q->limits.max_discard_sectors = max_discard_sectors;
+       struct queue_limits *lim = &q->limits;
+
+       lim->max_hw_discard_sectors = max_discard_sectors;
+       lim->max_discard_sectors =
+               min(max_discard_sectors, lim->max_user_discard_sectors);
 }
 EXPORT_SYMBOL(blk_queue_max_discard_sectors);
 
@@ -393,15 +595,7 @@ EXPORT_SYMBOL(blk_queue_alignment_offset);
 
 void disk_update_readahead(struct gendisk *disk)
 {
-       struct request_queue *q = disk->queue;
-
-       /*
-        * For read-ahead of large files to be effective, we need to read ahead
-        * at least twice the optimal I/O size.
-        */
-       disk->bdi->ra_pages =
-               max(queue_io_opt(q) * 2 / PAGE_SIZE, VM_READAHEAD_PAGES);
-       disk->bdi->io_pages = queue_max_sectors(q) >> (PAGE_SHIFT - 9);
+       blk_apply_bdi_limits(disk->bdi, &disk->queue->limits);
 }
 EXPORT_SYMBOL_GPL(disk_update_readahead);
 
@@ -689,33 +883,38 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
        t->zone_write_granularity = max(t->zone_write_granularity,
                                        b->zone_write_granularity);
        t->zoned = max(t->zoned, b->zoned);
+       if (!t->zoned) {
+               t->zone_write_granularity = 0;
+               t->max_zone_append_sectors = 0;
+       }
        return ret;
 }
 EXPORT_SYMBOL(blk_stack_limits);
 
 /**
- * disk_stack_limits - adjust queue limits for stacked drivers
- * @disk:  MD/DM gendisk (top)
+ * queue_limits_stack_bdev - adjust queue_limits for stacked devices
+ * @t: the stacking driver limits (top device)
  * @bdev:  the underlying block device (bottom)
  * @offset:  offset to beginning of data within component device
+ * @pfx: prefix to use for warnings logged
  *
  * Description:
- *    Merges the limits for a top level gendisk and a bottom level
- *    block_device.
+ *    This function is used by stacking drivers like MD and DM to ensure
+ *    that all component devices have compatible block sizes and
+ *    alignments.  The stacking driver must provide a queue_limits
+ *    struct (top) and then iteratively call the stacking function for
+ *    all component (bottom) devices.  The stacking function will
+ *    attempt to combine the values and ensure proper alignment.
  */
-void disk_stack_limits(struct gendisk *disk, struct block_device *bdev,
-                      sector_t offset)
+void queue_limits_stack_bdev(struct queue_limits *t, struct block_device *bdev,
+               sector_t offset, const char *pfx)
 {
-       struct request_queue *t = disk->queue;
-
-       if (blk_stack_limits(&t->limits, &bdev_get_queue(bdev)->limits,
-                       get_start_sect(bdev) + (offset >> 9)) < 0)
+       if (blk_stack_limits(t, &bdev_get_queue(bdev)->limits,
+                       get_start_sect(bdev) + offset))
                pr_notice("%s: Warning: Device %pg is misaligned\n",
-                       disk->disk_name, bdev);
-
-       disk_update_readahead(disk);
+                       pfx, bdev);
 }
-EXPORT_SYMBOL(disk_stack_limits);
+EXPORT_SYMBOL_GPL(queue_limits_stack_bdev);
 
 /**
  * blk_queue_update_dma_pad - update pad mask
index 7ff76ae6c76a9531050af5e7a70c14af755eb403..e42c263e53fb995cd7c0b0d6d3de021cae05aae1 100644 (file)
@@ -27,7 +27,7 @@ void blk_rq_stat_init(struct blk_rq_stat *stat)
 /* src is a per-cpu stat, mean isn't initialized */
 void blk_rq_stat_sum(struct blk_rq_stat *dst, struct blk_rq_stat *src)
 {
-       if (!src->nr_samples)
+       if (dst->nr_samples + src->nr_samples <= dst->nr_samples)
                return;
 
        dst->min = min(dst->min, src->min);
index 6b2429cad81af1d9ea4c717a5885616d22b0f68b..8c8f69d8ba48ee7ca553f9a72cc90d5367291666 100644 (file)
@@ -174,23 +174,29 @@ static ssize_t queue_discard_max_show(struct request_queue *q, char *page)
 static ssize_t queue_discard_max_store(struct request_queue *q,
                                       const char *page, size_t count)
 {
-       unsigned long max_discard;
-       ssize_t ret = queue_var_store(&max_discard, page, count);
+       unsigned long max_discard_bytes;
+       struct queue_limits lim;
+       ssize_t ret;
+       int err;
 
+       ret = queue_var_store(&max_discard_bytes, page, count);
        if (ret < 0)
                return ret;
 
-       if (max_discard & (q->limits.discard_granularity - 1))
+       if (max_discard_bytes & (q->limits.discard_granularity - 1))
                return -EINVAL;
 
-       max_discard >>= 9;
-       if (max_discard > UINT_MAX)
+       if ((max_discard_bytes >> SECTOR_SHIFT) > UINT_MAX)
                return -EINVAL;
 
-       if (max_discard > q->limits.max_hw_discard_sectors)
-               max_discard = q->limits.max_hw_discard_sectors;
+       blk_mq_freeze_queue(q);
+       lim = queue_limits_start_update(q);
+       lim.max_user_discard_sectors = max_discard_bytes >> SECTOR_SHIFT;
+       err = queue_limits_commit_update(q, &lim);
+       blk_mq_unfreeze_queue(q);
 
-       q->limits.max_discard_sectors = max_discard;
+       if (err)
+               return err;
        return ret;
 }
 
@@ -226,35 +232,22 @@ static ssize_t queue_zone_append_max_show(struct request_queue *q, char *page)
 static ssize_t
 queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
 {
-       unsigned long var;
-       unsigned int max_sectors_kb,
-               max_hw_sectors_kb = queue_max_hw_sectors(q) >> 1,
-                       page_kb = 1 << (PAGE_SHIFT - 10);
-       ssize_t ret = queue_var_store(&var, page, count);
+       unsigned long max_sectors_kb;
+       struct queue_limits lim;
+       ssize_t ret;
+       int err;
 
+       ret = queue_var_store(&max_sectors_kb, page, count);
        if (ret < 0)
                return ret;
 
-       max_sectors_kb = (unsigned int)var;
-       max_hw_sectors_kb = min_not_zero(max_hw_sectors_kb,
-                                        q->limits.max_dev_sectors >> 1);
-       if (max_sectors_kb == 0) {
-               q->limits.max_user_sectors = 0;
-               max_sectors_kb = min(max_hw_sectors_kb,
-                                    BLK_DEF_MAX_SECTORS_CAP >> 1);
-       } else {
-               if (max_sectors_kb > max_hw_sectors_kb ||
-                   max_sectors_kb < page_kb)
-                       return -EINVAL;
-               q->limits.max_user_sectors = max_sectors_kb << 1;
-       }
-
-       spin_lock_irq(&q->queue_lock);
-       q->limits.max_sectors = max_sectors_kb << 1;
-       if (q->disk)
-               q->disk->bdi->io_pages = max_sectors_kb >> (PAGE_SHIFT - 10);
-       spin_unlock_irq(&q->queue_lock);
-
+       blk_mq_freeze_queue(q);
+       lim = queue_limits_start_update(q);
+       lim.max_user_sectors = max_sectors_kb << 1;
+       err = queue_limits_commit_update(q, &lim);
+       blk_mq_unfreeze_queue(q);
+       if (err)
+               return err;
        return ret;
 }
 
index 16f5766620a41043645756c51d441f4488af9edf..f4850a6f860bbac8aba17aba9d217d83ec12f6a7 100644 (file)
@@ -1098,7 +1098,7 @@ static int throtl_dispatch_tg(struct throtl_grp *tg)
        while ((bio = throtl_peek_queued(&sq->queued[READ])) &&
               tg_may_dispatch(tg, bio, NULL)) {
 
-               tg_dispatch_one_bio(tg, bio_data_dir(bio));
+               tg_dispatch_one_bio(tg, READ);
                nr_reads++;
 
                if (nr_reads >= max_nr_reads)
@@ -1108,7 +1108,7 @@ static int throtl_dispatch_tg(struct throtl_grp *tg)
        while ((bio = throtl_peek_queued(&sq->queued[WRITE])) &&
               tg_may_dispatch(tg, bio, NULL)) {
 
-               tg_dispatch_one_bio(tg, bio_data_dir(bio));
+               tg_dispatch_one_bio(tg, WRITE);
                nr_writes++;
 
                if (nr_writes >= max_nr_writes)
@@ -1815,7 +1815,7 @@ static bool throtl_tg_is_idle(struct throtl_grp *tg)
        time = min_t(unsigned long, MAX_IDLE_TIME, 4 * tg->idletime_threshold);
        ret = tg->latency_target == DFL_LATENCY_TARGET ||
              tg->idletime_threshold == DFL_IDLE_THRESHOLD ||
-             (ktime_get_ns() >> 10) - tg->last_finish_time > time ||
+             (blk_time_get_ns() >> 10) - tg->last_finish_time > time ||
              tg->avg_idletime > tg->idletime_threshold ||
              (tg->latency_target && tg->bio_cnt &&
                tg->bad_bio_cnt * 5 < tg->bio_cnt);
@@ -2060,7 +2060,7 @@ static void blk_throtl_update_idletime(struct throtl_grp *tg)
        if (last_finish_time == 0)
                return;
 
-       now = ktime_get_ns() >> 10;
+       now = blk_time_get_ns() >> 10;
        if (now <= last_finish_time ||
            last_finish_time == tg->checked_last_finish_time)
                return;
@@ -2327,7 +2327,7 @@ void blk_throtl_bio_endio(struct bio *bio)
        if (!tg->td->limit_valid[LIMIT_LOW])
                return;
 
-       finish_time_ns = ktime_get_ns();
+       finish_time_ns = blk_time_get_ns();
        tg->last_finish_time = finish_time_ns >> 10;
 
        start_time = bio_issue_time(&bio->bi_issue) >> 10;
index 0c0e270a82650d9a0c6977931cd8a833b467f520..64472134dd26df23eede4fcd493543e445c1230e 100644 (file)
@@ -29,6 +29,7 @@
 #include "blk-wbt.h"
 #include "blk-rq-qos.h"
 #include "elevator.h"
+#include "blk.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/wbt.h>
@@ -274,13 +275,12 @@ static inline bool stat_sample_valid(struct blk_rq_stat *stat)
 
 static u64 rwb_sync_issue_lat(struct rq_wb *rwb)
 {
-       u64 now, issue = READ_ONCE(rwb->sync_issue);
+       u64 issue = READ_ONCE(rwb->sync_issue);
 
        if (!issue || !rwb->sync_cookie)
                return 0;
 
-       now = ktime_to_ns(ktime_get());
-       return now - issue;
+       return blk_time_get_ns() - issue;
 }
 
 static inline unsigned int wbt_inflight(struct rq_wb *rwb)
index d343e5756a9c8048374edcce8000230eed10480b..da0f4b2a8fa09330bdc71bf545ed2dc688326392 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/rbtree.h>
 #include <linux/blkdev.h>
 #include <linux/blk-mq.h>
 #include <linux/mm.h>
@@ -177,8 +176,7 @@ static int blk_zone_need_reset_cb(struct blk_zone *zone, unsigned int idx,
        }
 }
 
-static int blkdev_zone_reset_all_emulated(struct block_device *bdev,
-                                         gfp_t gfp_mask)
+static int blkdev_zone_reset_all_emulated(struct block_device *bdev)
 {
        struct gendisk *disk = bdev->bd_disk;
        sector_t capacity = bdev_nr_sectors(bdev);
@@ -205,7 +203,7 @@ static int blkdev_zone_reset_all_emulated(struct block_device *bdev,
                }
 
                bio = blk_next_bio(bio, bdev, 0, REQ_OP_ZONE_RESET | REQ_SYNC,
-                                  gfp_mask);
+                                  GFP_KERNEL);
                bio->bi_iter.bi_sector = sector;
                sector += zone_sectors;
 
@@ -223,7 +221,7 @@ out_free_need_reset:
        return ret;
 }
 
-static int blkdev_zone_reset_all(struct block_device *bdev, gfp_t gfp_mask)
+static int blkdev_zone_reset_all(struct block_device *bdev)
 {
        struct bio bio;
 
@@ -238,7 +236,6 @@ static int blkdev_zone_reset_all(struct block_device *bdev, gfp_t gfp_mask)
  * @sector:    Start sector of the first zone to operate on
  * @nr_sectors:        Number of sectors, should be at least the length of one zone and
  *             must be zone size aligned.
- * @gfp_mask:  Memory allocation flags (for bio_alloc)
  *
  * Description:
  *    Perform the specified operation on the range of zones specified by
@@ -248,7 +245,7 @@ static int blkdev_zone_reset_all(struct block_device *bdev, gfp_t gfp_mask)
  *    or finish request.
  */
 int blkdev_zone_mgmt(struct block_device *bdev, enum req_op op,
-                    sector_t sector, sector_t nr_sectors, gfp_t gfp_mask)
+                    sector_t sector, sector_t nr_sectors)
 {
        struct request_queue *q = bdev_get_queue(bdev);
        sector_t zone_sectors = bdev_zone_sectors(bdev);
@@ -285,12 +282,12 @@ int blkdev_zone_mgmt(struct block_device *bdev, enum req_op op,
         */
        if (op == REQ_OP_ZONE_RESET && sector == 0 && nr_sectors == capacity) {
                if (!blk_queue_zone_resetall(q))
-                       return blkdev_zone_reset_all_emulated(bdev, gfp_mask);
-               return blkdev_zone_reset_all(bdev, gfp_mask);
+                       return blkdev_zone_reset_all_emulated(bdev);
+               return blkdev_zone_reset_all(bdev);
        }
 
        while (sector < end_sector) {
-               bio = blk_next_bio(bio, bdev, 0, op | REQ_SYNC, gfp_mask);
+               bio = blk_next_bio(bio, bdev, 0, op | REQ_SYNC, GFP_KERNEL);
                bio->bi_iter.bi_sector = sector;
                sector += zone_sectors;
 
@@ -419,8 +416,7 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode,
                return -ENOTTY;
        }
 
-       ret = blkdev_zone_mgmt(bdev, op, zrange.sector, zrange.nr_sectors,
-                              GFP_KERNEL);
+       ret = blkdev_zone_mgmt(bdev, op, zrange.sector, zrange.nr_sectors);
 
 fail:
        if (cmd == BLKRESETZONE)
index 1ef920f72e0f87172227778cbf1fa4b78cdea295..a19b7b42e6503cd5ca5e03aba41b894a891929b8 100644 (file)
@@ -4,6 +4,8 @@
 
 #include <linux/blk-crypto.h>
 #include <linux/memblock.h>    /* for max_pfn/max_low_pfn */
+#include <linux/sched/sysctl.h>
+#include <linux/timekeeping.h>
 #include <xen/xen.h>
 #include "blk-crypto-internal.h"
 
@@ -70,6 +72,18 @@ static inline int bio_queue_enter(struct bio *bio)
        return __bio_queue_enter(q, bio);
 }
 
+static inline void blk_wait_io(struct completion *done)
+{
+       /* Prevent hang_check timer from firing at us during very long I/O */
+       unsigned long timeout = sysctl_hung_task_timeout_secs * HZ / 2;
+
+       if (timeout)
+               while (!wait_for_completion_io_timeout(done, timeout))
+                       ;
+       else
+               wait_for_completion_io(done);
+}
+
 #define BIO_INLINE_VECS 4
 struct bio_vec *bvec_alloc(mempool_t *pool, unsigned short *nr_vecs,
                gfp_t gfp_mask);
@@ -329,7 +343,7 @@ void blk_rq_set_mixed_merge(struct request *rq);
 bool blk_rq_merge_ok(struct request *rq, struct bio *bio);
 enum elv_merge blk_try_merge(struct request *rq, struct bio *bio);
 
-void blk_set_default_limits(struct queue_limits *lim);
+int blk_set_default_limits(struct queue_limits *lim);
 int blk_dev_init(void);
 
 /*
@@ -447,7 +461,7 @@ static inline void bio_release_page(struct bio *bio, struct page *page)
                unpin_user_page(page);
 }
 
-struct request_queue *blk_alloc_queue(int node_id);
+struct request_queue *blk_alloc_queue(struct queue_limits *lim, int node_id);
 
 int disk_scan_partitions(struct gendisk *disk, blk_mode_t mode);
 
@@ -516,4 +530,75 @@ static inline int req_ref_read(struct request *req)
        return atomic_read(&req->ref);
 }
 
+static inline u64 blk_time_get_ns(void)
+{
+       struct blk_plug *plug = current->plug;
+
+       if (!plug)
+               return ktime_get_ns();
+
+       /*
+        * 0 could very well be a valid time, but rather than flag "this is
+        * a valid timestamp" separately, just accept that we'll do an extra
+        * ktime_get_ns() if we just happen to get 0 as the current time.
+        */
+       if (!plug->cur_ktime) {
+               plug->cur_ktime = ktime_get_ns();
+               current->flags |= PF_BLOCK_TS;
+       }
+       return plug->cur_ktime;
+}
+
+static inline ktime_t blk_time_get(void)
+{
+       return ns_to_ktime(blk_time_get_ns());
+}
+
+/*
+ * From most significant bit:
+ * 1 bit: reserved for other usage, see below
+ * 12 bits: original size of bio
+ * 51 bits: issue time of bio
+ */
+#define BIO_ISSUE_RES_BITS      1
+#define BIO_ISSUE_SIZE_BITS     12
+#define BIO_ISSUE_RES_SHIFT     (64 - BIO_ISSUE_RES_BITS)
+#define BIO_ISSUE_SIZE_SHIFT    (BIO_ISSUE_RES_SHIFT - BIO_ISSUE_SIZE_BITS)
+#define BIO_ISSUE_TIME_MASK     ((1ULL << BIO_ISSUE_SIZE_SHIFT) - 1)
+#define BIO_ISSUE_SIZE_MASK     \
+       (((1ULL << BIO_ISSUE_SIZE_BITS) - 1) << BIO_ISSUE_SIZE_SHIFT)
+#define BIO_ISSUE_RES_MASK      (~((1ULL << BIO_ISSUE_RES_SHIFT) - 1))
+
+/* Reserved bit for blk-throtl */
+#define BIO_ISSUE_THROTL_SKIP_LATENCY (1ULL << 63)
+
+static inline u64 __bio_issue_time(u64 time)
+{
+       return time & BIO_ISSUE_TIME_MASK;
+}
+
+static inline u64 bio_issue_time(struct bio_issue *issue)
+{
+       return __bio_issue_time(issue->value);
+}
+
+static inline sector_t bio_issue_size(struct bio_issue *issue)
+{
+       return ((issue->value & BIO_ISSUE_SIZE_MASK) >> BIO_ISSUE_SIZE_SHIFT);
+}
+
+static inline void bio_issue_init(struct bio_issue *issue,
+                                      sector_t size)
+{
+       size &= (1ULL << BIO_ISSUE_SIZE_BITS) - 1;
+       issue->value = ((issue->value & BIO_ISSUE_RES_MASK) |
+                       (blk_time_get_ns() & BIO_ISSUE_TIME_MASK) |
+                       ((u64)size << BIO_ISSUE_SIZE_SHIFT));
+}
+
+void bdev_release(struct file *bdev_file);
+int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder,
+             const struct blk_holder_ops *hops, struct file *bdev_file);
+int bdev_permission(dev_t dev, blk_mode_t mode, void *holder);
+
 #endif /* BLK_INTERNAL_H */
index 7cfcb242f9a112cc8352121c5b6f73ceb467d4c9..d6a5219f29dd53b5fa7aa379d69a71aa5a087ebc 100644 (file)
@@ -169,6 +169,7 @@ static struct bio *bounce_clone_bio(struct bio *bio_src)
        if (bio_flagged(bio_src, BIO_REMAPPED))
                bio_set_flag(bio, BIO_REMAPPED);
        bio->bi_ioprio          = bio_src->bi_ioprio;
+       bio->bi_write_hint      = bio_src->bi_write_hint;
        bio->bi_iter.bi_sector  = bio_src->bi_iter.bi_sector;
        bio->bi_iter.bi_size    = bio_src->bi_iter.bi_size;
 
index b3acdbdb6e7ea8f62c8d9f76d7ae83a4a35bf0e2..bcc7dee6abced61e33c55950774cfac418375b09 100644 (file)
@@ -383,7 +383,7 @@ struct request_queue *bsg_setup_queue(struct device *dev, const char *name,
        if (blk_mq_alloc_tag_set(set))
                goto out_tag_set;
 
-       q = blk_mq_init_queue(set);
+       q = blk_mq_alloc_queue(set, NULL, NULL);
        if (IS_ERR(q)) {
                ret = PTR_ERR(q);
                goto out_queue;
index 0cf8cf72cdfa108926ae8fc7f53bce05a3225058..679d9b752fe828eb64b67d17e7492469c71e35d3 100644 (file)
@@ -73,6 +73,7 @@ static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,
                bio_init(&bio, bdev, vecs, nr_pages, dio_bio_write_op(iocb));
        }
        bio.bi_iter.bi_sector = pos >> SECTOR_SHIFT;
+       bio.bi_write_hint = file_inode(iocb->ki_filp)->i_write_hint;
        bio.bi_ioprio = iocb->ki_ioprio;
 
        ret = bio_iov_iter_get_pages(&bio, iter);
@@ -203,6 +204,7 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
 
        for (;;) {
                bio->bi_iter.bi_sector = pos >> SECTOR_SHIFT;
+               bio->bi_write_hint = file_inode(iocb->ki_filp)->i_write_hint;
                bio->bi_private = dio;
                bio->bi_end_io = blkdev_bio_end_io;
                bio->bi_ioprio = iocb->ki_ioprio;
@@ -321,6 +323,7 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
        dio->flags = 0;
        dio->iocb = iocb;
        bio->bi_iter.bi_sector = pos >> SECTOR_SHIFT;
+       bio->bi_write_hint = file_inode(iocb->ki_filp)->i_write_hint;
        bio->bi_end_io = blkdev_bio_end_io_async;
        bio->bi_ioprio = iocb->ki_ioprio;
 
@@ -482,7 +485,7 @@ static void blkdev_readahead(struct readahead_control *rac)
 }
 
 static int blkdev_map_blocks(struct iomap_writepage_ctx *wpc,
-               struct inode *inode, loff_t offset)
+               struct inode *inode, loff_t offset, unsigned int len)
 {
        loff_t isize = i_size_read(inode);
 
@@ -569,18 +572,17 @@ static int blkdev_fsync(struct file *filp, loff_t start, loff_t end,
 blk_mode_t file_to_blk_mode(struct file *file)
 {
        blk_mode_t mode = 0;
-       struct bdev_handle *handle = file->private_data;
 
        if (file->f_mode & FMODE_READ)
                mode |= BLK_OPEN_READ;
        if (file->f_mode & FMODE_WRITE)
                mode |= BLK_OPEN_WRITE;
        /*
-        * do_dentry_open() clears O_EXCL from f_flags, use handle->mode to
-        * determine whether the open was exclusive for already open files.
+        * do_dentry_open() clears O_EXCL from f_flags, use file->private_data
+        * to determine whether the open was exclusive for already open files.
         */
-       if (handle)
-               mode |= handle->mode & BLK_OPEN_EXCL;
+       if (file->private_data)
+               mode |= BLK_OPEN_EXCL;
        else if (file->f_flags & O_EXCL)
                mode |= BLK_OPEN_EXCL;
        if (file->f_flags & O_NDELAY)
@@ -599,36 +601,31 @@ blk_mode_t file_to_blk_mode(struct file *file)
 
 static int blkdev_open(struct inode *inode, struct file *filp)
 {
-       struct bdev_handle *handle;
+       struct block_device *bdev;
        blk_mode_t mode;
-
-       /*
-        * Preserve backwards compatibility and allow large file access
-        * even if userspace doesn't ask for it explicitly. Some mkfs
-        * binary needs it. We might want to drop this workaround
-        * during an unstable branch.
-        */
-       filp->f_flags |= O_LARGEFILE;
-       filp->f_mode |= FMODE_BUF_RASYNC | FMODE_CAN_ODIRECT;
+       int ret;
 
        mode = file_to_blk_mode(filp);
-       handle = bdev_open_by_dev(inode->i_rdev, mode,
-                       mode & BLK_OPEN_EXCL ? filp : NULL, NULL);
-       if (IS_ERR(handle))
-               return PTR_ERR(handle);
+       /* Use the file as the holder. */
+       if (mode & BLK_OPEN_EXCL)
+               filp->private_data = filp;
+       ret = bdev_permission(inode->i_rdev, mode, filp->private_data);
+       if (ret)
+               return ret;
 
-       if (bdev_nowait(handle->bdev))
-               filp->f_mode |= FMODE_NOWAIT;
+       bdev = blkdev_get_no_open(inode->i_rdev);
+       if (!bdev)
+               return -ENXIO;
 
-       filp->f_mapping = handle->bdev->bd_inode->i_mapping;
-       filp->f_wb_err = filemap_sample_wb_err(filp->f_mapping);
-       filp->private_data = handle;
-       return 0;
+       ret = bdev_open(bdev, mode, filp->private_data, NULL, filp);
+       if (ret)
+               blkdev_put_no_open(bdev);
+       return ret;
 }
 
 static int blkdev_release(struct inode *inode, struct file *filp)
 {
-       bdev_release(filp->private_data);
+       bdev_release(filp);
        return 0;
 }
 
index d74fb5b4ae68188a9b1bd7886212e8fa2566a7a7..bb29a68e1d67662533653d8e74742554ae09b39a 100644 (file)
@@ -342,7 +342,7 @@ EXPORT_SYMBOL_GPL(disk_uevent);
 
 int disk_scan_partitions(struct gendisk *disk, blk_mode_t mode)
 {
-       struct bdev_handle *handle;
+       struct file *file;
        int ret = 0;
 
        if (disk->flags & (GENHD_FL_NO_PART | GENHD_FL_HIDDEN))
@@ -366,12 +366,12 @@ int disk_scan_partitions(struct gendisk *disk, blk_mode_t mode)
        }
 
        set_bit(GD_NEED_PART_SCAN, &disk->state);
-       handle = bdev_open_by_dev(disk_devt(disk), mode & ~BLK_OPEN_EXCL, NULL,
-                                 NULL);
-       if (IS_ERR(handle))
-               ret = PTR_ERR(handle);
+       file = bdev_file_open_by_dev(disk_devt(disk), mode & ~BLK_OPEN_EXCL,
+                                    NULL, NULL);
+       if (IS_ERR(file))
+               ret = PTR_ERR(file);
        else
-               bdev_release(handle);
+               fput(file);
 
        /*
         * If blkdev_get_by_dev() failed early, GD_NEED_PART_SCAN is still set,
@@ -1201,7 +1201,7 @@ static int block_uevent(const struct device *dev, struct kobj_uevent_env *env)
        return add_uevent_var(env, "DISKSEQ=%llu", disk->diskseq);
 }
 
-struct class block_class = {
+const struct class block_class = {
        .name           = "block",
        .dev_uevent     = block_uevent,
 };
@@ -1391,19 +1391,21 @@ out_free_disk:
        return NULL;
 }
 
-struct gendisk *__blk_alloc_disk(int node, struct lock_class_key *lkclass)
+struct gendisk *__blk_alloc_disk(struct queue_limits *lim, int node,
+               struct lock_class_key *lkclass)
 {
+       struct queue_limits default_lim = { };
        struct request_queue *q;
        struct gendisk *disk;
 
-       q = blk_alloc_queue(node);
-       if (!q)
-               return NULL;
+       q = blk_alloc_queue(lim ? lim : &default_lim, node);
+       if (IS_ERR(q))
+               return ERR_CAST(q);
 
        disk = __alloc_disk_node(q, node, lkclass);
        if (!disk) {
                blk_put_queue(q);
-               return NULL;
+               return ERR_PTR(-ENOMEM);
        }
        set_bit(GD_OWNS_QUEUE, &disk->state);
        return disk;
index 37d18c13d958188ba35214fc842db985d0e908b3..791091a7eac234d79970aca9b32a5d317b085483 100644 (file)
@@ -8,6 +8,8 @@ struct bd_holder_disk {
        int                     refcnt;
 };
 
+static DEFINE_MUTEX(blk_holder_mutex);
+
 static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
                                                  struct gendisk *disk)
 {
@@ -80,7 +82,7 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
        kobject_get(bdev->bd_holder_dir);
        mutex_unlock(&bdev->bd_disk->open_mutex);
 
-       mutex_lock(&disk->open_mutex);
+       mutex_lock(&blk_holder_mutex);
        WARN_ON_ONCE(!bdev->bd_holder);
 
        holder = bd_find_holder_disk(bdev, disk);
@@ -108,7 +110,7 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
                goto out_del_symlink;
        list_add(&holder->list, &disk->slave_bdevs);
 
-       mutex_unlock(&disk->open_mutex);
+       mutex_unlock(&blk_holder_mutex);
        return 0;
 
 out_del_symlink:
@@ -116,7 +118,7 @@ out_del_symlink:
 out_free_holder:
        kfree(holder);
 out_unlock:
-       mutex_unlock(&disk->open_mutex);
+       mutex_unlock(&blk_holder_mutex);
        if (ret)
                kobject_put(bdev->bd_holder_dir);
        return ret;
@@ -140,7 +142,7 @@ void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
        if (WARN_ON_ONCE(!disk->slave_dir))
                return;
 
-       mutex_lock(&disk->open_mutex);
+       mutex_lock(&blk_holder_mutex);
        holder = bd_find_holder_disk(bdev, disk);
        if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) {
                del_symlink(disk->slave_dir, bdev_kobj(bdev));
@@ -149,6 +151,6 @@ void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
                list_del_init(&holder->list);
                kfree(holder);
        }
-       mutex_unlock(&disk->open_mutex);
+       mutex_unlock(&blk_holder_mutex);
 }
 EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
index 438f79c564cfc05d6f525550417eeee93c7b82bb..0c76137adcaaa5b9d212d789291d681c23c064f6 100644 (file)
@@ -18,7 +18,7 @@ static int blkpg_do_ioctl(struct block_device *bdev,
 {
        struct gendisk *disk = bdev->bd_disk;
        struct blkpg_partition p;
-       sector_t start, length;
+       sector_t start, length, capacity, end;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
@@ -41,6 +41,13 @@ static int blkpg_do_ioctl(struct block_device *bdev,
 
        start = p.start >> SECTOR_SHIFT;
        length = p.length >> SECTOR_SHIFT;
+       capacity = get_capacity(disk);
+
+       if (check_add_overflow(start, length, &end))
+               return -EINVAL;
+
+       if (start >= capacity || end > capacity)
+               return -EINVAL;
 
        switch (op) {
        case BLKPG_ADD_PARTITION:
@@ -469,7 +476,7 @@ static int blkdev_bszset(struct block_device *bdev, blk_mode_t mode,
                int __user *argp)
 {
        int ret, n;
-       struct bdev_handle *handle;
+       struct file *file;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
@@ -481,12 +488,11 @@ static int blkdev_bszset(struct block_device *bdev, blk_mode_t mode,
        if (mode & BLK_OPEN_EXCL)
                return set_blocksize(bdev, n);
 
-       handle = bdev_open_by_dev(bdev->bd_dev, mode, &bdev, NULL);
-       if (IS_ERR(handle))
+       file = bdev_file_open_by_dev(bdev->bd_dev, mode, &bdev, NULL);
+       if (IS_ERR(file))
                return -EBUSY;
        ret = set_blocksize(bdev, n);
-       bdev_release(handle);
-
+       fput(file);
        return ret;
 }
 
index dec7ce3a3edb7027b971232269846390e3baa834..d247a457bf6e3fd03c0e0f496988c6a5e8999ff1 100644 (file)
@@ -71,6 +71,7 @@ enum opal_response_token {
 #define SHORT_ATOM_BYTE  0xBF
 #define MEDIUM_ATOM_BYTE 0xDF
 #define LONG_ATOM_BYTE   0xE3
+#define EMPTY_ATOM_BYTE  0xFF
 
 #define OPAL_INVAL_PARAM 12
 #define OPAL_MANUFACTURED_INACTIVE 0x08
index 5f5ed5c75f04d91d7bc8bf87ff4c9fa685c62318..b11e88c82c8cfa9e179b05a6633f0b1294d818da 100644 (file)
@@ -419,21 +419,10 @@ static bool partition_overlaps(struct gendisk *disk, sector_t start,
 int bdev_add_partition(struct gendisk *disk, int partno, sector_t start,
                sector_t length)
 {
-       sector_t capacity = get_capacity(disk), end;
        struct block_device *part;
        int ret;
 
        mutex_lock(&disk->open_mutex);
-       if (check_add_overflow(start, length, &end)) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (start >= capacity || end > capacity) {
-               ret = -EINVAL;
-               goto out;
-       }
-
        if (!disk_live(disk)) {
                ret = -ENXIO;
                goto out;
index 7b521df00a39f4fc10239b71a1be86263d93beb1..c80183156d68020e0e14974308ac751b3df84421 100644 (file)
@@ -20,6 +20,7 @@ extern void note_bootable_part(dev_t dev, int part, int goodness);
  * Code to understand MacOS partition tables.
  */
 
+#ifdef CONFIG_PPC_PMAC
 static inline void mac_fix_string(char *stg, int len)
 {
        int i;
@@ -27,6 +28,7 @@ static inline void mac_fix_string(char *stg, int len)
        for (i = len - 1; i >= 0 && stg[i] == ' '; i--)
                stg[i] = 0;
 }
+#endif
 
 int mac_partition(struct parsed_partitions *state)
 {
index 3d9e9cd250bd541f3166932bde9e43b35c13f13a..14fe0fef811cfc2fb5e84047a592fa7a309addb4 100644 (file)
@@ -1056,16 +1056,20 @@ static int response_parse(const u8 *buf, size_t length,
                        token_length = response_parse_medium(iter, pos);
                else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */
                        token_length = response_parse_long(iter, pos);
+               else if (pos[0] == EMPTY_ATOM_BYTE) /* empty atom */
+                       token_length = 1;
                else /* TOKEN */
                        token_length = response_parse_token(iter, pos);
 
                if (token_length < 0)
                        return token_length;
 
+               if (pos[0] != EMPTY_ATOM_BYTE)
+                       num_entries++;
+
                pos += token_length;
                total -= token_length;
                iter++;
-               num_entries++;
        }
 
        resp->num = num_entries;
@@ -1208,7 +1212,7 @@ static int cmd_start(struct opal_dev *dev, const u8 *uid, const u8 *method)
 static int start_opal_session_cont(struct opal_dev *dev)
 {
        u32 hsn, tsn;
-       int error = 0;
+       int error;
 
        error = parse_and_check_status(dev);
        if (error)
@@ -1350,7 +1354,7 @@ static int get_active_key_cont(struct opal_dev *dev)
 {
        const char *activekey;
        size_t keylen;
-       int error = 0;
+       int error;
 
        error = parse_and_check_status(dev);
        if (error)
@@ -2153,7 +2157,7 @@ static int lock_unlock_locking_range(struct opal_dev *dev, void *data)
        u8 lr_buffer[OPAL_UID_LENGTH];
        struct opal_lock_unlock *lkul = data;
        u8 read_locked = 1, write_locked = 1;
-       int err = 0;
+       int err;
 
        if (build_locking_range(lr_buffer, sizeof(lr_buffer),
                                lkul->session.opal_key.lr) < 0)
@@ -2576,7 +2580,7 @@ static int opal_get_discv(struct opal_dev *dev, struct opal_discovery *discv)
        const struct opal_step discovery0_step = {
                opal_discovery0, discv
        };
-       int ret = 0;
+       int ret;
 
        mutex_lock(&dev->dev_lock);
        setup_opal_dev(dev);
@@ -3065,7 +3069,7 @@ bool opal_unlock_from_suspend(struct opal_dev *dev)
 {
        struct opal_suspend_data *suspend;
        bool was_failure = false;
-       int ret = 0;
+       int ret;
 
        if (!dev)
                return false;
@@ -3108,10 +3112,9 @@ static int opal_read_table(struct opal_dev *dev,
                { read_table_data, rw_tbl },
                { end_opal_session, }
        };
-       int ret = 0;
 
        if (!rw_tbl->size)
-               return ret;
+               return 0;
 
        return execute_steps(dev, read_table_steps,
                             ARRAY_SIZE(read_table_steps));
@@ -3125,10 +3128,9 @@ static int opal_write_table(struct opal_dev *dev,
                { write_table_data, rw_tbl },
                { end_opal_session, }
        };
-       int ret = 0;
 
        if (!rw_tbl->size)
-               return ret;
+               return 0;
 
        return execute_steps(dev, write_table_steps,
                             ARRAY_SIZE(write_table_steps));
index 914d8cddd43a92ebc65c02c0b92d7e7825cdc3d0..d90892fd6f2ad5faf295b7c91f3bcf1e90a5a713 100644 (file)
 #include <net/checksum.h>
 #include <asm/unaligned.h>
 
-typedef __be16 (csum_fn) (void *, unsigned int);
+typedef __be16 (csum_fn) (__be16, void *, unsigned int);
 
-static __be16 t10_pi_crc_fn(void *data, unsigned int len)
+static __be16 t10_pi_crc_fn(__be16 crc, void *data, unsigned int len)
 {
-       return cpu_to_be16(crc_t10dif(data, len));
+       return cpu_to_be16(crc_t10dif_update(be16_to_cpu(crc), data, len));
 }
 
-static __be16 t10_pi_ip_fn(void *data, unsigned int len)
+static __be16 t10_pi_ip_fn(__be16 csum, void *data, unsigned int len)
 {
        return (__force __be16)ip_compute_csum(data, len);
 }
@@ -32,12 +32,16 @@ static __be16 t10_pi_ip_fn(void *data, unsigned int len)
 static blk_status_t t10_pi_generate(struct blk_integrity_iter *iter,
                csum_fn *fn, enum t10_dif_type type)
 {
+       u8 offset = iter->pi_offset;
        unsigned int i;
 
        for (i = 0 ; i < iter->data_size ; i += iter->interval) {
-               struct t10_pi_tuple *pi = iter->prot_buf;
+               struct t10_pi_tuple *pi = iter->prot_buf + offset;
 
-               pi->guard_tag = fn(iter->data_buf, iter->interval);
+               pi->guard_tag = fn(0, iter->data_buf, iter->interval);
+               if (offset)
+                       pi->guard_tag = fn(pi->guard_tag, iter->prot_buf,
+                                          offset);
                pi->app_tag = 0;
 
                if (type == T10_PI_TYPE1_PROTECTION)
@@ -56,12 +60,13 @@ static blk_status_t t10_pi_generate(struct blk_integrity_iter *iter,
 static blk_status_t t10_pi_verify(struct blk_integrity_iter *iter,
                csum_fn *fn, enum t10_dif_type type)
 {
+       u8 offset = iter->pi_offset;
        unsigned int i;
 
        BUG_ON(type == T10_PI_TYPE0_PROTECTION);
 
        for (i = 0 ; i < iter->data_size ; i += iter->interval) {
-               struct t10_pi_tuple *pi = iter->prot_buf;
+               struct t10_pi_tuple *pi = iter->prot_buf + offset;
                __be16 csum;
 
                if (type == T10_PI_TYPE1_PROTECTION ||
@@ -83,7 +88,9 @@ static blk_status_t t10_pi_verify(struct blk_integrity_iter *iter,
                                goto next;
                }
 
-               csum = fn(iter->data_buf, iter->interval);
+               csum = fn(0, iter->data_buf, iter->interval);
+               if (offset)
+                       csum = fn(csum, iter->prot_buf, offset);
 
                if (pi->guard_tag != csum) {
                        pr_err("%s: guard tag error at sector %llu " \
@@ -134,8 +141,10 @@ static blk_status_t t10_pi_type1_verify_ip(struct blk_integrity_iter *iter)
  */
 static void t10_pi_type1_prepare(struct request *rq)
 {
-       const int tuple_sz = rq->q->integrity.tuple_size;
+       struct blk_integrity *bi = &rq->q->integrity;
+       const int tuple_sz = bi->tuple_size;
        u32 ref_tag = t10_pi_ref_tag(rq);
+       u8 offset = bi->pi_offset;
        struct bio *bio;
 
        __rq_for_each_bio(bio, rq) {
@@ -154,7 +163,7 @@ static void t10_pi_type1_prepare(struct request *rq)
 
                        p = bvec_kmap_local(&iv);
                        for (j = 0; j < iv.bv_len; j += tuple_sz) {
-                               struct t10_pi_tuple *pi = p;
+                               struct t10_pi_tuple *pi = p + offset;
 
                                if (be32_to_cpu(pi->ref_tag) == virt)
                                        pi->ref_tag = cpu_to_be32(ref_tag);
@@ -183,9 +192,11 @@ static void t10_pi_type1_prepare(struct request *rq)
  */
 static void t10_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
 {
-       unsigned intervals = nr_bytes >> rq->q->integrity.interval_exp;
-       const int tuple_sz = rq->q->integrity.tuple_size;
+       struct blk_integrity *bi = &rq->q->integrity;
+       unsigned intervals = nr_bytes >> bi->interval_exp;
+       const int tuple_sz = bi->tuple_size;
        u32 ref_tag = t10_pi_ref_tag(rq);
+       u8 offset = bi->pi_offset;
        struct bio *bio;
 
        __rq_for_each_bio(bio, rq) {
@@ -200,7 +211,7 @@ static void t10_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
 
                        p = bvec_kmap_local(&iv);
                        for (j = 0; j < iv.bv_len && intervals; j += tuple_sz) {
-                               struct t10_pi_tuple *pi = p;
+                               struct t10_pi_tuple *pi = p + offset;
 
                                if (be32_to_cpu(pi->ref_tag) == ref_tag)
                                        pi->ref_tag = cpu_to_be32(virt);
@@ -280,20 +291,24 @@ const struct blk_integrity_profile t10_pi_type3_ip = {
 };
 EXPORT_SYMBOL(t10_pi_type3_ip);
 
-static __be64 ext_pi_crc64(void *data, unsigned int len)
+static __be64 ext_pi_crc64(u64 crc, void *data, unsigned int len)
 {
-       return cpu_to_be64(crc64_rocksoft(data, len));
+       return cpu_to_be64(crc64_rocksoft_update(crc, data, len));
 }
 
 static blk_status_t ext_pi_crc64_generate(struct blk_integrity_iter *iter,
                                        enum t10_dif_type type)
 {
+       u8 offset = iter->pi_offset;
        unsigned int i;
 
        for (i = 0 ; i < iter->data_size ; i += iter->interval) {
-               struct crc64_pi_tuple *pi = iter->prot_buf;
+               struct crc64_pi_tuple *pi = iter->prot_buf + offset;
 
-               pi->guard_tag = ext_pi_crc64(iter->data_buf, iter->interval);
+               pi->guard_tag = ext_pi_crc64(0, iter->data_buf, iter->interval);
+               if (offset)
+                       pi->guard_tag = ext_pi_crc64(be64_to_cpu(pi->guard_tag),
+                                       iter->prot_buf, offset);
                pi->app_tag = 0;
 
                if (type == T10_PI_TYPE1_PROTECTION)
@@ -319,10 +334,11 @@ static bool ext_pi_ref_escape(u8 *ref_tag)
 static blk_status_t ext_pi_crc64_verify(struct blk_integrity_iter *iter,
                                      enum t10_dif_type type)
 {
+       u8 offset = iter->pi_offset;
        unsigned int i;
 
        for (i = 0; i < iter->data_size; i += iter->interval) {
-               struct crc64_pi_tuple *pi = iter->prot_buf;
+               struct crc64_pi_tuple *pi = iter->prot_buf + offset;
                u64 ref, seed;
                __be64 csum;
 
@@ -343,7 +359,11 @@ static blk_status_t ext_pi_crc64_verify(struct blk_integrity_iter *iter,
                                goto next;
                }
 
-               csum = ext_pi_crc64(iter->data_buf, iter->interval);
+               csum = ext_pi_crc64(0, iter->data_buf, iter->interval);
+               if (offset)
+                       csum = ext_pi_crc64(be64_to_cpu(csum), iter->prot_buf,
+                                           offset);
+
                if (pi->guard_tag != csum) {
                        pr_err("%s: guard tag error at sector %llu " \
                               "(rcvd %016llx, want %016llx)\n",
@@ -373,8 +393,10 @@ static blk_status_t ext_pi_type1_generate_crc64(struct blk_integrity_iter *iter)
 
 static void ext_pi_type1_prepare(struct request *rq)
 {
-       const int tuple_sz = rq->q->integrity.tuple_size;
+       struct blk_integrity *bi = &rq->q->integrity;
+       const int tuple_sz = bi->tuple_size;
        u64 ref_tag = ext_pi_ref_tag(rq);
+       u8 offset = bi->pi_offset;
        struct bio *bio;
 
        __rq_for_each_bio(bio, rq) {
@@ -393,7 +415,7 @@ static void ext_pi_type1_prepare(struct request *rq)
 
                        p = bvec_kmap_local(&iv);
                        for (j = 0; j < iv.bv_len; j += tuple_sz) {
-                               struct crc64_pi_tuple *pi = p;
+                               struct crc64_pi_tuple *pi = p +  offset;
                                u64 ref = get_unaligned_be48(pi->ref_tag);
 
                                if (ref == virt)
@@ -411,9 +433,11 @@ static void ext_pi_type1_prepare(struct request *rq)
 
 static void ext_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
 {
-       unsigned intervals = nr_bytes >> rq->q->integrity.interval_exp;
-       const int tuple_sz = rq->q->integrity.tuple_size;
+       struct blk_integrity *bi = &rq->q->integrity;
+       unsigned intervals = nr_bytes >> bi->interval_exp;
+       const int tuple_sz = bi->tuple_size;
        u64 ref_tag = ext_pi_ref_tag(rq);
+       u8 offset = bi->pi_offset;
        struct bio *bio;
 
        __rq_for_each_bio(bio, rq) {
@@ -428,7 +452,7 @@ static void ext_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
 
                        p = bvec_kmap_local(&iv);
                        for (j = 0; j < iv.bv_len && intervals; j += tuple_sz) {
-                               struct crc64_pi_tuple *pi = p;
+                               struct crc64_pi_tuple *pi = p + offset;
                                u64 ref = get_unaligned_be48(pi->ref_tag);
 
                                if (ref == ref_tag)
index 0b6dd8aa21f2edace686fb5531705698e7acc18d..0f1bd7dcde245988bb7d01dc9d0e32655669bdf8 100644 (file)
@@ -212,13 +212,12 @@ static int crypto_lskcipher_crypt_sg(struct skcipher_request *req,
 
        ivsize = crypto_lskcipher_ivsize(tfm);
        ivs = PTR_ALIGN(ivs, crypto_skcipher_alignmask(skcipher) + 1);
+       memcpy(ivs, req->iv, ivsize);
 
        flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
 
        if (req->base.flags & CRYPTO_SKCIPHER_REQ_CONT)
                flags |= CRYPTO_LSKCIPHER_FLAG_CONT;
-       else
-               memcpy(ivs, req->iv, ivsize);
 
        if (!(req->base.flags & CRYPTO_SKCIPHER_REQ_NOTFINAL))
                flags |= CRYPTO_LSKCIPHER_FLAG_FINAL;
@@ -234,8 +233,7 @@ static int crypto_lskcipher_crypt_sg(struct skcipher_request *req,
                flags |= CRYPTO_LSKCIPHER_FLAG_CONT;
        }
 
-       if (flags & CRYPTO_LSKCIPHER_FLAG_FINAL)
-               memcpy(req->iv, ivs, ivsize);
+       memcpy(req->iv, ivs, ivsize);
 
        return err;
 }
index 77accd029c4a71399de1729323405d7a3c262cc2..89af1006df5587ba560415a7d669251648f3c3e8 100644 (file)
@@ -510,16 +510,6 @@ static int ivpu_boot_pwr_domain_enable(struct ivpu_device *vdev)
        return ret;
 }
 
-static int ivpu_boot_pwr_domain_disable(struct ivpu_device *vdev)
-{
-       ivpu_boot_dpu_active_drive(vdev, false);
-       ivpu_boot_pwr_island_isolation_drive(vdev, true);
-       ivpu_boot_pwr_island_trickle_drive(vdev, false);
-       ivpu_boot_pwr_island_drive(vdev, false);
-
-       return ivpu_boot_wait_for_pwr_island_status(vdev, 0x0);
-}
-
 static void ivpu_boot_no_snoop_enable(struct ivpu_device *vdev)
 {
        u32 val = REGV_RD32(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES);
@@ -616,12 +606,37 @@ static int ivpu_hw_37xx_info_init(struct ivpu_device *vdev)
        return 0;
 }
 
+static int ivpu_hw_37xx_ip_reset(struct ivpu_device *vdev)
+{
+       int ret;
+       u32 val;
+
+       if (IVPU_WA(punit_disabled))
+               return 0;
+
+       ret = REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US);
+       if (ret) {
+               ivpu_err(vdev, "Timed out waiting for TRIGGER bit\n");
+               return ret;
+       }
+
+       val = REGB_RD32(VPU_37XX_BUTTRESS_VPU_IP_RESET);
+       val = REG_SET_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, val);
+       REGB_WR32(VPU_37XX_BUTTRESS_VPU_IP_RESET, val);
+
+       ret = REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US);
+       if (ret)
+               ivpu_err(vdev, "Timed out waiting for RESET completion\n");
+
+       return ret;
+}
+
 static int ivpu_hw_37xx_reset(struct ivpu_device *vdev)
 {
        int ret = 0;
 
-       if (ivpu_boot_pwr_domain_disable(vdev)) {
-               ivpu_err(vdev, "Failed to disable power domain\n");
+       if (ivpu_hw_37xx_ip_reset(vdev)) {
+               ivpu_err(vdev, "Failed to reset NPU\n");
                ret = -EIO;
        }
 
@@ -661,6 +676,11 @@ static int ivpu_hw_37xx_power_up(struct ivpu_device *vdev)
 {
        int ret;
 
+       /* PLL requests may fail when powering down, so issue WP 0 here */
+       ret = ivpu_pll_disable(vdev);
+       if (ret)
+               ivpu_warn(vdev, "Failed to disable PLL: %d\n", ret);
+
        ret = ivpu_hw_37xx_d0i3_disable(vdev);
        if (ret)
                ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret);
index 1c995307c1138885dc9cacd7ad73ca16633f2158..a1523d0b1ef3660709ae087003a703fb4f8237bd 100644 (file)
@@ -24,7 +24,7 @@
 #define SKU_HW_ID_SHIFT              16u
 #define SKU_HW_ID_MASK               0xffff0000u
 
-#define PLL_CONFIG_DEFAULT           0x1
+#define PLL_CONFIG_DEFAULT           0x0
 #define PLL_CDYN_DEFAULT             0x80
 #define PLL_EPP_DEFAULT              0x80
 #define PLL_REF_CLK_FREQ            (50 * 1000000)
index f501f27ebafdf6687b5a46ca7e2387faa931af3e..5f73854234ba93da22b00113376c296df1ebd35a 100644 (file)
@@ -58,11 +58,14 @@ static int ivpu_suspend(struct ivpu_device *vdev)
 {
        int ret;
 
+       /* Save PCI state before powering down as it sometimes gets corrupted if NPU hangs */
+       pci_save_state(to_pci_dev(vdev->drm.dev));
+
        ret = ivpu_shutdown(vdev);
-       if (ret) {
+       if (ret)
                ivpu_err(vdev, "Failed to shutdown VPU: %d\n", ret);
-               return ret;
-       }
+
+       pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot);
 
        return ret;
 }
@@ -71,6 +74,9 @@ static int ivpu_resume(struct ivpu_device *vdev)
 {
        int ret;
 
+       pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D0);
+       pci_restore_state(to_pci_dev(vdev->drm.dev));
+
 retry:
        ret = ivpu_hw_power_up(vdev);
        if (ret) {
@@ -120,15 +126,20 @@ static void ivpu_pm_recovery_work(struct work_struct *work)
 
        ivpu_fw_log_dump(vdev);
 
-retry:
-       ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev));
-       if (ret == -EAGAIN && !drm_dev_is_unplugged(&vdev->drm)) {
-               cond_resched();
-               goto retry;
-       }
+       atomic_inc(&vdev->pm->reset_counter);
+       atomic_set(&vdev->pm->reset_pending, 1);
+       down_write(&vdev->pm->reset_lock);
+
+       ivpu_suspend(vdev);
+       ivpu_pm_prepare_cold_boot(vdev);
+       ivpu_jobs_abort_all(vdev);
+
+       ret = ivpu_resume(vdev);
+       if (ret)
+               ivpu_err(vdev, "Failed to resume NPU: %d\n", ret);
 
-       if (ret && ret != -EAGAIN)
-               ivpu_err(vdev, "Failed to reset VPU: %d\n", ret);
+       up_write(&vdev->pm->reset_lock);
+       atomic_set(&vdev->pm->reset_pending, 0);
 
        kobject_uevent_env(&vdev->drm.dev->kobj, KOBJ_CHANGE, evt);
        pm_runtime_mark_last_busy(vdev->drm.dev);
@@ -200,9 +211,6 @@ int ivpu_pm_suspend_cb(struct device *dev)
        ivpu_suspend(vdev);
        ivpu_pm_prepare_warm_boot(vdev);
 
-       pci_save_state(to_pci_dev(dev));
-       pci_set_power_state(to_pci_dev(dev), PCI_D3hot);
-
        ivpu_dbg(vdev, PM, "Suspend done.\n");
 
        return 0;
@@ -216,9 +224,6 @@ int ivpu_pm_resume_cb(struct device *dev)
 
        ivpu_dbg(vdev, PM, "Resume..\n");
 
-       pci_set_power_state(to_pci_dev(dev), PCI_D0);
-       pci_restore_state(to_pci_dev(dev));
-
        ret = ivpu_resume(vdev);
        if (ret)
                ivpu_err(vdev, "Failed to resume: %d\n", ret);
index fe825a432c5bfcce4776d83e0f072c9675507dae..ab2a82cb1b0b48ab21682bdb87c052707f19d282 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/interrupt.h>
 #include <linux/timer.h>
 #include <linux/cper.h>
-#include <linux/cxl-event.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
 #include <linux/ratelimit.h>
@@ -674,52 +673,6 @@ static void ghes_defer_non_standard_event(struct acpi_hest_generic_data *gdata,
        schedule_work(&entry->work);
 }
 
-/*
- * Only a single callback can be registered for CXL CPER events.
- */
-static DECLARE_RWSEM(cxl_cper_rw_sem);
-static cxl_cper_callback cper_callback;
-
-static void cxl_cper_post_event(enum cxl_event_type event_type,
-                               struct cxl_cper_event_rec *rec)
-{
-       if (rec->hdr.length <= sizeof(rec->hdr) ||
-           rec->hdr.length > sizeof(*rec)) {
-               pr_err(FW_WARN "CXL CPER Invalid section length (%u)\n",
-                      rec->hdr.length);
-               return;
-       }
-
-       if (!(rec->hdr.validation_bits & CPER_CXL_COMP_EVENT_LOG_VALID)) {
-               pr_err(FW_WARN "CXL CPER invalid event\n");
-               return;
-       }
-
-       guard(rwsem_read)(&cxl_cper_rw_sem);
-       if (cper_callback)
-               cper_callback(event_type, rec);
-}
-
-int cxl_cper_register_callback(cxl_cper_callback callback)
-{
-       guard(rwsem_write)(&cxl_cper_rw_sem);
-       if (cper_callback)
-               return -EINVAL;
-       cper_callback = callback;
-       return 0;
-}
-EXPORT_SYMBOL_NS_GPL(cxl_cper_register_callback, CXL);
-
-int cxl_cper_unregister_callback(cxl_cper_callback callback)
-{
-       guard(rwsem_write)(&cxl_cper_rw_sem);
-       if (callback != cper_callback)
-               return -EINVAL;
-       cper_callback = NULL;
-       return 0;
-}
-EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_callback, CXL);
-
 static bool ghes_do_proc(struct ghes *ghes,
                         const struct acpi_hest_generic_status *estatus)
 {
@@ -754,22 +707,6 @@ static bool ghes_do_proc(struct ghes *ghes,
                }
                else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
                        queued = ghes_handle_arm_hw_error(gdata, sev, sync);
-               } else if (guid_equal(sec_type, &CPER_SEC_CXL_GEN_MEDIA_GUID)) {
-                       struct cxl_cper_event_rec *rec =
-                               acpi_hest_get_payload(gdata);
-
-                       cxl_cper_post_event(CXL_CPER_EVENT_GEN_MEDIA, rec);
-               } else if (guid_equal(sec_type, &CPER_SEC_CXL_DRAM_GUID)) {
-                       struct cxl_cper_event_rec *rec =
-                               acpi_hest_get_payload(gdata);
-
-                       cxl_cper_post_event(CXL_CPER_EVENT_DRAM, rec);
-               } else if (guid_equal(sec_type,
-                                     &CPER_SEC_CXL_MEM_MODULE_GUID)) {
-                       struct cxl_cper_event_rec *rec =
-                               acpi_hest_get_payload(gdata);
-
-                       cxl_cper_post_event(CXL_CPER_EVENT_MEM_MODULE, rec);
                } else {
                        void *err = acpi_hest_get_payload(gdata);
 
index dbdee2924594a921f27fead574fcf1855c4e471b..02255795b800d1a42ceb7694216d2b6c92594b6b 100644 (file)
@@ -525,10 +525,12 @@ static void acpi_ec_clear(struct acpi_ec *ec)
 
 static void acpi_ec_enable_event(struct acpi_ec *ec)
 {
-       spin_lock(&ec->lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ec->lock, flags);
        if (acpi_ec_started(ec))
                __acpi_ec_enable_event(ec);
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, flags);
 
        /* Drain additional events if hardware requires that */
        if (EC_FLAGS_CLEAR_ON_RESUME)
@@ -544,9 +546,11 @@ static void __acpi_ec_flush_work(void)
 
 static void acpi_ec_disable_event(struct acpi_ec *ec)
 {
-       spin_lock(&ec->lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ec->lock, flags);
        __acpi_ec_disable_event(ec);
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, flags);
 
        /*
         * When ec_freeze_events is true, we need to flush events in
@@ -567,9 +571,10 @@ void acpi_ec_flush_work(void)
 
 static bool acpi_ec_guard_event(struct acpi_ec *ec)
 {
+       unsigned long flags;
        bool guarded;
 
-       spin_lock(&ec->lock);
+       spin_lock_irqsave(&ec->lock, flags);
        /*
         * If firmware SCI_EVT clearing timing is "event", we actually
         * don't know when the SCI_EVT will be cleared by firmware after
@@ -585,29 +590,31 @@ static bool acpi_ec_guard_event(struct acpi_ec *ec)
        guarded = ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
                ec->event_state != EC_EVENT_READY &&
                (!ec->curr || ec->curr->command != ACPI_EC_COMMAND_QUERY);
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, flags);
        return guarded;
 }
 
 static int ec_transaction_polled(struct acpi_ec *ec)
 {
+       unsigned long flags;
        int ret = 0;
 
-       spin_lock(&ec->lock);
+       spin_lock_irqsave(&ec->lock, flags);
        if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_POLL))
                ret = 1;
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, flags);
        return ret;
 }
 
 static int ec_transaction_completed(struct acpi_ec *ec)
 {
+       unsigned long flags;
        int ret = 0;
 
-       spin_lock(&ec->lock);
+       spin_lock_irqsave(&ec->lock, flags);
        if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE))
                ret = 1;
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, flags);
        return ret;
 }
 
@@ -749,6 +756,7 @@ static int ec_guard(struct acpi_ec *ec)
 
 static int ec_poll(struct acpi_ec *ec)
 {
+       unsigned long flags;
        int repeat = 5; /* number of command restarts */
 
        while (repeat--) {
@@ -757,14 +765,14 @@ static int ec_poll(struct acpi_ec *ec)
                do {
                        if (!ec_guard(ec))
                                return 0;
-                       spin_lock(&ec->lock);
+                       spin_lock_irqsave(&ec->lock, flags);
                        advance_transaction(ec, false);
-                       spin_unlock(&ec->lock);
+                       spin_unlock_irqrestore(&ec->lock, flags);
                } while (time_before(jiffies, delay));
                pr_debug("controller reset, restart transaction\n");
-               spin_lock(&ec->lock);
+               spin_lock_irqsave(&ec->lock, flags);
                start_transaction(ec);
-               spin_unlock(&ec->lock);
+               spin_unlock_irqrestore(&ec->lock, flags);
        }
        return -ETIME;
 }
@@ -772,10 +780,11 @@ static int ec_poll(struct acpi_ec *ec)
 static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
                                        struct transaction *t)
 {
+       unsigned long tmp;
        int ret = 0;
 
        /* start transaction */
-       spin_lock(&ec->lock);
+       spin_lock_irqsave(&ec->lock, tmp);
        /* Enable GPE for command processing (IBF=0/OBF=1) */
        if (!acpi_ec_submit_flushable_request(ec)) {
                ret = -EINVAL;
@@ -786,11 +795,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
        ec->curr = t;
        ec_dbg_req("Command(%s) started", acpi_ec_cmd_string(t->command));
        start_transaction(ec);
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, tmp);
 
        ret = ec_poll(ec);
 
-       spin_lock(&ec->lock);
+       spin_lock_irqsave(&ec->lock, tmp);
        if (t->irq_count == ec_storm_threshold)
                acpi_ec_unmask_events(ec);
        ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command));
@@ -799,7 +808,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
        acpi_ec_complete_request(ec);
        ec_dbg_ref(ec, "Decrease command");
 unlock:
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, tmp);
        return ret;
 }
 
@@ -927,7 +936,9 @@ EXPORT_SYMBOL(ec_get_handle);
 
 static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
 {
-       spin_lock(&ec->lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ec->lock, flags);
        if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
                ec_dbg_drv("Starting EC");
                /* Enable GPE for event processing (SCI_EVT=1) */
@@ -937,28 +948,31 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
                }
                ec_log_drv("EC started");
        }
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, flags);
 }
 
 static bool acpi_ec_stopped(struct acpi_ec *ec)
 {
+       unsigned long flags;
        bool flushed;
 
-       spin_lock(&ec->lock);
+       spin_lock_irqsave(&ec->lock, flags);
        flushed = acpi_ec_flushed(ec);
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, flags);
        return flushed;
 }
 
 static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
 {
-       spin_lock(&ec->lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ec->lock, flags);
        if (acpi_ec_started(ec)) {
                ec_dbg_drv("Stopping EC");
                set_bit(EC_FLAGS_STOPPED, &ec->flags);
-               spin_unlock(&ec->lock);
+               spin_unlock_irqrestore(&ec->lock, flags);
                wait_event(ec->wait, acpi_ec_stopped(ec));
-               spin_lock(&ec->lock);
+               spin_lock_irqsave(&ec->lock, flags);
                /* Disable GPE for event processing (SCI_EVT=1) */
                if (!suspending) {
                        acpi_ec_complete_request(ec);
@@ -969,25 +983,29 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
                clear_bit(EC_FLAGS_STOPPED, &ec->flags);
                ec_log_drv("EC stopped");
        }
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, flags);
 }
 
 static void acpi_ec_enter_noirq(struct acpi_ec *ec)
 {
-       spin_lock(&ec->lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ec->lock, flags);
        ec->busy_polling = true;
        ec->polling_guard = 0;
        ec_log_drv("interrupt blocked");
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, flags);
 }
 
 static void acpi_ec_leave_noirq(struct acpi_ec *ec)
 {
-       spin_lock(&ec->lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ec->lock, flags);
        ec->busy_polling = ec_busy_polling;
        ec->polling_guard = ec_polling_guard;
        ec_log_drv("interrupt unblocked");
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, flags);
 }
 
 void acpi_ec_block_transactions(void)
@@ -1119,9 +1137,9 @@ static void acpi_ec_event_processor(struct work_struct *work)
 
        ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit);
 
-       spin_lock(&ec->lock);
+       spin_lock_irq(&ec->lock);
        ec->queries_in_progress--;
-       spin_unlock(&ec->lock);
+       spin_unlock_irq(&ec->lock);
 
        acpi_ec_put_query_handler(handler);
        kfree(q);
@@ -1184,12 +1202,12 @@ static int acpi_ec_submit_query(struct acpi_ec *ec)
         */
        ec_dbg_evt("Query(0x%02x) scheduled", value);
 
-       spin_lock(&ec->lock);
+       spin_lock_irq(&ec->lock);
 
        ec->queries_in_progress++;
        queue_work(ec_query_wq, &q->work);
 
-       spin_unlock(&ec->lock);
+       spin_unlock_irq(&ec->lock);
 
        return 0;
 
@@ -1205,14 +1223,14 @@ static void acpi_ec_event_handler(struct work_struct *work)
 
        ec_dbg_evt("Event started");
 
-       spin_lock(&ec->lock);
+       spin_lock_irq(&ec->lock);
 
        while (ec->events_to_process) {
-               spin_unlock(&ec->lock);
+               spin_unlock_irq(&ec->lock);
 
                acpi_ec_submit_query(ec);
 
-               spin_lock(&ec->lock);
+               spin_lock_irq(&ec->lock);
 
                ec->events_to_process--;
        }
@@ -1229,11 +1247,11 @@ static void acpi_ec_event_handler(struct work_struct *work)
 
                ec_dbg_evt("Event stopped");
 
-               spin_unlock(&ec->lock);
+               spin_unlock_irq(&ec->lock);
 
                guard_timeout = !!ec_guard(ec);
 
-               spin_lock(&ec->lock);
+               spin_lock_irq(&ec->lock);
 
                /* Take care of SCI_EVT unless someone else is doing that. */
                if (guard_timeout && !ec->curr)
@@ -1246,7 +1264,7 @@ static void acpi_ec_event_handler(struct work_struct *work)
 
        ec->events_in_progress--;
 
-       spin_unlock(&ec->lock);
+       spin_unlock_irq(&ec->lock);
 }
 
 static void clear_gpe_and_advance_transaction(struct acpi_ec *ec, bool interrupt)
@@ -1271,11 +1289,13 @@ static void clear_gpe_and_advance_transaction(struct acpi_ec *ec, bool interrupt
 
 static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
 {
-       spin_lock(&ec->lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ec->lock, flags);
 
        clear_gpe_and_advance_transaction(ec, true);
 
-       spin_unlock(&ec->lock);
+       spin_unlock_irqrestore(&ec->lock, flags);
 }
 
 static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
@@ -2085,7 +2105,7 @@ bool acpi_ec_dispatch_gpe(void)
         * Dispatch the EC GPE in-band, but do not report wakeup in any case
         * to allow the caller to process events properly after that.
         */
-       spin_lock(&first_ec->lock);
+       spin_lock_irq(&first_ec->lock);
 
        if (acpi_ec_gpe_status_set(first_ec)) {
                pm_pr_dbg("ACPI EC GPE status set\n");
@@ -2094,7 +2114,7 @@ bool acpi_ec_dispatch_gpe(void)
                work_in_progress = acpi_ec_work_in_progress(first_ec);
        }
 
-       spin_unlock(&first_ec->lock);
+       spin_unlock_irq(&first_ec->lock);
 
        if (!work_in_progress)
                return false;
@@ -2107,11 +2127,11 @@ bool acpi_ec_dispatch_gpe(void)
 
                pm_pr_dbg("ACPI EC work flushed\n");
 
-               spin_lock(&first_ec->lock);
+               spin_lock_irq(&first_ec->lock);
 
                work_in_progress = acpi_ec_work_in_progress(first_ec);
 
-               spin_unlock(&first_ec->lock);
+               spin_unlock_irq(&first_ec->lock);
        } while (work_in_progress && !pm_wakeup_pending());
 
        return false;
index da2e74fce2d995a932914876b44b3fb5d4275d2e..682ff550ccfb98381515b4821594176f5561f869 100644 (file)
@@ -671,9 +671,17 @@ MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets");
 static void ahci_pci_save_initial_config(struct pci_dev *pdev,
                                         struct ahci_host_priv *hpriv)
 {
-       if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && pdev->device == 0x1166) {
-               dev_info(&pdev->dev, "ASM1166 has only six ports\n");
-               hpriv->saved_port_map = 0x3f;
+       if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA) {
+               switch (pdev->device) {
+               case 0x1166:
+                       dev_info(&pdev->dev, "ASM1166 has only six ports\n");
+                       hpriv->saved_port_map = 0x3f;
+                       break;
+               case 0x1064:
+                       dev_info(&pdev->dev, "ASM1064 has only four ports\n");
+                       hpriv->saved_port_map = 0xf;
+                       break;
+               }
        }
 
        if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
index 64f7f7d6ba84e07c2f2db2fbbdfb3d315f821ec2..11a2c199a7c24628e858f2fc8e88e69a60c8b94b 100644 (file)
@@ -88,7 +88,6 @@ struct ceva_ahci_priv {
        u32 axicc;
        bool is_cci_enabled;
        int flags;
-       struct reset_control *rst;
 };
 
 static unsigned int ceva_ahci_read_id(struct ata_device *dev,
@@ -189,6 +188,60 @@ static const struct scsi_host_template ahci_platform_sht = {
        AHCI_SHT(DRV_NAME),
 };
 
+static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
+{
+       int rc, i;
+
+       rc = ahci_platform_enable_regulators(hpriv);
+       if (rc)
+               return rc;
+
+       rc = ahci_platform_enable_clks(hpriv);
+       if (rc)
+               goto disable_regulator;
+
+       /* Assert the controller reset */
+       rc = ahci_platform_assert_rsts(hpriv);
+       if (rc)
+               goto disable_clks;
+
+       for (i = 0; i < hpriv->nports; i++) {
+               rc = phy_init(hpriv->phys[i]);
+               if (rc)
+                       goto disable_rsts;
+       }
+
+       /* De-assert the controller reset */
+       ahci_platform_deassert_rsts(hpriv);
+
+       for (i = 0; i < hpriv->nports; i++) {
+               rc = phy_power_on(hpriv->phys[i]);
+               if (rc) {
+                       phy_exit(hpriv->phys[i]);
+                       goto disable_phys;
+               }
+       }
+
+       return 0;
+
+disable_rsts:
+       ahci_platform_deassert_rsts(hpriv);
+
+disable_phys:
+       while (--i >= 0) {
+               phy_power_off(hpriv->phys[i]);
+               phy_exit(hpriv->phys[i]);
+       }
+
+disable_clks:
+       ahci_platform_disable_clks(hpriv);
+
+disable_regulator:
+       ahci_platform_disable_regulators(hpriv);
+
+       return rc;
+}
+
 static int ceva_ahci_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -203,47 +256,19 @@ static int ceva_ahci_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        cevapriv->ahci_pdev = pdev;
-
-       cevapriv->rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
-                                                                 NULL);
-       if (IS_ERR(cevapriv->rst))
-               dev_err_probe(&pdev->dev, PTR_ERR(cevapriv->rst),
-                             "failed to get reset\n");
-
        hpriv = ahci_platform_get_resources(pdev, 0);
        if (IS_ERR(hpriv))
                return PTR_ERR(hpriv);
 
-       if (!cevapriv->rst) {
-               rc = ahci_platform_enable_resources(hpriv);
-               if (rc)
-                       return rc;
-       } else {
-               int i;
+       hpriv->rsts = devm_reset_control_get_optional_exclusive(&pdev->dev,
+                                                               NULL);
+       if (IS_ERR(hpriv->rsts))
+               return dev_err_probe(&pdev->dev, PTR_ERR(hpriv->rsts),
+                                    "failed to get reset\n");
 
-               rc = ahci_platform_enable_clks(hpriv);
-               if (rc)
-                       return rc;
-               /* Assert the controller reset */
-               reset_control_assert(cevapriv->rst);
-
-               for (i = 0; i < hpriv->nports; i++) {
-                       rc = phy_init(hpriv->phys[i]);
-                       if (rc)
-                               return rc;
-               }
-
-               /* De-assert the controller reset */
-               reset_control_deassert(cevapriv->rst);
-
-               for (i = 0; i < hpriv->nports; i++) {
-                       rc = phy_power_on(hpriv->phys[i]);
-                       if (rc) {
-                               phy_exit(hpriv->phys[i]);
-                               return rc;
-                       }
-               }
-       }
+       rc = ceva_ahci_platform_enable_resources(hpriv);
+       if (rc)
+               return rc;
 
        if (of_property_read_bool(np, "ceva,broken-gen2"))
                cevapriv->flags = CEVA_FLAG_BROKEN_GEN2;
@@ -252,52 +277,60 @@ static int ceva_ahci_probe(struct platform_device *pdev)
        if (of_property_read_u8_array(np, "ceva,p0-cominit-params",
                                        (u8 *)&cevapriv->pp2c[0], 4) < 0) {
                dev_warn(dev, "ceva,p0-cominit-params property not defined\n");
-               return -EINVAL;
+               rc = -EINVAL;
+               goto disable_resources;
        }
 
        if (of_property_read_u8_array(np, "ceva,p1-cominit-params",
                                        (u8 *)&cevapriv->pp2c[1], 4) < 0) {
                dev_warn(dev, "ceva,p1-cominit-params property not defined\n");
-               return -EINVAL;
+               rc = -EINVAL;
+               goto disable_resources;
        }
 
        /* Read OOB timing value for COMWAKE from device-tree*/
        if (of_property_read_u8_array(np, "ceva,p0-comwake-params",
                                        (u8 *)&cevapriv->pp3c[0], 4) < 0) {
                dev_warn(dev, "ceva,p0-comwake-params property not defined\n");
-               return -EINVAL;
+               rc = -EINVAL;
+               goto disable_resources;
        }
 
        if (of_property_read_u8_array(np, "ceva,p1-comwake-params",
                                        (u8 *)&cevapriv->pp3c[1], 4) < 0) {
                dev_warn(dev, "ceva,p1-comwake-params property not defined\n");
-               return -EINVAL;
+               rc = -EINVAL;
+               goto disable_resources;
        }
 
        /* Read phy BURST timing value from device-tree */
        if (of_property_read_u8_array(np, "ceva,p0-burst-params",
                                        (u8 *)&cevapriv->pp4c[0], 4) < 0) {
                dev_warn(dev, "ceva,p0-burst-params property not defined\n");
-               return -EINVAL;
+               rc = -EINVAL;
+               goto disable_resources;
        }
 
        if (of_property_read_u8_array(np, "ceva,p1-burst-params",
                                        (u8 *)&cevapriv->pp4c[1], 4) < 0) {
                dev_warn(dev, "ceva,p1-burst-params property not defined\n");
-               return -EINVAL;
+               rc = -EINVAL;
+               goto disable_resources;
        }
 
        /* Read phy RETRY interval timing value from device-tree */
        if (of_property_read_u16_array(np, "ceva,p0-retry-params",
                                        (u16 *)&cevapriv->pp5c[0], 2) < 0) {
                dev_warn(dev, "ceva,p0-retry-params property not defined\n");
-               return -EINVAL;
+               rc = -EINVAL;
+               goto disable_resources;
        }
 
        if (of_property_read_u16_array(np, "ceva,p1-retry-params",
                                        (u16 *)&cevapriv->pp5c[1], 2) < 0) {
                dev_warn(dev, "ceva,p1-retry-params property not defined\n");
-               return -EINVAL;
+               rc = -EINVAL;
+               goto disable_resources;
        }
 
        /*
@@ -335,7 +368,7 @@ static int __maybe_unused ceva_ahci_resume(struct device *dev)
        struct ahci_host_priv *hpriv = host->private_data;
        int rc;
 
-       rc = ahci_platform_enable_resources(hpriv);
+       rc = ceva_ahci_platform_enable_resources(hpriv);
        if (rc)
                return rc;
 
index 09ed67772fae492323361ab7e94f8a8d4345d2e8..be3412cdb22e78a1d663337698f07b07c66727e4 100644 (file)
@@ -2001,6 +2001,33 @@ bool ata_dev_power_init_tf(struct ata_device *dev, struct ata_taskfile *tf,
        return true;
 }
 
+static bool ata_dev_power_is_active(struct ata_device *dev)
+{
+       struct ata_taskfile tf;
+       unsigned int err_mask;
+
+       ata_tf_init(dev, &tf);
+       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+       tf.protocol = ATA_PROT_NODATA;
+       tf.command = ATA_CMD_CHK_POWER;
+
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+       if (err_mask) {
+               ata_dev_err(dev, "Check power mode failed (err_mask=0x%x)\n",
+                           err_mask);
+               /*
+                * Assume we are in standby mode so that we always force a
+                * spinup in ata_dev_power_set_active().
+                */
+               return false;
+       }
+
+       ata_dev_dbg(dev, "Power mode: 0x%02x\n", tf.nsect);
+
+       /* Active or idle */
+       return tf.nsect == 0xff;
+}
+
 /**
  *     ata_dev_power_set_standby - Set a device power mode to standby
  *     @dev: target device
@@ -2017,6 +2044,11 @@ void ata_dev_power_set_standby(struct ata_device *dev)
        struct ata_taskfile tf;
        unsigned int err_mask;
 
+       /* If the device is already sleeping or in standby, do nothing. */
+       if ((dev->flags & ATA_DFLAG_SLEEPING) ||
+           !ata_dev_power_is_active(dev))
+               return;
+
        /*
         * Some odd clown BIOSes issue spindown on power off (ACPI S4 or S5)
         * causing some drives to spin up and down again. For these, do nothing
@@ -2042,33 +2074,6 @@ void ata_dev_power_set_standby(struct ata_device *dev)
                            err_mask);
 }
 
-static bool ata_dev_power_is_active(struct ata_device *dev)
-{
-       struct ata_taskfile tf;
-       unsigned int err_mask;
-
-       ata_tf_init(dev, &tf);
-       tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
-       tf.protocol = ATA_PROT_NODATA;
-       tf.command = ATA_CMD_CHK_POWER;
-
-       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
-       if (err_mask) {
-               ata_dev_err(dev, "Check power mode failed (err_mask=0x%x)\n",
-                           err_mask);
-               /*
-                * Assume we are in standby mode so that we always force a
-                * spinup in ata_dev_power_set_active().
-                */
-               return false;
-       }
-
-       ata_dev_dbg(dev, "Power mode: 0x%02x\n", tf.nsect);
-
-       /* Active or idle */
-       return tf.nsect == 0xff;
-}
-
 /**
  *     ata_dev_power_set_active -  Set a device power mode to active
  *     @dev: target device
index 018ac202de345e9a97bc7198385c1d95d460eb28..024b78a0cfc11bbba2f0bf3c32f21d55aa101d3d 100644 (file)
@@ -431,9 +431,6 @@ init_cpu_capacity_callback(struct notifier_block *nb,
        struct cpufreq_policy *policy = data;
        int cpu;
 
-       if (!raw_capacity)
-               return 0;
-
        if (val != CPUFREQ_CREATE_POLICY)
                return 0;
 
@@ -450,9 +447,11 @@ init_cpu_capacity_callback(struct notifier_block *nb,
        }
 
        if (cpumask_empty(cpus_to_visit)) {
-               topology_normalize_cpu_scale();
-               schedule_work(&update_topology_flags_work);
-               free_raw_capacity();
+               if (raw_capacity) {
+                       topology_normalize_cpu_scale();
+                       schedule_work(&update_topology_flags_work);
+                       free_raw_capacity();
+               }
                pr_debug("cpu_capacity: parsing done\n");
                schedule_work(&parsing_done_work);
        }
@@ -472,7 +471,7 @@ static int __init register_cpufreq_notifier(void)
         * On ACPI-based systems skip registering cpufreq notifier as cpufreq
         * information is not needed for cpu capacity initialization.
         */
-       if (!acpi_disabled || !raw_capacity)
+       if (!acpi_disabled)
                return -EINVAL;
 
        if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL))
index eb4c0ace924201dfbdef7dc410c344640333f04b..0738ccad08b2e03c31696b9208200909b9de0171 100644 (file)
@@ -207,7 +207,7 @@ static inline int devtmpfs_init(void) { return 0; }
 #endif
 
 #ifdef CONFIG_BLOCK
-extern struct class block_class;
+extern const struct class block_class;
 static inline bool is_blockdev(struct device *dev)
 {
        return dev->class == &block_class;
index 14d46af40f9a15e185230eecf3bbac6ec94728ef..9828da9b933cb7511756d15ec8be2ebbd14f9e44 100644 (file)
@@ -125,7 +125,7 @@ static void __fwnode_link_del(struct fwnode_link *link)
  */
 static void __fwnode_link_cycle(struct fwnode_link *link)
 {
-       pr_debug("%pfwf: Relaxing link with %pfwf\n",
+       pr_debug("%pfwf: cycle: depends on %pfwf\n",
                 link->consumer, link->supplier);
        link->flags |= FWLINK_FLAG_CYCLE;
 }
@@ -284,10 +284,12 @@ static bool device_is_ancestor(struct device *dev, struct device *target)
        return false;
 }
 
+#define DL_MARKER_FLAGS                (DL_FLAG_INFERRED | \
+                                DL_FLAG_CYCLE | \
+                                DL_FLAG_MANAGED)
 static inline bool device_link_flag_is_sync_state_only(u32 flags)
 {
-       return (flags & ~(DL_FLAG_INFERRED | DL_FLAG_CYCLE)) ==
-               (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED);
+       return (flags & ~DL_MARKER_FLAGS) == DL_FLAG_SYNC_STATE_ONLY;
 }
 
 /**
@@ -1943,6 +1945,7 @@ static bool __fw_devlink_relax_cycles(struct device *con,
 
        /* Termination condition. */
        if (sup_dev == con) {
+               pr_debug("----- cycle: start -----\n");
                ret = true;
                goto out;
        }
@@ -1974,8 +1977,11 @@ static bool __fw_devlink_relax_cycles(struct device *con,
        else
                par_dev = fwnode_get_next_parent_dev(sup_handle);
 
-       if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode))
+       if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode)) {
+               pr_debug("%pfwf: cycle: child of %pfwf\n", sup_handle,
+                        par_dev->fwnode);
                ret = true;
+       }
 
        if (!sup_dev)
                goto out;
@@ -1991,6 +1997,8 @@ static bool __fw_devlink_relax_cycles(struct device *con,
 
                if (__fw_devlink_relax_cycles(con,
                                              dev_link->supplier->fwnode)) {
+                       pr_debug("%pfwf: cycle: depends on %pfwf\n", sup_handle,
+                                dev_link->supplier->fwnode);
                        fw_devlink_relax_link(dev_link);
                        dev_link->flags |= DL_FLAG_CYCLE;
                        ret = true;
@@ -2058,13 +2066,19 @@ static int fw_devlink_create_devlink(struct device *con,
 
        /*
         * SYNC_STATE_ONLY device links don't block probing and supports cycles.
-        * So cycle detection isn't necessary and shouldn't be done.
+        * So, one might expect that cycle detection isn't necessary for them.
+        * However, if the device link was marked as SYNC_STATE_ONLY because
+        * it's part of a cycle, then we still need to do cycle detection. This
+        * is because the consumer and supplier might be part of multiple cycles
+        * and we need to detect all those cycles.
         */
-       if (!(flags & DL_FLAG_SYNC_STATE_ONLY)) {
+       if (!device_link_flag_is_sync_state_only(flags) ||
+           flags & DL_FLAG_CYCLE) {
                device_links_write_lock();
                if (__fw_devlink_relax_cycles(con, sup_handle)) {
                        __fwnode_link_cycle(link);
                        flags = fw_devlink_get_flags(link->flags);
+                       pr_debug("----- cycle: end -----\n");
                        dev_info(con, "Fixed dependency cycle(s) with %pfwf\n",
                                 sup_handle);
                }
index 47de0f140ba65e0b9cfbff8574a8adeec69e471d..0b33e81f9c9b62d6cdd335c5638dd89f03fbc9c3 100644 (file)
@@ -588,6 +588,7 @@ CPU_SHOW_VULN_FALLBACK(mmio_stale_data);
 CPU_SHOW_VULN_FALLBACK(retbleed);
 CPU_SHOW_VULN_FALLBACK(spec_rstack_overflow);
 CPU_SHOW_VULN_FALLBACK(gds);
+CPU_SHOW_VULN_FALLBACK(reg_file_data_sampling);
 
 static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
 static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
@@ -602,6 +603,7 @@ static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL);
 static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL);
 static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL);
 static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL);
+static DEVICE_ATTR(reg_file_data_sampling, 0444, cpu_show_reg_file_data_sampling, NULL);
 
 static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_meltdown.attr,
@@ -617,6 +619,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_retbleed.attr,
        &dev_attr_spec_rstack_overflow.attr,
        &dev_attr_gather_data_sampling.attr,
+       &dev_attr_reg_file_data_sampling.attr,
        NULL
 };
 
index f37ad34c80ec486bda49b57e265299dbb37b7c60..0d01890160f3f4d0bc9bae5af2c49d44e522954c 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/msi.h>
 #include <linux/slab.h>
 
+/* Begin of removal area. Once everything is converted over. Cleanup the includes too! */
+
 #define DEV_ID_SHIFT   21
 #define MAX_DEV_MSIS   (1 << (32 - DEV_ID_SHIFT))
 
@@ -204,8 +206,8 @@ static void platform_msi_free_priv_data(struct device *dev)
  * Returns:
  * Zero for success, or an error code in case of failure
  */
-int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
-                                  irq_write_msi_msg_t write_msi_msg)
+static int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
+                                         irq_write_msi_msg_t write_msi_msg)
 {
        int err;
 
@@ -219,18 +221,6 @@ int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
 
        return err;
 }
-EXPORT_SYMBOL_GPL(platform_msi_domain_alloc_irqs);
-
-/**
- * platform_msi_domain_free_irqs - Free MSI interrupts for @dev
- * @dev:       The device for which to free interrupts
- */
-void platform_msi_domain_free_irqs(struct device *dev)
-{
-       msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);
-       platform_msi_free_priv_data(dev);
-}
-EXPORT_SYMBOL_GPL(platform_msi_domain_free_irqs);
 
 /**
  * platform_msi_get_host_data - Query the private data associated with
@@ -350,3 +340,104 @@ int platform_msi_device_domain_alloc(struct irq_domain *domain, unsigned int vir
 
        return msi_domain_populate_irqs(domain->parent, dev, virq, nr_irqs, &data->arg);
 }
+
+/* End of removal area */
+
+/* Real per device domain interfaces */
+
+/*
+ * This indirection can go when platform_device_msi_init_and_alloc_irqs()
+ * is switched to a proper irq_chip::irq_write_msi_msg() callback. Keep it
+ * simple for now.
+ */
+static void platform_msi_write_msi_msg(struct irq_data *d, struct msi_msg *msg)
+{
+       irq_write_msi_msg_t cb = d->chip_data;
+
+       cb(irq_data_get_msi_desc(d), msg);
+}
+
+static void platform_msi_set_desc_byindex(msi_alloc_info_t *arg, struct msi_desc *desc)
+{
+       arg->desc = desc;
+       arg->hwirq = desc->msi_index;
+}
+
+static const struct msi_domain_template platform_msi_template = {
+       .chip = {
+               .name                   = "pMSI",
+               .irq_mask               = irq_chip_mask_parent,
+               .irq_unmask             = irq_chip_unmask_parent,
+               .irq_write_msi_msg      = platform_msi_write_msi_msg,
+               /* The rest is filled in by the platform MSI parent */
+       },
+
+       .ops = {
+               .set_desc               = platform_msi_set_desc_byindex,
+       },
+
+       .info = {
+               .bus_token              = DOMAIN_BUS_DEVICE_MSI,
+       },
+};
+
+/**
+ * platform_device_msi_init_and_alloc_irqs - Initialize platform device MSI
+ *                                          and allocate interrupts for @dev
+ * @dev:               The device for which to allocate interrupts
+ * @nvec:              The number of interrupts to allocate
+ * @write_msi_msg:     Callback to write an interrupt message for @dev
+ *
+ * Returns:
+ * Zero for success, or an error code in case of failure
+ *
+ * This creates a MSI domain on @dev which has @dev->msi.domain as
+ * parent. The parent domain sets up the new domain. The domain has
+ * a fixed size of @nvec. The domain is managed by devres and will
+ * be removed when the device is removed.
+ *
+ * Note: For migration purposes this falls back to the original platform_msi code
+ *      up to the point where all platforms have been converted to the MSI
+ *      parent model.
+ */
+int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nvec,
+                                           irq_write_msi_msg_t write_msi_msg)
+{
+       struct irq_domain *domain = dev->msi.domain;
+
+       if (!domain || !write_msi_msg)
+               return -EINVAL;
+
+       /* Migration support. Will go away once everything is converted */
+       if (!irq_domain_is_msi_parent(domain))
+               return platform_msi_domain_alloc_irqs(dev, nvec, write_msi_msg);
+
+       /*
+        * @write_msi_msg is stored in the resulting msi_domain_info::data.
+        * The underlying domain creation mechanism will assign that
+        * callback to the resulting irq chip.
+        */
+       if (!msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN,
+                                         &platform_msi_template,
+                                         nvec, NULL, write_msi_msg))
+               return -ENODEV;
+
+       return msi_domain_alloc_irqs_range(dev, MSI_DEFAULT_DOMAIN, 0, nvec - 1);
+}
+EXPORT_SYMBOL_GPL(platform_device_msi_init_and_alloc_irqs);
+
+/**
+ * platform_device_msi_free_irqs_all - Free all interrupts for @dev
+ * @dev:       The device for which to free interrupts
+ */
+void platform_device_msi_free_irqs_all(struct device *dev)
+{
+       struct irq_domain *domain = dev->msi.domain;
+
+       msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);
+
+       /* Migration support. Will go away once everything is converted */
+       if (!irq_domain_is_msi_parent(domain))
+               platform_msi_free_priv_data(dev);
+}
+EXPORT_SYMBOL_GPL(platform_device_msi_free_irqs_all);
index 026bdcb45127f530093cb4041f734d222e2fb005..0d957c5f1bcc987a585abaad9ed53623c33b4189 100644 (file)
@@ -9,6 +9,23 @@
 
 #define BLOCK_TEST_SIZE 12
 
+static void get_changed_bytes(void *orig, void *new, size_t size)
+{
+       char *o = orig;
+       char *n = new;
+       int i;
+
+       get_random_bytes(new, size);
+
+       /*
+        * This could be nicer and more efficient but we shouldn't
+        * super care.
+        */
+       for (i = 0; i < size; i++)
+               while (n[i] == o[i])
+                       get_random_bytes(&n[i], 1);
+}
+
 static const struct regmap_config test_regmap_config = {
        .max_register = BLOCK_TEST_SIZE,
        .reg_stride = 1,
@@ -1202,7 +1219,8 @@ static void raw_noinc_write(struct kunit *test)
        struct regmap *map;
        struct regmap_config config;
        struct regmap_ram_data *data;
-       unsigned int val, val_test, val_last;
+       unsigned int val;
+       u16 val_test, val_last;
        u16 val_array[BLOCK_TEST_SIZE];
 
        config = raw_regmap_config;
@@ -1251,7 +1269,7 @@ static void raw_sync(struct kunit *test)
        struct regmap *map;
        struct regmap_config config;
        struct regmap_ram_data *data;
-       u16 val[2];
+       u16 val[3];
        u16 *hw_buf;
        unsigned int rval;
        int i;
@@ -1265,17 +1283,13 @@ static void raw_sync(struct kunit *test)
 
        hw_buf = (u16 *)data->vals;
 
-       get_random_bytes(&val, sizeof(val));
+       get_changed_bytes(&hw_buf[2], &val[0], sizeof(val));
 
        /* Do a regular write and a raw write in cache only mode */
        regcache_cache_only(map, true);
-       KUNIT_EXPECT_EQ(test, 0, regmap_raw_write(map, 2, val, sizeof(val)));
-       if (config.val_format_endian == REGMAP_ENDIAN_BIG)
-               KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 6,
-                                                     be16_to_cpu(val[0])));
-       else
-               KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 6,
-                                                     le16_to_cpu(val[0])));
+       KUNIT_EXPECT_EQ(test, 0, regmap_raw_write(map, 2, val,
+                                                 sizeof(u16) * 2));
+       KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 4, val[2]));
 
        /* We should read back the new values, and defaults for the rest */
        for (i = 0; i < config.max_register + 1; i++) {
@@ -1284,24 +1298,34 @@ static void raw_sync(struct kunit *test)
                switch (i) {
                case 2:
                case 3:
-               case 6:
                        if (config.val_format_endian == REGMAP_ENDIAN_BIG) {
                                KUNIT_EXPECT_EQ(test, rval,
-                                               be16_to_cpu(val[i % 2]));
+                                               be16_to_cpu(val[i - 2]));
                        } else {
                                KUNIT_EXPECT_EQ(test, rval,
-                                               le16_to_cpu(val[i % 2]));
+                                               le16_to_cpu(val[i - 2]));
                        }
                        break;
+               case 4:
+                       KUNIT_EXPECT_EQ(test, rval, val[i - 2]);
+                       break;
                default:
                        KUNIT_EXPECT_EQ(test, config.reg_defaults[i].def, rval);
                        break;
                }
        }
+
+       /*
+        * The value written via _write() was translated by the core,
+        * translate the original copy for comparison purposes.
+        */
+       if (config.val_format_endian == REGMAP_ENDIAN_BIG)
+               val[2] = cpu_to_be16(val[2]);
+       else
+               val[2] = cpu_to_le16(val[2]);
        
        /* The values should not appear in the "hardware" */
-       KUNIT_EXPECT_MEMNEQ(test, &hw_buf[2], val, sizeof(val));
-       KUNIT_EXPECT_MEMNEQ(test, &hw_buf[6], val, sizeof(u16));
+       KUNIT_EXPECT_MEMNEQ(test, &hw_buf[2], &val[0], sizeof(val));
 
        for (i = 0; i < config.max_register + 1; i++)
                data->written[i] = false;
@@ -1312,8 +1336,7 @@ static void raw_sync(struct kunit *test)
        KUNIT_EXPECT_EQ(test, 0, regcache_sync(map));
 
        /* The values should now appear in the "hardware" */
-       KUNIT_EXPECT_MEMEQ(test, &hw_buf[2], val, sizeof(val));
-       KUNIT_EXPECT_MEMEQ(test, &hw_buf[6], val, sizeof(u16));
+       KUNIT_EXPECT_MEMEQ(test, &hw_buf[2], &val[0], sizeof(val));
 
        regmap_exit(map);
 }
index 2b98114a9fe0926d8b79021ff60e5d92dd2b8e37..a25414228e47410fe7756e5cc434fe2b0f53115d 100644 (file)
@@ -1779,7 +1779,7 @@ static int fd_alloc_disk(int drive, int system)
        struct gendisk *disk;
        int err;
 
-       disk = blk_mq_alloc_disk(&unit[drive].tag_set, NULL);
+       disk = blk_mq_alloc_disk(&unit[drive].tag_set, NULL, NULL);
        if (IS_ERR(disk))
                return PTR_ERR(disk);
 
index b1b47d88f5db44dd9dcb8fc7468718ac36869130..b6dac8cee70fe13a49a7699727e47f13a27be91c 100644 (file)
@@ -24,8 +24,8 @@ static DEFINE_MUTEX(aoeblk_mutex);
 static struct kmem_cache *buf_pool_cache;
 static struct dentry *aoe_debugfs_dir;
 
-/* GPFS needs a larger value than the default. */
-static int aoe_maxsectors;
+/* random default picked from the historic block max_sectors cap */
+static int aoe_maxsectors = 2560;
 module_param(aoe_maxsectors, int, 0644);
 MODULE_PARM_DESC(aoe_maxsectors,
        "When nonzero, set the maximum number of sectors per I/O request");
@@ -334,6 +334,10 @@ aoeblk_gdalloc(void *vp)
        mempool_t *mp;
        struct blk_mq_tag_set *set;
        sector_t ssize;
+       struct queue_limits lim = {
+               .max_hw_sectors         = aoe_maxsectors,
+               .io_opt                 = SZ_2M,
+       };
        ulong flags;
        int late = 0;
        int err;
@@ -371,7 +375,7 @@ aoeblk_gdalloc(void *vp)
                goto err_mempool;
        }
 
-       gd = blk_mq_alloc_disk(set, d);
+       gd = blk_mq_alloc_disk(set, &lim, d);
        if (IS_ERR(gd)) {
                pr_err("aoe: cannot allocate block queue for %ld.%d\n",
                        d->aoemajor, d->aoeminor);
@@ -384,14 +388,9 @@ aoeblk_gdalloc(void *vp)
        WARN_ON(d->flags & DEVFL_TKILL);
        WARN_ON(d->gd);
        WARN_ON(d->flags & DEVFL_UP);
-       /* random number picked from the history block max_sectors cap */
-       blk_queue_max_hw_sectors(gd->queue, 2560u);
-       blk_queue_io_opt(gd->queue, SZ_2M);
        d->bufpool = mp;
        d->blkq = gd->queue;
        d->gd = gd;
-       if (aoe_maxsectors)
-               blk_queue_max_hw_sectors(gd->queue, aoe_maxsectors);
        gd->major = AOE_MAJOR;
        gd->first_minor = d->sysminor;
        gd->minors = AOE_PARTITIONS;
index d7317425be510d1c3d4bbac5a18fba2ea8e76c1d..cc9077b588d7e7af30401ab03c826a358b2a232c 100644 (file)
@@ -419,13 +419,16 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *qu
        rcu_read_lock();
        for_each_netdev_rcu(&init_net, ifp) {
                dev_hold(ifp);
-               if (!is_aoe_netif(ifp))
-                       goto cont;
+               if (!is_aoe_netif(ifp)) {
+                       dev_put(ifp);
+                       continue;
+               }
 
                skb = new_skb(sizeof *h + sizeof *ch);
                if (skb == NULL) {
                        printk(KERN_INFO "aoe: skb alloc failure\n");
-                       goto cont;
+                       dev_put(ifp);
+                       continue;
                }
                skb_put(skb, sizeof *h + sizeof *ch);
                skb->dev = ifp;
@@ -440,9 +443,6 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *qu
                h->major = cpu_to_be16(aoemajor);
                h->minor = aoeminor;
                h->cmd = AOECMD_CFG;
-
-cont:
-               dev_put(ifp);
        }
        rcu_read_unlock();
 }
index c51ea95bc2ce41f6260302f5efe914d3e12e1d98..923a134fd766562fcf9d33a993739040517258c1 100644 (file)
@@ -63,6 +63,7 @@ tx(int id) __must_hold(&txlock)
                        pr_warn("aoe: packet could not be sent on %s.  %s\n",
                                ifp ? ifp->name : "netif",
                                "consider increasing tx_queue_len");
+               dev_put(ifp);
                spin_lock_irq(&txlock);
        }
        return 0;
index 50949207798d2a27a3fb6c86e94c5afd490ff5d6..cacc4ba942a814015fa82e592c8f946340a5a577 100644 (file)
@@ -1994,7 +1994,7 @@ static int ataflop_alloc_disk(unsigned int drive, unsigned int type)
 {
        struct gendisk *disk;
 
-       disk = blk_mq_alloc_disk(&unit[drive].tag_set, NULL);
+       disk = blk_mq_alloc_disk(&unit[drive].tag_set, NULL, NULL);
        if (IS_ERR(disk))
                return PTR_ERR(disk);
 
index 970bd6ff38c491a610f65026817f5c076aed8285..e322cef6596bfaa2f1cbf6de1f275a804670d49b 100644 (file)
@@ -318,6 +318,16 @@ static int brd_alloc(int i)
        struct gendisk *disk;
        char buf[DISK_NAME_LEN];
        int err = -ENOMEM;
+       struct queue_limits lim = {
+               /*
+                * This is so fdisk will align partitions on 4k, because of
+                * direct_access API needing 4k alignment, returning a PFN
+                * (This is only a problem on very small devices <= 4M,
+                *  otherwise fdisk will align on 1M. Regardless this call
+                *  is harmless)
+                */
+               .physical_block_size    = PAGE_SIZE,
+       };
 
        list_for_each_entry(brd, &brd_devices, brd_list)
                if (brd->brd_number == i)
@@ -335,10 +345,11 @@ static int brd_alloc(int i)
                debugfs_create_u64(buf, 0444, brd_debugfs_dir,
                                &brd->brd_nr_pages);
 
-       disk = brd->brd_disk = blk_alloc_disk(NUMA_NO_NODE);
-       if (!disk)
+       disk = brd->brd_disk = blk_alloc_disk(&lim, NUMA_NO_NODE);
+       if (IS_ERR(disk)) {
+               err = PTR_ERR(disk);
                goto out_free_dev;
-
+       }
        disk->major             = RAMDISK_MAJOR;
        disk->first_minor       = i * max_part;
        disk->minors            = max_part;
@@ -347,15 +358,6 @@ static int brd_alloc(int i)
        strscpy(disk->disk_name, buf, DISK_NAME_LEN);
        set_capacity(disk, rd_size * 2);
        
-       /*
-        * This is so fdisk will align partitions on 4k, because of
-        * direct_access API needing 4k alignment, returning a PFN
-        * (This is only a problem on very small devices <= 4M,
-        *  otherwise fdisk will align on 1M. Regardless this call
-        *  is harmless)
-        */
-       blk_queue_physical_block_size(disk->queue, PAGE_SIZE);
-
        /* Tell the block layer that this is not a rotational device */
        blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue);
        blk_queue_flag_set(QUEUE_FLAG_SYNCHRONOUS, disk->queue);
index c21e3732759ec21069939f43ca944e044ea95095..94dc0a235919d755a788f758150ba80c66635910 100644 (file)
@@ -524,9 +524,9 @@ struct drbd_md {
 
 struct drbd_backing_dev {
        struct block_device *backing_bdev;
-       struct bdev_handle *backing_bdev_handle;
+       struct file *backing_bdev_file;
        struct block_device *md_bdev;
-       struct bdev_handle *md_bdev_handle;
+       struct file *f_md_bdev;
        struct drbd_md md;
        struct disk_conf *disk_conf; /* RCU, for updates: resource->conf_update */
        sector_t known_size; /* last known size of that backing device */
index 6bc86106c7b2ab5d59b6ab66e452976d235a7d97..113b441d4d3670c15f2b10c85b0ec6f82c7ab002 100644 (file)
@@ -2690,6 +2690,14 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
        int id;
        int vnr = adm_ctx->volume;
        enum drbd_ret_code err = ERR_NOMEM;
+       struct queue_limits lim = {
+               /*
+                * Setting the max_hw_sectors to an odd value of 8kibyte here.
+                * This triggers a max_bio_size message upon first attach or
+                * connect.
+                */
+               .max_hw_sectors         = DRBD_MAX_BIO_SIZE_SAFE >> 8,
+       };
 
        device = minor_to_device(minor);
        if (device)
@@ -2708,9 +2716,11 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
 
        drbd_init_set_defaults(device);
 
-       disk = blk_alloc_disk(NUMA_NO_NODE);
-       if (!disk)
+       disk = blk_alloc_disk(&lim, NUMA_NO_NODE);
+       if (IS_ERR(disk)) {
+               err = PTR_ERR(disk);
                goto out_no_disk;
+       }
 
        device->vdisk = disk;
        device->rq_queue = disk->queue;
@@ -2727,9 +2737,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
 
        blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, disk->queue);
        blk_queue_write_cache(disk->queue, true, true);
-       /* Setting the max_hw_sectors to an odd value of 8kibyte here
-          This triggers a max_bio_size message upon first attach or connect */
-       blk_queue_max_hw_sectors(disk->queue, DRBD_MAX_BIO_SIZE_SAFE >> 8);
 
        device->md_io.page = alloc_page(GFP_KERNEL);
        if (!device->md_io.page)
index 43747a1aae43537a1e578ce41949af3711a3bd3c..5d65c9754d8377e60f59228f7abb2eac9669a439 100644 (file)
@@ -1189,9 +1189,31 @@ static int drbd_check_al_size(struct drbd_device *device, struct disk_conf *dc)
        return 0;
 }
 
-static void blk_queue_discard_granularity(struct request_queue *q, unsigned int granularity)
+static unsigned int drbd_max_peer_bio_size(struct drbd_device *device)
 {
-       q->limits.discard_granularity = granularity;
+       /*
+        * We may ignore peer limits if the peer is modern enough.  From 8.3.8
+        * onwards the peer can use multiple BIOs for a single peer_request.
+        */
+       if (device->state.conn < C_WF_REPORT_PARAMS)
+               return device->peer_max_bio_size;
+
+       if (first_peer_device(device)->connection->agreed_pro_version < 94)
+               return min(device->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
+
+       /*
+        * Correct old drbd (up to 8.3.7) if it believes it can do more than
+        * 32KiB.
+        */
+       if (first_peer_device(device)->connection->agreed_pro_version == 94)
+               return DRBD_MAX_SIZE_H80_PACKET;
+
+       /*
+        * drbd 8.3.8 onwards, before 8.4.0
+        */
+       if (first_peer_device(device)->connection->agreed_pro_version < 100)
+               return DRBD_MAX_BIO_SIZE_P95;
+       return DRBD_MAX_BIO_SIZE;
 }
 
 static unsigned int drbd_max_discard_sectors(struct drbd_connection *connection)
@@ -1204,149 +1226,119 @@ static unsigned int drbd_max_discard_sectors(struct drbd_connection *connection)
        return AL_EXTENT_SIZE >> 9;
 }
 
-static void decide_on_discard_support(struct drbd_device *device,
+static bool drbd_discard_supported(struct drbd_connection *connection,
                struct drbd_backing_dev *bdev)
 {
-       struct drbd_connection *connection =
-               first_peer_device(device)->connection;
-       struct request_queue *q = device->rq_queue;
-       unsigned int max_discard_sectors;
-
        if (bdev && !bdev_max_discard_sectors(bdev->backing_bdev))
-               goto not_supported;
+               return false;
 
        if (connection->cstate >= C_CONNECTED &&
            !(connection->agreed_features & DRBD_FF_TRIM)) {
                drbd_info(connection,
                        "peer DRBD too old, does not support TRIM: disabling discards\n");
-               goto not_supported;
+               return false;
        }
 
-       /*
-        * We don't care for the granularity, really.
-        *
-        * Stacking limits below should fix it for the local device.  Whether or
-        * not it is a suitable granularity on the remote device is not our
-        * problem, really. If you care, you need to use devices with similar
-        * topology on all peers.
-        */
-       blk_queue_discard_granularity(q, 512);
-       max_discard_sectors = drbd_max_discard_sectors(connection);
-       blk_queue_max_discard_sectors(q, max_discard_sectors);
-       blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
-       return;
-
-not_supported:
-       blk_queue_discard_granularity(q, 0);
-       blk_queue_max_discard_sectors(q, 0);
+       return true;
 }
 
-static void fixup_write_zeroes(struct drbd_device *device, struct request_queue *q)
+/* This is the workaround for "bio would need to, but cannot, be split" */
+static unsigned int drbd_backing_dev_max_segments(struct drbd_device *device)
 {
-       /* Fixup max_write_zeroes_sectors after blk_stack_limits():
-        * if we can handle "zeroes" efficiently on the protocol,
-        * we want to do that, even if our backend does not announce
-        * max_write_zeroes_sectors itself. */
-       struct drbd_connection *connection = first_peer_device(device)->connection;
-       /* If the peer announces WZEROES support, use it.  Otherwise, rather
-        * send explicit zeroes than rely on some discard-zeroes-data magic. */
-       if (connection->agreed_features & DRBD_FF_WZEROES)
-               q->limits.max_write_zeroes_sectors = DRBD_MAX_BBIO_SECTORS;
-       else
-               q->limits.max_write_zeroes_sectors = 0;
-}
+       unsigned int max_segments;
 
-static void fixup_discard_support(struct drbd_device *device, struct request_queue *q)
-{
-       unsigned int max_discard = device->rq_queue->limits.max_discard_sectors;
-       unsigned int discard_granularity =
-               device->rq_queue->limits.discard_granularity >> SECTOR_SHIFT;
+       rcu_read_lock();
+       max_segments = rcu_dereference(device->ldev->disk_conf)->max_bio_bvecs;
+       rcu_read_unlock();
 
-       if (discard_granularity > max_discard) {
-               blk_queue_discard_granularity(q, 0);
-               blk_queue_max_discard_sectors(q, 0);
-       }
+       if (!max_segments)
+               return BLK_MAX_SEGMENTS;
+       return max_segments;
 }
 
-static void drbd_setup_queue_param(struct drbd_device *device, struct drbd_backing_dev *bdev,
-                                  unsigned int max_bio_size, struct o_qlim *o)
+void drbd_reconsider_queue_parameters(struct drbd_device *device,
+               struct drbd_backing_dev *bdev, struct o_qlim *o)
 {
+       struct drbd_connection *connection =
+               first_peer_device(device)->connection;
        struct request_queue * const q = device->rq_queue;
-       unsigned int max_hw_sectors = max_bio_size >> 9;
-       unsigned int max_segments = 0;
+       unsigned int now = queue_max_hw_sectors(q) << 9;
+       struct queue_limits lim;
        struct request_queue *b = NULL;
-       struct disk_conf *dc;
+       unsigned int new;
 
        if (bdev) {
                b = bdev->backing_bdev->bd_disk->queue;
 
-               max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
-               rcu_read_lock();
-               dc = rcu_dereference(device->ldev->disk_conf);
-               max_segments = dc->max_bio_bvecs;
-               rcu_read_unlock();
-
-               blk_set_stacking_limits(&q->limits);
+               device->local_max_bio_size =
+                       queue_max_hw_sectors(b) << SECTOR_SHIFT;
        }
 
-       blk_queue_max_hw_sectors(q, max_hw_sectors);
-       /* This is the workaround for "bio would need to, but cannot, be split" */
-       blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS);
-       blk_queue_segment_boundary(q, PAGE_SIZE-1);
-       decide_on_discard_support(device, bdev);
-
-       if (b) {
-               blk_stack_limits(&q->limits, &b->limits, 0);
-               disk_update_readahead(device->vdisk);
+       /*
+        * We may later detach and re-attach on a disconnected Primary.  Avoid
+        * decreasing the value in this case.
+        *
+        * We want to store what we know the peer DRBD can handle, not what the
+        * peer IO backend can handle.
+        */
+       new = min3(DRBD_MAX_BIO_SIZE, device->local_max_bio_size,
+               max(drbd_max_peer_bio_size(device), device->peer_max_bio_size));
+       if (new != now) {
+               if (device->state.role == R_PRIMARY && new < now)
+                       drbd_err(device, "ASSERT FAILED new < now; (%u < %u)\n",
+                                       new, now);
+               drbd_info(device, "max BIO size = %u\n", new);
        }
-       fixup_write_zeroes(device, q);
-       fixup_discard_support(device, q);
-}
-
-void drbd_reconsider_queue_parameters(struct drbd_device *device, struct drbd_backing_dev *bdev, struct o_qlim *o)
-{
-       unsigned int now, new, local, peer;
-
-       now = queue_max_hw_sectors(device->rq_queue) << 9;
-       local = device->local_max_bio_size; /* Eventually last known value, from volatile memory */
-       peer = device->peer_max_bio_size; /* Eventually last known value, from meta data */
 
+       lim = queue_limits_start_update(q);
        if (bdev) {
-               local = queue_max_hw_sectors(bdev->backing_bdev->bd_disk->queue) << 9;
-               device->local_max_bio_size = local;
+               blk_set_stacking_limits(&lim);
+               lim.max_segments = drbd_backing_dev_max_segments(device);
+       } else {
+               lim.max_segments = BLK_MAX_SEGMENTS;
        }
-       local = min(local, DRBD_MAX_BIO_SIZE);
 
-       /* We may ignore peer limits if the peer is modern enough.
-          Because new from 8.3.8 onwards the peer can use multiple
-          BIOs for a single peer_request */
-       if (device->state.conn >= C_WF_REPORT_PARAMS) {
-               if (first_peer_device(device)->connection->agreed_pro_version < 94)
-                       peer = min(device->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
-                       /* Correct old drbd (up to 8.3.7) if it believes it can do more than 32KiB */
-               else if (first_peer_device(device)->connection->agreed_pro_version == 94)
-                       peer = DRBD_MAX_SIZE_H80_PACKET;
-               else if (first_peer_device(device)->connection->agreed_pro_version < 100)
-                       peer = DRBD_MAX_BIO_SIZE_P95;  /* drbd 8.3.8 onwards, before 8.4.0 */
-               else
-                       peer = DRBD_MAX_BIO_SIZE;
+       lim.max_hw_sectors = new >> SECTOR_SHIFT;
+       lim.seg_boundary_mask = PAGE_SIZE - 1;
 
-               /* We may later detach and re-attach on a disconnected Primary.
-                * Avoid this setting to jump back in that case.
-                * We want to store what we know the peer DRBD can handle,
-                * not what the peer IO backend can handle. */
-               if (peer > device->peer_max_bio_size)
-                       device->peer_max_bio_size = peer;
+       /*
+        * We don't care for the granularity, really.
+        *
+        * Stacking limits below should fix it for the local device.  Whether or
+        * not it is a suitable granularity on the remote device is not our
+        * problem, really. If you care, you need to use devices with similar
+        * topology on all peers.
+        */
+       if (drbd_discard_supported(connection, bdev)) {
+               lim.discard_granularity = 512;
+               lim.max_hw_discard_sectors =
+                       drbd_max_discard_sectors(connection);
+       } else {
+               lim.discard_granularity = 0;
+               lim.max_hw_discard_sectors = 0;
        }
-       new = min(local, peer);
 
-       if (device->state.role == R_PRIMARY && new < now)
-               drbd_err(device, "ASSERT FAILED new < now; (%u < %u)\n", new, now);
+       if (bdev)
+               blk_stack_limits(&lim, &b->limits, 0);
 
-       if (new != now)
-               drbd_info(device, "max BIO size = %u\n", new);
+       /*
+        * If we can handle "zeroes" efficiently on the protocol, we want to do
+        * that, even if our backend does not announce max_write_zeroes_sectors
+        * itself.
+        */
+       if (connection->agreed_features & DRBD_FF_WZEROES)
+               lim.max_write_zeroes_sectors = DRBD_MAX_BBIO_SECTORS;
+       else
+               lim.max_write_zeroes_sectors = 0;
+
+       if ((lim.discard_granularity >> SECTOR_SHIFT) >
+           lim.max_hw_discard_sectors) {
+               lim.discard_granularity = 0;
+               lim.max_hw_discard_sectors = 0;
+       }
 
-       drbd_setup_queue_param(device, bdev, new, o);
+       if (queue_limits_commit_update(q, &lim))
+               drbd_err(device, "setting new queue limits failed\n");
 }
 
 /* Starts the worker thread */
@@ -1635,45 +1627,45 @@ success:
        return 0;
 }
 
-static struct bdev_handle *open_backing_dev(struct drbd_device *device,
+static struct file *open_backing_dev(struct drbd_device *device,
                const char *bdev_path, void *claim_ptr, bool do_bd_link)
 {
-       struct bdev_handle *handle;
+       struct file *file;
        int err = 0;
 
-       handle = bdev_open_by_path(bdev_path, BLK_OPEN_READ | BLK_OPEN_WRITE,
-                                  claim_ptr, NULL);
-       if (IS_ERR(handle)) {
+       file = bdev_file_open_by_path(bdev_path, BLK_OPEN_READ | BLK_OPEN_WRITE,
+                                     claim_ptr, NULL);
+       if (IS_ERR(file)) {
                drbd_err(device, "open(\"%s\") failed with %ld\n",
-                               bdev_path, PTR_ERR(handle));
-               return handle;
+                               bdev_path, PTR_ERR(file));
+               return file;
        }
 
        if (!do_bd_link)
-               return handle;
+               return file;
 
-       err = bd_link_disk_holder(handle->bdev, device->vdisk);
+       err = bd_link_disk_holder(file_bdev(file), device->vdisk);
        if (err) {
-               bdev_release(handle);
+               fput(file);
                drbd_err(device, "bd_link_disk_holder(\"%s\", ...) failed with %d\n",
                                bdev_path, err);
-               handle = ERR_PTR(err);
+               file = ERR_PTR(err);
        }
-       return handle;
+       return file;
 }
 
 static int open_backing_devices(struct drbd_device *device,
                struct disk_conf *new_disk_conf,
                struct drbd_backing_dev *nbc)
 {
-       struct bdev_handle *handle;
+       struct file *file;
 
-       handle = open_backing_dev(device, new_disk_conf->backing_dev, device,
+       file = open_backing_dev(device, new_disk_conf->backing_dev, device,
                                  true);
-       if (IS_ERR(handle))
+       if (IS_ERR(file))
                return ERR_OPEN_DISK;
-       nbc->backing_bdev = handle->bdev;
-       nbc->backing_bdev_handle = handle;
+       nbc->backing_bdev = file_bdev(file);
+       nbc->backing_bdev_file = file;
 
        /*
         * meta_dev_idx >= 0: external fixed size, possibly multiple
@@ -1683,7 +1675,7 @@ static int open_backing_devices(struct drbd_device *device,
         * should check it for you already; but if you don't, or
         * someone fooled it, we need to double check here)
         */
-       handle = open_backing_dev(device, new_disk_conf->meta_dev,
+       file = open_backing_dev(device, new_disk_conf->meta_dev,
                /* claim ptr: device, if claimed exclusively; shared drbd_m_holder,
                 * if potentially shared with other drbd minors */
                        (new_disk_conf->meta_dev_idx < 0) ? (void*)device : (void*)drbd_m_holder,
@@ -1691,21 +1683,21 @@ static int open_backing_devices(struct drbd_device *device,
                 * as would happen with internal metadata. */
                        (new_disk_conf->meta_dev_idx != DRBD_MD_INDEX_FLEX_INT &&
                         new_disk_conf->meta_dev_idx != DRBD_MD_INDEX_INTERNAL));
-       if (IS_ERR(handle))
+       if (IS_ERR(file))
                return ERR_OPEN_MD_DISK;
-       nbc->md_bdev = handle->bdev;
-       nbc->md_bdev_handle = handle;
+       nbc->md_bdev = file_bdev(file);
+       nbc->f_md_bdev = file;
        return NO_ERROR;
 }
 
 static void close_backing_dev(struct drbd_device *device,
-               struct bdev_handle *handle, bool do_bd_unlink)
+               struct file *bdev_file, bool do_bd_unlink)
 {
-       if (!handle)
+       if (!bdev_file)
                return;
        if (do_bd_unlink)
-               bd_unlink_disk_holder(handle->bdev, device->vdisk);
-       bdev_release(handle);
+               bd_unlink_disk_holder(file_bdev(bdev_file), device->vdisk);
+       fput(bdev_file);
 }
 
 void drbd_backing_dev_free(struct drbd_device *device, struct drbd_backing_dev *ldev)
@@ -1713,9 +1705,9 @@ void drbd_backing_dev_free(struct drbd_device *device, struct drbd_backing_dev *
        if (ldev == NULL)
                return;
 
-       close_backing_dev(device, ldev->md_bdev_handle,
+       close_backing_dev(device, ldev->f_md_bdev,
                          ldev->md_bdev != ldev->backing_bdev);
-       close_backing_dev(device, ldev->backing_bdev_handle, true);
+       close_backing_dev(device, ldev->backing_bdev_file, true);
 
        kfree(ldev->disk_conf);
        kfree(ldev);
@@ -2131,9 +2123,9 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
  fail:
        conn_reconfig_done(connection);
        if (nbc) {
-               close_backing_dev(device, nbc->md_bdev_handle,
+               close_backing_dev(device, nbc->f_md_bdev,
                          nbc->md_bdev != nbc->backing_bdev);
-               close_backing_dev(device, nbc->backing_bdev_handle, true);
+               close_backing_dev(device, nbc->backing_bdev_file, true);
                kfree(nbc);
        }
        kfree(new_disk_conf);
index 287a8d1d3f707f217c2e715c62decb4e83e27d1f..e858e7e0383f262fa0bf412c5867ee6832ffcb64 100644 (file)
@@ -1542,9 +1542,10 @@ int drbd_bitmap_io_from_worker(struct drbd_device *device,
 
 int notify_resource_state_change(struct sk_buff *skb,
                                  unsigned int seq,
-                                 struct drbd_resource_state_change *resource_state_change,
+                                 void *state_change,
                                  enum drbd_notification_type type)
 {
+       struct drbd_resource_state_change *resource_state_change = state_change;
        struct drbd_resource *resource = resource_state_change->resource;
        struct resource_info resource_info = {
                .res_role = resource_state_change->role[NEW],
@@ -1558,13 +1559,14 @@ int notify_resource_state_change(struct sk_buff *skb,
 
 int notify_connection_state_change(struct sk_buff *skb,
                                    unsigned int seq,
-                                   struct drbd_connection_state_change *connection_state_change,
+                                   void *state_change,
                                    enum drbd_notification_type type)
 {
-       struct drbd_connection *connection = connection_state_change->connection;
+       struct drbd_connection_state_change *p = state_change;
+       struct drbd_connection *connection = p->connection;
        struct connection_info connection_info = {
-               .conn_connection_state = connection_state_change->cstate[NEW],
-               .conn_role = connection_state_change->peer_role[NEW],
+               .conn_connection_state = p->cstate[NEW],
+               .conn_role = p->peer_role[NEW],
        };
 
        return notify_connection_state(skb, seq, connection, &connection_info, type);
@@ -1572,9 +1574,10 @@ int notify_connection_state_change(struct sk_buff *skb,
 
 int notify_device_state_change(struct sk_buff *skb,
                                unsigned int seq,
-                               struct drbd_device_state_change *device_state_change,
+                               void *state_change,
                                enum drbd_notification_type type)
 {
+       struct drbd_device_state_change *device_state_change = state_change;
        struct drbd_device *device = device_state_change->device;
        struct device_info device_info = {
                .dev_disk_state = device_state_change->disk_state[NEW],
@@ -1585,9 +1588,10 @@ int notify_device_state_change(struct sk_buff *skb,
 
 int notify_peer_device_state_change(struct sk_buff *skb,
                                     unsigned int seq,
-                                    struct drbd_peer_device_state_change *p,
+                                    void *state_change,
                                     enum drbd_notification_type type)
 {
+       struct drbd_peer_device_state_change *p = state_change;
        struct drbd_peer_device *peer_device = p->peer_device;
        struct peer_device_info peer_device_info = {
                .peer_repl_state = p->repl_state[NEW],
@@ -1605,8 +1609,8 @@ static void broadcast_state_change(struct drbd_state_change *state_change)
        struct drbd_resource_state_change *resource_state_change = &state_change->resource[0];
        bool resource_state_has_changed;
        unsigned int n_device, n_connection, n_peer_device, n_peer_devices;
-       int (*last_func)(struct sk_buff *, unsigned int, void *,
-                         enum drbd_notification_type) = NULL;
+       int (*last_func)(struct sk_buff *, unsigned int,
+               void *, enum drbd_notification_type) = NULL;
        void *last_arg = NULL;
 
 #define HAS_CHANGED(state) ((state)[OLD] != (state)[NEW])
@@ -1616,7 +1620,7 @@ static void broadcast_state_change(struct drbd_state_change *state_change)
        })
 #define REMEMBER_STATE_CHANGE(func, arg, type) \
        ({ FINAL_STATE_CHANGE(type | NOTIFY_CONTINUES); \
-          last_func = (typeof(last_func))func; \
+          last_func = func; \
           last_arg = arg; \
         })
 
index 9d78d8e3912eee6d581a2a70dc683665a2b91e97..a56a57d67686291a8fd6401b28a1a70473d336c2 100644 (file)
@@ -46,19 +46,19 @@ extern void forget_state_change(struct drbd_state_change *);
 
 extern int notify_resource_state_change(struct sk_buff *,
                                         unsigned int,
-                                        struct drbd_resource_state_change *,
+                                        void *,
                                         enum drbd_notification_type type);
 extern int notify_connection_state_change(struct sk_buff *,
                                           unsigned int,
-                                          struct drbd_connection_state_change *,
+                                          void *,
                                           enum drbd_notification_type type);
 extern int notify_device_state_change(struct sk_buff *,
                                       unsigned int,
-                                      struct drbd_device_state_change *,
+                                      void *,
                                       enum drbd_notification_type type);
 extern int notify_peer_device_state_change(struct sk_buff *,
                                            unsigned int,
-                                           struct drbd_peer_device_state_change *,
+                                           void *,
                                            enum drbd_notification_type type);
 
 #endif  /* DRBD_STATE_CHANGE_H */
index d0e41d52d6a9b58474c52edd7f5dc23f9a0c19c1..1b399ec8c07d1e7027a759051b18187dde83ab1e 100644 (file)
@@ -530,14 +530,13 @@ static struct format_descr format_req;
 static char *floppy_track_buffer;
 static int max_buffer_sectors;
 
-typedef void (*done_f)(int);
 static const struct cont_t {
        void (*interrupt)(void);
                                /* this is called after the interrupt of the
                                 * main command */
        void (*redo)(void);     /* this is called to retry the operation */
        void (*error)(void);    /* this is called to tally an error */
-       done_f done;            /* this is called to say if the operation has
+       void (*done)(int);      /* this is called to say if the operation has
                                 * succeeded/failed */
 } *cont;
 
@@ -985,6 +984,10 @@ static void empty(void)
 {
 }
 
+static void empty_done(int result)
+{
+}
+
 static void (*floppy_work_fn)(void);
 
 static void floppy_work_workfn(struct work_struct *work)
@@ -1998,14 +2001,14 @@ static const struct cont_t wakeup_cont = {
        .interrupt      = empty,
        .redo           = do_wakeup,
        .error          = empty,
-       .done           = (done_f)empty
+       .done           = empty_done,
 };
 
 static const struct cont_t intr_cont = {
        .interrupt      = empty,
        .redo           = process_fd_request,
        .error          = empty,
-       .done           = (done_f)empty
+       .done           = empty_done,
 };
 
 /* schedules handler, waiting for completion. May be interrupted, will then
@@ -4513,13 +4516,15 @@ static bool floppy_available(int drive)
 
 static int floppy_alloc_disk(unsigned int drive, unsigned int type)
 {
+       struct queue_limits lim = {
+               .max_hw_sectors = 64,
+       };
        struct gendisk *disk;
 
-       disk = blk_mq_alloc_disk(&tag_sets[drive], NULL);
+       disk = blk_mq_alloc_disk(&tag_sets[drive], &lim, NULL);
        if (IS_ERR(disk))
                return PTR_ERR(disk);
 
-       blk_queue_max_hw_sectors(disk->queue, 64);
        disk->major = FLOPPY_MAJOR;
        disk->first_minor = TOMINOR(drive) | (type << 2);
        disk->minors = 1;
index f8145499da38c834225b8f2d2ee0448d19adc8e1..28a95fd366fea5741db9d72b34afc6ddc6d0890a 100644 (file)
@@ -750,12 +750,13 @@ static void loop_sysfs_exit(struct loop_device *lo)
                                   &loop_attribute_group);
 }
 
-static void loop_config_discard(struct loop_device *lo)
+static void loop_config_discard(struct loop_device *lo,
+               struct queue_limits *lim)
 {
        struct file *file = lo->lo_backing_file;
        struct inode *inode = file->f_mapping->host;
-       struct request_queue *q = lo->lo_queue;
-       u32 granularity, max_discard_sectors;
+       u32 granularity = 0, max_discard_sectors = 0;
+       struct kstatfs sbuf;
 
        /*
         * If the backing device is a block device, mirror its zeroing
@@ -775,29 +776,17 @@ static void loop_config_discard(struct loop_device *lo)
         * We use punch hole to reclaim the free space used by the
         * image a.k.a. discard.
         */
-       } else if (!file->f_op->fallocate) {
-               max_discard_sectors = 0;
-               granularity = 0;
-
-       } else {
-               struct kstatfs sbuf;
-
+       } else if (file->f_op->fallocate && !vfs_statfs(&file->f_path, &sbuf)) {
                max_discard_sectors = UINT_MAX >> 9;
-               if (!vfs_statfs(&file->f_path, &sbuf))
-                       granularity = sbuf.f_bsize;
-               else
-                       max_discard_sectors = 0;
+               granularity = sbuf.f_bsize;
        }
 
-       if (max_discard_sectors) {
-               q->limits.discard_granularity = granularity;
-               blk_queue_max_discard_sectors(q, max_discard_sectors);
-               blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
-       } else {
-               q->limits.discard_granularity = 0;
-               blk_queue_max_discard_sectors(q, 0);
-               blk_queue_max_write_zeroes_sectors(q, 0);
-       }
+       lim->max_hw_discard_sectors = max_discard_sectors;
+       lim->max_write_zeroes_sectors = max_discard_sectors;
+       if (max_discard_sectors)
+               lim->discard_granularity = granularity;
+       else
+               lim->discard_granularity = 0;
 }
 
 struct loop_worker {
@@ -986,6 +975,20 @@ loop_set_status_from_info(struct loop_device *lo,
        return 0;
 }
 
+static int loop_reconfigure_limits(struct loop_device *lo, unsigned short bsize,
+               bool update_discard_settings)
+{
+       struct queue_limits lim;
+
+       lim = queue_limits_start_update(lo->lo_queue);
+       lim.logical_block_size = bsize;
+       lim.physical_block_size = bsize;
+       lim.io_min = bsize;
+       if (update_discard_settings)
+               loop_config_discard(lo, &lim);
+       return queue_limits_commit_update(lo->lo_queue, &lim);
+}
+
 static int loop_configure(struct loop_device *lo, blk_mode_t mode,
                          struct block_device *bdev,
                          const struct loop_config *config)
@@ -1083,11 +1086,10 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,
        else
                bsize = 512;
 
-       blk_queue_logical_block_size(lo->lo_queue, bsize);
-       blk_queue_physical_block_size(lo->lo_queue, bsize);
-       blk_queue_io_min(lo->lo_queue, bsize);
+       error = loop_reconfigure_limits(lo, bsize, true);
+       if (WARN_ON_ONCE(error))
+               goto out_unlock;
 
-       loop_config_discard(lo);
        loop_update_rotational(lo);
        loop_update_dio(lo);
        loop_sysfs_init(lo);
@@ -1154,9 +1156,7 @@ static void __loop_clr_fd(struct loop_device *lo, bool release)
        lo->lo_offset = 0;
        lo->lo_sizelimit = 0;
        memset(lo->lo_file_name, 0, LO_NAME_SIZE);
-       blk_queue_logical_block_size(lo->lo_queue, 512);
-       blk_queue_physical_block_size(lo->lo_queue, 512);
-       blk_queue_io_min(lo->lo_queue, 512);
+       loop_reconfigure_limits(lo, 512, false);
        invalidate_disk(lo->lo_disk);
        loop_sysfs_exit(lo);
        /* let user-space know about this change */
@@ -1488,9 +1488,7 @@ static int loop_set_block_size(struct loop_device *lo, unsigned long arg)
        invalidate_bdev(lo->lo_device);
 
        blk_mq_freeze_queue(lo->lo_queue);
-       blk_queue_logical_block_size(lo->lo_queue, arg);
-       blk_queue_physical_block_size(lo->lo_queue, arg);
-       blk_queue_io_min(lo->lo_queue, arg);
+       err = loop_reconfigure_limits(lo, arg, false);
        loop_update_dio(lo);
        blk_mq_unfreeze_queue(lo->lo_queue);
 
@@ -1982,6 +1980,12 @@ static const struct blk_mq_ops loop_mq_ops = {
 
 static int loop_add(int i)
 {
+       struct queue_limits lim = {
+               /*
+                * Random number picked from the historic block max_sectors cap.
+                */
+               .max_hw_sectors         = 2560u,
+       };
        struct loop_device *lo;
        struct gendisk *disk;
        int err;
@@ -2025,16 +2029,13 @@ static int loop_add(int i)
        if (err)
                goto out_free_idr;
 
-       disk = lo->lo_disk = blk_mq_alloc_disk(&lo->tag_set, lo);
+       disk = lo->lo_disk = blk_mq_alloc_disk(&lo->tag_set, &lim, lo);
        if (IS_ERR(disk)) {
                err = PTR_ERR(disk);
                goto out_cleanup_tags;
        }
        lo->lo_queue = lo->lo_disk->queue;
 
-       /* random number picked from the history block max_sectors cap */
-       blk_queue_max_hw_sectors(lo->lo_queue, 2560u);
-
        /*
         * By default, we do buffer IO, so it doesn't make sense to enable
         * merge because the I/O submitted to backing file is handled page by
index b200950e8fb5f9b7c5efcb044dddf52087765e2e..43a187609ef794a82a57ea49fe1b34a40593e828 100644 (file)
@@ -3401,6 +3401,12 @@ static const struct blk_mq_ops mtip_mq_ops = {
  */
 static int mtip_block_initialize(struct driver_data *dd)
 {
+       struct queue_limits lim = {
+               .physical_block_size    = 4096,
+               .max_hw_sectors         = 0xffff,
+               .max_segments           = MTIP_MAX_SG,
+               .max_segment_size       = 0x400000,
+       };
        int rv = 0, wait_for_rebuild = 0;
        sector_t capacity;
        unsigned int index = 0;
@@ -3431,7 +3437,7 @@ static int mtip_block_initialize(struct driver_data *dd)
                goto block_queue_alloc_tag_error;
        }
 
-       dd->disk = blk_mq_alloc_disk(&dd->tags, dd);
+       dd->disk = blk_mq_alloc_disk(&dd->tags, &lim, dd);
        if (IS_ERR(dd->disk)) {
                dev_err(&dd->pdev->dev,
                        "Unable to allocate request queue\n");
@@ -3481,12 +3487,7 @@ skip_create_disk:
        /* Set device limits. */
        blk_queue_flag_set(QUEUE_FLAG_NONROT, dd->queue);
        blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, dd->queue);
-       blk_queue_max_segments(dd->queue, MTIP_MAX_SG);
-       blk_queue_physical_block_size(dd->queue, 4096);
-       blk_queue_max_hw_sectors(dd->queue, 0xffff);
-       blk_queue_max_segment_size(dd->queue, 0x400000);
        dma_set_max_seg_size(&dd->pdev->dev, 0x400000);
-       blk_queue_io_min(dd->queue, 4096);
 
        /* Set the capacity of the device in 512 byte sectors. */
        if (!(mtip_hw_get_capacity(dd, &capacity))) {
index d914156db2d8b2d698432001ecc6534f619b7394..27b2187e7a6d55cad41bec8ee664ca7cc5026c28 100644 (file)
@@ -114,6 +114,10 @@ static const struct block_device_operations n64cart_fops = {
  */
 static int __init n64cart_probe(struct platform_device *pdev)
 {
+       struct queue_limits lim = {
+               .physical_block_size    = 4096,
+               .logical_block_size     = 4096,
+       };
        struct gendisk *disk;
        int err = -ENOMEM;
 
@@ -131,9 +135,11 @@ static int __init n64cart_probe(struct platform_device *pdev)
        if (IS_ERR(reg_base))
                return PTR_ERR(reg_base);
 
-       disk = blk_alloc_disk(NUMA_NO_NODE);
-       if (!disk)
+       disk = blk_alloc_disk(&lim, NUMA_NO_NODE);
+       if (IS_ERR(disk)) {
+               err = PTR_ERR(disk);
                goto out;
+       }
 
        disk->first_minor = 0;
        disk->flags = GENHD_FL_NO_PART;
@@ -145,8 +151,6 @@ static int __init n64cart_probe(struct platform_device *pdev)
        set_disk_ro(disk, 1);
 
        blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue);
-       blk_queue_physical_block_size(disk->queue, 4096);
-       blk_queue_logical_block_size(disk->queue, 4096);
 
        err = add_disk(disk);
        if (err)
index 33a8f37bb6a1f504060f783c6d727e4c76026a2e..9d4ec9273bf9545b715aa2aefdb3d8cefaaba9ca 100644 (file)
@@ -316,9 +316,12 @@ static void nbd_mark_nsock_dead(struct nbd_device *nbd, struct nbd_sock *nsock,
        nsock->sent = 0;
 }
 
-static int nbd_set_size(struct nbd_device *nbd, loff_t bytesize,
+static int __nbd_set_size(struct nbd_device *nbd, loff_t bytesize,
                loff_t blksize)
 {
+       struct queue_limits lim;
+       int error;
+
        if (!blksize)
                blksize = 1u << NBD_DEF_BLKSIZE_BITS;
 
@@ -334,10 +337,16 @@ static int nbd_set_size(struct nbd_device *nbd, loff_t bytesize,
        if (!nbd->pid)
                return 0;
 
+       lim = queue_limits_start_update(nbd->disk->queue);
        if (nbd->config->flags & NBD_FLAG_SEND_TRIM)
-               blk_queue_max_discard_sectors(nbd->disk->queue, UINT_MAX);
-       blk_queue_logical_block_size(nbd->disk->queue, blksize);
-       blk_queue_physical_block_size(nbd->disk->queue, blksize);
+               lim.max_hw_discard_sectors = UINT_MAX;
+       else
+               lim.max_hw_discard_sectors = 0;
+       lim.logical_block_size = blksize;
+       lim.physical_block_size = blksize;
+       error = queue_limits_commit_update(nbd->disk->queue, &lim);
+       if (error)
+               return error;
 
        if (max_part)
                set_bit(GD_NEED_PART_SCAN, &nbd->disk->state);
@@ -346,6 +355,18 @@ static int nbd_set_size(struct nbd_device *nbd, loff_t bytesize,
        return 0;
 }
 
+static int nbd_set_size(struct nbd_device *nbd, loff_t bytesize,
+               loff_t blksize)
+{
+       int error;
+
+       blk_mq_freeze_queue(nbd->disk->queue);
+       error = __nbd_set_size(nbd, bytesize, blksize);
+       blk_mq_unfreeze_queue(nbd->disk->queue);
+
+       return error;
+}
+
 static void nbd_complete_rq(struct request *req)
 {
        struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req);
@@ -1351,7 +1372,6 @@ static void nbd_config_put(struct nbd_device *nbd)
                nbd->config = NULL;
 
                nbd->tag_set.timeout = 0;
-               blk_queue_max_discard_sectors(nbd->disk->queue, 0);
 
                mutex_unlock(&nbd->config_lock);
                nbd_put(nbd);
@@ -1783,6 +1803,12 @@ static const struct blk_mq_ops nbd_mq_ops = {
 
 static struct nbd_device *nbd_dev_add(int index, unsigned int refs)
 {
+       struct queue_limits lim = {
+               .max_hw_sectors         = 65536,
+               .max_user_sectors       = 256,
+               .max_segments           = USHRT_MAX,
+               .max_segment_size       = UINT_MAX,
+       };
        struct nbd_device *nbd;
        struct gendisk *disk;
        int err = -ENOMEM;
@@ -1823,7 +1849,7 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs)
        if (err < 0)
                goto out_free_tags;
 
-       disk = blk_mq_alloc_disk(&nbd->tag_set, NULL);
+       disk = blk_mq_alloc_disk(&nbd->tag_set, &lim, NULL);
        if (IS_ERR(disk)) {
                err = PTR_ERR(disk);
                goto out_free_idr;
@@ -1843,11 +1869,6 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs)
         * Tell the block layer that we are not a rotational device
         */
        blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue);
-       blk_queue_max_discard_sectors(disk->queue, 0);
-       blk_queue_max_segment_size(disk->queue, UINT_MAX);
-       blk_queue_max_segments(disk->queue, USHRT_MAX);
-       blk_queue_max_hw_sectors(disk->queue, 65536);
-       disk->queue->limits.max_sectors = 256;
 
        mutex_init(&nbd->config_lock);
        refcount_set(&nbd->config_refs, 0);
@@ -2433,6 +2454,12 @@ static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info)
        }
 
        dev_list = nla_nest_start_noflag(reply, NBD_ATTR_DEVICE_LIST);
+       if (!dev_list) {
+               nlmsg_free(reply);
+               ret = -EMSGSIZE;
+               goto out;
+       }
+
        if (index == -1) {
                ret = idr_for_each(&nbd_index_idr, &status_cb, reply);
                if (ret) {
index 36755f263e8ec03b1828bf44a05cc3b54bb6a03f..71c39bcd872c7ecaabc67e91f35aa2fb267d6826 100644 (file)
@@ -115,6 +115,18 @@ module_param_string(init_hctx, g_init_hctx_str, sizeof(g_init_hctx_str), 0444);
 MODULE_PARM_DESC(init_hctx, "Fault injection to fail hctx init. init_hctx=<interval>,<probability>,<space>,<times>");
 #endif
 
+/*
+ * Historic queue modes.
+ *
+ * These days nothing but NULL_Q_MQ is actually supported, but we keep it the
+ * enum for error reporting.
+ */
+enum {
+       NULL_Q_BIO      = 0,
+       NULL_Q_RQ       = 1,
+       NULL_Q_MQ       = 2,
+};
+
 static int g_queue_mode = NULL_Q_MQ;
 
 static int null_param_store_val(const char *str, int *val, int min, int max)
@@ -165,8 +177,8 @@ static bool g_blocking;
 module_param_named(blocking, g_blocking, bool, 0444);
 MODULE_PARM_DESC(blocking, "Register as a blocking blk-mq driver device");
 
-static bool shared_tags;
-module_param(shared_tags, bool, 0444);
+static bool g_shared_tags;
+module_param_named(shared_tags, g_shared_tags, bool, 0444);
 MODULE_PARM_DESC(shared_tags, "Share tag set between devices for blk-mq");
 
 static bool g_shared_tag_bitmap;
@@ -426,6 +438,7 @@ NULLB_DEVICE_ATTR(zone_max_open, uint, NULL);
 NULLB_DEVICE_ATTR(zone_max_active, uint, NULL);
 NULLB_DEVICE_ATTR(virt_boundary, bool, NULL);
 NULLB_DEVICE_ATTR(no_sched, bool, NULL);
+NULLB_DEVICE_ATTR(shared_tags, bool, NULL);
 NULLB_DEVICE_ATTR(shared_tag_bitmap, bool, NULL);
 
 static ssize_t nullb_device_power_show(struct config_item *item, char *page)
@@ -571,6 +584,7 @@ static struct configfs_attribute *nullb_device_attrs[] = {
        &nullb_device_attr_zone_offline,
        &nullb_device_attr_virt_boundary,
        &nullb_device_attr_no_sched,
+       &nullb_device_attr_shared_tags,
        &nullb_device_attr_shared_tag_bitmap,
        NULL,
 };
@@ -653,10 +667,11 @@ static ssize_t memb_group_features_show(struct config_item *item, char *page)
                        "badblocks,blocking,blocksize,cache_size,"
                        "completion_nsec,discard,home_node,hw_queue_depth,"
                        "irqmode,max_sectors,mbps,memory_backed,no_sched,"
-                       "poll_queues,power,queue_mode,shared_tag_bitmap,size,"
-                       "submit_queues,use_per_node_hctx,virt_boundary,zoned,"
-                       "zone_capacity,zone_max_active,zone_max_open,"
-                       "zone_nr_conv,zone_offline,zone_readonly,zone_size\n");
+                       "poll_queues,power,queue_mode,shared_tag_bitmap,"
+                       "shared_tags,size,submit_queues,use_per_node_hctx,"
+                       "virt_boundary,zoned,zone_capacity,zone_max_active,"
+                       "zone_max_open,zone_nr_conv,zone_offline,zone_readonly,"
+                       "zone_size\n");
 }
 
 CONFIGFS_ATTR_RO(memb_group_, features);
@@ -738,6 +753,7 @@ static struct nullb_device *null_alloc_dev(void)
        dev->zone_max_active = g_zone_max_active;
        dev->virt_boundary = g_virt_boundary;
        dev->no_sched = g_no_sched;
+       dev->shared_tags = g_shared_tags;
        dev->shared_tag_bitmap = g_shared_tag_bitmap;
        return dev;
 }
@@ -752,98 +768,11 @@ static void null_free_dev(struct nullb_device *dev)
        kfree(dev);
 }
 
-static void put_tag(struct nullb_queue *nq, unsigned int tag)
-{
-       clear_bit_unlock(tag, nq->tag_map);
-
-       if (waitqueue_active(&nq->wait))
-               wake_up(&nq->wait);
-}
-
-static unsigned int get_tag(struct nullb_queue *nq)
-{
-       unsigned int tag;
-
-       do {
-               tag = find_first_zero_bit(nq->tag_map, nq->queue_depth);
-               if (tag >= nq->queue_depth)
-                       return -1U;
-       } while (test_and_set_bit_lock(tag, nq->tag_map));
-
-       return tag;
-}
-
-static void free_cmd(struct nullb_cmd *cmd)
-{
-       put_tag(cmd->nq, cmd->tag);
-}
-
-static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer);
-
-static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq)
-{
-       struct nullb_cmd *cmd;
-       unsigned int tag;
-
-       tag = get_tag(nq);
-       if (tag != -1U) {
-               cmd = &nq->cmds[tag];
-               cmd->tag = tag;
-               cmd->error = BLK_STS_OK;
-               cmd->nq = nq;
-               if (nq->dev->irqmode == NULL_IRQ_TIMER) {
-                       hrtimer_init(&cmd->timer, CLOCK_MONOTONIC,
-                                    HRTIMER_MODE_REL);
-                       cmd->timer.function = null_cmd_timer_expired;
-               }
-               return cmd;
-       }
-
-       return NULL;
-}
-
-static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, struct bio *bio)
-{
-       struct nullb_cmd *cmd;
-       DEFINE_WAIT(wait);
-
-       do {
-               /*
-                * This avoids multiple return statements, multiple calls to
-                * __alloc_cmd() and a fast path call to prepare_to_wait().
-                */
-               cmd = __alloc_cmd(nq);
-               if (cmd) {
-                       cmd->bio = bio;
-                       return cmd;
-               }
-               prepare_to_wait(&nq->wait, &wait, TASK_UNINTERRUPTIBLE);
-               io_schedule();
-               finish_wait(&nq->wait, &wait);
-       } while (1);
-}
-
-static void end_cmd(struct nullb_cmd *cmd)
-{
-       int queue_mode = cmd->nq->dev->queue_mode;
-
-       switch (queue_mode)  {
-       case NULL_Q_MQ:
-               blk_mq_end_request(cmd->rq, cmd->error);
-               return;
-       case NULL_Q_BIO:
-               cmd->bio->bi_status = cmd->error;
-               bio_endio(cmd->bio);
-               break;
-       }
-
-       free_cmd(cmd);
-}
-
 static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
 {
-       end_cmd(container_of(timer, struct nullb_cmd, timer));
+       struct nullb_cmd *cmd = container_of(timer, struct nullb_cmd, timer);
 
+       blk_mq_end_request(blk_mq_rq_from_pdu(cmd), cmd->error);
        return HRTIMER_NORESTART;
 }
 
@@ -856,7 +785,9 @@ static void null_cmd_end_timer(struct nullb_cmd *cmd)
 
 static void null_complete_rq(struct request *rq)
 {
-       end_cmd(blk_mq_rq_to_pdu(rq));
+       struct nullb_cmd *cmd = blk_mq_rq_to_pdu(rq);
+
+       blk_mq_end_request(rq, cmd->error);
 }
 
 static struct nullb_page *null_alloc_page(void)
@@ -1273,7 +1204,7 @@ static int null_transfer(struct nullb *nullb, struct page *page,
 
 static int null_handle_rq(struct nullb_cmd *cmd)
 {
-       struct request *rq = cmd->rq;
+       struct request *rq = blk_mq_rq_from_pdu(cmd);
        struct nullb *nullb = cmd->nq->dev->nullb;
        int err;
        unsigned int len;
@@ -1298,63 +1229,21 @@ static int null_handle_rq(struct nullb_cmd *cmd)
        return 0;
 }
 
-static int null_handle_bio(struct nullb_cmd *cmd)
-{
-       struct bio *bio = cmd->bio;
-       struct nullb *nullb = cmd->nq->dev->nullb;
-       int err;
-       unsigned int len;
-       sector_t sector = bio->bi_iter.bi_sector;
-       struct bio_vec bvec;
-       struct bvec_iter iter;
-
-       spin_lock_irq(&nullb->lock);
-       bio_for_each_segment(bvec, bio, iter) {
-               len = bvec.bv_len;
-               err = null_transfer(nullb, bvec.bv_page, len, bvec.bv_offset,
-                                    op_is_write(bio_op(bio)), sector,
-                                    bio->bi_opf & REQ_FUA);
-               if (err) {
-                       spin_unlock_irq(&nullb->lock);
-                       return err;
-               }
-               sector += len >> SECTOR_SHIFT;
-       }
-       spin_unlock_irq(&nullb->lock);
-       return 0;
-}
-
-static void null_stop_queue(struct nullb *nullb)
-{
-       struct request_queue *q = nullb->q;
-
-       if (nullb->dev->queue_mode == NULL_Q_MQ)
-               blk_mq_stop_hw_queues(q);
-}
-
-static void null_restart_queue_async(struct nullb *nullb)
-{
-       struct request_queue *q = nullb->q;
-
-       if (nullb->dev->queue_mode == NULL_Q_MQ)
-               blk_mq_start_stopped_hw_queues(q, true);
-}
-
 static inline blk_status_t null_handle_throttled(struct nullb_cmd *cmd)
 {
        struct nullb_device *dev = cmd->nq->dev;
        struct nullb *nullb = dev->nullb;
        blk_status_t sts = BLK_STS_OK;
-       struct request *rq = cmd->rq;
+       struct request *rq = blk_mq_rq_from_pdu(cmd);
 
        if (!hrtimer_active(&nullb->bw_timer))
                hrtimer_restart(&nullb->bw_timer);
 
        if (atomic_long_sub_return(blk_rq_bytes(rq), &nullb->cur_bytes) < 0) {
-               null_stop_queue(nullb);
+               blk_mq_stop_hw_queues(nullb->q);
                /* race with timer */
                if (atomic_long_read(&nullb->cur_bytes) > 0)
-                       null_restart_queue_async(nullb);
+                       blk_mq_start_stopped_hw_queues(nullb->q, true);
                /* requeue request */
                sts = BLK_STS_DEV_RESOURCE;
        }
@@ -1381,37 +1270,29 @@ static inline blk_status_t null_handle_memory_backed(struct nullb_cmd *cmd,
                                                     sector_t nr_sectors)
 {
        struct nullb_device *dev = cmd->nq->dev;
-       int err;
 
        if (op == REQ_OP_DISCARD)
                return null_handle_discard(dev, sector, nr_sectors);
+       return errno_to_blk_status(null_handle_rq(cmd));
 
-       if (dev->queue_mode == NULL_Q_BIO)
-               err = null_handle_bio(cmd);
-       else
-               err = null_handle_rq(cmd);
-
-       return errno_to_blk_status(err);
 }
 
 static void nullb_zero_read_cmd_buffer(struct nullb_cmd *cmd)
 {
+       struct request *rq = blk_mq_rq_from_pdu(cmd);
        struct nullb_device *dev = cmd->nq->dev;
        struct bio *bio;
 
-       if (dev->memory_backed)
-               return;
-
-       if (dev->queue_mode == NULL_Q_BIO && bio_op(cmd->bio) == REQ_OP_READ) {
-               zero_fill_bio(cmd->bio);
-       } else if (req_op(cmd->rq) == REQ_OP_READ) {
-               __rq_for_each_bio(bio, cmd->rq)
+       if (!dev->memory_backed && req_op(rq) == REQ_OP_READ) {
+               __rq_for_each_bio(bio, rq)
                        zero_fill_bio(bio);
        }
 }
 
 static inline void nullb_complete_cmd(struct nullb_cmd *cmd)
 {
+       struct request *rq = blk_mq_rq_from_pdu(cmd);
+
        /*
         * Since root privileges are required to configure the null_blk
         * driver, it is fine that this driver does not initialize the
@@ -1425,20 +1306,10 @@ static inline void nullb_complete_cmd(struct nullb_cmd *cmd)
        /* Complete IO by inline, softirq or timer */
        switch (cmd->nq->dev->irqmode) {
        case NULL_IRQ_SOFTIRQ:
-               switch (cmd->nq->dev->queue_mode) {
-               case NULL_Q_MQ:
-                       blk_mq_complete_request(cmd->rq);
-                       break;
-               case NULL_Q_BIO:
-                       /*
-                        * XXX: no proper submitting cpu information available.
-                        */
-                       end_cmd(cmd);
-                       break;
-               }
+               blk_mq_complete_request(rq);
                break;
        case NULL_IRQ_NONE:
-               end_cmd(cmd);
+               blk_mq_end_request(rq, cmd->error);
                break;
        case NULL_IRQ_TIMER:
                null_cmd_end_timer(cmd);
@@ -1499,7 +1370,7 @@ static enum hrtimer_restart nullb_bwtimer_fn(struct hrtimer *timer)
                return HRTIMER_NORESTART;
 
        atomic_long_set(&nullb->cur_bytes, mb_per_tick(mbps));
-       null_restart_queue_async(nullb);
+       blk_mq_start_stopped_hw_queues(nullb->q, true);
 
        hrtimer_forward_now(&nullb->bw_timer, timer_interval);
 
@@ -1516,26 +1387,6 @@ static void nullb_setup_bwtimer(struct nullb *nullb)
        hrtimer_start(&nullb->bw_timer, timer_interval, HRTIMER_MODE_REL);
 }
 
-static struct nullb_queue *nullb_to_queue(struct nullb *nullb)
-{
-       int index = 0;
-
-       if (nullb->nr_queues != 1)
-               index = raw_smp_processor_id() / ((nr_cpu_ids + nullb->nr_queues - 1) / nullb->nr_queues);
-
-       return &nullb->queues[index];
-}
-
-static void null_submit_bio(struct bio *bio)
-{
-       sector_t sector = bio->bi_iter.bi_sector;
-       sector_t nr_sectors = bio_sectors(bio);
-       struct nullb *nullb = bio->bi_bdev->bd_disk->private_data;
-       struct nullb_queue *nq = nullb_to_queue(nullb);
-
-       null_handle_cmd(alloc_cmd(nq, bio), sector, nr_sectors, bio_op(bio));
-}
-
 #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
 
 static bool should_timeout_request(struct request *rq)
@@ -1655,7 +1506,7 @@ static int null_poll(struct blk_mq_hw_ctx *hctx, struct io_comp_batch *iob)
                                                blk_rq_sectors(req));
                if (!blk_mq_add_to_batch(req, iob, (__force int) cmd->error,
                                        blk_mq_end_request_batch))
-                       end_cmd(cmd);
+                       blk_mq_end_request(req, cmd->error);
                nr++;
        }
 
@@ -1711,7 +1562,6 @@ static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx,
                hrtimer_init(&cmd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
                cmd->timer.function = null_cmd_timer_expired;
        }
-       cmd->rq = rq;
        cmd->error = BLK_STS_OK;
        cmd->nq = nq;
        cmd->fake_timeout = should_timeout_request(rq) ||
@@ -1770,34 +1620,8 @@ static void null_queue_rqs(struct request **rqlist)
        *rqlist = requeue_list;
 }
 
-static void cleanup_queue(struct nullb_queue *nq)
-{
-       bitmap_free(nq->tag_map);
-       kfree(nq->cmds);
-}
-
-static void cleanup_queues(struct nullb *nullb)
-{
-       int i;
-
-       for (i = 0; i < nullb->nr_queues; i++)
-               cleanup_queue(&nullb->queues[i]);
-
-       kfree(nullb->queues);
-}
-
-static void null_exit_hctx(struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx)
-{
-       struct nullb_queue *nq = hctx->driver_data;
-       struct nullb *nullb = nq->dev->nullb;
-
-       nullb->nr_queues--;
-}
-
 static void null_init_queue(struct nullb *nullb, struct nullb_queue *nq)
 {
-       init_waitqueue_head(&nq->wait);
-       nq->queue_depth = nullb->queue_depth;
        nq->dev = nullb->dev;
        INIT_LIST_HEAD(&nq->poll_list);
        spin_lock_init(&nq->poll_lock);
@@ -1815,7 +1639,6 @@ static int null_init_hctx(struct blk_mq_hw_ctx *hctx, void *driver_data,
        nq = &nullb->queues[hctx_idx];
        hctx->driver_data = nq;
        null_init_queue(nullb, nq);
-       nullb->nr_queues++;
 
        return 0;
 }
@@ -1828,7 +1651,6 @@ static const struct blk_mq_ops null_mq_ops = {
        .poll           = null_poll,
        .map_queues     = null_map_queues,
        .init_hctx      = null_init_hctx,
-       .exit_hctx      = null_exit_hctx,
 };
 
 static void null_del_dev(struct nullb *nullb)
@@ -1849,21 +1671,20 @@ static void null_del_dev(struct nullb *nullb)
        if (test_bit(NULLB_DEV_FL_THROTTLED, &nullb->dev->flags)) {
                hrtimer_cancel(&nullb->bw_timer);
                atomic_long_set(&nullb->cur_bytes, LONG_MAX);
-               null_restart_queue_async(nullb);
+               blk_mq_start_stopped_hw_queues(nullb->q, true);
        }
 
        put_disk(nullb->disk);
-       if (dev->queue_mode == NULL_Q_MQ &&
-           nullb->tag_set == &nullb->__tag_set)
+       if (nullb->tag_set == &nullb->__tag_set)
                blk_mq_free_tag_set(nullb->tag_set);
-       cleanup_queues(nullb);
+       kfree(nullb->queues);
        if (null_cache_active(nullb))
                null_free_device_storage(nullb->dev, true);
        kfree(nullb);
        dev->nullb = NULL;
 }
 
-static void null_config_discard(struct nullb *nullb)
+static void null_config_discard(struct nullb *nullb, struct queue_limits *lim)
 {
        if (nullb->dev->discard == false)
                return;
@@ -1880,43 +1701,14 @@ static void null_config_discard(struct nullb *nullb)
                return;
        }
 
-       blk_queue_max_discard_sectors(nullb->q, UINT_MAX >> 9);
+       lim->max_hw_discard_sectors = UINT_MAX >> 9;
 }
 
-static const struct block_device_operations null_bio_ops = {
-       .owner          = THIS_MODULE,
-       .submit_bio     = null_submit_bio,
-       .report_zones   = null_report_zones,
-};
-
-static const struct block_device_operations null_rq_ops = {
+static const struct block_device_operations null_ops = {
        .owner          = THIS_MODULE,
        .report_zones   = null_report_zones,
 };
 
-static int setup_commands(struct nullb_queue *nq)
-{
-       struct nullb_cmd *cmd;
-       int i;
-
-       nq->cmds = kcalloc(nq->queue_depth, sizeof(*cmd), GFP_KERNEL);
-       if (!nq->cmds)
-               return -ENOMEM;
-
-       nq->tag_map = bitmap_zalloc(nq->queue_depth, GFP_KERNEL);
-       if (!nq->tag_map) {
-               kfree(nq->cmds);
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < nq->queue_depth; i++) {
-               cmd = &nq->cmds[i];
-               cmd->tag = -1U;
-       }
-
-       return 0;
-}
-
 static int setup_queues(struct nullb *nullb)
 {
        int nqueues = nr_cpu_ids;
@@ -1929,101 +1721,66 @@ static int setup_queues(struct nullb *nullb)
        if (!nullb->queues)
                return -ENOMEM;
 
-       nullb->queue_depth = nullb->dev->hw_queue_depth;
        return 0;
 }
 
-static int init_driver_queues(struct nullb *nullb)
+static int null_init_tag_set(struct blk_mq_tag_set *set, int poll_queues)
 {
-       struct nullb_queue *nq;
-       int i, ret = 0;
-
-       for (i = 0; i < nullb->dev->submit_queues; i++) {
-               nq = &nullb->queues[i];
-
-               null_init_queue(nullb, nq);
-
-               ret = setup_commands(nq);
-               if (ret)
-                       return ret;
-               nullb->nr_queues++;
+       set->ops = &null_mq_ops;
+       set->cmd_size = sizeof(struct nullb_cmd);
+       set->timeout = 5 * HZ;
+       set->nr_maps = 1;
+       if (poll_queues) {
+               set->nr_hw_queues += poll_queues;
+               set->nr_maps += 2;
        }
-       return 0;
+       return blk_mq_alloc_tag_set(set);
 }
 
-static int null_gendisk_register(struct nullb *nullb)
+static int null_init_global_tag_set(void)
 {
-       sector_t size = ((sector_t)nullb->dev->size * SZ_1M) >> SECTOR_SHIFT;
-       struct gendisk *disk = nullb->disk;
+       int error;
 
-       set_capacity(disk, size);
-
-       disk->major             = null_major;
-       disk->first_minor       = nullb->index;
-       disk->minors            = 1;
-       if (queue_is_mq(nullb->q))
-               disk->fops              = &null_rq_ops;
-       else
-               disk->fops              = &null_bio_ops;
-       disk->private_data      = nullb;
-       strscpy_pad(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
+       if (tag_set.ops)
+               return 0;
 
-       if (nullb->dev->zoned) {
-               int ret = null_register_zoned_dev(nullb);
+       tag_set.nr_hw_queues = g_submit_queues;
+       tag_set.queue_depth = g_hw_queue_depth;
+       tag_set.numa_node = g_home_node;
+       tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+       if (g_no_sched)
+               tag_set.flags |= BLK_MQ_F_NO_SCHED;
+       if (g_shared_tag_bitmap)
+               tag_set.flags |= BLK_MQ_F_TAG_HCTX_SHARED;
+       if (g_blocking)
+               tag_set.flags |= BLK_MQ_F_BLOCKING;
 
-               if (ret)
-                       return ret;
-       }
-
-       return add_disk(disk);
+       error = null_init_tag_set(&tag_set, g_poll_queues);
+       if (error)
+               tag_set.ops = NULL;
+       return error;
 }
 
-static int null_init_tag_set(struct nullb *nullb, struct blk_mq_tag_set *set)
+static int null_setup_tagset(struct nullb *nullb)
 {
-       unsigned int flags = BLK_MQ_F_SHOULD_MERGE;
-       int hw_queues, numa_node;
-       unsigned int queue_depth;
-       int poll_queues;
-
-       if (nullb) {
-               hw_queues = nullb->dev->submit_queues;
-               poll_queues = nullb->dev->poll_queues;
-               queue_depth = nullb->dev->hw_queue_depth;
-               numa_node = nullb->dev->home_node;
-               if (nullb->dev->no_sched)
-                       flags |= BLK_MQ_F_NO_SCHED;
-               if (nullb->dev->shared_tag_bitmap)
-                       flags |= BLK_MQ_F_TAG_HCTX_SHARED;
-               if (nullb->dev->blocking)
-                       flags |= BLK_MQ_F_BLOCKING;
-       } else {
-               hw_queues = g_submit_queues;
-               poll_queues = g_poll_queues;
-               queue_depth = g_hw_queue_depth;
-               numa_node = g_home_node;
-               if (g_no_sched)
-                       flags |= BLK_MQ_F_NO_SCHED;
-               if (g_shared_tag_bitmap)
-                       flags |= BLK_MQ_F_TAG_HCTX_SHARED;
-               if (g_blocking)
-                       flags |= BLK_MQ_F_BLOCKING;
-       }
-
-       set->ops = &null_mq_ops;
-       set->cmd_size   = sizeof(struct nullb_cmd);
-       set->flags = flags;
-       set->driver_data = nullb;
-       set->nr_hw_queues = hw_queues;
-       set->queue_depth = queue_depth;
-       set->numa_node = numa_node;
-       if (poll_queues) {
-               set->nr_hw_queues += poll_queues;
-               set->nr_maps = 3;
-       } else {
-               set->nr_maps = 1;
+       if (nullb->dev->shared_tags) {
+               nullb->tag_set = &tag_set;
+               return null_init_global_tag_set();
        }
 
-       return blk_mq_alloc_tag_set(set);
+       nullb->tag_set = &nullb->__tag_set;
+       nullb->tag_set->driver_data = nullb;
+       nullb->tag_set->nr_hw_queues = nullb->dev->submit_queues;
+       nullb->tag_set->queue_depth = nullb->dev->hw_queue_depth;
+       nullb->tag_set->numa_node = nullb->dev->home_node;
+       nullb->tag_set->flags = BLK_MQ_F_SHOULD_MERGE;
+       if (nullb->dev->no_sched)
+               nullb->tag_set->flags |= BLK_MQ_F_NO_SCHED;
+       if (nullb->dev->shared_tag_bitmap)
+               nullb->tag_set->flags |= BLK_MQ_F_TAG_HCTX_SHARED;
+       if (nullb->dev->blocking)
+               nullb->tag_set->flags |= BLK_MQ_F_BLOCKING;
+       return null_init_tag_set(nullb->tag_set, nullb->dev->poll_queues);
 }
 
 static int null_validate_conf(struct nullb_device *dev)
@@ -2032,11 +1789,15 @@ static int null_validate_conf(struct nullb_device *dev)
                pr_err("legacy IO path is no longer available\n");
                return -EINVAL;
        }
+       if (dev->queue_mode == NULL_Q_BIO) {
+               pr_err("BIO-based IO path is no longer available, using blk-mq instead.\n");
+               dev->queue_mode = NULL_Q_MQ;
+       }
 
        dev->blocksize = round_down(dev->blocksize, 512);
        dev->blocksize = clamp_t(unsigned int, dev->blocksize, 512, 4096);
 
-       if (dev->queue_mode == NULL_Q_MQ && dev->use_per_node_hctx) {
+       if (dev->use_per_node_hctx) {
                if (dev->submit_queues != nr_online_nodes)
                        dev->submit_queues = nr_online_nodes;
        } else if (dev->submit_queues > nr_cpu_ids)
@@ -2048,8 +1809,6 @@ static int null_validate_conf(struct nullb_device *dev)
        if (dev->poll_queues > g_poll_queues)
                dev->poll_queues = g_poll_queues;
        dev->prev_poll_queues = dev->poll_queues;
-
-       dev->queue_mode = min_t(unsigned int, dev->queue_mode, NULL_Q_MQ);
        dev->irqmode = min_t(unsigned int, dev->irqmode, NULL_IRQ_TIMER);
 
        /* Do memory allocation, so set blocking */
@@ -2060,9 +1819,6 @@ static int null_validate_conf(struct nullb_device *dev)
        dev->cache_size = min_t(unsigned long, ULONG_MAX / 1024 / 1024,
                                                dev->cache_size);
        dev->mbps = min_t(unsigned int, 1024 * 40, dev->mbps);
-       /* can not stop a queue */
-       if (dev->queue_mode == NULL_Q_BIO)
-               dev->mbps = 0;
 
        if (dev->zoned &&
            (!dev->zone_size || !is_power_of_2(dev->zone_size))) {
@@ -2102,6 +1858,12 @@ static bool null_setup_fault(void)
 
 static int null_add_dev(struct nullb_device *dev)
 {
+       struct queue_limits lim = {
+               .logical_block_size     = dev->blocksize,
+               .physical_block_size    = dev->blocksize,
+               .max_hw_sectors         = dev->max_sectors,
+       };
+
        struct nullb *nullb;
        int rv;
 
@@ -2123,36 +1885,25 @@ static int null_add_dev(struct nullb_device *dev)
        if (rv)
                goto out_free_nullb;
 
-       if (dev->queue_mode == NULL_Q_MQ) {
-               if (shared_tags) {
-                       nullb->tag_set = &tag_set;
-                       rv = 0;
-               } else {
-                       nullb->tag_set = &nullb->__tag_set;
-                       rv = null_init_tag_set(nullb, nullb->tag_set);
-               }
+       rv = null_setup_tagset(nullb);
+       if (rv)
+               goto out_cleanup_queues;
 
+       if (dev->virt_boundary)
+               lim.virt_boundary_mask = PAGE_SIZE - 1;
+       null_config_discard(nullb, &lim);
+       if (dev->zoned) {
+               rv = null_init_zoned_dev(dev, &lim);
                if (rv)
-                       goto out_cleanup_queues;
-
-               nullb->tag_set->timeout = 5 * HZ;
-               nullb->disk = blk_mq_alloc_disk(nullb->tag_set, nullb);
-               if (IS_ERR(nullb->disk)) {
-                       rv = PTR_ERR(nullb->disk);
                        goto out_cleanup_tags;
-               }
-               nullb->q = nullb->disk->queue;
-       } else if (dev->queue_mode == NULL_Q_BIO) {
-               rv = -ENOMEM;
-               nullb->disk = blk_alloc_disk(nullb->dev->home_node);
-               if (!nullb->disk)
-                       goto out_cleanup_queues;
+       }
 
-               nullb->q = nullb->disk->queue;
-               rv = init_driver_queues(nullb);
-               if (rv)
-                       goto out_cleanup_disk;
+       nullb->disk = blk_mq_alloc_disk(nullb->tag_set, &lim, nullb);
+       if (IS_ERR(nullb->disk)) {
+               rv = PTR_ERR(nullb->disk);
+               goto out_cleanup_zone;
        }
+       nullb->q = nullb->disk->queue;
 
        if (dev->mbps) {
                set_bit(NULLB_DEV_FL_THROTTLED, &dev->flags);
@@ -2164,12 +1915,6 @@ static int null_add_dev(struct nullb_device *dev)
                blk_queue_write_cache(nullb->q, true, true);
        }
 
-       if (dev->zoned) {
-               rv = null_init_zoned_dev(dev, nullb->q);
-               if (rv)
-                       goto out_cleanup_disk;
-       }
-
        nullb->q->queuedata = nullb;
        blk_queue_flag_set(QUEUE_FLAG_NONROT, nullb->q);
 
@@ -2177,22 +1922,12 @@ static int null_add_dev(struct nullb_device *dev)
        rv = ida_alloc(&nullb_indexes, GFP_KERNEL);
        if (rv < 0) {
                mutex_unlock(&lock);
-               goto out_cleanup_zone;
+               goto out_cleanup_disk;
        }
        nullb->index = rv;
        dev->index = rv;
        mutex_unlock(&lock);
 
-       blk_queue_logical_block_size(nullb->q, dev->blocksize);
-       blk_queue_physical_block_size(nullb->q, dev->blocksize);
-       if (dev->max_sectors)
-               blk_queue_max_hw_sectors(nullb->q, dev->max_sectors);
-
-       if (dev->virt_boundary)
-               blk_queue_virt_boundary(nullb->q, PAGE_SIZE - 1);
-
-       null_config_discard(nullb);
-
        if (config_item_name(&dev->group.cg_item)) {
                /* Use configfs dir name as the device name */
                snprintf(nullb->disk_name, sizeof(nullb->disk_name),
@@ -2201,7 +1936,22 @@ static int null_add_dev(struct nullb_device *dev)
                sprintf(nullb->disk_name, "nullb%d", nullb->index);
        }
 
-       rv = null_gendisk_register(nullb);
+       set_capacity(nullb->disk,
+               ((sector_t)nullb->dev->size * SZ_1M) >> SECTOR_SHIFT);
+       nullb->disk->major = null_major;
+       nullb->disk->first_minor = nullb->index;
+       nullb->disk->minors = 1;
+       nullb->disk->fops = &null_ops;
+       nullb->disk->private_data = nullb;
+       strscpy_pad(nullb->disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
+
+       if (nullb->dev->zoned) {
+               rv = null_register_zoned_dev(nullb);
+               if (rv)
+                       goto out_ida_free;
+       }
+
+       rv = add_disk(nullb->disk);
        if (rv)
                goto out_ida_free;
 
@@ -2220,10 +1970,10 @@ out_cleanup_zone:
 out_cleanup_disk:
        put_disk(nullb->disk);
 out_cleanup_tags:
-       if (dev->queue_mode == NULL_Q_MQ && nullb->tag_set == &nullb->__tag_set)
+       if (nullb->tag_set == &nullb->__tag_set)
                blk_mq_free_tag_set(nullb->tag_set);
 out_cleanup_queues:
-       cleanup_queues(nullb);
+       kfree(nullb->queues);
 out_free_nullb:
        kfree(nullb);
        dev->nullb = NULL;
@@ -2299,7 +2049,7 @@ static int __init null_init(void)
                return -EINVAL;
        }
 
-       if (g_queue_mode == NULL_Q_MQ && g_use_per_node_hctx) {
+       if (g_use_per_node_hctx) {
                if (g_submit_queues != nr_online_nodes) {
                        pr_warn("submit_queues param is set to %u.\n",
                                nr_online_nodes);
@@ -2311,18 +2061,12 @@ static int __init null_init(void)
                g_submit_queues = 1;
        }
 
-       if (g_queue_mode == NULL_Q_MQ && shared_tags) {
-               ret = null_init_tag_set(NULL, &tag_set);
-               if (ret)
-                       return ret;
-       }
-
        config_group_init(&nullb_subsys.su_group);
        mutex_init(&nullb_subsys.su_mutex);
 
        ret = configfs_register_subsystem(&nullb_subsys);
        if (ret)
-               goto err_tagset;
+               return ret;
 
        mutex_init(&lock);
 
@@ -2349,9 +2093,6 @@ err_dev:
        unregister_blkdev(null_major, "nullb");
 err_conf:
        configfs_unregister_subsystem(&nullb_subsys);
-err_tagset:
-       if (g_queue_mode == NULL_Q_MQ && shared_tags)
-               blk_mq_free_tag_set(&tag_set);
        return ret;
 }
 
@@ -2370,7 +2111,7 @@ static void __exit null_exit(void)
        }
        mutex_unlock(&lock);
 
-       if (g_queue_mode == NULL_Q_MQ && shared_tags)
+       if (tag_set.ops)
                blk_mq_free_tag_set(&tag_set);
 }
 
index 929f659dd255b7068b74453099d46f965df7b30f..477b9774682346b95becee2afd9a7a1a5559af1b 100644 (file)
 #include <linux/mutex.h>
 
 struct nullb_cmd {
-       union {
-               struct request *rq;
-               struct bio *bio;
-       };
-       unsigned int tag;
        blk_status_t error;
        bool fake_timeout;
        struct nullb_queue *nq;
@@ -28,16 +23,11 @@ struct nullb_cmd {
 };
 
 struct nullb_queue {
-       unsigned long *tag_map;
-       wait_queue_head_t wait;
-       unsigned int queue_depth;
        struct nullb_device *dev;
        unsigned int requeue_selection;
 
        struct list_head poll_list;
        spinlock_t poll_lock;
-
-       struct nullb_cmd *cmds;
 };
 
 struct nullb_zone {
@@ -60,13 +50,6 @@ struct nullb_zone {
        unsigned int capacity;
 };
 
-/* Queue modes */
-enum {
-       NULL_Q_BIO      = 0,
-       NULL_Q_RQ       = 1,
-       NULL_Q_MQ       = 2,
-};
-
 struct nullb_device {
        struct nullb *nullb;
        struct config_group group;
@@ -119,6 +102,7 @@ struct nullb_device {
        bool zoned; /* if device is zoned */
        bool virt_boundary; /* virtual boundary on/off for the device */
        bool no_sched; /* no IO scheduler for the device */
+       bool shared_tags; /* share tag set between devices for blk-mq */
        bool shared_tag_bitmap; /* use hostwide shared tags */
 };
 
@@ -130,14 +114,12 @@ struct nullb {
        struct gendisk *disk;
        struct blk_mq_tag_set *tag_set;
        struct blk_mq_tag_set __tag_set;
-       unsigned int queue_depth;
        atomic_long_t cur_bytes;
        struct hrtimer bw_timer;
        unsigned long cache_flush_pos;
        spinlock_t lock;
 
        struct nullb_queue *queues;
-       unsigned int nr_queues;
        char disk_name[DISK_NAME_LEN];
 };
 
@@ -147,7 +129,7 @@ blk_status_t null_process_cmd(struct nullb_cmd *cmd, enum req_op op,
                              sector_t sector, unsigned int nr_sectors);
 
 #ifdef CONFIG_BLK_DEV_ZONED
-int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q);
+int null_init_zoned_dev(struct nullb_device *dev, struct queue_limits *lim);
 int null_register_zoned_dev(struct nullb *nullb);
 void null_free_zoned_dev(struct nullb_device *dev);
 int null_report_zones(struct gendisk *disk, sector_t sector,
@@ -160,7 +142,7 @@ ssize_t zone_cond_store(struct nullb_device *dev, const char *page,
                        size_t count, enum blk_zone_cond cond);
 #else
 static inline int null_init_zoned_dev(struct nullb_device *dev,
-                                     struct request_queue *q)
+               struct queue_limits *lim)
 {
        pr_err("CONFIG_BLK_DEV_ZONED not enabled\n");
        return -EINVAL;
index 6b2b370e786f5f6c6a4fc4eeb9b75f4c96fd3be6..ef2d05d5f0df7ea0784a35ffc566fc8f686efee4 100644 (file)
@@ -41,10 +41,11 @@ TRACE_EVENT(nullb_zone_op,
                __field(unsigned int, zone_cond)
            ),
            TP_fast_assign(
-               __entry->op = req_op(cmd->rq);
+               __entry->op = req_op(blk_mq_rq_from_pdu(cmd));
                __entry->zone_no = zone_no;
                __entry->zone_cond = zone_cond;
-               __assign_disk_name(__entry->disk, cmd->rq->q->disk);
+               __assign_disk_name(__entry->disk,
+                       blk_mq_rq_from_pdu(cmd)->q->disk);
            ),
            TP_printk("%s req=%-15s zone_no=%u zone_cond=%-10s",
                      __print_disk_name(__entry->disk),
index 6f5e0994862eaedb65273513be975affd4e30fba..1689e25841048355f5f3babf4f9c9e8bbca5cd1d 100644 (file)
@@ -58,7 +58,8 @@ static inline void null_unlock_zone(struct nullb_device *dev,
                mutex_unlock(&zone->mutex);
 }
 
-int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
+int null_init_zoned_dev(struct nullb_device *dev,
+                       struct queue_limits *lim)
 {
        sector_t dev_capacity_sects, zone_capacity_sects;
        struct nullb_zone *zone;
@@ -151,27 +152,22 @@ int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
                sector += dev->zone_size_sects;
        }
 
+       lim->zoned = true;
+       lim->chunk_sectors = dev->zone_size_sects;
+       lim->max_zone_append_sectors = dev->zone_size_sects;
+       lim->max_open_zones = dev->zone_max_open;
+       lim->max_active_zones = dev->zone_max_active;
        return 0;
 }
 
 int null_register_zoned_dev(struct nullb *nullb)
 {
-       struct nullb_device *dev = nullb->dev;
        struct request_queue *q = nullb->q;
 
-       disk_set_zoned(nullb->disk);
        blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
        blk_queue_required_elevator_features(q, ELEVATOR_F_ZBD_SEQ_WRITE);
-       blk_queue_chunk_sectors(q, dev->zone_size_sects);
        nullb->disk->nr_zones = bdev_nr_zones(nullb->disk->part0);
-       blk_queue_max_zone_append_sectors(q, dev->zone_size_sects);
-       disk_set_max_open_zones(nullb->disk, dev->zone_max_open);
-       disk_set_max_active_zones(nullb->disk, dev->zone_max_active);
-
-       if (queue_is_mq(q))
-               return blk_revalidate_disk_zones(nullb->disk, NULL);
-
-       return 0;
+       return blk_revalidate_disk_zones(nullb->disk, NULL);
 }
 
 void null_free_zoned_dev(struct nullb_device *dev)
@@ -394,10 +390,7 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
         */
        if (append) {
                sector = zone->wp;
-               if (dev->queue_mode == NULL_Q_MQ)
-                       cmd->rq->__sector = sector;
-               else
-                       cmd->bio->bi_iter.bi_sector = sector;
+               blk_mq_rq_from_pdu(cmd)->__sector = sector;
        } else if (sector != zone->wp) {
                ret = BLK_STS_IOERR;
                goto unlock;
index d56d972aadb36fa2a3b85282eef1ea058a9bf73e..21728e9ea5c374603b50b758282d9091329e2e82 100644 (file)
@@ -340,8 +340,8 @@ static ssize_t device_map_show(const struct class *c, const struct class_attribu
                n += sysfs_emit_at(data, n, "%s %u:%u %u:%u\n",
                        pd->disk->disk_name,
                        MAJOR(pd->pkt_dev), MINOR(pd->pkt_dev),
-                       MAJOR(pd->bdev_handle->bdev->bd_dev),
-                       MINOR(pd->bdev_handle->bdev->bd_dev));
+                       MAJOR(file_bdev(pd->bdev_file)->bd_dev),
+                       MINOR(file_bdev(pd->bdev_file)->bd_dev));
        }
        mutex_unlock(&ctl_mutex);
        return n;
@@ -438,7 +438,7 @@ static int pkt_seq_show(struct seq_file *m, void *p)
        int states[PACKET_NUM_STATES];
 
        seq_printf(m, "Writer %s mapped to %pg:\n", pd->disk->disk_name,
-                  pd->bdev_handle->bdev);
+                  file_bdev(pd->bdev_file));
 
        seq_printf(m, "\nSettings:\n");
        seq_printf(m, "\tpacket size:\t\t%dkB\n", pd->settings.size / 2);
@@ -715,7 +715,7 @@ static void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *nod
  */
 static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc)
 {
-       struct request_queue *q = bdev_get_queue(pd->bdev_handle->bdev);
+       struct request_queue *q = bdev_get_queue(file_bdev(pd->bdev_file));
        struct scsi_cmnd *scmd;
        struct request *rq;
        int ret = 0;
@@ -828,6 +828,12 @@ static noinline_for_stack int pkt_set_speed(struct pktcdvd_device *pd,
  */
 static void pkt_queue_bio(struct pktcdvd_device *pd, struct bio *bio)
 {
+       /*
+        * Some CDRW drives can not handle writes larger than one packet,
+        * even if the size is a multiple of the packet size.
+        */
+       bio->bi_opf |= REQ_NOMERGE;
+
        spin_lock(&pd->iosched.lock);
        if (bio_data_dir(bio) == READ)
                bio_list_add(&pd->iosched.read_queue, bio);
@@ -1048,7 +1054,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
                        continue;
 
                bio = pkt->r_bios[f];
-               bio_init(bio, pd->bdev_handle->bdev, bio->bi_inline_vecs, 1,
+               bio_init(bio, file_bdev(pd->bdev_file), bio->bi_inline_vecs, 1,
                         REQ_OP_READ);
                bio->bi_iter.bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9);
                bio->bi_end_io = pkt_end_io_read;
@@ -1264,7 +1270,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
        struct device *ddev = disk_to_dev(pd->disk);
        int f;
 
-       bio_init(pkt->w_bio, pd->bdev_handle->bdev, pkt->w_bio->bi_inline_vecs,
+       bio_init(pkt->w_bio, file_bdev(pd->bdev_file), pkt->w_bio->bi_inline_vecs,
                 pkt->frames, REQ_OP_WRITE);
        pkt->w_bio->bi_iter.bi_sector = pkt->sector;
        pkt->w_bio->bi_end_io = pkt_end_io_packet_write;
@@ -2162,20 +2168,20 @@ static int pkt_open_dev(struct pktcdvd_device *pd, bool write)
        int ret;
        long lba;
        struct request_queue *q;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
 
        /*
         * We need to re-open the cdrom device without O_NONBLOCK to be able
         * to read/write from/to it. It is already opened in O_NONBLOCK mode
         * so open should not fail.
         */
-       bdev_handle = bdev_open_by_dev(pd->bdev_handle->bdev->bd_dev,
+       bdev_file = bdev_file_open_by_dev(file_bdev(pd->bdev_file)->bd_dev,
                                       BLK_OPEN_READ, pd, NULL);
-       if (IS_ERR(bdev_handle)) {
-               ret = PTR_ERR(bdev_handle);
+       if (IS_ERR(bdev_file)) {
+               ret = PTR_ERR(bdev_file);
                goto out;
        }
-       pd->open_bdev_handle = bdev_handle;
+       pd->f_open_bdev = bdev_file;
 
        ret = pkt_get_last_written(pd, &lba);
        if (ret) {
@@ -2184,18 +2190,13 @@ static int pkt_open_dev(struct pktcdvd_device *pd, bool write)
        }
 
        set_capacity(pd->disk, lba << 2);
-       set_capacity_and_notify(pd->bdev_handle->bdev->bd_disk, lba << 2);
+       set_capacity_and_notify(file_bdev(pd->bdev_file)->bd_disk, lba << 2);
 
-       q = bdev_get_queue(pd->bdev_handle->bdev);
+       q = bdev_get_queue(file_bdev(pd->bdev_file));
        if (write) {
                ret = pkt_open_write(pd);
                if (ret)
                        goto out_putdev;
-               /*
-                * Some CDRW drives can not handle writes larger than one packet,
-                * even if the size is a multiple of the packet size.
-                */
-               blk_queue_max_hw_sectors(q, pd->settings.size);
                set_bit(PACKET_WRITABLE, &pd->flags);
        } else {
                pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
@@ -2218,7 +2219,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, bool write)
        return 0;
 
 out_putdev:
-       bdev_release(bdev_handle);
+       fput(bdev_file);
 out:
        return ret;
 }
@@ -2237,8 +2238,8 @@ static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
        pkt_lock_door(pd, 0);
 
        pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
-       bdev_release(pd->open_bdev_handle);
-       pd->open_bdev_handle = NULL;
+       fput(pd->f_open_bdev);
+       pd->f_open_bdev = NULL;
 
        pkt_shrink_pktlist(pd);
 }
@@ -2326,7 +2327,7 @@ static void pkt_end_io_read_cloned(struct bio *bio)
 
 static void pkt_make_request_read(struct pktcdvd_device *pd, struct bio *bio)
 {
-       struct bio *cloned_bio = bio_alloc_clone(pd->bdev_handle->bdev, bio,
+       struct bio *cloned_bio = bio_alloc_clone(file_bdev(pd->bdev_file), bio,
                GFP_NOIO, &pkt_bio_set);
        struct packet_stacked_data *psd = mempool_alloc(&psd_pool, GFP_NOIO);
 
@@ -2338,9 +2339,9 @@ static void pkt_make_request_read(struct pktcdvd_device *pd, struct bio *bio)
        pkt_queue_bio(pd, cloned_bio);
 }
 
-static void pkt_make_request_write(struct request_queue *q, struct bio *bio)
+static void pkt_make_request_write(struct bio *bio)
 {
-       struct pktcdvd_device *pd = q->queuedata;
+       struct pktcdvd_device *pd = bio->bi_bdev->bd_disk->private_data;
        sector_t zone;
        struct packet_data *pkt;
        int was_empty, blocked_bio;
@@ -2432,7 +2433,7 @@ static void pkt_make_request_write(struct request_queue *q, struct bio *bio)
 
 static void pkt_submit_bio(struct bio *bio)
 {
-       struct pktcdvd_device *pd = bio->bi_bdev->bd_disk->queue->queuedata;
+       struct pktcdvd_device *pd = bio->bi_bdev->bd_disk->private_data;
        struct device *ddev = disk_to_dev(pd->disk);
        struct bio *split;
 
@@ -2476,7 +2477,7 @@ static void pkt_submit_bio(struct bio *bio)
                        split = bio;
                }
 
-               pkt_make_request_write(bio->bi_bdev->bd_disk->queue, split);
+               pkt_make_request_write(split);
        } while (split != bio);
 
        return;
@@ -2484,20 +2485,11 @@ end_io:
        bio_io_error(bio);
 }
 
-static void pkt_init_queue(struct pktcdvd_device *pd)
-{
-       struct request_queue *q = pd->disk->queue;
-
-       blk_queue_logical_block_size(q, CD_FRAMESIZE);
-       blk_queue_max_hw_sectors(q, PACKET_MAX_SECTORS);
-       q->queuedata = pd;
-}
-
 static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
 {
        struct device *ddev = disk_to_dev(pd->disk);
        int i;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct scsi_device *sdev;
 
        if (pd->pkt_dev == dev) {
@@ -2508,9 +2500,9 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
                struct pktcdvd_device *pd2 = pkt_devs[i];
                if (!pd2)
                        continue;
-               if (pd2->bdev_handle->bdev->bd_dev == dev) {
+               if (file_bdev(pd2->bdev_file)->bd_dev == dev) {
                        dev_err(ddev, "%pg already setup\n",
-                               pd2->bdev_handle->bdev);
+                               file_bdev(pd2->bdev_file));
                        return -EBUSY;
                }
                if (pd2->pkt_dev == dev) {
@@ -2519,13 +2511,13 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
                }
        }
 
-       bdev_handle = bdev_open_by_dev(dev, BLK_OPEN_READ | BLK_OPEN_NDELAY,
+       bdev_file = bdev_file_open_by_dev(dev, BLK_OPEN_READ | BLK_OPEN_NDELAY,
                                       NULL, NULL);
-       if (IS_ERR(bdev_handle))
-               return PTR_ERR(bdev_handle);
-       sdev = scsi_device_from_queue(bdev_handle->bdev->bd_disk->queue);
+       if (IS_ERR(bdev_file))
+               return PTR_ERR(bdev_file);
+       sdev = scsi_device_from_queue(file_bdev(bdev_file)->bd_disk->queue);
        if (!sdev) {
-               bdev_release(bdev_handle);
+               fput(bdev_file);
                return -EINVAL;
        }
        put_device(&sdev->sdev_gendev);
@@ -2533,10 +2525,8 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
        /* This is safe, since we have a reference from open(). */
        __module_get(THIS_MODULE);
 
-       pd->bdev_handle = bdev_handle;
-       set_blocksize(bdev_handle->bdev, CD_FRAMESIZE);
-
-       pkt_init_queue(pd);
+       pd->bdev_file = bdev_file;
+       set_blocksize(file_bdev(bdev_file), CD_FRAMESIZE);
 
        atomic_set(&pd->cdrw.pending_bios, 0);
        pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->disk->disk_name);
@@ -2546,11 +2536,11 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
        }
 
        proc_create_single_data(pd->disk->disk_name, 0, pkt_proc, pkt_seq_show, pd);
-       dev_notice(ddev, "writer mapped to %pg\n", bdev_handle->bdev);
+       dev_notice(ddev, "writer mapped to %pg\n", file_bdev(bdev_file));
        return 0;
 
 out_mem:
-       bdev_release(bdev_handle);
+       fput(bdev_file);
        /* This is safe: open() is still holding a reference. */
        module_put(THIS_MODULE);
        return -ENOMEM;
@@ -2605,9 +2595,9 @@ static unsigned int pkt_check_events(struct gendisk *disk,
 
        if (!pd)
                return 0;
-       if (!pd->bdev_handle)
+       if (!pd->bdev_file)
                return 0;
-       attached_disk = pd->bdev_handle->bdev->bd_disk;
+       attached_disk = file_bdev(pd->bdev_file)->bd_disk;
        if (!attached_disk || !attached_disk->fops->check_events)
                return 0;
        return attached_disk->fops->check_events(attached_disk, clearing);
@@ -2634,6 +2624,10 @@ static const struct block_device_operations pktcdvd_ops = {
  */
 static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
 {
+       struct queue_limits lim = {
+               .max_hw_sectors         = PACKET_MAX_SECTORS,
+               .logical_block_size     = CD_FRAMESIZE,
+       };
        int idx;
        int ret = -ENOMEM;
        struct pktcdvd_device *pd;
@@ -2673,10 +2667,11 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
        pd->write_congestion_on  = write_congestion_on;
        pd->write_congestion_off = write_congestion_off;
 
-       ret = -ENOMEM;
-       disk = blk_alloc_disk(NUMA_NO_NODE);
-       if (!disk)
+       disk = blk_alloc_disk(&lim, NUMA_NO_NODE);
+       if (IS_ERR(disk)) {
+               ret = PTR_ERR(disk);
                goto out_mem;
+       }
        pd->disk = disk;
        disk->major = pktdev_major;
        disk->first_minor = idx;
@@ -2692,7 +2687,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
                goto out_mem2;
 
        /* inherit events of the host device */
-       disk->events = pd->bdev_handle->bdev->bd_disk->events;
+       disk->events = file_bdev(pd->bdev_file)->bd_disk->events;
 
        ret = add_disk(disk);
        if (ret)
@@ -2757,7 +2752,7 @@ static int pkt_remove_dev(dev_t pkt_dev)
        pkt_debugfs_dev_remove(pd);
        pkt_sysfs_dev_remove(pd);
 
-       bdev_release(pd->bdev_handle);
+       fput(pd->bdev_file);
 
        remove_proc_entry(pd->disk->disk_name, pkt_proc);
        dev_notice(ddev, "writer unmapped\n");
@@ -2784,7 +2779,7 @@ static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd)
 
        pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index);
        if (pd) {
-               ctrl_cmd->dev = new_encode_dev(pd->bdev_handle->bdev->bd_dev);
+               ctrl_cmd->dev = new_encode_dev(file_bdev(pd->bdev_file)->bd_dev);
                ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev);
        } else {
                ctrl_cmd->dev = 0;
index 36d7b36c60c76bd705115f4ce61bf1c50bafab11..b810ac0a5c4b97ed92b6a8f3075fee8ca415b6b6 100644 (file)
@@ -382,6 +382,14 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev)
        struct ps3disk_private *priv;
        int error;
        unsigned int devidx;
+       struct queue_limits lim = {
+               .logical_block_size     = dev->blk_size,
+               .max_hw_sectors         = dev->bounce_size >> 9,
+               .max_segments           = -1,
+               .max_segment_size       = dev->bounce_size,
+               .dma_alignment          = dev->blk_size - 1,
+       };
+
        struct request_queue *queue;
        struct gendisk *gendisk;
 
@@ -431,7 +439,7 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev)
        if (error)
                goto fail_teardown;
 
-       gendisk = blk_mq_alloc_disk(&priv->tag_set, dev);
+       gendisk = blk_mq_alloc_disk(&priv->tag_set, &lim, dev);
        if (IS_ERR(gendisk)) {
                dev_err(&dev->sbd.core, "%s:%u: blk_mq_alloc_disk failed\n",
                        __func__, __LINE__);
@@ -441,15 +449,8 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev)
 
        queue = gendisk->queue;
 
-       blk_queue_max_hw_sectors(queue, dev->bounce_size >> 9);
-       blk_queue_dma_alignment(queue, dev->blk_size-1);
-       blk_queue_logical_block_size(queue, dev->blk_size);
-
        blk_queue_write_cache(queue, true, false);
 
-       blk_queue_max_segments(queue, -1);
-       blk_queue_max_segment_size(queue, dev->bounce_size);
-
        priv->gendisk = gendisk;
        gendisk->major = ps3disk_major;
        gendisk->first_minor = devidx * PS3DISK_MINORS;
index 38d42af01b253517f0a185fe4d582c2006f09a29..bdcf083b45e2349fc9d92854ca3433ddf78fa7fb 100644 (file)
@@ -730,10 +730,10 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev)
 
        ps3vram_proc_init(dev);
 
-       gendisk = blk_alloc_disk(NUMA_NO_NODE);
-       if (!gendisk) {
+       gendisk = blk_alloc_disk(NULL, NUMA_NO_NODE);
+       if (IS_ERR(gendisk)) {
                dev_err(&dev->core, "blk_alloc_disk failed\n");
-               error = -ENOMEM;
+               error = PTR_ERR(gendisk);
                goto out_cache_cleanup;
        }
 
index 12b5d53ec85645fb22395d41adef81d13cdb7292..26ff5cd2bf0abc118d5c83cdf733554a3be97e0c 100644 (file)
@@ -575,7 +575,7 @@ static const struct attribute_group rbd_bus_group = {
 };
 __ATTRIBUTE_GROUPS(rbd_bus);
 
-static struct bus_type rbd_bus_type = {
+static const struct bus_type rbd_bus_type = {
        .name           = "rbd",
        .bus_groups     = rbd_bus_groups,
 };
@@ -4952,6 +4952,14 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        struct request_queue *q;
        unsigned int objset_bytes =
            rbd_dev->layout.object_size * rbd_dev->layout.stripe_count;
+       struct queue_limits lim = {
+               .max_hw_sectors         = objset_bytes >> SECTOR_SHIFT,
+               .max_user_sectors       = objset_bytes >> SECTOR_SHIFT,
+               .io_min                 = rbd_dev->opts->alloc_size,
+               .io_opt                 = rbd_dev->opts->alloc_size,
+               .max_segments           = USHRT_MAX,
+               .max_segment_size       = UINT_MAX,
+       };
        int err;
 
        memset(&rbd_dev->tag_set, 0, sizeof(rbd_dev->tag_set));
@@ -4966,7 +4974,13 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        if (err)
                return err;
 
-       disk = blk_mq_alloc_disk(&rbd_dev->tag_set, rbd_dev);
+       if (rbd_dev->opts->trim) {
+               lim.discard_granularity = rbd_dev->opts->alloc_size;
+               lim.max_hw_discard_sectors = objset_bytes >> SECTOR_SHIFT;
+               lim.max_write_zeroes_sectors = objset_bytes >> SECTOR_SHIFT;
+       }
+
+       disk = blk_mq_alloc_disk(&rbd_dev->tag_set, &lim, rbd_dev);
        if (IS_ERR(disk)) {
                err = PTR_ERR(disk);
                goto out_tag_set;
@@ -4987,19 +5001,6 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
        /* QUEUE_FLAG_ADD_RANDOM is off by default for blk-mq */
 
-       blk_queue_max_hw_sectors(q, objset_bytes >> SECTOR_SHIFT);
-       q->limits.max_sectors = queue_max_hw_sectors(q);
-       blk_queue_max_segments(q, USHRT_MAX);
-       blk_queue_max_segment_size(q, UINT_MAX);
-       blk_queue_io_min(q, rbd_dev->opts->alloc_size);
-       blk_queue_io_opt(q, rbd_dev->opts->alloc_size);
-
-       if (rbd_dev->opts->trim) {
-               q->limits.discard_granularity = rbd_dev->opts->alloc_size;
-               blk_queue_max_discard_sectors(q, objset_bytes >> SECTOR_SHIFT);
-               blk_queue_max_write_zeroes_sectors(q, objset_bytes >> SECTOR_SHIFT);
-       }
-
        if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC))
                blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, q);
 
index 4044c369d22a5f6229d2907acacbba497c03b8f4..b7ffe03c61606d205558169193d61e632ce26b35 100644 (file)
@@ -1329,43 +1329,6 @@ static void rnbd_init_mq_hw_queues(struct rnbd_clt_dev *dev)
        }
 }
 
-static void setup_request_queue(struct rnbd_clt_dev *dev,
-                               struct rnbd_msg_open_rsp *rsp)
-{
-       blk_queue_logical_block_size(dev->queue,
-                                    le16_to_cpu(rsp->logical_block_size));
-       blk_queue_physical_block_size(dev->queue,
-                                     le16_to_cpu(rsp->physical_block_size));
-       blk_queue_max_hw_sectors(dev->queue,
-                                dev->sess->max_io_size / SECTOR_SIZE);
-
-       /*
-        * we don't support discards to "discontiguous" segments
-        * in on request
-        */
-       blk_queue_max_discard_segments(dev->queue, 1);
-
-       blk_queue_max_discard_sectors(dev->queue,
-                                     le32_to_cpu(rsp->max_discard_sectors));
-       dev->queue->limits.discard_granularity =
-                                       le32_to_cpu(rsp->discard_granularity);
-       dev->queue->limits.discard_alignment =
-                                       le32_to_cpu(rsp->discard_alignment);
-       if (le16_to_cpu(rsp->secure_discard))
-               blk_queue_max_secure_erase_sectors(dev->queue,
-                                       le32_to_cpu(rsp->max_discard_sectors));
-       blk_queue_flag_set(QUEUE_FLAG_SAME_COMP, dev->queue);
-       blk_queue_flag_set(QUEUE_FLAG_SAME_FORCE, dev->queue);
-       blk_queue_max_segments(dev->queue, dev->sess->max_segments);
-       blk_queue_io_opt(dev->queue, dev->sess->max_io_size);
-       blk_queue_virt_boundary(dev->queue, SZ_4K - 1);
-       blk_queue_write_cache(dev->queue,
-                             !!(rsp->cache_policy & RNBD_WRITEBACK),
-                             !!(rsp->cache_policy & RNBD_FUA));
-       blk_queue_max_write_zeroes_sectors(dev->queue,
-                                          le32_to_cpu(rsp->max_write_zeroes_sectors));
-}
-
 static int rnbd_clt_setup_gen_disk(struct rnbd_clt_dev *dev,
                                   struct rnbd_msg_open_rsp *rsp, int idx)
 {
@@ -1403,18 +1366,41 @@ static int rnbd_clt_setup_gen_disk(struct rnbd_clt_dev *dev,
 static int rnbd_client_setup_device(struct rnbd_clt_dev *dev,
                                    struct rnbd_msg_open_rsp *rsp)
 {
+       struct queue_limits lim = {
+               .logical_block_size     = le16_to_cpu(rsp->logical_block_size),
+               .physical_block_size    = le16_to_cpu(rsp->physical_block_size),
+               .io_opt                 = dev->sess->max_io_size,
+               .max_hw_sectors         = dev->sess->max_io_size / SECTOR_SIZE,
+               .max_hw_discard_sectors = le32_to_cpu(rsp->max_discard_sectors),
+               .discard_granularity    = le32_to_cpu(rsp->discard_granularity),
+               .discard_alignment      = le32_to_cpu(rsp->discard_alignment),
+               .max_segments           = dev->sess->max_segments,
+               .virt_boundary_mask     = SZ_4K - 1,
+               .max_write_zeroes_sectors =
+                       le32_to_cpu(rsp->max_write_zeroes_sectors),
+       };
        int idx = dev->clt_device_id;
 
        dev->size = le64_to_cpu(rsp->nsectors) *
                        le16_to_cpu(rsp->logical_block_size);
 
-       dev->gd = blk_mq_alloc_disk(&dev->sess->tag_set, dev);
+       if (rsp->secure_discard) {
+               lim.max_secure_erase_sectors =
+                       le32_to_cpu(rsp->max_discard_sectors);
+       }
+
+       dev->gd = blk_mq_alloc_disk(&dev->sess->tag_set, &lim, dev);
        if (IS_ERR(dev->gd))
                return PTR_ERR(dev->gd);
        dev->queue = dev->gd->queue;
        rnbd_init_mq_hw_queues(dev);
 
-       setup_request_queue(dev, rsp);
+       blk_queue_flag_set(QUEUE_FLAG_SAME_COMP, dev->queue);
+       blk_queue_flag_set(QUEUE_FLAG_SAME_FORCE, dev->queue);
+       blk_queue_write_cache(dev->queue,
+                             !!(rsp->cache_policy & RNBD_WRITEBACK),
+                             !!(rsp->cache_policy & RNBD_FUA));
+
        return rnbd_clt_setup_gen_disk(dev, rsp, idx);
 }
 
index 3a0d5dcec6f2559f85b13c432248533651c27c44..f6e3a3c4b76cc48b9b1fbe92c5cdca361598f08f 100644 (file)
@@ -145,7 +145,7 @@ static int process_rdma(struct rnbd_srv_session *srv_sess,
        priv->sess_dev = sess_dev;
        priv->id = id;
 
-       bio = bio_alloc(sess_dev->bdev_handle->bdev, 1,
+       bio = bio_alloc(file_bdev(sess_dev->bdev_file), 1,
                        rnbd_to_bio_flags(le32_to_cpu(msg->rw)), GFP_KERNEL);
        if (bio_add_page(bio, virt_to_page(data), datalen,
                        offset_in_page(data)) != datalen) {
@@ -219,7 +219,7 @@ void rnbd_destroy_sess_dev(struct rnbd_srv_sess_dev *sess_dev, bool keep_id)
        rnbd_put_sess_dev(sess_dev);
        wait_for_completion(&dc); /* wait for inflights to drop to zero */
 
-       bdev_release(sess_dev->bdev_handle);
+       fput(sess_dev->bdev_file);
        mutex_lock(&sess_dev->dev->lock);
        list_del(&sess_dev->dev_list);
        if (!sess_dev->readonly)
@@ -534,7 +534,7 @@ rnbd_srv_get_or_create_srv_dev(struct block_device *bdev,
 static void rnbd_srv_fill_msg_open_rsp(struct rnbd_msg_open_rsp *rsp,
                                        struct rnbd_srv_sess_dev *sess_dev)
 {
-       struct block_device *bdev = sess_dev->bdev_handle->bdev;
+       struct block_device *bdev = file_bdev(sess_dev->bdev_file);
 
        rsp->hdr.type = cpu_to_le16(RNBD_MSG_OPEN_RSP);
        rsp->device_id = cpu_to_le32(sess_dev->device_id);
@@ -560,7 +560,7 @@ static void rnbd_srv_fill_msg_open_rsp(struct rnbd_msg_open_rsp *rsp,
 static struct rnbd_srv_sess_dev *
 rnbd_srv_create_set_sess_dev(struct rnbd_srv_session *srv_sess,
                              const struct rnbd_msg_open *open_msg,
-                             struct bdev_handle *handle, bool readonly,
+                             struct file *bdev_file, bool readonly,
                              struct rnbd_srv_dev *srv_dev)
 {
        struct rnbd_srv_sess_dev *sdev = rnbd_sess_dev_alloc(srv_sess);
@@ -572,7 +572,7 @@ rnbd_srv_create_set_sess_dev(struct rnbd_srv_session *srv_sess,
 
        strscpy(sdev->pathname, open_msg->dev_name, sizeof(sdev->pathname));
 
-       sdev->bdev_handle       = handle;
+       sdev->bdev_file         = bdev_file;
        sdev->sess              = srv_sess;
        sdev->dev               = srv_dev;
        sdev->readonly          = readonly;
@@ -678,7 +678,7 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess,
        struct rnbd_srv_dev *srv_dev;
        struct rnbd_srv_sess_dev *srv_sess_dev;
        const struct rnbd_msg_open *open_msg = msg;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        blk_mode_t open_flags = BLK_OPEN_READ;
        char *full_path;
        struct rnbd_msg_open_rsp *rsp = data;
@@ -716,15 +716,15 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess,
                goto reject;
        }
 
-       bdev_handle = bdev_open_by_path(full_path, open_flags, NULL, NULL);
-       if (IS_ERR(bdev_handle)) {
-               ret = PTR_ERR(bdev_handle);
+       bdev_file = bdev_file_open_by_path(full_path, open_flags, NULL, NULL);
+       if (IS_ERR(bdev_file)) {
+               ret = PTR_ERR(bdev_file);
                pr_err("Opening device '%s' on session %s failed, failed to open the block device, err: %pe\n",
-                      full_path, srv_sess->sessname, bdev_handle);
+                      full_path, srv_sess->sessname, bdev_file);
                goto free_path;
        }
 
-       srv_dev = rnbd_srv_get_or_create_srv_dev(bdev_handle->bdev, srv_sess,
+       srv_dev = rnbd_srv_get_or_create_srv_dev(file_bdev(bdev_file), srv_sess,
                                                  open_msg->access_mode);
        if (IS_ERR(srv_dev)) {
                pr_err("Opening device '%s' on session %s failed, creating srv_dev failed, err: %pe\n",
@@ -734,7 +734,7 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess,
        }
 
        srv_sess_dev = rnbd_srv_create_set_sess_dev(srv_sess, open_msg,
-                               bdev_handle,
+                               bdev_file,
                                open_msg->access_mode == RNBD_ACCESS_RO,
                                srv_dev);
        if (IS_ERR(srv_sess_dev)) {
@@ -750,7 +750,7 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess,
         */
        mutex_lock(&srv_dev->lock);
        if (!srv_dev->dev_kobj.state_in_sysfs) {
-               ret = rnbd_srv_create_dev_sysfs(srv_dev, bdev_handle->bdev);
+               ret = rnbd_srv_create_dev_sysfs(srv_dev, file_bdev(bdev_file));
                if (ret) {
                        mutex_unlock(&srv_dev->lock);
                        rnbd_srv_err(srv_sess_dev,
@@ -793,7 +793,7 @@ srv_dev_put:
        }
        rnbd_put_srv_dev(srv_dev);
 blkdev_put:
-       bdev_release(bdev_handle);
+       fput(bdev_file);
 free_path:
        kfree(full_path);
 reject:
index 343cc682b617b4447e813e0027a7ed009133fe23..18d873808b8d835d61017124939b880dfc2d26d8 100644 (file)
@@ -46,7 +46,7 @@ struct rnbd_srv_dev {
 struct rnbd_srv_sess_dev {
        /* Entry inside rnbd_srv_dev struct */
        struct list_head                dev_list;
-       struct bdev_handle              *bdev_handle;
+       struct file                     *bdev_file;
        struct rnbd_srv_session         *sess;
        struct rnbd_srv_dev             *dev;
        struct kobject                  kobj;
index 7bf4b48e2282e72247d3db519110d4de04b80f14..c99dd6698977ea61992aa0cb087109ef1c380c3f 100644 (file)
@@ -784,6 +784,14 @@ static const struct blk_mq_ops vdc_mq_ops = {
 
 static int probe_disk(struct vdc_port *port)
 {
+       struct queue_limits lim = {
+               .physical_block_size            = port->vdisk_phys_blksz,
+               .max_hw_sectors                 = port->max_xfer_size,
+               /* Each segment in a request is up to an aligned page in size. */
+               .seg_boundary_mask              = PAGE_SIZE - 1,
+               .max_segment_size               = PAGE_SIZE,
+               .max_segments                   = port->ring_cookies,
+       };
        struct request_queue *q;
        struct gendisk *g;
        int err;
@@ -824,7 +832,7 @@ static int probe_disk(struct vdc_port *port)
        if (err)
                return err;
 
-       g = blk_mq_alloc_disk(&port->tag_set, port);
+       g = blk_mq_alloc_disk(&port->tag_set, &lim, port);
        if (IS_ERR(g)) {
                printk(KERN_ERR PFX "%s: Could not allocate gendisk.\n",
                       port->vio.name);
@@ -835,12 +843,6 @@ static int probe_disk(struct vdc_port *port)
        port->disk = g;
        q = g->queue;
 
-       /* Each segment in a request is up to an aligned page in size. */
-       blk_queue_segment_boundary(q, PAGE_SIZE - 1);
-       blk_queue_max_segment_size(q, PAGE_SIZE);
-
-       blk_queue_max_segments(q, port->ring_cookies);
-       blk_queue_max_hw_sectors(q, port->max_xfer_size);
        g->major = vdc_major;
        g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
        g->minors = 1 << PARTITION_SHIFT;
@@ -872,8 +874,6 @@ static int probe_disk(struct vdc_port *port)
                }
        }
 
-       blk_queue_physical_block_size(q, port->vdisk_phys_blksz);
-
        pr_info(PFX "%s: %u sectors (%u MB) protocol %d.%d\n",
               g->disk_name,
               port->vdisk_size, (port->vdisk_size >> (20 - 9)),
index f85b6af414b4318b394665bec1a679f174b31755..6731678f3a41db753c306a3f90a84b6aa17bb0dc 100644 (file)
@@ -820,7 +820,7 @@ static int swim_floppy_init(struct swim_priv *swd)
                        goto exit_put_disks;
 
                swd->unit[drive].disk =
-                       blk_mq_alloc_disk(&swd->unit[drive].tag_set,
+                       blk_mq_alloc_disk(&swd->unit[drive].tag_set, NULL,
                                          &swd->unit[drive]);
                if (IS_ERR(swd->unit[drive].disk)) {
                        blk_mq_free_tag_set(&swd->unit[drive].tag_set);
@@ -916,7 +916,7 @@ out:
        return ret;
 }
 
-static int swim_remove(struct platform_device *dev)
+static void swim_remove(struct platform_device *dev)
 {
        struct swim_priv *swd = platform_get_drvdata(dev);
        int drive;
@@ -937,13 +937,11 @@ static int swim_remove(struct platform_device *dev)
                release_mem_region(res->start, resource_size(res));
 
        kfree(swd);
-
-       return 0;
 }
 
 static struct platform_driver swim_driver = {
        .probe  = swim_probe,
-       .remove = swim_remove,
+       .remove_new = swim_remove,
        .driver   = {
                .name   = CARDNAME,
        },
index c2bc85826358e93df0896821529ac8a5e81caa19..a04756ac778ee803ddbe287d7c770ceceb247694 100644 (file)
@@ -1210,7 +1210,7 @@ static int swim3_attach(struct macio_dev *mdev,
        if (rc)
                goto out_unregister;
 
-       disk = blk_mq_alloc_disk(&fs->tag_set, fs);
+       disk = blk_mq_alloc_disk(&fs->tag_set, NULL, fs);
        if (IS_ERR(disk)) {
                rc = PTR_ERR(disk);
                goto out_free_tag_set;
index 1dfb2e77898ba64215c8da9a9f3219f91f3616a6..bea3d5cf8a83487909270d5f2398267250507a31 100644 (file)
@@ -246,21 +246,12 @@ static int ublk_dev_param_zoned_validate(const struct ublk_device *ub)
        return 0;
 }
 
-static int ublk_dev_param_zoned_apply(struct ublk_device *ub)
+static void ublk_dev_param_zoned_apply(struct ublk_device *ub)
 {
-       const struct ublk_param_zoned *p = &ub->params.zoned;
-
-       disk_set_zoned(ub->ub_disk);
        blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, ub->ub_disk->queue);
        blk_queue_required_elevator_features(ub->ub_disk->queue,
                                             ELEVATOR_F_ZBD_SEQ_WRITE);
-       disk_set_max_active_zones(ub->ub_disk, p->max_active_zones);
-       disk_set_max_open_zones(ub->ub_disk, p->max_open_zones);
-       blk_queue_max_zone_append_sectors(ub->ub_disk->queue, p->max_zone_append_sectors);
-
        ub->ub_disk->nr_zones = ublk_get_nr_zones(ub);
-
-       return 0;
 }
 
 /* Based on virtblk_alloc_report_buffer */
@@ -432,9 +423,8 @@ static int ublk_dev_param_zoned_validate(const struct ublk_device *ub)
        return -EOPNOTSUPP;
 }
 
-static int ublk_dev_param_zoned_apply(struct ublk_device *ub)
+static void ublk_dev_param_zoned_apply(struct ublk_device *ub)
 {
-       return -EOPNOTSUPP;
 }
 
 static int ublk_revalidate_disk_zones(struct ublk_device *ub)
@@ -498,11 +488,6 @@ static void ublk_dev_param_basic_apply(struct ublk_device *ub)
        struct request_queue *q = ub->ub_disk->queue;
        const struct ublk_param_basic *p = &ub->params.basic;
 
-       blk_queue_logical_block_size(q, 1 << p->logical_bs_shift);
-       blk_queue_physical_block_size(q, 1 << p->physical_bs_shift);
-       blk_queue_io_min(q, 1 << p->io_min_shift);
-       blk_queue_io_opt(q, 1 << p->io_opt_shift);
-
        blk_queue_write_cache(q, p->attrs & UBLK_ATTR_VOLATILE_CACHE,
                        p->attrs & UBLK_ATTR_FUA);
        if (p->attrs & UBLK_ATTR_ROTATIONAL)
@@ -510,29 +495,12 @@ static void ublk_dev_param_basic_apply(struct ublk_device *ub)
        else
                blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
 
-       blk_queue_max_hw_sectors(q, p->max_sectors);
-       blk_queue_chunk_sectors(q, p->chunk_sectors);
-       blk_queue_virt_boundary(q, p->virt_boundary_mask);
-
        if (p->attrs & UBLK_ATTR_READ_ONLY)
                set_disk_ro(ub->ub_disk, true);
 
        set_capacity(ub->ub_disk, p->dev_sectors);
 }
 
-static void ublk_dev_param_discard_apply(struct ublk_device *ub)
-{
-       struct request_queue *q = ub->ub_disk->queue;
-       const struct ublk_param_discard *p = &ub->params.discard;
-
-       q->limits.discard_alignment = p->discard_alignment;
-       q->limits.discard_granularity = p->discard_granularity;
-       blk_queue_max_discard_sectors(q, p->max_discard_sectors);
-       blk_queue_max_write_zeroes_sectors(q,
-                       p->max_write_zeroes_sectors);
-       blk_queue_max_discard_segments(q, p->max_discard_segments);
-}
-
 static int ublk_validate_params(const struct ublk_device *ub)
 {
        /* basic param is the only one which must be set */
@@ -576,20 +544,12 @@ static int ublk_validate_params(const struct ublk_device *ub)
        return 0;
 }
 
-static int ublk_apply_params(struct ublk_device *ub)
+static void ublk_apply_params(struct ublk_device *ub)
 {
-       if (!(ub->params.types & UBLK_PARAM_TYPE_BASIC))
-               return -EINVAL;
-
        ublk_dev_param_basic_apply(ub);
 
-       if (ub->params.types & UBLK_PARAM_TYPE_DISCARD)
-               ublk_dev_param_discard_apply(ub);
-
        if (ub->params.types & UBLK_PARAM_TYPE_ZONED)
-               return ublk_dev_param_zoned_apply(ub);
-
-       return 0;
+               ublk_dev_param_zoned_apply(ub);
 }
 
 static inline bool ublk_support_user_copy(const struct ublk_queue *ubq)
@@ -645,14 +605,16 @@ static inline bool ublk_need_get_data(const struct ublk_queue *ubq)
        return ubq->flags & UBLK_F_NEED_GET_DATA;
 }
 
-static struct ublk_device *ublk_get_device(struct ublk_device *ub)
+/* Called in slow path only, keep it noinline for trace purpose */
+static noinline struct ublk_device *ublk_get_device(struct ublk_device *ub)
 {
        if (kobject_get_unless_zero(&ub->cdev_dev.kobj))
                return ub;
        return NULL;
 }
 
-static void ublk_put_device(struct ublk_device *ub)
+/* Called in slow path only, keep it noinline for trace purpose */
+static noinline void ublk_put_device(struct ublk_device *ub)
 {
        put_device(&ub->cdev_dev);
 }
@@ -711,7 +673,7 @@ static void ublk_free_disk(struct gendisk *disk)
        struct ublk_device *ub = disk->private_data;
 
        clear_bit(UB_STATE_USED, &ub->state);
-       put_device(&ub->cdev_dev);
+       ublk_put_device(ub);
 }
 
 static void ublk_store_owner_uid_gid(unsigned int *owner_uid,
@@ -2182,7 +2144,7 @@ static void ublk_remove(struct ublk_device *ub)
        cancel_work_sync(&ub->stop_work);
        cancel_work_sync(&ub->quiesce_work);
        cdev_device_del(&ub->cdev, &ub->cdev_dev);
-       put_device(&ub->cdev_dev);
+       ublk_put_device(ub);
        ublks_added--;
 }
 
@@ -2205,12 +2167,47 @@ static struct ublk_device *ublk_get_device_from_id(int idx)
 static int ublk_ctrl_start_dev(struct ublk_device *ub, struct io_uring_cmd *cmd)
 {
        const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe);
+       const struct ublk_param_basic *p = &ub->params.basic;
        int ublksrv_pid = (int)header->data[0];
+       struct queue_limits lim = {
+               .logical_block_size     = 1 << p->logical_bs_shift,
+               .physical_block_size    = 1 << p->physical_bs_shift,
+               .io_min                 = 1 << p->io_min_shift,
+               .io_opt                 = 1 << p->io_opt_shift,
+               .max_hw_sectors         = p->max_sectors,
+               .chunk_sectors          = p->chunk_sectors,
+               .virt_boundary_mask     = p->virt_boundary_mask,
+
+       };
        struct gendisk *disk;
        int ret = -EINVAL;
 
        if (ublksrv_pid <= 0)
                return -EINVAL;
+       if (!(ub->params.types & UBLK_PARAM_TYPE_BASIC))
+               return -EINVAL;
+
+       if (ub->params.types & UBLK_PARAM_TYPE_DISCARD) {
+               const struct ublk_param_discard *pd = &ub->params.discard;
+
+               lim.discard_alignment = pd->discard_alignment;
+               lim.discard_granularity = pd->discard_granularity;
+               lim.max_hw_discard_sectors = pd->max_discard_sectors;
+               lim.max_write_zeroes_sectors = pd->max_write_zeroes_sectors;
+               lim.max_discard_segments = pd->max_discard_segments;
+       }
+
+       if (ub->params.types & UBLK_PARAM_TYPE_ZONED) {
+               const struct ublk_param_zoned *p = &ub->params.zoned;
+
+               if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED))
+                       return -EOPNOTSUPP;
+
+               lim.zoned = true;
+               lim.max_active_zones = p->max_active_zones;
+               lim.max_open_zones =  p->max_open_zones;
+               lim.max_zone_append_sectors = p->max_zone_append_sectors;
+       }
 
        if (wait_for_completion_interruptible(&ub->completion) != 0)
                return -EINTR;
@@ -2222,7 +2219,7 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, struct io_uring_cmd *cmd)
                goto out_unlock;
        }
 
-       disk = blk_mq_alloc_disk(&ub->tag_set, NULL);
+       disk = blk_mq_alloc_disk(&ub->tag_set, &lim, NULL);
        if (IS_ERR(disk)) {
                ret = PTR_ERR(disk);
                goto out_unlock;
@@ -2234,15 +2231,13 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, struct io_uring_cmd *cmd)
        ub->dev_info.ublksrv_pid = ublksrv_pid;
        ub->ub_disk = disk;
 
-       ret = ublk_apply_params(ub);
-       if (ret)
-               goto out_put_disk;
+       ublk_apply_params(ub);
 
        /* don't probe partitions if any one ubq daemon is un-trusted */
        if (ub->nr_privileged_daemon != ub->nr_queues_ready)
                set_bit(GD_SUPPRESS_PART_SCAN, &disk->state);
 
-       get_device(&ub->cdev_dev);
+       ublk_get_device(ub);
        ub->dev_info.state = UBLK_S_DEV_LIVE;
 
        if (ublk_dev_is_zoned(ub)) {
@@ -2262,7 +2257,6 @@ out_put_cdev:
                ub->dev_info.state = UBLK_S_DEV_DEAD;
                ublk_put_device(ub);
        }
-out_put_disk:
        if (ret)
                put_disk(disk);
 out_unlock:
@@ -2474,7 +2468,7 @@ static inline bool ublk_idr_freed(int id)
        return ptr == NULL;
 }
 
-static int ublk_ctrl_del_dev(struct ublk_device **p_ub)
+static int ublk_ctrl_del_dev(struct ublk_device **p_ub, bool wait)
 {
        struct ublk_device *ub = *p_ub;
        int idx = ub->ub_number;
@@ -2508,7 +2502,7 @@ static int ublk_ctrl_del_dev(struct ublk_device **p_ub)
         * - the device number is freed already, we will not find this
         *   device via ublk_get_device_from_id()
         */
-       if (wait_event_interruptible(ublk_idr_wq, ublk_idr_freed(idx)))
+       if (wait && wait_event_interruptible(ublk_idr_wq, ublk_idr_freed(idx)))
                return -EINTR;
        return 0;
 }
@@ -2907,7 +2901,10 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
                ret = ublk_ctrl_add_dev(cmd);
                break;
        case UBLK_CMD_DEL_DEV:
-               ret = ublk_ctrl_del_dev(&ub);
+               ret = ublk_ctrl_del_dev(&ub, true);
+               break;
+       case UBLK_U_CMD_DEL_DEV_ASYNC:
+               ret = ublk_ctrl_del_dev(&ub, false);
                break;
        case UBLK_CMD_GET_QUEUE_AFFINITY:
                ret = ublk_ctrl_get_queue_affinity(ub, cmd);
index 2bf14a0e2815f6292a02b3fa1e394489af780074..42dea7601d8799279b17aaa4929b93503f721e3a 100644 (file)
@@ -720,25 +720,24 @@ fail_report:
        return ret;
 }
 
-static int virtblk_probe_zoned_device(struct virtio_device *vdev,
-                                      struct virtio_blk *vblk,
-                                      struct request_queue *q)
+static int virtblk_read_zoned_limits(struct virtio_blk *vblk,
+               struct queue_limits *lim)
 {
+       struct virtio_device *vdev = vblk->vdev;
        u32 v, wg;
 
        dev_dbg(&vdev->dev, "probing host-managed zoned device\n");
 
-       disk_set_zoned(vblk->disk);
-       blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
+       lim->zoned = true;
 
        virtio_cread(vdev, struct virtio_blk_config,
                     zoned.max_open_zones, &v);
-       disk_set_max_open_zones(vblk->disk, v);
+       lim->max_open_zones = v;
        dev_dbg(&vdev->dev, "max open zones = %u\n", v);
 
        virtio_cread(vdev, struct virtio_blk_config,
                     zoned.max_active_zones, &v);
-       disk_set_max_active_zones(vblk->disk, v);
+       lim->max_active_zones = v;
        dev_dbg(&vdev->dev, "max active zones = %u\n", v);
 
        virtio_cread(vdev, struct virtio_blk_config,
@@ -747,8 +746,8 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
                dev_warn(&vdev->dev, "zero write granularity reported\n");
                return -ENODEV;
        }
-       blk_queue_physical_block_size(q, wg);
-       blk_queue_io_min(q, wg);
+       lim->physical_block_size = wg;
+       lim->io_min = wg;
 
        dev_dbg(&vdev->dev, "write granularity = %u\n", wg);
 
@@ -764,13 +763,13 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
                        vblk->zone_sectors);
                return -ENODEV;
        }
-       blk_queue_chunk_sectors(q, vblk->zone_sectors);
+       lim->chunk_sectors = vblk->zone_sectors;
        dev_dbg(&vdev->dev, "zone sectors = %u\n", vblk->zone_sectors);
 
        if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
                dev_warn(&vblk->vdev->dev,
                         "ignoring negotiated F_DISCARD for zoned device\n");
-               blk_queue_max_discard_sectors(q, 0);
+               lim->max_hw_discard_sectors = 0;
        }
 
        virtio_cread(vdev, struct virtio_blk_config,
@@ -785,25 +784,21 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
                        wg, v);
                return -ENODEV;
        }
-       blk_queue_max_zone_append_sectors(q, v);
+       lim->max_zone_append_sectors = v;
        dev_dbg(&vdev->dev, "max append sectors = %u\n", v);
 
-       return blk_revalidate_disk_zones(vblk->disk, NULL);
+       return 0;
 }
-
 #else
-
 /*
- * Zoned block device support is not configured in this kernel.
- * Host-managed zoned devices can't be supported, but others are
- * good to go as regular block devices.
+ * Zoned block device support is not configured in this kernel, host-managed
+ * zoned devices can't be supported.
  */
 #define virtblk_report_zones       NULL
-
-static inline int virtblk_probe_zoned_device(struct virtio_device *vdev,
-                       struct virtio_blk *vblk, struct request_queue *q)
+static inline int virtblk_read_zoned_limits(struct virtio_blk *vblk,
+               struct queue_limits *lim)
 {
-       dev_err(&vdev->dev,
+       dev_err(&vblk->vdev->dev,
                "virtio_blk: zoned devices are not supported");
        return -EOPNOTSUPP;
 }
@@ -1248,31 +1243,17 @@ static const struct blk_mq_ops virtio_mq_ops = {
 static unsigned int virtblk_queue_depth;
 module_param_named(queue_depth, virtblk_queue_depth, uint, 0444);
 
-static int virtblk_probe(struct virtio_device *vdev)
+static int virtblk_read_limits(struct virtio_blk *vblk,
+               struct queue_limits *lim)
 {
-       struct virtio_blk *vblk;
-       struct request_queue *q;
-       int err, index;
-
+       struct virtio_device *vdev = vblk->vdev;
        u32 v, blk_size, max_size, sg_elems, opt_io_size;
        u32 max_discard_segs = 0;
        u32 discard_granularity = 0;
        u16 min_io_size;
        u8 physical_block_exp, alignment_offset;
-       unsigned int queue_depth;
        size_t max_dma_size;
-
-       if (!vdev->config->get) {
-               dev_err(&vdev->dev, "%s failure: config access disabled\n",
-                       __func__);
-               return -EINVAL;
-       }
-
-       err = ida_alloc_range(&vd_index_ida, 0,
-                             minor_to_index(1 << MINORBITS) - 1, GFP_KERNEL);
-       if (err < 0)
-               goto out;
-       index = err;
+       int err;
 
        /* We need to know how many segments before we allocate. */
        err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SEG_MAX,
@@ -1286,78 +1267,11 @@ static int virtblk_probe(struct virtio_device *vdev)
        /* Prevent integer overflows and honor max vq size */
        sg_elems = min_t(u32, sg_elems, VIRTIO_BLK_MAX_SG_ELEMS - 2);
 
-       vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
-       if (!vblk) {
-               err = -ENOMEM;
-               goto out_free_index;
-       }
-
-       mutex_init(&vblk->vdev_mutex);
-
-       vblk->vdev = vdev;
-
-       INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
-
-       err = init_vq(vblk);
-       if (err)
-               goto out_free_vblk;
-
-       /* Default queue sizing is to fill the ring. */
-       if (!virtblk_queue_depth) {
-               queue_depth = vblk->vqs[0].vq->num_free;
-               /* ... but without indirect descs, we use 2 descs per req */
-               if (!virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC))
-                       queue_depth /= 2;
-       } else {
-               queue_depth = virtblk_queue_depth;
-       }
-
-       memset(&vblk->tag_set, 0, sizeof(vblk->tag_set));
-       vblk->tag_set.ops = &virtio_mq_ops;
-       vblk->tag_set.queue_depth = queue_depth;
-       vblk->tag_set.numa_node = NUMA_NO_NODE;
-       vblk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
-       vblk->tag_set.cmd_size =
-               sizeof(struct virtblk_req) +
-               sizeof(struct scatterlist) * VIRTIO_BLK_INLINE_SG_CNT;
-       vblk->tag_set.driver_data = vblk;
-       vblk->tag_set.nr_hw_queues = vblk->num_vqs;
-       vblk->tag_set.nr_maps = 1;
-       if (vblk->io_queues[HCTX_TYPE_POLL])
-               vblk->tag_set.nr_maps = 3;
-
-       err = blk_mq_alloc_tag_set(&vblk->tag_set);
-       if (err)
-               goto out_free_vq;
-
-       vblk->disk = blk_mq_alloc_disk(&vblk->tag_set, vblk);
-       if (IS_ERR(vblk->disk)) {
-               err = PTR_ERR(vblk->disk);
-               goto out_free_tags;
-       }
-       q = vblk->disk->queue;
-
-       virtblk_name_format("vd", index, vblk->disk->disk_name, DISK_NAME_LEN);
-
-       vblk->disk->major = major;
-       vblk->disk->first_minor = index_to_minor(index);
-       vblk->disk->minors = 1 << PART_BITS;
-       vblk->disk->private_data = vblk;
-       vblk->disk->fops = &virtblk_fops;
-       vblk->index = index;
-
-       /* configure queue flush support */
-       virtblk_update_cache_mode(vdev);
-
-       /* If disk is read-only in the host, the guest should obey */
-       if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
-               set_disk_ro(vblk->disk, 1);
-
        /* We can handle whatever the host told us to handle. */
-       blk_queue_max_segments(q, sg_elems);
+       lim->max_segments = sg_elems;
 
        /* No real sector limit. */
-       blk_queue_max_hw_sectors(q, UINT_MAX);
+       lim->max_hw_sectors = UINT_MAX;
 
        max_dma_size = virtio_max_dma_size(vdev);
        max_size = max_dma_size > U32_MAX ? U32_MAX : max_dma_size;
@@ -1369,7 +1283,7 @@ static int virtblk_probe(struct virtio_device *vdev)
        if (!err)
                max_size = min(max_size, v);
 
-       blk_queue_max_segment_size(q, max_size);
+       lim->max_segment_size = max_size;
 
        /* Host can optionally specify the block size of the device */
        err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE,
@@ -1381,38 +1295,37 @@ static int virtblk_probe(struct virtio_device *vdev)
                        dev_err(&vdev->dev,
                                "virtio_blk: invalid block size: 0x%x\n",
                                blk_size);
-                       goto out_cleanup_disk;
+                       return err;
                }
 
-               blk_queue_logical_block_size(q, blk_size);
+               lim->logical_block_size = blk_size;
        } else
-               blk_size = queue_logical_block_size(q);
+               blk_size = lim->logical_block_size;
 
        /* Use topology information if available */
        err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
                                   struct virtio_blk_config, physical_block_exp,
                                   &physical_block_exp);
        if (!err && physical_block_exp)
-               blk_queue_physical_block_size(q,
-                               blk_size * (1 << physical_block_exp));
+               lim->physical_block_size = blk_size * (1 << physical_block_exp);
 
        err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
                                   struct virtio_blk_config, alignment_offset,
                                   &alignment_offset);
        if (!err && alignment_offset)
-               blk_queue_alignment_offset(q, blk_size * alignment_offset);
+               lim->alignment_offset = blk_size * alignment_offset;
 
        err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
                                   struct virtio_blk_config, min_io_size,
                                   &min_io_size);
        if (!err && min_io_size)
-               blk_queue_io_min(q, blk_size * min_io_size);
+               lim->io_min = blk_size * min_io_size;
 
        err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
                                   struct virtio_blk_config, opt_io_size,
                                   &opt_io_size);
        if (!err && opt_io_size)
-               blk_queue_io_opt(q, blk_size * opt_io_size);
+               lim->io_opt = blk_size * opt_io_size;
 
        if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
                virtio_cread(vdev, struct virtio_blk_config,
@@ -1420,7 +1333,7 @@ static int virtblk_probe(struct virtio_device *vdev)
 
                virtio_cread(vdev, struct virtio_blk_config,
                             max_discard_sectors, &v);
-               blk_queue_max_discard_sectors(q, v ? v : UINT_MAX);
+               lim->max_hw_discard_sectors = v ? v : UINT_MAX;
 
                virtio_cread(vdev, struct virtio_blk_config, max_discard_seg,
                             &max_discard_segs);
@@ -1429,7 +1342,7 @@ static int virtblk_probe(struct virtio_device *vdev)
        if (virtio_has_feature(vdev, VIRTIO_BLK_F_WRITE_ZEROES)) {
                virtio_cread(vdev, struct virtio_blk_config,
                             max_write_zeroes_sectors, &v);
-               blk_queue_max_write_zeroes_sectors(q, v ? v : UINT_MAX);
+               lim->max_write_zeroes_sectors = v ? v : UINT_MAX;
        }
 
        /* The discard and secure erase limits are combined since the Linux
@@ -1455,8 +1368,7 @@ static int virtblk_probe(struct virtio_device *vdev)
                if (!v) {
                        dev_err(&vdev->dev,
                                "virtio_blk: secure_erase_sector_alignment can't be 0\n");
-                       err = -EINVAL;
-                       goto out_cleanup_disk;
+                       return -EINVAL;
                }
 
                discard_granularity = min_not_zero(discard_granularity, v);
@@ -1470,11 +1382,10 @@ static int virtblk_probe(struct virtio_device *vdev)
                if (!v) {
                        dev_err(&vdev->dev,
                                "virtio_blk: max_secure_erase_sectors can't be 0\n");
-                       err = -EINVAL;
-                       goto out_cleanup_disk;
+                       return -EINVAL;
                }
 
-               blk_queue_max_secure_erase_sectors(q, v);
+               lim->max_secure_erase_sectors = v;
 
                virtio_cread(vdev, struct virtio_blk_config,
                             max_secure_erase_seg, &v);
@@ -1485,8 +1396,7 @@ static int virtblk_probe(struct virtio_device *vdev)
                if (!v) {
                        dev_err(&vdev->dev,
                                "virtio_blk: max_secure_erase_seg can't be 0\n");
-                       err = -EINVAL;
-                       goto out_cleanup_disk;
+                       return -EINVAL;
                }
 
                max_discard_segs = min_not_zero(max_discard_segs, v);
@@ -1502,45 +1412,142 @@ static int virtblk_probe(struct virtio_device *vdev)
                if (!max_discard_segs)
                        max_discard_segs = sg_elems;
 
-               blk_queue_max_discard_segments(q,
-                                              min(max_discard_segs, MAX_DISCARD_SEGMENTS));
+               lim->max_discard_segments =
+                       min(max_discard_segs, MAX_DISCARD_SEGMENTS);
 
                if (discard_granularity)
-                       q->limits.discard_granularity = discard_granularity << SECTOR_SHIFT;
+                       lim->discard_granularity =
+                               discard_granularity << SECTOR_SHIFT;
                else
-                       q->limits.discard_granularity = blk_size;
+                       lim->discard_granularity = blk_size;
        }
 
-       virtblk_update_capacity(vblk, false);
-       virtio_device_ready(vdev);
-
-       /*
-        * All steps that follow use the VQs therefore they need to be
-        * placed after the virtio_device_ready() call above.
-        */
        if (virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED)) {
                u8 model;
 
-               virtio_cread(vdev, struct virtio_blk_config, zoned.model,
-                               &model);
+               virtio_cread(vdev, struct virtio_blk_config, zoned.model, &model);
                switch (model) {
                case VIRTIO_BLK_Z_NONE:
                case VIRTIO_BLK_Z_HA:
-                       /* Present the host-aware device as non-zoned */
-                       break;
+                       /* treat host-aware devices as non-zoned */
+                       return 0;
                case VIRTIO_BLK_Z_HM:
-                       err = virtblk_probe_zoned_device(vdev, vblk, q);
+                       err = virtblk_read_zoned_limits(vblk, lim);
                        if (err)
-                               goto out_cleanup_disk;
+                               return err;
                        break;
                default:
-                       dev_err(&vdev->dev, "unsupported zone model %d\n",
-                               model);
-                       err = -EINVAL;
-                       goto out_cleanup_disk;
+                       dev_err(&vdev->dev, "unsupported zone model %d\n", model);
+                       return -EINVAL;
                }
        }
 
+       return 0;
+}
+
+static int virtblk_probe(struct virtio_device *vdev)
+{
+       struct virtio_blk *vblk;
+       struct queue_limits lim = { };
+       int err, index;
+       unsigned int queue_depth;
+
+       if (!vdev->config->get) {
+               dev_err(&vdev->dev, "%s failure: config access disabled\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       err = ida_alloc_range(&vd_index_ida, 0,
+                             minor_to_index(1 << MINORBITS) - 1, GFP_KERNEL);
+       if (err < 0)
+               goto out;
+       index = err;
+
+       vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
+       if (!vblk) {
+               err = -ENOMEM;
+               goto out_free_index;
+       }
+
+       mutex_init(&vblk->vdev_mutex);
+
+       vblk->vdev = vdev;
+
+       INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
+
+       err = init_vq(vblk);
+       if (err)
+               goto out_free_vblk;
+
+       /* Default queue sizing is to fill the ring. */
+       if (!virtblk_queue_depth) {
+               queue_depth = vblk->vqs[0].vq->num_free;
+               /* ... but without indirect descs, we use 2 descs per req */
+               if (!virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC))
+                       queue_depth /= 2;
+       } else {
+               queue_depth = virtblk_queue_depth;
+       }
+
+       memset(&vblk->tag_set, 0, sizeof(vblk->tag_set));
+       vblk->tag_set.ops = &virtio_mq_ops;
+       vblk->tag_set.queue_depth = queue_depth;
+       vblk->tag_set.numa_node = NUMA_NO_NODE;
+       vblk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+       vblk->tag_set.cmd_size =
+               sizeof(struct virtblk_req) +
+               sizeof(struct scatterlist) * VIRTIO_BLK_INLINE_SG_CNT;
+       vblk->tag_set.driver_data = vblk;
+       vblk->tag_set.nr_hw_queues = vblk->num_vqs;
+       vblk->tag_set.nr_maps = 1;
+       if (vblk->io_queues[HCTX_TYPE_POLL])
+               vblk->tag_set.nr_maps = 3;
+
+       err = blk_mq_alloc_tag_set(&vblk->tag_set);
+       if (err)
+               goto out_free_vq;
+
+       err = virtblk_read_limits(vblk, &lim);
+       if (err)
+               goto out_free_tags;
+
+       vblk->disk = blk_mq_alloc_disk(&vblk->tag_set, &lim, vblk);
+       if (IS_ERR(vblk->disk)) {
+               err = PTR_ERR(vblk->disk);
+               goto out_free_tags;
+       }
+
+       virtblk_name_format("vd", index, vblk->disk->disk_name, DISK_NAME_LEN);
+
+       vblk->disk->major = major;
+       vblk->disk->first_minor = index_to_minor(index);
+       vblk->disk->minors = 1 << PART_BITS;
+       vblk->disk->private_data = vblk;
+       vblk->disk->fops = &virtblk_fops;
+       vblk->index = index;
+
+       /* configure queue flush support */
+       virtblk_update_cache_mode(vdev);
+
+       /* If disk is read-only in the host, the guest should obey */
+       if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
+               set_disk_ro(vblk->disk, 1);
+
+       virtblk_update_capacity(vblk, false);
+       virtio_device_ready(vdev);
+
+       /*
+        * All steps that follow use the VQs therefore they need to be
+        * placed after the virtio_device_ready() call above.
+        */
+       if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && lim.zoned) {
+               blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, vblk->disk->queue);
+               err = blk_revalidate_disk_zones(vblk->disk, NULL);
+               if (err)
+                       goto out_cleanup_disk;
+       }
+
        err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);
        if (err)
                goto out_cleanup_disk;
index 4defd7f387c786b937b445e3f7b8615fc733075c..944576d582fb14145e64822118aaebfc0df343fe 100644 (file)
@@ -465,7 +465,7 @@ static int xen_vbd_translate(struct phys_req *req, struct xen_blkif *blkif,
        }
 
        req->dev  = vbd->pdevice;
-       req->bdev = vbd->bdev_handle->bdev;
+       req->bdev = file_bdev(vbd->bdev_file);
        rc = 0;
 
  out:
@@ -969,7 +969,7 @@ static int dispatch_discard_io(struct xen_blkif_ring *ring,
        int err = 0;
        int status = BLKIF_RSP_OKAY;
        struct xen_blkif *blkif = ring->blkif;
-       struct block_device *bdev = blkif->vbd.bdev_handle->bdev;
+       struct block_device *bdev = file_bdev(blkif->vbd.bdev_file);
        struct phys_req preq;
 
        xen_blkif_get(blkif);
index 1432c83183d098eab8865a8f9186dcd194170493..b427d54bc1205ec2903a01d51bd87511e619041e 100644 (file)
@@ -221,7 +221,7 @@ struct xen_vbd {
        unsigned char           type;
        /* phys device that this vbd maps to. */
        u32                     pdevice;
-       struct bdev_handle      *bdev_handle;
+       struct file             *bdev_file;
        /* Cached size parameter. */
        sector_t                size;
        unsigned int            flush_support:1;
@@ -360,7 +360,7 @@ struct pending_req {
 };
 
 
-#define vbd_sz(_v)     bdev_nr_sectors((_v)->bdev_handle->bdev)
+#define vbd_sz(_v)     bdev_nr_sectors(file_bdev((_v)->bdev_file))
 
 #define xen_blkif_get(_b) (atomic_inc(&(_b)->refcnt))
 #define xen_blkif_put(_b)                              \
index e34219ea2b058c47d7464be4ce64d18c81d0e3f2..0621878940ae57c5fcd3425cfc80dadd757e82c3 100644 (file)
@@ -81,7 +81,7 @@ static void xen_update_blkif_status(struct xen_blkif *blkif)
        int i;
 
        /* Not ready to connect? */
-       if (!blkif->rings || !blkif->rings[0].irq || !blkif->vbd.bdev_handle)
+       if (!blkif->rings || !blkif->rings[0].irq || !blkif->vbd.bdev_file)
                return;
 
        /* Already connected? */
@@ -99,13 +99,12 @@ static void xen_update_blkif_status(struct xen_blkif *blkif)
                return;
        }
 
-       err = sync_blockdev(blkif->vbd.bdev_handle->bdev);
+       err = sync_blockdev(file_bdev(blkif->vbd.bdev_file));
        if (err) {
                xenbus_dev_error(blkif->be->dev, err, "block flush");
                return;
        }
-       invalidate_inode_pages2(
-                       blkif->vbd.bdev_handle->bdev->bd_inode->i_mapping);
+       invalidate_inode_pages2(blkif->vbd.bdev_file->f_mapping);
 
        for (i = 0; i < blkif->nr_rings; i++) {
                ring = &blkif->rings[i];
@@ -473,9 +472,9 @@ static void xenvbd_sysfs_delif(struct xenbus_device *dev)
 
 static void xen_vbd_free(struct xen_vbd *vbd)
 {
-       if (vbd->bdev_handle)
-               bdev_release(vbd->bdev_handle);
-       vbd->bdev_handle = NULL;
+       if (vbd->bdev_file)
+               fput(vbd->bdev_file);
+       vbd->bdev_file = NULL;
 }
 
 static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
@@ -483,7 +482,7 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
                          int cdrom)
 {
        struct xen_vbd *vbd;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
 
        vbd = &blkif->vbd;
        vbd->handle   = handle;
@@ -492,17 +491,17 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
 
        vbd->pdevice  = MKDEV(major, minor);
 
-       bdev_handle = bdev_open_by_dev(vbd->pdevice, vbd->readonly ?
+       bdev_file = bdev_file_open_by_dev(vbd->pdevice, vbd->readonly ?
                                 BLK_OPEN_READ : BLK_OPEN_WRITE, NULL, NULL);
 
-       if (IS_ERR(bdev_handle)) {
+       if (IS_ERR(bdev_file)) {
                pr_warn("xen_vbd_create: device %08x could not be opened\n",
                        vbd->pdevice);
                return -ENOENT;
        }
 
-       vbd->bdev_handle = bdev_handle;
-       if (vbd->bdev_handle->bdev->bd_disk == NULL) {
+       vbd->bdev_file = bdev_file;
+       if (file_bdev(vbd->bdev_file)->bd_disk == NULL) {
                pr_warn("xen_vbd_create: device %08x doesn't exist\n",
                        vbd->pdevice);
                xen_vbd_free(vbd);
@@ -510,14 +509,14 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
        }
        vbd->size = vbd_sz(vbd);
 
-       if (cdrom || disk_to_cdi(vbd->bdev_handle->bdev->bd_disk))
+       if (cdrom || disk_to_cdi(file_bdev(vbd->bdev_file)->bd_disk))
                vbd->type |= VDISK_CDROM;
-       if (vbd->bdev_handle->bdev->bd_disk->flags & GENHD_FL_REMOVABLE)
+       if (file_bdev(vbd->bdev_file)->bd_disk->flags & GENHD_FL_REMOVABLE)
                vbd->type |= VDISK_REMOVABLE;
 
-       if (bdev_write_cache(bdev_handle->bdev))
+       if (bdev_write_cache(file_bdev(bdev_file)))
                vbd->flush_support = true;
-       if (bdev_max_secure_erase_sectors(bdev_handle->bdev))
+       if (bdev_max_secure_erase_sectors(file_bdev(bdev_file)))
                vbd->discard_secure = true;
 
        pr_debug("Successful creation of handle=%04x (dom=%u)\n",
@@ -570,7 +569,7 @@ static void xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info
        struct xen_blkif *blkif = be->blkif;
        int err;
        int state = 0;
-       struct block_device *bdev = be->blkif->vbd.bdev_handle->bdev;
+       struct block_device *bdev = file_bdev(be->blkif->vbd.bdev_file);
 
        if (!xenbus_read_unsigned(dev->nodename, "discard-enable", 1))
                return;
@@ -932,7 +931,7 @@ again:
        }
        err = xenbus_printf(xbt, dev->nodename, "sector-size", "%lu",
                            (unsigned long)bdev_logical_block_size(
-                                       be->blkif->vbd.bdev_handle->bdev));
+                                       file_bdev(be->blkif->vbd.bdev_file)));
        if (err) {
                xenbus_dev_fatal(dev, err, "writing %s/sector-size",
                                 dev->nodename);
@@ -940,7 +939,7 @@ again:
        }
        err = xenbus_printf(xbt, dev->nodename, "physical-sector-size", "%u",
                            bdev_physical_block_size(
-                                       be->blkif->vbd.bdev_handle->bdev));
+                                       file_bdev(be->blkif->vbd.bdev_file)));
        if (err)
                xenbus_dev_error(dev, err, "writing %s/physical-sector-size",
                                 dev->nodename);
index 434fab306777439754a0f9feed417f848b2442a4..fd7c0ff2139cee128ece1011791b2db03283e66c 100644 (file)
@@ -941,39 +941,35 @@ static const struct blk_mq_ops blkfront_mq_ops = {
        .complete = blkif_complete_rq,
 };
 
-static void blkif_set_queue_limits(struct blkfront_info *info)
+static void blkif_set_queue_limits(const struct blkfront_info *info,
+               struct queue_limits *lim)
 {
-       struct request_queue *rq = info->rq;
-       struct gendisk *gd = info->gd;
        unsigned int segments = info->max_indirect_segments ? :
                                BLKIF_MAX_SEGMENTS_PER_REQUEST;
 
-       blk_queue_flag_set(QUEUE_FLAG_VIRT, rq);
-
        if (info->feature_discard) {
-               blk_queue_max_discard_sectors(rq, get_capacity(gd));
-               rq->limits.discard_granularity = info->discard_granularity ?:
-                                                info->physical_sector_size;
-               rq->limits.discard_alignment = info->discard_alignment;
+               lim->max_hw_discard_sectors = UINT_MAX;
+               if (info->discard_granularity)
+                       lim->discard_granularity = info->discard_granularity;
+               lim->discard_alignment = info->discard_alignment;
                if (info->feature_secdiscard)
-                       blk_queue_max_secure_erase_sectors(rq,
-                                                          get_capacity(gd));
+                       lim->max_secure_erase_sectors = UINT_MAX;
        }
 
        /* Hard sector size and max sectors impersonate the equiv. hardware. */
-       blk_queue_logical_block_size(rq, info->sector_size);
-       blk_queue_physical_block_size(rq, info->physical_sector_size);
-       blk_queue_max_hw_sectors(rq, (segments * XEN_PAGE_SIZE) / 512);
+       lim->logical_block_size = info->sector_size;
+       lim->physical_block_size = info->physical_sector_size;
+       lim->max_hw_sectors = (segments * XEN_PAGE_SIZE) / 512;
 
        /* Each segment in a request is up to an aligned page in size. */
-       blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
-       blk_queue_max_segment_size(rq, PAGE_SIZE);
+       lim->seg_boundary_mask = PAGE_SIZE - 1;
+       lim->max_segment_size = PAGE_SIZE;
 
        /* Ensure a merged request will fit in a single I/O ring slot. */
-       blk_queue_max_segments(rq, segments / GRANTS_PER_PSEG);
+       lim->max_segments = segments / GRANTS_PER_PSEG;
 
        /* Make sure buffer addresses are sector-aligned. */
-       blk_queue_dma_alignment(rq, 511);
+       lim->dma_alignment = 511;
 }
 
 static const char *flush_info(struct blkfront_info *info)
@@ -1070,6 +1066,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
                struct blkfront_info *info, u16 sector_size,
                unsigned int physical_sector_size)
 {
+       struct queue_limits lim = {};
        struct gendisk *gd;
        int nr_minors = 1;
        int err;
@@ -1136,11 +1133,13 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
        if (err)
                goto out_release_minors;
 
-       gd = blk_mq_alloc_disk(&info->tag_set, info);
+       blkif_set_queue_limits(info, &lim);
+       gd = blk_mq_alloc_disk(&info->tag_set, &lim, info);
        if (IS_ERR(gd)) {
                err = PTR_ERR(gd);
                goto out_free_tag_set;
        }
+       blk_queue_flag_set(QUEUE_FLAG_VIRT, gd->queue);
 
        strcpy(gd->disk_name, DEV_NAME);
        ptr = encode_disk_name(gd->disk_name + sizeof(DEV_NAME) - 1, offset);
@@ -1162,7 +1161,6 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
        info->gd = gd;
        info->sector_size = sector_size;
        info->physical_sector_size = physical_sector_size;
-       blkif_set_queue_limits(info);
 
        xlvbd_flush(info);
 
@@ -2006,18 +2004,19 @@ static int blkfront_probe(struct xenbus_device *dev,
 
 static int blkif_recover(struct blkfront_info *info)
 {
+       struct queue_limits lim;
        unsigned int r_index;
        struct request *req, *n;
        int rc;
        struct bio *bio;
-       unsigned int segs;
        struct blkfront_ring_info *rinfo;
 
+       lim = queue_limits_start_update(info->rq);
        blkfront_gather_backend_features(info);
-       /* Reset limits changed by blk_mq_update_nr_hw_queues(). */
-       blkif_set_queue_limits(info);
-       segs = info->max_indirect_segments ? : BLKIF_MAX_SEGMENTS_PER_REQUEST;
-       blk_queue_max_segments(info->rq, segs / GRANTS_PER_PSEG);
+       blkif_set_queue_limits(info, &lim);
+       rc = queue_limits_commit_update(info->rq, &lim);
+       if (rc)
+               return rc;
 
        for_each_rinfo(info, rinfo, r_index) {
                rc = blkfront_setup_indirect(rinfo);
@@ -2037,7 +2036,9 @@ static int blkif_recover(struct blkfront_info *info)
        list_for_each_entry_safe(req, n, &info->requests, queuelist) {
                /* Requeue pending requests (flush or discard) */
                list_del_init(&req->queuelist);
-               BUG_ON(req->nr_phys_segments > segs);
+               BUG_ON(req->nr_phys_segments >
+                      (info->max_indirect_segments ? :
+                       BLKIF_MAX_SEGMENTS_PER_REQUEST));
                blk_mq_requeue_request(req, false);
        }
        blk_mq_start_stopped_hw_queues(info->rq, true);
index 11493167b0a848a255b5db442f97cb71e3f97e6a..7c5f4e4d9b50374cb96f5b1699cbeb0a60cc54d6 100644 (file)
@@ -318,7 +318,7 @@ static int z2ram_register_disk(int minor)
        struct gendisk *disk;
        int err;
 
-       disk = blk_mq_alloc_disk(&tag_set, NULL);
+       disk = blk_mq_alloc_disk(&tag_set, NULL, NULL);
        if (IS_ERR(disk))
                return PTR_ERR(disk);
 
index 6772e0c654fa7f885192caa273fc1220e5736682..da7a20fa6152a97462dbeeefc8fbb7a09409a91c 100644 (file)
@@ -426,11 +426,11 @@ static void reset_bdev(struct zram *zram)
        if (!zram->backing_dev)
                return;
 
-       bdev_release(zram->bdev_handle);
+       fput(zram->bdev_file);
        /* hope filp_close flush all of IO */
        filp_close(zram->backing_dev, NULL);
        zram->backing_dev = NULL;
-       zram->bdev_handle = NULL;
+       zram->bdev_file = NULL;
        zram->disk->fops = &zram_devops;
        kvfree(zram->bitmap);
        zram->bitmap = NULL;
@@ -476,7 +476,7 @@ static ssize_t backing_dev_store(struct device *dev,
        struct address_space *mapping;
        unsigned int bitmap_sz;
        unsigned long nr_pages, *bitmap = NULL;
-       struct bdev_handle *bdev_handle = NULL;
+       struct file *bdev_file = NULL;
        int err;
        struct zram *zram = dev_to_zram(dev);
 
@@ -513,11 +513,11 @@ static ssize_t backing_dev_store(struct device *dev,
                goto out;
        }
 
-       bdev_handle = bdev_open_by_dev(inode->i_rdev,
+       bdev_file = bdev_file_open_by_dev(inode->i_rdev,
                                BLK_OPEN_READ | BLK_OPEN_WRITE, zram, NULL);
-       if (IS_ERR(bdev_handle)) {
-               err = PTR_ERR(bdev_handle);
-               bdev_handle = NULL;
+       if (IS_ERR(bdev_file)) {
+               err = PTR_ERR(bdev_file);
+               bdev_file = NULL;
                goto out;
        }
 
@@ -531,7 +531,7 @@ static ssize_t backing_dev_store(struct device *dev,
 
        reset_bdev(zram);
 
-       zram->bdev_handle = bdev_handle;
+       zram->bdev_file = bdev_file;
        zram->backing_dev = backing_dev;
        zram->bitmap = bitmap;
        zram->nr_pages = nr_pages;
@@ -544,8 +544,8 @@ static ssize_t backing_dev_store(struct device *dev,
 out:
        kvfree(bitmap);
 
-       if (bdev_handle)
-               bdev_release(bdev_handle);
+       if (bdev_file)
+               fput(bdev_file);
 
        if (backing_dev)
                filp_close(backing_dev, NULL);
@@ -587,7 +587,7 @@ static void read_from_bdev_async(struct zram *zram, struct page *page,
 {
        struct bio *bio;
 
-       bio = bio_alloc(zram->bdev_handle->bdev, 1, parent->bi_opf, GFP_NOIO);
+       bio = bio_alloc(file_bdev(zram->bdev_file), 1, parent->bi_opf, GFP_NOIO);
        bio->bi_iter.bi_sector = entry * (PAGE_SIZE >> 9);
        __bio_add_page(bio, page, PAGE_SIZE, 0);
        bio_chain(bio, parent);
@@ -703,7 +703,7 @@ static ssize_t writeback_store(struct device *dev,
                        continue;
                }
 
-               bio_init(&bio, zram->bdev_handle->bdev, &bio_vec, 1,
+               bio_init(&bio, file_bdev(zram->bdev_file), &bio_vec, 1,
                         REQ_OP_WRITE | REQ_SYNC);
                bio.bi_iter.bi_sector = blk_idx * (PAGE_SIZE >> 9);
                __bio_add_page(&bio, page, PAGE_SIZE, 0);
@@ -785,7 +785,7 @@ static void zram_sync_read(struct work_struct *work)
        struct bio_vec bv;
        struct bio bio;
 
-       bio_init(&bio, zw->zram->bdev_handle->bdev, &bv, 1, REQ_OP_READ);
+       bio_init(&bio, file_bdev(zw->zram->bdev_file), &bv, 1, REQ_OP_READ);
        bio.bi_iter.bi_sector = zw->entry * (PAGE_SIZE >> 9);
        __bio_add_page(&bio, zw->page, PAGE_SIZE, 0);
        zw->error = submit_bio_wait(&bio);
@@ -2177,6 +2177,28 @@ ATTRIBUTE_GROUPS(zram_disk);
  */
 static int zram_add(void)
 {
+       struct queue_limits lim = {
+               .logical_block_size             = ZRAM_LOGICAL_BLOCK_SIZE,
+               /*
+                * To ensure that we always get PAGE_SIZE aligned and
+                * n*PAGE_SIZED sized I/O requests.
+                */
+               .physical_block_size            = PAGE_SIZE,
+               .io_min                         = PAGE_SIZE,
+               .io_opt                         = PAGE_SIZE,
+               .max_hw_discard_sectors         = UINT_MAX,
+               /*
+                * zram_bio_discard() will clear all logical blocks if logical
+                * block size is identical with physical block size(PAGE_SIZE).
+                * But if it is different, we will skip discarding some parts of
+                * logical blocks in the part of the request range which isn't
+                * aligned to physical block size.  So we can't ensure that all
+                * discarded logical blocks are zeroed.
+                */
+#if ZRAM_LOGICAL_BLOCK_SIZE == PAGE_SIZE
+               .max_write_zeroes_sectors       = UINT_MAX,
+#endif
+       };
        struct zram *zram;
        int ret, device_id;
 
@@ -2195,11 +2217,11 @@ static int zram_add(void)
 #endif
 
        /* gendisk structure */
-       zram->disk = blk_alloc_disk(NUMA_NO_NODE);
-       if (!zram->disk) {
+       zram->disk = blk_alloc_disk(&lim, NUMA_NO_NODE);
+       if (IS_ERR(zram->disk)) {
                pr_err("Error allocating disk structure for device %d\n",
                        device_id);
-               ret = -ENOMEM;
+               ret = PTR_ERR(zram->disk);
                goto out_free_idr;
        }
 
@@ -2216,29 +2238,6 @@ static int zram_add(void)
        /* zram devices sort of resembles non-rotational disks */
        blk_queue_flag_set(QUEUE_FLAG_NONROT, zram->disk->queue);
        blk_queue_flag_set(QUEUE_FLAG_SYNCHRONOUS, zram->disk->queue);
-
-       /*
-        * To ensure that we always get PAGE_SIZE aligned
-        * and n*PAGE_SIZED sized I/O requests.
-        */
-       blk_queue_physical_block_size(zram->disk->queue, PAGE_SIZE);
-       blk_queue_logical_block_size(zram->disk->queue,
-                                       ZRAM_LOGICAL_BLOCK_SIZE);
-       blk_queue_io_min(zram->disk->queue, PAGE_SIZE);
-       blk_queue_io_opt(zram->disk->queue, PAGE_SIZE);
-       blk_queue_max_discard_sectors(zram->disk->queue, UINT_MAX);
-
-       /*
-        * zram_bio_discard() will clear all logical blocks if logical block
-        * size is identical with physical block size(PAGE_SIZE). But if it is
-        * different, we will skip discarding some parts of logical blocks in
-        * the part of the request range which isn't aligned to physical block
-        * size.  So we can't ensure that all discarded logical blocks are
-        * zeroed.
-        */
-       if (ZRAM_LOGICAL_BLOCK_SIZE == PAGE_SIZE)
-               blk_queue_max_write_zeroes_sectors(zram->disk->queue, UINT_MAX);
-
        blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, zram->disk->queue);
        ret = device_add_disk(NULL, zram->disk, zram_disk_groups);
        if (ret)
index 3b94d12f41b40644b112b9362d371dd1108ece24..37bf29f34d26f0c068bf29f7084bc87534416d8f 100644 (file)
@@ -132,7 +132,7 @@ struct zram {
        spinlock_t wb_limit_lock;
        bool wb_limit_enable;
        u64 bd_wb_limit;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        unsigned long *bitmap;
        unsigned long nr_pages;
 #endif
index fdb0fae88d1c584e94bdc3b206999203779cd755..b40b32fa7f1c38c5d12931ee7b06e5b8ab144d77 100644 (file)
@@ -152,7 +152,7 @@ static int qca_send_patch_config_cmd(struct hci_dev *hdev)
        bt_dev_dbg(hdev, "QCA Patch config");
 
        skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, sizeof(cmd),
-                               cmd, HCI_EV_VENDOR, HCI_INIT_TIMEOUT);
+                               cmd, 0, HCI_INIT_TIMEOUT);
        if (IS_ERR(skb)) {
                err = PTR_ERR(skb);
                bt_dev_err(hdev, "Sending QCA Patch config failed (%d)", err);
index a617578356953c30a4a882f7928d16d464a4a04d..9a7243d5db71ff35697cf26cf7a744910f2741fd 100644 (file)
@@ -1417,7 +1417,7 @@ static int bcm4377_check_bdaddr(struct bcm4377_data *bcm4377)
 
        bda = (struct hci_rp_read_bd_addr *)skb->data;
        if (!bcm4377_is_valid_bdaddr(bcm4377, &bda->bdaddr))
-               set_bit(HCI_QUIRK_INVALID_BDADDR, &bcm4377->hdev->quirks);
+               set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &bcm4377->hdev->quirks);
 
        kfree_skb(skb);
        return 0;
@@ -2368,7 +2368,6 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        hdev->set_bdaddr = bcm4377_hci_set_bdaddr;
        hdev->setup = bcm4377_hci_setup;
 
-       set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
        if (bcm4377->hw->broken_mws_transport_config)
                set_bit(HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG, &hdev->quirks);
        if (bcm4377->hw->broken_ext_scan)
index 94b8c406f0c0edf0245064bd994ea6b84637b7b1..edd2a81b4d5ed7f5f9f36058ffe9131877ddde56 100644 (file)
@@ -7,6 +7,7 @@
  *
  *  Copyright (C) 2007 Texas Instruments, Inc.
  *  Copyright (c) 2010, 2012, 2018 The Linux Foundation. All rights reserved.
+ *  Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  *  Acknowledgements:
  *  This file is based on hci_ll.c, which was...
@@ -1806,13 +1807,12 @@ static int qca_power_on(struct hci_dev *hdev)
 
 static void hci_coredump_qca(struct hci_dev *hdev)
 {
+       int err;
        static const u8 param[] = { 0x26 };
-       struct sk_buff *skb;
 
-       skb = __hci_cmd_sync(hdev, 0xfc0c, 1, param, HCI_CMD_TIMEOUT);
-       if (IS_ERR(skb))
-               bt_dev_err(hdev, "%s: trigger crash failed (%ld)", __func__, PTR_ERR(skb));
-       kfree_skb(skb);
+       err = __hci_cmd_send(hdev, 0xfc0c, 1, param);
+       if (err < 0)
+               bt_dev_err(hdev, "%s: trigger crash failed (%d)", __func__, err);
 }
 
 static int qca_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id)
@@ -1904,7 +1904,17 @@ retry:
        case QCA_WCN6750:
        case QCA_WCN6855:
        case QCA_WCN7850:
-               set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
+
+               /* Set BDA quirk bit for reading BDA value from fwnode property
+                * only if that property exist in DT.
+                */
+               if (fwnode_property_present(dev_fwnode(hdev->dev.parent), "local-bd-address")) {
+                       set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
+                       bt_dev_info(hdev, "setting quirk bit to read BDA from fwnode later");
+               } else {
+                       bt_dev_dbg(hdev, "local-bd-address` is not present in the devicetree so not setting quirk bit for BDA");
+               }
+
                hci_set_aosp_capable(hdev);
 
                ret = qca_read_soc_version(hdev, &ver, soc_type);
index e6742998f372c4b2d7959a943938f10f44163bc0..d5e7fa9173a1690656494e09333cdf98099ba7c7 100644 (file)
@@ -186,11 +186,12 @@ config SUNXI_RSB
 
 config TEGRA_ACONNECT
        tristate "Tegra ACONNECT Bus Driver"
-       depends on ARCH_TEGRA_210_SOC
+       depends on ARCH_TEGRA
        depends on OF && PM
        help
          Driver for the Tegra ACONNECT bus which is used to interface with
-         the devices inside the Audio Processing Engine (APE) for Tegra210.
+         the devices inside the Audio Processing Engine (APE) for
+         Tegra210 and later.
 
 config TEGRA_GMI
        tristate "Tegra Generic Memory Interface bus driver"
index 6b5da73c85417644b5885e534c39917e4e5496a3..837bf9d51c6ec93888cec97ecde0eb2a792339e2 100644 (file)
@@ -120,7 +120,7 @@ static int imx_weim_gpr_setup(struct platform_device *pdev)
                i++;
        }
 
-       if (i == 0 || i % 4)
+       if (i == 0)
                goto err;
 
        for (i = 0; i < ARRAY_SIZE(gprvals); i++) {
index fd3e9d82340a57e775663dae7eff7aa555fc2510..1e29ba76615d6cae592977d114eabc969c949f37 100644 (file)
@@ -128,7 +128,7 @@ struct sunxi_rsb {
 };
 
 /* bus / slave device related functions */
-static struct bus_type sunxi_rsb_bus;
+static const struct bus_type sunxi_rsb_bus;
 
 static int sunxi_rsb_device_match(struct device *dev, struct device_driver *drv)
 {
@@ -177,7 +177,7 @@ static int sunxi_rsb_device_modalias(const struct device *dev, struct kobj_ueven
        return of_device_uevent_modalias(dev, env);
 }
 
-static struct bus_type sunxi_rsb_bus = {
+static const struct bus_type sunxi_rsb_bus = {
        .name           = RSB_CTRL_NAME,
        .match          = sunxi_rsb_device_match,
        .probe          = sunxi_rsb_device_probe,
index 245e5e827d0dcfe3b011b7d3d003add057b43c28..41d33f39efe52a55347b8203bacfd618f849ebc4 100644 (file)
@@ -2400,7 +2400,7 @@ static int sysc_child_add_clocks(struct sysc *ddata,
        return 0;
 }
 
-static struct device_type sysc_device_type = {
+static const struct device_type sysc_device_type = {
 };
 
 static struct sysc *sysc_child_to_parent(struct device *dev)
index 57186c58dc849c15db2f9c25ad8c816398f29986..1d7dd3d2c101cd4412876d62162fb733c800c02c 100644 (file)
@@ -129,8 +129,12 @@ static void ax45mp_dma_cache_wback(phys_addr_t paddr, size_t size)
        unsigned long line_size;
        unsigned long flags;
 
+       if (unlikely(start == end))
+               return;
+
        line_size = ax45mp_priv.ax45mp_cache_line_size;
        start = start & (~(line_size - 1));
+       end = ((end + line_size - 1) & (~(line_size - 1)));
        local_irq_save(flags);
        ax45mp_cpu_dcache_wb_range(start, end);
        local_irq_restore(flags);
index d668b174ace92fbd7e6a8635034f01249afb67e2..eefdd422ad8e9f8f9b8c47c0b2a62b84cc4dc749 100644 (file)
@@ -724,11 +724,6 @@ static void probe_gdrom_setupdisk(void)
 
 static int probe_gdrom_setupqueue(void)
 {
-       blk_queue_logical_block_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
-       /* using DMA so memory will need to be contiguous */
-       blk_queue_max_segments(gd.gdrom_rq, 1);
-       /* set a large max size to get most from DMA */
-       blk_queue_max_segment_size(gd.gdrom_rq, 0x40000);
        gd.disk->queue = gd.gdrom_rq;
        return gdrom_init_dma_mode();
 }
@@ -743,6 +738,13 @@ static const struct blk_mq_ops gdrom_mq_ops = {
  */
 static int probe_gdrom(struct platform_device *devptr)
 {
+       struct queue_limits lim = {
+               .logical_block_size             = GDROM_HARD_SECTOR,
+               /* using DMA so memory will need to be contiguous */
+               .max_segments                   = 1,
+               /* set a large max size to get most from DMA */
+               .max_segment_size               = 0x40000,
+       };
        int err;
 
        /*
@@ -778,7 +780,7 @@ static int probe_gdrom(struct platform_device *devptr)
        if (err)
                goto probe_fail_free_cd_info;
 
-       gd.disk = blk_mq_alloc_disk(&gd.tag_set, NULL);
+       gd.disk = blk_mq_alloc_disk(&gd.tag_set, &lim, NULL);
        if (IS_ERR(gd.disk)) {
                err = PTR_ERR(gd.disk);
                goto probe_fail_free_tag_set;
@@ -829,7 +831,7 @@ probe_fail_no_mem:
        return err;
 }
 
-static int remove_gdrom(struct platform_device *devptr)
+static void remove_gdrom(struct platform_device *devptr)
 {
        blk_mq_free_tag_set(&gd.tag_set);
        free_irq(HW_EVENT_GDROM_CMD, &gd);
@@ -840,13 +842,11 @@ static int remove_gdrom(struct platform_device *devptr)
        unregister_cdrom(gd.cd_info);
        kfree(gd.cd_info);
        kfree(gd.toc);
-
-       return 0;
 }
 
 static struct platform_driver gdrom_driver = {
        .probe = probe_gdrom,
-       .remove = remove_gdrom,
+       .remove_new = remove_gdrom,
        .driver = {
                        .name = GDROM_DEV_NAME,
        },
index 6994165e03957c89000addbf1479f18ebbbe26fc..0b60ae78f9d88601fa7939dc96ef583e142e8d4b 100644 (file)
@@ -2458,15 +2458,18 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = {
 static void __init rk3588_clk_init(struct device_node *np)
 {
        struct rockchip_clk_provider *ctx;
+       unsigned long clk_nr_clks;
        void __iomem *reg_base;
 
+       clk_nr_clks = rockchip_clk_find_max_clk_id(rk3588_clk_branches,
+                                       ARRAY_SIZE(rk3588_clk_branches)) + 1;
        reg_base = of_iomap(np, 0);
        if (!reg_base) {
                pr_err("%s: could not map cru region\n", __func__);
                return;
        }
 
-       ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+       ctx = rockchip_clk_init(np, reg_base, clk_nr_clks);
        if (IS_ERR(ctx)) {
                pr_err("%s: rockchip clk init failed\n", __func__);
                iounmap(reg_base);
index 4059d9365ae642e3e967138e67b9e664c15b6851..73d2cbdc716b45d4e9b9825ba2778e39e8e280cf 100644 (file)
@@ -429,6 +429,23 @@ void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
 }
 EXPORT_SYMBOL_GPL(rockchip_clk_register_plls);
 
+unsigned long rockchip_clk_find_max_clk_id(struct rockchip_clk_branch *list,
+                                          unsigned int nr_clk)
+{
+       unsigned long max = 0;
+       unsigned int idx;
+
+       for (idx = 0; idx < nr_clk; idx++, list++) {
+               if (list->id > max)
+                       max = list->id;
+               if (list->child && list->child->id > max)
+                       max = list->id;
+       }
+
+       return max;
+}
+EXPORT_SYMBOL_GPL(rockchip_clk_find_max_clk_id);
+
 void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
                                    struct rockchip_clk_branch *list,
                                    unsigned int nr_clk)
index 758ebaf2236bfa5ed50f9e7853cc16827a1a7105..fd3b476dedda9a8620fa4be2b1f7a7ece2da2be2 100644 (file)
@@ -973,6 +973,8 @@ struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
                        void __iomem *base, unsigned long nr_clks);
 void rockchip_clk_of_add_provider(struct device_node *np,
                                struct rockchip_clk_provider *ctx);
+unsigned long rockchip_clk_find_max_clk_id(struct rockchip_clk_branch *list,
+                                          unsigned int nr_clk);
 void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
                                    struct rockchip_clk_branch *list,
                                    unsigned int nr_clk);
index 0964bb11657f100916b85b7f00074a9bdb365c62..782993951fff8f7cc209329fc84af7f825fee143 100644 (file)
@@ -2475,7 +2475,7 @@ static const struct samsung_cmu_info misc_cmu_info __initconst = {
        .nr_clk_ids             = CLKS_NR_MISC,
        .clk_regs               = misc_clk_regs,
        .nr_clk_regs            = ARRAY_SIZE(misc_clk_regs),
-       .clk_name               = "dout_cmu_misc_bus",
+       .clk_name               = "bus",
 };
 
 /* ---- platform_driver ----------------------------------------------------- */
index e054de92de91bceb06f7fd289d8c0c9c3b8c42f3..8d4a52056684ee711fe510692a0841d795585079 100644 (file)
@@ -1807,7 +1807,7 @@ TIMER_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init);
 #endif
 
 int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *ts,
-                                struct clocksource **cs)
+                                enum clocksource_ids *cs_id)
 {
        struct arm_smccc_res hvc_res;
        u32 ptp_counter;
@@ -1831,8 +1831,8 @@ int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *ts,
        *ts = ktime_to_timespec64(ktime);
        if (cycle)
                *cycle = (u64)hvc_res.a2 << 32 | hvc_res.a3;
-       if (cs)
-               *cs = &clocksource_counter;
+       if (cs_id)
+               *cs_id = CSID_ARM_ARCH_COUNTER;
 
        return 0;
 }
index e4974b508328d1ae50e839602c572581f15ada56..a933ef53845a5b4ad24b3adfb1a303d44e9b2517 100644 (file)
@@ -159,6 +159,7 @@ static int __subdev_8255_init(struct comedi_device *dev,
                return -ENOMEM;
 
        spriv->context = context;
+       spriv->io      = io;
 
        s->type         = COMEDI_SUBD_DIO;
        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
index 30ea8b53ebf8191db808b928041b0ac9a6e1512a..05ae9122823f8032bf62d8e7cd1f7570115a04f8 100644 (file)
@@ -87,6 +87,8 @@ struct waveform_private {
        struct comedi_device *dev;      /* parent comedi device */
        u64 ao_last_scan_time;          /* time of previous AO scan in usec */
        unsigned int ao_scan_period;    /* AO scan period in usec */
+       bool ai_timer_enable:1;         /* should AI timer be running? */
+       bool ao_timer_enable:1;         /* should AO timer be running? */
        unsigned short ao_loopbacks[N_CHANS];
 };
 
@@ -236,8 +238,12 @@ static void waveform_ai_timer(struct timer_list *t)
                        time_increment = devpriv->ai_convert_time - now;
                else
                        time_increment = 1;
-               mod_timer(&devpriv->ai_timer,
-                         jiffies + usecs_to_jiffies(time_increment));
+               spin_lock(&dev->spinlock);
+               if (devpriv->ai_timer_enable) {
+                       mod_timer(&devpriv->ai_timer,
+                                 jiffies + usecs_to_jiffies(time_increment));
+               }
+               spin_unlock(&dev->spinlock);
        }
 
 overrun:
@@ -393,9 +399,12 @@ static int waveform_ai_cmd(struct comedi_device *dev,
         * Seem to need an extra jiffy here, otherwise timer expires slightly
         * early!
         */
+       spin_lock_bh(&dev->spinlock);
+       devpriv->ai_timer_enable = true;
        devpriv->ai_timer.expires =
                jiffies + usecs_to_jiffies(devpriv->ai_convert_period) + 1;
        add_timer(&devpriv->ai_timer);
+       spin_unlock_bh(&dev->spinlock);
        return 0;
 }
 
@@ -404,6 +413,9 @@ static int waveform_ai_cancel(struct comedi_device *dev,
 {
        struct waveform_private *devpriv = dev->private;
 
+       spin_lock_bh(&dev->spinlock);
+       devpriv->ai_timer_enable = false;
+       spin_unlock_bh(&dev->spinlock);
        if (in_softirq()) {
                /* Assume we were called from the timer routine itself. */
                del_timer(&devpriv->ai_timer);
@@ -495,8 +507,12 @@ static void waveform_ao_timer(struct timer_list *t)
                unsigned int time_inc = devpriv->ao_last_scan_time +
                                        devpriv->ao_scan_period - now;
 
-               mod_timer(&devpriv->ao_timer,
-                         jiffies + usecs_to_jiffies(time_inc));
+               spin_lock(&dev->spinlock);
+               if (devpriv->ao_timer_enable) {
+                       mod_timer(&devpriv->ao_timer,
+                                 jiffies + usecs_to_jiffies(time_inc));
+               }
+               spin_unlock(&dev->spinlock);
        }
 
 underrun:
@@ -517,9 +533,12 @@ static int waveform_ao_inttrig_start(struct comedi_device *dev,
        async->inttrig = NULL;
 
        devpriv->ao_last_scan_time = ktime_to_us(ktime_get());
+       spin_lock_bh(&dev->spinlock);
+       devpriv->ao_timer_enable = true;
        devpriv->ao_timer.expires =
                jiffies + usecs_to_jiffies(devpriv->ao_scan_period);
        add_timer(&devpriv->ao_timer);
+       spin_unlock_bh(&dev->spinlock);
 
        return 1;
 }
@@ -604,6 +623,9 @@ static int waveform_ao_cancel(struct comedi_device *dev,
        struct waveform_private *devpriv = dev->private;
 
        s->async->inttrig = NULL;
+       spin_lock_bh(&dev->spinlock);
+       devpriv->ao_timer_enable = false;
+       spin_unlock_bh(&dev->spinlock);
        if (in_softirq()) {
                /* Assume we were called from the timer routine itself. */
                del_timer(&devpriv->ao_timer);
index 3d5e6d705fc6ee3a0224a0b1fa57c32076fe306f..44b19e69617632bf4951d8da1e514f9c0c689d4b 100644 (file)
@@ -108,9 +108,8 @@ static inline void send_msg(struct cn_msg *msg)
                filter_data[1] = 0;
        }
 
-       if (cn_netlink_send_mult(msg, msg->len, 0, CN_IDX_PROC, GFP_NOWAIT,
-                            cn_filter, (void *)filter_data) == -ESRCH)
-               atomic_set(&proc_event_num_listeners, 0);
+       cn_netlink_send_mult(msg, msg->len, 0, CN_IDX_PROC, GFP_NOWAIT,
+                            cn_filter, (void *)filter_data);
 
        local_unlock(&local_event.lock);
 }
index 09c77afb33ca84e79c077c87659252c64840929a..3f24481fc04a1258624020a9a919f2d10640057a 100644 (file)
@@ -31,10 +31,11 @@ struct counter_device_allochelper {
        struct counter_device counter;
 
        /*
-        * This is cache line aligned to ensure private data behaves like if it
-        * were kmalloced separately.
+        * This ensures private data behaves like if it were kmalloced
+        * separately. Also ensures the minimum alignment for safe DMA
+        * operations (which may or may not mean cache alignment).
         */
-       unsigned long privdata[] ____cacheline_aligned;
+       unsigned long privdata[] __aligned(ARCH_DMA_MINALIGN);
 };
 
 static void counter_device_release(struct device *dev)
index ca94e60e705a1df435b1dd75a13c0a50dc3f8c27..79619227ea511b5247ca7941400ae821b1030f73 100644 (file)
@@ -2987,6 +2987,9 @@ static void intel_cpufreq_adjust_perf(unsigned int cpunum,
        if (min_pstate < cpu->min_perf_ratio)
                min_pstate = cpu->min_perf_ratio;
 
+       if (min_pstate > cpu->max_perf_ratio)
+               min_pstate = cpu->max_perf_ratio;
+
        max_pstate = min(cap_pstate, cpu->max_perf_ratio);
        if (max_pstate < min_pstate)
                max_pstate = min_pstate;
index 1262a7773ef304d184799771166ca5700fb7871a..de50c00ba218fb19302438b6df29f24a38a9c591 100644 (file)
@@ -299,22 +299,6 @@ theend:
        return err;
 }
 
-static void sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq)
-{
-       struct skcipher_request *breq = container_of(areq, struct skcipher_request, base);
-       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(breq);
-       struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
-       struct sun8i_ce_dev *ce = op->ce;
-       struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(breq);
-       int flow, err;
-
-       flow = rctx->flow;
-       err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(breq->base.tfm));
-       local_bh_disable();
-       crypto_finalize_skcipher_request(engine, breq, err);
-       local_bh_enable();
-}
-
 static void sun8i_ce_cipher_unprepare(struct crypto_engine *engine,
                                      void *async_req)
 {
@@ -360,6 +344,23 @@ static void sun8i_ce_cipher_unprepare(struct crypto_engine *engine,
        dma_unmap_single(ce->dev, rctx->addr_key, op->keylen, DMA_TO_DEVICE);
 }
 
+static void sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq)
+{
+       struct skcipher_request *breq = container_of(areq, struct skcipher_request, base);
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(breq);
+       struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+       struct sun8i_ce_dev *ce = op->ce;
+       struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(breq);
+       int flow, err;
+
+       flow = rctx->flow;
+       err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(breq->base.tfm));
+       sun8i_ce_cipher_unprepare(engine, areq);
+       local_bh_disable();
+       crypto_finalize_skcipher_request(engine, breq, err);
+       local_bh_enable();
+}
+
 int sun8i_ce_cipher_do_one(struct crypto_engine *engine, void *areq)
 {
        int err = sun8i_ce_cipher_prepare(engine, areq);
@@ -368,7 +369,6 @@ int sun8i_ce_cipher_do_one(struct crypto_engine *engine, void *areq)
                return err;
 
        sun8i_ce_cipher_run(engine, areq);
-       sun8i_ce_cipher_unprepare(engine, areq);
        return 0;
 }
 
index 32268e239bf15e49c9749e3fd5e9640ea09056a0..f394e45e11ab42821500f80e7d854244078b8b2b 100644 (file)
@@ -38,7 +38,7 @@ config CRYPTO_DEV_CCP_CRYPTO
 config CRYPTO_DEV_SP_PSP
        bool "Platform Security Processor (PSP) device"
        default y
-       depends on CRYPTO_DEV_CCP_DD && X86_64
+       depends on CRYPTO_DEV_CCP_DD && X86_64 && AMD_IOMMU
        help
         Provide support for the AMD Platform Security Processor (PSP).
         The PSP is a dedicated processor that provides support for key
index b04bc1d3d627d447c2cfc10b9078b040800c8406..f44efbb89c346a8e0b72c3d262ec9213c95aab18 100644 (file)
 #include <linux/hw_random.h>
 #include <linux/ccp.h>
 #include <linux/firmware.h>
+#include <linux/panic_notifier.h>
 #include <linux/gfp.h>
 #include <linux/cpufeature.h>
 #include <linux/fs.h>
 #include <linux/fs_struct.h>
 #include <linux/psp.h>
+#include <linux/amd-iommu.h>
 
 #include <asm/smp.h>
 #include <asm/cacheflush.h>
+#include <asm/e820/types.h>
+#include <asm/sev.h>
 
 #include "psp-dev.h"
 #include "sev-dev.h"
 #define SEV_FW_FILE            "amd/sev.fw"
 #define SEV_FW_NAME_SIZE       64
 
+/* Minimum firmware version required for the SEV-SNP support */
+#define SNP_MIN_API_MAJOR      1
+#define SNP_MIN_API_MINOR      51
+
+/*
+ * Maximum number of firmware-writable buffers that might be specified
+ * in the parameters of a legacy SEV command buffer.
+ */
+#define CMD_BUF_FW_WRITABLE_MAX 2
+
+/* Leave room in the descriptor array for an end-of-list indicator. */
+#define CMD_BUF_DESC_MAX (CMD_BUF_FW_WRITABLE_MAX + 1)
+
 static DEFINE_MUTEX(sev_cmd_mutex);
 static struct sev_misc_dev *misc_dev;
 
@@ -68,9 +85,14 @@ static int psp_timeout;
  *   The TMR is a 1MB area that must be 1MB aligned.  Use the page allocator
  *   to allocate the memory, which will return aligned memory for the specified
  *   allocation order.
+ *
+ * When SEV-SNP is enabled the TMR needs to be 2MB aligned and 2MB sized.
  */
-#define SEV_ES_TMR_SIZE                (1024 * 1024)
+#define SEV_TMR_SIZE           (1024 * 1024)
+#define SNP_TMR_SIZE           (2 * 1024 * 1024)
+
 static void *sev_es_tmr;
+static size_t sev_es_tmr_size = SEV_TMR_SIZE;
 
 /* INIT_EX NV Storage:
  *   The NV Storage is a 32Kb area and must be 4Kb page aligned.  Use the page
@@ -80,6 +102,13 @@ static void *sev_es_tmr;
 #define NV_LENGTH (32 * 1024)
 static void *sev_init_ex_buffer;
 
+/*
+ * SEV_DATA_RANGE_LIST:
+ *   Array containing range of pages that firmware transitions to HV-fixed
+ *   page state.
+ */
+static struct sev_data_range_list *snp_range_list;
+
 static inline bool sev_version_greater_or_equal(u8 maj, u8 min)
 {
        struct sev_device *sev = psp_master->sev_data;
@@ -115,6 +144,25 @@ static int sev_wait_cmd_ioc(struct sev_device *sev,
 {
        int ret;
 
+       /*
+        * If invoked during panic handling, local interrupts are disabled,
+        * so the PSP command completion interrupt can't be used. Poll for
+        * PSP command completion instead.
+        */
+       if (irqs_disabled()) {
+               unsigned long timeout_usecs = (timeout * USEC_PER_SEC) / 10;
+
+               /* Poll for SEV command completion: */
+               while (timeout_usecs--) {
+                       *reg = ioread32(sev->io_regs + sev->vdata->cmdresp_reg);
+                       if (*reg & PSP_CMDRESP_RESP)
+                               return 0;
+
+                       udelay(10);
+               }
+               return -ETIMEDOUT;
+       }
+
        ret = wait_event_timeout(sev->int_queue,
                        sev->int_rcvd, timeout * HZ);
        if (!ret)
@@ -130,6 +178,8 @@ static int sev_cmd_buffer_len(int cmd)
        switch (cmd) {
        case SEV_CMD_INIT:                      return sizeof(struct sev_data_init);
        case SEV_CMD_INIT_EX:                   return sizeof(struct sev_data_init_ex);
+       case SEV_CMD_SNP_SHUTDOWN_EX:           return sizeof(struct sev_data_snp_shutdown_ex);
+       case SEV_CMD_SNP_INIT_EX:               return sizeof(struct sev_data_snp_init_ex);
        case SEV_CMD_PLATFORM_STATUS:           return sizeof(struct sev_user_data_status);
        case SEV_CMD_PEK_CSR:                   return sizeof(struct sev_data_pek_csr);
        case SEV_CMD_PEK_CERT_IMPORT:           return sizeof(struct sev_data_pek_cert_import);
@@ -158,23 +208,27 @@ static int sev_cmd_buffer_len(int cmd)
        case SEV_CMD_GET_ID:                    return sizeof(struct sev_data_get_id);
        case SEV_CMD_ATTESTATION_REPORT:        return sizeof(struct sev_data_attestation_report);
        case SEV_CMD_SEND_CANCEL:               return sizeof(struct sev_data_send_cancel);
+       case SEV_CMD_SNP_GCTX_CREATE:           return sizeof(struct sev_data_snp_addr);
+       case SEV_CMD_SNP_LAUNCH_START:          return sizeof(struct sev_data_snp_launch_start);
+       case SEV_CMD_SNP_LAUNCH_UPDATE:         return sizeof(struct sev_data_snp_launch_update);
+       case SEV_CMD_SNP_ACTIVATE:              return sizeof(struct sev_data_snp_activate);
+       case SEV_CMD_SNP_DECOMMISSION:          return sizeof(struct sev_data_snp_addr);
+       case SEV_CMD_SNP_PAGE_RECLAIM:          return sizeof(struct sev_data_snp_page_reclaim);
+       case SEV_CMD_SNP_GUEST_STATUS:          return sizeof(struct sev_data_snp_guest_status);
+       case SEV_CMD_SNP_LAUNCH_FINISH:         return sizeof(struct sev_data_snp_launch_finish);
+       case SEV_CMD_SNP_DBG_DECRYPT:           return sizeof(struct sev_data_snp_dbg);
+       case SEV_CMD_SNP_DBG_ENCRYPT:           return sizeof(struct sev_data_snp_dbg);
+       case SEV_CMD_SNP_PAGE_UNSMASH:          return sizeof(struct sev_data_snp_page_unsmash);
+       case SEV_CMD_SNP_PLATFORM_STATUS:       return sizeof(struct sev_data_snp_addr);
+       case SEV_CMD_SNP_GUEST_REQUEST:         return sizeof(struct sev_data_snp_guest_request);
+       case SEV_CMD_SNP_CONFIG:                return sizeof(struct sev_user_data_snp_config);
+       case SEV_CMD_SNP_COMMIT:                return sizeof(struct sev_data_snp_commit);
        default:                                return 0;
        }
 
        return 0;
 }
 
-static void *sev_fw_alloc(unsigned long len)
-{
-       struct page *page;
-
-       page = alloc_pages(GFP_KERNEL, get_order(len));
-       if (!page)
-               return NULL;
-
-       return page_address(page);
-}
-
 static struct file *open_file_as_root(const char *filename, int flags, umode_t mode)
 {
        struct file *fp;
@@ -305,13 +359,485 @@ static int sev_write_init_ex_file_if_required(int cmd_id)
        return sev_write_init_ex_file();
 }
 
+/*
+ * snp_reclaim_pages() needs __sev_do_cmd_locked(), and __sev_do_cmd_locked()
+ * needs snp_reclaim_pages(), so a forward declaration is needed.
+ */
+static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret);
+
+static int snp_reclaim_pages(unsigned long paddr, unsigned int npages, bool locked)
+{
+       int ret, err, i;
+
+       paddr = __sme_clr(ALIGN_DOWN(paddr, PAGE_SIZE));
+
+       for (i = 0; i < npages; i++, paddr += PAGE_SIZE) {
+               struct sev_data_snp_page_reclaim data = {0};
+
+               data.paddr = paddr;
+
+               if (locked)
+                       ret = __sev_do_cmd_locked(SEV_CMD_SNP_PAGE_RECLAIM, &data, &err);
+               else
+                       ret = sev_do_cmd(SEV_CMD_SNP_PAGE_RECLAIM, &data, &err);
+
+               if (ret)
+                       goto cleanup;
+
+               ret = rmp_make_shared(__phys_to_pfn(paddr), PG_LEVEL_4K);
+               if (ret)
+                       goto cleanup;
+       }
+
+       return 0;
+
+cleanup:
+       /*
+        * If there was a failure reclaiming the page then it is no longer safe
+        * to release it back to the system; leak it instead.
+        */
+       snp_leak_pages(__phys_to_pfn(paddr), npages - i);
+       return ret;
+}
+
+static int rmp_mark_pages_firmware(unsigned long paddr, unsigned int npages, bool locked)
+{
+       unsigned long pfn = __sme_clr(paddr) >> PAGE_SHIFT;
+       int rc, i;
+
+       for (i = 0; i < npages; i++, pfn++) {
+               rc = rmp_make_private(pfn, 0, PG_LEVEL_4K, 0, true);
+               if (rc)
+                       goto cleanup;
+       }
+
+       return 0;
+
+cleanup:
+       /*
+        * Try unrolling the firmware state changes by
+        * reclaiming the pages which were already changed to the
+        * firmware state.
+        */
+       snp_reclaim_pages(paddr, i, locked);
+
+       return rc;
+}
+
+static struct page *__snp_alloc_firmware_pages(gfp_t gfp_mask, int order)
+{
+       unsigned long npages = 1ul << order, paddr;
+       struct sev_device *sev;
+       struct page *page;
+
+       if (!psp_master || !psp_master->sev_data)
+               return NULL;
+
+       page = alloc_pages(gfp_mask, order);
+       if (!page)
+               return NULL;
+
+       /* If SEV-SNP is initialized then add the page in RMP table. */
+       sev = psp_master->sev_data;
+       if (!sev->snp_initialized)
+               return page;
+
+       paddr = __pa((unsigned long)page_address(page));
+       if (rmp_mark_pages_firmware(paddr, npages, false))
+               return NULL;
+
+       return page;
+}
+
+void *snp_alloc_firmware_page(gfp_t gfp_mask)
+{
+       struct page *page;
+
+       page = __snp_alloc_firmware_pages(gfp_mask, 0);
+
+       return page ? page_address(page) : NULL;
+}
+EXPORT_SYMBOL_GPL(snp_alloc_firmware_page);
+
+static void __snp_free_firmware_pages(struct page *page, int order, bool locked)
+{
+       struct sev_device *sev = psp_master->sev_data;
+       unsigned long paddr, npages = 1ul << order;
+
+       if (!page)
+               return;
+
+       paddr = __pa((unsigned long)page_address(page));
+       if (sev->snp_initialized &&
+           snp_reclaim_pages(paddr, npages, locked))
+               return;
+
+       __free_pages(page, order);
+}
+
+void snp_free_firmware_page(void *addr)
+{
+       if (!addr)
+               return;
+
+       __snp_free_firmware_pages(virt_to_page(addr), 0, false);
+}
+EXPORT_SYMBOL_GPL(snp_free_firmware_page);
+
+static void *sev_fw_alloc(unsigned long len)
+{
+       struct page *page;
+
+       page = __snp_alloc_firmware_pages(GFP_KERNEL, get_order(len));
+       if (!page)
+               return NULL;
+
+       return page_address(page);
+}
+
+/**
+ * struct cmd_buf_desc - descriptors for managing legacy SEV command address
+ * parameters corresponding to buffers that may be written to by firmware.
+ *
+ * @paddr_ptr:  pointer to the address parameter in the command buffer which may
+ *              need to be saved/restored depending on whether a bounce buffer
+ *              is used. In the case of a bounce buffer, the command buffer
+ *              needs to be updated with the address of the new bounce buffer
+ *              snp_map_cmd_buf_desc() has allocated specifically for it. Must
+ *              be NULL if this descriptor is only an end-of-list indicator.
+ *
+ * @paddr_orig: storage for the original address parameter, which can be used to
+ *              restore the original value in @paddr_ptr in cases where it is
+ *              replaced with the address of a bounce buffer.
+ *
+ * @len: length of buffer located at the address originally stored at @paddr_ptr
+ *
+ * @guest_owned: true if the address corresponds to guest-owned pages, in which
+ *               case bounce buffers are not needed.
+ */
+struct cmd_buf_desc {
+       u64 *paddr_ptr;
+       u64 paddr_orig;
+       u32 len;
+       bool guest_owned;
+};
+
+/*
+ * If a legacy SEV command parameter is a memory address, those pages in
+ * turn need to be transitioned to/from firmware-owned before/after
+ * executing the firmware command.
+ *
+ * Additionally, in cases where those pages are not guest-owned, a bounce
+ * buffer is needed in place of the original memory address parameter.
+ *
+ * A set of descriptors are used to keep track of this handling, and
+ * initialized here based on the specific commands being executed.
+ */
+static void snp_populate_cmd_buf_desc_list(int cmd, void *cmd_buf,
+                                          struct cmd_buf_desc *desc_list)
+{
+       switch (cmd) {
+       case SEV_CMD_PDH_CERT_EXPORT: {
+               struct sev_data_pdh_cert_export *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->pdh_cert_address;
+               desc_list[0].len = data->pdh_cert_len;
+               desc_list[1].paddr_ptr = &data->cert_chain_address;
+               desc_list[1].len = data->cert_chain_len;
+               break;
+       }
+       case SEV_CMD_GET_ID: {
+               struct sev_data_get_id *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->address;
+               desc_list[0].len = data->len;
+               break;
+       }
+       case SEV_CMD_PEK_CSR: {
+               struct sev_data_pek_csr *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->address;
+               desc_list[0].len = data->len;
+               break;
+       }
+       case SEV_CMD_LAUNCH_UPDATE_DATA: {
+               struct sev_data_launch_update_data *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->address;
+               desc_list[0].len = data->len;
+               desc_list[0].guest_owned = true;
+               break;
+       }
+       case SEV_CMD_LAUNCH_UPDATE_VMSA: {
+               struct sev_data_launch_update_vmsa *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->address;
+               desc_list[0].len = data->len;
+               desc_list[0].guest_owned = true;
+               break;
+       }
+       case SEV_CMD_LAUNCH_MEASURE: {
+               struct sev_data_launch_measure *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->address;
+               desc_list[0].len = data->len;
+               break;
+       }
+       case SEV_CMD_LAUNCH_UPDATE_SECRET: {
+               struct sev_data_launch_secret *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->guest_address;
+               desc_list[0].len = data->guest_len;
+               desc_list[0].guest_owned = true;
+               break;
+       }
+       case SEV_CMD_DBG_DECRYPT: {
+               struct sev_data_dbg *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->dst_addr;
+               desc_list[0].len = data->len;
+               desc_list[0].guest_owned = true;
+               break;
+       }
+       case SEV_CMD_DBG_ENCRYPT: {
+               struct sev_data_dbg *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->dst_addr;
+               desc_list[0].len = data->len;
+               desc_list[0].guest_owned = true;
+               break;
+       }
+       case SEV_CMD_ATTESTATION_REPORT: {
+               struct sev_data_attestation_report *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->address;
+               desc_list[0].len = data->len;
+               break;
+       }
+       case SEV_CMD_SEND_START: {
+               struct sev_data_send_start *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->session_address;
+               desc_list[0].len = data->session_len;
+               break;
+       }
+       case SEV_CMD_SEND_UPDATE_DATA: {
+               struct sev_data_send_update_data *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->hdr_address;
+               desc_list[0].len = data->hdr_len;
+               desc_list[1].paddr_ptr = &data->trans_address;
+               desc_list[1].len = data->trans_len;
+               break;
+       }
+       case SEV_CMD_SEND_UPDATE_VMSA: {
+               struct sev_data_send_update_vmsa *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->hdr_address;
+               desc_list[0].len = data->hdr_len;
+               desc_list[1].paddr_ptr = &data->trans_address;
+               desc_list[1].len = data->trans_len;
+               break;
+       }
+       case SEV_CMD_RECEIVE_UPDATE_DATA: {
+               struct sev_data_receive_update_data *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->guest_address;
+               desc_list[0].len = data->guest_len;
+               desc_list[0].guest_owned = true;
+               break;
+       }
+       case SEV_CMD_RECEIVE_UPDATE_VMSA: {
+               struct sev_data_receive_update_vmsa *data = cmd_buf;
+
+               desc_list[0].paddr_ptr = &data->guest_address;
+               desc_list[0].len = data->guest_len;
+               desc_list[0].guest_owned = true;
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+static int snp_map_cmd_buf_desc(struct cmd_buf_desc *desc)
+{
+       unsigned int npages;
+
+       if (!desc->len)
+               return 0;
+
+       /* Allocate a bounce buffer if this isn't a guest owned page. */
+       if (!desc->guest_owned) {
+               struct page *page;
+
+               page = alloc_pages(GFP_KERNEL_ACCOUNT, get_order(desc->len));
+               if (!page) {
+                       pr_warn("Failed to allocate bounce buffer for SEV legacy command.\n");
+                       return -ENOMEM;
+               }
+
+               desc->paddr_orig = *desc->paddr_ptr;
+               *desc->paddr_ptr = __psp_pa(page_to_virt(page));
+       }
+
+       npages = PAGE_ALIGN(desc->len) >> PAGE_SHIFT;
+
+       /* Transition the buffer to firmware-owned. */
+       if (rmp_mark_pages_firmware(*desc->paddr_ptr, npages, true)) {
+               pr_warn("Error moving pages to firmware-owned state for SEV legacy command.\n");
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+static int snp_unmap_cmd_buf_desc(struct cmd_buf_desc *desc)
+{
+       unsigned int npages;
+
+       if (!desc->len)
+               return 0;
+
+       npages = PAGE_ALIGN(desc->len) >> PAGE_SHIFT;
+
+       /* Transition the buffers back to hypervisor-owned. */
+       if (snp_reclaim_pages(*desc->paddr_ptr, npages, true)) {
+               pr_warn("Failed to reclaim firmware-owned pages while issuing SEV legacy command.\n");
+               return -EFAULT;
+       }
+
+       /* Copy data from bounce buffer and then free it. */
+       if (!desc->guest_owned) {
+               void *bounce_buf = __va(__sme_clr(*desc->paddr_ptr));
+               void *dst_buf = __va(__sme_clr(desc->paddr_orig));
+
+               memcpy(dst_buf, bounce_buf, desc->len);
+               __free_pages(virt_to_page(bounce_buf), get_order(desc->len));
+
+               /* Restore the original address in the command buffer. */
+               *desc->paddr_ptr = desc->paddr_orig;
+       }
+
+       return 0;
+}
+
+static int snp_map_cmd_buf_desc_list(int cmd, void *cmd_buf, struct cmd_buf_desc *desc_list)
+{
+       int i;
+
+       snp_populate_cmd_buf_desc_list(cmd, cmd_buf, desc_list);
+
+       for (i = 0; i < CMD_BUF_DESC_MAX; i++) {
+               struct cmd_buf_desc *desc = &desc_list[i];
+
+               if (!desc->paddr_ptr)
+                       break;
+
+               if (snp_map_cmd_buf_desc(desc))
+                       goto err_unmap;
+       }
+
+       return 0;
+
+err_unmap:
+       for (i--; i >= 0; i--)
+               snp_unmap_cmd_buf_desc(&desc_list[i]);
+
+       return -EFAULT;
+}
+
+static int snp_unmap_cmd_buf_desc_list(struct cmd_buf_desc *desc_list)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < CMD_BUF_DESC_MAX; i++) {
+               struct cmd_buf_desc *desc = &desc_list[i];
+
+               if (!desc->paddr_ptr)
+                       break;
+
+               if (snp_unmap_cmd_buf_desc(&desc_list[i]))
+                       ret = -EFAULT;
+       }
+
+       return ret;
+}
+
+static bool sev_cmd_buf_writable(int cmd)
+{
+       switch (cmd) {
+       case SEV_CMD_PLATFORM_STATUS:
+       case SEV_CMD_GUEST_STATUS:
+       case SEV_CMD_LAUNCH_START:
+       case SEV_CMD_RECEIVE_START:
+       case SEV_CMD_LAUNCH_MEASURE:
+       case SEV_CMD_SEND_START:
+       case SEV_CMD_SEND_UPDATE_DATA:
+       case SEV_CMD_SEND_UPDATE_VMSA:
+       case SEV_CMD_PEK_CSR:
+       case SEV_CMD_PDH_CERT_EXPORT:
+       case SEV_CMD_GET_ID:
+       case SEV_CMD_ATTESTATION_REPORT:
+               return true;
+       default:
+               return false;
+       }
+}
+
+/* After SNP is INIT'ed, the behavior of legacy SEV commands is changed. */
+static bool snp_legacy_handling_needed(int cmd)
+{
+       struct sev_device *sev = psp_master->sev_data;
+
+       return cmd < SEV_CMD_SNP_INIT && sev->snp_initialized;
+}
+
+static int snp_prep_cmd_buf(int cmd, void *cmd_buf, struct cmd_buf_desc *desc_list)
+{
+       if (!snp_legacy_handling_needed(cmd))
+               return 0;
+
+       if (snp_map_cmd_buf_desc_list(cmd, cmd_buf, desc_list))
+               return -EFAULT;
+
+       /*
+        * Before command execution, the command buffer needs to be put into
+        * the firmware-owned state.
+        */
+       if (sev_cmd_buf_writable(cmd)) {
+               if (rmp_mark_pages_firmware(__pa(cmd_buf), 1, true))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+static int snp_reclaim_cmd_buf(int cmd, void *cmd_buf)
+{
+       if (!snp_legacy_handling_needed(cmd))
+               return 0;
+
+       /*
+        * After command completion, the command buffer needs to be put back
+        * into the hypervisor-owned state.
+        */
+       if (sev_cmd_buf_writable(cmd))
+               if (snp_reclaim_pages(__pa(cmd_buf), 1, true))
+                       return -EFAULT;
+
+       return 0;
+}
+
 static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret)
 {
+       struct cmd_buf_desc desc_list[CMD_BUF_DESC_MAX] = {0};
        struct psp_device *psp = psp_master;
        struct sev_device *sev;
        unsigned int cmdbuff_hi, cmdbuff_lo;
        unsigned int phys_lsb, phys_msb;
        unsigned int reg, ret = 0;
+       void *cmd_buf;
        int buf_len;
 
        if (!psp || !psp->sev_data)
@@ -331,12 +857,47 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret)
         * work for some memory, e.g. vmalloc'd addresses, and @data may not be
         * physically contiguous.
         */
-       if (data)
-               memcpy(sev->cmd_buf, data, buf_len);
+       if (data) {
+               /*
+                * Commands are generally issued one at a time and require the
+                * sev_cmd_mutex, but there could be recursive firmware requests
+                * due to SEV_CMD_SNP_PAGE_RECLAIM needing to be issued while
+                * preparing buffers for another command. This is the only known
+                * case of nesting in the current code, so exactly one
+                * additional command buffer is available for that purpose.
+                */
+               if (!sev->cmd_buf_active) {
+                       cmd_buf = sev->cmd_buf;
+                       sev->cmd_buf_active = true;
+               } else if (!sev->cmd_buf_backup_active) {
+                       cmd_buf = sev->cmd_buf_backup;
+                       sev->cmd_buf_backup_active = true;
+               } else {
+                       dev_err(sev->dev,
+                               "SEV: too many firmware commands in progress, no command buffers available.\n");
+                       return -EBUSY;
+               }
+
+               memcpy(cmd_buf, data, buf_len);
+
+               /*
+                * The behavior of the SEV-legacy commands is altered when the
+                * SNP firmware is in the INIT state.
+                */
+               ret = snp_prep_cmd_buf(cmd, cmd_buf, desc_list);
+               if (ret) {
+                       dev_err(sev->dev,
+                               "SEV: failed to prepare buffer for legacy command 0x%x. Error: %d\n",
+                               cmd, ret);
+                       return ret;
+               }
+       } else {
+               cmd_buf = sev->cmd_buf;
+       }
 
        /* Get the physical address of the command buffer */
-       phys_lsb = data ? lower_32_bits(__psp_pa(sev->cmd_buf)) : 0;
-       phys_msb = data ? upper_32_bits(__psp_pa(sev->cmd_buf)) : 0;
+       phys_lsb = data ? lower_32_bits(__psp_pa(cmd_buf)) : 0;
+       phys_msb = data ? upper_32_bits(__psp_pa(cmd_buf)) : 0;
 
        dev_dbg(sev->dev, "sev command id %#x buffer 0x%08x%08x timeout %us\n",
                cmd, phys_msb, phys_lsb, psp_timeout);
@@ -374,115 +935,329 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret)
                        cmd, FIELD_GET(PSP_CMDRESP_STS, reg));
 
                /*
-                * PSP firmware may report additional error information in the
-                * command buffer registers on error. Print contents of command
-                * buffer registers if they changed.
+                * PSP firmware may report additional error information in the
+                * command buffer registers on error. Print contents of command
+                * buffer registers if they changed.
+                */
+               cmdbuff_hi = ioread32(sev->io_regs + sev->vdata->cmdbuff_addr_hi_reg);
+               cmdbuff_lo = ioread32(sev->io_regs + sev->vdata->cmdbuff_addr_lo_reg);
+               if (cmdbuff_hi != phys_msb || cmdbuff_lo != phys_lsb) {
+                       dev_dbg(sev->dev, "Additional error information reported in cmdbuff:");
+                       dev_dbg(sev->dev, "  cmdbuff hi: %#010x\n", cmdbuff_hi);
+                       dev_dbg(sev->dev, "  cmdbuff lo: %#010x\n", cmdbuff_lo);
+               }
+               ret = -EIO;
+       } else {
+               ret = sev_write_init_ex_file_if_required(cmd);
+       }
+
+       /*
+        * Copy potential output from the PSP back to data.  Do this even on
+        * failure in case the caller wants to glean something from the error.
+        */
+       if (data) {
+               int ret_reclaim;
+               /*
+                * Restore the page state after the command completes.
+                */
+               ret_reclaim = snp_reclaim_cmd_buf(cmd, cmd_buf);
+               if (ret_reclaim) {
+                       dev_err(sev->dev,
+                               "SEV: failed to reclaim buffer for legacy command %#x. Error: %d\n",
+                               cmd, ret_reclaim);
+                       return ret_reclaim;
+               }
+
+               memcpy(data, cmd_buf, buf_len);
+
+               if (sev->cmd_buf_backup_active)
+                       sev->cmd_buf_backup_active = false;
+               else
+                       sev->cmd_buf_active = false;
+
+               if (snp_unmap_cmd_buf_desc_list(desc_list))
+                       return -EFAULT;
+       }
+
+       print_hex_dump_debug("(out): ", DUMP_PREFIX_OFFSET, 16, 2, data,
+                            buf_len, false);
+
+       return ret;
+}
+
+int sev_do_cmd(int cmd, void *data, int *psp_ret)
+{
+       int rc;
+
+       mutex_lock(&sev_cmd_mutex);
+       rc = __sev_do_cmd_locked(cmd, data, psp_ret);
+       mutex_unlock(&sev_cmd_mutex);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(sev_do_cmd);
+
+static int __sev_init_locked(int *error)
+{
+       struct sev_data_init data;
+
+       memset(&data, 0, sizeof(data));
+       if (sev_es_tmr) {
+               /*
+                * Do not include the encryption mask on the physical
+                * address of the TMR (firmware should clear it anyway).
+                */
+               data.tmr_address = __pa(sev_es_tmr);
+
+               data.flags |= SEV_INIT_FLAGS_SEV_ES;
+               data.tmr_len = sev_es_tmr_size;
+       }
+
+       return __sev_do_cmd_locked(SEV_CMD_INIT, &data, error);
+}
+
+static int __sev_init_ex_locked(int *error)
+{
+       struct sev_data_init_ex data;
+
+       memset(&data, 0, sizeof(data));
+       data.length = sizeof(data);
+       data.nv_address = __psp_pa(sev_init_ex_buffer);
+       data.nv_len = NV_LENGTH;
+
+       if (sev_es_tmr) {
+               /*
+                * Do not include the encryption mask on the physical
+                * address of the TMR (firmware should clear it anyway).
+                */
+               data.tmr_address = __pa(sev_es_tmr);
+
+               data.flags |= SEV_INIT_FLAGS_SEV_ES;
+               data.tmr_len = sev_es_tmr_size;
+       }
+
+       return __sev_do_cmd_locked(SEV_CMD_INIT_EX, &data, error);
+}
+
+static inline int __sev_do_init_locked(int *psp_ret)
+{
+       if (sev_init_ex_buffer)
+               return __sev_init_ex_locked(psp_ret);
+       else
+               return __sev_init_locked(psp_ret);
+}
+
+static void snp_set_hsave_pa(void *arg)
+{
+       wrmsrl(MSR_VM_HSAVE_PA, 0);
+}
+
+static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg)
+{
+       struct sev_data_range_list *range_list = arg;
+       struct sev_data_range *range = &range_list->ranges[range_list->num_elements];
+       size_t size;
+
+       /*
+        * Ensure the list of HV_FIXED pages that will be passed to firmware
+        * do not exceed the page-sized argument buffer.
+        */
+       if ((range_list->num_elements * sizeof(struct sev_data_range) +
+            sizeof(struct sev_data_range_list)) > PAGE_SIZE)
+               return -E2BIG;
+
+       switch (rs->desc) {
+       case E820_TYPE_RESERVED:
+       case E820_TYPE_PMEM:
+       case E820_TYPE_ACPI:
+               range->base = rs->start & PAGE_MASK;
+               size = PAGE_ALIGN((rs->end + 1) - rs->start);
+               range->page_count = size >> PAGE_SHIFT;
+               range_list->num_elements++;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int __sev_snp_init_locked(int *error)
+{
+       struct psp_device *psp = psp_master;
+       struct sev_data_snp_init_ex data;
+       struct sev_device *sev;
+       void *arg = &data;
+       int cmd, rc = 0;
+
+       if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP))
+               return -ENODEV;
+
+       sev = psp->sev_data;
+
+       if (sev->snp_initialized)
+               return 0;
+
+       if (!sev_version_greater_or_equal(SNP_MIN_API_MAJOR, SNP_MIN_API_MINOR)) {
+               dev_dbg(sev->dev, "SEV-SNP support requires firmware version >= %d:%d\n",
+                       SNP_MIN_API_MAJOR, SNP_MIN_API_MINOR);
+               return 0;
+       }
+
+       /* SNP_INIT requires MSR_VM_HSAVE_PA to be cleared on all CPUs. */
+       on_each_cpu(snp_set_hsave_pa, NULL, 1);
+
+       /*
+        * Starting in SNP firmware v1.52, the SNP_INIT_EX command takes a list
+        * of system physical address ranges to convert into HV-fixed page
+        * states during the RMP initialization.  For instance, the memory that
+        * UEFI reserves should be included in the that list. This allows system
+        * components that occasionally write to memory (e.g. logging to UEFI
+        * reserved regions) to not fail due to RMP initialization and SNP
+        * enablement.
+        *
+        */
+       if (sev_version_greater_or_equal(SNP_MIN_API_MAJOR, 52)) {
+               /*
+                * Firmware checks that the pages containing the ranges enumerated
+                * in the RANGES structure are either in the default page state or in the
+                * firmware page state.
+                */
+               snp_range_list = kzalloc(PAGE_SIZE, GFP_KERNEL);
+               if (!snp_range_list) {
+                       dev_err(sev->dev,
+                               "SEV: SNP_INIT_EX range list memory allocation failed\n");
+                       return -ENOMEM;
+               }
+
+               /*
+                * Retrieve all reserved memory regions from the e820 memory map
+                * to be setup as HV-fixed pages.
                 */
-               cmdbuff_hi = ioread32(sev->io_regs + sev->vdata->cmdbuff_addr_hi_reg);
-               cmdbuff_lo = ioread32(sev->io_regs + sev->vdata->cmdbuff_addr_lo_reg);
-               if (cmdbuff_hi != phys_msb || cmdbuff_lo != phys_lsb) {
-                       dev_dbg(sev->dev, "Additional error information reported in cmdbuff:");
-                       dev_dbg(sev->dev, "  cmdbuff hi: %#010x\n", cmdbuff_hi);
-                       dev_dbg(sev->dev, "  cmdbuff lo: %#010x\n", cmdbuff_lo);
+               rc = walk_iomem_res_desc(IORES_DESC_NONE, IORESOURCE_MEM, 0, ~0,
+                                        snp_range_list, snp_filter_reserved_mem_regions);
+               if (rc) {
+                       dev_err(sev->dev,
+                               "SEV: SNP_INIT_EX walk_iomem_res_desc failed rc = %d\n", rc);
+                       return rc;
                }
-               ret = -EIO;
+
+               memset(&data, 0, sizeof(data));
+               data.init_rmp = 1;
+               data.list_paddr_en = 1;
+               data.list_paddr = __psp_pa(snp_range_list);
+               cmd = SEV_CMD_SNP_INIT_EX;
        } else {
-               ret = sev_write_init_ex_file_if_required(cmd);
+               cmd = SEV_CMD_SNP_INIT;
+               arg = NULL;
        }
 
-       print_hex_dump_debug("(out): ", DUMP_PREFIX_OFFSET, 16, 2, data,
-                            buf_len, false);
-
        /*
-        * Copy potential output from the PSP back to data.  Do this even on
-        * failure in case the caller wants to glean something from the error.
+        * The following sequence must be issued before launching the first SNP
+        * guest to ensure all dirty cache lines are flushed, including from
+        * updates to the RMP table itself via the RMPUPDATE instruction:
+        *
+        * - WBINVD on all running CPUs
+        * - SEV_CMD_SNP_INIT[_EX] firmware command
+        * - WBINVD on all running CPUs
+        * - SEV_CMD_SNP_DF_FLUSH firmware command
         */
-       if (data)
-               memcpy(data, sev->cmd_buf, buf_len);
+       wbinvd_on_all_cpus();
 
-       return ret;
-}
+       rc = __sev_do_cmd_locked(cmd, arg, error);
+       if (rc)
+               return rc;
 
-static int sev_do_cmd(int cmd, void *data, int *psp_ret)
-{
-       int rc;
+       /* Prepare for first SNP guest launch after INIT. */
+       wbinvd_on_all_cpus();
+       rc = __sev_do_cmd_locked(SEV_CMD_SNP_DF_FLUSH, NULL, error);
+       if (rc)
+               return rc;
 
-       mutex_lock(&sev_cmd_mutex);
-       rc = __sev_do_cmd_locked(cmd, data, psp_ret);
-       mutex_unlock(&sev_cmd_mutex);
+       sev->snp_initialized = true;
+       dev_dbg(sev->dev, "SEV-SNP firmware initialized\n");
+
+       sev_es_tmr_size = SNP_TMR_SIZE;
 
        return rc;
 }
 
-static int __sev_init_locked(int *error)
+static void __sev_platform_init_handle_tmr(struct sev_device *sev)
 {
-       struct sev_data_init data;
+       if (sev_es_tmr)
+               return;
 
-       memset(&data, 0, sizeof(data));
+       /* Obtain the TMR memory area for SEV-ES use */
+       sev_es_tmr = sev_fw_alloc(sev_es_tmr_size);
        if (sev_es_tmr) {
-               /*
-                * Do not include the encryption mask on the physical
-                * address of the TMR (firmware should clear it anyway).
-                */
-               data.tmr_address = __pa(sev_es_tmr);
-
-               data.flags |= SEV_INIT_FLAGS_SEV_ES;
-               data.tmr_len = SEV_ES_TMR_SIZE;
+               /* Must flush the cache before giving it to the firmware */
+               if (!sev->snp_initialized)
+                       clflush_cache_range(sev_es_tmr, sev_es_tmr_size);
+       } else {
+                       dev_warn(sev->dev, "SEV: TMR allocation failed, SEV-ES support unavailable\n");
        }
-
-       return __sev_do_cmd_locked(SEV_CMD_INIT, &data, error);
 }
 
-static int __sev_init_ex_locked(int *error)
+/*
+ * If an init_ex_path is provided allocate a buffer for the file and
+ * read in the contents. Additionally, if SNP is initialized, convert
+ * the buffer pages to firmware pages.
+ */
+static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev)
 {
-       struct sev_data_init_ex data;
+       struct page *page;
+       int rc;
 
-       memset(&data, 0, sizeof(data));
-       data.length = sizeof(data);
-       data.nv_address = __psp_pa(sev_init_ex_buffer);
-       data.nv_len = NV_LENGTH;
+       if (!init_ex_path)
+               return 0;
 
-       if (sev_es_tmr) {
-               /*
-                * Do not include the encryption mask on the physical
-                * address of the TMR (firmware should clear it anyway).
-                */
-               data.tmr_address = __pa(sev_es_tmr);
+       if (sev_init_ex_buffer)
+               return 0;
 
-               data.flags |= SEV_INIT_FLAGS_SEV_ES;
-               data.tmr_len = SEV_ES_TMR_SIZE;
+       page = alloc_pages(GFP_KERNEL, get_order(NV_LENGTH));
+       if (!page) {
+               dev_err(sev->dev, "SEV: INIT_EX NV memory allocation failed\n");
+               return -ENOMEM;
        }
 
-       return __sev_do_cmd_locked(SEV_CMD_INIT_EX, &data, error);
-}
+       sev_init_ex_buffer = page_address(page);
 
-static inline int __sev_do_init_locked(int *psp_ret)
-{
-       if (sev_init_ex_buffer)
-               return __sev_init_ex_locked(psp_ret);
-       else
-               return __sev_init_locked(psp_ret);
+       rc = sev_read_init_ex_file();
+       if (rc)
+               return rc;
+
+       /* If SEV-SNP is initialized, transition to firmware page. */
+       if (sev->snp_initialized) {
+               unsigned long npages;
+
+               npages = 1UL << get_order(NV_LENGTH);
+               if (rmp_mark_pages_firmware(__pa(sev_init_ex_buffer), npages, false)) {
+                       dev_err(sev->dev, "SEV: INIT_EX NV memory page state change failed.\n");
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
 }
 
 static int __sev_platform_init_locked(int *error)
 {
-       int rc = 0, psp_ret = SEV_RET_NO_FW_CALL;
-       struct psp_device *psp = psp_master;
+       int rc, psp_ret = SEV_RET_NO_FW_CALL;
        struct sev_device *sev;
 
-       if (!psp || !psp->sev_data)
+       if (!psp_master || !psp_master->sev_data)
                return -ENODEV;
 
-       sev = psp->sev_data;
+       sev = psp_master->sev_data;
 
        if (sev->state == SEV_STATE_INIT)
                return 0;
 
-       if (sev_init_ex_buffer) {
-               rc = sev_read_init_ex_file();
-               if (rc)
-                       return rc;
-       }
+       __sev_platform_init_handle_tmr(sev);
+
+       rc = __sev_platform_init_handle_init_ex_path(sev);
+       if (rc)
+               return rc;
 
        rc = __sev_do_init_locked(&psp_ret);
        if (rc && psp_ret == SEV_RET_SECURE_DATA_INVALID) {
@@ -520,12 +1295,46 @@ static int __sev_platform_init_locked(int *error)
        return 0;
 }
 
-int sev_platform_init(int *error)
+static int _sev_platform_init_locked(struct sev_platform_init_args *args)
+{
+       struct sev_device *sev;
+       int rc;
+
+       if (!psp_master || !psp_master->sev_data)
+               return -ENODEV;
+
+       sev = psp_master->sev_data;
+
+       if (sev->state == SEV_STATE_INIT)
+               return 0;
+
+       /*
+        * Legacy guests cannot be running while SNP_INIT(_EX) is executing,
+        * so perform SEV-SNP initialization at probe time.
+        */
+       rc = __sev_snp_init_locked(&args->error);
+       if (rc && rc != -ENODEV) {
+               /*
+                * Don't abort the probe if SNP INIT failed,
+                * continue to initialize the legacy SEV firmware.
+                */
+               dev_err(sev->dev, "SEV-SNP: failed to INIT rc %d, error %#x\n",
+                       rc, args->error);
+       }
+
+       /* Defer legacy SEV/SEV-ES support if allowed by caller/module. */
+       if (args->probe && !psp_init_on_probe)
+               return 0;
+
+       return __sev_platform_init_locked(&args->error);
+}
+
+int sev_platform_init(struct sev_platform_init_args *args)
 {
        int rc;
 
        mutex_lock(&sev_cmd_mutex);
-       rc = __sev_platform_init_locked(error);
+       rc = _sev_platform_init_locked(args);
        mutex_unlock(&sev_cmd_mutex);
 
        return rc;
@@ -556,17 +1365,6 @@ static int __sev_platform_shutdown_locked(int *error)
        return ret;
 }
 
-static int sev_platform_shutdown(int *error)
-{
-       int rc;
-
-       mutex_lock(&sev_cmd_mutex);
-       rc = __sev_platform_shutdown_locked(NULL);
-       mutex_unlock(&sev_cmd_mutex);
-
-       return rc;
-}
-
 static int sev_get_platform_state(int *state, int *error)
 {
        struct sev_user_data_status data;
@@ -842,6 +1640,72 @@ fw_err:
        return ret;
 }
 
+static int __sev_snp_shutdown_locked(int *error, bool panic)
+{
+       struct sev_device *sev = psp_master->sev_data;
+       struct sev_data_snp_shutdown_ex data;
+       int ret;
+
+       if (!sev->snp_initialized)
+               return 0;
+
+       memset(&data, 0, sizeof(data));
+       data.len = sizeof(data);
+       data.iommu_snp_shutdown = 1;
+
+       /*
+        * If invoked during panic handling, local interrupts are disabled
+        * and all CPUs are stopped, so wbinvd_on_all_cpus() can't be called.
+        * In that case, a wbinvd() is done on remote CPUs via the NMI
+        * callback, so only a local wbinvd() is needed here.
+        */
+       if (!panic)
+               wbinvd_on_all_cpus();
+       else
+               wbinvd();
+
+       ret = __sev_do_cmd_locked(SEV_CMD_SNP_SHUTDOWN_EX, &data, error);
+       /* SHUTDOWN may require DF_FLUSH */
+       if (*error == SEV_RET_DFFLUSH_REQUIRED) {
+               ret = __sev_do_cmd_locked(SEV_CMD_SNP_DF_FLUSH, NULL, NULL);
+               if (ret) {
+                       dev_err(sev->dev, "SEV-SNP DF_FLUSH failed\n");
+                       return ret;
+               }
+               /* reissue the shutdown command */
+               ret = __sev_do_cmd_locked(SEV_CMD_SNP_SHUTDOWN_EX, &data,
+                                         error);
+       }
+       if (ret) {
+               dev_err(sev->dev, "SEV-SNP firmware shutdown failed\n");
+               return ret;
+       }
+
+       /*
+        * SNP_SHUTDOWN_EX with IOMMU_SNP_SHUTDOWN set to 1 disables SNP
+        * enforcement by the IOMMU and also transitions all pages
+        * associated with the IOMMU to the Reclaim state.
+        * Firmware was transitioning the IOMMU pages to Hypervisor state
+        * before version 1.53. But, accounting for the number of assigned
+        * 4kB pages in a 2M page was done incorrectly by not transitioning
+        * to the Reclaim state. This resulted in RMP #PF when later accessing
+        * the 2M page containing those pages during kexec boot. Hence, the
+        * firmware now transitions these pages to Reclaim state and hypervisor
+        * needs to transition these pages to shared state. SNP Firmware
+        * version 1.53 and above are needed for kexec boot.
+        */
+       ret = amd_iommu_snp_disable();
+       if (ret) {
+               dev_err(sev->dev, "SNP IOMMU shutdown failed\n");
+               return ret;
+       }
+
+       sev->snp_initialized = false;
+       dev_dbg(sev->dev, "SEV-SNP firmware shutdown\n");
+
+       return ret;
+}
+
 static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp, bool writable)
 {
        struct sev_device *sev = psp_master->sev_data;
@@ -1084,6 +1948,85 @@ e_free_pdh:
        return ret;
 }
 
+static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp)
+{
+       struct sev_device *sev = psp_master->sev_data;
+       struct sev_data_snp_addr buf;
+       struct page *status_page;
+       void *data;
+       int ret;
+
+       if (!sev->snp_initialized || !argp->data)
+               return -EINVAL;
+
+       status_page = alloc_page(GFP_KERNEL_ACCOUNT);
+       if (!status_page)
+               return -ENOMEM;
+
+       data = page_address(status_page);
+
+       /*
+        * Firmware expects status page to be in firmware-owned state, otherwise
+        * it will report firmware error code INVALID_PAGE_STATE (0x1A).
+        */
+       if (rmp_mark_pages_firmware(__pa(data), 1, true)) {
+               ret = -EFAULT;
+               goto cleanup;
+       }
+
+       buf.address = __psp_pa(data);
+       ret = __sev_do_cmd_locked(SEV_CMD_SNP_PLATFORM_STATUS, &buf, &argp->error);
+
+       /*
+        * Status page will be transitioned to Reclaim state upon success, or
+        * left in Firmware state in failure. Use snp_reclaim_pages() to
+        * transition either case back to Hypervisor-owned state.
+        */
+       if (snp_reclaim_pages(__pa(data), 1, true))
+               return -EFAULT;
+
+       if (ret)
+               goto cleanup;
+
+       if (copy_to_user((void __user *)argp->data, data,
+                        sizeof(struct sev_user_data_snp_status)))
+               ret = -EFAULT;
+
+cleanup:
+       __free_pages(status_page, 0);
+       return ret;
+}
+
+static int sev_ioctl_do_snp_commit(struct sev_issue_cmd *argp)
+{
+       struct sev_device *sev = psp_master->sev_data;
+       struct sev_data_snp_commit buf;
+
+       if (!sev->snp_initialized)
+               return -EINVAL;
+
+       buf.len = sizeof(buf);
+
+       return __sev_do_cmd_locked(SEV_CMD_SNP_COMMIT, &buf, &argp->error);
+}
+
+static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable)
+{
+       struct sev_device *sev = psp_master->sev_data;
+       struct sev_user_data_snp_config config;
+
+       if (!sev->snp_initialized || !argp->data)
+               return -EINVAL;
+
+       if (!writable)
+               return -EPERM;
+
+       if (copy_from_user(&config, (void __user *)argp->data, sizeof(config)))
+               return -EFAULT;
+
+       return __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error);
+}
+
 static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
 {
        void __user *argp = (void __user *)arg;
@@ -1135,6 +2078,15 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
        case SEV_GET_ID2:
                ret = sev_ioctl_do_get_id2(&input);
                break;
+       case SNP_PLATFORM_STATUS:
+               ret = sev_ioctl_do_snp_platform_status(&input);
+               break;
+       case SNP_COMMIT:
+               ret = sev_ioctl_do_snp_commit(&input);
+               break;
+       case SNP_SET_CONFIG:
+               ret = sev_ioctl_do_snp_set_config(&input, writable);
+               break;
        default:
                ret = -EINVAL;
                goto out;
@@ -1245,10 +2197,12 @@ int sev_dev_init(struct psp_device *psp)
        if (!sev)
                goto e_err;
 
-       sev->cmd_buf = (void *)devm_get_free_pages(dev, GFP_KERNEL, 0);
+       sev->cmd_buf = (void *)devm_get_free_pages(dev, GFP_KERNEL, 1);
        if (!sev->cmd_buf)
                goto e_sev;
 
+       sev->cmd_buf_backup = (uint8_t *)sev->cmd_buf + PAGE_SIZE;
+
        psp->sev_data = sev;
 
        sev->dev = dev;
@@ -1287,24 +2241,51 @@ e_err:
        return ret;
 }
 
-static void sev_firmware_shutdown(struct sev_device *sev)
+static void __sev_firmware_shutdown(struct sev_device *sev, bool panic)
 {
-       sev_platform_shutdown(NULL);
+       int error;
+
+       __sev_platform_shutdown_locked(NULL);
 
        if (sev_es_tmr) {
-               /* The TMR area was encrypted, flush it from the cache */
-               wbinvd_on_all_cpus();
+               /*
+                * The TMR area was encrypted, flush it from the cache.
+                *
+                * If invoked during panic handling, local interrupts are
+                * disabled and all CPUs are stopped, so wbinvd_on_all_cpus()
+                * can't be used. In that case, wbinvd() is done on remote CPUs
+                * via the NMI callback, and done for this CPU later during
+                * SNP shutdown, so wbinvd_on_all_cpus() can be skipped.
+                */
+               if (!panic)
+                       wbinvd_on_all_cpus();
 
-               free_pages((unsigned long)sev_es_tmr,
-                          get_order(SEV_ES_TMR_SIZE));
+               __snp_free_firmware_pages(virt_to_page(sev_es_tmr),
+                                         get_order(sev_es_tmr_size),
+                                         true);
                sev_es_tmr = NULL;
        }
 
        if (sev_init_ex_buffer) {
-               free_pages((unsigned long)sev_init_ex_buffer,
-                          get_order(NV_LENGTH));
+               __snp_free_firmware_pages(virt_to_page(sev_init_ex_buffer),
+                                         get_order(NV_LENGTH),
+                                         true);
                sev_init_ex_buffer = NULL;
        }
+
+       if (snp_range_list) {
+               kfree(snp_range_list);
+               snp_range_list = NULL;
+       }
+
+       __sev_snp_shutdown_locked(&error, panic);
+}
+
+static void sev_firmware_shutdown(struct sev_device *sev)
+{
+       mutex_lock(&sev_cmd_mutex);
+       __sev_firmware_shutdown(sev, false);
+       mutex_unlock(&sev_cmd_mutex);
 }
 
 void sev_dev_destroy(struct psp_device *psp)
@@ -1322,6 +2303,29 @@ void sev_dev_destroy(struct psp_device *psp)
        psp_clear_sev_irq_handler(psp);
 }
 
+static int snp_shutdown_on_panic(struct notifier_block *nb,
+                                unsigned long reason, void *arg)
+{
+       struct sev_device *sev = psp_master->sev_data;
+
+       /*
+        * If sev_cmd_mutex is already acquired, then it's likely
+        * another PSP command is in flight and issuing a shutdown
+        * would fail in unexpected ways. Rather than create even
+        * more confusion during a panic, just bail out here.
+        */
+       if (mutex_is_locked(&sev_cmd_mutex))
+               return NOTIFY_DONE;
+
+       __sev_firmware_shutdown(sev, true);
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block snp_panic_notifier = {
+       .notifier_call = snp_shutdown_on_panic,
+};
+
 int sev_issue_cmd_external_user(struct file *filep, unsigned int cmd,
                                void *data, int *error)
 {
@@ -1335,7 +2339,8 @@ EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user);
 void sev_pci_init(void)
 {
        struct sev_device *sev = psp_master->sev_data;
-       int error, rc;
+       struct sev_platform_init_args args = {0};
+       int rc;
 
        if (!sev)
                return;
@@ -1348,36 +2353,18 @@ void sev_pci_init(void)
        if (sev_update_firmware(sev->dev) == 0)
                sev_get_api_version();
 
-       /* If an init_ex_path is provided rely on INIT_EX for PSP initialization
-        * instead of INIT.
-        */
-       if (init_ex_path) {
-               sev_init_ex_buffer = sev_fw_alloc(NV_LENGTH);
-               if (!sev_init_ex_buffer) {
-                       dev_err(sev->dev,
-                               "SEV: INIT_EX NV memory allocation failed\n");
-                       goto err;
-               }
-       }
-
-       /* Obtain the TMR memory area for SEV-ES use */
-       sev_es_tmr = sev_fw_alloc(SEV_ES_TMR_SIZE);
-       if (sev_es_tmr)
-               /* Must flush the cache before giving it to the firmware */
-               clflush_cache_range(sev_es_tmr, SEV_ES_TMR_SIZE);
-       else
-               dev_warn(sev->dev,
-                        "SEV: TMR allocation failed, SEV-ES support unavailable\n");
-
-       if (!psp_init_on_probe)
-               return;
-
        /* Initialize the platform */
-       rc = sev_platform_init(&error);
+       args.probe = true;
+       rc = sev_platform_init(&args);
        if (rc)
                dev_err(sev->dev, "SEV: failed to INIT error %#x, rc %d\n",
-                       error, rc);
+                       args.error, rc);
 
+       dev_info(sev->dev, "SEV%s API:%d.%d build:%d\n", sev->snp_initialized ?
+               "-SNP" : "", sev->api_major, sev->api_minor, sev->build);
+
+       atomic_notifier_chain_register(&panic_notifier_list,
+                                      &snp_panic_notifier);
        return;
 
 err:
@@ -1392,4 +2379,7 @@ void sev_pci_exit(void)
                return;
 
        sev_firmware_shutdown(sev);
+
+       atomic_notifier_chain_unregister(&panic_notifier_list,
+                                        &snp_panic_notifier);
 }
index 778c95155e745becb09ada5f21d83044e6a120e1..3e4e5574e88a30278fa476543e0f423ee08480ac 100644 (file)
@@ -52,6 +52,11 @@ struct sev_device {
        u8 build;
 
        void *cmd_buf;
+       void *cmd_buf_backup;
+       bool cmd_buf_active;
+       bool cmd_buf_backup_active;
+
+       bool snp_initialized;
 };
 
 int sev_dev_init(struct psp_device *psp);
index 1b13b4aa16ecc441a37266996f1b4aca6863a436..a235e6c300f1e5419eb06945757946ced70f12e2 100644 (file)
@@ -332,12 +332,12 @@ static int rk_hash_run(struct crypto_engine *engine, void *breq)
 theend:
        pm_runtime_put_autosuspend(rkc->dev);
 
+       rk_hash_unprepare(engine, breq);
+
        local_bh_disable();
        crypto_finalize_hash_request(engine, breq, err);
        local_bh_enable();
 
-       rk_hash_unprepare(engine, breq);
-
        return 0;
 }
 
index 2621ff8a93764d4ad905bcfe7e52331f45bb2c71..de53eddf6796b6c6ac6eafdeaee9a7ee03c979d3 100644 (file)
@@ -104,7 +104,8 @@ static void virtio_crypto_dataq_akcipher_callback(struct virtio_crypto_request *
 }
 
 static int virtio_crypto_alg_akcipher_init_session(struct virtio_crypto_akcipher_ctx *ctx,
-               struct virtio_crypto_ctrl_header *header, void *para,
+               struct virtio_crypto_ctrl_header *header,
+               struct virtio_crypto_akcipher_session_para *para,
                const uint8_t *key, unsigned int keylen)
 {
        struct scatterlist outhdr_sg, key_sg, inhdr_sg, *sgs[3];
@@ -128,7 +129,7 @@ static int virtio_crypto_alg_akcipher_init_session(struct virtio_crypto_akcipher
 
        ctrl = &vc_ctrl_req->ctrl;
        memcpy(&ctrl->header, header, sizeof(ctrl->header));
-       memcpy(&ctrl->u, para, sizeof(ctrl->u));
+       memcpy(&ctrl->u.akcipher_create_session.para, para, sizeof(*para));
        input = &vc_ctrl_req->input;
        input->status = cpu_to_le32(VIRTIO_CRYPTO_ERR);
 
index dcf2b39e1048822ca90324667d85f68225c05fa4..1a3e6aafbdcc33dd2aae8731be8a5ad52cc0891e 100644 (file)
@@ -316,31 +316,27 @@ static const struct cxl_root_ops acpi_root_ops = {
        .qos_class = cxl_acpi_qos_class,
 };
 
-static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
-                          const unsigned long end)
+static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
+                            struct cxl_cfmws_context *ctx)
 {
        int target_map[CXL_DECODER_MAX_INTERLEAVE];
-       struct cxl_cfmws_context *ctx = arg;
        struct cxl_port *root_port = ctx->root_port;
        struct resource *cxl_res = ctx->cxl_res;
        struct cxl_cxims_context cxims_ctx;
        struct cxl_root_decoder *cxlrd;
        struct device *dev = ctx->dev;
-       struct acpi_cedt_cfmws *cfmws;
        cxl_calc_hb_fn cxl_calc_hb;
        struct cxl_decoder *cxld;
        unsigned int ways, i, ig;
        struct resource *res;
        int rc;
 
-       cfmws = (struct acpi_cedt_cfmws *) header;
-
        rc = cxl_acpi_cfmws_verify(dev, cfmws);
        if (rc) {
                dev_err(dev, "CFMWS range %#llx-%#llx not registered\n",
                        cfmws->base_hpa,
                        cfmws->base_hpa + cfmws->window_size - 1);
-               return 0;
+               return rc;
        }
 
        rc = eiw_to_ways(cfmws->interleave_ways, &ways);
@@ -376,7 +372,7 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
 
        cxlrd = cxl_root_decoder_alloc(root_port, ways, cxl_calc_hb);
        if (IS_ERR(cxlrd))
-               return 0;
+               return PTR_ERR(cxlrd);
 
        cxld = &cxlrd->cxlsd.cxld;
        cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
@@ -420,16 +416,7 @@ err_xormap:
                put_device(&cxld->dev);
        else
                rc = cxl_decoder_autoremove(dev, cxld);
-       if (rc) {
-               dev_err(dev, "Failed to add decode range: %pr", res);
-               return rc;
-       }
-       dev_dbg(dev, "add: %s node: %d range [%#llx - %#llx]\n",
-               dev_name(&cxld->dev),
-               phys_to_target_node(cxld->hpa_range.start),
-               cxld->hpa_range.start, cxld->hpa_range.end);
-
-       return 0;
+       return rc;
 
 err_insert:
        kfree(res->name);
@@ -438,6 +425,29 @@ err_name:
        return -ENOMEM;
 }
 
+static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
+                          const unsigned long end)
+{
+       struct acpi_cedt_cfmws *cfmws = (struct acpi_cedt_cfmws *)header;
+       struct cxl_cfmws_context *ctx = arg;
+       struct device *dev = ctx->dev;
+       int rc;
+
+       rc = __cxl_parse_cfmws(cfmws, ctx);
+       if (rc)
+               dev_err(dev,
+                       "Failed to add decode range: [%#llx - %#llx] (%d)\n",
+                       cfmws->base_hpa,
+                       cfmws->base_hpa + cfmws->window_size - 1, rc);
+       else
+               dev_dbg(dev, "decode range: node: %d range [%#llx - %#llx]\n",
+                       phys_to_target_node(cfmws->base_hpa), cfmws->base_hpa,
+                       cfmws->base_hpa + cfmws->window_size - 1);
+
+       /* never fail cxl_acpi load for a single window failure */
+       return 0;
+}
+
 __mock struct acpi_device *to_cxl_host_bridge(struct device *host,
                                              struct device *dev)
 {
index 6fe11546889fabb48e997fda83e1f184a64179c6..08fd0baea7a0eb0f1c1442e9f454e3c32736d19c 100644 (file)
@@ -210,19 +210,12 @@ static int cxl_port_perf_data_calculate(struct cxl_port *port,
        return 0;
 }
 
-static void add_perf_entry(struct device *dev, struct dsmas_entry *dent,
-                          struct list_head *list)
+static void update_perf_entry(struct device *dev, struct dsmas_entry *dent,
+                             struct cxl_dpa_perf *dpa_perf)
 {
-       struct cxl_dpa_perf *dpa_perf;
-
-       dpa_perf = kzalloc(sizeof(*dpa_perf), GFP_KERNEL);
-       if (!dpa_perf)
-               return;
-
        dpa_perf->dpa_range = dent->dpa_range;
        dpa_perf->coord = dent->coord;
        dpa_perf->qos_class = dent->qos_class;
-       list_add_tail(&dpa_perf->list, list);
        dev_dbg(dev,
                "DSMAS: dpa: %#llx qos: %d read_bw: %d write_bw %d read_lat: %d write_lat: %d\n",
                dent->dpa_range.start, dpa_perf->qos_class,
@@ -230,20 +223,6 @@ static void add_perf_entry(struct device *dev, struct dsmas_entry *dent,
                dent->coord.read_latency, dent->coord.write_latency);
 }
 
-static void free_perf_ents(void *data)
-{
-       struct cxl_memdev_state *mds = data;
-       struct cxl_dpa_perf *dpa_perf, *n;
-       LIST_HEAD(discard);
-
-       list_splice_tail_init(&mds->ram_perf_list, &discard);
-       list_splice_tail_init(&mds->pmem_perf_list, &discard);
-       list_for_each_entry_safe(dpa_perf, n, &discard, list) {
-               list_del(&dpa_perf->list);
-               kfree(dpa_perf);
-       }
-}
-
 static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds,
                                     struct xarray *dsmas_xa)
 {
@@ -263,16 +242,14 @@ static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds,
        xa_for_each(dsmas_xa, index, dent) {
                if (resource_size(&cxlds->ram_res) &&
                    range_contains(&ram_range, &dent->dpa_range))
-                       add_perf_entry(dev, dent, &mds->ram_perf_list);
+                       update_perf_entry(dev, dent, &mds->ram_perf);
                else if (resource_size(&cxlds->pmem_res) &&
                         range_contains(&pmem_range, &dent->dpa_range))
-                       add_perf_entry(dev, dent, &mds->pmem_perf_list);
+                       update_perf_entry(dev, dent, &mds->pmem_perf);
                else
                        dev_dbg(dev, "no partition for dsmas dpa: %#llx\n",
                                dent->dpa_range.start);
        }
-
-       devm_add_action_or_reset(&cxlds->cxlmd->dev, free_perf_ents, mds);
 }
 
 static int match_cxlrd_qos_class(struct device *dev, void *data)
@@ -293,24 +270,24 @@ static int match_cxlrd_qos_class(struct device *dev, void *data)
        return 0;
 }
 
-static void cxl_qos_match(struct cxl_port *root_port,
-                         struct list_head *work_list,
-                         struct list_head *discard_list)
+static void reset_dpa_perf(struct cxl_dpa_perf *dpa_perf)
 {
-       struct cxl_dpa_perf *dpa_perf, *n;
+       *dpa_perf = (struct cxl_dpa_perf) {
+               .qos_class = CXL_QOS_CLASS_INVALID,
+       };
+}
 
-       list_for_each_entry_safe(dpa_perf, n, work_list, list) {
-               int rc;
+static bool cxl_qos_match(struct cxl_port *root_port,
+                         struct cxl_dpa_perf *dpa_perf)
+{
+       if (dpa_perf->qos_class == CXL_QOS_CLASS_INVALID)
+               return false;
 
-               if (dpa_perf->qos_class == CXL_QOS_CLASS_INVALID)
-                       return;
+       if (!device_for_each_child(&root_port->dev, &dpa_perf->qos_class,
+                                  match_cxlrd_qos_class))
+               return false;
 
-               rc = device_for_each_child(&root_port->dev,
-                                          (void *)&dpa_perf->qos_class,
-                                          match_cxlrd_qos_class);
-               if (!rc)
-                       list_move_tail(&dpa_perf->list, discard_list);
-       }
+       return true;
 }
 
 static int match_cxlrd_hb(struct device *dev, void *data)
@@ -334,23 +311,10 @@ static int match_cxlrd_hb(struct device *dev, void *data)
        return 0;
 }
 
-static void discard_dpa_perf(struct list_head *list)
-{
-       struct cxl_dpa_perf *dpa_perf, *n;
-
-       list_for_each_entry_safe(dpa_perf, n, list, list) {
-               list_del(&dpa_perf->list);
-               kfree(dpa_perf);
-       }
-}
-DEFINE_FREE(dpa_perf, struct list_head *, if (!list_empty(_T)) discard_dpa_perf(_T))
-
 static int cxl_qos_class_verify(struct cxl_memdev *cxlmd)
 {
        struct cxl_dev_state *cxlds = cxlmd->cxlds;
        struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
-       LIST_HEAD(__discard);
-       struct list_head *discard __free(dpa_perf) = &__discard;
        struct cxl_port *root_port;
        int rc;
 
@@ -363,16 +327,17 @@ static int cxl_qos_class_verify(struct cxl_memdev *cxlmd)
        root_port = &cxl_root->port;
 
        /* Check that the QTG IDs are all sane between end device and root decoders */
-       cxl_qos_match(root_port, &mds->ram_perf_list, discard);
-       cxl_qos_match(root_port, &mds->pmem_perf_list, discard);
+       if (!cxl_qos_match(root_port, &mds->ram_perf))
+               reset_dpa_perf(&mds->ram_perf);
+       if (!cxl_qos_match(root_port, &mds->pmem_perf))
+               reset_dpa_perf(&mds->pmem_perf);
 
        /* Check to make sure that the device's host bridge is under a root decoder */
        rc = device_for_each_child(&root_port->dev,
-                                  (void *)cxlmd->endpoint->host_bridge,
-                                  match_cxlrd_hb);
+                                  cxlmd->endpoint->host_bridge, match_cxlrd_hb);
        if (!rc) {
-               list_splice_tail_init(&mds->ram_perf_list, discard);
-               list_splice_tail_init(&mds->pmem_perf_list, discard);
+               reset_dpa_perf(&mds->ram_perf);
+               reset_dpa_perf(&mds->pmem_perf);
        }
 
        return rc;
@@ -417,6 +382,7 @@ void cxl_endpoint_parse_cdat(struct cxl_port *port)
 
        cxl_memdev_set_qos_class(cxlds, dsmas_xa);
        cxl_qos_class_verify(cxlmd);
+       cxl_memdev_update_perf(cxlmd);
 }
 EXPORT_SYMBOL_NS_GPL(cxl_endpoint_parse_cdat, CXL);
 
index 27166a41170579a9441a2f9bf3e2a915ed85d893..9adda4795eb786b8658b573dd1e79befbad52255 100644 (file)
@@ -1391,8 +1391,8 @@ struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev)
        mds->cxlds.reg_map.host = dev;
        mds->cxlds.reg_map.resource = CXL_RESOURCE_NONE;
        mds->cxlds.type = CXL_DEVTYPE_CLASSMEM;
-       INIT_LIST_HEAD(&mds->ram_perf_list);
-       INIT_LIST_HEAD(&mds->pmem_perf_list);
+       mds->ram_perf.qos_class = CXL_QOS_CLASS_INVALID;
+       mds->pmem_perf.qos_class = CXL_QOS_CLASS_INVALID;
 
        return mds;
 }
index dae8802ecdb01ee748e3891120bc0011e9e8894e..d4e259f3a7e914b9e3f17330cbc57f691d1976c2 100644 (file)
@@ -447,13 +447,41 @@ static struct attribute *cxl_memdev_attributes[] = {
        NULL,
 };
 
+static ssize_t pmem_qos_class_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+       struct cxl_dev_state *cxlds = cxlmd->cxlds;
+       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
+
+       return sysfs_emit(buf, "%d\n", mds->pmem_perf.qos_class);
+}
+
+static struct device_attribute dev_attr_pmem_qos_class =
+       __ATTR(qos_class, 0444, pmem_qos_class_show, NULL);
+
 static struct attribute *cxl_memdev_pmem_attributes[] = {
        &dev_attr_pmem_size.attr,
+       &dev_attr_pmem_qos_class.attr,
        NULL,
 };
 
+static ssize_t ram_qos_class_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+       struct cxl_dev_state *cxlds = cxlmd->cxlds;
+       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
+
+       return sysfs_emit(buf, "%d\n", mds->ram_perf.qos_class);
+}
+
+static struct device_attribute dev_attr_ram_qos_class =
+       __ATTR(qos_class, 0444, ram_qos_class_show, NULL);
+
 static struct attribute *cxl_memdev_ram_attributes[] = {
        &dev_attr_ram_size.attr,
+       &dev_attr_ram_qos_class.attr,
        NULL,
 };
 
@@ -477,14 +505,42 @@ static struct attribute_group cxl_memdev_attribute_group = {
        .is_visible = cxl_memdev_visible,
 };
 
+static umode_t cxl_ram_visible(struct kobject *kobj, struct attribute *a, int n)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
+
+       if (a == &dev_attr_ram_qos_class.attr)
+               if (mds->ram_perf.qos_class == CXL_QOS_CLASS_INVALID)
+                       return 0;
+
+       return a->mode;
+}
+
 static struct attribute_group cxl_memdev_ram_attribute_group = {
        .name = "ram",
        .attrs = cxl_memdev_ram_attributes,
+       .is_visible = cxl_ram_visible,
 };
 
+static umode_t cxl_pmem_visible(struct kobject *kobj, struct attribute *a, int n)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
+
+       if (a == &dev_attr_pmem_qos_class.attr)
+               if (mds->pmem_perf.qos_class == CXL_QOS_CLASS_INVALID)
+                       return 0;
+
+       return a->mode;
+}
+
 static struct attribute_group cxl_memdev_pmem_attribute_group = {
        .name = "pmem",
        .attrs = cxl_memdev_pmem_attributes,
+       .is_visible = cxl_pmem_visible,
 };
 
 static umode_t cxl_memdev_security_visible(struct kobject *kobj,
@@ -519,6 +575,13 @@ static const struct attribute_group *cxl_memdev_attribute_groups[] = {
        NULL,
 };
 
+void cxl_memdev_update_perf(struct cxl_memdev *cxlmd)
+{
+       sysfs_update_group(&cxlmd->dev.kobj, &cxl_memdev_ram_attribute_group);
+       sysfs_update_group(&cxlmd->dev.kobj, &cxl_memdev_pmem_attribute_group);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_memdev_update_perf, CXL);
+
 static const struct device_type cxl_memdev_type = {
        .name = "cxl_memdev",
        .release = cxl_memdev_release,
index 6c9c8d92f8f71401af70fec26be60e0339c18c64..e9e6c81ce034a8ffaba105132d5b9ecc59d51880 100644 (file)
@@ -477,9 +477,9 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
                allowed++;
        }
 
-       if (!allowed) {
-               cxl_set_mem_enable(cxlds, 0);
-               info->mem_enabled = 0;
+       if (!allowed && info->mem_enabled) {
+               dev_err(dev, "Range register decodes outside platform defined CXL ranges.\n");
+               return -ENXIO;
        }
 
        /*
@@ -932,11 +932,21 @@ static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { }
 void cxl_cor_error_detected(struct pci_dev *pdev)
 {
        struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+       struct device *dev = &cxlds->cxlmd->dev;
+
+       scoped_guard(device, dev) {
+               if (!dev->driver) {
+                       dev_warn(&pdev->dev,
+                                "%s: memdev disabled, abort error handling\n",
+                                dev_name(dev));
+                       return;
+               }
 
-       if (cxlds->rcd)
-               cxl_handle_rdport_errors(cxlds);
+               if (cxlds->rcd)
+                       cxl_handle_rdport_errors(cxlds);
 
-       cxl_handle_endpoint_cor_ras(cxlds);
+               cxl_handle_endpoint_cor_ras(cxlds);
+       }
 }
 EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, CXL);
 
@@ -948,16 +958,25 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
        struct device *dev = &cxlmd->dev;
        bool ue;
 
-       if (cxlds->rcd)
-               cxl_handle_rdport_errors(cxlds);
+       scoped_guard(device, dev) {
+               if (!dev->driver) {
+                       dev_warn(&pdev->dev,
+                                "%s: memdev disabled, abort error handling\n",
+                                dev_name(dev));
+                       return PCI_ERS_RESULT_DISCONNECT;
+               }
+
+               if (cxlds->rcd)
+                       cxl_handle_rdport_errors(cxlds);
+               /*
+                * A frozen channel indicates an impending reset which is fatal to
+                * CXL.mem operation, and will likely crash the system. On the off
+                * chance the situation is recoverable dump the status of the RAS
+                * capability registers and bounce the active state of the memdev.
+                */
+               ue = cxl_handle_endpoint_ras(cxlds);
+       }
 
-       /*
-        * A frozen channel indicates an impending reset which is fatal to
-        * CXL.mem operation, and will likely crash the system. On the off
-        * chance the situation is recoverable dump the status of the RAS
-        * capability registers and bounce the active state of the memdev.
-        */
-       ue = cxl_handle_endpoint_ras(cxlds);
 
        switch (state) {
        case pci_channel_io_normal:
index ce0e2d82bb2b4cfdc61761d5e32a8c91cc121d82..4c7fd2d5cccb2965eb528cbc26bb261ef01dcdce 100644 (file)
@@ -730,12 +730,17 @@ static int match_auto_decoder(struct device *dev, void *data)
        return 0;
 }
 
-static struct cxl_decoder *cxl_region_find_decoder(struct cxl_port *port,
-                                                  struct cxl_region *cxlr)
+static struct cxl_decoder *
+cxl_region_find_decoder(struct cxl_port *port,
+                       struct cxl_endpoint_decoder *cxled,
+                       struct cxl_region *cxlr)
 {
        struct device *dev;
        int id = 0;
 
+       if (port == cxled_to_port(cxled))
+               return &cxled->cxld;
+
        if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags))
                dev = device_find_child(&port->dev, &cxlr->params,
                                        match_auto_decoder);
@@ -753,8 +758,31 @@ static struct cxl_decoder *cxl_region_find_decoder(struct cxl_port *port,
        return to_cxl_decoder(dev);
 }
 
-static struct cxl_region_ref *alloc_region_ref(struct cxl_port *port,
-                                              struct cxl_region *cxlr)
+static bool auto_order_ok(struct cxl_port *port, struct cxl_region *cxlr_iter,
+                         struct cxl_decoder *cxld)
+{
+       struct cxl_region_ref *rr = cxl_rr_load(port, cxlr_iter);
+       struct cxl_decoder *cxld_iter = rr->decoder;
+
+       /*
+        * Allow the out of order assembly of auto-discovered regions.
+        * Per CXL Spec 3.1 8.2.4.20.12 software must commit decoders
+        * in HPA order. Confirm that the decoder with the lesser HPA
+        * starting address has the lesser id.
+        */
+       dev_dbg(&cxld->dev, "check for HPA violation %s:%d < %s:%d\n",
+               dev_name(&cxld->dev), cxld->id,
+               dev_name(&cxld_iter->dev), cxld_iter->id);
+
+       if (cxld_iter->id > cxld->id)
+               return true;
+
+       return false;
+}
+
+static struct cxl_region_ref *
+alloc_region_ref(struct cxl_port *port, struct cxl_region *cxlr,
+                struct cxl_endpoint_decoder *cxled)
 {
        struct cxl_region_params *p = &cxlr->params;
        struct cxl_region_ref *cxl_rr, *iter;
@@ -764,16 +792,21 @@ static struct cxl_region_ref *alloc_region_ref(struct cxl_port *port,
        xa_for_each(&port->regions, index, iter) {
                struct cxl_region_params *ip = &iter->region->params;
 
-               if (!ip->res)
+               if (!ip->res || ip->res->start < p->res->start)
                        continue;
 
-               if (ip->res->start > p->res->start) {
-                       dev_dbg(&cxlr->dev,
-                               "%s: HPA order violation %s:%pr vs %pr\n",
-                               dev_name(&port->dev),
-                               dev_name(&iter->region->dev), ip->res, p->res);
-                       return ERR_PTR(-EBUSY);
+               if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags)) {
+                       struct cxl_decoder *cxld;
+
+                       cxld = cxl_region_find_decoder(port, cxled, cxlr);
+                       if (auto_order_ok(port, iter->region, cxld))
+                               continue;
                }
+               dev_dbg(&cxlr->dev, "%s: HPA order violation %s:%pr vs %pr\n",
+                       dev_name(&port->dev),
+                       dev_name(&iter->region->dev), ip->res, p->res);
+
+               return ERR_PTR(-EBUSY);
        }
 
        cxl_rr = kzalloc(sizeof(*cxl_rr), GFP_KERNEL);
@@ -853,10 +886,7 @@ static int cxl_rr_alloc_decoder(struct cxl_port *port, struct cxl_region *cxlr,
 {
        struct cxl_decoder *cxld;
 
-       if (port == cxled_to_port(cxled))
-               cxld = &cxled->cxld;
-       else
-               cxld = cxl_region_find_decoder(port, cxlr);
+       cxld = cxl_region_find_decoder(port, cxled, cxlr);
        if (!cxld) {
                dev_dbg(&cxlr->dev, "%s: no decoder available\n",
                        dev_name(&port->dev));
@@ -953,7 +983,7 @@ static int cxl_port_attach_region(struct cxl_port *port,
                        nr_targets_inc = true;
                }
        } else {
-               cxl_rr = alloc_region_ref(port, cxlr);
+               cxl_rr = alloc_region_ref(port, cxlr, cxled);
                if (IS_ERR(cxl_rr)) {
                        dev_dbg(&cxlr->dev,
                                "%s: failed to allocate region reference\n",
index b6017c0c57b4d5e69dfe45011b7a8b3f5bf0b913..003feebab79b5f8e7563ba2e32665b4377871a55 100644 (file)
@@ -880,6 +880,8 @@ void cxl_switch_parse_cdat(struct cxl_port *port);
 int cxl_endpoint_get_perf_coordinates(struct cxl_port *port,
                                      struct access_coordinate *coord);
 
+void cxl_memdev_update_perf(struct cxl_memdev *cxlmd);
+
 /*
  * Unit test builds overrides this to __weak, find the 'strong' version
  * of these symbols in tools/testing/cxl/.
index 5303d6942b880af65dcf8e77b02d26626c2bb94d..20fb3b35e89e0473ee8ad42dcd17407086fb8cdb 100644 (file)
@@ -395,13 +395,11 @@ enum cxl_devtype {
 
 /**
  * struct cxl_dpa_perf - DPA performance property entry
- * @list - list entry
  * @dpa_range - range for DPA address
  * @coord - QoS performance data (i.e. latency, bandwidth)
  * @qos_class - QoS Class cookies
  */
 struct cxl_dpa_perf {
-       struct list_head list;
        struct range dpa_range;
        struct access_coordinate coord;
        int qos_class;
@@ -471,8 +469,8 @@ struct cxl_dev_state {
  * @security: security driver state info
  * @fw: firmware upload / activation state
  * @mbox_send: @dev specific transport for transmitting mailbox commands
- * @ram_perf_list: performance data entries matched to RAM
- * @pmem_perf_list: performance data entries matched to PMEM
+ * @ram_perf: performance data entry matched to RAM partition
+ * @pmem_perf: performance data entry matched to PMEM partition
  *
  * See CXL 3.0 8.2.9.8.2 Capacity Configuration and Label Storage for
  * details on capacity parameters.
@@ -494,8 +492,8 @@ struct cxl_memdev_state {
        u64 next_volatile_bytes;
        u64 next_persistent_bytes;
 
-       struct list_head ram_perf_list;
-       struct list_head pmem_perf_list;
+       struct cxl_dpa_perf ram_perf;
+       struct cxl_dpa_perf pmem_perf;
 
        struct cxl_event_state event;
        struct cxl_poison_state poison;
index c5c9d8e0d88d69fcc9f031e1bd46ba7c44de4fd4..0c79d9ce877ccaef9895a9885801d4fff69c5093 100644 (file)
@@ -215,52 +215,6 @@ static ssize_t trigger_poison_list_store(struct device *dev,
 }
 static DEVICE_ATTR_WO(trigger_poison_list);
 
-static ssize_t ram_qos_class_show(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
-{
-       struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
-       struct cxl_dev_state *cxlds = cxlmd->cxlds;
-       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
-       struct cxl_dpa_perf *dpa_perf;
-
-       if (!dev->driver)
-               return -ENOENT;
-
-       if (list_empty(&mds->ram_perf_list))
-               return -ENOENT;
-
-       dpa_perf = list_first_entry(&mds->ram_perf_list, struct cxl_dpa_perf,
-                                   list);
-
-       return sysfs_emit(buf, "%d\n", dpa_perf->qos_class);
-}
-
-static struct device_attribute dev_attr_ram_qos_class =
-       __ATTR(qos_class, 0444, ram_qos_class_show, NULL);
-
-static ssize_t pmem_qos_class_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
-       struct cxl_dev_state *cxlds = cxlmd->cxlds;
-       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
-       struct cxl_dpa_perf *dpa_perf;
-
-       if (!dev->driver)
-               return -ENOENT;
-
-       if (list_empty(&mds->pmem_perf_list))
-               return -ENOENT;
-
-       dpa_perf = list_first_entry(&mds->pmem_perf_list, struct cxl_dpa_perf,
-                                   list);
-
-       return sysfs_emit(buf, "%d\n", dpa_perf->qos_class);
-}
-
-static struct device_attribute dev_attr_pmem_qos_class =
-       __ATTR(qos_class, 0444, pmem_qos_class_show, NULL);
-
 static umode_t cxl_mem_visible(struct kobject *kobj, struct attribute *a, int n)
 {
        struct device *dev = kobj_to_dev(kobj);
@@ -272,21 +226,11 @@ static umode_t cxl_mem_visible(struct kobject *kobj, struct attribute *a, int n)
                              mds->poison.enabled_cmds))
                        return 0;
 
-       if (a == &dev_attr_pmem_qos_class.attr)
-               if (list_empty(&mds->pmem_perf_list))
-                       return 0;
-
-       if (a == &dev_attr_ram_qos_class.attr)
-               if (list_empty(&mds->ram_perf_list))
-                       return 0;
-
        return a->mode;
 }
 
 static struct attribute *cxl_mem_attrs[] = {
        &dev_attr_trigger_poison_list.attr,
-       &dev_attr_ram_qos_class.attr,
-       &dev_attr_pmem_qos_class.attr,
        NULL
 };
 
index 233e7c42c161d8e0b64424776d121f5d08176010..2ff361e756d66147d8d20969c376730ae2bcc90e 100644 (file)
@@ -974,61 +974,6 @@ static struct pci_driver cxl_pci_driver = {
        },
 };
 
-#define CXL_EVENT_HDR_FLAGS_REC_SEVERITY GENMASK(1, 0)
-static void cxl_cper_event_call(enum cxl_event_type ev_type,
-                               struct cxl_cper_event_rec *rec)
-{
-       struct cper_cxl_event_devid *device_id = &rec->hdr.device_id;
-       struct pci_dev *pdev __free(pci_dev_put) = NULL;
-       enum cxl_event_log_type log_type;
-       struct cxl_dev_state *cxlds;
-       unsigned int devfn;
-       u32 hdr_flags;
-
-       devfn = PCI_DEVFN(device_id->device_num, device_id->func_num);
-       pdev = pci_get_domain_bus_and_slot(device_id->segment_num,
-                                          device_id->bus_num, devfn);
-       if (!pdev)
-               return;
-
-       guard(pci_dev)(pdev);
-       if (pdev->driver != &cxl_pci_driver)
-               return;
-
-       cxlds = pci_get_drvdata(pdev);
-       if (!cxlds)
-               return;
-
-       /* Fabricate a log type */
-       hdr_flags = get_unaligned_le24(rec->event.generic.hdr.flags);
-       log_type = FIELD_GET(CXL_EVENT_HDR_FLAGS_REC_SEVERITY, hdr_flags);
-
-       cxl_event_trace_record(cxlds->cxlmd, log_type, ev_type,
-                              &uuid_null, &rec->event);
-}
-
-static int __init cxl_pci_driver_init(void)
-{
-       int rc;
-
-       rc = cxl_cper_register_callback(cxl_cper_event_call);
-       if (rc)
-               return rc;
-
-       rc = pci_register_driver(&cxl_pci_driver);
-       if (rc)
-               cxl_cper_unregister_callback(cxl_cper_event_call);
-
-       return rc;
-}
-
-static void __exit cxl_pci_driver_exit(void)
-{
-       pci_unregister_driver(&cxl_pci_driver);
-       cxl_cper_unregister_callback(cxl_cper_event_call);
-}
-
-module_init(cxl_pci_driver_init);
-module_exit(cxl_pci_driver_exit);
+module_pci_driver(cxl_pci_driver);
 MODULE_LICENSE("GPL v2");
 MODULE_IMPORT_NS(CXL);
index b38786f0ad7995d9b0d22aa18fdd6d2407320c26..b75fdaffad9a4ea6cd8d15e8f43bea550848b46c 100644 (file)
@@ -346,6 +346,20 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
        dw_edma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr);
 }
 
+static void dw_edma_v0_sync_ll_data(struct dw_edma_chunk *chunk)
+{
+       /*
+        * In case of remote eDMA engine setup, the DW PCIe RP/EP internal
+        * configuration registers and application memory are normally accessed
+        * over different buses. Ensure LL-data reaches the memory before the
+        * doorbell register is toggled by issuing the dummy-read from the remote
+        * LL memory in a hope that the MRd TLP will return only after the
+        * last MWr TLP is completed
+        */
+       if (!(chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
+               readl(chunk->ll_region.vaddr.io);
+}
+
 static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
 {
        struct dw_edma_chan *chan = chunk->chan;
@@ -412,6 +426,9 @@ static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
                SET_CH_32(dw, chan->dir, chan->id, llp.msb,
                          upper_32_bits(chunk->ll_region.paddr));
        }
+
+       dw_edma_v0_sync_ll_data(chunk);
+
        /* Doorbell */
        SET_RW_32(dw, chan->dir, doorbell,
                  FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK, chan->id));
index 00b735a0202ab2e8e030910db2747c02be8bf75e..10e8f0715114fb5f08f135b4f2d592ce6c53f10c 100644 (file)
@@ -65,18 +65,12 @@ static void dw_hdma_v0_core_off(struct dw_edma *dw)
 
 static u16 dw_hdma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
 {
-       u32 num_ch = 0;
-       int id;
-
-       for (id = 0; id < HDMA_V0_MAX_NR_CH; id++) {
-               if (GET_CH_32(dw, id, dir, ch_en) & BIT(0))
-                       num_ch++;
-       }
-
-       if (num_ch > HDMA_V0_MAX_NR_CH)
-               num_ch = HDMA_V0_MAX_NR_CH;
-
-       return (u16)num_ch;
+       /*
+        * The HDMA IP have no way to know the number of hardware channels
+        * available, we set it to maximum channels and let the platform
+        * set the right number of channels.
+        */
+       return HDMA_V0_MAX_NR_CH;
 }
 
 static enum dma_status dw_hdma_v0_core_ch_status(struct dw_edma_chan *chan)
@@ -228,6 +222,20 @@ static void dw_hdma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
        dw_hdma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr);
 }
 
+static void dw_hdma_v0_sync_ll_data(struct dw_edma_chunk *chunk)
+{
+       /*
+        * In case of remote HDMA engine setup, the DW PCIe RP/EP internal
+        * configuration registers and application memory are normally accessed
+        * over different buses. Ensure LL-data reaches the memory before the
+        * doorbell register is toggled by issuing the dummy-read from the remote
+        * LL memory in a hope that the MRd TLP will return only after the
+        * last MWr TLP is completed
+        */
+       if (!(chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
+               readl(chunk->ll_region.vaddr.io);
+}
+
 static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
 {
        struct dw_edma_chan *chan = chunk->chan;
@@ -242,7 +250,9 @@ static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
                /* Interrupt enable&unmask - done, abort */
                tmp = GET_CH_32(dw, chan->dir, chan->id, int_setup) |
                      HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK |
-                     HDMA_V0_LOCAL_STOP_INT_EN | HDMA_V0_LOCAL_STOP_INT_EN;
+                     HDMA_V0_LOCAL_STOP_INT_EN | HDMA_V0_LOCAL_ABORT_INT_EN;
+               if (!(dw->chip->flags & DW_EDMA_CHIP_LOCAL))
+                       tmp |= HDMA_V0_REMOTE_STOP_INT_EN | HDMA_V0_REMOTE_ABORT_INT_EN;
                SET_CH_32(dw, chan->dir, chan->id, int_setup, tmp);
                /* Channel control */
                SET_CH_32(dw, chan->dir, chan->id, control1, HDMA_V0_LINKLIST_EN);
@@ -256,6 +266,9 @@ static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
        /* Set consumer cycle */
        SET_CH_32(dw, chan->dir, chan->id, cycle_sync,
                  HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
+
+       dw_hdma_v0_sync_ll_data(chunk);
+
        /* Doorbell */
        SET_CH_32(dw, chan->dir, chan->id, doorbell, HDMA_V0_DOORBELL_START);
 }
index a974abdf8aaf5ecd83eadd56f191a313ec37e9ff..eab5fd7177e545cab3f2217bd1a8add0d8dbb435 100644 (file)
@@ -15,7 +15,7 @@
 #define HDMA_V0_LOCAL_ABORT_INT_EN             BIT(6)
 #define HDMA_V0_REMOTE_ABORT_INT_EN            BIT(5)
 #define HDMA_V0_LOCAL_STOP_INT_EN              BIT(4)
-#define HDMA_V0_REMOTEL_STOP_INT_EN            BIT(3)
+#define HDMA_V0_REMOTE_STOP_INT_EN             BIT(3)
 #define HDMA_V0_ABORT_INT_MASK                 BIT(2)
 #define HDMA_V0_STOP_INT_MASK                  BIT(0)
 #define HDMA_V0_LINKLIST_EN                    BIT(0)
index b53f46245c377f05520c8275c95bf10c59be34d7..793f1a7ad5e343bbfe403c9e0ad28e891bd0d556 100644 (file)
@@ -503,7 +503,7 @@ void fsl_edma_fill_tcd(struct fsl_edma_chan *fsl_chan,
        if (fsl_chan->is_multi_fifo) {
                /* set mloff to support multiple fifo */
                burst = cfg->direction == DMA_DEV_TO_MEM ?
-                               cfg->src_addr_width : cfg->dst_addr_width;
+                               cfg->src_maxburst : cfg->dst_maxburst;
                nbytes |= EDMA_V3_TCD_NBYTES_MLOFF(-(burst * 4));
                /* enable DMLOE/SMLOE */
                if (cfg->direction == DMA_MEM_TO_DEV) {
index bb5221158a7702379322392a46a1ebfb4de0f476..f5e216b157c75ff2215d7c74cd1d9febad47031c 100644 (file)
@@ -30,8 +30,9 @@
 #define EDMA_TCD_ATTR_SSIZE(x)         (((x) & GENMASK(2, 0)) << 8)
 #define EDMA_TCD_ATTR_SMOD(x)          (((x) & GENMASK(4, 0)) << 11)
 
-#define EDMA_TCD_CITER_CITER(x)                ((x) & GENMASK(14, 0))
-#define EDMA_TCD_BITER_BITER(x)                ((x) & GENMASK(14, 0))
+#define EDMA_TCD_ITER_MASK             GENMASK(14, 0)
+#define EDMA_TCD_CITER_CITER(x)                ((x) & EDMA_TCD_ITER_MASK)
+#define EDMA_TCD_BITER_BITER(x)                ((x) & EDMA_TCD_ITER_MASK)
 
 #define EDMA_TCD_CSR_START             BIT(0)
 #define EDMA_TCD_CSR_INT_MAJOR         BIT(1)
index 45cc419b1b4acbe87c12c3daaccafce73f8de1ba..d36e28b9c767ae7ebb44bc9e87de7bbc0363f926 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <dt-bindings/dma/fsl-edma.h>
+#include <linux/bitfield.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/clk.h>
@@ -582,7 +583,8 @@ static int fsl_edma_probe(struct platform_device *pdev)
                                        DMAENGINE_ALIGN_32_BYTES;
 
        /* Per worst case 'nbytes = 1' take CITER as the max_seg_size */
-       dma_set_max_seg_size(fsl_edma->dma_dev.dev, 0x3fff);
+       dma_set_max_seg_size(fsl_edma->dma_dev.dev,
+                            FIELD_GET(EDMA_TCD_ITER_MASK, EDMA_TCD_ITER_MASK));
 
        fsl_edma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
index f405c77060ad8b3508e7c75bee09968e1ae9bc78..5005e138fc239bf23a8a888c90e5ad720f697d3d 100644 (file)
 #define FSL_QDMA_CMD_WTHROTL_OFFSET    20
 #define FSL_QDMA_CMD_DSEN_OFFSET       19
 #define FSL_QDMA_CMD_LWC_OFFSET                16
+#define FSL_QDMA_CMD_PF                        BIT(17)
 
 /* Field definition for Descriptor status */
 #define QDMA_CCDF_STATUS_RTE           BIT(5)
@@ -160,6 +161,10 @@ struct fsl_qdma_format {
                        u8 __reserved1[2];
                        u8 cfg8b_w1;
                } __packed;
+               struct {
+                       __le32 __reserved2;
+                       __le32 cmd;
+               } __packed;
                __le64 data;
        };
 } __packed;
@@ -354,7 +359,6 @@ static void fsl_qdma_free_chan_resources(struct dma_chan *chan)
 static void fsl_qdma_comp_fill_memcpy(struct fsl_qdma_comp *fsl_comp,
                                      dma_addr_t dst, dma_addr_t src, u32 len)
 {
-       u32 cmd;
        struct fsl_qdma_format *sdf, *ddf;
        struct fsl_qdma_format *ccdf, *csgf_desc, *csgf_src, *csgf_dest;
 
@@ -383,14 +387,11 @@ static void fsl_qdma_comp_fill_memcpy(struct fsl_qdma_comp *fsl_comp,
        /* This entry is the last entry. */
        qdma_csgf_set_f(csgf_dest, len);
        /* Descriptor Buffer */
-       cmd = cpu_to_le32(FSL_QDMA_CMD_RWTTYPE <<
-                         FSL_QDMA_CMD_RWTTYPE_OFFSET);
-       sdf->data = QDMA_SDDF_CMD(cmd);
-
-       cmd = cpu_to_le32(FSL_QDMA_CMD_RWTTYPE <<
-                         FSL_QDMA_CMD_RWTTYPE_OFFSET);
-       cmd |= cpu_to_le32(FSL_QDMA_CMD_LWC << FSL_QDMA_CMD_LWC_OFFSET);
-       ddf->data = QDMA_SDDF_CMD(cmd);
+       sdf->cmd = cpu_to_le32((FSL_QDMA_CMD_RWTTYPE << FSL_QDMA_CMD_RWTTYPE_OFFSET) |
+                              FSL_QDMA_CMD_PF);
+
+       ddf->cmd = cpu_to_le32((FSL_QDMA_CMD_RWTTYPE << FSL_QDMA_CMD_RWTTYPE_OFFSET) |
+                              (FSL_QDMA_CMD_LWC << FSL_QDMA_CMD_LWC_OFFSET));
 }
 
 /*
@@ -624,7 +625,7 @@ static int fsl_qdma_halt(struct fsl_qdma_engine *fsl_qdma)
 
 static int
 fsl_qdma_queue_transfer_complete(struct fsl_qdma_engine *fsl_qdma,
-                                void *block,
+                                __iomem void *block,
                                 int id)
 {
        bool duplicate;
@@ -1196,10 +1197,6 @@ static int fsl_qdma_probe(struct platform_device *pdev)
        if (!fsl_qdma->queue)
                return -ENOMEM;
 
-       ret = fsl_qdma_irq_init(pdev, fsl_qdma);
-       if (ret)
-               return ret;
-
        fsl_qdma->irq_base = platform_get_irq_byname(pdev, "qdma-queue0");
        if (fsl_qdma->irq_base < 0)
                return fsl_qdma->irq_base;
@@ -1238,16 +1235,19 @@ static int fsl_qdma_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, fsl_qdma);
 
-       ret = dma_async_device_register(&fsl_qdma->dma_dev);
+       ret = fsl_qdma_reg_init(fsl_qdma);
        if (ret) {
-               dev_err(&pdev->dev,
-                       "Can't register NXP Layerscape qDMA engine.\n");
+               dev_err(&pdev->dev, "Can't Initialize the qDMA engine.\n");
                return ret;
        }
 
-       ret = fsl_qdma_reg_init(fsl_qdma);
+       ret = fsl_qdma_irq_init(pdev, fsl_qdma);
+       if (ret)
+               return ret;
+
+       ret = dma_async_device_register(&fsl_qdma->dma_dev);
        if (ret) {
-               dev_err(&pdev->dev, "Can't Initialize the qDMA engine.\n");
+               dev_err(&pdev->dev, "Can't register NXP Layerscape qDMA engine.\n");
                return ret;
        }
 
index 77f8885cf4075acfd3ff535b7e09519a8df41c70..e5a94a93a3cc4e6da66aca64cc2174b20d80a7bb 100644 (file)
@@ -345,7 +345,7 @@ static void idxd_cdev_evl_drain_pasid(struct idxd_wq *wq, u32 pasid)
        spin_lock(&evl->lock);
        status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET);
        t = status.tail;
-       h = evl->head;
+       h = status.head;
        size = evl->size;
 
        while (h != t) {
index 9cfbd9b14c4c43306326e857b8b3d982c612314f..f3f25ee676f30eb283989586d458a5c8b8c01f9f 100644 (file)
@@ -68,9 +68,9 @@ static int debugfs_evl_show(struct seq_file *s, void *d)
 
        spin_lock(&evl->lock);
 
-       h = evl->head;
        evl_status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET);
        t = evl_status.tail;
+       h = evl_status.head;
        evl_size = evl->size;
 
        seq_printf(s, "Event Log head %u tail %u interrupt pending %u\n\n",
index 47de3f93ff1e9a72eb718b07c05213d19ec1d23b..d0f5db6cf1eda103db09c31449cf3a58d58b7971 100644 (file)
@@ -300,7 +300,6 @@ struct idxd_evl {
        unsigned int log_size;
        /* The number of entries in the event log. */
        u16 size;
-       u16 head;
        unsigned long *bmap;
        bool batch_fail[IDXD_MAX_BATCH_IDENT];
 };
index 14df1f1347a8dd83b82263438acf3fe613513564..4954adc6bb609e508c510daf630f1077191fd2c7 100644 (file)
@@ -343,7 +343,9 @@ static void idxd_cleanup_internals(struct idxd_device *idxd)
 static int idxd_init_evl(struct idxd_device *idxd)
 {
        struct device *dev = &idxd->pdev->dev;
+       unsigned int evl_cache_size;
        struct idxd_evl *evl;
+       const char *idxd_name;
 
        if (idxd->hw.gen_cap.evl_support == 0)
                return 0;
@@ -355,9 +357,16 @@ static int idxd_init_evl(struct idxd_device *idxd)
        spin_lock_init(&evl->lock);
        evl->size = IDXD_EVL_SIZE_MIN;
 
-       idxd->evl_cache = kmem_cache_create(dev_name(idxd_confdev(idxd)),
-                                           sizeof(struct idxd_evl_fault) + evl_ent_size(idxd),
-                                           0, 0, NULL);
+       idxd_name = dev_name(idxd_confdev(idxd));
+       evl_cache_size = sizeof(struct idxd_evl_fault) + evl_ent_size(idxd);
+       /*
+        * Since completion record in evl_cache will be copied to user
+        * when handling completion record page fault, need to create
+        * the cache suitable for user copy.
+        */
+       idxd->evl_cache = kmem_cache_create_usercopy(idxd_name, evl_cache_size,
+                                                    0, 0, 0, evl_cache_size,
+                                                    NULL);
        if (!idxd->evl_cache) {
                kfree(evl);
                return -ENOMEM;
index c8a0aa874b1153f845278e03e9e5153cc487c0fb..348aa21389a9fceb4cd522579c8f8a9963e72ef3 100644 (file)
@@ -367,9 +367,9 @@ static void process_evl_entries(struct idxd_device *idxd)
        /* Clear interrupt pending bit */
        iowrite32(evl_status.bits_upper32,
                  idxd->reg_base + IDXD_EVLSTATUS_OFFSET + sizeof(u32));
-       h = evl->head;
        evl_status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET);
        t = evl_status.tail;
+       h = evl_status.head;
        size = idxd->evl->size;
 
        while (h != t) {
@@ -378,7 +378,6 @@ static void process_evl_entries(struct idxd_device *idxd)
                h = (h + 1) % size;
        }
 
-       evl->head = h;
        evl_status.head = h;
        iowrite32(evl_status.bits_lower32, idxd->reg_base + IDXD_EVLSTATUS_OFFSET);
        spin_unlock(&evl->lock);
index 1ebfbe88e7335af1f9ba4894e2e2ffa2e85becf2..97ebc791a30bd61af42f347f39e08899bd2c6184 100644 (file)
@@ -747,8 +747,8 @@ static int mv_xor_v2_probe(struct platform_device *pdev)
        if (IS_ERR(xor_dev->clk))
                return PTR_ERR(xor_dev->clk);
 
-       ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1,
-                                            mv_xor_v2_set_msi_msg);
+       ret = platform_device_msi_init_and_alloc_irqs(&pdev->dev, 1,
+                                                     mv_xor_v2_set_msi_msg);
        if (ret)
                return ret;
 
@@ -851,7 +851,7 @@ free_hw_desq:
                          xor_dev->desc_size * MV_XOR_V2_DESC_NUM,
                          xor_dev->hw_desq_virt, xor_dev->hw_desq);
 free_msi_irqs:
-       platform_msi_domain_free_irqs(&pdev->dev);
+       platform_device_msi_free_irqs_all(&pdev->dev);
        return ret;
 }
 
@@ -867,7 +867,7 @@ static void mv_xor_v2_remove(struct platform_device *pdev)
 
        devm_free_irq(&pdev->dev, xor_dev->irq, xor_dev);
 
-       platform_msi_domain_free_irqs(&pdev->dev);
+       platform_device_msi_free_irqs_all(&pdev->dev);
 
        tasklet_kill(&xor_dev->irq_tasklet);
 }
index 1aa65e5de0f3ad9bc0fa0907ebda8e8c0fe6d0ab..f792407348077dd9fe481cfdec6577a701493487 100644 (file)
@@ -385,8 +385,6 @@ int pt_dmaengine_register(struct pt_device *pt)
        chan->vc.desc_free = pt_do_cleanup;
        vchan_init(&chan->vc, dma_dev);
 
-       dma_set_mask_and_coherent(pt->dev, DMA_BIT_MASK(64));
-
        ret = dma_async_device_register(dma_dev);
        if (ret)
                goto err_reg;
index d63b93dc7047643c00b5381df936715bc4c56369..202ac95227cbe8495871cfa0e1114e7a31c558c7 100644 (file)
@@ -696,7 +696,7 @@ static void hidma_free_msis(struct hidma_dev *dmadev)
                        devm_free_irq(dev, virq, &dmadev->lldev);
        }
 
-       platform_msi_domain_free_irqs(dev);
+       platform_device_msi_free_irqs_all(dev);
 #endif
 }
 
@@ -706,8 +706,8 @@ static int hidma_request_msi(struct hidma_dev *dmadev,
 #ifdef CONFIG_GENERIC_MSI_IRQ
        int rc, i, virq;
 
-       rc = platform_msi_domain_alloc_irqs(&pdev->dev, HIDMA_MSI_INTS,
-                                           hidma_write_msi_msg);
+       rc = platform_device_msi_init_and_alloc_irqs(&pdev->dev, HIDMA_MSI_INTS,
+                                                    hidma_write_msi_msg);
        if (rc)
                return rc;
 
index 5152bd1b0daf599869195e81805fbb2709dbe6b4..7f686d179fc93c85f684d051595a1d4c1934bdbb 100644 (file)
@@ -508,6 +508,26 @@ err_pin_prop:
        return ERR_PTR(ret);
 }
 
+static void dpll_netdev_pin_assign(struct net_device *dev, struct dpll_pin *dpll_pin)
+{
+       rtnl_lock();
+       rcu_assign_pointer(dev->dpll_pin, dpll_pin);
+       rtnl_unlock();
+}
+
+void dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)
+{
+       WARN_ON(!dpll_pin);
+       dpll_netdev_pin_assign(dev, dpll_pin);
+}
+EXPORT_SYMBOL(dpll_netdev_pin_set);
+
+void dpll_netdev_pin_clear(struct net_device *dev)
+{
+       dpll_netdev_pin_assign(dev, NULL);
+}
+EXPORT_SYMBOL(dpll_netdev_pin_clear);
+
 /**
  * dpll_pin_get - find existing or create new dpll pin
  * @clock_id: clock_id of creator
@@ -564,7 +584,7 @@ void dpll_pin_put(struct dpll_pin *pin)
                xa_destroy(&pin->parent_refs);
                xa_erase(&dpll_pin_xa, pin->id);
                dpll_pin_prop_free(&pin->prop);
-               kfree(pin);
+               kfree_rcu(pin, rcu);
        }
        mutex_unlock(&dpll_lock);
 }
index 717f715015c742238d5585fddc5cd267fbb0db9f..2b6d8ef1cdf36cff24328e497c49d667659dd0e6 100644 (file)
@@ -47,6 +47,7 @@ struct dpll_device {
  * @prop:              pin properties copied from the registerer
  * @rclk_dev_name:     holds name of device when pin can recover clock from it
  * @refcount:          refcount
+ * @rcu:               rcu_head for kfree_rcu()
  **/
 struct dpll_pin {
        u32 id;
@@ -57,6 +58,7 @@ struct dpll_pin {
        struct xarray parent_refs;
        struct dpll_pin_properties prop;
        refcount_t refcount;
+       struct rcu_head rcu;
 };
 
 /**
index 314bb377546519ef25987b2e6f77827f590fe5fe..b57355e0c214bb3badca414c7d127d79a772bcdb 100644 (file)
@@ -8,6 +8,7 @@
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/netdevice.h>
 #include <net/genetlink.h>
 #include "dpll_core.h"
 #include "dpll_netlink.h"
@@ -47,18 +48,6 @@ dpll_msg_add_dev_parent_handle(struct sk_buff *msg, u32 id)
        return 0;
 }
 
-/**
- * dpll_msg_pin_handle_size - get size of pin handle attribute for given pin
- * @pin: pin pointer
- *
- * Return: byte size of pin handle attribute for given pin.
- */
-size_t dpll_msg_pin_handle_size(struct dpll_pin *pin)
-{
-       return pin ? nla_total_size(4) : 0; /* DPLL_A_PIN_ID */
-}
-EXPORT_SYMBOL_GPL(dpll_msg_pin_handle_size);
-
 /**
  * dpll_msg_add_pin_handle - attach pin handle attribute to a given message
  * @msg: pointer to sk_buff message to attach a pin handle
@@ -68,7 +57,7 @@ EXPORT_SYMBOL_GPL(dpll_msg_pin_handle_size);
  * * 0 - success
  * * -EMSGSIZE - no space in message to attach pin handle
  */
-int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin)
+static int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin)
 {
        if (!pin)
                return 0;
@@ -76,7 +65,28 @@ int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin)
                return -EMSGSIZE;
        return 0;
 }
-EXPORT_SYMBOL_GPL(dpll_msg_add_pin_handle);
+
+static struct dpll_pin *dpll_netdev_pin(const struct net_device *dev)
+{
+       return rcu_dereference_rtnl(dev->dpll_pin);
+}
+
+/**
+ * dpll_netdev_pin_handle_size - get size of pin handle attribute of a netdev
+ * @dev: netdev from which to get the pin
+ *
+ * Return: byte size of pin handle attribute, or 0 if @dev has no pin.
+ */
+size_t dpll_netdev_pin_handle_size(const struct net_device *dev)
+{
+       return dpll_netdev_pin(dev) ? nla_total_size(4) : 0; /* DPLL_A_PIN_ID */
+}
+
+int dpll_netdev_add_pin_handle(struct sk_buff *msg,
+                              const struct net_device *dev)
+{
+       return dpll_msg_add_pin_handle(msg, dpll_netdev_pin(dev));
+}
 
 static int
 dpll_msg_add_mode(struct sk_buff *msg, struct dpll_device *dpll,
@@ -1199,6 +1209,7 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
        unsigned long i;
        int ret = 0;
 
+       mutex_lock(&dpll_lock);
        xa_for_each_marked_start(&dpll_pin_xa, i, pin, DPLL_REGISTERED,
                                 ctx->idx) {
                if (!dpll_pin_available(pin))
@@ -1218,6 +1229,8 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
                }
                genlmsg_end(skb, hdr);
        }
+       mutex_unlock(&dpll_lock);
+
        if (ret == -EMSGSIZE) {
                ctx->idx = i;
                return skb->len;
@@ -1373,6 +1386,7 @@ int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
        unsigned long i;
        int ret = 0;
 
+       mutex_lock(&dpll_lock);
        xa_for_each_marked_start(&dpll_device_xa, i, dpll, DPLL_REGISTERED,
                                 ctx->idx) {
                hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
@@ -1389,6 +1403,8 @@ int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
                }
                genlmsg_end(skb, hdr);
        }
+       mutex_unlock(&dpll_lock);
+
        if (ret == -EMSGSIZE) {
                ctx->idx = i;
                return skb->len;
@@ -1439,20 +1455,6 @@ dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
        mutex_unlock(&dpll_lock);
 }
 
-int dpll_lock_dumpit(struct netlink_callback *cb)
-{
-       mutex_lock(&dpll_lock);
-
-       return 0;
-}
-
-int dpll_unlock_dumpit(struct netlink_callback *cb)
-{
-       mutex_unlock(&dpll_lock);
-
-       return 0;
-}
-
 int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
                      struct genl_info *info)
 {
index eaee5be7aa642a9359c0b438e7157eec830b6519..1e95f5397cfce65270fbc88d8916a24386258047 100644 (file)
@@ -95,9 +95,7 @@ static const struct genl_split_ops dpll_nl_ops[] = {
        },
        {
                .cmd    = DPLL_CMD_DEVICE_GET,
-               .start  = dpll_lock_dumpit,
                .dumpit = dpll_nl_device_get_dumpit,
-               .done   = dpll_unlock_dumpit,
                .flags  = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
        },
        {
@@ -129,9 +127,7 @@ static const struct genl_split_ops dpll_nl_ops[] = {
        },
        {
                .cmd            = DPLL_CMD_PIN_GET,
-               .start          = dpll_lock_dumpit,
                .dumpit         = dpll_nl_pin_get_dumpit,
-               .done           = dpll_unlock_dumpit,
                .policy         = dpll_pin_get_dump_nl_policy,
                .maxattr        = DPLL_A_PIN_ID,
                .flags          = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
index 92d4c9c4f788dc1b36c7b076a980afd2903aba68..f491262bee4f0c16e97624353bef6a4938b761aa 100644 (file)
@@ -30,8 +30,6 @@ dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
 void
 dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
                   struct genl_info *info);
-int dpll_lock_dumpit(struct netlink_callback *cb);
-int dpll_unlock_dumpit(struct netlink_callback *cb);
 
 int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info);
 int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info);
index 5a7f3fabee22d929ef4e016363b1712a6adaf8e4..16c8de5050e592505ebeacfa85949e05474685ef 100644 (file)
@@ -78,6 +78,7 @@ config EDAC_GHES
 config EDAC_AMD64
        tristate "AMD64 (Opteron, Athlon64)"
        depends on AMD_NB && EDAC_DECODE_MCE
+       imply AMD_ATL
        help
          Support for error detection and correction of DRAM ECC errors on
          the AMD64 families (>= K8) of memory controllers.
index 537b9987a431c23c263fd59631316cf3780b3e72..1f3520d7686135ad2e2ba6f38b289fff9810fe08 100644 (file)
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
+#include <linux/ras.h>
 #include "amd64_edac.h"
 #include <asm/amd_nb.h>
 
@@ -1051,281 +1052,6 @@ static int fixup_node_id(int node_id, struct mce *m)
        return nid - gpu_node_map.base_node_id + 1;
 }
 
-/* Protect the PCI config register pairs used for DF indirect access. */
-static DEFINE_MUTEX(df_indirect_mutex);
-
-/*
- * Data Fabric Indirect Access uses FICAA/FICAD.
- *
- * Fabric Indirect Configuration Access Address (FICAA): Constructed based
- * on the device's Instance Id and the PCI function and register offset of
- * the desired register.
- *
- * Fabric Indirect Configuration Access Data (FICAD): There are FICAD LO
- * and FICAD HI registers but so far we only need the LO register.
- *
- * Use Instance Id 0xFF to indicate a broadcast read.
- */
-#define DF_BROADCAST   0xFF
-static int __df_indirect_read(u16 node, u8 func, u16 reg, u8 instance_id, u32 *lo)
-{
-       struct pci_dev *F4;
-       u32 ficaa;
-       int err = -ENODEV;
-
-       if (node >= amd_nb_num())
-               goto out;
-
-       F4 = node_to_amd_nb(node)->link;
-       if (!F4)
-               goto out;
-
-       ficaa  = (instance_id == DF_BROADCAST) ? 0 : 1;
-       ficaa |= reg & 0x3FC;
-       ficaa |= (func & 0x7) << 11;
-       ficaa |= instance_id << 16;
-
-       mutex_lock(&df_indirect_mutex);
-
-       err = pci_write_config_dword(F4, 0x5C, ficaa);
-       if (err) {
-               pr_warn("Error writing DF Indirect FICAA, FICAA=0x%x\n", ficaa);
-               goto out_unlock;
-       }
-
-       err = pci_read_config_dword(F4, 0x98, lo);
-       if (err)
-               pr_warn("Error reading DF Indirect FICAD LO, FICAA=0x%x.\n", ficaa);
-
-out_unlock:
-       mutex_unlock(&df_indirect_mutex);
-
-out:
-       return err;
-}
-
-static int df_indirect_read_instance(u16 node, u8 func, u16 reg, u8 instance_id, u32 *lo)
-{
-       return __df_indirect_read(node, func, reg, instance_id, lo);
-}
-
-static int df_indirect_read_broadcast(u16 node, u8 func, u16 reg, u32 *lo)
-{
-       return __df_indirect_read(node, func, reg, DF_BROADCAST, lo);
-}
-
-struct addr_ctx {
-       u64 ret_addr;
-       u32 tmp;
-       u16 nid;
-       u8 inst_id;
-};
-
-static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr)
-{
-       u64 dram_base_addr, dram_limit_addr, dram_hole_base;
-
-       u8 die_id_shift, die_id_mask, socket_id_shift, socket_id_mask;
-       u8 intlv_num_dies, intlv_num_chan, intlv_num_sockets;
-       u8 intlv_addr_sel, intlv_addr_bit;
-       u8 num_intlv_bits, hashed_bit;
-       u8 lgcy_mmio_hole_en, base = 0;
-       u8 cs_mask, cs_id = 0;
-       bool hash_enabled = false;
-
-       struct addr_ctx ctx;
-
-       memset(&ctx, 0, sizeof(ctx));
-
-       /* Start from the normalized address */
-       ctx.ret_addr = norm_addr;
-
-       ctx.nid = nid;
-       ctx.inst_id = umc;
-
-       /* Read D18F0x1B4 (DramOffset), check if base 1 is used. */
-       if (df_indirect_read_instance(nid, 0, 0x1B4, umc, &ctx.tmp))
-               goto out_err;
-
-       /* Remove HiAddrOffset from normalized address, if enabled: */
-       if (ctx.tmp & BIT(0)) {
-               u64 hi_addr_offset = (ctx.tmp & GENMASK_ULL(31, 20)) << 8;
-
-               if (norm_addr >= hi_addr_offset) {
-                       ctx.ret_addr -= hi_addr_offset;
-                       base = 1;
-               }
-       }
-
-       /* Read D18F0x110 (DramBaseAddress). */
-       if (df_indirect_read_instance(nid, 0, 0x110 + (8 * base), umc, &ctx.tmp))
-               goto out_err;
-
-       /* Check if address range is valid. */
-       if (!(ctx.tmp & BIT(0))) {
-               pr_err("%s: Invalid DramBaseAddress range: 0x%x.\n",
-                       __func__, ctx.tmp);
-               goto out_err;
-       }
-
-       lgcy_mmio_hole_en = ctx.tmp & BIT(1);
-       intlv_num_chan    = (ctx.tmp >> 4) & 0xF;
-       intlv_addr_sel    = (ctx.tmp >> 8) & 0x7;
-       dram_base_addr    = (ctx.tmp & GENMASK_ULL(31, 12)) << 16;
-
-       /* {0, 1, 2, 3} map to address bits {8, 9, 10, 11} respectively */
-       if (intlv_addr_sel > 3) {
-               pr_err("%s: Invalid interleave address select %d.\n",
-                       __func__, intlv_addr_sel);
-               goto out_err;
-       }
-
-       /* Read D18F0x114 (DramLimitAddress). */
-       if (df_indirect_read_instance(nid, 0, 0x114 + (8 * base), umc, &ctx.tmp))
-               goto out_err;
-
-       intlv_num_sockets = (ctx.tmp >> 8) & 0x1;
-       intlv_num_dies    = (ctx.tmp >> 10) & 0x3;
-       dram_limit_addr   = ((ctx.tmp & GENMASK_ULL(31, 12)) << 16) | GENMASK_ULL(27, 0);
-
-       intlv_addr_bit = intlv_addr_sel + 8;
-
-       /* Re-use intlv_num_chan by setting it equal to log2(#channels) */
-       switch (intlv_num_chan) {
-       case 0: intlv_num_chan = 0; break;
-       case 1: intlv_num_chan = 1; break;
-       case 3: intlv_num_chan = 2; break;
-       case 5: intlv_num_chan = 3; break;
-       case 7: intlv_num_chan = 4; break;
-
-       case 8: intlv_num_chan = 1;
-               hash_enabled = true;
-               break;
-       default:
-               pr_err("%s: Invalid number of interleaved channels %d.\n",
-                       __func__, intlv_num_chan);
-               goto out_err;
-       }
-
-       num_intlv_bits = intlv_num_chan;
-
-       if (intlv_num_dies > 2) {
-               pr_err("%s: Invalid number of interleaved nodes/dies %d.\n",
-                       __func__, intlv_num_dies);
-               goto out_err;
-       }
-
-       num_intlv_bits += intlv_num_dies;
-
-       /* Add a bit if sockets are interleaved. */
-       num_intlv_bits += intlv_num_sockets;
-
-       /* Assert num_intlv_bits <= 4 */
-       if (num_intlv_bits > 4) {
-               pr_err("%s: Invalid interleave bits %d.\n",
-                       __func__, num_intlv_bits);
-               goto out_err;
-       }
-
-       if (num_intlv_bits > 0) {
-               u64 temp_addr_x, temp_addr_i, temp_addr_y;
-               u8 die_id_bit, sock_id_bit, cs_fabric_id;
-
-               /*
-                * Read FabricBlockInstanceInformation3_CS[BlockFabricID].
-                * This is the fabric id for this coherent slave. Use
-                * umc/channel# as instance id of the coherent slave
-                * for FICAA.
-                */
-               if (df_indirect_read_instance(nid, 0, 0x50, umc, &ctx.tmp))
-                       goto out_err;
-
-               cs_fabric_id = (ctx.tmp >> 8) & 0xFF;
-               die_id_bit   = 0;
-
-               /* If interleaved over more than 1 channel: */
-               if (intlv_num_chan) {
-                       die_id_bit = intlv_num_chan;
-                       cs_mask    = (1 << die_id_bit) - 1;
-                       cs_id      = cs_fabric_id & cs_mask;
-               }
-
-               sock_id_bit = die_id_bit;
-
-               /* Read D18F1x208 (SystemFabricIdMask). */
-               if (intlv_num_dies || intlv_num_sockets)
-                       if (df_indirect_read_broadcast(nid, 1, 0x208, &ctx.tmp))
-                               goto out_err;
-
-               /* If interleaved over more than 1 die. */
-               if (intlv_num_dies) {
-                       sock_id_bit  = die_id_bit + intlv_num_dies;
-                       die_id_shift = (ctx.tmp >> 24) & 0xF;
-                       die_id_mask  = (ctx.tmp >> 8) & 0xFF;
-
-                       cs_id |= ((cs_fabric_id & die_id_mask) >> die_id_shift) << die_id_bit;
-               }
-
-               /* If interleaved over more than 1 socket. */
-               if (intlv_num_sockets) {
-                       socket_id_shift = (ctx.tmp >> 28) & 0xF;
-                       socket_id_mask  = (ctx.tmp >> 16) & 0xFF;
-
-                       cs_id |= ((cs_fabric_id & socket_id_mask) >> socket_id_shift) << sock_id_bit;
-               }
-
-               /*
-                * The pre-interleaved address consists of XXXXXXIIIYYYYY
-                * where III is the ID for this CS, and XXXXXXYYYYY are the
-                * address bits from the post-interleaved address.
-                * "num_intlv_bits" has been calculated to tell us how many "I"
-                * bits there are. "intlv_addr_bit" tells us how many "Y" bits
-                * there are (where "I" starts).
-                */
-               temp_addr_y = ctx.ret_addr & GENMASK_ULL(intlv_addr_bit - 1, 0);
-               temp_addr_i = (cs_id << intlv_addr_bit);
-               temp_addr_x = (ctx.ret_addr & GENMASK_ULL(63, intlv_addr_bit)) << num_intlv_bits;
-               ctx.ret_addr    = temp_addr_x | temp_addr_i | temp_addr_y;
-       }
-
-       /* Add dram base address */
-       ctx.ret_addr += dram_base_addr;
-
-       /* If legacy MMIO hole enabled */
-       if (lgcy_mmio_hole_en) {
-               if (df_indirect_read_broadcast(nid, 0, 0x104, &ctx.tmp))
-                       goto out_err;
-
-               dram_hole_base = ctx.tmp & GENMASK(31, 24);
-               if (ctx.ret_addr >= dram_hole_base)
-                       ctx.ret_addr += (BIT_ULL(32) - dram_hole_base);
-       }
-
-       if (hash_enabled) {
-               /* Save some parentheses and grab ls-bit at the end. */
-               hashed_bit =    (ctx.ret_addr >> 12) ^
-                               (ctx.ret_addr >> 18) ^
-                               (ctx.ret_addr >> 21) ^
-                               (ctx.ret_addr >> 30) ^
-                               cs_id;
-
-               hashed_bit &= BIT(0);
-
-               if (hashed_bit != ((ctx.ret_addr >> intlv_addr_bit) & BIT(0)))
-                       ctx.ret_addr ^= BIT(intlv_addr_bit);
-       }
-
-       /* Is calculated system address is above DRAM limit address? */
-       if (ctx.ret_addr > dram_limit_addr)
-               goto out_err;
-
-       *sys_addr = ctx.ret_addr;
-       return 0;
-
-out_err:
-       return -EINVAL;
-}
-
 static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
 
 /*
@@ -1915,7 +1641,7 @@ ddr3:
 /* On F10h and later ErrAddr is MC4_ADDR[47:1] */
 static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)
 {
-       u16 mce_nid = topology_die_id(m->extcpu);
+       u16 mce_nid = topology_amd_node_id(m->extcpu);
        struct mem_ctl_info *mci;
        u8 start_bit = 1;
        u8 end_bit   = 47;
@@ -3073,9 +2799,10 @@ static void decode_umc_error(int node_id, struct mce *m)
 {
        u8 ecc_type = (m->status >> 45) & 0x3;
        struct mem_ctl_info *mci;
+       unsigned long sys_addr;
        struct amd64_pvt *pvt;
+       struct atl_err a_err;
        struct err_info err;
-       u64 sys_addr;
 
        node_id = fixup_node_id(node_id, m);
 
@@ -3106,7 +2833,12 @@ static void decode_umc_error(int node_id, struct mce *m)
 
        pvt->ops->get_err_info(m, &err);
 
-       if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) {
+       a_err.addr = m->addr;
+       a_err.ipid = m->ipid;
+       a_err.cpu  = m->extcpu;
+
+       sys_addr = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
+       if (IS_ERR_VALUE(sys_addr)) {
                err.err_code = ERR_NORM_ADDR;
                goto log_error;
        }
@@ -3446,7 +3178,7 @@ static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
        int cpu;
 
        for_each_online_cpu(cpu)
-               if (topology_die_id(cpu) == nid)
+               if (topology_amd_node_id(cpu) == nid)
                        cpumask_set_cpu(cpu, mask);
 }
 
index 2b83d6de9352be81a21e65f5abcaca0cca2b6950..3fd22a1eb1a965362b3422dfbe81f3af7a7a36ff 100644 (file)
@@ -951,6 +951,7 @@ static const struct x86_cpu_id i10nm_cpuids[] = {
        X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(EMERALDRAPIDS_X,   X86_STEPPINGS(0x0, 0xf), &spr_cfg),
        X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(GRANITERAPIDS_X,   X86_STEPPINGS(0x0, 0xf), &gnr_cfg),
        X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ATOM_CRESTMONT_X,  X86_STEPPINGS(0x0, 0xf), &gnr_cfg),
+       X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ATOM_CRESTMONT,    X86_STEPPINGS(0x0, 0xf), &gnr_cfg),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids);
index 2b0ecdeba5cdc91f9645f329c55264072d5c02da..cdd8480e736877f77b290d0f6dfddd12a88f88d9 100644 (file)
@@ -238,6 +238,7 @@ static struct work_struct ecclog_work;
 #define DID_ADL_N_SKU9 0x4678
 #define DID_ADL_N_SKU10        0x4679
 #define DID_ADL_N_SKU11        0x467c
+#define DID_ADL_N_SKU12        0x4632
 
 /* Compute die IDs for Raptor Lake-P with IBECC */
 #define DID_RPL_P_SKU1 0xa706
@@ -583,6 +584,7 @@ static const struct pci_device_id igen6_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, DID_ADL_N_SKU9), (kernel_ulong_t)&adl_n_cfg },
        { PCI_VDEVICE(INTEL, DID_ADL_N_SKU10), (kernel_ulong_t)&adl_n_cfg },
        { PCI_VDEVICE(INTEL, DID_ADL_N_SKU11), (kernel_ulong_t)&adl_n_cfg },
+       { PCI_VDEVICE(INTEL, DID_ADL_N_SKU12), (kernel_ulong_t)&adl_n_cfg },
        { PCI_VDEVICE(INTEL, DID_RPL_P_SKU1), (kernel_ulong_t)&rpl_p_cfg },
        { PCI_VDEVICE(INTEL, DID_RPL_P_SKU2), (kernel_ulong_t)&rpl_p_cfg },
        { PCI_VDEVICE(INTEL, DID_RPL_P_SKU3), (kernel_ulong_t)&rpl_p_cfg },
index ec8b6c9fedfddf926692802a268155a5e27effad..8130c3dc64da56470ac60015897787a12005c5fc 100644 (file)
@@ -584,7 +584,7 @@ static void decode_mc3_mce(struct mce *m)
 static void decode_mc4_mce(struct mce *m)
 {
        unsigned int fam = x86_family(m->cpuid);
-       int node_id = topology_die_id(m->extcpu);
+       int node_id = topology_amd_node_id(m->extcpu);
        u16 ec = EC(m->status);
        u8 xec = XEC(m->status, 0x1f);
        u8 offset = 0;
@@ -746,7 +746,7 @@ static void decode_smca_error(struct mce *m)
 
        if ((bank_type == SMCA_UMC || bank_type == SMCA_UMC_V2) &&
            xec == 0 && decode_dram_ecc)
-               decode_dram_ecc(topology_die_id(m->extcpu), m);
+               decode_dram_ecc(topology_amd_node_id(m->extcpu), m);
 }
 
 static inline void amd_decode_err_code(u16 ec)
index 709babce43ba0265493969337a2cbf0e65be0d4d..5527055b09641c6f36ec4889b235435b7a7fcac0 100644 (file)
@@ -1324,11 +1324,9 @@ static int mc_probe(struct platform_device *pdev)
        struct synps_edac_priv *priv;
        struct mem_ctl_info *mci;
        void __iomem *baseaddr;
-       struct resource *res;
        int rc;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       baseaddr = devm_ioremap_resource(&pdev->dev, res);
+       baseaddr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(baseaddr))
                return PTR_ERR(baseaddr);
 
index 62caf454b567079e0962e327c5f9eae6ec85f3d5..1688a5050f63a4e2754aa3b49974dd6f9bc57fa7 100644 (file)
 
 #define ECCW0_FLIP_CTRL                                0x109C
 #define ECCW0_FLIP0_OFFSET                     0x10A0
+#define ECCW0_FLIP0_BITS                       31
+#define ECCW0_FLIP1_OFFSET                     0x10A4
 #define ECCW1_FLIP_CTRL                                0x10AC
 #define ECCW1_FLIP0_OFFSET                     0x10B0
+#define ECCW1_FLIP1_OFFSET                     0x10B4
 #define ECCR0_CERR_STAT_OFFSET                 0x10BC
 #define ECCR0_CE_ADDR_LO_OFFSET                        0x10C0
 #define ECCR0_CE_ADDR_HI_OFFSET                        0x10C4
 #define XDDR_BUS_WIDTH_32                      1
 #define XDDR_BUS_WIDTH_16                      2
 
-#define ECC_CEPOISON_MASK                      0x1
-#define ECC_UEPOISON_MASK                      0x3
-
 #define XDDR_MAX_ROW_CNT                       18
 #define XDDR_MAX_COL_CNT                       10
 #define XDDR_MAX_RANK_CNT                      2
  * https://docs.xilinx.com/r/en-US/am012-versal-register-reference/PCSR_LOCK-XRAM_SLCR-Register
  */
 #define PCSR_UNLOCK_VAL                                0xF9E8D7C6
+#define PCSR_LOCK_VAL                          1
 #define XDDR_ERR_TYPE_CE                       0
 #define XDDR_ERR_TYPE_UE                       1
 
 #define XILINX_DRAM_SIZE_12G                   3
 #define XILINX_DRAM_SIZE_16G                   4
 #define XILINX_DRAM_SIZE_32G                   5
+#define NUM_UE_BITPOS                          2
 
 /**
  * struct ecc_error_info - ECC error log information.
@@ -479,7 +481,7 @@ static void err_callback(const u32 *payload, void *data)
        writel(regval, priv->ddrmc_baseaddr + XDDR_ISR_OFFSET);
 
        /* Lock the PCSR registers */
-       writel(1, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET);
+       writel(PCSR_LOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET);
        edac_dbg(3, "Total error count CE %d UE %d\n",
                 priv->ce_cnt, priv->ue_cnt);
 }
@@ -650,7 +652,7 @@ static void enable_intr(struct edac_priv *priv)
        writel(XDDR_IRQ_UE_MASK,
               priv->ddrmc_baseaddr + XDDR_IRQ1_EN_OFFSET);
        /* Lock the PCSR registers */
-       writel(1, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET);
+       writel(PCSR_LOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET);
 }
 
 static void disable_intr(struct edac_priv *priv)
@@ -663,7 +665,7 @@ static void disable_intr(struct edac_priv *priv)
               priv->ddrmc_baseaddr + XDDR_IRQ_DIS_OFFSET);
 
        /* Lock the PCSR registers */
-       writel(1, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET);
+       writel(PCSR_LOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET);
 }
 
 #define to_mci(k) container_of(k, struct mem_ctl_info, dev)
@@ -734,38 +736,63 @@ static void poison_setup(struct edac_priv *priv)
        writel(regval, priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC15_OFFSET);
 }
 
-static ssize_t xddr_inject_data_poison_store(struct mem_ctl_info *mci,
-                                            const char __user *data)
+static void xddr_inject_data_ce_store(struct mem_ctl_info *mci, u8 ce_bitpos)
 {
+       u32 ecc0_flip0, ecc1_flip0, ecc0_flip1, ecc1_flip1;
        struct edac_priv *priv = mci->pvt_info;
 
-       writel(0, priv->ddrmc_baseaddr + ECCW0_FLIP0_OFFSET);
-       writel(0, priv->ddrmc_baseaddr + ECCW1_FLIP0_OFFSET);
-
-       if (strncmp(data, "CE", 2) == 0) {
-               writel(ECC_CEPOISON_MASK, priv->ddrmc_baseaddr +
-                      ECCW0_FLIP0_OFFSET);
-               writel(ECC_CEPOISON_MASK, priv->ddrmc_baseaddr +
-                      ECCW1_FLIP0_OFFSET);
+       if (ce_bitpos < ECCW0_FLIP0_BITS) {
+               ecc0_flip0 = BIT(ce_bitpos);
+               ecc1_flip0 = BIT(ce_bitpos);
+               ecc0_flip1 = 0;
+               ecc1_flip1 = 0;
        } else {
-               writel(ECC_UEPOISON_MASK, priv->ddrmc_baseaddr +
-                      ECCW0_FLIP0_OFFSET);
-               writel(ECC_UEPOISON_MASK, priv->ddrmc_baseaddr +
-                      ECCW1_FLIP0_OFFSET);
+               ce_bitpos = ce_bitpos - ECCW0_FLIP0_BITS;
+               ecc0_flip1 = BIT(ce_bitpos);
+               ecc1_flip1 = BIT(ce_bitpos);
+               ecc0_flip0 = 0;
+               ecc1_flip0 = 0;
        }
 
-       /* Lock the PCSR registers */
-       writel(1, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET);
-
-       return 0;
+       writel(ecc0_flip0, priv->ddrmc_baseaddr + ECCW0_FLIP0_OFFSET);
+       writel(ecc1_flip0, priv->ddrmc_baseaddr + ECCW1_FLIP0_OFFSET);
+       writel(ecc0_flip1, priv->ddrmc_baseaddr + ECCW0_FLIP1_OFFSET);
+       writel(ecc1_flip1, priv->ddrmc_baseaddr + ECCW1_FLIP1_OFFSET);
 }
 
-static ssize_t inject_data_poison_store(struct file *file, const char __user *data,
-                                       size_t count, loff_t *ppos)
+/*
+ * To inject a correctable error, the following steps are needed:
+ *
+ * - Write the correctable error bit position value:
+ *     echo <bit_pos val> > /sys/kernel/debug/edac/<controller instance>/inject_ce
+ *
+ * poison_setup() derives the row, column, bank, group and rank and
+ * writes to the ADEC registers based on the address given by the user.
+ *
+ * The ADEC12 and ADEC13 are mask registers; write 0 to make sure default
+ * configuration is there and no addresses are masked.
+ *
+ * The row, column, bank, group and rank registers are written to the
+ * match ADEC bit to generate errors at the particular address. ADEC14
+ * and ADEC15 have the match bits.
+ *
+ * xddr_inject_data_ce_store() updates the ECC FLIP registers with the
+ * bits to be corrupted based on the bit position given by the user.
+ *
+ * Upon doing a read to the address the errors are injected.
+ */
+static ssize_t inject_data_ce_store(struct file *file, const char __user *data,
+                                   size_t count, loff_t *ppos)
 {
        struct device *dev = file->private_data;
        struct mem_ctl_info *mci = to_mci(dev);
        struct edac_priv *priv = mci->pvt_info;
+       u8 ce_bitpos;
+       int ret;
+
+       ret = kstrtou8_from_user(data, count, 0, &ce_bitpos);
+       if (ret)
+               return ret;
 
        /* Unlock the PCSR registers */
        writel(PCSR_UNLOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET);
@@ -773,17 +800,110 @@ static ssize_t inject_data_poison_store(struct file *file, const char __user *da
 
        poison_setup(priv);
 
+       xddr_inject_data_ce_store(mci, ce_bitpos);
+       ret = count;
+
        /* Lock the PCSR registers */
-       writel(1, priv->ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET);
+       writel(PCSR_LOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET);
+       writel(PCSR_LOCK_VAL, priv->ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET);
+
+       return ret;
+}
+
+static const struct file_operations xddr_inject_ce_fops = {
+       .open = simple_open,
+       .write = inject_data_ce_store,
+       .llseek = generic_file_llseek,
+};
+
+static void xddr_inject_data_ue_store(struct mem_ctl_info *mci, u32 val0, u32 val1)
+{
+       struct edac_priv *priv = mci->pvt_info;
+
+       writel(val0, priv->ddrmc_baseaddr + ECCW0_FLIP0_OFFSET);
+       writel(val0, priv->ddrmc_baseaddr + ECCW0_FLIP1_OFFSET);
+       writel(val1, priv->ddrmc_baseaddr + ECCW1_FLIP1_OFFSET);
+       writel(val1, priv->ddrmc_baseaddr + ECCW1_FLIP1_OFFSET);
+}
+
+/*
+ * To inject an uncorrectable error, the following steps are needed:
+ *     echo <bit_pos val> > /sys/kernel/debug/edac/<controller instance>/inject_ue
+ *
+ * poison_setup() derives the row, column, bank, group and rank and
+ * writes to the ADEC registers based on the address given by the user.
+ *
+ * The ADEC12 and ADEC13 are mask registers; write 0 so that none of the
+ * addresses are masked. The row, column, bank, group and rank registers
+ * are written to the match ADEC bit to generate errors at the
+ * particular address. ADEC14 and ADEC15 have the match bits.
+ *
+ * xddr_inject_data_ue_store() updates the ECC FLIP registers with the
+ * bits to be corrupted based on the bit position given by the user. For
+ * uncorrectable errors
+ * 2 bit errors are injected.
+ *
+ * Upon doing a read to the address the errors are injected.
+ */
+static ssize_t inject_data_ue_store(struct file *file, const char __user *data,
+                                   size_t count, loff_t *ppos)
+{
+       struct device *dev = file->private_data;
+       struct mem_ctl_info *mci = to_mci(dev);
+       struct edac_priv *priv = mci->pvt_info;
+       char buf[6], *pbuf, *token[2];
+       u32 val0 = 0, val1 = 0;
+       u8 len, ue0, ue1;
+       int i, ret;
+
+       len = min_t(size_t, count, sizeof(buf));
+       if (copy_from_user(buf, data, len))
+               return -EFAULT;
+
+       buf[len] = '\0';
+       pbuf = &buf[0];
+       for (i = 0; i < NUM_UE_BITPOS; i++)
+               token[i] = strsep(&pbuf, ",");
+
+       ret = kstrtou8(token[0], 0, &ue0);
+       if (ret)
+               return ret;
+
+       ret = kstrtou8(token[1], 0, &ue1);
+       if (ret)
+               return ret;
+
+       if (ue0 < ECCW0_FLIP0_BITS) {
+               val0 = BIT(ue0);
+       } else {
+               ue0 = ue0 - ECCW0_FLIP0_BITS;
+               val1 = BIT(ue0);
+       }
+
+       if (ue1 < ECCW0_FLIP0_BITS) {
+               val0 |= BIT(ue1);
+       } else {
+               ue1 = ue1 - ECCW0_FLIP0_BITS;
+               val1 |= BIT(ue1);
+       }
 
-       xddr_inject_data_poison_store(mci, data);
+       /* Unlock the PCSR registers */
+       writel(PCSR_UNLOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET);
+       writel(PCSR_UNLOCK_VAL, priv->ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET);
 
+       poison_setup(priv);
+
+       xddr_inject_data_ue_store(mci, val0, val1);
+
+       /* Lock the PCSR registers */
+       writel(PCSR_LOCK_VAL, priv->ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET);
+       writel(PCSR_LOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET);
        return count;
 }
 
-static const struct file_operations xddr_inject_enable_fops = {
+static const struct file_operations xddr_inject_ue_fops = {
        .open = simple_open,
-       .write = inject_data_poison_store,
+       .write = inject_data_ue_store,
        .llseek = generic_file_llseek,
 };
 
@@ -795,8 +915,17 @@ static void create_debugfs_attributes(struct mem_ctl_info *mci)
        if (!priv->debugfs)
                return;
 
-       edac_debugfs_create_file("inject_error", 0200, priv->debugfs,
-                                &mci->dev, &xddr_inject_enable_fops);
+       if (!edac_debugfs_create_file("inject_ce", 0200, priv->debugfs,
+                                     &mci->dev, &xddr_inject_ce_fops)) {
+               debugfs_remove_recursive(priv->debugfs);
+               return;
+       }
+
+       if (!edac_debugfs_create_file("inject_ue", 0200, priv->debugfs,
+                                     &mci->dev, &xddr_inject_ue_fops)) {
+               debugfs_remove_recursive(priv->debugfs);
+               return;
+       }
        debugfs_create_x64("address", 0600, priv->debugfs,
                           &priv->err_inject_addr);
        mci->debugfs = priv->debugfs;
@@ -1031,7 +1160,7 @@ free_edac_mc:
        return rc;
 }
 
-static int mc_remove(struct platform_device *pdev)
+static void mc_remove(struct platform_device *pdev)
 {
        struct mem_ctl_info *mci = platform_get_drvdata(pdev);
        struct edac_priv *priv = mci->pvt_info;
@@ -1049,8 +1178,6 @@ static int mc_remove(struct platform_device *pdev)
                              XPM_EVENT_ERROR_MASK_DDRMC_NCR, err_callback, mci);
        edac_mc_del_mc(&pdev->dev);
        edac_mc_free(mci);
-
-       return 0;
 }
 
 static struct platform_driver xilinx_ddr_edac_mc_driver = {
@@ -1059,7 +1186,7 @@ static struct platform_driver xilinx_ddr_edac_mc_driver = {
                .of_match_table = xlnx_edac_match,
        },
        .probe = mc_probe,
-       .remove = mc_remove,
+       .remove_new = mc_remove,
 };
 
 module_platform_driver(xilinx_ddr_edac_mc_driver);
index 8aaa7fcb2630dcf47a5325982cbed1037f685b3b..401a77e3b5fa8ed9e9b834c4a55cde98d2b2a8db 100644 (file)
@@ -500,7 +500,19 @@ static void bm_work(struct work_struct *work)
                fw_notice(card, "phy config: new root=%x, gap_count=%d\n",
                          new_root_id, gap_count);
                fw_send_phy_config(card, new_root_id, generation, gap_count);
-               reset_bus(card, true);
+               /*
+                * Where possible, use a short bus reset to minimize
+                * disruption to isochronous transfers. But in the event
+                * of a gap count inconsistency, use a long bus reset.
+                *
+                * As noted in 1394a 8.4.6.2, nodes on a mixed 1394/1394a bus
+                * may set different gap counts after a bus reset. On a mixed
+                * 1394/1394a bus, a short bus reset can get doubled. Some
+                * nodes may treat the double reset as one bus reset and others
+                * may treat it as two, causing a gap count inconsistency
+                * again. Using a long bus reset prevents this.
+                */
+               reset_bus(card, card->gap_count != 0);
                /* Will allocate broadcast channel after the reset. */
                goto out;
        }
index 9db9290c326930d7ac903382f234f9435876b39b..7bc71f4be64a07510507e1c9b7d0f1a61de30e3b 100644 (file)
@@ -3773,6 +3773,7 @@ static int pci_probe(struct pci_dev *dev,
        return 0;
 
  fail_msi:
+       devm_free_irq(&dev->dev, dev->irq, ohci);
        pci_disable_msi(dev);
 
        return err;
@@ -3800,6 +3801,7 @@ static void pci_remove(struct pci_dev *dev)
 
        software_reset(ohci);
 
+       devm_free_irq(&dev->dev, dev->irq, ohci);
        pci_disable_msi(dev);
 
        dev_notice(&dev->dev, "removing fw-ohci device\n");
index 1c7940ba55393f62050fde61d8f4fd71dce73233..2f557e90f2ebe57839f909e3910037f10b84a323 100644 (file)
@@ -105,7 +105,7 @@ static struct attribute *ffa_device_attributes_attrs[] = {
 };
 ATTRIBUTE_GROUPS(ffa_device_attributes);
 
-struct bus_type ffa_bus_type = {
+const struct bus_type ffa_bus_type = {
        .name           = "arm_ffa",
        .match          = ffa_device_match,
        .probe          = ffa_device_probe,
index c15928b8c5cc9976b9f12ca5a7e4154dcbb0e888..77c78be6e79c959fd8a15319b12e21e92e3f8c54 100644 (file)
@@ -141,6 +141,17 @@ out:
        return ret;
 }
 
+static int scmi_protocol_table_register(const struct scmi_device_id *id_table)
+{
+       int ret = 0;
+       const struct scmi_device_id *entry;
+
+       for (entry = id_table; entry->name && ret == 0; entry++)
+               ret = scmi_protocol_device_request(entry);
+
+       return ret;
+}
+
 /**
  * scmi_protocol_device_unrequest  - Helper to unrequest a device
  *
@@ -186,6 +197,15 @@ static void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table
        mutex_unlock(&scmi_requested_devices_mtx);
 }
 
+static void
+scmi_protocol_table_unregister(const struct scmi_device_id *id_table)
+{
+       const struct scmi_device_id *entry;
+
+       for (entry = id_table; entry->name; entry++)
+               scmi_protocol_device_unrequest(entry);
+}
+
 static const struct scmi_device_id *
 scmi_dev_match_id(struct scmi_device *scmi_dev, struct scmi_driver *scmi_drv)
 {
@@ -263,7 +283,7 @@ static void scmi_dev_remove(struct device *dev)
                scmi_drv->remove(scmi_dev);
 }
 
-struct bus_type scmi_bus_type = {
+const struct bus_type scmi_bus_type = {
        .name = "scmi_protocol",
        .match = scmi_dev_match,
        .probe = scmi_dev_probe,
@@ -279,7 +299,7 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner,
        if (!driver->probe)
                return -EINVAL;
 
-       retval = scmi_protocol_device_request(driver->id_table);
+       retval = scmi_protocol_table_register(driver->id_table);
        if (retval)
                return retval;
 
@@ -299,7 +319,7 @@ EXPORT_SYMBOL_GPL(scmi_driver_register);
 void scmi_driver_unregister(struct scmi_driver *driver)
 {
        driver_unregister(&driver->driver);
-       scmi_protocol_device_unrequest(driver->id_table);
+       scmi_protocol_table_unregister(driver->id_table);
 }
 EXPORT_SYMBOL_GPL(scmi_driver_unregister);
 
index e2050adbf85c6a125fc5ba241fb0c6b133466bfe..134019297d08b1bd9e4b02e69a1cc16a3dc429b2 100644 (file)
@@ -13,7 +13,7 @@
 #include "notify.h"
 
 /* Updated only after ALL the mandatory features for that version are merged */
-#define SCMI_PROTOCOL_SUPPORTED_VERSION                0x20000
+#define SCMI_PROTOCOL_SUPPORTED_VERSION                0x30000
 
 enum scmi_clock_protocol_cmd {
        CLOCK_ATTRIBUTES = 0x3,
@@ -28,8 +28,13 @@ enum scmi_clock_protocol_cmd {
        CLOCK_POSSIBLE_PARENTS_GET = 0xC,
        CLOCK_PARENT_SET = 0xD,
        CLOCK_PARENT_GET = 0xE,
+       CLOCK_GET_PERMISSIONS = 0xF,
 };
 
+#define CLOCK_STATE_CONTROL_ALLOWED    BIT(31)
+#define CLOCK_PARENT_CONTROL_ALLOWED   BIT(30)
+#define CLOCK_RATE_CONTROL_ALLOWED     BIT(29)
+
 enum clk_state {
        CLK_STATE_DISABLE,
        CLK_STATE_ENABLE,
@@ -49,6 +54,8 @@ struct scmi_msg_resp_clock_attributes {
 #define SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(x)        ((x) & BIT(30))
 #define SUPPORTS_EXTENDED_NAMES(x)             ((x) & BIT(29))
 #define SUPPORTS_PARENT_CLOCK(x)               ((x) & BIT(28))
+#define SUPPORTS_EXTENDED_CONFIG(x)            ((x) & BIT(27))
+#define SUPPORTS_GET_PERMISSIONS(x)            ((x) & BIT(1))
        u8 name[SCMI_SHORT_NAME_MAX_SIZE];
        __le32 clock_enable_latency;
 };
@@ -152,14 +159,18 @@ struct clock_info {
        u32 version;
        int num_clocks;
        int max_async_req;
+       bool notify_rate_changed_cmd;
+       bool notify_rate_change_requested_cmd;
        atomic_t cur_async_req;
        struct scmi_clock_info *clk;
        int (*clock_config_set)(const struct scmi_protocol_handle *ph,
                                u32 clk_id, enum clk_state state,
-                               u8 oem_type, u32 oem_val, bool atomic);
+                               enum scmi_clock_oem_config oem_type,
+                               u32 oem_val, bool atomic);
        int (*clock_config_get)(const struct scmi_protocol_handle *ph,
-                               u32 clk_id, u8 oem_type, u32 *attributes,
-                               bool *enabled, u32 *oem_val, bool atomic);
+                               u32 clk_id, enum scmi_clock_oem_config oem_type,
+                               u32 *attributes, bool *enabled, u32 *oem_val,
+                               bool atomic);
 };
 
 static enum scmi_clock_protocol_cmd evt_2_cmd[] = {
@@ -167,6 +178,15 @@ static enum scmi_clock_protocol_cmd evt_2_cmd[] = {
        CLOCK_RATE_CHANGE_REQUESTED_NOTIFY,
 };
 
+static inline struct scmi_clock_info *
+scmi_clock_domain_lookup(struct clock_info *ci, u32 clk_id)
+{
+       if (clk_id >= ci->num_clocks)
+               return ERR_PTR(-EINVAL);
+
+       return ci->clk + clk_id;
+}
+
 static int
 scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph,
                                   struct clock_info *ci)
@@ -189,6 +209,17 @@ scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph,
        }
 
        ph->xops->xfer_put(ph, t);
+
+       if (!ret) {
+               if (!ph->hops->protocol_msg_check(ph, CLOCK_RATE_NOTIFY, NULL))
+                       ci->notify_rate_changed_cmd = true;
+
+               if (!ph->hops->protocol_msg_check(ph,
+                                                 CLOCK_RATE_CHANGE_REQUESTED_NOTIFY,
+                                                 NULL))
+                       ci->notify_rate_change_requested_cmd = true;
+       }
+
        return ret;
 }
 
@@ -284,14 +315,44 @@ static int scmi_clock_possible_parents(const struct scmi_protocol_handle *ph, u3
        return ret;
 }
 
+static int
+scmi_clock_get_permissions(const struct scmi_protocol_handle *ph, u32 clk_id,
+                          struct scmi_clock_info *clk)
+{
+       struct scmi_xfer *t;
+       u32 perm;
+       int ret;
+
+       ret = ph->xops->xfer_get_init(ph, CLOCK_GET_PERMISSIONS,
+                                     sizeof(clk_id), sizeof(perm), &t);
+       if (ret)
+               return ret;
+
+       put_unaligned_le32(clk_id, t->tx.buf);
+
+       ret = ph->xops->do_xfer(ph, t);
+       if (!ret) {
+               perm = get_unaligned_le32(t->rx.buf);
+
+               clk->state_ctrl_forbidden = !(perm & CLOCK_STATE_CONTROL_ALLOWED);
+               clk->rate_ctrl_forbidden = !(perm & CLOCK_RATE_CONTROL_ALLOWED);
+               clk->parent_ctrl_forbidden = !(perm & CLOCK_PARENT_CONTROL_ALLOWED);
+       }
+
+       ph->xops->xfer_put(ph, t);
+
+       return ret;
+}
+
 static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
-                                    u32 clk_id, struct scmi_clock_info *clk,
+                                    u32 clk_id, struct clock_info *cinfo,
                                     u32 version)
 {
        int ret;
        u32 attributes;
        struct scmi_xfer *t;
        struct scmi_msg_resp_clock_attributes *attr;
+       struct scmi_clock_info *clk = cinfo->clk + clk_id;
 
        ret = ph->xops->xfer_get_init(ph, CLOCK_ATTRIBUTES,
                                      sizeof(clk_id), sizeof(*attr), &t);
@@ -324,12 +385,20 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
                                                    NULL, clk->name,
                                                    SCMI_MAX_STR_SIZE);
 
-               if (SUPPORTS_RATE_CHANGED_NOTIF(attributes))
+               if (cinfo->notify_rate_changed_cmd &&
+                   SUPPORTS_RATE_CHANGED_NOTIF(attributes))
                        clk->rate_changed_notifications = true;
-               if (SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes))
+               if (cinfo->notify_rate_change_requested_cmd &&
+                   SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes))
                        clk->rate_change_requested_notifications = true;
-               if (SUPPORTS_PARENT_CLOCK(attributes))
-                       scmi_clock_possible_parents(ph, clk_id, clk);
+               if (PROTOCOL_REV_MAJOR(version) >= 0x3) {
+                       if (SUPPORTS_PARENT_CLOCK(attributes))
+                               scmi_clock_possible_parents(ph, clk_id, clk);
+                       if (SUPPORTS_GET_PERMISSIONS(attributes))
+                               scmi_clock_get_permissions(ph, clk_id, clk);
+                       if (SUPPORTS_EXTENDED_CONFIG(attributes))
+                               clk->extended_config = true;
+               }
        }
 
        return ret;
@@ -502,6 +571,14 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,
        struct scmi_xfer *t;
        struct scmi_clock_set_rate *cfg;
        struct clock_info *ci = ph->get_priv(ph);
+       struct scmi_clock_info *clk;
+
+       clk = scmi_clock_domain_lookup(ci, clk_id);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       if (clk->rate_ctrl_forbidden)
+               return -EACCES;
 
        ret = ph->xops->xfer_get_init(ph, CLOCK_RATE_SET, sizeof(*cfg), 0, &t);
        if (ret)
@@ -543,7 +620,8 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,
 
 static int
 scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,
-                     enum clk_state state, u8 __unused0, u32 __unused1,
+                     enum clk_state state,
+                     enum scmi_clock_oem_config __unused0, u32 __unused1,
                      bool atomic)
 {
        int ret;
@@ -580,14 +658,16 @@ scmi_clock_set_parent(const struct scmi_protocol_handle *ph, u32 clk_id,
        struct clock_info *ci = ph->get_priv(ph);
        struct scmi_clock_info *clk;
 
-       if (clk_id >= ci->num_clocks)
-               return -EINVAL;
-
-       clk = ci->clk + clk_id;
+       clk = scmi_clock_domain_lookup(ci, clk_id);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
 
        if (parent_id >= clk->num_parents)
                return -EINVAL;
 
+       if (clk->parent_ctrl_forbidden)
+               return -EACCES;
+
        ret = ph->xops->xfer_get_init(ph, CLOCK_PARENT_SET,
                                      sizeof(*cfg), 0, &t);
        if (ret)
@@ -628,10 +708,11 @@ scmi_clock_get_parent(const struct scmi_protocol_handle *ph, u32 clk_id,
        return ret;
 }
 
-/* For SCMI clock v2.1 and onwards */
+/* For SCMI clock v3.0 and onwards */
 static int
 scmi_clock_config_set_v2(const struct scmi_protocol_handle *ph, u32 clk_id,
-                        enum clk_state state, u8 oem_type, u32 oem_val,
+                        enum clk_state state,
+                        enum scmi_clock_oem_config oem_type, u32 oem_val,
                         bool atomic)
 {
        int ret;
@@ -671,6 +752,14 @@ static int scmi_clock_enable(const struct scmi_protocol_handle *ph, u32 clk_id,
                             bool atomic)
 {
        struct clock_info *ci = ph->get_priv(ph);
+       struct scmi_clock_info *clk;
+
+       clk = scmi_clock_domain_lookup(ci, clk_id);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       if (clk->state_ctrl_forbidden)
+               return -EACCES;
 
        return ci->clock_config_set(ph, clk_id, CLK_STATE_ENABLE,
                                    NULL_OEM_TYPE, 0, atomic);
@@ -680,16 +769,24 @@ static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id,
                              bool atomic)
 {
        struct clock_info *ci = ph->get_priv(ph);
+       struct scmi_clock_info *clk;
+
+       clk = scmi_clock_domain_lookup(ci, clk_id);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       if (clk->state_ctrl_forbidden)
+               return -EACCES;
 
        return ci->clock_config_set(ph, clk_id, CLK_STATE_DISABLE,
                                    NULL_OEM_TYPE, 0, atomic);
 }
 
-/* For SCMI clock v2.1 and onwards */
+/* For SCMI clock v3.0 and onwards */
 static int
 scmi_clock_config_get_v2(const struct scmi_protocol_handle *ph, u32 clk_id,
-                        u8 oem_type, u32 *attributes, bool *enabled,
-                        u32 *oem_val, bool atomic)
+                        enum scmi_clock_oem_config oem_type, u32 *attributes,
+                        bool *enabled, u32 *oem_val, bool atomic)
 {
        int ret;
        u32 flags;
@@ -730,8 +827,8 @@ scmi_clock_config_get_v2(const struct scmi_protocol_handle *ph, u32 clk_id,
 
 static int
 scmi_clock_config_get(const struct scmi_protocol_handle *ph, u32 clk_id,
-                     u8 oem_type, u32 *attributes, bool *enabled,
-                     u32 *oem_val, bool atomic)
+                     enum scmi_clock_oem_config oem_type, u32 *attributes,
+                     bool *enabled, u32 *oem_val, bool atomic)
 {
        int ret;
        struct scmi_xfer *t;
@@ -768,20 +865,38 @@ static int scmi_clock_state_get(const struct scmi_protocol_handle *ph,
 }
 
 static int scmi_clock_config_oem_set(const struct scmi_protocol_handle *ph,
-                                    u32 clk_id, u8 oem_type, u32 oem_val,
-                                    bool atomic)
+                                    u32 clk_id,
+                                    enum scmi_clock_oem_config oem_type,
+                                    u32 oem_val, bool atomic)
 {
        struct clock_info *ci = ph->get_priv(ph);
+       struct scmi_clock_info *clk;
+
+       clk = scmi_clock_domain_lookup(ci, clk_id);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       if (!clk->extended_config)
+               return -EOPNOTSUPP;
 
        return ci->clock_config_set(ph, clk_id, CLK_STATE_UNCHANGED,
                                    oem_type, oem_val, atomic);
 }
 
 static int scmi_clock_config_oem_get(const struct scmi_protocol_handle *ph,
-                                    u32 clk_id, u8 oem_type, u32 *oem_val,
-                                    u32 *attributes, bool atomic)
+                                    u32 clk_id,
+                                    enum scmi_clock_oem_config oem_type,
+                                    u32 *oem_val, u32 *attributes, bool atomic)
 {
        struct clock_info *ci = ph->get_priv(ph);
+       struct scmi_clock_info *clk;
+
+       clk = scmi_clock_domain_lookup(ci, clk_id);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       if (!clk->extended_config)
+               return -EOPNOTSUPP;
 
        return ci->clock_config_get(ph, clk_id, oem_type, attributes,
                                    NULL, oem_val, atomic);
@@ -800,10 +915,10 @@ scmi_clock_info_get(const struct scmi_protocol_handle *ph, u32 clk_id)
        struct scmi_clock_info *clk;
        struct clock_info *ci = ph->get_priv(ph);
 
-       if (clk_id >= ci->num_clocks)
+       clk = scmi_clock_domain_lookup(ci, clk_id);
+       if (IS_ERR(clk))
                return NULL;
 
-       clk = ci->clk + clk_id;
        if (!clk->name[0])
                return NULL;
 
@@ -824,6 +939,28 @@ static const struct scmi_clk_proto_ops clk_proto_ops = {
        .parent_get = scmi_clock_get_parent,
 };
 
+static bool scmi_clk_notify_supported(const struct scmi_protocol_handle *ph,
+                                     u8 evt_id, u32 src_id)
+{
+       bool supported;
+       struct scmi_clock_info *clk;
+       struct clock_info *ci = ph->get_priv(ph);
+
+       if (evt_id >= ARRAY_SIZE(evt_2_cmd))
+               return false;
+
+       clk = scmi_clock_domain_lookup(ci, src_id);
+       if (IS_ERR(clk))
+               return false;
+
+       if (evt_id == SCMI_EVENT_CLOCK_RATE_CHANGED)
+               supported = clk->rate_changed_notifications;
+       else
+               supported = clk->rate_change_requested_notifications;
+
+       return supported;
+}
+
 static int scmi_clk_rate_notify(const struct scmi_protocol_handle *ph,
                                u32 clk_id, int message_id, bool enable)
 {
@@ -908,6 +1045,7 @@ static const struct scmi_event clk_events[] = {
 };
 
 static const struct scmi_event_ops clk_event_ops = {
+       .is_notify_supported = scmi_clk_notify_supported,
        .get_num_sources = scmi_clk_get_num_sources,
        .set_notify_enabled = scmi_clk_set_notify_enabled,
        .fill_custom_report = scmi_clk_fill_custom_report,
@@ -949,7 +1087,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
        for (clkid = 0; clkid < cinfo->num_clocks; clkid++) {
                struct scmi_clock_info *clk = cinfo->clk + clkid;
 
-               ret = scmi_clock_attributes_get(ph, clkid, clk, version);
+               ret = scmi_clock_attributes_get(ph, clkid, cinfo, version);
                if (!ret)
                        scmi_clock_describe_rates_get(ph, clkid, clk);
        }
index 00b165d1f502df7816527298996f196585d10f5a..6affbfdd1dec1aeedb82dc53adbef3d182e33d02 100644 (file)
@@ -141,7 +141,7 @@ scmi_revision_area_get(const struct scmi_protocol_handle *ph);
 void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph,
                                     u8 *prot_imp);
 
-extern struct bus_type scmi_bus_type;
+extern const struct bus_type scmi_bus_type;
 
 #define SCMI_BUS_NOTIFY_DEVICE_REQUEST         0
 #define SCMI_BUS_NOTIFY_DEVICE_UNREQUEST       1
index 3ea64b22cf0dfd4493c8179de90b81b822759342..34d77802c990ac796147359a9b5c7660ee85ee08 100644 (file)
@@ -86,6 +86,12 @@ struct scmi_xfers_info {
  * @users: A refcount to track effective users of this protocol.
  * @priv: Reference for optional protocol private data.
  * @version: Protocol version supported by the platform as detected at runtime.
+ * @negotiated_version: When the platform supports a newer protocol version,
+ *                     the agent will try to negotiate with the platform the
+ *                     usage of the newest version known to it, since
+ *                     backward compatibility is NOT automatically assured.
+ *                     This field is NON-zero when a successful negotiation
+ *                     has completed.
  * @ph: An embedded protocol handle that will be passed down to protocol
  *     initialization code to identify this instance.
  *
@@ -99,6 +105,7 @@ struct scmi_protocol_instance {
        refcount_t                      users;
        void                            *priv;
        unsigned int                    version;
+       unsigned int                    negotiated_version;
        struct scmi_protocol_handle     ph;
 };
 
@@ -1754,10 +1761,44 @@ static void scmi_common_fastchannel_db_ring(struct scmi_fc_db_info *db)
 #endif
 }
 
+/**
+ * scmi_protocol_msg_check  - Check protocol message attributes
+ *
+ * @ph: A reference to the protocol handle.
+ * @message_id: The ID of the message to check.
+ * @attributes: A parameter to optionally return the retrieved message
+ *             attributes, in case of Success.
+ *
+ * An helper to check protocol message attributes for a specific protocol
+ * and message pair.
+ *
+ * Return: 0 on SUCCESS
+ */
+static int scmi_protocol_msg_check(const struct scmi_protocol_handle *ph,
+                                  u32 message_id, u32 *attributes)
+{
+       int ret;
+       struct scmi_xfer *t;
+
+       ret = xfer_get_init(ph, PROTOCOL_MESSAGE_ATTRIBUTES,
+                           sizeof(__le32), 0, &t);
+       if (ret)
+               return ret;
+
+       put_unaligned_le32(message_id, t->tx.buf);
+       ret = do_xfer(ph, t);
+       if (!ret && attributes)
+               *attributes = get_unaligned_le32(t->rx.buf);
+       xfer_put(ph, t);
+
+       return ret;
+}
+
 static const struct scmi_proto_helpers_ops helpers_ops = {
        .extended_name_get = scmi_common_extended_name_get,
        .iter_response_init = scmi_iterator_init,
        .iter_response_run = scmi_iterator_run,
+       .protocol_msg_check = scmi_protocol_msg_check,
        .fastchannel_init = scmi_common_fastchannel_init,
        .fastchannel_db_ring = scmi_common_fastchannel_db_ring,
 };
@@ -1781,6 +1822,44 @@ scmi_revision_area_get(const struct scmi_protocol_handle *ph)
        return pi->handle->version;
 }
 
+/**
+ * scmi_protocol_version_negotiate  - Negotiate protocol version
+ *
+ * @ph: A reference to the protocol handle.
+ *
+ * An helper to negotiate a protocol version different from the latest
+ * advertised as supported from the platform: on Success backward
+ * compatibility is assured by the platform.
+ *
+ * Return: 0 on Success
+ */
+static int scmi_protocol_version_negotiate(struct scmi_protocol_handle *ph)
+{
+       int ret;
+       struct scmi_xfer *t;
+       struct scmi_protocol_instance *pi = ph_to_pi(ph);
+
+       /* At first check if NEGOTIATE_PROTOCOL_VERSION is supported ... */
+       ret = scmi_protocol_msg_check(ph, NEGOTIATE_PROTOCOL_VERSION, NULL);
+       if (ret)
+               return ret;
+
+       /* ... then attempt protocol version negotiation */
+       ret = xfer_get_init(ph, NEGOTIATE_PROTOCOL_VERSION,
+                           sizeof(__le32), 0, &t);
+       if (ret)
+               return ret;
+
+       put_unaligned_le32(pi->proto->supported_version, t->tx.buf);
+       ret = do_xfer(ph, t);
+       if (!ret)
+               pi->negotiated_version = pi->proto->supported_version;
+
+       xfer_put(ph, t);
+
+       return ret;
+}
+
 /**
  * scmi_alloc_init_protocol_instance  - Allocate and initialize a protocol
  * instance descriptor.
@@ -1853,11 +1932,21 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info,
        devres_close_group(handle->dev, pi->gid);
        dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", pi->proto->id);
 
-       if (pi->version > proto->supported_version)
-               dev_warn(handle->dev,
-                        "Detected UNSUPPORTED higher version 0x%X for protocol 0x%X."
-                        "Backward compatibility is NOT assured.\n",
-                        pi->version, pi->proto->id);
+       if (pi->version > proto->supported_version) {
+               ret = scmi_protocol_version_negotiate(&pi->ph);
+               if (!ret) {
+                       dev_info(handle->dev,
+                                "Protocol 0x%X successfully negotiated version 0x%X\n",
+                                proto->id, pi->negotiated_version);
+               } else {
+                       dev_warn(handle->dev,
+                                "Detected UNSUPPORTED higher version 0x%X for protocol 0x%X.\n",
+                                pi->version, pi->proto->id);
+                       dev_warn(handle->dev,
+                                "Trying version 0x%X. Backward compatibility is NOT assured.\n",
+                                pi->proto->supported_version);
+               }
+       }
 
        return pi;
 
index 0efd20cd9d69d8586f04022cc96fe08270c207b4..27c52531194d0797ac0682f51bbad34a7cef479f 100644 (file)
@@ -99,6 +99,7 @@
 #define PROTO_ID_MASK          GENMASK(31, 24)
 #define EVT_ID_MASK            GENMASK(23, 16)
 #define SRC_ID_MASK            GENMASK(15, 0)
+#define NOTIF_UNSUPP           -1
 
 /*
  * Builds an unsigned 32bit key from the given input tuple to be used
@@ -788,6 +789,7 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
 
        pd->ph = ph;
        for (i = 0; i < ee->num_events; i++, evt++) {
+               int id;
                struct scmi_registered_event *r_evt;
 
                r_evt = devm_kzalloc(ni->handle->dev, sizeof(*r_evt),
@@ -809,6 +811,11 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
                if (!r_evt->report)
                        return -ENOMEM;
 
+               for (id = 0; id < r_evt->num_sources; id++)
+                       if (ee->ops->is_notify_supported &&
+                           !ee->ops->is_notify_supported(ph, r_evt->evt->id, id))
+                               refcount_set(&r_evt->sources[id], NOTIF_UNSUPP);
+
                pd->registered_events[i] = r_evt;
                /* Ensure events are updated */
                smp_wmb();
@@ -1166,7 +1173,13 @@ static inline int __scmi_enable_evt(struct scmi_registered_event *r_evt,
                        int ret = 0;
 
                        sid = &r_evt->sources[src_id];
-                       if (refcount_read(sid) == 0) {
+                       if (refcount_read(sid) == NOTIF_UNSUPP) {
+                               dev_dbg(r_evt->proto->ph->dev,
+                                       "Notification NOT supported - proto_id:%d  evt_id:%d  src_id:%d",
+                                       r_evt->proto->id, r_evt->evt->id,
+                                       src_id);
+                               ret = -EOPNOTSUPP;
+                       } else if (refcount_read(sid) == 0) {
                                ret = REVT_NOTIFY_ENABLE(r_evt, r_evt->evt->id,
                                                         src_id);
                                if (!ret)
@@ -1179,6 +1192,8 @@ static inline int __scmi_enable_evt(struct scmi_registered_event *r_evt,
        } else {
                for (; num_sources; src_id++, num_sources--) {
                        sid = &r_evt->sources[src_id];
+                       if (refcount_read(sid) == NOTIF_UNSUPP)
+                               continue;
                        if (refcount_dec_and_test(sid))
                                REVT_NOTIFY_DISABLE(r_evt,
                                                    r_evt->evt->id, src_id);
index 4e9b627edfefaa819f958be55b67e188b257c1ed..76758a736cf47ac24a41f2ac1f76d0f34aa56160 100644 (file)
@@ -35,6 +35,8 @@ struct scmi_protocol_handle;
 
 /**
  * struct scmi_event_ops  - Protocol helpers called by the notification core.
+ * @is_notify_supported: Return 0 if the specified notification for the
+ *                      specified resource (src_id) is supported.
  * @get_num_sources: Returns the number of possible events' sources for this
  *                  protocol
  * @set_notify_enabled: Enable/disable the required evt_id/src_id notifications
@@ -50,6 +52,8 @@ struct scmi_protocol_handle;
  *         process context.
  */
 struct scmi_event_ops {
+       bool (*is_notify_supported)(const struct scmi_protocol_handle *ph,
+                                   u8 evt_id, u32 src_id);
        int (*get_num_sources)(const struct scmi_protocol_handle *ph);
        int (*set_notify_enabled)(const struct scmi_protocol_handle *ph,
                                  u8 evt_id, u32 src_id, bool enabled);
index 25bfb465484d089479b4a48b4526a4473bac00f0..4e7944b91e3857a582b8d2f5cd40c29be31a7d37 100644 (file)
@@ -109,8 +109,10 @@ enum scmi_optee_pta_cmd {
  * @rx_len: Response size
  * @mu: Mutex protection on channel access
  * @cinfo: SCMI channel information
- * @shmem: Virtual base address of the shared memory
- * @req: Shared memory protocol handle for SCMI request and synchronous response
+ * @req: union for SCMI interface
+ * @req.shmem: Virtual base address of the shared memory
+ * @req.msg: Shared memory protocol handle for SCMI request and
+ *   synchronous response
  * @tee_shm: TEE shared memory handle @req or NULL if using IOMEM shmem
  * @link: Reference in agent's channel list
  */
index 211e8e0aef2c2b4fade048990249c2444afb946a..981e327e63e38211ae657e8e28f284e9c0ea6f19 100644 (file)
@@ -182,6 +182,8 @@ struct scmi_perf_info {
        enum scmi_power_scale power_scale;
        u64 stats_addr;
        u32 stats_size;
+       bool notify_lvl_cmd;
+       bool notify_lim_cmd;
        struct perf_dom_info *dom_info;
 };
 
@@ -222,6 +224,15 @@ static int scmi_perf_attributes_get(const struct scmi_protocol_handle *ph,
        }
 
        ph->xops->xfer_put(ph, t);
+
+       if (!ret) {
+               if (!ph->hops->protocol_msg_check(ph, PERF_NOTIFY_LEVEL, NULL))
+                       pi->notify_lvl_cmd = true;
+
+               if (!ph->hops->protocol_msg_check(ph, PERF_NOTIFY_LIMITS, NULL))
+                       pi->notify_lim_cmd = true;
+       }
+
        return ret;
 }
 
@@ -239,6 +250,7 @@ static void scmi_perf_xa_destroy(void *data)
 static int
 scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
                                struct perf_dom_info *dom_info,
+                               bool notify_lim_cmd, bool notify_lvl_cmd,
                                u32 version)
 {
        int ret;
@@ -260,8 +272,12 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
 
                dom_info->set_limits = SUPPORTS_SET_LIMITS(flags);
                dom_info->info.set_perf = SUPPORTS_SET_PERF_LVL(flags);
-               dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags);
-               dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags);
+               if (notify_lim_cmd)
+                       dom_info->perf_limit_notify =
+                               SUPPORTS_PERF_LIMIT_NOTIFY(flags);
+               if (notify_lvl_cmd)
+                       dom_info->perf_level_notify =
+                               SUPPORTS_PERF_LEVEL_NOTIFY(flags);
                dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags);
                if (PROTOCOL_REV_MAJOR(version) >= 0x4)
                        dom_info->level_indexing_mode =
@@ -270,15 +286,30 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
                                        le32_to_cpu(attr->sustained_freq_khz);
                dom_info->sustained_perf_level =
                                        le32_to_cpu(attr->sustained_perf_level);
+               /*
+                * sustained_freq_khz = mult_factor * sustained_perf_level
+                * mult_factor must be non zero positive integer(not fraction)
+                */
                if (!dom_info->sustained_freq_khz ||
                    !dom_info->sustained_perf_level ||
-                   dom_info->level_indexing_mode)
+                   dom_info->level_indexing_mode) {
                        /* CPUFreq converts to kHz, hence default 1000 */
                        dom_info->mult_factor = 1000;
-               else
+               } else {
                        dom_info->mult_factor =
                                        (dom_info->sustained_freq_khz * 1000UL)
                                        / dom_info->sustained_perf_level;
+                       if ((dom_info->sustained_freq_khz * 1000UL) %
+                           dom_info->sustained_perf_level)
+                               dev_warn(ph->dev,
+                                        "multiplier for domain %d rounded\n",
+                                        dom_info->id);
+               }
+               if (!dom_info->mult_factor)
+                       dev_warn(ph->dev,
+                                "Wrong sustained perf/frequency(domain %d)\n",
+                                dom_info->id);
+
                strscpy(dom_info->info.name, attr->name,
                        SCMI_SHORT_NAME_MAX_SIZE);
        }
@@ -295,9 +326,9 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
                                            dom_info->id, NULL, dom_info->info.name,
                                            SCMI_MAX_STR_SIZE);
 
+       xa_init(&dom_info->opps_by_lvl);
        if (dom_info->level_indexing_mode) {
                xa_init(&dom_info->opps_by_idx);
-               xa_init(&dom_info->opps_by_lvl);
                hash_init(dom_info->opps_by_freq);
        }
 
@@ -340,13 +371,21 @@ static int iter_perf_levels_update_state(struct scmi_iterator_state *st,
 }
 
 static inline void
-process_response_opp(struct scmi_opp *opp, unsigned int loop_idx,
+process_response_opp(struct device *dev, struct perf_dom_info *dom,
+                    struct scmi_opp *opp, unsigned int loop_idx,
                     const struct scmi_msg_resp_perf_describe_levels *r)
 {
+       int ret;
+
        opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val);
        opp->power = le32_to_cpu(r->opp[loop_idx].power);
        opp->trans_latency_us =
                le16_to_cpu(r->opp[loop_idx].transition_latency_us);
+
+       ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
+       if (ret)
+               dev_warn(dev, "Failed to add opps_by_lvl at %d - ret:%d\n",
+                        opp->perf, ret);
 }
 
 static inline void
@@ -354,16 +393,21 @@ process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
                        struct scmi_opp *opp, unsigned int loop_idx,
                        const struct scmi_msg_resp_perf_describe_levels_v4 *r)
 {
+       int ret;
+
        opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val);
        opp->power = le32_to_cpu(r->opp[loop_idx].power);
        opp->trans_latency_us =
                le16_to_cpu(r->opp[loop_idx].transition_latency_us);
 
+       ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
+       if (ret)
+               dev_warn(dev, "Failed to add opps_by_lvl at %d - ret:%d\n",
+                        opp->perf, ret);
+
        /* Note that PERF v4 reports always five 32-bit words */
        opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq);
        if (dom->level_indexing_mode) {
-               int ret;
-
                opp->level_index = le32_to_cpu(r->opp[loop_idx].level_index);
 
                ret = xa_insert(&dom->opps_by_idx, opp->level_index, opp,
@@ -373,12 +417,6 @@ process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
                                 "Failed to add opps_by_idx at %d - ret:%d\n",
                                 opp->level_index, ret);
 
-               ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
-               if (ret)
-                       dev_warn(dev,
-                                "Failed to add opps_by_lvl at %d - ret:%d\n",
-                                opp->perf, ret);
-
                hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq);
        }
 }
@@ -393,7 +431,8 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph,
 
        opp = &p->perf_dom->opp[st->desc_index + st->loop_idx];
        if (PROTOCOL_REV_MAJOR(p->version) <= 0x3)
-               process_response_opp(opp, st->loop_idx, response);
+               process_response_opp(ph->dev, p->perf_dom, opp, st->loop_idx,
+                                    response);
        else
                process_response_opp_v4(ph->dev, p->perf_dom, opp, st->loop_idx,
                                        response);
@@ -978,6 +1017,27 @@ static const struct scmi_perf_proto_ops perf_proto_ops = {
        .power_scale_get = scmi_power_scale_get,
 };
 
+static bool scmi_perf_notify_supported(const struct scmi_protocol_handle *ph,
+                                      u8 evt_id, u32 src_id)
+{
+       bool supported;
+       struct perf_dom_info *dom;
+
+       if (evt_id >= ARRAY_SIZE(evt_2_cmd))
+               return false;
+
+       dom = scmi_perf_domain_lookup(ph, src_id);
+       if (IS_ERR(dom))
+               return false;
+
+       if (evt_id == SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED)
+               supported = dom->perf_limit_notify;
+       else
+               supported = dom->perf_level_notify;
+
+       return supported;
+}
+
 static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph,
                                        u8 evt_id, u32 src_id, bool enable)
 {
@@ -995,18 +1055,47 @@ static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph,
        return ret;
 }
 
+static int
+scmi_perf_xlate_opp_to_freq(struct perf_dom_info *dom,
+                           unsigned int index, unsigned long *freq)
+{
+       struct scmi_opp *opp;
+
+       if (!dom || !freq)
+               return -EINVAL;
+
+       if (!dom->level_indexing_mode) {
+               opp = xa_load(&dom->opps_by_lvl, index);
+               if (!opp)
+                       return -ENODEV;
+
+               *freq = opp->perf * dom->mult_factor;
+       } else {
+               opp = xa_load(&dom->opps_by_idx, index);
+               if (!opp)
+                       return -ENODEV;
+
+               *freq = opp->indicative_freq * dom->mult_factor;
+       }
+
+       return 0;
+}
+
 static void *scmi_perf_fill_custom_report(const struct scmi_protocol_handle *ph,
                                          u8 evt_id, ktime_t timestamp,
                                          const void *payld, size_t payld_sz,
                                          void *report, u32 *src_id)
 {
+       int ret;
        void *rep = NULL;
+       struct perf_dom_info *dom;
 
        switch (evt_id) {
        case SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED:
        {
                const struct scmi_perf_limits_notify_payld *p = payld;
                struct scmi_perf_limits_report *r = report;
+               unsigned long freq_min, freq_max;
 
                if (sizeof(*p) != payld_sz)
                        break;
@@ -1016,14 +1105,36 @@ static void *scmi_perf_fill_custom_report(const struct scmi_protocol_handle *ph,
                r->domain_id = le32_to_cpu(p->domain_id);
                r->range_max = le32_to_cpu(p->range_max);
                r->range_min = le32_to_cpu(p->range_min);
+               /* Check if the reported domain exist at all */
+               dom = scmi_perf_domain_lookup(ph, r->domain_id);
+               if (IS_ERR(dom))
+                       break;
+               /*
+                * Event will be reported from this point on...
+                * ...even if, later, xlated frequencies were not retrieved.
+                */
                *src_id = r->domain_id;
                rep = r;
+
+               ret = scmi_perf_xlate_opp_to_freq(dom, r->range_max, &freq_max);
+               if (ret)
+                       break;
+
+               ret = scmi_perf_xlate_opp_to_freq(dom, r->range_min, &freq_min);
+               if (ret)
+                       break;
+
+               /* Report translated freqs ONLY if both available */
+               r->range_max_freq = freq_max;
+               r->range_min_freq = freq_min;
+
                break;
        }
        case SCMI_EVENT_PERFORMANCE_LEVEL_CHANGED:
        {
                const struct scmi_perf_level_notify_payld *p = payld;
                struct scmi_perf_level_report *r = report;
+               unsigned long freq;
 
                if (sizeof(*p) != payld_sz)
                        break;
@@ -1031,9 +1142,27 @@ static void *scmi_perf_fill_custom_report(const struct scmi_protocol_handle *ph,
                r->timestamp = timestamp;
                r->agent_id = le32_to_cpu(p->agent_id);
                r->domain_id = le32_to_cpu(p->domain_id);
+               /* Report translated freqs ONLY if available */
                r->performance_level = le32_to_cpu(p->performance_level);
+               /* Check if the reported domain exist at all */
+               dom = scmi_perf_domain_lookup(ph, r->domain_id);
+               if (IS_ERR(dom))
+                       break;
+               /*
+                * Event will be reported from this point on...
+                * ...even if, later, xlated frequencies were not retrieved.
+                */
                *src_id = r->domain_id;
                rep = r;
+
+               /* Report translated freqs ONLY if available */
+               ret = scmi_perf_xlate_opp_to_freq(dom, r->performance_level,
+                                                 &freq);
+               if (ret)
+                       break;
+
+               r->performance_level_freq = freq;
+
                break;
        }
        default:
@@ -1067,6 +1196,7 @@ static const struct scmi_event perf_events[] = {
 };
 
 static const struct scmi_event_ops perf_event_ops = {
+       .is_notify_supported = scmi_perf_notify_supported,
        .get_num_sources = scmi_perf_get_num_sources,
        .set_notify_enabled = scmi_perf_set_notify_enabled,
        .fill_custom_report = scmi_perf_fill_custom_report,
@@ -1111,7 +1241,8 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
                struct perf_dom_info *dom = pinfo->dom_info + domain;
 
                dom->id = domain;
-               scmi_perf_domain_attributes_get(ph, dom, version);
+               scmi_perf_domain_attributes_get(ph, dom, pinfo->notify_lim_cmd,
+                                               pinfo->notify_lvl_cmd, version);
                scmi_perf_describe_levels_get(ph, dom, version);
 
                if (dom->perf_fastchannels)
index c2e6b9b4d941cd4e9e5ba9032be4b23006fc435a..49666bd1d8ac0c4efcba123aa365416068a3b50c 100644 (file)
@@ -68,6 +68,7 @@ struct power_dom_info {
 
 struct scmi_power_info {
        u32 version;
+       bool notify_state_change_cmd;
        int num_domains;
        u64 stats_addr;
        u32 stats_size;
@@ -97,13 +98,18 @@ static int scmi_power_attributes_get(const struct scmi_protocol_handle *ph,
        }
 
        ph->xops->xfer_put(ph, t);
+
+       if (!ret)
+               if (!ph->hops->protocol_msg_check(ph, POWER_STATE_NOTIFY, NULL))
+                       pi->notify_state_change_cmd = true;
+
        return ret;
 }
 
 static int
 scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
                                 u32 domain, struct power_dom_info *dom_info,
-                                u32 version)
+                                u32 version, bool notify_state_change_cmd)
 {
        int ret;
        u32 flags;
@@ -122,7 +128,9 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
        if (!ret) {
                flags = le32_to_cpu(attr->flags);
 
-               dom_info->state_set_notify = SUPPORTS_STATE_SET_NOTIFY(flags);
+               if (notify_state_change_cmd)
+                       dom_info->state_set_notify =
+                               SUPPORTS_STATE_SET_NOTIFY(flags);
                dom_info->state_set_async = SUPPORTS_STATE_SET_ASYNC(flags);
                dom_info->state_set_sync = SUPPORTS_STATE_SET_SYNC(flags);
                strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
@@ -231,6 +239,20 @@ static int scmi_power_request_notify(const struct scmi_protocol_handle *ph,
        return ret;
 }
 
+static bool scmi_power_notify_supported(const struct scmi_protocol_handle *ph,
+                                       u8 evt_id, u32 src_id)
+{
+       struct power_dom_info *dom;
+       struct scmi_power_info *pinfo = ph->get_priv(ph);
+
+       if (evt_id != SCMI_EVENT_POWER_STATE_CHANGED ||
+           src_id >= pinfo->num_domains)
+               return false;
+
+       dom = pinfo->dom_info + src_id;
+       return dom->state_set_notify;
+}
+
 static int scmi_power_set_notify_enabled(const struct scmi_protocol_handle *ph,
                                         u8 evt_id, u32 src_id, bool enable)
 {
@@ -285,6 +307,7 @@ static const struct scmi_event power_events[] = {
 };
 
 static const struct scmi_event_ops power_event_ops = {
+       .is_notify_supported = scmi_power_notify_supported,
        .get_num_sources = scmi_power_get_num_sources,
        .set_notify_enabled = scmi_power_set_notify_enabled,
        .fill_custom_report = scmi_power_fill_custom_report,
@@ -326,7 +349,8 @@ static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph)
        for (domain = 0; domain < pinfo->num_domains; domain++) {
                struct power_dom_info *dom = pinfo->dom_info + domain;
 
-               scmi_power_domain_attributes_get(ph, domain, dom, version);
+               scmi_power_domain_attributes_get(ph, domain, dom, version,
+                                                pinfo->notify_state_change_cmd);
        }
 
        pinfo->version = version;
index a4c6cd4716fe4497681a76e5fc662f7fb670e0c5..2fab92367e42f8eb454f5b38383789673914e4e9 100644 (file)
@@ -124,6 +124,8 @@ struct scmi_powercap_state {
 struct powercap_info {
        u32 version;
        int num_domains;
+       bool notify_cap_cmd;
+       bool notify_measurements_cmd;
        struct scmi_powercap_state *states;
        struct scmi_powercap_info *powercaps;
 };
@@ -157,6 +159,18 @@ scmi_powercap_attributes_get(const struct scmi_protocol_handle *ph,
        }
 
        ph->xops->xfer_put(ph, t);
+
+       if (!ret) {
+               if (!ph->hops->protocol_msg_check(ph,
+                                                 POWERCAP_CAP_NOTIFY, NULL))
+                       pi->notify_cap_cmd = true;
+
+               if (!ph->hops->protocol_msg_check(ph,
+                                                 POWERCAP_MEASUREMENTS_NOTIFY,
+                                                 NULL))
+                       pi->notify_measurements_cmd = true;
+       }
+
        return ret;
 }
 
@@ -200,10 +214,12 @@ scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
                flags = le32_to_cpu(resp->attributes);
 
                dom_info->id = domain;
-               dom_info->notify_powercap_cap_change =
-                       SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
-               dom_info->notify_powercap_measurement_change =
-                       SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
+               if (pinfo->notify_cap_cmd)
+                       dom_info->notify_powercap_cap_change =
+                               SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
+               if (pinfo->notify_measurements_cmd)
+                       dom_info->notify_powercap_measurement_change =
+                               SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
                dom_info->async_powercap_cap_set =
                        SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
                dom_info->powercap_cap_config =
@@ -788,6 +804,26 @@ static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
        return ret;
 }
 
+static bool
+scmi_powercap_notify_supported(const struct scmi_protocol_handle *ph,
+                              u8 evt_id, u32 src_id)
+{
+       bool supported = false;
+       const struct scmi_powercap_info *dom_info;
+       struct powercap_info *pi = ph->get_priv(ph);
+
+       if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
+               return false;
+
+       dom_info = pi->powercaps + src_id;
+       if (evt_id == SCMI_EVENT_POWERCAP_CAP_CHANGED)
+               supported = dom_info->notify_powercap_cap_change;
+       else if (evt_id == SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED)
+               supported = dom_info->notify_powercap_measurement_change;
+
+       return supported;
+}
+
 static int
 scmi_powercap_set_notify_enabled(const struct scmi_protocol_handle *ph,
                                 u8 evt_id, u32 src_id, bool enable)
@@ -904,6 +940,7 @@ static const struct scmi_event powercap_events[] = {
 };
 
 static const struct scmi_event_ops powercap_event_ops = {
+       .is_notify_supported = scmi_powercap_notify_supported,
        .get_num_sources = scmi_powercap_get_num_sources,
        .set_notify_enabled = scmi_powercap_set_notify_enabled,
        .fill_custom_report = scmi_powercap_fill_custom_report,
index e683c26f24eb0cffac8a817c6d8162a61ae1d4c2..693019fff0f67e52cbd120b3e56eb237fa7dd1c1 100644 (file)
@@ -33,6 +33,7 @@ enum scmi_common_cmd {
        PROTOCOL_VERSION = 0x0,
        PROTOCOL_ATTRIBUTES = 0x1,
        PROTOCOL_MESSAGE_ATTRIBUTES = 0x2,
+       NEGOTIATE_PROTOCOL_VERSION = 0x10,
 };
 
 /**
@@ -251,6 +252,8 @@ struct scmi_fc_info {
  *                     provided in @ops.
  * @iter_response_run: A common helper to trigger the run of a previously
  *                    initialized iterator.
+ * @protocol_msg_check: A common helper to check is a specific protocol message
+ *                     is supported.
  * @fastchannel_init: A common helper used to initialize FC descriptors by
  *                   gathering FC descriptions from the SCMI platform server.
  * @fastchannel_db_ring: A common helper to ring a FC doorbell.
@@ -264,6 +267,8 @@ struct scmi_proto_helpers_ops {
                                    unsigned int max_resources, u8 msg_id,
                                    size_t tx_size, void *priv);
        int (*iter_response_run)(void *iter);
+       int (*protocol_msg_check)(const struct scmi_protocol_handle *ph,
+                                 u32 message_id, u32 *attributes);
        void (*fastchannel_init)(const struct scmi_protocol_handle *ph,
                                 u8 describe_id, u32 message_id,
                                 u32 valid_size, u32 domain,
index 19970d9f9e3677f90c17c3a016c040e541112a51..1b318316535ec4d5c5dc8c454a0a0d6d15155694 100644 (file)
@@ -67,6 +67,7 @@ struct reset_dom_info {
 struct scmi_reset_info {
        u32 version;
        int num_domains;
+       bool notify_reset_cmd;
        struct reset_dom_info *dom_info;
 };
 
@@ -89,18 +90,24 @@ static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph,
        }
 
        ph->xops->xfer_put(ph, t);
+
+       if (!ret)
+               if (!ph->hops->protocol_msg_check(ph, RESET_NOTIFY, NULL))
+                       pi->notify_reset_cmd = true;
+
        return ret;
 }
 
 static int
 scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
-                                u32 domain, struct reset_dom_info *dom_info,
-                                u32 version)
+                                struct scmi_reset_info *pinfo,
+                                u32 domain, u32 version)
 {
        int ret;
        u32 attributes;
        struct scmi_xfer *t;
        struct scmi_msg_resp_reset_domain_attributes *attr;
+       struct reset_dom_info *dom_info = pinfo->dom_info + domain;
 
        ret = ph->xops->xfer_get_init(ph, RESET_DOMAIN_ATTRIBUTES,
                                      sizeof(domain), sizeof(*attr), &t);
@@ -115,7 +122,9 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
                attributes = le32_to_cpu(attr->attributes);
 
                dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes);
-               dom_info->reset_notify = SUPPORTS_NOTIFY_RESET(attributes);
+               if (pinfo->notify_reset_cmd)
+                       dom_info->reset_notify =
+                               SUPPORTS_NOTIFY_RESET(attributes);
                dom_info->latency_us = le32_to_cpu(attr->latency);
                if (dom_info->latency_us == U32_MAX)
                        dom_info->latency_us = 0;
@@ -226,6 +235,20 @@ static const struct scmi_reset_proto_ops reset_proto_ops = {
        .deassert = scmi_reset_domain_deassert,
 };
 
+static bool scmi_reset_notify_supported(const struct scmi_protocol_handle *ph,
+                                       u8 evt_id, u32 src_id)
+{
+       struct reset_dom_info *dom;
+       struct scmi_reset_info *pi = ph->get_priv(ph);
+
+       if (evt_id != SCMI_EVENT_RESET_ISSUED || src_id >= pi->num_domains)
+               return false;
+
+       dom = pi->dom_info + src_id;
+
+       return dom->reset_notify;
+}
+
 static int scmi_reset_notify(const struct scmi_protocol_handle *ph,
                             u32 domain_id, bool enable)
 {
@@ -301,6 +324,7 @@ static const struct scmi_event reset_events[] = {
 };
 
 static const struct scmi_event_ops reset_event_ops = {
+       .is_notify_supported = scmi_reset_notify_supported,
        .get_num_sources = scmi_reset_get_num_sources,
        .set_notify_enabled = scmi_reset_set_notify_enabled,
        .fill_custom_report = scmi_reset_fill_custom_report,
@@ -339,11 +363,8 @@ static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
        if (!pinfo->dom_info)
                return -ENOMEM;
 
-       for (domain = 0; domain < pinfo->num_domains; domain++) {
-               struct reset_dom_info *dom = pinfo->dom_info + domain;
-
-               scmi_reset_domain_attributes_get(ph, domain, dom, version);
-       }
+       for (domain = 0; domain < pinfo->num_domains; domain++)
+               scmi_reset_domain_attributes_get(ph, pinfo, domain, version);
 
        pinfo->version = version;
        return ph->set_priv(ph, pinfo, version);
index 3111499653704695d249a877a0defdf38aef89d4..7fc5535ca34c710f7154ff55c5e53b9e655a828e 100644 (file)
@@ -215,6 +215,8 @@ struct scmi_sensor_update_notify_payld {
 
 struct sensors_info {
        u32 version;
+       bool notify_trip_point_cmd;
+       bool notify_continuos_update_cmd;
        int num_sensors;
        int max_requests;
        u64 reg_addr;
@@ -246,6 +248,18 @@ static int scmi_sensor_attributes_get(const struct scmi_protocol_handle *ph,
        }
 
        ph->xops->xfer_put(ph, t);
+
+       if (!ret) {
+               if (!ph->hops->protocol_msg_check(ph,
+                                                 SENSOR_TRIP_POINT_NOTIFY, NULL))
+                       si->notify_trip_point_cmd = true;
+
+               if (!ph->hops->protocol_msg_check(ph,
+                                                 SENSOR_CONTINUOUS_UPDATE_NOTIFY,
+                                                 NULL))
+                       si->notify_continuos_update_cmd = true;
+       }
+
        return ret;
 }
 
@@ -594,7 +608,8 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
         * Such bitfields are assumed to be zeroed on non
         * relevant fw versions...assuming fw not buggy !
         */
-       s->update = SUPPORTS_UPDATE_NOTIFY(attrl);
+       if (si->notify_continuos_update_cmd)
+               s->update = SUPPORTS_UPDATE_NOTIFY(attrl);
        s->timestamped = SUPPORTS_TIMESTAMP(attrl);
        if (s->timestamped)
                s->tstamp_scale = S32_EXT(SENSOR_TSTAMP_EXP(attrl));
@@ -988,6 +1003,25 @@ static const struct scmi_sensor_proto_ops sensor_proto_ops = {
        .config_set = scmi_sensor_config_set,
 };
 
+static bool scmi_sensor_notify_supported(const struct scmi_protocol_handle *ph,
+                                        u8 evt_id, u32 src_id)
+{
+       bool supported = false;
+       const struct scmi_sensor_info *s;
+       struct sensors_info *sinfo = ph->get_priv(ph);
+
+       s = scmi_sensor_info_get(ph, src_id);
+       if (!s)
+               return false;
+
+       if (evt_id == SCMI_EVENT_SENSOR_TRIP_POINT_EVENT)
+               supported = sinfo->notify_trip_point_cmd;
+       else if (evt_id == SCMI_EVENT_SENSOR_UPDATE)
+               supported = s->update;
+
+       return supported;
+}
+
 static int scmi_sensor_set_notify_enabled(const struct scmi_protocol_handle *ph,
                                          u8 evt_id, u32 src_id, bool enable)
 {
@@ -1099,6 +1133,7 @@ static const struct scmi_event sensor_events[] = {
 };
 
 static const struct scmi_event_ops sensor_event_ops = {
+       .is_notify_supported = scmi_sensor_notify_supported,
        .get_num_sources = scmi_sensor_get_num_sources,
        .set_notify_enabled = scmi_sensor_set_notify_enabled,
        .fill_custom_report = scmi_sensor_fill_custom_report,
index 7611e9665038dc0eeb0d49a36ac84bc52fa03396..39936e1dd30e982c099ba68b0f893df60ed1cd15 100644 (file)
@@ -214,6 +214,13 @@ static int smc_chan_free(int id, void *p, void *data)
        struct scmi_chan_info *cinfo = p;
        struct scmi_smc *scmi_info = cinfo->transport_info;
 
+       /*
+        * Different protocols might share the same chan info, so a previous
+        * smc_chan_free call might have already freed the structure.
+        */
+       if (!scmi_info)
+               return 0;
+
        /* Ignore any possible further reception on the IRQ path */
        if (scmi_info->irq > 0)
                free_irq(scmi_info->irq, scmi_info);
index 1621da97bcbb85d668eb3bd91428d7fc5bec1aa8..b6358c155f7fcac6df05b3287e7dc95e58f5c6e5 100644 (file)
@@ -36,8 +36,20 @@ struct scmi_system_power_state_notifier_payld {
 struct scmi_system_info {
        u32 version;
        bool graceful_timeout_supported;
+       bool power_state_notify_cmd;
 };
 
+static bool scmi_system_notify_supported(const struct scmi_protocol_handle *ph,
+                                        u8 evt_id, u32 src_id)
+{
+       struct scmi_system_info *pinfo = ph->get_priv(ph);
+
+       if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER)
+               return false;
+
+       return pinfo->power_state_notify_cmd;
+}
+
 static int scmi_system_request_notify(const struct scmi_protocol_handle *ph,
                                      bool enable)
 {
@@ -114,6 +126,7 @@ static const struct scmi_event system_events[] = {
 };
 
 static const struct scmi_event_ops system_event_ops = {
+       .is_notify_supported = scmi_system_notify_supported,
        .set_notify_enabled = scmi_system_set_notify_enabled,
        .fill_custom_report = scmi_system_fill_custom_report,
 };
@@ -147,6 +160,9 @@ static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph)
        if (PROTOCOL_REV_MAJOR(pinfo->version) >= 0x2)
                pinfo->graceful_timeout_supported = true;
 
+       if (!ph->hops->protocol_msg_check(ph, SYSTEM_POWER_STATE_NOTIFY, NULL))
+               pinfo->power_state_notify_cmd = true;
+
        return ph->set_priv(ph, pinfo, version);
 }
 
index 3e8d4b51a8140c16720eef8f08d311b024b1a830..97bafb5f7038924fb99eea6f5679b18b2d459e5a 100644 (file)
@@ -292,7 +292,7 @@ static int efi_capsule_open(struct inode *inode, struct file *file)
                return -ENOMEM;
        }
 
-       cap_info->phys = kzalloc(sizeof(void *), GFP_KERNEL);
+       cap_info->phys = kzalloc(sizeof(phys_addr_t), GFP_KERNEL);
        if (!cap_info->phys) {
                kfree(cap_info->pages);
                kfree(cap_info);
index bfa30625f5d03167219a0f62ffc437436ff06693..3dc2f9aaf08db020a74201d2462c2fd2efecef46 100644 (file)
@@ -24,6 +24,8 @@ static bool efi_noinitrd;
 static bool efi_nosoftreserve;
 static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA);
 
+int efi_mem_encrypt;
+
 bool __pure __efi_soft_reserve_enabled(void)
 {
        return !efi_nosoftreserve;
@@ -75,6 +77,12 @@ efi_status_t efi_parse_options(char const *cmdline)
                        efi_noinitrd = true;
                } else if (IS_ENABLED(CONFIG_X86_64) && !strcmp(param, "no5lvl")) {
                        efi_no5lvl = true;
+               } else if (IS_ENABLED(CONFIG_ARCH_HAS_MEM_ENCRYPT) &&
+                          !strcmp(param, "mem_encrypt") && val) {
+                       if (parse_option_str(val, "on"))
+                               efi_mem_encrypt = 1;
+                       else if (parse_option_str(val, "off"))
+                               efi_mem_encrypt = -1;
                } else if (!strcmp(param, "efi") && val) {
                        efi_nochunk = parse_option_str(val, "nochunk");
                        efi_novamap |= parse_option_str(val, "novamap");
index c04b82ea40f2169b6764ff69a14ff3acc5a8795d..fc18fd649ed771a9edad143b263bd4f887f5f467 100644 (file)
@@ -37,8 +37,8 @@ extern bool efi_no5lvl;
 extern bool efi_nochunk;
 extern bool efi_nokaslr;
 extern int efi_loglevel;
+extern int efi_mem_encrypt;
 extern bool efi_novamap;
-
 extern const efi_system_table_t *efi_system_table;
 
 typedef union efi_dxe_services_table efi_dxe_services_table_t;
index 99429bc4b0c7eb0c639b84934fe614f8f8cb5721..0336ed175e671a0ec53b8700a23addaeccddfca5 100644 (file)
@@ -884,6 +884,9 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
                }
        }
 
+       if (efi_mem_encrypt > 0)
+               hdr->xloadflags |= XLF_MEM_ENCRYPTION;
+
        status = efi_decompress_kernel(&kernel_entry);
        if (status != EFI_SUCCESS) {
                efi_err("Failed to decompress kernel\n");
index 81f5f62e34fce04fb6db2db11294f8281c58f5b7..fbeeaee4ac85603783412b2afddd9c5ec6fafd49 100644 (file)
@@ -167,7 +167,7 @@ static int mpfs_auto_update_verify_image(struct fw_upload *fw_uploader)
        u32 *response_msg;
        int ret;
 
-       response_msg = devm_kzalloc(priv->dev, AUTO_UPDATE_FEATURE_RESP_SIZE * sizeof(response_msg),
+       response_msg = devm_kzalloc(priv->dev, AUTO_UPDATE_FEATURE_RESP_SIZE * sizeof(*response_msg),
                                    GFP_KERNEL);
        if (!response_msg)
                return -ENOMEM;
@@ -384,7 +384,8 @@ static int mpfs_auto_update_available(struct mpfs_auto_update_priv *priv)
        u32 *response_msg;
        int ret;
 
-       response_msg = devm_kzalloc(priv->dev, AUTO_UPDATE_FEATURE_RESP_SIZE * sizeof(response_msg),
+       response_msg = devm_kzalloc(priv->dev,
+                                   AUTO_UPDATE_FEATURE_RESP_SIZE * sizeof(*response_msg),
                                    GFP_KERNEL);
        if (!response_msg)
                return -ENOMEM;
index bbcdd9fed3fb61625105121e026c1a70cb01e1e4..4221fed70ad48c8d82b29279ecd47db8d968c973 100644 (file)
@@ -77,7 +77,7 @@ static const char *get_filename(struct tegra_bpmp *bpmp,
 
        root_path_buf = kzalloc(root_path_buf_len, GFP_KERNEL);
        if (!root_path_buf)
-               goto out;
+               return NULL;
 
        root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf,
                                root_path_buf_len);
index e00c333105170f5a2a702593feab340ddc4a7d8e..753e7be039e4d9cd830190d75d8b62ca1219ec96 100644 (file)
@@ -127,8 +127,6 @@ static int gen_74x164_probe(struct spi_device *spi)
        if (IS_ERR(chip->gpiod_oe))
                return PTR_ERR(chip->gpiod_oe);
 
-       gpiod_set_value_cansleep(chip->gpiod_oe, 1);
-
        spi_set_drvdata(spi, chip);
 
        chip->gpio_chip.label = spi->modalias;
@@ -153,6 +151,8 @@ static int gen_74x164_probe(struct spi_device *spi)
                goto exit_destroy;
        }
 
+       gpiod_set_value_cansleep(chip->gpiod_oe, 1);
+
        ret = gpiochip_add_data(&chip->gpio_chip, chip);
        if (!ret)
                return 0;
index 8b3a0f45b57456b13a04ecf4bf706b8cbf27b8dd..75be4a3ca7f8443f55a68aff5185044bbbdaa367 100644 (file)
@@ -968,11 +968,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 
        ret = gpiochip_irqchip_init_valid_mask(gc);
        if (ret)
-               goto err_remove_acpi_chip;
+               goto err_free_hogs;
 
        ret = gpiochip_irqchip_init_hw(gc);
        if (ret)
-               goto err_remove_acpi_chip;
+               goto err_remove_irqchip_mask;
 
        ret = gpiochip_add_irqchip(gc, lock_key, request_key);
        if (ret)
@@ -997,13 +997,13 @@ err_remove_irqchip:
        gpiochip_irqchip_remove(gc);
 err_remove_irqchip_mask:
        gpiochip_irqchip_free_valid_mask(gc);
-err_remove_acpi_chip:
+err_free_hogs:
+       gpiochip_free_hogs(gc);
        acpi_gpiochip_remove(gc);
+       gpiochip_remove_pin_ranges(gc);
 err_remove_of_chip:
-       gpiochip_free_hogs(gc);
        of_gpiochip_remove(gc);
 err_free_gpiochip_mask:
-       gpiochip_remove_pin_ranges(gc);
        gpiochip_free_valid_mask(gc);
 err_remove_from_list:
        spin_lock_irqsave(&gpio_lock, flags);
@@ -2042,6 +2042,11 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_free);
 int gpiochip_generic_config(struct gpio_chip *gc, unsigned int offset,
                            unsigned long config)
 {
+#ifdef CONFIG_PINCTRL
+       if (list_empty(&gc->gpiodev->pin_ranges))
+               return -ENOTSUPP;
+#endif
+
        return pinctrl_gpio_set_config(gc, offset, config);
 }
 EXPORT_SYMBOL_GPL(gpiochip_generic_config);
index 2520db0b776e1bccf213fd541baf6275dbb192eb..c7edba18a6f09c4d3c75af737d94737a0e6f2890 100644 (file)
@@ -199,7 +199,7 @@ config DRM_TTM
 config DRM_TTM_KUNIT_TEST
         tristate "KUnit tests for TTM" if !KUNIT_ALL_TESTS
         default n
-        depends on DRM && KUNIT && MMU
+        depends on DRM && KUNIT && MMU && (UML || COMPILE_TEST)
         select DRM_TTM
         select DRM_EXPORT_FOR_TESTS if m
         select DRM_KUNIT_TEST_HELPERS
@@ -207,7 +207,8 @@ config DRM_TTM_KUNIT_TEST
         help
           Enables unit tests for TTM, a GPU memory manager subsystem used
           to manage memory buffers. This option is mostly useful for kernel
-          developers.
+          developers. It depends on (UML || COMPILE_TEST) since no other driver
+          which uses TTM can be loaded while running the tests.
 
           If in doubt, say "N".
 
index 6dce81a061ab1feff52c48f7b160c5e1c13b1322..79827a6dcd7f5cbbf30d61f6701ecee8ae6614fa 100644 (file)
@@ -200,6 +200,7 @@ extern uint amdgpu_dc_debug_mask;
 extern uint amdgpu_dc_visual_confirm;
 extern uint amdgpu_dm_abm_level;
 extern int amdgpu_backlight;
+extern int amdgpu_damage_clips;
 extern struct amdgpu_mgpu_info mgpu_info;
 extern int amdgpu_ras_enable;
 extern uint amdgpu_ras_mask;
@@ -1549,9 +1550,11 @@ static inline int amdgpu_acpi_smart_shift_update(struct drm_device *dev,
 #if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)
 bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev);
 bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev);
+void amdgpu_choose_low_power_state(struct amdgpu_device *adev);
 #else
 static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; }
 static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { return false; }
+static inline void amdgpu_choose_low_power_state(struct amdgpu_device *adev) { }
 #endif
 
 #if defined(CONFIG_DRM_AMD_DC)
index 2deebece810e78a7ce039772a839684f570bceca..7099ff9cf8c50d7b7ea96149bcef235368fae165 100644 (file)
@@ -1519,4 +1519,22 @@ bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev)
 #endif /* CONFIG_AMD_PMC */
 }
 
+/**
+ * amdgpu_choose_low_power_state
+ *
+ * @adev: amdgpu_device_pointer
+ *
+ * Choose the target low power state for the GPU
+ */
+void amdgpu_choose_low_power_state(struct amdgpu_device *adev)
+{
+       if (adev->in_runpm)
+               return;
+
+       if (amdgpu_acpi_is_s0ix_active(adev))
+               adev->in_s0ix = true;
+       else if (amdgpu_acpi_is_s3_active(adev))
+               adev->in_s3 = true;
+}
+
 #endif /* CONFIG_SUSPEND */
index fdde7488d0ed9a8ff93f4a4cc58c123b904236c7..94bdb5fa6ebc6ac7715a64191b5050a9670bf673 100644 (file)
@@ -4514,13 +4514,15 @@ int amdgpu_device_prepare(struct drm_device *dev)
        struct amdgpu_device *adev = drm_to_adev(dev);
        int i, r;
 
+       amdgpu_choose_low_power_state(adev);
+
        if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
        /* Evict the majority of BOs before starting suspend sequence */
        r = amdgpu_device_evict_resources(adev);
        if (r)
-               return r;
+               goto unprepare;
 
        for (i = 0; i < adev->num_ip_blocks; i++) {
                if (!adev->ip_blocks[i].status.valid)
@@ -4529,10 +4531,15 @@ int amdgpu_device_prepare(struct drm_device *dev)
                        continue;
                r = adev->ip_blocks[i].version->funcs->prepare_suspend((void *)adev);
                if (r)
-                       return r;
+                       goto unprepare;
        }
 
        return 0;
+
+unprepare:
+       adev->in_s0ix = adev->in_s3 = false;
+
+       return r;
 }
 
 /**
@@ -4569,7 +4576,6 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon)
                drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true);
 
        cancel_delayed_work_sync(&adev->delayed_init_work);
-       flush_delayed_work(&adev->gfx.gfx_off_delay_work);
 
        amdgpu_ras_suspend(adev);
 
index 211501ea91694d9f79b84752223f5e6ce60843c1..586f4d03039dfb5177a27fce81fbdbead88e0235 100644 (file)
@@ -211,6 +211,7 @@ int amdgpu_seamless = -1; /* auto */
 uint amdgpu_debug_mask;
 int amdgpu_agp = -1; /* auto */
 int amdgpu_wbrf = -1;
+int amdgpu_damage_clips = -1; /* auto */
 
 static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work);
 
@@ -859,6 +860,18 @@ int amdgpu_backlight = -1;
 MODULE_PARM_DESC(backlight, "Backlight control (0 = pwm, 1 = aux, -1 auto (default))");
 module_param_named(backlight, amdgpu_backlight, bint, 0444);
 
+/**
+ * DOC: damageclips (int)
+ * Enable or disable damage clips support. If damage clips support is disabled,
+ * we will force full frame updates, irrespective of what user space sends to
+ * us.
+ *
+ * Defaults to -1 (where it is enabled unless a PSR-SU display is detected).
+ */
+MODULE_PARM_DESC(damageclips,
+                "Damage clips support (0 = disable, 1 = enable, -1 auto (default))");
+module_param_named(damageclips, amdgpu_damage_clips, int, 0444);
+
 /**
  * DOC: tmz (int)
  * Trusted Memory Zone (TMZ) is a method to protect data being written
index b9674c57c4365fb5ebdf9644fc4ac0a31b955da8..6ddc8e3360e220644618b26059d735e6bbda10e4 100644 (file)
@@ -723,8 +723,15 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable)
 
                if (adev->gfx.gfx_off_req_count == 0 &&
                    !adev->gfx.gfx_off_state) {
-                       schedule_delayed_work(&adev->gfx.gfx_off_delay_work,
+                       /* If going to s2idle, no need to wait */
+                       if (adev->in_s0ix) {
+                               if (!amdgpu_dpm_set_powergating_by_smu(adev,
+                                               AMD_IP_BLOCK_TYPE_GFX, true))
+                                       adev->gfx.gfx_off_state = true;
+                       } else {
+                               schedule_delayed_work(&adev->gfx.gfx_off_delay_work,
                                              delay);
+                       }
                }
        } else {
                if (adev->gfx.gfx_off_req_count == 0) {
index c64c01e2944a2e4c1f4177355771a1b47cfcc666..1c614451deadd10d5dfb29a591fbeb394505ac91 100644 (file)
@@ -574,11 +574,34 @@ soc15_asic_reset_method(struct amdgpu_device *adev)
                return AMD_RESET_METHOD_MODE1;
 }
 
+static bool soc15_need_reset_on_resume(struct amdgpu_device *adev)
+{
+       u32 sol_reg;
+
+       sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81);
+
+       /* Will reset for the following suspend abort cases.
+        * 1) Only reset limit on APU side, dGPU hasn't checked yet.
+        * 2) S3 suspend abort and TOS already launched.
+        */
+       if (adev->flags & AMD_IS_APU && adev->in_s3 &&
+                       !adev->suspend_complete &&
+                       sol_reg)
+               return true;
+
+       return false;
+}
+
 static int soc15_asic_reset(struct amdgpu_device *adev)
 {
        /* original raven doesn't have full asic reset */
-       if ((adev->apu_flags & AMD_APU_IS_RAVEN) ||
-           (adev->apu_flags & AMD_APU_IS_RAVEN2))
+       /* On the latest Raven, the GPU reset can be performed
+        * successfully. So now, temporarily enable it for the
+        * S3 suspend abort case.
+        */
+       if (((adev->apu_flags & AMD_APU_IS_RAVEN) ||
+           (adev->apu_flags & AMD_APU_IS_RAVEN2)) &&
+               !soc15_need_reset_on_resume(adev))
                return 0;
 
        switch (soc15_asic_reset_method(adev)) {
@@ -1298,24 +1321,6 @@ static int soc15_common_suspend(void *handle)
        return soc15_common_hw_fini(adev);
 }
 
-static bool soc15_need_reset_on_resume(struct amdgpu_device *adev)
-{
-       u32 sol_reg;
-
-       sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81);
-
-       /* Will reset for the following suspend abort cases.
-        * 1) Only reset limit on APU side, dGPU hasn't checked yet.
-        * 2) S3 suspend abort and TOS already launched.
-        */
-       if (adev->flags & AMD_IS_APU && adev->in_s3 &&
-                       !adev->suspend_complete &&
-                       sol_reg)
-               return true;
-
-       return false;
-}
-
 static int soc15_common_resume(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
index 48c6efcdeac974ba109224510442b0488e1875d0..4d7188912edfee820dca2ac854b55314dc2f1b27 100644 (file)
@@ -50,13 +50,13 @@ static const struct amd_ip_funcs soc21_common_ip_funcs;
 /* SOC21 */
 static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn0[] = {
        {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)},
-       {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)},
+       {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 0)},
        {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)},
 };
 
 static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn1[] = {
        {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)},
-       {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)},
+       {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 0)},
 };
 
 static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_encode_vcn0 = {
index d722cbd317834a8a893a0ed5a847feb3a51d6961..826bc4f6c8a7043853d0b8e21bad73660c6a8a8c 100644 (file)
@@ -55,8 +55,8 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd,
        m = get_mqd(mqd);
 
        if (has_wa_flag) {
-               uint32_t wa_mask = minfo->update_flag == UPDATE_FLAG_DBG_WA_ENABLE ?
-                                               0xffff : 0xffffffff;
+               uint32_t wa_mask =
+                       (minfo->update_flag & UPDATE_FLAG_DBG_WA_ENABLE) ? 0xffff : 0xffffffff;
 
                m->compute_static_thread_mgmt_se0 = wa_mask;
                m->compute_static_thread_mgmt_se1 = wa_mask;
index 42d881809dc70e230133674e4b12f6f68567837a..697b6d530d12ef30ed06a22d3cf5c15fa740b62a 100644 (file)
@@ -303,6 +303,15 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
                update_cu_mask(mm, mqd, minfo, 0);
        set_priority(m, q);
 
+       if (minfo && KFD_GC_VERSION(mm->dev) >= IP_VERSION(9, 4, 2)) {
+               if (minfo->update_flag & UPDATE_FLAG_IS_GWS)
+                       m->compute_resource_limits |=
+                               COMPUTE_RESOURCE_LIMITS__FORCE_SIMD_DIST_MASK;
+               else
+                       m->compute_resource_limits &=
+                               ~COMPUTE_RESOURCE_LIMITS__FORCE_SIMD_DIST_MASK;
+       }
+
        q->is_active = QUEUE_IS_ACTIVE(*q);
 }
 
index 677281c0793e23a694eb5a7bba9b5f9fd48f61d8..80320b8603fc6692cc5f10426d24f33b5ce0acfa 100644 (file)
@@ -532,6 +532,7 @@ struct queue_properties {
 enum mqd_update_flag {
        UPDATE_FLAG_DBG_WA_ENABLE = 1,
        UPDATE_FLAG_DBG_WA_DISABLE = 2,
+       UPDATE_FLAG_IS_GWS = 4, /* quirk for gfx9 IP */
 };
 
 struct mqd_update_info {
index 43eff221eae58ca008e2e2e92aec09eb749157d7..4858112f9a53b7e491186e0efa0e70dbb92ee47a 100644 (file)
@@ -95,6 +95,7 @@ void kfd_process_dequeue_from_device(struct kfd_process_device *pdd)
 int pqm_set_gws(struct process_queue_manager *pqm, unsigned int qid,
                        void *gws)
 {
+       struct mqd_update_info minfo = {0};
        struct kfd_node *dev = NULL;
        struct process_queue_node *pqn;
        struct kfd_process_device *pdd;
@@ -146,9 +147,10 @@ int pqm_set_gws(struct process_queue_manager *pqm, unsigned int qid,
        }
 
        pdd->qpd.num_gws = gws ? dev->adev->gds.gws_size : 0;
+       minfo.update_flag = gws ? UPDATE_FLAG_IS_GWS : 0;
 
        return pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm,
-                                                       pqn->q, NULL);
+                                                       pqn->q, &minfo);
 }
 
 void kfd_process_dequeue_from_all_devices(struct kfd_process *p)
index e5f7c92eebcbbfa6a1fda115ca2b599cab48e4e8..6ed2ec381aaa320ed1514038a1b6b10c44843019 100644 (file)
@@ -1638,12 +1638,10 @@ static int fill_in_l2_l3_pcache(struct kfd_cache_properties **props_ext,
                else
                        mode = UNKNOWN_MEMORY_PARTITION_MODE;
 
-               if (pcache->cache_level == 2)
-                       pcache->cache_size = pcache_info[cache_type].cache_size * num_xcc;
-               else if (mode)
-                       pcache->cache_size = pcache_info[cache_type].cache_size / mode;
-               else
-                       pcache->cache_size = pcache_info[cache_type].cache_size;
+               pcache->cache_size = pcache_info[cache_type].cache_size;
+               /* Partition mode only affects L3 cache size */
+               if (mode && pcache->cache_level == 3)
+                       pcache->cache_size /= mode;
 
                if (pcache_info[cache_type].flags & CRAT_CACHE_FLAGS_DATA_CACHE)
                        pcache->cache_type |= HSA_CACHE_TYPE_DATA;
index 59d2eee72a3297f4f9b7fbc70040391641f7c67f..1a9bbb04bd5e2c7fb9d29b5c7f2e1d0cd92d978c 100644 (file)
@@ -1843,21 +1843,12 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
                        DRM_ERROR("amdgpu: fail to register dmub aux callback");
                        goto error;
                }
-               if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD, dmub_hpd_callback, true)) {
-                       DRM_ERROR("amdgpu: fail to register dmub hpd callback");
-                       goto error;
-               }
-               if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_IRQ, dmub_hpd_callback, true)) {
-                       DRM_ERROR("amdgpu: fail to register dmub hpd callback");
-                       goto error;
-               }
-       }
-
-       /* Enable outbox notification only after IRQ handlers are registered and DMUB is alive.
-        * It is expected that DMUB will resend any pending notifications at this point, for
-        * example HPD from DPIA.
-        */
-       if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
+               /* Enable outbox notification only after IRQ handlers are registered and DMUB is alive.
+                * It is expected that DMUB will resend any pending notifications at this point. Note
+                * that hpd and hpd_irq handler registration are deferred to register_hpd_handlers() to
+                * align legacy interface initialization sequence. Connection status will be proactivly
+                * detected once in the amdgpu_dm_initialize_drm_device.
+                */
                dc_enable_dmub_outbox(adev->dm.dc);
 
                /* DPIA trace goes to dmesg logs only if outbox is enabled */
@@ -1956,7 +1947,7 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
                                      &adev->dm.dmub_bo_gpu_addr,
                                      &adev->dm.dmub_bo_cpu_addr);
 
-       if (adev->dm.hpd_rx_offload_wq) {
+       if (adev->dm.hpd_rx_offload_wq && adev->dm.dc) {
                for (i = 0; i < adev->dm.dc->caps.max_links; i++) {
                        if (adev->dm.hpd_rx_offload_wq[i].wq) {
                                destroy_workqueue(adev->dm.hpd_rx_offload_wq[i].wq);
@@ -2287,6 +2278,7 @@ static int dm_sw_fini(void *handle)
 
        if (adev->dm.dmub_srv) {
                dmub_srv_destroy(adev->dm.dmub_srv);
+               kfree(adev->dm.dmub_srv);
                adev->dm.dmub_srv = NULL;
        }
 
@@ -3536,6 +3528,14 @@ static void register_hpd_handlers(struct amdgpu_device *adev)
        int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
        int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
 
+       if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
+               if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD, dmub_hpd_callback, true))
+                       DRM_ERROR("amdgpu: fail to register dmub hpd callback");
+
+               if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_IRQ, dmub_hpd_callback, true))
+                       DRM_ERROR("amdgpu: fail to register dmub hpd callback");
+       }
+
        list_for_each_entry(connector,
                        &dev->mode_config.connector_list, head) {
 
@@ -3564,10 +3564,6 @@ static void register_hpd_handlers(struct amdgpu_device *adev)
                                        handle_hpd_rx_irq,
                                        (void *) aconnector);
                }
-
-               if (adev->dm.hpd_rx_offload_wq)
-                       adev->dm.hpd_rx_offload_wq[connector->index].aconnector =
-                               aconnector;
        }
 }
 
@@ -4561,6 +4557,10 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
                        goto fail;
                }
 
+               if (dm->hpd_rx_offload_wq)
+                       dm->hpd_rx_offload_wq[aconnector->base.index].aconnector =
+                               aconnector;
+
                if (!dc_link_detect_connection_type(link, &new_connection_type))
                        DRM_ERROR("KMS: Failed to detect connector\n");
 
@@ -5219,6 +5219,7 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
                                struct drm_plane_state *new_plane_state,
                                struct drm_crtc_state *crtc_state,
                                struct dc_flip_addrs *flip_addrs,
+                               bool is_psr_su,
                                bool *dirty_regions_changed)
 {
        struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
@@ -5243,6 +5244,10 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
        num_clips = drm_plane_get_damage_clips_count(new_plane_state);
        clips = drm_plane_get_damage_clips(new_plane_state);
 
+       if (num_clips && (!amdgpu_damage_clips || (amdgpu_damage_clips < 0 &&
+                                                  is_psr_su)))
+               goto ffu;
+
        if (!dm_crtc_state->mpo_requested) {
                if (!num_clips || num_clips > DC_MAX_DIRTY_RECTS)
                        goto ffu;
@@ -6194,7 +6199,9 @@ create_stream_for_sink(struct drm_connector *connector,
                if (recalculate_timing) {
                        freesync_mode = get_highest_refresh_rate_mode(aconnector, false);
                        drm_mode_copy(&saved_mode, &mode);
+                       saved_mode.picture_aspect_ratio = mode.picture_aspect_ratio;
                        drm_mode_copy(&mode, freesync_mode);
+                       mode.picture_aspect_ratio = saved_mode.picture_aspect_ratio;
                } else {
                        decide_crtc_timing_for_drm_display_mode(
                                        &mode, preferred_mode, scale);
@@ -6527,10 +6534,15 @@ amdgpu_dm_connector_late_register(struct drm_connector *connector)
 static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector)
 {
        struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
-       struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
        struct dc_link *dc_link = aconnector->dc_link;
        struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
        struct edid *edid;
+       struct i2c_adapter *ddc;
+
+       if (dc_link && dc_link->aux_mode)
+               ddc = &aconnector->dm_dp_aux.aux.ddc;
+       else
+               ddc = &aconnector->i2c->base;
 
        /*
         * Note: drm_get_edid gets edid in the following order:
@@ -6538,7 +6550,7 @@ static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector)
         * 2) firmware EDID if set via edid_firmware module parameter
         * 3) regular DDC read.
         */
-       edid = drm_get_edid(connector, &amdgpu_connector->ddc_bus->aux.ddc);
+       edid = drm_get_edid(connector, ddc);
        if (!edid) {
                DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
                return;
@@ -6579,12 +6591,18 @@ static int get_modes(struct drm_connector *connector)
 static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
 {
        struct drm_connector *connector = &aconnector->base;
-       struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(&aconnector->base);
+       struct dc_link *dc_link = aconnector->dc_link;
        struct dc_sink_init_data init_params = {
                        .link = aconnector->dc_link,
                        .sink_signal = SIGNAL_TYPE_VIRTUAL
        };
        struct edid *edid;
+       struct i2c_adapter *ddc;
+
+       if (dc_link->aux_mode)
+               ddc = &aconnector->dm_dp_aux.aux.ddc;
+       else
+               ddc = &aconnector->i2c->base;
 
        /*
         * Note: drm_get_edid gets edid in the following order:
@@ -6592,7 +6610,7 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
         * 2) firmware EDID if set via edid_firmware module parameter
         * 3) regular DDC read.
         */
-       edid = drm_get_edid(connector, &amdgpu_connector->ddc_bus->aux.ddc);
+       edid = drm_get_edid(connector, ddc);
        if (!edid) {
                DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
                return;
@@ -8298,6 +8316,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                        fill_dc_dirty_rects(plane, old_plane_state,
                                            new_plane_state, new_crtc_state,
                                            &bundle->flip_addrs[planes_count],
+                                           acrtc_state->stream->link->psr_settings.psr_version ==
+                                           DC_PSR_VERSION_SU_1,
                                            &dirty_rects_changed);
 
                        /*
@@ -11149,14 +11169,23 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
                                if (range->flags != 1)
                                        continue;
 
-                               amdgpu_dm_connector->min_vfreq = range->min_vfreq;
-                               amdgpu_dm_connector->max_vfreq = range->max_vfreq;
-                               amdgpu_dm_connector->pixel_clock_mhz =
-                                       range->pixel_clock_mhz * 10;
-
                                connector->display_info.monitor_range.min_vfreq = range->min_vfreq;
                                connector->display_info.monitor_range.max_vfreq = range->max_vfreq;
 
+                               if (edid->revision >= 4) {
+                                       if (data->pad2 & DRM_EDID_RANGE_OFFSET_MIN_VFREQ)
+                                               connector->display_info.monitor_range.min_vfreq += 255;
+                                       if (data->pad2 & DRM_EDID_RANGE_OFFSET_MAX_VFREQ)
+                                               connector->display_info.monitor_range.max_vfreq += 255;
+                               }
+
+                               amdgpu_dm_connector->min_vfreq =
+                                       connector->display_info.monitor_range.min_vfreq;
+                               amdgpu_dm_connector->max_vfreq =
+                                       connector->display_info.monitor_range.max_vfreq;
+                               amdgpu_dm_connector->pixel_clock_mhz =
+                                       range->pixel_clock_mhz * 10;
+
                                break;
                        }
 
index 85b7f58a7f35a478f551ec097b1613b504ced535..c27063305a1341c677c95e91dd49eb4fca1ea94a 100644 (file)
@@ -67,6 +67,8 @@ static void apply_edid_quirks(struct edid *edid, struct dc_edid_caps *edid_caps)
        /* Workaround for some monitors that do not clear DPCD 0x317 if FreeSync is unsupported */
        case drm_edid_encode_panel_id('A', 'U', 'O', 0xA7AB):
        case drm_edid_encode_panel_id('A', 'U', 'O', 0xE69B):
+       case drm_edid_encode_panel_id('B', 'O', 'E', 0x092A):
+       case drm_edid_encode_panel_id('L', 'G', 'D', 0x06D1):
                DRM_DEBUG_DRIVER("Clearing DPCD 0x317 on monitor with panel id %X\n", panel_id);
                edid_caps->panel_patch.remove_sink_ext_caps = true;
                break;
@@ -120,6 +122,8 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
 
        edid_caps->edid_hdmi = connector->display_info.is_hdmi;
 
+       apply_edid_quirks(edid_buf, edid_caps);
+
        sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
        if (sad_count <= 0)
                return result;
@@ -146,8 +150,6 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
        else
                edid_caps->speaker_flags = DEFAULT_SPEAKER_LOCATION;
 
-       apply_edid_quirks(edid_buf, edid_caps);
-
        kfree(sads);
        kfree(sadb);
 
index f2dfa96f9ef5d9e4805fdbf592cac078efa391a5..39530b2ea4957cc0a6718f322158e101f15431d0 100644 (file)
@@ -94,7 +94,7 @@ static void calculate_bandwidth(
        const uint32_t s_high = 7;
        const uint32_t dmif_chunk_buff_margin = 1;
 
-       uint32_t max_chunks_fbc_mode;
+       uint32_t max_chunks_fbc_mode = 0;
        int32_t num_cursor_lines;
 
        int32_t i, j, k;
index 960c4b4f6ddf3670156abd99cc0a02aeb176c7dc..05f392501c0ae3572250061b31defef7cde51fb5 100644 (file)
@@ -1850,19 +1850,21 @@ static enum bp_result get_firmware_info_v3_2(
                /* Vega12 */
                smu_info_v3_2 = GET_IMAGE(struct atom_smu_info_v3_2,
                                                        DATA_TABLES(smu_info));
-               DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_2->gpuclk_ss_percentage);
                if (!smu_info_v3_2)
                        return BP_RESULT_BADBIOSTABLE;
 
+               DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_2->gpuclk_ss_percentage);
+
                info->default_engine_clk = smu_info_v3_2->bootup_dcefclk_10khz * 10;
        } else if (revision.minor == 3) {
                /* Vega20 */
                smu_info_v3_3 = GET_IMAGE(struct atom_smu_info_v3_3,
                                                        DATA_TABLES(smu_info));
-               DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_3->gpuclk_ss_percentage);
                if (!smu_info_v3_3)
                        return BP_RESULT_BADBIOSTABLE;
 
+               DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_3->gpuclk_ss_percentage);
+
                info->default_engine_clk = smu_info_v3_3->bootup_dcefclk_10khz * 10;
        }
 
@@ -2422,10 +2424,11 @@ static enum bp_result get_integrated_info_v11(
        info_v11 = GET_IMAGE(struct atom_integrated_system_info_v1_11,
                                        DATA_TABLES(integratedsysteminfo));
 
-       DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v11->gpuclk_ss_percentage);
        if (info_v11 == NULL)
                return BP_RESULT_BADBIOSTABLE;
 
+       DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v11->gpuclk_ss_percentage);
+
        info->gpu_cap_info =
        le32_to_cpu(info_v11->gpucapinfo);
        /*
@@ -2637,11 +2640,12 @@ static enum bp_result get_integrated_info_v2_1(
 
        info_v2_1 = GET_IMAGE(struct atom_integrated_system_info_v2_1,
                                        DATA_TABLES(integratedsysteminfo));
-       DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_1->gpuclk_ss_percentage);
 
        if (info_v2_1 == NULL)
                return BP_RESULT_BADBIOSTABLE;
 
+       DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_1->gpuclk_ss_percentage);
+
        info->gpu_cap_info =
        le32_to_cpu(info_v2_1->gpucapinfo);
        /*
@@ -2799,11 +2803,11 @@ static enum bp_result get_integrated_info_v2_2(
        info_v2_2 = GET_IMAGE(struct atom_integrated_system_info_v2_2,
                                        DATA_TABLES(integratedsysteminfo));
 
-       DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_2->gpuclk_ss_percentage);
-
        if (info_v2_2 == NULL)
                return BP_RESULT_BADBIOSTABLE;
 
+       DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_2->gpuclk_ss_percentage);
+
        info->gpu_cap_info =
        le32_to_cpu(info_v2_2->gpucapinfo);
        /*
index a5489fe6875f453149d622d59e9b6417b4db616c..aa9fd1dc550a5e8b2142cfb10db96f4779bdc788 100644 (file)
@@ -546,6 +546,8 @@ static unsigned int find_dcfclk_for_voltage(const struct vg_dpm_clocks *clock_ta
        int i;
 
        for (i = 0; i < VG_NUM_SOC_VOLTAGE_LEVELS; i++) {
+               if (i >= VG_NUM_DCFCLK_DPM_LEVELS)
+                       break;
                if (clock_table->SocVoltage[i] == voltage)
                        return clock_table->DcfClocks[i];
        }
index 14cec1c7b718c4ab48fbd9588f4b6465c13897cd..e648902592358ff08ca3a536d9f0abe56bfe5e34 100644 (file)
@@ -655,10 +655,13 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk
        struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1];
        uint32_t max_fclk = 0, min_pstate = 0, max_dispclk = 0, max_dppclk = 0;
        uint32_t max_pstate = 0, max_dram_speed_mts = 0, min_dram_speed_mts = 0;
+       uint32_t num_memps, num_fclk, num_dcfclk;
        int i;
 
        /* Determine min/max p-state values. */
-       for (i = 0; i < clock_table->NumMemPstatesEnabled; i++) {
+       num_memps = (clock_table->NumMemPstatesEnabled > NUM_MEM_PSTATE_LEVELS) ? NUM_MEM_PSTATE_LEVELS :
+               clock_table->NumMemPstatesEnabled;
+       for (i = 0; i < num_memps; i++) {
                uint32_t dram_speed_mts = calc_dram_speed_mts(&clock_table->MemPstateTable[i]);
 
                if (is_valid_clock_value(dram_speed_mts) && dram_speed_mts > max_dram_speed_mts) {
@@ -670,7 +673,7 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk
        min_dram_speed_mts = max_dram_speed_mts;
        min_pstate = max_pstate;
 
-       for (i = 0; i < clock_table->NumMemPstatesEnabled; i++) {
+       for (i = 0; i < num_memps; i++) {
                uint32_t dram_speed_mts = calc_dram_speed_mts(&clock_table->MemPstateTable[i]);
 
                if (is_valid_clock_value(dram_speed_mts) && dram_speed_mts < min_dram_speed_mts) {
@@ -699,9 +702,13 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk
        /* Base the clock table on dcfclk, need at least one entry regardless of pmfw table */
        ASSERT(clock_table->NumDcfClkLevelsEnabled > 0);
 
-       max_fclk = find_max_clk_value(clock_table->FclkClocks_Freq, clock_table->NumFclkLevelsEnabled);
+       num_fclk = (clock_table->NumFclkLevelsEnabled > NUM_FCLK_DPM_LEVELS) ? NUM_FCLK_DPM_LEVELS :
+               clock_table->NumFclkLevelsEnabled;
+       max_fclk = find_max_clk_value(clock_table->FclkClocks_Freq, num_fclk);
 
-       for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) {
+       num_dcfclk = (clock_table->NumFclkLevelsEnabled > NUM_DCFCLK_DPM_LEVELS) ? NUM_DCFCLK_DPM_LEVELS :
+               clock_table->NumDcfClkLevelsEnabled;
+       for (i = 0; i < num_dcfclk; i++) {
                int j;
 
                /* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */
index 2b79a0e5638e1b757ea3d3527add517db139552e..363d522603a21744c02e3e3497a2907862b02fd1 100644 (file)
@@ -125,7 +125,7 @@ bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
                unsigned int count,
                union dmub_rb_cmd *cmd_list)
 {
-       struct dc_context *dc_ctx = dc_dmub_srv->ctx;
+       struct dc_context *dc_ctx;
        struct dmub_srv *dmub;
        enum dmub_status status;
        int i;
@@ -133,6 +133,7 @@ bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
        if (!dc_dmub_srv || !dc_dmub_srv->dmub)
                return false;
 
+       dc_ctx = dc_dmub_srv->ctx;
        dmub = dc_dmub_srv->dmub;
 
        for (i = 0 ; i < count; i++) {
@@ -1161,7 +1162,7 @@ void dc_dmub_srv_subvp_save_surf_addr(const struct dc_dmub_srv *dc_dmub_srv, con
 
 bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait)
 {
-       struct dc_context *dc_ctx = dc_dmub_srv->ctx;
+       struct dc_context *dc_ctx;
        enum dmub_status status;
 
        if (!dc_dmub_srv || !dc_dmub_srv->dmub)
@@ -1170,6 +1171,8 @@ bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait)
        if (dc_dmub_srv->ctx->dc->debug.dmcub_emulation)
                return true;
 
+       dc_ctx = dc_dmub_srv->ctx;
+
        if (wait) {
                if (dc_dmub_srv->ctx->dc->debug.disable_timeout) {
                        do {
index e8570060d007ba5bab0db3b3395aca2b9c487573..5bca67407c5b16b682ed669ef2b6382be7965b1b 100644 (file)
@@ -290,4 +290,5 @@ void dce_panel_cntl_construct(
        dce_panel_cntl->base.funcs = &dce_link_panel_cntl_funcs;
        dce_panel_cntl->base.ctx = init_data->ctx;
        dce_panel_cntl->base.inst = init_data->inst;
+       dce_panel_cntl->base.pwrseq_inst = 0;
 }
index e43f77c11c00825aad64ada6ddfb4b0bdce23aff..5f97a868ada34734d99a6a35a329d9c3cd3c5ac2 100644 (file)
@@ -56,16 +56,13 @@ static void dpp3_enable_cm_block(
 
 static enum dc_lut_mode dpp30_get_gamcor_current(struct dpp *dpp_base)
 {
-       enum dc_lut_mode mode;
+       enum dc_lut_mode mode = LUT_BYPASS;
        uint32_t state_mode;
        uint32_t lut_mode;
        struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base);
 
        REG_GET(CM_GAMCOR_CONTROL, CM_GAMCOR_MODE_CURRENT, &state_mode);
 
-       if (state_mode == 0)
-               mode = LUT_BYPASS;
-
        if (state_mode == 2) {//Programmable RAM LUT
                REG_GET(CM_GAMCOR_CONTROL, CM_GAMCOR_SELECT_CURRENT, &lut_mode);
                if (lut_mode == 0)
index ad0df1a72a90ab4ff13b267f1c69392e68703884..9e96a3ace2077cb53bff30f5984a5391a017d239 100644 (file)
@@ -215,4 +215,5 @@ void dcn301_panel_cntl_construct(
        dcn301_panel_cntl->base.funcs = &dcn301_link_panel_cntl_funcs;
        dcn301_panel_cntl->base.ctx = init_data->ctx;
        dcn301_panel_cntl->base.inst = init_data->inst;
+       dcn301_panel_cntl->base.pwrseq_inst = 0;
 }
index 03248422d6ffde2d6923fb33185bf8dd12607787..281be20b1a1071576a4ca9037ee105333268801e 100644 (file)
@@ -154,8 +154,24 @@ void dcn31_panel_cntl_construct(
        struct dcn31_panel_cntl *dcn31_panel_cntl,
        const struct panel_cntl_init_data *init_data)
 {
+       uint8_t pwrseq_inst = 0xF;
+
        dcn31_panel_cntl->base.funcs = &dcn31_link_panel_cntl_funcs;
        dcn31_panel_cntl->base.ctx = init_data->ctx;
        dcn31_panel_cntl->base.inst = init_data->inst;
-       dcn31_panel_cntl->base.pwrseq_inst = init_data->pwrseq_inst;
+
+       switch (init_data->eng_id) {
+       case ENGINE_ID_DIGA:
+               pwrseq_inst = 0;
+               break;
+       case ENGINE_ID_DIGB:
+               pwrseq_inst = 1;
+               break;
+       default:
+               DC_LOG_WARNING("Unsupported pwrseq engine id: %d!\n", init_data->eng_id);
+               ASSERT(false);
+               break;
+       }
+
+       dcn31_panel_cntl->base.pwrseq_inst = pwrseq_inst;
 }
index ba76dd4a2ce29a68a75883b8e8538395195b4089..a0a65e0991041d90904c516c7279c5b8aa76967c 100644 (file)
@@ -2760,7 +2760,7 @@ static int build_synthetic_soc_states(bool disable_dc_mode_overwrite, struct clk
        struct _vcs_dpi_voltage_scaling_st entry = {0};
        struct clk_limit_table_entry max_clk_data = {0};
 
-       unsigned int min_dcfclk_mhz = 399, min_fclk_mhz = 599;
+       unsigned int min_dcfclk_mhz = 199, min_fclk_mhz = 299;
 
        static const unsigned int num_dcfclk_stas = 5;
        unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {199, 615, 906, 1324, 1564};
index 23a608274096f89002e7e5438be18c85d023e442..1ba6933d2b3617aa6d275647d17320dd0755ae69 100644 (file)
@@ -398,7 +398,6 @@ void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc,
        /* Copy clocks tables entries, if available */
        if (dml2->config.bbox_overrides.clks_table.num_states) {
                p->in_states->num_states = dml2->config.bbox_overrides.clks_table.num_states;
-
                for (i = 0; i < dml2->config.bbox_overrides.clks_table.num_entries_per_clk.num_dcfclk_levels; i++) {
                        p->in_states->state_array[i].dcfclk_mhz = dml2->config.bbox_overrides.clks_table.clk_entries[i].dcfclk_mhz;
                }
@@ -437,6 +436,14 @@ void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc,
        }
 
        dml2_policy_build_synthetic_soc_states(s, p);
+       if (dml2->v20.dml_core_ctx.project == dml_project_dcn35 ||
+               dml2->v20.dml_core_ctx.project == dml_project_dcn351) {
+               // Override last out_state with data from last in_state
+               // This will ensure that out_state contains max fclk
+               memcpy(&p->out_states->state_array[p->out_states->num_states - 1],
+                               &p->in_states->state_array[p->in_states->num_states - 1],
+                               sizeof(struct soc_state_bounding_box_st));
+       }
 }
 
 void dml2_translate_ip_params(const struct dc *in, struct ip_params_st *out)
index 26307e599614c6e1212c53184ba02849ae6e1dbb..2a58a7687bdb5779db6c639d3cbf2277aaf231ae 100644 (file)
@@ -76,6 +76,11 @@ static void map_hw_resources(struct dml2_context *dml2,
                        in_out_display_cfg->hw.DLGRefClkFreqMHz = 50;
                }
                for (j = 0; j < mode_support_info->DPPPerSurface[i]; j++) {
+                       if (i >= __DML2_WRAPPER_MAX_STREAMS_PLANES__) {
+                               dml_print("DML::%s: Index out of bounds: i=%d, __DML2_WRAPPER_MAX_STREAMS_PLANES__=%d\n",
+                                         __func__, i, __DML2_WRAPPER_MAX_STREAMS_PLANES__);
+                               break;
+                       }
                        dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id[num_pipes] = dml2->v20.scratch.dml_to_dc_pipe_mapping.disp_cfg_to_stream_id[i];
                        dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id_valid[num_pipes] = true;
                        dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id[num_pipes] = dml2->v20.scratch.dml_to_dc_pipe_mapping.disp_cfg_to_plane_id[i];
index 5c7f380a84f91ecb1a668e4798be6aaf9347a46f..7252f5f781f0d7869e147846bc1eb44f09e63593 100644 (file)
@@ -211,7 +211,7 @@ void dcn21_set_pipe(struct pipe_ctx *pipe_ctx)
        struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu;
        uint32_t otg_inst;
 
-       if (!abm && !tg && !panel_cntl)
+       if (!abm || !tg || !panel_cntl)
                return;
 
        otg_inst = tg->inst;
@@ -245,7 +245,7 @@ bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx,
        struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl;
        uint32_t otg_inst;
 
-       if (!abm && !tg && !panel_cntl)
+       if (!abm || !tg || !panel_cntl)
                return false;
 
        otg_inst = tg->inst;
index 5dcbaa2db964aee7de17c2e9306606cac1817b08..e97d964a1791cefb2eb47c91780a41e3682baed0 100644 (file)
@@ -57,7 +57,7 @@ struct panel_cntl_funcs {
 struct panel_cntl_init_data {
        struct dc_context *ctx;
        uint32_t inst;
-       uint32_t pwrseq_inst;
+       uint32_t eng_id;
 };
 
 struct panel_cntl {
index 37d3027c32dcb1007dbb90e209f7f459be81617e..cf22b8f28ba6c65394a536465143d1c2f81bd2b6 100644 (file)
@@ -370,30 +370,6 @@ static enum transmitter translate_encoder_to_transmitter(
        }
 }
 
-static uint8_t translate_dig_inst_to_pwrseq_inst(struct dc_link *link)
-{
-       uint8_t pwrseq_inst = 0xF;
-       struct dc_context *dc_ctx = link->dc->ctx;
-
-       DC_LOGGER_INIT(dc_ctx->logger);
-
-       switch (link->eng_id) {
-       case ENGINE_ID_DIGA:
-               pwrseq_inst = 0;
-               break;
-       case ENGINE_ID_DIGB:
-               pwrseq_inst = 1;
-               break;
-       default:
-               DC_LOG_WARNING("Unsupported pwrseq engine id: %d!\n", link->eng_id);
-               ASSERT(false);
-               break;
-       }
-
-       return pwrseq_inst;
-}
-
-
 static void link_destruct(struct dc_link *link)
 {
        int i;
@@ -657,7 +633,7 @@ static bool construct_phy(struct dc_link *link,
                        link->link_id.id == CONNECTOR_ID_LVDS)) {
                panel_cntl_init_data.ctx = dc_ctx;
                panel_cntl_init_data.inst = panel_cntl_init_data.ctx->dc_edp_id_count;
-               panel_cntl_init_data.pwrseq_inst = translate_dig_inst_to_pwrseq_inst(link);
+               panel_cntl_init_data.eng_id = link->eng_id;
                link->panel_cntl =
                        link->dc->res_pool->funcs->panel_cntl_create(
                                                                &panel_cntl_init_data);
index 8fe66c3678508d9aee6779fa25cd6128e1f30832..5b0bc7f6a188ccd6b304a369be0bdfe43b91f76a 100644 (file)
@@ -361,7 +361,7 @@ bool link_validate_dpia_bandwidth(const struct dc_stream_state *stream, const un
        struct dc_link *dpia_link[MAX_DPIA_NUM] = {0};
        int num_dpias = 0;
 
-       for (uint8_t i = 0; i < num_streams; ++i) {
+       for (unsigned int i = 0; i < num_streams; ++i) {
                if (stream[i].signal == SIGNAL_TYPE_DISPLAY_PORT) {
                        /* new dpia sst stream, check whether it exceeds max dpia */
                        if (num_dpias >= MAX_DPIA_NUM)
index 5a0b0451895690d184ec00c56873f0d1acad6864..16a62e01871224495cd771c4042f04d3be85e04d 100644 (file)
@@ -517,6 +517,7 @@ enum link_training_result dp_check_link_loss_status(
 {
        enum link_training_result status = LINK_TRAINING_SUCCESS;
        union lane_status lane_status;
+       union lane_align_status_updated dpcd_lane_status_updated;
        uint8_t dpcd_buf[6] = {0};
        uint32_t lane;
 
@@ -532,10 +533,12 @@ enum link_training_result dp_check_link_loss_status(
                 * check lanes status
                 */
                lane_status.raw = dp_get_nibble_at_index(&dpcd_buf[2], lane);
+               dpcd_lane_status_updated.raw = dpcd_buf[4];
 
                if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
                        !lane_status.bits.CR_DONE_0 ||
-                       !lane_status.bits.SYMBOL_LOCKED_0) {
+                       !lane_status.bits.SYMBOL_LOCKED_0 ||
+                       !dp_is_interlane_aligned(dpcd_lane_status_updated)) {
                        /* if one of the channel equalization, clock
                         * recovery or symbol lock is dropped
                         * consider it as (link has been
index e8dda44b23cb29aa3ec2686b6656bd044c194606..5d36bab0029ca54a03aaef4fc83ff99e59550e5a 100644 (file)
@@ -619,7 +619,7 @@ static enum link_training_result dpia_training_eq_non_transparent(
        uint32_t retries_eq = 0;
        enum dc_status status;
        enum dc_dp_training_pattern tr_pattern;
-       uint32_t wait_time_microsec;
+       uint32_t wait_time_microsec = 0;
        enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
        union lane_align_status_updated dpcd_lane_status_updated = {0};
        union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
index 1c3d89264ef72c56251e09549cde90f8d78ce91a..5fdcda8f86026d94697a069ed53a83752a0ebdee 100644 (file)
@@ -780,7 +780,7 @@ static const struct dc_debug_options debug_defaults_drv = {
        .disable_z10 = false,
        .ignore_pg = true,
        .psp_disabled_wa = true,
-       .ips2_eval_delay_us = 1650,
+       .ips2_eval_delay_us = 2000,
        .ips2_entry_delay_us = 800,
        .static_screen_wait_frames = 2,
 };
index 087d57850304c45193a7f5de336953c1dec9cbba..39c5e1dfa275a64f32fa358d875efc6d0bd99682 100644 (file)
@@ -2558,6 +2558,7 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev,
 {
        struct amdgpu_device *adev = dev_get_drvdata(dev);
        int err, ret;
+       u32 pwm_mode;
        int value;
 
        if (amdgpu_in_reset(adev))
@@ -2569,13 +2570,22 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev,
        if (err)
                return err;
 
+       if (value == 0)
+               pwm_mode = AMD_FAN_CTRL_NONE;
+       else if (value == 1)
+               pwm_mode = AMD_FAN_CTRL_MANUAL;
+       else if (value == 2)
+               pwm_mode = AMD_FAN_CTRL_AUTO;
+       else
+               return -EINVAL;
+
        ret = pm_runtime_get_sync(adev_to_drm(adev)->dev);
        if (ret < 0) {
                pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
                return ret;
        }
 
-       ret = amdgpu_dpm_set_fan_control_mode(adev, value);
+       ret = amdgpu_dpm_set_fan_control_mode(adev, pwm_mode);
 
        pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
        pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
index df4f20293c16a368748cd4138c0912906f80acc7..eb4da3666e05d6d145a927258d7ea247425dad93 100644 (file)
@@ -6925,6 +6925,23 @@ static int si_dpm_enable(struct amdgpu_device *adev)
        return 0;
 }
 
+static int si_set_temperature_range(struct amdgpu_device *adev)
+{
+       int ret;
+
+       ret = si_thermal_enable_alert(adev, false);
+       if (ret)
+               return ret;
+       ret = si_thermal_set_temperature_range(adev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+       if (ret)
+               return ret;
+       ret = si_thermal_enable_alert(adev, true);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
 static void si_dpm_disable(struct amdgpu_device *adev)
 {
        struct rv7xx_power_info *pi = rv770_get_pi(adev);
@@ -7608,6 +7625,18 @@ static int si_dpm_process_interrupt(struct amdgpu_device *adev,
 
 static int si_dpm_late_init(void *handle)
 {
+       int ret;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!adev->pm.dpm_enabled)
+               return 0;
+
+       ret = si_set_temperature_range(adev);
+       if (ret)
+               return ret;
+#if 0 //TODO ?
+       si_dpm_powergate_uvd(adev, true);
+#endif
        return 0;
 }
 
index 4cd43bbec910e351eb27a79b4c39308d6462d196..bcad42534da46d780423d636953c40993e7001ac 100644 (file)
@@ -1303,13 +1303,12 @@ static int arcturus_get_power_limit(struct smu_context *smu,
        if (default_power_limit)
                *default_power_limit = power_limit;
 
-       if (smu->od_enabled) {
+       if (smu->od_enabled)
                od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
-               od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
-       } else {
+       else
                od_percent_upper = 0;
-               od_percent_lower = 100;
-       }
+
+       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
 
        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);
index 8d1d29ffb0f1c54a781c2508447454f9bb7aa5ee..ed189a3878ebe7199833e495f45417461897a93a 100644 (file)
@@ -2357,13 +2357,12 @@ static int navi10_get_power_limit(struct smu_context *smu,
                *default_power_limit = power_limit;
 
        if (smu->od_enabled &&
-                   navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) {
+                   navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT))
                od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
-               od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
-       } else {
+       else
                od_percent_upper = 0;
-               od_percent_lower = 100;
-       }
+
+       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
 
        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);
index 21fc033528fa9d1a57ea2699a2780501e2902b3c..e2ad2b972ab0b3550d7aceb66e632eb372a0ffc5 100644 (file)
@@ -640,13 +640,12 @@ static int sienna_cichlid_get_power_limit(struct smu_context *smu,
        if (default_power_limit)
                *default_power_limit = power_limit;
 
-       if (smu->od_enabled) {
+       if (smu->od_enabled)
                od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
-               od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
-       } else {
+       else
                od_percent_upper = 0;
-               od_percent_lower = 100;
-       }
+
+       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
 
        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);
index 2ff6deedef955ec3a77cc4f2edf0884ed518c535..da1f43999d0947d0c57246414d300b0aff5c415e 100644 (file)
@@ -451,7 +451,7 @@ static int vangogh_init_smc_tables(struct smu_context *smu)
 
 #ifdef CONFIG_X86
        /* AMD x86 APU only */
-       smu->cpu_core_num = boot_cpu_data.x86_max_cores;
+       smu->cpu_core_num = topology_num_cores_per_package();
 #else
        smu->cpu_core_num = 4;
 #endif
index a9954ffc02c562b91bf1166bb4bf87208152b36a..9b80f18ea6c359f279f050ee9f645b92dd43d057 100644 (file)
@@ -2369,13 +2369,12 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
        if (default_power_limit)
                *default_power_limit = power_limit;
 
-       if (smu->od_enabled) {
+       if (smu->od_enabled)
                od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
-               od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
-       } else {
+       else
                od_percent_upper = 0;
-               od_percent_lower = 100;
-       }
+
+       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
 
        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);
index 0ffdb58af74e654af7ca73acf078415663f41dfe..3dc7b60cb0754d0f62fd3cead74f1553071b8597 100644 (file)
@@ -2333,13 +2333,12 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
        if (default_power_limit)
                *default_power_limit = power_limit;
 
-       if (smu->od_enabled) {
+       if (smu->od_enabled)
                od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
-               od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
-       } else {
+       else
                od_percent_upper = 0;
-               od_percent_lower = 100;
-       }
+
+       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
 
        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);
index 4894f7ee737b41dd0e81503b5cb7f3fc1182a6e6..6dae5ad74ff081c4616304ada3a6af302cc21f87 100644 (file)
@@ -229,8 +229,6 @@ int smu_v14_0_check_fw_version(struct smu_context *smu)
                smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_2;
                break;
        case IP_VERSION(14, 0, 0):
-               if ((smu->smc_fw_version < 0x5d3a00))
-                       dev_warn(smu->adev->dev, "The PMFW version(%x) is behind in this BIOS!\n", smu->smc_fw_version);
                smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_0;
                break;
        default:
index 47fdbae4adfc0207f628c8e2e156703b960e5829..9310c4758e38ce9791ba8d61ce61a2face051fe8 100644 (file)
@@ -261,7 +261,10 @@ static int smu_v14_0_0_get_smu_metrics_data(struct smu_context *smu,
                *value = metrics->MpipuclkFrequency;
                break;
        case METRICS_AVERAGE_GFXACTIVITY:
-               *value = metrics->GfxActivity / 100;
+               if ((smu->smc_fw_version > 0x5d4600))
+                       *value = metrics->GfxActivity;
+               else
+                       *value = metrics->GfxActivity / 100;
                break;
        case METRICS_AVERAGE_VCNACTIVITY:
                *value = metrics->VcnActivity / 100;
index bb55f697a1819264e1320f6118d28dd776236f4f..6886db2d9e00c4544ee3d81e29e779f806c8a9b7 100644 (file)
@@ -25,20 +25,18 @@ static void drm_aux_hpd_bridge_release(struct device *dev)
        ida_free(&drm_aux_hpd_bridge_ida, adev->id);
 
        of_node_put(adev->dev.platform_data);
+       of_node_put(adev->dev.of_node);
 
        kfree(adev);
 }
 
-static void drm_aux_hpd_bridge_unregister_adev(void *_adev)
+static void drm_aux_hpd_bridge_free_adev(void *_adev)
 {
-       struct auxiliary_device *adev = _adev;
-
-       auxiliary_device_delete(adev);
-       auxiliary_device_uninit(adev);
+       auxiliary_device_uninit(_adev);
 }
 
 /**
- * drm_dp_hpd_bridge_register - Create a simple HPD DisplayPort bridge
+ * devm_drm_dp_hpd_bridge_alloc - allocate a HPD DisplayPort bridge
  * @parent: device instance providing this bridge
  * @np: device node pointer corresponding to this bridge instance
  *
@@ -46,11 +44,9 @@ static void drm_aux_hpd_bridge_unregister_adev(void *_adev)
  * DRM_MODE_CONNECTOR_DisplayPort, which terminates the bridge chain and is
  * able to send the HPD events.
  *
- * Return: device instance that will handle created bridge or an error code
- * encoded into the pointer.
+ * Return: bridge auxiliary device pointer or an error pointer
  */
-struct device *drm_dp_hpd_bridge_register(struct device *parent,
-                                         struct device_node *np)
+struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent, struct device_node *np)
 {
        struct auxiliary_device *adev;
        int ret;
@@ -74,18 +70,62 @@ struct device *drm_dp_hpd_bridge_register(struct device *parent,
 
        ret = auxiliary_device_init(adev);
        if (ret) {
+               of_node_put(adev->dev.platform_data);
+               of_node_put(adev->dev.of_node);
                ida_free(&drm_aux_hpd_bridge_ida, adev->id);
                kfree(adev);
                return ERR_PTR(ret);
        }
 
-       ret = auxiliary_device_add(adev);
-       if (ret) {
-               auxiliary_device_uninit(adev);
+       ret = devm_add_action_or_reset(parent, drm_aux_hpd_bridge_free_adev, adev);
+       if (ret)
                return ERR_PTR(ret);
-       }
 
-       ret = devm_add_action_or_reset(parent, drm_aux_hpd_bridge_unregister_adev, adev);
+       return adev;
+}
+EXPORT_SYMBOL_GPL(devm_drm_dp_hpd_bridge_alloc);
+
+static void drm_aux_hpd_bridge_del_adev(void *_adev)
+{
+       auxiliary_device_delete(_adev);
+}
+
+/**
+ * devm_drm_dp_hpd_bridge_add - register a HDP DisplayPort bridge
+ * @dev: struct device to tie registration lifetime to
+ * @adev: bridge auxiliary device to be registered
+ *
+ * Returns: zero on success or a negative errno
+ */
+int devm_drm_dp_hpd_bridge_add(struct device *dev, struct auxiliary_device *adev)
+{
+       int ret;
+
+       ret = auxiliary_device_add(adev);
+       if (ret)
+               return ret;
+
+       return devm_add_action_or_reset(dev, drm_aux_hpd_bridge_del_adev, adev);
+}
+EXPORT_SYMBOL_GPL(devm_drm_dp_hpd_bridge_add);
+
+/**
+ * drm_dp_hpd_bridge_register - allocate and register a HDP DisplayPort bridge
+ * @parent: device instance providing this bridge
+ * @np: device node pointer corresponding to this bridge instance
+ *
+ * Return: device instance that will handle created bridge or an error pointer
+ */
+struct device *drm_dp_hpd_bridge_register(struct device *parent, struct device_node *np)
+{
+       struct auxiliary_device *adev;
+       int ret;
+
+       adev = devm_drm_dp_hpd_bridge_alloc(parent, np);
+       if (IS_ERR(adev))
+               return ERR_CAST(adev);
+
+       ret = devm_drm_dp_hpd_bridge_add(parent, adev);
        if (ret)
                return ERR_PTR(ret);
 
index f57e6d74fb0e039a710b9bd8161a8e8e25d5888b..5ebdd6f8f36e6bc8d67e99a54bac3856d45ac9eb 100644 (file)
@@ -332,6 +332,7 @@ alloc_range_bias(struct drm_buddy *mm,
                 u64 start, u64 end,
                 unsigned int order)
 {
+       u64 req_size = mm->chunk_size << order;
        struct drm_buddy_block *block;
        struct drm_buddy_block *buddy;
        LIST_HEAD(dfs);
@@ -367,6 +368,15 @@ alloc_range_bias(struct drm_buddy *mm,
                if (drm_buddy_block_is_allocated(block))
                        continue;
 
+               if (block_start < start || block_end > end) {
+                       u64 adjusted_start = max(block_start, start);
+                       u64 adjusted_end = min(block_end, end);
+
+                       if (round_down(adjusted_end + 1, req_size) <=
+                           round_up(adjusted_start, req_size))
+                               continue;
+               }
+
                if (contains(start, end, block_start, block_end) &&
                    order == drm_buddy_block_order(block)) {
                        /*
@@ -538,7 +548,13 @@ static int __alloc_range(struct drm_buddy *mm,
                list_add(&block->left->tmp_link, dfs);
        } while (1);
 
+       if (total_allocated < size) {
+               err = -ENOSPC;
+               goto err_free;
+       }
+
        list_splice_tail(&allocated, blocks);
+
        return 0;
 
 err_undo:
@@ -755,8 +771,12 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm,
                return -EINVAL;
 
        /* Actual range allocation */
-       if (start + size == end)
+       if (start + size == end) {
+               if (!IS_ALIGNED(start | end, min_block_size))
+                       return -EINVAL;
+
                return __drm_buddy_alloc_range(mm, start, size, NULL, blocks);
+       }
 
        original_size = size;
        original_min_size = min_block_size;
index cb90e70d85e862a495f2e8691813161a93b7a030..65f9f66933bba2785fc3b64f7040e676c2afd352 100644 (file)
@@ -904,6 +904,7 @@ out:
        connector_set = NULL;
        fb = NULL;
        mode = NULL;
+       num_connectors = 0;
 
        DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
 
index 834a5e28abbe5959cc6da2933904c4feb4c7b00d..7352bde299d54767fecb34232cb5941a01d6ea88 100644 (file)
@@ -820,7 +820,7 @@ struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev,
        if (max_segment == 0)
                max_segment = UINT_MAX;
        err = sg_alloc_table_from_pages_segment(sg, pages, nr_pages, 0,
-                                               nr_pages << PAGE_SHIFT,
+                                               (unsigned long)nr_pages << PAGE_SHIFT,
                                                max_segment, GFP_KERNEL);
        if (err) {
                kfree(sg);
index 3f479483d7d80f21febcda087570bcc6af2fd34c..23b4e9a3361d82e0d5bc6a1daf121a0645011d96 100644 (file)
@@ -760,9 +760,11 @@ static void output_poll_execute(struct work_struct *work)
        changed = dev->mode_config.delayed_event;
        dev->mode_config.delayed_event = false;
 
-       if (!drm_kms_helper_poll && dev->mode_config.poll_running) {
-               drm_kms_helper_disable_hpd(dev);
-               dev->mode_config.poll_running = false;
+       if (!drm_kms_helper_poll) {
+               if (dev->mode_config.poll_running) {
+                       drm_kms_helper_disable_hpd(dev);
+                       dev->mode_config.poll_running = false;
+               }
                goto out;
        }
 
index 84101baeecc6e67d562e15e7d5ded57df39ffdc1..a6c19de462928ed70da033a60b10f08061bd1dc8 100644 (file)
@@ -1040,7 +1040,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
        uint64_t *points;
        uint32_t signaled_count, i;
 
-       if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT)
+       if (flags & (DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |
+                    DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE))
                lockdep_assert_none_held_once();
 
        points = kmalloc_array(count, sizeof(*points), GFP_KERNEL);
@@ -1109,7 +1110,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
         * fallthough and try a 0 timeout wait!
         */
 
-       if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
+       if (flags & (DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |
+                    DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE)) {
                for (i = 0; i < count; ++i)
                        drm_syncobj_fence_add_wait(syncobjs[i], &entries[i]);
        }
@@ -1416,10 +1418,21 @@ syncobj_eventfd_entry_func(struct drm_syncobj *syncobj,
 
        /* This happens inside the syncobj lock */
        fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, 1));
+       if (!fence)
+               return;
+
        ret = dma_fence_chain_find_seqno(&fence, entry->point);
-       if (ret != 0 || !fence) {
+       if (ret != 0) {
+               /* The given seqno has not been submitted yet. */
                dma_fence_put(fence);
                return;
+       } else if (!fence) {
+               /* If dma_fence_chain_find_seqno returns 0 but sets the fence
+                * to NULL, it implies that the given seqno is signaled and a
+                * later seqno has already been submitted. Assign a stub fence
+                * so that the eventfd still gets signaled below.
+                */
+               fence = dma_fence_get_stub();
        }
 
        list_del_init(&entry->node);
index 47cd6bb04366f34a798d76df35b3bba3be2cd67e..06900ff307b23a411114394e8d5d0f5e7ba4ad89 100644 (file)
@@ -246,7 +246,14 @@ static enum phy icl_aux_pw_to_phy(struct drm_i915_private *i915,
        enum aux_ch aux_ch = icl_aux_pw_to_ch(power_well);
        struct intel_digital_port *dig_port = aux_ch_to_digital_port(i915, aux_ch);
 
-       return intel_port_to_phy(i915, dig_port->base.port);
+       /*
+        * FIXME should we care about the (VBT defined) dig_port->aux_ch
+        * relationship or should this be purely defined by the hardware layout?
+        * Currently if the port doesn't appear in the VBT, or if it's declared
+        * as HDMI-only and routed to a combo PHY, the encoder either won't be
+        * present at all or it will not have an aux_ch assigned.
+        */
+       return dig_port ? intel_port_to_phy(i915, dig_port->base.port) : PHY_NONE;
 }
 
 static void hsw_wait_for_power_well_enable(struct drm_i915_private *dev_priv,
@@ -414,7 +421,8 @@ icl_combo_phy_aux_power_well_enable(struct drm_i915_private *dev_priv,
 
        intel_de_rmw(dev_priv, regs->driver, 0, HSW_PWR_WELL_CTL_REQ(pw_idx));
 
-       if (DISPLAY_VER(dev_priv) < 12)
+       /* FIXME this is a mess */
+       if (phy != PHY_NONE)
                intel_de_rmw(dev_priv, ICL_PORT_CL_DW12(phy),
                             0, ICL_LANE_ENABLE_AUX);
 
@@ -437,7 +445,10 @@ icl_combo_phy_aux_power_well_disable(struct drm_i915_private *dev_priv,
 
        drm_WARN_ON(&dev_priv->drm, !IS_ICELAKE(dev_priv));
 
-       intel_de_rmw(dev_priv, ICL_PORT_CL_DW12(phy), ICL_LANE_ENABLE_AUX, 0);
+       /* FIXME this is a mess */
+       if (phy != PHY_NONE)
+               intel_de_rmw(dev_priv, ICL_PORT_CL_DW12(phy),
+                            ICL_LANE_ENABLE_AUX, 0);
 
        intel_de_rmw(dev_priv, regs->driver, HSW_PWR_WELL_CTL_REQ(pw_idx), 0);
 
index 3fdd8a5179831288f1e10bc8d9161d8d23a7ba6a..ac7fe6281afe3f52b37c0e75f422045982bb076a 100644 (file)
@@ -609,6 +609,13 @@ struct intel_connector {
         * and active (i.e. dpms ON state). */
        bool (*get_hw_state)(struct intel_connector *);
 
+       /*
+        * Optional hook called during init/resume to sync any state
+        * stored in the connector (eg. DSC state) wrt. the HW state.
+        */
+       void (*sync_state)(struct intel_connector *connector,
+                          const struct intel_crtc_state *crtc_state);
+
        /* Panel info for eDP and LVDS */
        struct intel_panel panel;
 
index f5ef95da55346ff14cc6b102c27e78e8960cec65..94d2a15d8444ad6a9d88029091cf4aafda60f497 100644 (file)
@@ -2355,6 +2355,9 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
        limits->min_rate = intel_dp_common_rate(intel_dp, 0);
        limits->max_rate = intel_dp_max_link_rate(intel_dp);
 
+       /* FIXME 128b/132b SST support missing */
+       limits->max_rate = min(limits->max_rate, 810000);
+
        limits->min_lane_count = 1;
        limits->max_lane_count = intel_dp_max_lane_count(intel_dp);
 
@@ -5696,6 +5699,9 @@ intel_dp_detect(struct drm_connector *connector,
                goto out;
        }
 
+       if (!intel_dp_is_edp(intel_dp))
+               intel_psr_init_dpcd(intel_dp);
+
        intel_dp_detect_dsc_caps(intel_dp, intel_connector);
 
        intel_dp_configure_mst(intel_dp);
@@ -5856,6 +5862,19 @@ intel_dp_connector_unregister(struct drm_connector *connector)
        intel_connector_unregister(connector);
 }
 
+void intel_dp_connector_sync_state(struct intel_connector *connector,
+                                  const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *i915 = to_i915(connector->base.dev);
+
+       if (crtc_state && crtc_state->dsc.compression_enable) {
+               drm_WARN_ON(&i915->drm, !connector->dp.dsc_decompression_aux);
+               connector->dp.dsc_decompression_enabled = true;
+       } else {
+               connector->dp.dsc_decompression_enabled = false;
+       }
+}
+
 void intel_dp_encoder_flush_work(struct drm_encoder *encoder)
 {
        struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder));
index 05db46b111f216e150760e0dff76581cc18bbcca..375d0677cd8c516c56ca2cf9ba592b4746677304 100644 (file)
@@ -45,6 +45,8 @@ bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
 int intel_dp_min_bpp(enum intel_output_format output_format);
 bool intel_dp_init_connector(struct intel_digital_port *dig_port,
                             struct intel_connector *intel_connector);
+void intel_dp_connector_sync_state(struct intel_connector *connector,
+                                  const struct intel_crtc_state *crtc_state);
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
                              int link_rate, int lane_count);
 int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
index 3a595cd433d4952078ed20227a1d47f4fe11d458..8538d1ce2fcb854bdf5fcc60086992039312702e 100644 (file)
@@ -330,23 +330,13 @@ static const struct hdcp2_dp_msg_data hdcp2_dp_msg_data[] = {
          0, 0 },
 };
 
-static struct drm_dp_aux *
-intel_dp_hdcp_get_aux(struct intel_connector *connector)
-{
-       struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
-
-       if (intel_encoder_is_mst(connector->encoder))
-               return &connector->port->aux;
-       else
-               return &dig_port->dp.aux;
-}
-
 static int
 intel_dp_hdcp2_read_rx_status(struct intel_connector *connector,
                              u8 *rx_status)
 {
        struct drm_i915_private *i915 = to_i915(connector->base.dev);
-       struct drm_dp_aux *aux = intel_dp_hdcp_get_aux(connector);
+       struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
+       struct drm_dp_aux *aux = &dig_port->dp.aux;
        ssize_t ret;
 
        ret = drm_dp_dpcd_read(aux,
@@ -399,7 +389,9 @@ intel_dp_hdcp2_wait_for_msg(struct intel_connector *connector,
                            const struct hdcp2_dp_msg_data *hdcp2_msg_data)
 {
        struct drm_i915_private *i915 = to_i915(connector->base.dev);
-       struct intel_hdcp *hdcp = &connector->hdcp;
+       struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
+       struct intel_dp *dp = &dig_port->dp;
+       struct intel_hdcp *hdcp = &dp->attached_connector->hdcp;
        u8 msg_id = hdcp2_msg_data->msg_id;
        int ret, timeout;
        bool msg_ready = false;
@@ -454,8 +446,9 @@ int intel_dp_hdcp2_write_msg(struct intel_connector *connector,
        unsigned int offset;
        u8 *byte = buf;
        ssize_t ret, bytes_to_write, len;
+       struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
+       struct drm_dp_aux *aux = &dig_port->dp.aux;
        const struct hdcp2_dp_msg_data *hdcp2_msg_data;
-       struct drm_dp_aux *aux;
 
        hdcp2_msg_data = get_hdcp2_dp_msg_data(*byte);
        if (!hdcp2_msg_data)
@@ -463,8 +456,6 @@ int intel_dp_hdcp2_write_msg(struct intel_connector *connector,
 
        offset = hdcp2_msg_data->offset;
 
-       aux = intel_dp_hdcp_get_aux(connector);
-
        /* No msg_id in DP HDCP2.2 msgs */
        bytes_to_write = size - 1;
        byte++;
@@ -490,7 +481,8 @@ static
 ssize_t get_receiver_id_list_rx_info(struct intel_connector *connector,
                                     u32 *dev_cnt, u8 *byte)
 {
-       struct drm_dp_aux *aux = intel_dp_hdcp_get_aux(connector);
+       struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
+       struct drm_dp_aux *aux = &dig_port->dp.aux;
        ssize_t ret;
        u8 *rx_info = byte;
 
@@ -515,8 +507,9 @@ int intel_dp_hdcp2_read_msg(struct intel_connector *connector,
 {
        struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
        struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-       struct intel_hdcp *hdcp = &connector->hdcp;
-       struct drm_dp_aux *aux;
+       struct drm_dp_aux *aux = &dig_port->dp.aux;
+       struct intel_dp *dp = &dig_port->dp;
+       struct intel_hdcp *hdcp = &dp->attached_connector->hdcp;
        unsigned int offset;
        u8 *byte = buf;
        ssize_t ret, bytes_to_recv, len;
@@ -530,8 +523,6 @@ int intel_dp_hdcp2_read_msg(struct intel_connector *connector,
                return -EINVAL;
        offset = hdcp2_msg_data->offset;
 
-       aux = intel_dp_hdcp_get_aux(connector);
-
        ret = intel_dp_hdcp2_wait_for_msg(connector, hdcp2_msg_data);
        if (ret < 0)
                return ret;
@@ -561,13 +552,8 @@ int intel_dp_hdcp2_read_msg(struct intel_connector *connector,
 
                /* Entire msg read timeout since initiate of msg read */
                if (bytes_to_recv == size - 1 && hdcp2_msg_data->msg_read_timeout > 0) {
-                       if (intel_encoder_is_mst(connector->encoder))
-                               msg_end = ktime_add_ms(ktime_get_raw(),
-                                                      hdcp2_msg_data->msg_read_timeout *
-                                                      connector->port->parent->num_ports);
-                       else
-                               msg_end = ktime_add_ms(ktime_get_raw(),
-                                                      hdcp2_msg_data->msg_read_timeout);
+                       msg_end = ktime_add_ms(ktime_get_raw(),
+                                              hdcp2_msg_data->msg_read_timeout);
                }
 
                ret = drm_dp_dpcd_read(aux, offset,
@@ -651,12 +637,11 @@ static
 int intel_dp_hdcp2_capable(struct intel_connector *connector,
                           bool *capable)
 {
-       struct drm_dp_aux *aux;
+       struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
+       struct drm_dp_aux *aux = &dig_port->dp.aux;
        u8 rx_caps[3];
        int ret;
 
-       aux = intel_dp_hdcp_get_aux(connector);
-
        *capable = false;
        ret = drm_dp_dpcd_read(aux,
                               DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
index 8a9432335030346ecf3b7501a4cfb19cd59d5259..a01a59f57ae5525acb65e2725b3b37a9e31a065c 100644 (file)
@@ -1534,6 +1534,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
                return NULL;
 
        intel_connector->get_hw_state = intel_dp_mst_get_hw_state;
+       intel_connector->sync_state = intel_dp_connector_sync_state;
        intel_connector->mst_port = intel_dp;
        intel_connector->port = port;
        drm_dp_mst_get_port_malloc(port);
index 94eece7f63be3341fc92807345c0f7b01f862275..caeca3a8442c5d76008525ff56c65356eb6171be 100644 (file)
@@ -318,12 +318,6 @@ static void intel_modeset_update_connector_atomic_state(struct drm_i915_private
                        const struct intel_crtc_state *crtc_state =
                                to_intel_crtc_state(crtc->base.state);
 
-                       if (crtc_state->dsc.compression_enable) {
-                               drm_WARN_ON(&i915->drm, !connector->dp.dsc_decompression_aux);
-                               connector->dp.dsc_decompression_enabled = true;
-                       } else {
-                               connector->dp.dsc_decompression_enabled = false;
-                       }
                        conn_state->max_bpc = (crtc_state->pipe_bpp ?: 24) / 3;
                }
        }
@@ -775,8 +769,9 @@ static void intel_modeset_readout_hw_state(struct drm_i915_private *i915)
 
        drm_connector_list_iter_begin(&i915->drm, &conn_iter);
        for_each_intel_connector_iter(connector, &conn_iter) {
+               struct intel_crtc_state *crtc_state = NULL;
+
                if (connector->get_hw_state(connector)) {
-                       struct intel_crtc_state *crtc_state;
                        struct intel_crtc *crtc;
 
                        connector->base.dpms = DRM_MODE_DPMS_ON;
@@ -802,6 +797,10 @@ static void intel_modeset_readout_hw_state(struct drm_i915_private *i915)
                        connector->base.dpms = DRM_MODE_DPMS_OFF;
                        connector->base.encoder = NULL;
                }
+
+               if (connector->sync_state)
+                       connector->sync_state(connector, crtc_state);
+
                drm_dbg_kms(&i915->drm,
                            "[CONNECTOR:%d:%s] hw state readout: %s\n",
                            connector->base.base.id, connector->base.name,
index 57bbf3e3af92fbb0325d0c41765f7a0f0d0ac806..4faaf4b3fc53baf048cad365636955c2fce0e921 100644 (file)
@@ -2776,9 +2776,6 @@ void intel_psr_init(struct intel_dp *intel_dp)
        if (!(HAS_PSR(dev_priv) || HAS_DP20(dev_priv)))
                return;
 
-       if (!intel_dp_is_edp(intel_dp))
-               intel_psr_init_dpcd(intel_dp);
-
        /*
         * HSW spec explicitly says PSR is tied to port A.
         * BDW+ platforms have a instance of PSR registers per transcoder but
index acc6b6804105102389dc26c3fefce80444d0adad..2915d7afe5ccc2facdaeaee164e7b9c60796f361 100644 (file)
@@ -1209,7 +1209,7 @@ static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo,
        struct intel_sdvo_tv_format format;
        u32 format_map;
 
-       format_map = 1 << conn_state->tv.mode;
+       format_map = 1 << conn_state->tv.legacy_mode;
        memset(&format, 0, sizeof(format));
        memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map)));
 
@@ -2298,7 +2298,7 @@ static int intel_sdvo_get_tv_modes(struct drm_connector *connector)
         * Read the list of supported input resolutions for the selected TV
         * format.
         */
-       format_map = 1 << conn_state->tv.mode;
+       format_map = 1 << conn_state->tv.legacy_mode;
        memcpy(&tv_res, &format_map,
               min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request)));
 
@@ -2363,7 +2363,7 @@ intel_sdvo_connector_atomic_get_property(struct drm_connector *connector,
                int i;
 
                for (i = 0; i < intel_sdvo_connector->format_supported_num; i++)
-                       if (state->tv.mode == intel_sdvo_connector->tv_format_supported[i]) {
+                       if (state->tv.legacy_mode == intel_sdvo_connector->tv_format_supported[i]) {
                                *val = i;
 
                                return 0;
@@ -2419,7 +2419,7 @@ intel_sdvo_connector_atomic_set_property(struct drm_connector *connector,
        struct intel_sdvo_connector_state *sdvo_state = to_intel_sdvo_connector_state(state);
 
        if (property == intel_sdvo_connector->tv_format) {
-               state->tv.mode = intel_sdvo_connector->tv_format_supported[val];
+               state->tv.legacy_mode = intel_sdvo_connector->tv_format_supported[val];
 
                if (state->crtc) {
                        struct drm_crtc_state *crtc_state =
@@ -3076,7 +3076,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
                drm_property_add_enum(intel_sdvo_connector->tv_format, i,
                                      tv_format_names[intel_sdvo_connector->tv_format_supported[i]]);
 
-       intel_sdvo_connector->base.base.state->tv.mode = intel_sdvo_connector->tv_format_supported[0];
+       intel_sdvo_connector->base.base.state->tv.legacy_mode = intel_sdvo_connector->tv_format_supported[0];
        drm_object_attach_property(&intel_sdvo_connector->base.base.base,
                                   intel_sdvo_connector->tv_format, 0);
        return true;
index d4386cb3569e0991bc3c0c78a4415d77a7bc1998..992a725de751a2d1925c23da8763e5ea7dce4714 100644 (file)
@@ -949,7 +949,7 @@ intel_disable_tv(struct intel_atomic_state *state,
 
 static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state *conn_state)
 {
-       int format = conn_state->tv.mode;
+       int format = conn_state->tv.legacy_mode;
 
        return &tv_modes[format];
 }
@@ -1704,7 +1704,7 @@ static void intel_tv_find_better_format(struct drm_connector *connector)
                        break;
        }
 
-       connector->state->tv.mode = i;
+       connector->state->tv.legacy_mode = i;
 }
 
 static int
@@ -1859,7 +1859,7 @@ static int intel_tv_atomic_check(struct drm_connector *connector,
        old_state = drm_atomic_get_old_connector_state(state, connector);
        new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
 
-       if (old_state->tv.mode != new_state->tv.mode ||
+       if (old_state->tv.legacy_mode != new_state->tv.legacy_mode ||
            old_state->tv.margins.left != new_state->tv.margins.left ||
            old_state->tv.margins.right != new_state->tv.margins.right ||
            old_state->tv.margins.top != new_state->tv.margins.top ||
@@ -1896,7 +1896,7 @@ static void intel_tv_add_properties(struct drm_connector *connector)
        conn_state->tv.margins.right = 46;
        conn_state->tv.margins.bottom = 37;
 
-       conn_state->tv.mode = 0;
+       conn_state->tv.legacy_mode = 0;
 
        /* Create TV properties then attach current values */
        for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
@@ -1910,7 +1910,7 @@ static void intel_tv_add_properties(struct drm_connector *connector)
 
        drm_object_attach_property(&connector->base,
                                   i915->drm.mode_config.legacy_tv_mode_property,
-                                  conn_state->tv.mode);
+                                  conn_state->tv.legacy_mode);
        drm_object_attach_property(&connector->base,
                                   i915->drm.mode_config.tv_left_margin_property,
                                   conn_state->tv.margins.left);
index 64f440fdc22b2c832a77ca7ca73cf83ecc5ba625..8b21dc8e26d525f514f74f2a647ea703b2cd2d9a 100644 (file)
@@ -51,8 +51,8 @@
 #define DSCC_PICTURE_PARAMETER_SET_0           _MMIO(0x6BA00)
 #define _DSCA_PPS_0                            0x6B200
 #define _DSCC_PPS_0                            0x6BA00
-#define DSCA_PPS(pps)                          _MMIO(_DSCA_PPS_0 + (pps) * 4)
-#define DSCC_PPS(pps)                          _MMIO(_DSCC_PPS_0 + (pps) * 4)
+#define DSCA_PPS(pps)                          _MMIO(_DSCA_PPS_0 + ((pps) < 12 ? (pps) : (pps) + 12) * 4)
+#define DSCC_PPS(pps)                          _MMIO(_DSCC_PPS_0 + ((pps) < 12 ? (pps) : (pps) + 12) * 4)
 #define _ICL_DSC0_PICTURE_PARAMETER_SET_0_PB   0x78270
 #define _ICL_DSC1_PICTURE_PARAMETER_SET_0_PB   0x78370
 #define _ICL_DSC0_PICTURE_PARAMETER_SET_0_PC   0x78470
index 1d3ebdf4069b5d0fea98aefdb2b1609f82b9650e..c08b67593565c5827d4555e70b88b083e97172d9 100644 (file)
@@ -379,6 +379,9 @@ i915_gem_userptr_release(struct drm_i915_gem_object *obj)
 {
        GEM_WARN_ON(obj->userptr.page_ref);
 
+       if (!obj->userptr.notifier.mm)
+               return;
+
        mmu_interval_notifier_remove(&obj->userptr.notifier);
        obj->userptr.notifier.mm = NULL;
 }
index 2990dd4d4a0d8a84ad5794815dbb4661610314a2..e14ac0ab1314d1032a707762a1be444a14b3ca39 100644 (file)
@@ -3,6 +3,8 @@
  * Copyright © 2021 Intel Corporation
  */
 
+#include <linux/jiffies.h>
+
 //#include "gt/intel_engine_user.h"
 #include "gt/intel_gt.h"
 #include "i915_drv.h"
@@ -12,7 +14,7 @@
 
 #define REDUCED_TIMESLICE      5
 #define REDUCED_PREEMPT                10
-#define WAIT_FOR_RESET_TIME    10000
+#define WAIT_FOR_RESET_TIME_MS 10000
 
 struct intel_engine_cs *intel_selftest_find_any_engine(struct intel_gt *gt)
 {
@@ -91,7 +93,7 @@ int intel_selftest_wait_for_rq(struct i915_request *rq)
 {
        long ret;
 
-       ret = i915_request_wait(rq, 0, WAIT_FOR_RESET_TIME);
+       ret = i915_request_wait(rq, 0, msecs_to_jiffies(WAIT_FOR_RESET_TIME_MS));
        if (ret < 0)
                return ret;
 
index 3f73b211fa8e3e3bc4812180883c9685f8377f19..3407450435e2057dd3973441ba6e31485e69ee6d 100644 (file)
@@ -294,6 +294,5 @@ void meson_encoder_cvbs_remove(struct meson_drm *priv)
        if (priv->encoders[MESON_ENC_CVBS]) {
                meson_encoder_cvbs = priv->encoders[MESON_ENC_CVBS];
                drm_bridge_remove(&meson_encoder_cvbs->bridge);
-               drm_bridge_remove(meson_encoder_cvbs->next_bridge);
        }
 }
index 3f93c70488cad1829bbe488d8bf8f7b3833859f1..311b91630fbe536cf724223a1fa71e565ba2c778 100644 (file)
@@ -168,6 +168,5 @@ void meson_encoder_dsi_remove(struct meson_drm *priv)
        if (priv->encoders[MESON_ENC_DSI]) {
                meson_encoder_dsi = priv->encoders[MESON_ENC_DSI];
                drm_bridge_remove(&meson_encoder_dsi->bridge);
-               drm_bridge_remove(meson_encoder_dsi->next_bridge);
        }
 }
index 25ea765586908f14d08715f45ca9def85a6a07f3..c4686568c9ca5d81b4066315681263e0fbd848a2 100644 (file)
@@ -474,6 +474,5 @@ void meson_encoder_hdmi_remove(struct meson_drm *priv)
        if (priv->encoders[MESON_ENC_HDMI]) {
                meson_encoder_hdmi = priv->encoders[MESON_ENC_HDMI];
                drm_bridge_remove(&meson_encoder_hdmi->bridge);
-               drm_bridge_remove(meson_encoder_hdmi->next_bridge);
        }
 }
index c0bc924cd3025dc21939e2e75548f273a90fd620..c9c55e2ea584927ce7b3f8ffc50e7ed807f6671a 100644 (file)
@@ -1287,7 +1287,7 @@ static void a6xx_calc_ubwc_config(struct adreno_gpu *gpu)
        gpu->ubwc_config.highest_bank_bit = 15;
 
        if (adreno_is_a610(gpu)) {
-               gpu->ubwc_config.highest_bank_bit = 14;
+               gpu->ubwc_config.highest_bank_bit = 13;
                gpu->ubwc_config.min_acc_len = 1;
                gpu->ubwc_config.ubwc_mode = 1;
        }
index d37d599aec273b41b7ec54eb04b55ee86770d1a5..4c72124ffb5d495bdd24eefaf086f4d9401663ce 100644 (file)
@@ -329,10 +329,26 @@ static const struct component_ops dp_display_comp_ops = {
        .unbind = dp_display_unbind,
 };
 
+static void dp_display_send_hpd_event(struct msm_dp *dp_display)
+{
+       struct dp_display_private *dp;
+       struct drm_connector *connector;
+
+       dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+       connector = dp->dp_display.connector;
+       drm_helper_hpd_irq_event(connector->dev);
+}
+
 static int dp_display_send_hpd_notification(struct dp_display_private *dp,
                                            bool hpd)
 {
-       struct drm_bridge *bridge = dp->dp_display.bridge;
+       if ((hpd && dp->dp_display.link_ready) ||
+                       (!hpd && !dp->dp_display.link_ready)) {
+               drm_dbg_dp(dp->drm_dev, "HPD already %s\n",
+                               (hpd ? "on" : "off"));
+               return 0;
+       }
 
        /* reset video pattern flag on disconnect */
        if (!hpd) {
@@ -348,7 +364,7 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp,
 
        drm_dbg_dp(dp->drm_dev, "type=%d hpd=%d\n",
                        dp->dp_display.connector_type, hpd);
-       drm_bridge_hpd_notify(bridge, dp->dp_display.link_ready);
+       dp_display_send_hpd_event(&dp->dp_display);
 
        return 0;
 }
index 5f68e31a3e4e1cbeed95bfde138711c0fc9c9759..0915f3b68752e34702ae8864249d049e3b277ee2 100644 (file)
@@ -26,7 +26,7 @@ int msm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
 {
        void *vaddr;
 
-       vaddr = msm_gem_get_vaddr(obj);
+       vaddr = msm_gem_get_vaddr_locked(obj);
        if (IS_ERR(vaddr))
                return PTR_ERR(vaddr);
        iosys_map_set_vaddr(map, vaddr);
@@ -36,7 +36,7 @@ int msm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
 
 void msm_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
 {
-       msm_gem_put_vaddr(obj);
+       msm_gem_put_vaddr_locked(obj);
 }
 
 struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
index 095390774f22b547668227ed492a6e9783b055f9..655002b21b0d5dc345283a7699d14b0e88b3e472 100644 (file)
@@ -751,12 +751,14 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
        struct msm_ringbuffer *ring = submit->ring;
        unsigned long flags;
 
-       pm_runtime_get_sync(&gpu->pdev->dev);
+       WARN_ON(!mutex_is_locked(&gpu->lock));
 
-       mutex_lock(&gpu->lock);
+       pm_runtime_get_sync(&gpu->pdev->dev);
 
        msm_gpu_hw_init(gpu);
 
+       submit->seqno = submit->hw_fence->seqno;
+
        update_sw_cntrs(gpu);
 
        /*
@@ -781,11 +783,8 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
        gpu->funcs->submit(gpu, submit);
        gpu->cur_ctx_seqno = submit->queue->ctx->seqno;
 
-       hangcheck_timer_reset(gpu);
-
-       mutex_unlock(&gpu->lock);
-
        pm_runtime_put(&gpu->pdev->dev);
+       hangcheck_timer_reset(gpu);
 }
 
 /*
index 5cc8d358cc9759307a444cd62bce83c62b3dcdb7..d5512037c38bcd7ca807aaf281dceaebdd688a4e 100644 (file)
@@ -21,6 +21,8 @@ struct msm_iommu_pagetable {
        struct msm_mmu base;
        struct msm_mmu *parent;
        struct io_pgtable_ops *pgtbl_ops;
+       const struct iommu_flush_ops *tlb;
+       struct device *iommu_dev;
        unsigned long pgsize_bitmap;    /* Bitmap of page sizes in use */
        phys_addr_t ttbr;
        u32 asid;
@@ -201,11 +203,33 @@ static const struct msm_mmu_funcs pagetable_funcs = {
 
 static void msm_iommu_tlb_flush_all(void *cookie)
 {
+       struct msm_iommu_pagetable *pagetable = cookie;
+       struct adreno_smmu_priv *adreno_smmu;
+
+       if (!pm_runtime_get_if_in_use(pagetable->iommu_dev))
+               return;
+
+       adreno_smmu = dev_get_drvdata(pagetable->parent->dev);
+
+       pagetable->tlb->tlb_flush_all((void *)adreno_smmu->cookie);
+
+       pm_runtime_put_autosuspend(pagetable->iommu_dev);
 }
 
 static void msm_iommu_tlb_flush_walk(unsigned long iova, size_t size,
                size_t granule, void *cookie)
 {
+       struct msm_iommu_pagetable *pagetable = cookie;
+       struct adreno_smmu_priv *adreno_smmu;
+
+       if (!pm_runtime_get_if_in_use(pagetable->iommu_dev))
+               return;
+
+       adreno_smmu = dev_get_drvdata(pagetable->parent->dev);
+
+       pagetable->tlb->tlb_flush_walk(iova, size, granule, (void *)adreno_smmu->cookie);
+
+       pm_runtime_put_autosuspend(pagetable->iommu_dev);
 }
 
 static void msm_iommu_tlb_add_page(struct iommu_iotlb_gather *gather,
@@ -213,7 +237,7 @@ static void msm_iommu_tlb_add_page(struct iommu_iotlb_gather *gather,
 {
 }
 
-static const struct iommu_flush_ops null_tlb_ops = {
+static const struct iommu_flush_ops tlb_ops = {
        .tlb_flush_all = msm_iommu_tlb_flush_all,
        .tlb_flush_walk = msm_iommu_tlb_flush_walk,
        .tlb_add_page = msm_iommu_tlb_add_page,
@@ -254,10 +278,10 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent)
 
        /* The incoming cfg will have the TTBR1 quirk enabled */
        ttbr0_cfg.quirks &= ~IO_PGTABLE_QUIRK_ARM_TTBR1;
-       ttbr0_cfg.tlb = &null_tlb_ops;
+       ttbr0_cfg.tlb = &tlb_ops;
 
        pagetable->pgtbl_ops = alloc_io_pgtable_ops(ARM_64_LPAE_S1,
-               &ttbr0_cfg, iommu->domain);
+               &ttbr0_cfg, pagetable);
 
        if (!pagetable->pgtbl_ops) {
                kfree(pagetable);
@@ -279,6 +303,8 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent)
 
        /* Needed later for TLB flush */
        pagetable->parent = parent;
+       pagetable->tlb = ttbr1_cfg->tlb;
+       pagetable->iommu_dev = ttbr1_cfg->iommu_dev;
        pagetable->pgsize_bitmap = ttbr0_cfg.pgsize_bitmap;
        pagetable->ttbr = ttbr0_cfg.arm_lpae_s1_cfg.ttbr;
 
index 4bc13f7d005ab7c643f78206d8d41d72cd779045..9d6655f96f0cebcc0c03e5b9bef6900c299f2f0d 100644 (file)
@@ -21,8 +21,6 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job)
 
        msm_fence_init(submit->hw_fence, fctx);
 
-       submit->seqno = submit->hw_fence->seqno;
-
        mutex_lock(&priv->lru.lock);
 
        for (i = 0; i < submit->nr_bos; i++) {
@@ -35,8 +33,13 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job)
 
        mutex_unlock(&priv->lru.lock);
 
+       /* TODO move submit path over to using a per-ring lock.. */
+       mutex_lock(&gpu->lock);
+
        msm_gpu_submit(gpu, submit);
 
+       mutex_unlock(&gpu->lock);
+
        return dma_fence_get(submit->hw_fence);
 }
 
index 1e6aaf95ff7c79483f7d8bba1ddce897bb7affcf..ceef470c9fbfcfb08be6abd69627b7e7bc66366d 100644 (file)
@@ -100,3 +100,11 @@ config DRM_NOUVEAU_SVM
        help
          Say Y here if you want to enable experimental support for
          Shared Virtual Memory (SVM).
+
+config DRM_NOUVEAU_GSP_DEFAULT
+       bool "Use GSP firmware for Turing/Ampere (needs firmware installed)"
+       depends on DRM_NOUVEAU
+       default n
+       help
+         Say Y here if you want to use the GSP codepaths by default on
+         Turing and Ampere GPUs.
index 0d9fc741a719328722f2c1873bb07bf4b120e890..932c9fd0b2d89ce8c3ec04165bbefa0cec8b25ce 100644 (file)
@@ -11,6 +11,7 @@ struct nvkm_client {
        u32 debug;
 
        struct rb_root objroot;
+       spinlock_t obj_lock;
 
        void *data;
        int (*event)(u64 token, void *argv, u32 argc);
index a04156ca8390ba6fea6a21e07e9eb5bba3ec7605..80f74ee0fc78677f8f890e8cc5daf8f363817b34 100644 (file)
@@ -128,12 +128,14 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
        struct nouveau_abi16_ntfy *ntfy, *temp;
 
        /* Cancel all jobs from the entity's queue. */
-       drm_sched_entity_fini(&chan->sched.entity);
+       if (chan->sched)
+               drm_sched_entity_fini(&chan->sched->entity);
 
        if (chan->chan)
                nouveau_channel_idle(chan->chan);
 
-       nouveau_sched_fini(&chan->sched);
+       if (chan->sched)
+               nouveau_sched_destroy(&chan->sched);
 
        /* cleanup notifier state */
        list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) {
@@ -197,6 +199,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
        struct nouveau_cli *cli = nouveau_cli(file_priv);
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nvif_device *device = &drm->client.device;
+       struct nvkm_device *nvkm_device = nvxx_device(&drm->client.device);
        struct nvkm_gr *gr = nvxx_gr(device);
        struct drm_nouveau_getparam *getparam = data;
        struct pci_dev *pdev = to_pci_dev(dev->dev);
@@ -261,6 +264,14 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
                getparam->value = nouveau_exec_push_max_from_ib_max(ib_max);
                break;
        }
+       case NOUVEAU_GETPARAM_VRAM_BAR_SIZE:
+               getparam->value = nvkm_device->func->resource_size(nvkm_device, 1);
+               break;
+       case NOUVEAU_GETPARAM_VRAM_USED: {
+               struct ttm_resource_manager *vram_mgr = ttm_manager_type(&drm->ttm.bdev, TTM_PL_VRAM);
+               getparam->value = (u64)ttm_resource_manager_usage(vram_mgr);
+               break;
+       }
        default:
                NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param);
                return -EINVAL;
@@ -337,10 +348,16 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
        if (ret)
                goto done;
 
-       ret = nouveau_sched_init(&chan->sched, drm, drm->sched_wq,
-                                chan->chan->dma.ib_max);
-       if (ret)
-               goto done;
+       /* If we're not using the VM_BIND uAPI, we don't need a scheduler.
+        *
+        * The client lock is already acquired by nouveau_abi16_get().
+        */
+       if (nouveau_cli_uvmm(cli)) {
+               ret = nouveau_sched_create(&chan->sched, drm, drm->sched_wq,
+                                          chan->chan->dma.ib_max);
+               if (ret)
+                       goto done;
+       }
 
        init->channel = chan->chan->chid;
 
index 1f5e243c0c759ef759dbba7d4f89279c90bce5d4..11c8c4a80079bbb2b658816dd42d05f68a5eaab6 100644 (file)
@@ -26,7 +26,7 @@ struct nouveau_abi16_chan {
        struct nouveau_bo *ntfy;
        struct nouveau_vma *ntfy_vma;
        struct nvkm_mm  heap;
-       struct nouveau_sched sched;
+       struct nouveau_sched *sched;
 };
 
 struct nouveau_abi16 {
index 6f6c31a9937b2fe751c6cffe429cc21a6b47a385..a947e1d5f309ae525e8087d13899f1efd1e8e73b 100644 (file)
@@ -201,7 +201,8 @@ nouveau_cli_fini(struct nouveau_cli *cli)
        WARN_ON(!list_empty(&cli->worker));
 
        usif_client_fini(cli);
-       nouveau_sched_fini(&cli->sched);
+       if (cli->sched)
+               nouveau_sched_destroy(&cli->sched);
        if (uvmm)
                nouveau_uvmm_fini(uvmm);
        nouveau_vmm_fini(&cli->svm);
@@ -311,7 +312,7 @@ nouveau_cli_init(struct nouveau_drm *drm, const char *sname,
        cli->mem = &mems[ret];
 
        /* Don't pass in the (shared) sched_wq in order to let
-        * nouveau_sched_init() create a dedicated one for VM_BIND jobs.
+        * nouveau_sched_create() create a dedicated one for VM_BIND jobs.
         *
         * This is required to ensure that for VM_BIND jobs free_job() work and
         * run_job() work can always run concurrently and hence, free_job() work
@@ -320,7 +321,7 @@ nouveau_cli_init(struct nouveau_drm *drm, const char *sname,
         * locks which indirectly or directly are held for allocations
         * elsewhere.
         */
-       ret = nouveau_sched_init(&cli->sched, drm, NULL, 1);
+       ret = nouveau_sched_create(&cli->sched, drm, NULL, 1);
        if (ret)
                goto done;
 
index 8a6d94c8b1631fd7ab8bbc193f35b064057a0185..e239c6bf4afa4f75d4ca30c63583af82f2ab9621 100644 (file)
@@ -98,7 +98,7 @@ struct nouveau_cli {
                bool disabled;
        } uvmm;
 
-       struct nouveau_sched sched;
+       struct nouveau_sched *sched;
 
        const struct nvif_mclass *mem;
 
index bc5d71b79ab203ff7e874c612f3ea1e7c36323de..e65c0ef23bc73d59f3066ff02ae9360253b93e6d 100644 (file)
@@ -389,7 +389,7 @@ nouveau_exec_ioctl_exec(struct drm_device *dev,
        if (ret)
                goto out;
 
-       args.sched = &chan16->sched;
+       args.sched = chan16->sched;
        args.file_priv = file_priv;
        args.chan = chan;
 
index 49c2bcbef1299de1f556353423300b345e5cc538..5a887d67dc0e8c71cf1987acb68f48f4bbf05d70 100644 (file)
@@ -764,7 +764,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
                return -ENOMEM;
 
        if (unlikely(nouveau_cli_uvmm(cli)))
-               return -ENOSYS;
+               return nouveau_abi16_put(abi16, -ENOSYS);
 
        list_for_each_entry(temp, &abi16->channels, head) {
                if (temp->chan->chid == req->channel) {
index dd98f6910f9cab7b19117186339a138277e77b78..32fa2e273965bf140a4cb2e05262b638c312cd6e 100644 (file)
@@ -398,7 +398,7 @@ static const struct drm_sched_backend_ops nouveau_sched_ops = {
        .free_job = nouveau_sched_free_job,
 };
 
-int
+static int
 nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm,
                   struct workqueue_struct *wq, u32 credit_limit)
 {
@@ -453,7 +453,30 @@ fail_wq:
        return ret;
 }
 
-void
+int
+nouveau_sched_create(struct nouveau_sched **psched, struct nouveau_drm *drm,
+                    struct workqueue_struct *wq, u32 credit_limit)
+{
+       struct nouveau_sched *sched;
+       int ret;
+
+       sched = kzalloc(sizeof(*sched), GFP_KERNEL);
+       if (!sched)
+               return -ENOMEM;
+
+       ret = nouveau_sched_init(sched, drm, wq, credit_limit);
+       if (ret) {
+               kfree(sched);
+               return ret;
+       }
+
+       *psched = sched;
+
+       return 0;
+}
+
+
+static void
 nouveau_sched_fini(struct nouveau_sched *sched)
 {
        struct drm_gpu_scheduler *drm_sched = &sched->base;
@@ -471,3 +494,14 @@ nouveau_sched_fini(struct nouveau_sched *sched)
        if (sched->wq)
                destroy_workqueue(sched->wq);
 }
+
+void
+nouveau_sched_destroy(struct nouveau_sched **psched)
+{
+       struct nouveau_sched *sched = *psched;
+
+       nouveau_sched_fini(sched);
+       kfree(sched);
+
+       *psched = NULL;
+}
index a6528f5981e6a6e8182a44e0ec3c0336302e6154..e1f01a23e6f6e84cf2700bde86e4fb5e3e013df1 100644 (file)
@@ -111,8 +111,8 @@ struct nouveau_sched {
        } job;
 };
 
-int nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm,
-                      struct workqueue_struct *wq, u32 credit_limit);
-void nouveau_sched_fini(struct nouveau_sched *sched);
+int nouveau_sched_create(struct nouveau_sched **psched, struct nouveau_drm *drm,
+                        struct workqueue_struct *wq, u32 credit_limit);
+void nouveau_sched_destroy(struct nouveau_sched **psched);
 
 #endif
index cc03e0c22ff3fec65cf6a40ae34db2af20bb349e..5e4565c5011a976d1c8057e9366d9e1da03de97a 100644 (file)
@@ -1011,7 +1011,7 @@ nouveau_svm_fault_buffer_ctor(struct nouveau_svm *svm, s32 oclass, int id)
        if (ret)
                return ret;
 
-       buffer->fault = kvcalloc(sizeof(*buffer->fault), buffer->entries, GFP_KERNEL);
+       buffer->fault = kvcalloc(buffer->entries, sizeof(*buffer->fault), GFP_KERNEL);
        if (!buffer->fault)
                return -ENOMEM;
 
index 4f223c972c6a8cb3bab7873dfa2a1c38756648b2..0a0a11dc9ec03eeba855f47ca57c1ad1c5669f54 100644 (file)
@@ -1740,7 +1740,7 @@ nouveau_uvmm_ioctl_vm_bind(struct drm_device *dev,
        if (ret)
                return ret;
 
-       args.sched = &cli->sched;
+       args.sched = cli->sched;
        args.file_priv = file_priv;
 
        ret = nouveau_uvmm_vm_bind(&args);
index ebdeb8eb9e774186707d17508975311c14f3fabf..c55662937ab22caa54cd0d8f3df44b0d3e170197 100644 (file)
@@ -180,6 +180,7 @@ nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg,
        client->device = device;
        client->debug = nvkm_dbgopt(dbg, "CLIENT");
        client->objroot = RB_ROOT;
+       spin_lock_init(&client->obj_lock);
        client->event = event;
        INIT_LIST_HEAD(&client->umem);
        spin_lock_init(&client->lock);
index 7c554c14e8841da1bb0374f25d9a47512c6f3765..aea3ba72027abfbdf0456f065bce416eac26b348 100644 (file)
@@ -30,8 +30,10 @@ nvkm_object_search(struct nvkm_client *client, u64 handle,
                   const struct nvkm_object_func *func)
 {
        struct nvkm_object *object;
+       unsigned long flags;
 
        if (handle) {
+               spin_lock_irqsave(&client->obj_lock, flags);
                struct rb_node *node = client->objroot.rb_node;
                while (node) {
                        object = rb_entry(node, typeof(*object), node);
@@ -40,9 +42,12 @@ nvkm_object_search(struct nvkm_client *client, u64 handle,
                        else
                        if (handle > object->object)
                                node = node->rb_right;
-                       else
+                       else {
+                               spin_unlock_irqrestore(&client->obj_lock, flags);
                                goto done;
+                       }
                }
+               spin_unlock_irqrestore(&client->obj_lock, flags);
                return ERR_PTR(-ENOENT);
        } else {
                object = &client->object;
@@ -57,30 +62,39 @@ done:
 void
 nvkm_object_remove(struct nvkm_object *object)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&object->client->obj_lock, flags);
        if (!RB_EMPTY_NODE(&object->node))
                rb_erase(&object->node, &object->client->objroot);
+       spin_unlock_irqrestore(&object->client->obj_lock, flags);
 }
 
 bool
 nvkm_object_insert(struct nvkm_object *object)
 {
-       struct rb_node **ptr = &object->client->objroot.rb_node;
+       struct rb_node **ptr;
        struct rb_node *parent = NULL;
+       unsigned long flags;
 
+       spin_lock_irqsave(&object->client->obj_lock, flags);
+       ptr = &object->client->objroot.rb_node;
        while (*ptr) {
                struct nvkm_object *this = rb_entry(*ptr, typeof(*this), node);
                parent = *ptr;
-               if (object->object < this->object)
+               if (object->object < this->object) {
                        ptr = &parent->rb_left;
-               else
-               if (object->object > this->object)
+               } else if (object->object > this->object) {
                        ptr = &parent->rb_right;
-               else
+               } else {
+                       spin_unlock_irqrestore(&object->client->obj_lock, flags);
                        return false;
+               }
        }
 
        rb_link_node(&object->node, parent, ptr);
        rb_insert_color(&object->node, &object->client->objroot);
+       spin_unlock_irqrestore(&object->client->obj_lock, flags);
        return true;
 }
 
index 4135690326f44789535e8cb375ccfe1ee5fa68c3..3a30bea30e366f47ecda0bbabac5441aed285565 100644 (file)
@@ -168,12 +168,11 @@ r535_bar_new_(const struct nvkm_bar_func *hw, struct nvkm_device *device,
        rm->flush = r535_bar_flush;
 
        ret = gf100_bar_new_(rm, device, type, inst, &bar);
-       *pbar = bar;
        if (ret) {
-               if (!bar)
-                       kfree(rm);
+               kfree(rm);
                return ret;
        }
+       *pbar = bar;
 
        bar->flushBAR2PhysMode = ioremap(device->func->resource_addr(device, 3), PAGE_SIZE);
        if (!bar->flushBAR2PhysMode)
index 19188683c8fca90a7656b53ab15a8ee58d8575e0..8c2bf1c16f2a9568a8d434838d0c7691d9d70ff7 100644 (file)
@@ -154,11 +154,17 @@ shadow_fw_init(struct nvkm_bios *bios, const char *name)
        return (void *)fw;
 }
 
+static void
+shadow_fw_release(void *fw)
+{
+       release_firmware(fw);
+}
+
 static const struct nvbios_source
 shadow_fw = {
        .name = "firmware",
        .init = shadow_fw_init,
-       .fini = (void(*)(void *))release_firmware,
+       .fini = shadow_fw_release,
        .read = shadow_fw_read,
        .rw = false,
 };
index a41735ab60683f02fde33f0107a2edae89155a6e..a73a5b58979045b07468c1443940f87e1b151f67 100644 (file)
@@ -1054,8 +1054,6 @@ r535_gsp_postinit(struct nvkm_gsp *gsp)
        /* Release the DMA buffers that were needed only for boot and init */
        nvkm_gsp_mem_dtor(gsp, &gsp->boot.fw);
        nvkm_gsp_mem_dtor(gsp, &gsp->libos);
-       nvkm_gsp_mem_dtor(gsp, &gsp->rmargs);
-       nvkm_gsp_mem_dtor(gsp, &gsp->wpr_meta);
 
        return ret;
 }
@@ -2163,6 +2161,8 @@ r535_gsp_dtor(struct nvkm_gsp *gsp)
 
        r535_gsp_dtor_fws(gsp);
 
+       nvkm_gsp_mem_dtor(gsp, &gsp->rmargs);
+       nvkm_gsp_mem_dtor(gsp, &gsp->wpr_meta);
        nvkm_gsp_mem_dtor(gsp, &gsp->shm.mem);
        nvkm_gsp_mem_dtor(gsp, &gsp->loginit);
        nvkm_gsp_mem_dtor(gsp, &gsp->logintr);
@@ -2312,8 +2312,12 @@ r535_gsp_load(struct nvkm_gsp *gsp, int ver, const struct nvkm_gsp_fwif *fwif)
 {
        struct nvkm_subdev *subdev = &gsp->subdev;
        int ret;
+       bool enable_gsp = fwif->enable;
 
-       if (!nvkm_boolopt(subdev->device->cfgopt, "NvGspRm", fwif->enable))
+#if IS_ENABLED(CONFIG_DRM_NOUVEAU_GSP_DEFAULT)
+       enable_gsp = true;
+#endif
+       if (!nvkm_boolopt(subdev->device->cfgopt, "NvGspRm", enable_gsp))
                return -EINVAL;
 
        if ((ret = r535_gsp_load_fw(gsp, "gsp", fwif->ver, &gsp->fws.rm)) ||
index c4c0f08e92026d80824a6932a696144da65e0311..4945a1e787eb3efc8bb9617bef1a75fba13bb656 100644 (file)
@@ -1768,11 +1768,11 @@ static const struct panel_desc starry_qfh032011_53g_desc = {
 };
 
 static const struct drm_display_mode starry_himax83102_j02_default_mode = {
-       .clock = 162850,
+       .clock = 162680,
        .hdisplay = 1200,
-       .hsync_start = 1200 + 50,
-       .hsync_end = 1200 + 50 + 20,
-       .htotal = 1200 + 50 + 20 + 50,
+       .hsync_start = 1200 + 60,
+       .hsync_end = 1200 + 60 + 20,
+       .htotal = 1200 + 60 + 20 + 40,
        .vdisplay = 1920,
        .vsync_start = 1920 + 116,
        .vsync_end = 1920 + 116 + 8,
index 85b3b4871a1d63bf5a8cb2315a25dfd5ef2b8b70..fdd768bbd487c24b545da7aba2d0d45f63784293 100644 (file)
@@ -1985,8 +1985,10 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
                clock = vop2_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags);
        }
 
-       if (!clock)
+       if (!clock) {
+               vop2_unlock(vop2);
                return;
+       }
 
        if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
            !(vp_data->feature & VOP2_VP_FEATURE_OUTPUT_10BIT))
index a73cff7a307082d97ce78e43deaff5547cf55964..03d1c76aec2d3f7aca6a52acbb1a42455b37faa8 100644 (file)
@@ -1243,9 +1243,26 @@ static int host1x_drm_probe(struct host1x_device *dev)
 
        drm_mode_config_reset(drm);
 
-       err = drm_aperture_remove_framebuffers(&tegra_drm_driver);
-       if (err < 0)
-               goto hub;
+       /*
+        * Only take over from a potential firmware framebuffer if any CRTCs
+        * have been registered. This must not be a fatal error because there
+        * are other accelerators that are exposed via this driver.
+        *
+        * Another case where this happens is on Tegra234 where the display
+        * hardware is no longer part of the host1x complex, so this driver
+        * will not expose any modesetting features.
+        */
+       if (drm->mode_config.num_crtc > 0) {
+               err = drm_aperture_remove_framebuffers(&tegra_drm_driver);
+               if (err < 0)
+                       goto hub;
+       } else {
+               /*
+                * Indicate to userspace that this doesn't expose any display
+                * capabilities.
+                */
+               drm->driver_features &= ~(DRIVER_MODESET | DRIVER_ATOMIC);
+       }
 
        err = drm_dev_register(drm, 0);
        if (err < 0)
index ea2af6bd9abebcf381cc6a1a245e8cc1f044a656..e48863a445564d9200c75223d0ab3df8090a4bc5 100644 (file)
 
 #include <linux/prime_numbers.h>
 #include <linux/sched/signal.h>
+#include <linux/sizes.h>
 
 #include <drm/drm_buddy.h>
 
 #include "../lib/drm_random.h"
 
+static unsigned int random_seed;
+
 static inline u64 get_size(int order, u64 chunk_size)
 {
        return (1 << order) * chunk_size;
 }
 
+static void drm_test_buddy_alloc_range_bias(struct kunit *test)
+{
+       u32 mm_size, ps, bias_size, bias_start, bias_end, bias_rem;
+       DRM_RND_STATE(prng, random_seed);
+       unsigned int i, count, *order;
+       struct drm_buddy mm;
+       LIST_HEAD(allocated);
+
+       bias_size = SZ_1M;
+       ps = roundup_pow_of_two(prandom_u32_state(&prng) % bias_size);
+       ps = max(SZ_4K, ps);
+       mm_size = (SZ_8M-1) & ~(ps-1); /* Multiple roots */
+
+       kunit_info(test, "mm_size=%u, ps=%u\n", mm_size, ps);
+
+       KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, ps),
+                              "buddy_init failed\n");
+
+       count = mm_size / bias_size;
+       order = drm_random_order(count, &prng);
+       KUNIT_EXPECT_TRUE(test, order);
+
+       /*
+        * Idea is to split the address space into uniform bias ranges, and then
+        * in some random order allocate within each bias, using various
+        * patterns within. This should detect if allocations leak out from a
+        * given bias, for example.
+        */
+
+       for (i = 0; i < count; i++) {
+               LIST_HEAD(tmp);
+               u32 size;
+
+               bias_start = order[i] * bias_size;
+               bias_end = bias_start + bias_size;
+               bias_rem = bias_size;
+
+               /* internal round_up too big */
+               KUNIT_ASSERT_TRUE_MSG(test,
+                                     drm_buddy_alloc_blocks(&mm, bias_start,
+                                                            bias_end, bias_size + ps, bias_size,
+                                                            &allocated,
+                                                            DRM_BUDDY_RANGE_ALLOCATION),
+                                     "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
+                                     bias_start, bias_end, bias_size, bias_size);
+
+               /* size too big */
+               KUNIT_ASSERT_TRUE_MSG(test,
+                                     drm_buddy_alloc_blocks(&mm, bias_start,
+                                                            bias_end, bias_size + ps, ps,
+                                                            &allocated,
+                                                            DRM_BUDDY_RANGE_ALLOCATION),
+                                     "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
+                                     bias_start, bias_end, bias_size + ps, ps);
+
+               /* bias range too small for size */
+               KUNIT_ASSERT_TRUE_MSG(test,
+                                     drm_buddy_alloc_blocks(&mm, bias_start + ps,
+                                                            bias_end, bias_size, ps,
+                                                            &allocated,
+                                                            DRM_BUDDY_RANGE_ALLOCATION),
+                                     "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
+                                     bias_start + ps, bias_end, bias_size, ps);
+
+               /* bias misaligned */
+               KUNIT_ASSERT_TRUE_MSG(test,
+                                     drm_buddy_alloc_blocks(&mm, bias_start + ps,
+                                                            bias_end - ps,
+                                                            bias_size >> 1, bias_size >> 1,
+                                                            &allocated,
+                                                            DRM_BUDDY_RANGE_ALLOCATION),
+                                     "buddy_alloc h didn't fail with bias(%x-%x), size=%u, ps=%u\n",
+                                     bias_start + ps, bias_end - ps, bias_size >> 1, bias_size >> 1);
+
+               /* single big page */
+               KUNIT_ASSERT_FALSE_MSG(test,
+                                      drm_buddy_alloc_blocks(&mm, bias_start,
+                                                             bias_end, bias_size, bias_size,
+                                                             &tmp,
+                                                             DRM_BUDDY_RANGE_ALLOCATION),
+                                      "buddy_alloc i failed with bias(%x-%x), size=%u, ps=%u\n",
+                                      bias_start, bias_end, bias_size, bias_size);
+               drm_buddy_free_list(&mm, &tmp);
+
+               /* single page with internal round_up */
+               KUNIT_ASSERT_FALSE_MSG(test,
+                                      drm_buddy_alloc_blocks(&mm, bias_start,
+                                                             bias_end, ps, bias_size,
+                                                             &tmp,
+                                                             DRM_BUDDY_RANGE_ALLOCATION),
+                                      "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
+                                      bias_start, bias_end, ps, bias_size);
+               drm_buddy_free_list(&mm, &tmp);
+
+               /* random size within */
+               size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
+               if (size)
+                       KUNIT_ASSERT_FALSE_MSG(test,
+                                              drm_buddy_alloc_blocks(&mm, bias_start,
+                                                                     bias_end, size, ps,
+                                                                     &tmp,
+                                                                     DRM_BUDDY_RANGE_ALLOCATION),
+                                              "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
+                                              bias_start, bias_end, size, ps);
+
+               bias_rem -= size;
+               /* too big for current avail */
+               KUNIT_ASSERT_TRUE_MSG(test,
+                                     drm_buddy_alloc_blocks(&mm, bias_start,
+                                                            bias_end, bias_rem + ps, ps,
+                                                            &allocated,
+                                                            DRM_BUDDY_RANGE_ALLOCATION),
+                                     "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
+                                     bias_start, bias_end, bias_rem + ps, ps);
+
+               if (bias_rem) {
+                       /* random fill of the remainder */
+                       size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
+                       size = max(size, ps);
+
+                       KUNIT_ASSERT_FALSE_MSG(test,
+                                              drm_buddy_alloc_blocks(&mm, bias_start,
+                                                                     bias_end, size, ps,
+                                                                     &allocated,
+                                                                     DRM_BUDDY_RANGE_ALLOCATION),
+                                              "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
+                                              bias_start, bias_end, size, ps);
+                       /*
+                        * Intentionally allow some space to be left
+                        * unallocated, and ideally not always on the bias
+                        * boundaries.
+                        */
+                       drm_buddy_free_list(&mm, &tmp);
+               } else {
+                       list_splice_tail(&tmp, &allocated);
+               }
+       }
+
+       kfree(order);
+       drm_buddy_free_list(&mm, &allocated);
+       drm_buddy_fini(&mm);
+
+       /*
+        * Something more free-form. Idea is to pick a random starting bias
+        * range within the address space and then start filling it up. Also
+        * randomly grow the bias range in both directions as we go along. This
+        * should give us bias start/end which is not always uniform like above,
+        * and in some cases will require the allocator to jump over already
+        * allocated nodes in the middle of the address space.
+        */
+
+       KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, ps),
+                              "buddy_init failed\n");
+
+       bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps);
+       bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps);
+       bias_end = max(bias_end, bias_start + ps);
+       bias_rem = bias_end - bias_start;
+
+       do {
+               u32 size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
+
+               KUNIT_ASSERT_FALSE_MSG(test,
+                                      drm_buddy_alloc_blocks(&mm, bias_start,
+                                                             bias_end, size, ps,
+                                                             &allocated,
+                                                             DRM_BUDDY_RANGE_ALLOCATION),
+                                      "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
+                                      bias_start, bias_end, size, ps);
+               bias_rem -= size;
+
+               /*
+                * Try to randomly grow the bias range in both directions, or
+                * only one, or perhaps don't grow at all.
+                */
+               do {
+                       u32 old_bias_start = bias_start;
+                       u32 old_bias_end = bias_end;
+
+                       if (bias_start)
+                               bias_start -= round_up(prandom_u32_state(&prng) % bias_start, ps);
+                       if (bias_end != mm_size)
+                               bias_end += round_up(prandom_u32_state(&prng) % (mm_size - bias_end), ps);
+
+                       bias_rem += old_bias_start - bias_start;
+                       bias_rem += bias_end - old_bias_end;
+               } while (!bias_rem && (bias_start || bias_end != mm_size));
+       } while (bias_rem);
+
+       KUNIT_ASSERT_EQ(test, bias_start, 0);
+       KUNIT_ASSERT_EQ(test, bias_end, mm_size);
+       KUNIT_ASSERT_TRUE_MSG(test,
+                             drm_buddy_alloc_blocks(&mm, bias_start, bias_end,
+                                                    ps, ps,
+                                                    &allocated,
+                                                    DRM_BUDDY_RANGE_ALLOCATION),
+                             "buddy_alloc passed with bias(%x-%x), size=%u\n",
+                             bias_start, bias_end, ps);
+
+       drm_buddy_free_list(&mm, &allocated);
+       drm_buddy_fini(&mm);
+}
+
+static void drm_test_buddy_alloc_contiguous(struct kunit *test)
+{
+       const unsigned long ps = SZ_4K, mm_size = 16 * 3 * SZ_4K;
+       unsigned long i, n_pages, total;
+       struct drm_buddy_block *block;
+       struct drm_buddy mm;
+       LIST_HEAD(left);
+       LIST_HEAD(middle);
+       LIST_HEAD(right);
+       LIST_HEAD(allocated);
+
+       KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
+
+       /*
+        * Idea is to fragment the address space by alternating block
+        * allocations between three different lists; one for left, middle and
+        * right. We can then free a list to simulate fragmentation. In
+        * particular we want to exercise the DRM_BUDDY_CONTIGUOUS_ALLOCATION,
+        * including the try_harder path.
+        */
+
+       i = 0;
+       n_pages = mm_size / ps;
+       do {
+               struct list_head *list;
+               int slot = i % 3;
+
+               if (slot == 0)
+                       list = &left;
+               else if (slot == 1)
+                       list = &middle;
+               else
+                       list = &right;
+               KUNIT_ASSERT_FALSE_MSG(test,
+                                      drm_buddy_alloc_blocks(&mm, 0, mm_size,
+                                                             ps, ps, list, 0),
+                                      "buddy_alloc hit an error size=%lu\n",
+                                      ps);
+       } while (++i < n_pages);
+
+       KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+                                                          3 * ps, ps, &allocated,
+                                                          DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+                              "buddy_alloc didn't error size=%lu\n", 3 * ps);
+
+       drm_buddy_free_list(&mm, &middle);
+       KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+                                                          3 * ps, ps, &allocated,
+                                                          DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+                              "buddy_alloc didn't error size=%lu\n", 3 * ps);
+       KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+                                                          2 * ps, ps, &allocated,
+                                                          DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+                              "buddy_alloc didn't error size=%lu\n", 2 * ps);
+
+       drm_buddy_free_list(&mm, &right);
+       KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+                                                          3 * ps, ps, &allocated,
+                                                          DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+                              "buddy_alloc didn't error size=%lu\n", 3 * ps);
+       /*
+        * At this point we should have enough contiguous space for 2 blocks,
+        * however they are never buddies (since we freed middle and right) so
+        * will require the try_harder logic to find them.
+        */
+       KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+                                                           2 * ps, ps, &allocated,
+                                                           DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+                              "buddy_alloc hit an error size=%lu\n", 2 * ps);
+
+       drm_buddy_free_list(&mm, &left);
+       KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
+                                                           3 * ps, ps, &allocated,
+                                                           DRM_BUDDY_CONTIGUOUS_ALLOCATION),
+                              "buddy_alloc hit an error size=%lu\n", 3 * ps);
+
+       total = 0;
+       list_for_each_entry(block, &allocated, link)
+               total += drm_buddy_block_size(&mm, block);
+
+       KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3);
+
+       drm_buddy_free_list(&mm, &allocated);
+       drm_buddy_fini(&mm);
+}
+
 static void drm_test_buddy_alloc_pathological(struct kunit *test)
 {
        u64 mm_size, size, start = 0;
@@ -275,16 +567,30 @@ static void drm_test_buddy_alloc_limit(struct kunit *test)
        drm_buddy_fini(&mm);
 }
 
+static int drm_buddy_suite_init(struct kunit_suite *suite)
+{
+       while (!random_seed)
+               random_seed = get_random_u32();
+
+       kunit_info(suite, "Testing DRM buddy manager, with random_seed=0x%x\n",
+                  random_seed);
+
+       return 0;
+}
+
 static struct kunit_case drm_buddy_tests[] = {
        KUNIT_CASE(drm_test_buddy_alloc_limit),
        KUNIT_CASE(drm_test_buddy_alloc_optimistic),
        KUNIT_CASE(drm_test_buddy_alloc_pessimistic),
        KUNIT_CASE(drm_test_buddy_alloc_pathological),
+       KUNIT_CASE(drm_test_buddy_alloc_contiguous),
+       KUNIT_CASE(drm_test_buddy_alloc_range_bias),
        {}
 };
 
 static struct kunit_suite drm_buddy_test_suite = {
        .name = "drm_buddy",
+       .suite_init = drm_buddy_suite_init,
        .test_cases = drm_buddy_tests,
 };
 
index 1eb0c304f9607f6ae4034638a2cf8e3ee8da06ca..f37c0d76586568ce645b8fc42be6d1042849cbd9 100644 (file)
@@ -157,7 +157,7 @@ static void drm_test_mm_init(struct kunit *test)
 
        /* After creation, it should all be one massive hole */
        if (!assert_one_hole(test, &mm, 0, size)) {
-               KUNIT_FAIL(test, "");
+               KUNIT_FAIL(test, "mm not one hole on creation");
                goto out;
        }
 
@@ -171,14 +171,14 @@ static void drm_test_mm_init(struct kunit *test)
 
        /* After filling the range entirely, there should be no holes */
        if (!assert_no_holes(test, &mm)) {
-               KUNIT_FAIL(test, "");
+               KUNIT_FAIL(test, "mm has holes when filled");
                goto out;
        }
 
        /* And then after emptying it again, the massive hole should be back */
        drm_mm_remove_node(&tmp);
        if (!assert_one_hole(test, &mm, 0, size)) {
-               KUNIT_FAIL(test, "");
+               KUNIT_FAIL(test, "mm does not have single hole after emptying");
                goto out;
        }
 
index b62f420a9f969d61e09e1cde82f2e49b9415d8aa..112438d965ffbefd4fa2cce5f246cc03a63759f9 100644 (file)
@@ -387,7 +387,7 @@ static void ttm_pool_free_range(struct ttm_pool *pool, struct ttm_tt *tt,
                                enum ttm_caching caching,
                                pgoff_t start_page, pgoff_t end_page)
 {
-       struct page **pages = tt->pages;
+       struct page **pages = &tt->pages[start_page];
        unsigned int order;
        pgoff_t i, nr;
 
index 68d9f6116bdfc3522ee5d6d94ef2bb763ec81090..777c20ceabab12f04f3f2062df3524ef1c2c0923 100644 (file)
@@ -10,7 +10,7 @@
 
 #include "xe_bo.h"
 
-#define i915_gem_object_is_shmem(obj) ((obj)->flags & XE_BO_CREATE_SYSTEM_BIT)
+#define i915_gem_object_is_shmem(obj) (0) /* We don't use shmem */
 
 static inline dma_addr_t i915_gem_object_get_dma_address(const struct xe_bo *bo, pgoff_t n)
 {
index a6523df0f1d39fbe7f0354d404f95886a3d56424..c347e2c29f81f133c7766a5089811edb046b0085 100644 (file)
@@ -114,21 +114,21 @@ static void test_copy(struct xe_migrate *m, struct xe_bo *bo,
                                                   region |
                                                   XE_BO_NEEDS_CPU_ACCESS);
        if (IS_ERR(remote)) {
-               KUNIT_FAIL(test, "Failed to allocate remote bo for %s: %li\n",
-                          str, PTR_ERR(remote));
+               KUNIT_FAIL(test, "Failed to allocate remote bo for %s: %pe\n",
+                          str, remote);
                return;
        }
 
        err = xe_bo_validate(remote, NULL, false);
        if (err) {
-               KUNIT_FAIL(test, "Failed to validate system bo for %s: %li\n",
+               KUNIT_FAIL(test, "Failed to validate system bo for %s: %i\n",
                           str, err);
                goto out_unlock;
        }
 
        err = xe_bo_vmap(remote);
        if (err) {
-               KUNIT_FAIL(test, "Failed to vmap system bo for %s: %li\n",
+               KUNIT_FAIL(test, "Failed to vmap system bo for %s: %i\n",
                           str, err);
                goto out_unlock;
        }
index ef56bd517b28c2604b1ed8c5f494a839217d25da..421b819fd4ba9a182d1dcbb7b364ad9a144477cb 100644 (file)
@@ -21,4 +21,5 @@ kunit_test_suite(xe_mocs_test_suite);
 
 MODULE_AUTHOR("Intel Corporation");
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("xe_mocs kunit test");
 MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
index 0b0e262e2166d69da1063915fa4c6eeedfd38bd6..4d3b80ec906d0a6f44793df496ef776a90d84596 100644 (file)
 #include "xe_ttm_stolen_mgr.h"
 #include "xe_vm.h"
 
+const char *const xe_mem_type_to_name[TTM_NUM_MEM_TYPES]  = {
+       [XE_PL_SYSTEM] = "system",
+       [XE_PL_TT] = "gtt",
+       [XE_PL_VRAM0] = "vram0",
+       [XE_PL_VRAM1] = "vram1",
+       [XE_PL_STOLEN] = "stolen"
+};
+
 static const struct ttm_place sys_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
@@ -713,8 +721,7 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,
                migrate = xe->tiles[0].migrate;
 
        xe_assert(xe, migrate);
-
-       trace_xe_bo_move(bo);
+       trace_xe_bo_move(bo, new_mem->mem_type, old_mem_type, move_lacks_source);
        xe_device_mem_access_get(xe);
 
        if (xe_bo_is_pinned(bo) && !xe_bo_is_user(bo)) {
index 9b1279aca1272cd69eab6d1121ed651b83210166..8be42ac6cd07023c520988cfff2cf3599de4859f 100644 (file)
@@ -243,6 +243,7 @@ int xe_bo_evict_pinned(struct xe_bo *bo);
 int xe_bo_restore_pinned(struct xe_bo *bo);
 
 extern struct ttm_device_funcs xe_ttm_funcs;
+extern const char *const xe_mem_type_to_name[];
 
 int xe_gem_create_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file);
index 1f0b4b9ce84f585ea599ccaf7f4641c3d139121f..5176c27e4b6a4c59739f5e456f79ca7d8a77ce94 100644 (file)
@@ -83,9 +83,6 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file)
        return 0;
 }
 
-static void device_kill_persistent_exec_queues(struct xe_device *xe,
-                                              struct xe_file *xef);
-
 static void xe_file_close(struct drm_device *dev, struct drm_file *file)
 {
        struct xe_device *xe = to_xe_device(dev);
@@ -102,8 +99,6 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file)
        mutex_unlock(&xef->exec_queue.lock);
        xa_destroy(&xef->exec_queue.xa);
        mutex_destroy(&xef->exec_queue.lock);
-       device_kill_persistent_exec_queues(xe, xef);
-
        mutex_lock(&xef->vm.lock);
        xa_for_each(&xef->vm.xa, idx, vm)
                xe_vm_close_and_put(vm);
@@ -255,9 +250,6 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
                        xa_erase(&xe->usm.asid_to_vm, asid);
        }
 
-       drmm_mutex_init(&xe->drm, &xe->persistent_engines.lock);
-       INIT_LIST_HEAD(&xe->persistent_engines.list);
-
        spin_lock_init(&xe->pinned.lock);
        INIT_LIST_HEAD(&xe->pinned.kernel_bo_present);
        INIT_LIST_HEAD(&xe->pinned.external_vram);
@@ -570,37 +562,6 @@ void xe_device_shutdown(struct xe_device *xe)
 {
 }
 
-void xe_device_add_persistent_exec_queues(struct xe_device *xe, struct xe_exec_queue *q)
-{
-       mutex_lock(&xe->persistent_engines.lock);
-       list_add_tail(&q->persistent.link, &xe->persistent_engines.list);
-       mutex_unlock(&xe->persistent_engines.lock);
-}
-
-void xe_device_remove_persistent_exec_queues(struct xe_device *xe,
-                                            struct xe_exec_queue *q)
-{
-       mutex_lock(&xe->persistent_engines.lock);
-       if (!list_empty(&q->persistent.link))
-               list_del(&q->persistent.link);
-       mutex_unlock(&xe->persistent_engines.lock);
-}
-
-static void device_kill_persistent_exec_queues(struct xe_device *xe,
-                                              struct xe_file *xef)
-{
-       struct xe_exec_queue *q, *next;
-
-       mutex_lock(&xe->persistent_engines.lock);
-       list_for_each_entry_safe(q, next, &xe->persistent_engines.list,
-                                persistent.link)
-               if (q->persistent.xef == xef) {
-                       xe_exec_queue_kill(q);
-                       list_del_init(&q->persistent.link);
-               }
-       mutex_unlock(&xe->persistent_engines.lock);
-}
-
 void xe_device_wmb(struct xe_device *xe)
 {
        struct xe_gt *gt = xe_root_mmio_gt(xe);
index 3da83b2332063882afcaffb3f204410fa848de9d..08d8b72c77319a74bc34562c92ec0aab0195be42 100644 (file)
@@ -42,10 +42,6 @@ int xe_device_probe(struct xe_device *xe);
 void xe_device_remove(struct xe_device *xe);
 void xe_device_shutdown(struct xe_device *xe);
 
-void xe_device_add_persistent_exec_queues(struct xe_device *xe, struct xe_exec_queue *q);
-void xe_device_remove_persistent_exec_queues(struct xe_device *xe,
-                                            struct xe_exec_queue *q);
-
 void xe_device_wmb(struct xe_device *xe);
 
 static inline struct xe_file *to_xe_file(const struct drm_file *file)
index 5dc9127a20293e1ebb56c3684e2fdb7e6f425b43..e8491979a6f21810cf4c480af08e9b2b6abfd4ee 100644 (file)
@@ -341,14 +341,6 @@ struct xe_device {
                struct mutex lock;
        } usm;
 
-       /** @persistent_engines: engines that are closed but still running */
-       struct {
-               /** @lock: protects persistent engines */
-               struct mutex lock;
-               /** @list: list of persistent engines */
-               struct list_head list;
-       } persistent_engines;
-
        /** @pinned: pinned BO state */
        struct {
                /** @lock: protected pinned BO list state */
index 82d1305e831f298f013338e4f7ee9e6e2ea67168..6040e4d22b2809c10385fadfbd6f4d8b6fdd0b28 100644 (file)
@@ -131,14 +131,6 @@ static void bo_meminfo(struct xe_bo *bo,
 
 static void show_meminfo(struct drm_printer *p, struct drm_file *file)
 {
-       static const char *const mem_type_to_name[TTM_NUM_MEM_TYPES]  = {
-               [XE_PL_SYSTEM] = "system",
-               [XE_PL_TT] = "gtt",
-               [XE_PL_VRAM0] = "vram0",
-               [XE_PL_VRAM1] = "vram1",
-               [4 ... 6] = NULL,
-               [XE_PL_STOLEN] = "stolen"
-       };
        struct drm_memory_stats stats[TTM_NUM_MEM_TYPES] = {};
        struct xe_file *xef = file->driver_priv;
        struct ttm_device *bdev = &xef->xe->ttm;
@@ -171,7 +163,7 @@ static void show_meminfo(struct drm_printer *p, struct drm_file *file)
        spin_unlock(&client->bos_lock);
 
        for (mem_type = XE_PL_SYSTEM; mem_type < TTM_NUM_MEM_TYPES; ++mem_type) {
-               if (!mem_type_to_name[mem_type])
+               if (!xe_mem_type_to_name[mem_type])
                        continue;
 
                man = ttm_manager_type(bdev, mem_type);
@@ -182,7 +174,7 @@ static void show_meminfo(struct drm_printer *p, struct drm_file *file)
                                               DRM_GEM_OBJECT_RESIDENT |
                                               (mem_type != XE_PL_SYSTEM ? 0 :
                                               DRM_GEM_OBJECT_PURGEABLE),
-                                              mem_type_to_name[mem_type]);
+                                              xe_mem_type_to_name[mem_type]);
                }
        }
 }
index 254b1d3af4cb56888700f82b2a6b8fa3436e1a2a..49223026c89fd5e3626be84a9687774d29b6bcb2 100644 (file)
@@ -60,7 +60,6 @@ static struct xe_exec_queue *__xe_exec_queue_create(struct xe_device *xe,
        q->fence_irq = &gt->fence_irq[hwe->class];
        q->ring_ops = gt->ring_ops[hwe->class];
        q->ops = gt->exec_queue_ops;
-       INIT_LIST_HEAD(&q->persistent.link);
        INIT_LIST_HEAD(&q->compute.link);
        INIT_LIST_HEAD(&q->multi_gt_link);
 
@@ -310,102 +309,6 @@ static int exec_queue_set_timeslice(struct xe_device *xe, struct xe_exec_queue *
        return q->ops->set_timeslice(q, value);
 }
 
-static int exec_queue_set_preemption_timeout(struct xe_device *xe,
-                                            struct xe_exec_queue *q, u64 value,
-                                            bool create)
-{
-       u32 min = 0, max = 0;
-
-       xe_exec_queue_get_prop_minmax(q->hwe->eclass,
-                                     XE_EXEC_QUEUE_PREEMPT_TIMEOUT, &min, &max);
-
-       if (xe_exec_queue_enforce_schedule_limit() &&
-           !xe_hw_engine_timeout_in_range(value, min, max))
-               return -EINVAL;
-
-       return q->ops->set_preempt_timeout(q, value);
-}
-
-static int exec_queue_set_persistence(struct xe_device *xe, struct xe_exec_queue *q,
-                                     u64 value, bool create)
-{
-       if (XE_IOCTL_DBG(xe, !create))
-               return -EINVAL;
-
-       if (XE_IOCTL_DBG(xe, xe_vm_in_preempt_fence_mode(q->vm)))
-               return -EINVAL;
-
-       if (value)
-               q->flags |= EXEC_QUEUE_FLAG_PERSISTENT;
-       else
-               q->flags &= ~EXEC_QUEUE_FLAG_PERSISTENT;
-
-       return 0;
-}
-
-static int exec_queue_set_job_timeout(struct xe_device *xe, struct xe_exec_queue *q,
-                                     u64 value, bool create)
-{
-       u32 min = 0, max = 0;
-
-       if (XE_IOCTL_DBG(xe, !create))
-               return -EINVAL;
-
-       xe_exec_queue_get_prop_minmax(q->hwe->eclass,
-                                     XE_EXEC_QUEUE_JOB_TIMEOUT, &min, &max);
-
-       if (xe_exec_queue_enforce_schedule_limit() &&
-           !xe_hw_engine_timeout_in_range(value, min, max))
-               return -EINVAL;
-
-       return q->ops->set_job_timeout(q, value);
-}
-
-static int exec_queue_set_acc_trigger(struct xe_device *xe, struct xe_exec_queue *q,
-                                     u64 value, bool create)
-{
-       if (XE_IOCTL_DBG(xe, !create))
-               return -EINVAL;
-
-       if (XE_IOCTL_DBG(xe, !xe->info.has_usm))
-               return -EINVAL;
-
-       q->usm.acc_trigger = value;
-
-       return 0;
-}
-
-static int exec_queue_set_acc_notify(struct xe_device *xe, struct xe_exec_queue *q,
-                                    u64 value, bool create)
-{
-       if (XE_IOCTL_DBG(xe, !create))
-               return -EINVAL;
-
-       if (XE_IOCTL_DBG(xe, !xe->info.has_usm))
-               return -EINVAL;
-
-       q->usm.acc_notify = value;
-
-       return 0;
-}
-
-static int exec_queue_set_acc_granularity(struct xe_device *xe, struct xe_exec_queue *q,
-                                         u64 value, bool create)
-{
-       if (XE_IOCTL_DBG(xe, !create))
-               return -EINVAL;
-
-       if (XE_IOCTL_DBG(xe, !xe->info.has_usm))
-               return -EINVAL;
-
-       if (value > DRM_XE_ACC_GRANULARITY_64M)
-               return -EINVAL;
-
-       q->usm.acc_granularity = value;
-
-       return 0;
-}
-
 typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe,
                                             struct xe_exec_queue *q,
                                             u64 value, bool create);
@@ -413,12 +316,6 @@ typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe,
 static const xe_exec_queue_set_property_fn exec_queue_set_property_funcs[] = {
        [DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY] = exec_queue_set_priority,
        [DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE] = exec_queue_set_timeslice,
-       [DRM_XE_EXEC_QUEUE_SET_PROPERTY_PREEMPTION_TIMEOUT] = exec_queue_set_preemption_timeout,
-       [DRM_XE_EXEC_QUEUE_SET_PROPERTY_PERSISTENCE] = exec_queue_set_persistence,
-       [DRM_XE_EXEC_QUEUE_SET_PROPERTY_JOB_TIMEOUT] = exec_queue_set_job_timeout,
-       [DRM_XE_EXEC_QUEUE_SET_PROPERTY_ACC_TRIGGER] = exec_queue_set_acc_trigger,
-       [DRM_XE_EXEC_QUEUE_SET_PROPERTY_ACC_NOTIFY] = exec_queue_set_acc_notify,
-       [DRM_XE_EXEC_QUEUE_SET_PROPERTY_ACC_GRANULARITY] = exec_queue_set_acc_granularity,
 };
 
 static int exec_queue_user_ext_set_property(struct xe_device *xe,
@@ -437,10 +334,15 @@ static int exec_queue_user_ext_set_property(struct xe_device *xe,
 
        if (XE_IOCTL_DBG(xe, ext.property >=
                         ARRAY_SIZE(exec_queue_set_property_funcs)) ||
-           XE_IOCTL_DBG(xe, ext.pad))
+           XE_IOCTL_DBG(xe, ext.pad) ||
+           XE_IOCTL_DBG(xe, ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY &&
+                        ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE))
                return -EINVAL;
 
        idx = array_index_nospec(ext.property, ARRAY_SIZE(exec_queue_set_property_funcs));
+       if (!exec_queue_set_property_funcs[idx])
+               return -EINVAL;
+
        return exec_queue_set_property_funcs[idx](xe, q, ext.value,  create);
 }
 
@@ -704,9 +606,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
                }
 
                q = xe_exec_queue_create(xe, vm, logical_mask,
-                                        args->width, hwe,
-                                        xe_vm_in_lr_mode(vm) ? 0 :
-                                        EXEC_QUEUE_FLAG_PERSISTENT);
+                                        args->width, hwe, 0);
                up_read(&vm->lock);
                xe_vm_put(vm);
                if (IS_ERR(q))
@@ -728,8 +628,6 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
                        goto kill_exec_queue;
        }
 
-       q->persistent.xef = xef;
-
        mutex_lock(&xef->exec_queue.lock);
        err = xa_alloc(&xef->exec_queue.xa, &id, q, xa_limit_32b, GFP_KERNEL);
        mutex_unlock(&xef->exec_queue.lock);
@@ -872,10 +770,7 @@ int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data,
        if (XE_IOCTL_DBG(xe, !q))
                return -ENOENT;
 
-       if (!(q->flags & EXEC_QUEUE_FLAG_PERSISTENT))
-               xe_exec_queue_kill(q);
-       else
-               xe_device_add_persistent_exec_queues(xe, q);
+       xe_exec_queue_kill(q);
 
        trace_xe_exec_queue_close(q);
        xe_exec_queue_put(q);
index 8d4b7feb8c306b8a406a46f74c5cad2a430bdef3..36f4901d8d7ee917215d745da900ea49b7616a78 100644 (file)
@@ -105,16 +105,6 @@ struct xe_exec_queue {
                struct xe_guc_exec_queue *guc;
        };
 
-       /**
-        * @persistent: persistent exec queue state
-        */
-       struct {
-               /** @xef: file which this exec queue belongs to */
-               struct xe_file *xef;
-               /** @link: link in list of persistent exec queues */
-               struct list_head link;
-       } persistent;
-
        union {
                /**
                 * @parallel: parallel submission state
@@ -160,16 +150,6 @@ struct xe_exec_queue {
                spinlock_t lock;
        } compute;
 
-       /** @usm: unified shared memory state */
-       struct {
-               /** @acc_trigger: access counter trigger */
-               u32 acc_trigger;
-               /** @acc_notify: access counter notify */
-               u32 acc_notify;
-               /** @acc_granularity: access counter granularity */
-               u32 acc_granularity;
-       } usm;
-
        /** @ops: submission backend exec queue operations */
        const struct xe_exec_queue_ops *ops;
 
index 96b5224eb4787d4c7abd2b65b56d0559724bd2c8..acb4d9f38fd738dd5a0e66607cb1bbdbe91311c2 100644 (file)
@@ -212,7 +212,7 @@ static void xe_execlist_port_wake_locked(struct xe_execlist_port *port,
 static void xe_execlist_make_active(struct xe_execlist_exec_queue *exl)
 {
        struct xe_execlist_port *port = exl->port;
-       enum xe_exec_queue_priority priority = exl->active_priority;
+       enum xe_exec_queue_priority priority = exl->q->sched_props.priority;
 
        XE_WARN_ON(priority == XE_EXEC_QUEUE_PRIORITY_UNSET);
        XE_WARN_ON(priority < 0);
@@ -378,8 +378,6 @@ static void execlist_exec_queue_fini_async(struct work_struct *w)
                list_del(&exl->active_link);
        spin_unlock_irqrestore(&exl->port->lock, flags);
 
-       if (q->flags & EXEC_QUEUE_FLAG_PERSISTENT)
-               xe_device_remove_persistent_exec_queues(xe, q);
        drm_sched_entity_fini(&exl->entity);
        drm_sched_fini(&exl->sched);
        kfree(exl);
index 9358f733688969391e68f22a2658b08c993d296a..9fcae65b64699eadb80a82b06386588a8af07f86 100644 (file)
@@ -145,10 +145,10 @@ void xe_gt_idle_sysfs_init(struct xe_gt_idle *gtidle)
        }
 
        if (xe_gt_is_media_type(gt)) {
-               sprintf(gtidle->name, "gt%d-mc\n", gt->info.id);
+               sprintf(gtidle->name, "gt%d-mc", gt->info.id);
                gtidle->idle_residency = xe_guc_pc_mc6_residency;
        } else {
-               sprintf(gtidle->name, "gt%d-rc\n", gt->info.id);
+               sprintf(gtidle->name, "gt%d-rc", gt->info.id);
                gtidle->idle_residency = xe_guc_pc_rc6_residency;
        }
 
index 7eef23a00d77ee679b011d8e4a0dc2b3ed1bb360..f4c485289dbe4d606e9022c5b58eec8e8123fdca 100644 (file)
@@ -247,6 +247,14 @@ int xe_gt_tlb_invalidation_vma(struct xe_gt *gt,
 
        xe_gt_assert(gt, vma);
 
+       /* Execlists not supported */
+       if (gt_to_xe(gt)->info.force_execlist) {
+               if (fence)
+                       __invalidation_fence_signal(fence);
+
+               return 0;
+       }
+
        action[len++] = XE_GUC_ACTION_TLB_INVALIDATION;
        action[len++] = 0; /* seqno, replaced in send_tlb_invalidation */
        if (!xe->info.has_range_tlb_invalidation) {
@@ -317,6 +325,10 @@ int xe_gt_tlb_invalidation_wait(struct xe_gt *gt, int seqno)
        struct drm_printer p = drm_err_printer(__func__);
        int ret;
 
+       /* Execlists not supported */
+       if (gt_to_xe(gt)->info.force_execlist)
+               return 0;
+
        /*
         * XXX: See above, this algorithm only works if seqno are always in
         * order
index 54ffcfcdd41f9ce3c590f5814fcbe3d3535946ac..f22ae717b0b2d3d8ff938d83f9ea954b4d5746e4 100644 (file)
@@ -1028,8 +1028,6 @@ static void __guc_exec_queue_fini_async(struct work_struct *w)
 
        if (xe_exec_queue_is_lr(q))
                cancel_work_sync(&ge->lr_tdr);
-       if (q->flags & EXEC_QUEUE_FLAG_PERSISTENT)
-               xe_device_remove_persistent_exec_queues(gt_to_xe(q->gt), q);
        release_guc_id(guc, q);
        xe_sched_entity_fini(&ge->entity);
        xe_sched_fini(&ge->sched);
index 0ec5ad2539f1be6098aa248876a2816f65b91f38..b38319d2801e008f14fa4b5089cd1b9dc204f547 100644 (file)
@@ -682,8 +682,6 @@ static void xe_lrc_set_ppgtt(struct xe_lrc *lrc, struct xe_vm *vm)
 
 #define PVC_CTX_ASID           (0x2e + 1)
 #define PVC_CTX_ACC_CTR_THOLD  (0x2a + 1)
-#define ACC_GRANULARITY_S       20
-#define ACC_NOTIFY_S            16
 
 int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
                struct xe_exec_queue *q, struct xe_vm *vm, u32 ring_size)
@@ -754,13 +752,7 @@ int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
        xe_lrc_write_ctx_reg(lrc, CTX_RING_CTL,
                             RING_CTL_SIZE(lrc->ring.size) | RING_VALID);
        if (xe->info.has_asid && vm)
-               xe_lrc_write_ctx_reg(lrc, PVC_CTX_ASID,
-                                    (q->usm.acc_granularity <<
-                                     ACC_GRANULARITY_S) | vm->usm.asid);
-       if (xe->info.has_usm && vm)
-               xe_lrc_write_ctx_reg(lrc, PVC_CTX_ACC_CTR_THOLD,
-                                    (q->usm.acc_notify << ACC_NOTIFY_S) |
-                                    q->usm.acc_trigger);
+               xe_lrc_write_ctx_reg(lrc, PVC_CTX_ASID, vm->usm.asid);
 
        lrc->desc = LRC_VALID;
        lrc->desc |= LRC_LEGACY_64B_CONTEXT << LRC_ADDRESSING_MODE_SHIFT;
index 5f6b53ea5528b2c904ce0c4ee30e39c4a16139b7..02f7808f28cabd5533e634b41d1780769bdcbb10 100644 (file)
@@ -105,7 +105,7 @@ static void xe_resize_vram_bar(struct xe_device *xe)
 
        pci_bus_for_each_resource(root, root_res, i) {
                if (root_res && root_res->flags & (IORESOURCE_MEM | IORESOURCE_MEM_64) &&
-                   root_res->start > 0x100000000ull)
+                   (u64)root_res->start > 0x100000000ul)
                        break;
        }
 
index e45b37c3f0c262744f960d769eeed29a07ef14e7..6653c045f3c927f21e9d73dacb591ad363e01c47 100644 (file)
@@ -20,8 +20,8 @@
 
 struct xe_pt_dir {
        struct xe_pt pt;
-       /** @dir: Directory structure for the xe_pt_walk functionality */
-       struct xe_ptw_dir dir;
+       /** @children: Array of page-table child nodes */
+       struct xe_ptw *children[XE_PDES];
 };
 
 #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_VM)
@@ -44,7 +44,7 @@ static struct xe_pt_dir *as_xe_pt_dir(struct xe_pt *pt)
 
 static struct xe_pt *xe_pt_entry(struct xe_pt_dir *pt_dir, unsigned int index)
 {
-       return container_of(pt_dir->dir.entries[index], struct xe_pt, base);
+       return container_of(pt_dir->children[index], struct xe_pt, base);
 }
 
 static u64 __xe_pt_empty_pte(struct xe_tile *tile, struct xe_vm *vm,
@@ -65,6 +65,14 @@ static u64 __xe_pt_empty_pte(struct xe_tile *tile, struct xe_vm *vm,
                XE_PTE_NULL;
 }
 
+static void xe_pt_free(struct xe_pt *pt)
+{
+       if (pt->level)
+               kfree(as_xe_pt_dir(pt));
+       else
+               kfree(pt);
+}
+
 /**
  * xe_pt_create() - Create a page-table.
  * @vm: The vm to create for.
@@ -85,15 +93,19 @@ struct xe_pt *xe_pt_create(struct xe_vm *vm, struct xe_tile *tile,
 {
        struct xe_pt *pt;
        struct xe_bo *bo;
-       size_t size;
        int err;
 
-       size = !level ?  sizeof(struct xe_pt) : sizeof(struct xe_pt_dir) +
-               XE_PDES * sizeof(struct xe_ptw *);
-       pt = kzalloc(size, GFP_KERNEL);
+       if (level) {
+               struct xe_pt_dir *dir = kzalloc(sizeof(*dir), GFP_KERNEL);
+
+               pt = (dir) ? &dir->pt : NULL;
+       } else {
+               pt = kzalloc(sizeof(*pt), GFP_KERNEL);
+       }
        if (!pt)
                return ERR_PTR(-ENOMEM);
 
+       pt->level = level;
        bo = xe_bo_create_pin_map(vm->xe, tile, vm, SZ_4K,
                                  ttm_bo_type_kernel,
                                  XE_BO_CREATE_VRAM_IF_DGFX(tile) |
@@ -106,8 +118,7 @@ struct xe_pt *xe_pt_create(struct xe_vm *vm, struct xe_tile *tile,
                goto err_kfree;
        }
        pt->bo = bo;
-       pt->level = level;
-       pt->base.dir = level ? &as_xe_pt_dir(pt)->dir : NULL;
+       pt->base.children = level ? as_xe_pt_dir(pt)->children : NULL;
 
        if (vm->xef)
                xe_drm_client_add_bo(vm->xef->client, pt->bo);
@@ -116,7 +127,7 @@ struct xe_pt *xe_pt_create(struct xe_vm *vm, struct xe_tile *tile,
        return pt;
 
 err_kfree:
-       kfree(pt);
+       xe_pt_free(pt);
        return ERR_PTR(err);
 }
 
@@ -193,7 +204,7 @@ void xe_pt_destroy(struct xe_pt *pt, u32 flags, struct llist_head *deferred)
                                              deferred);
                }
        }
-       kfree(pt);
+       xe_pt_free(pt);
 }
 
 /**
@@ -358,7 +369,7 @@ xe_pt_insert_entry(struct xe_pt_stage_bind_walk *xe_walk, struct xe_pt *parent,
                struct iosys_map *map = &parent->bo->vmap;
 
                if (unlikely(xe_child))
-                       parent->base.dir->entries[offset] = &xe_child->base;
+                       parent->base.children[offset] = &xe_child->base;
 
                xe_pt_write(xe_walk->vm->xe, map, offset, pte);
                parent->num_live++;
@@ -488,10 +499,12 @@ xe_pt_stage_bind_entry(struct xe_ptw *parent, pgoff_t offset,
                 * this device *requires* 64K PTE size for VRAM, fail.
                 */
                if (level == 0 && !xe_parent->is_compact) {
-                       if (xe_pt_is_pte_ps64K(addr, next, xe_walk))
+                       if (xe_pt_is_pte_ps64K(addr, next, xe_walk)) {
+                               xe_walk->vma->gpuva.flags |= XE_VMA_PTE_64K;
                                pte |= XE_PTE_PS64;
-                       else if (XE_WARN_ON(xe_walk->needs_64K))
+                       } else if (XE_WARN_ON(xe_walk->needs_64K)) {
                                return -EINVAL;
+                       }
                }
 
                ret = xe_pt_insert_entry(xe_walk, xe_parent, offset, NULL, pte);
@@ -534,13 +547,16 @@ xe_pt_stage_bind_entry(struct xe_ptw *parent, pgoff_t offset,
                *child = &xe_child->base;
 
                /*
-                * Prefer the compact pagetable layout for L0 if possible.
+                * Prefer the compact pagetable layout for L0 if possible. Only
+                * possible if VMA covers entire 2MB region as compact 64k and
+                * 4k pages cannot be mixed within a 2MB region.
                 * TODO: Suballocate the pt bo to avoid wasting a lot of
                 * memory.
                 */
                if (GRAPHICS_VERx100(tile_to_xe(xe_walk->tile)) >= 1250 && level == 1 &&
                    covers && xe_pt_scan_64K(addr, next, xe_walk)) {
                        walk->shifts = xe_compact_pt_shifts;
+                       xe_walk->vma->gpuva.flags |= XE_VMA_PTE_COMPACT;
                        flags |= XE_PDE_64K;
                        xe_child->is_compact = true;
                }
@@ -853,7 +869,7 @@ static void xe_pt_commit_bind(struct xe_vma *vma,
                                xe_pt_destroy(xe_pt_entry(pt_dir, j_),
                                              xe_vma_vm(vma)->flags, deferred);
 
-                       pt_dir->dir.entries[j_] = &newpte->base;
+                       pt_dir->children[j_] = &newpte->base;
                }
                kfree(entries[i].pt_entries);
        }
@@ -1507,7 +1523,7 @@ xe_pt_commit_unbind(struct xe_vma *vma,
                                        xe_pt_destroy(xe_pt_entry(pt_dir, i),
                                                      xe_vma_vm(vma)->flags, deferred);
 
-                               pt_dir->dir.entries[i] = NULL;
+                               pt_dir->children[i] = NULL;
                        }
                }
        }
index 8f6c8d063f39f0293a6c4d966c009dfc24ca9045..b8b3d2aea4923d0ac087f6a2c972652aba8efc6f 100644 (file)
@@ -74,7 +74,7 @@ int xe_pt_walk_range(struct xe_ptw *parent, unsigned int level,
                     u64 addr, u64 end, struct xe_pt_walk *walk)
 {
        pgoff_t offset = xe_pt_offset(addr, level, walk);
-       struct xe_ptw **entries = parent->dir ? parent->dir->entries : NULL;
+       struct xe_ptw **entries = parent->children ? parent->children : NULL;
        const struct xe_pt_walk_ops *ops = walk->ops;
        enum page_walk_action action;
        struct xe_ptw *child;
index ec3d1e9efa6d514ae21bb4b4a1b35a0bc2baf59c..5ecc4d2f0f6536b7ec79033f80f556ce1f00edc5 100644 (file)
@@ -8,28 +8,15 @@
 #include <linux/pagewalk.h>
 #include <linux/types.h>
 
-struct xe_ptw_dir;
-
 /**
  * struct xe_ptw - base class for driver pagetable subclassing.
- * @dir: Pointer to an array of children if any.
+ * @children: Pointer to an array of children if any.
  *
  * Drivers could subclass this, and if it's a page-directory, typically
- * embed the xe_ptw_dir::entries array in the same allocation.
+ * embed an array of xe_ptw pointers.
  */
 struct xe_ptw {
-       struct xe_ptw_dir *dir;
-};
-
-/**
- * struct xe_ptw_dir - page directory structure
- * @entries: Array holding page directory children.
- *
- * It is the responsibility of the user to ensure @entries is
- * correctly sized.
- */
-struct xe_ptw_dir {
-       struct xe_ptw *entries[0];
+       struct xe_ptw **children;
 };
 
 /**
index d35d9ec58e86f95c8244fc02e6a9709b63ccf93a..372378e89e989239833879e23d2e62a2fd573b54 100644 (file)
@@ -151,6 +151,11 @@ xe_range_fence_tree_next(struct xe_range_fence *rfence, u64 start, u64 last)
        return xe_range_fence_tree_iter_next(rfence, start, last);
 }
 
+static void xe_range_fence_free(struct xe_range_fence *rfence)
+{
+       kfree(rfence);
+}
+
 const struct xe_range_fence_ops xe_range_fence_kfree_ops = {
-       .free = (void (*)(struct xe_range_fence *rfence)) kfree,
+       .free = xe_range_fence_free,
 };
index aab92bee1d7cf2ff52ec07befe0dcc220325a649..02c9577fe418516bcb891174b9599b6c0b2903bf 100644 (file)
@@ -19,7 +19,7 @@
 #include "xe_macros.h"
 #include "xe_sched_job_types.h"
 
-struct user_fence {
+struct xe_user_fence {
        struct xe_device *xe;
        struct kref refcount;
        struct dma_fence_cb cb;
@@ -27,31 +27,32 @@ struct user_fence {
        struct mm_struct *mm;
        u64 __user *addr;
        u64 value;
+       int signalled;
 };
 
 static void user_fence_destroy(struct kref *kref)
 {
-       struct user_fence *ufence = container_of(kref, struct user_fence,
+       struct xe_user_fence *ufence = container_of(kref, struct xe_user_fence,
                                                 refcount);
 
        mmdrop(ufence->mm);
        kfree(ufence);
 }
 
-static void user_fence_get(struct user_fence *ufence)
+static void user_fence_get(struct xe_user_fence *ufence)
 {
        kref_get(&ufence->refcount);
 }
 
-static void user_fence_put(struct user_fence *ufence)
+static void user_fence_put(struct xe_user_fence *ufence)
 {
        kref_put(&ufence->refcount, user_fence_destroy);
 }
 
-static struct user_fence *user_fence_create(struct xe_device *xe, u64 addr,
-                                           u64 value)
+static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
+                                              u64 value)
 {
-       struct user_fence *ufence;
+       struct xe_user_fence *ufence;
 
        ufence = kmalloc(sizeof(*ufence), GFP_KERNEL);
        if (!ufence)
@@ -69,7 +70,7 @@ static struct user_fence *user_fence_create(struct xe_device *xe, u64 addr,
 
 static void user_fence_worker(struct work_struct *w)
 {
-       struct user_fence *ufence = container_of(w, struct user_fence, worker);
+       struct xe_user_fence *ufence = container_of(w, struct xe_user_fence, worker);
 
        if (mmget_not_zero(ufence->mm)) {
                kthread_use_mm(ufence->mm);
@@ -80,10 +81,11 @@ static void user_fence_worker(struct work_struct *w)
        }
 
        wake_up_all(&ufence->xe->ufence_wq);
+       WRITE_ONCE(ufence->signalled, 1);
        user_fence_put(ufence);
 }
 
-static void kick_ufence(struct user_fence *ufence, struct dma_fence *fence)
+static void kick_ufence(struct xe_user_fence *ufence, struct dma_fence *fence)
 {
        INIT_WORK(&ufence->worker, user_fence_worker);
        queue_work(ufence->xe->ordered_wq, &ufence->worker);
@@ -92,7 +94,7 @@ static void kick_ufence(struct user_fence *ufence, struct dma_fence *fence)
 
 static void user_fence_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
 {
-       struct user_fence *ufence = container_of(cb, struct user_fence, cb);
+       struct xe_user_fence *ufence = container_of(cb, struct xe_user_fence, cb);
 
        kick_ufence(ufence, fence);
 }
@@ -340,3 +342,39 @@ err_out:
 
        return ERR_PTR(-ENOMEM);
 }
+
+/**
+ * xe_sync_ufence_get() - Get user fence from sync
+ * @sync: input sync
+ *
+ * Get a user fence reference from sync.
+ *
+ * Return: xe_user_fence pointer with reference
+ */
+struct xe_user_fence *xe_sync_ufence_get(struct xe_sync_entry *sync)
+{
+       user_fence_get(sync->ufence);
+
+       return sync->ufence;
+}
+
+/**
+ * xe_sync_ufence_put() - Put user fence reference
+ * @ufence: user fence reference
+ *
+ */
+void xe_sync_ufence_put(struct xe_user_fence *ufence)
+{
+       user_fence_put(ufence);
+}
+
+/**
+ * xe_sync_ufence_get_status() - Get user fence status
+ * @ufence: user fence
+ *
+ * Return: 1 if signalled, 0 not signalled, <0 on error
+ */
+int xe_sync_ufence_get_status(struct xe_user_fence *ufence)
+{
+       return READ_ONCE(ufence->signalled);
+}
index f43cdcaca6c5794ec8b42ab3bc77e1942004d046..0fd0d51208e627c9be72eef661c160458db6f5a4 100644 (file)
@@ -38,4 +38,8 @@ static inline bool xe_sync_is_ufence(struct xe_sync_entry *sync)
        return !!sync->ufence;
 }
 
+struct xe_user_fence *xe_sync_ufence_get(struct xe_sync_entry *sync);
+void xe_sync_ufence_put(struct xe_user_fence *ufence);
+int xe_sync_ufence_get_status(struct xe_user_fence *ufence);
+
 #endif
index 852db5e7884fcde668f6f85b6e4049fa5290f8a9..30ac3f51993b944e3dd86ccb059c75441f87f5e1 100644 (file)
@@ -18,7 +18,7 @@ struct xe_sync_entry {
        struct drm_syncobj *syncobj;
        struct dma_fence *fence;
        struct dma_fence_chain *chain_fence;
-       struct user_fence *ufence;
+       struct xe_user_fence *ufence;
        u64 addr;
        u64 timeline_value;
        u32 type;
index 044c20881de7ef0ede17f4dcfcdf34863817d8de..0650b2fa75efba85aea8d2a98e7d076ebabd607a 100644 (file)
@@ -167,9 +167,10 @@ int xe_tile_init_noalloc(struct xe_tile *tile)
                goto err_mem_access;
 
        tile->mem.kernel_bb_pool = xe_sa_bo_manager_init(tile, SZ_1M, 16);
-       if (IS_ERR(tile->mem.kernel_bb_pool))
+       if (IS_ERR(tile->mem.kernel_bb_pool)) {
                err = PTR_ERR(tile->mem.kernel_bb_pool);
-
+               goto err_mem_access;
+       }
        xe_wa_apply_tile_workarounds(tile);
 
        xe_tile_sysfs_init(tile);
index 95163c303f3e11694bdc1bafd18eb6386740eb01..4ddc55527f9ab3e632635c5f920d4f4420df1255 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/tracepoint.h>
 #include <linux/types.h>
 
+#include "xe_bo.h"
 #include "xe_bo_types.h"
 #include "xe_exec_queue_types.h"
 #include "xe_gpu_scheduler_types.h"
@@ -26,16 +27,16 @@ DECLARE_EVENT_CLASS(xe_gt_tlb_invalidation_fence,
                    TP_ARGS(fence),
 
                    TP_STRUCT__entry(
-                            __field(u64, fence)
+                            __field(struct xe_gt_tlb_invalidation_fence *, fence)
                             __field(int, seqno)
                             ),
 
                    TP_fast_assign(
-                          __entry->fence = (u64)fence;
+                          __entry->fence = fence;
                           __entry->seqno = fence->seqno;
                           ),
 
-                   TP_printk("fence=0x%016llx, seqno=%d",
+                   TP_printk("fence=%p, seqno=%d",
                              __entry->fence, __entry->seqno)
 );
 
@@ -82,16 +83,16 @@ DECLARE_EVENT_CLASS(xe_bo,
                    TP_STRUCT__entry(
                             __field(size_t, size)
                             __field(u32, flags)
-                            __field(u64, vm)
+                            __field(struct xe_vm *, vm)
                             ),
 
                    TP_fast_assign(
                           __entry->size = bo->size;
                           __entry->flags = bo->flags;
-                          __entry->vm = (unsigned long)bo->vm;
+                          __entry->vm = bo->vm;
                           ),
 
-                   TP_printk("size=%zu, flags=0x%02x, vm=0x%016llx",
+                   TP_printk("size=%zu, flags=0x%02x, vm=%p",
                              __entry->size, __entry->flags, __entry->vm)
 );
 
@@ -100,9 +101,31 @@ DEFINE_EVENT(xe_bo, xe_bo_cpu_fault,
             TP_ARGS(bo)
 );
 
-DEFINE_EVENT(xe_bo, xe_bo_move,
-            TP_PROTO(struct xe_bo *bo),
-            TP_ARGS(bo)
+TRACE_EVENT(xe_bo_move,
+           TP_PROTO(struct xe_bo *bo, uint32_t new_placement, uint32_t old_placement,
+                    bool move_lacks_source),
+           TP_ARGS(bo, new_placement, old_placement, move_lacks_source),
+           TP_STRUCT__entry(
+                    __field(struct xe_bo *, bo)
+                    __field(size_t, size)
+                    __field(u32, new_placement)
+                    __field(u32, old_placement)
+                    __array(char, device_id, 12)
+                    __field(bool, move_lacks_source)
+                       ),
+
+           TP_fast_assign(
+                  __entry->bo      = bo;
+                  __entry->size = bo->size;
+                  __entry->new_placement = new_placement;
+                  __entry->old_placement = old_placement;
+                  strscpy(__entry->device_id, dev_name(xe_bo_device(__entry->bo)->drm.dev), 12);
+                  __entry->move_lacks_source = move_lacks_source;
+                  ),
+           TP_printk("move_lacks_source:%s, migrate object %p [size %zu] from %s to %s device_id:%s",
+                     __entry->move_lacks_source ? "yes" : "no", __entry->bo, __entry->size,
+                     xe_mem_type_to_name[__entry->old_placement],
+                     xe_mem_type_to_name[__entry->new_placement], __entry->device_id)
 );
 
 DECLARE_EVENT_CLASS(xe_exec_queue,
@@ -327,16 +350,16 @@ DECLARE_EVENT_CLASS(xe_hw_fence,
                    TP_STRUCT__entry(
                             __field(u64, ctx)
                             __field(u32, seqno)
-                            __field(u64, fence)
+                            __field(struct xe_hw_fence *, fence)
                             ),
 
                    TP_fast_assign(
                           __entry->ctx = fence->dma.context;
                           __entry->seqno = fence->dma.seqno;
-                          __entry->fence = (unsigned long)fence;
+                          __entry->fence = fence;
                           ),
 
-                   TP_printk("ctx=0x%016llx, fence=0x%016llx, seqno=%u",
+                   TP_printk("ctx=0x%016llx, fence=%p, seqno=%u",
                              __entry->ctx, __entry->fence, __entry->seqno)
 );
 
@@ -365,7 +388,7 @@ DECLARE_EVENT_CLASS(xe_vma,
                    TP_ARGS(vma),
 
                    TP_STRUCT__entry(
-                            __field(u64, vma)
+                            __field(struct xe_vma *, vma)
                             __field(u32, asid)
                             __field(u64, start)
                             __field(u64, end)
@@ -373,14 +396,14 @@ DECLARE_EVENT_CLASS(xe_vma,
                             ),
 
                    TP_fast_assign(
-                          __entry->vma = (unsigned long)vma;
+                          __entry->vma = vma;
                           __entry->asid = xe_vma_vm(vma)->usm.asid;
                           __entry->start = xe_vma_start(vma);
                           __entry->end = xe_vma_end(vma) - 1;
                           __entry->ptr = xe_vma_userptr(vma);
                           ),
 
-                   TP_printk("vma=0x%016llx, asid=0x%05x, start=0x%012llx, end=0x%012llx, ptr=0x%012llx,",
+                   TP_printk("vma=%p, asid=0x%05x, start=0x%012llx, end=0x%012llx, userptr=0x%012llx,",
                              __entry->vma, __entry->asid, __entry->start,
                              __entry->end, __entry->ptr)
 )
@@ -465,16 +488,16 @@ DECLARE_EVENT_CLASS(xe_vm,
                    TP_ARGS(vm),
 
                    TP_STRUCT__entry(
-                            __field(u64, vm)
+                            __field(struct xe_vm *, vm)
                             __field(u32, asid)
                             ),
 
                    TP_fast_assign(
-                          __entry->vm = (unsigned long)vm;
+                          __entry->vm = vm;
                           __entry->asid = vm->usm.asid;
                           ),
 
-                   TP_printk("vm=0x%016llx, asid=0x%05x",  __entry->vm,
+                   TP_printk("vm=%p, asid=0x%05x",  __entry->vm,
                              __entry->asid)
 );
 
index 865e10d0a06aa31bc13fc60802257b80ebdc9430..3b21afe5b4883fa64aeb92c6d2174b014be96c59 100644 (file)
@@ -897,6 +897,11 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
        struct xe_device *xe = vm->xe;
        bool read_only = xe_vma_read_only(vma);
 
+       if (vma->ufence) {
+               xe_sync_ufence_put(vma->ufence);
+               vma->ufence = NULL;
+       }
+
        if (xe_vma_is_userptr(vma)) {
                struct xe_userptr *userptr = &to_userptr_vma(vma)->userptr;
 
@@ -995,9 +1000,16 @@ int xe_vm_prepare_vma(struct drm_exec *exec, struct xe_vma *vma,
        int err;
 
        XE_WARN_ON(!vm);
-       err = drm_exec_prepare_obj(exec, xe_vm_obj(vm), num_shared);
-       if (!err && bo && !bo->vm)
-               err = drm_exec_prepare_obj(exec, &bo->ttm.base, num_shared);
+       if (num_shared)
+               err = drm_exec_prepare_obj(exec, xe_vm_obj(vm), num_shared);
+       else
+               err = drm_exec_lock_obj(exec, xe_vm_obj(vm));
+       if (!err && bo && !bo->vm) {
+               if (num_shared)
+                       err = drm_exec_prepare_obj(exec, &bo->ttm.base, num_shared);
+               else
+                       err = drm_exec_lock_obj(exec, &bo->ttm.base);
+       }
 
        return err;
 }
@@ -1601,6 +1613,16 @@ xe_vm_unbind_vma(struct xe_vma *vma, struct xe_exec_queue *q,
 
        trace_xe_vma_unbind(vma);
 
+       if (vma->ufence) {
+               struct xe_user_fence * const f = vma->ufence;
+
+               if (!xe_sync_ufence_get_status(f))
+                       return ERR_PTR(-EBUSY);
+
+               vma->ufence = NULL;
+               xe_sync_ufence_put(f);
+       }
+
        if (number_tiles > 1) {
                fences = kmalloc_array(number_tiles, sizeof(*fences),
                                       GFP_KERNEL);
@@ -1734,6 +1756,21 @@ err_fences:
        return ERR_PTR(err);
 }
 
+static struct xe_user_fence *
+find_ufence_get(struct xe_sync_entry *syncs, u32 num_syncs)
+{
+       unsigned int i;
+
+       for (i = 0; i < num_syncs; i++) {
+               struct xe_sync_entry *e = &syncs[i];
+
+               if (xe_sync_is_ufence(e))
+                       return xe_sync_ufence_get(e);
+       }
+
+       return NULL;
+}
+
 static int __xe_vm_bind(struct xe_vm *vm, struct xe_vma *vma,
                        struct xe_exec_queue *q, struct xe_sync_entry *syncs,
                        u32 num_syncs, bool immediate, bool first_op,
@@ -1741,9 +1778,16 @@ static int __xe_vm_bind(struct xe_vm *vm, struct xe_vma *vma,
 {
        struct dma_fence *fence;
        struct xe_exec_queue *wait_exec_queue = to_wait_exec_queue(vm, q);
+       struct xe_user_fence *ufence;
 
        xe_vm_assert_held(vm);
 
+       ufence = find_ufence_get(syncs, num_syncs);
+       if (vma->ufence && ufence)
+               xe_sync_ufence_put(vma->ufence);
+
+       vma->ufence = ufence ?: vma->ufence;
+
        if (immediate) {
                fence = xe_vm_bind_vma(vma, q, syncs, num_syncs, first_op,
                                       last_op);
@@ -2110,10 +2154,6 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_bo *bo,
                struct xe_vma_op *op = gpuva_op_to_vma_op(__op);
 
                if (__op->op == DRM_GPUVA_OP_MAP) {
-                       op->map.immediate =
-                               flags & DRM_XE_VM_BIND_FLAG_IMMEDIATE;
-                       op->map.read_only =
-                               flags & DRM_XE_VM_BIND_FLAG_READONLY;
                        op->map.is_null = flags & DRM_XE_VM_BIND_FLAG_NULL;
                        op->map.pat_index = pat_index;
                } else if (__op->op == DRM_GPUVA_OP_PREFETCH) {
@@ -2183,15 +2223,17 @@ static u64 xe_vma_max_pte_size(struct xe_vma *vma)
 {
        if (vma->gpuva.flags & XE_VMA_PTE_1G)
                return SZ_1G;
-       else if (vma->gpuva.flags & XE_VMA_PTE_2M)
+       else if (vma->gpuva.flags & (XE_VMA_PTE_2M | XE_VMA_PTE_COMPACT))
                return SZ_2M;
+       else if (vma->gpuva.flags & XE_VMA_PTE_64K)
+               return SZ_64K;
        else if (vma->gpuva.flags & XE_VMA_PTE_4K)
                return SZ_4K;
 
        return SZ_1G;   /* Uninitialized, used max size */
 }
 
-static u64 xe_vma_set_pte_size(struct xe_vma *vma, u64 size)
+static void xe_vma_set_pte_size(struct xe_vma *vma, u64 size)
 {
        switch (size) {
        case SZ_1G:
@@ -2200,9 +2242,13 @@ static u64 xe_vma_set_pte_size(struct xe_vma *vma, u64 size)
        case SZ_2M:
                vma->gpuva.flags |= XE_VMA_PTE_2M;
                break;
+       case SZ_64K:
+               vma->gpuva.flags |= XE_VMA_PTE_64K;
+               break;
+       case SZ_4K:
+               vma->gpuva.flags |= XE_VMA_PTE_4K;
+               break;
        }
-
-       return SZ_4K;
 }
 
 static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op)
@@ -2300,8 +2346,6 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct xe_exec_queue *q,
                switch (op->base.op) {
                case DRM_GPUVA_OP_MAP:
                {
-                       flags |= op->map.read_only ?
-                               VMA_CREATE_FLAG_READ_ONLY : 0;
                        flags |= op->map.is_null ?
                                VMA_CREATE_FLAG_IS_NULL : 0;
 
@@ -2432,7 +2476,7 @@ static int op_execute(struct drm_exec *exec, struct xe_vm *vm,
        case DRM_GPUVA_OP_MAP:
                err = xe_vm_bind(vm, vma, op->q, xe_vma_bo(vma),
                                 op->syncs, op->num_syncs,
-                                op->map.immediate || !xe_vm_in_fault_mode(vm),
+                                !xe_vm_in_fault_mode(vm),
                                 op->flags & XE_VMA_OP_FIRST,
                                 op->flags & XE_VMA_OP_LAST);
                break;
@@ -2707,14 +2751,11 @@ static int vm_bind_ioctl_ops_execute(struct xe_vm *vm,
        return 0;
 }
 
-#define SUPPORTED_FLAGS        \
-       (DRM_XE_VM_BIND_FLAG_READONLY | \
-        DRM_XE_VM_BIND_FLAG_IMMEDIATE | DRM_XE_VM_BIND_FLAG_NULL)
+#define SUPPORTED_FLAGS        (DRM_XE_VM_BIND_FLAG_NULL | \
+        DRM_XE_VM_BIND_FLAG_DUMPABLE)
 #define XE_64K_PAGE_MASK 0xffffull
 #define ALL_DRM_XE_SYNCS_FLAGS (DRM_XE_SYNCS_FLAG_WAIT_FOR_OP)
 
-#define MAX_BINDS      512     /* FIXME: Picking random upper limit */
-
 static int vm_bind_ioctl_check_args(struct xe_device *xe,
                                    struct drm_xe_vm_bind *args,
                                    struct drm_xe_vm_bind_op **bind_ops)
@@ -2726,16 +2767,16 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe,
            XE_IOCTL_DBG(xe, args->reserved[0] || args->reserved[1]))
                return -EINVAL;
 
-       if (XE_IOCTL_DBG(xe, args->extensions) ||
-           XE_IOCTL_DBG(xe, args->num_binds > MAX_BINDS))
+       if (XE_IOCTL_DBG(xe, args->extensions))
                return -EINVAL;
 
        if (args->num_binds > 1) {
                u64 __user *bind_user =
                        u64_to_user_ptr(args->vector_of_binds);
 
-               *bind_ops = kmalloc(sizeof(struct drm_xe_vm_bind_op) *
-                                   args->num_binds, GFP_KERNEL);
+               *bind_ops = kvmalloc_array(args->num_binds,
+                                          sizeof(struct drm_xe_vm_bind_op),
+                                          GFP_KERNEL | __GFP_ACCOUNT);
                if (!*bind_ops)
                        return -ENOMEM;
 
@@ -2825,7 +2866,7 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe,
 
 free_bind_ops:
        if (args->num_binds > 1)
-               kfree(*bind_ops);
+               kvfree(*bind_ops);
        return err;
 }
 
@@ -2913,13 +2954,15 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        }
 
        if (args->num_binds) {
-               bos = kcalloc(args->num_binds, sizeof(*bos), GFP_KERNEL);
+               bos = kvcalloc(args->num_binds, sizeof(*bos),
+                              GFP_KERNEL | __GFP_ACCOUNT);
                if (!bos) {
                        err = -ENOMEM;
                        goto release_vm_lock;
                }
 
-               ops = kcalloc(args->num_binds, sizeof(*ops), GFP_KERNEL);
+               ops = kvcalloc(args->num_binds, sizeof(*ops),
+                              GFP_KERNEL | __GFP_ACCOUNT);
                if (!ops) {
                        err = -ENOMEM;
                        goto release_vm_lock;
@@ -3060,10 +3103,10 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        for (i = 0; bos && i < args->num_binds; ++i)
                xe_bo_put(bos[i]);
 
-       kfree(bos);
-       kfree(ops);
+       kvfree(bos);
+       kvfree(ops);
        if (args->num_binds > 1)
-               kfree(bind_ops);
+               kvfree(bind_ops);
 
        return err;
 
@@ -3087,10 +3130,10 @@ put_exec_queue:
        if (q)
                xe_exec_queue_put(q);
 free_objs:
-       kfree(bos);
-       kfree(ops);
+       kvfree(bos);
+       kvfree(ops);
        if (args->num_binds > 1)
-               kfree(bind_ops);
+               kvfree(bind_ops);
        return err;
 }
 
index 5ac9c5bebabc3cf3ecf528f51f8aa92cebc410ef..7300eea5394ba8c1ece10dba63314bf733ee5157 100644 (file)
@@ -19,6 +19,7 @@
 
 struct xe_bo;
 struct xe_sync_entry;
+struct xe_user_fence;
 struct xe_vm;
 
 #define XE_VMA_READ_ONLY       DRM_GPUVA_USERBITS
@@ -29,6 +30,8 @@ struct xe_vm;
 #define XE_VMA_PTE_4K          (DRM_GPUVA_USERBITS << 5)
 #define XE_VMA_PTE_2M          (DRM_GPUVA_USERBITS << 6)
 #define XE_VMA_PTE_1G          (DRM_GPUVA_USERBITS << 7)
+#define XE_VMA_PTE_64K         (DRM_GPUVA_USERBITS << 8)
+#define XE_VMA_PTE_COMPACT     (DRM_GPUVA_USERBITS << 9)
 
 /** struct xe_userptr - User pointer */
 struct xe_userptr {
@@ -102,6 +105,12 @@ struct xe_vma {
         * @pat_index: The pat index to use when encoding the PTEs for this vma.
         */
        u16 pat_index;
+
+       /**
+        * @ufence: The user fence that was provided with MAP.
+        * Needs to be signalled before UNMAP can be processed.
+        */
+       struct xe_user_fence *ufence;
 };
 
 /**
@@ -286,10 +295,6 @@ struct xe_vm {
 struct xe_vma_op_map {
        /** @vma: VMA to map */
        struct xe_vma *vma;
-       /** @immediate: Immediate bind */
-       bool immediate;
-       /** @read_only: Read only */
-       bool read_only;
        /** @is_null: is NULL binding */
        bool is_null;
        /** @pat_index: The pat index to use for this operation. */
index 42fd504abbcda248e67fd84a64e2f96a2609b4cb..89983d7d73ca1539c19ff4a511c0c179bd07ed91 100644 (file)
@@ -169,6 +169,7 @@ static const struct host1x_info host1x06_info = {
        .num_sid_entries = ARRAY_SIZE(tegra186_sid_table),
        .sid_table = tegra186_sid_table,
        .reserve_vblank_syncpts = false,
+       .skip_reset_assert = true,
 };
 
 static const struct host1x_sid_entry tegra194_sid_table[] = {
@@ -680,13 +681,15 @@ static int __maybe_unused host1x_runtime_suspend(struct device *dev)
        host1x_intr_stop(host);
        host1x_syncpt_save(host);
 
-       err = reset_control_bulk_assert(host->nresets, host->resets);
-       if (err) {
-               dev_err(dev, "failed to assert reset: %d\n", err);
-               goto resume_host1x;
-       }
+       if (!host->info->skip_reset_assert) {
+               err = reset_control_bulk_assert(host->nresets, host->resets);
+               if (err) {
+                       dev_err(dev, "failed to assert reset: %d\n", err);
+                       goto resume_host1x;
+               }
 
-       usleep_range(1000, 2000);
+               usleep_range(1000, 2000);
+       }
 
        clk_disable_unprepare(host->clk);
        reset_control_bulk_release(host->nresets, host->resets);
index c8e302de76257008aa3fb172da0c3acd4412c572..925a118db23f5751cbbe50db317e98fd4c543414 100644 (file)
@@ -116,6 +116,12 @@ struct host1x_info {
         * the display driver disables VBLANK increments.
         */
        bool reserve_vblank_syncpts;
+       /*
+        * On Tegra186, secure world applications may require access to
+        * host1x during suspend/resume. To allow this, we need to leave
+        * host1x not in reset.
+        */
+       bool skip_reset_assert;
 };
 
 struct host1x {
index 6ef0c88e3e60a6910eb60f052107dafac9f01d1c..d2f3f234f29dea35b2bfb37ef693ba9d6a9b8bf6 100644 (file)
@@ -203,6 +203,8 @@ struct hidpp_device {
        struct hidpp_scroll_counter vertical_wheel_counter;
 
        u8 wireless_feature_index;
+
+       bool connected_once;
 };
 
 /* HID++ 1.0 error codes */
@@ -988,8 +990,13 @@ static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp)
        hidpp->protocol_minor = response.rap.params[1];
 
 print_version:
-       hid_info(hidpp->hid_dev, "HID++ %u.%u device connected.\n",
-                hidpp->protocol_major, hidpp->protocol_minor);
+       if (!hidpp->connected_once) {
+               hid_info(hidpp->hid_dev, "HID++ %u.%u device connected.\n",
+                        hidpp->protocol_major, hidpp->protocol_minor);
+               hidpp->connected_once = true;
+       } else
+               hid_dbg(hidpp->hid_dev, "HID++ %u.%u device connected.\n",
+                        hidpp->protocol_major, hidpp->protocol_minor);
        return 0;
 }
 
@@ -4184,7 +4191,7 @@ static void hidpp_connect_event(struct work_struct *work)
        /* Get device version to check if it is connected */
        ret = hidpp_root_get_protocol_version(hidpp);
        if (ret) {
-               hid_info(hidpp->hid_dev, "Disconnected\n");
+               hid_dbg(hidpp->hid_dev, "Disconnected\n");
                if (hidpp->battery.ps) {
                        hidpp->battery.online = false;
                        hidpp->battery.status = POWER_SUPPLY_STATUS_UNKNOWN;
index fd5b0637dad683e7b20c929974c958e79936880c..3e91e4d6ba6fa335c7f5988638791d3df8d1773a 100644 (file)
@@ -2151,6 +2151,10 @@ static const struct hid_device_id mt_devices[] = {
                HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
                        USB_VENDOR_ID_SYNAPTICS, 0xcd7e) },
 
+       { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
+               HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+                       USB_VENDOR_ID_SYNAPTICS, 0xcddc) },
+
        { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
                HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
                        USB_VENDOR_ID_SYNAPTICS, 0xce08) },
index aa6cb033bb06b77f182e6df441a04e1b016aaef5..03d5601ce807b3b1d49ed88bc923774d71ace572 100644 (file)
@@ -722,6 +722,8 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev,
        spin_lock_irqsave(&ishtp_dev->cl_list_lock, flags);
        list_for_each_entry(cl, &ishtp_dev->cl_list, link) {
                cl->state = ISHTP_CL_DISCONNECTED;
+               if (warm_reset && cl->device->reference_count)
+                       continue;
 
                /*
                 * Wake any pending process. The waiter would check dev->state
index 82c907f01bd3b66af02efa1d313f3bb2f7cb7209..8a7f2f6a4f86864cd5783ed51852f56cef614d5f 100644 (file)
@@ -49,7 +49,9 @@ static void ishtp_read_list_flush(struct ishtp_cl *cl)
        list_for_each_entry_safe(rb, next, &cl->dev->read_list.list, list)
                if (rb->cl && ishtp_cl_cmp_id(cl, rb->cl)) {
                        list_del(&rb->list);
-                       ishtp_io_rb_free(rb);
+                       spin_lock(&cl->free_list_spinlock);
+                       list_add_tail(&rb->list, &cl->free_rb_list.list);
+                       spin_unlock(&cl->free_list_spinlock);
                }
        spin_unlock_irqrestore(&cl->dev->read_list_spinlock, flags);
 }
index b613f11ed9498d7045f8649496049dc1b0b91839..2bc45b24075c3fe4b70ef222bbd21a4ee11eeb21 100644 (file)
@@ -2087,7 +2087,7 @@ static int wacom_allocate_inputs(struct wacom *wacom)
        return 0;
 }
 
-static int wacom_register_inputs(struct wacom *wacom)
+static int wacom_setup_inputs(struct wacom *wacom)
 {
        struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev;
        struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
@@ -2106,10 +2106,6 @@ static int wacom_register_inputs(struct wacom *wacom)
                input_free_device(pen_input_dev);
                wacom_wac->pen_input = NULL;
                pen_input_dev = NULL;
-       } else {
-               error = input_register_device(pen_input_dev);
-               if (error)
-                       goto fail;
        }
 
        error = wacom_setup_touch_input_capabilities(touch_input_dev, wacom_wac);
@@ -2118,10 +2114,6 @@ static int wacom_register_inputs(struct wacom *wacom)
                input_free_device(touch_input_dev);
                wacom_wac->touch_input = NULL;
                touch_input_dev = NULL;
-       } else {
-               error = input_register_device(touch_input_dev);
-               if (error)
-                       goto fail;
        }
 
        error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
@@ -2130,7 +2122,34 @@ static int wacom_register_inputs(struct wacom *wacom)
                input_free_device(pad_input_dev);
                wacom_wac->pad_input = NULL;
                pad_input_dev = NULL;
-       } else {
+       }
+
+       return 0;
+}
+
+static int wacom_register_inputs(struct wacom *wacom)
+{
+       struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev;
+       struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+       int error = 0;
+
+       pen_input_dev = wacom_wac->pen_input;
+       touch_input_dev = wacom_wac->touch_input;
+       pad_input_dev = wacom_wac->pad_input;
+
+       if (pen_input_dev) {
+               error = input_register_device(pen_input_dev);
+               if (error)
+                       goto fail;
+       }
+
+       if (touch_input_dev) {
+               error = input_register_device(touch_input_dev);
+               if (error)
+                       goto fail;
+       }
+
+       if (pad_input_dev) {
                error = input_register_device(pad_input_dev);
                if (error)
                        goto fail;
@@ -2383,6 +2402,20 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
        if (error)
                goto fail;
 
+       error = wacom_setup_inputs(wacom);
+       if (error)
+               goto fail;
+
+       if (features->type == HID_GENERIC)
+               connect_mask |= HID_CONNECT_DRIVER;
+
+       /* Regular HID work starts now */
+       error = hid_hw_start(hdev, connect_mask);
+       if (error) {
+               hid_err(hdev, "hw start failed\n");
+               goto fail;
+       }
+
        error = wacom_register_inputs(wacom);
        if (error)
                goto fail;
@@ -2397,16 +2430,6 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
                        goto fail;
        }
 
-       if (features->type == HID_GENERIC)
-               connect_mask |= HID_CONNECT_DRIVER;
-
-       /* Regular HID work starts now */
-       error = hid_hw_start(hdev, connect_mask);
-       if (error) {
-               hid_err(hdev, "hw start failed\n");
-               goto fail;
-       }
-
        if (!wireless) {
                /* Note that if query fails it is not a hard failure */
                wacom_query_tablet_data(wacom);
index da8a01fedd3944a7588aad5e2a523b44b2b2797c..fbe10fbc5769e53affe44a0826a55853b306c0ee 100644 (file)
@@ -2575,7 +2575,14 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
                                wacom_wac->hid_data.tipswitch);
                input_report_key(input, wacom_wac->tool[0], sense);
                if (wacom_wac->serial[0]) {
-                       input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]);
+                       /*
+                        * xf86-input-wacom does not accept a serial number
+                        * of '0'. Report the low 32 bits if possible, but
+                        * if they are zero, report the upper ones instead.
+                        */
+                       __u32 serial_lo = wacom_wac->serial[0] & 0xFFFFFFFFu;
+                       __u32 serial_hi = wacom_wac->serial[0] >> 32;
+                       input_event(input, EV_MSC, MSC_SERIAL, (int)(serial_lo ? serial_lo : serial_hi));
                        input_report_abs(input, ABS_MISC, sense ? id : 0);
                }
 
index 56f7e06c673e4236ba8d1e01957723a800af63a0..adbf674355b2b8a472c03bd60092960cb0c742cf 100644 (file)
@@ -322,125 +322,89 @@ static int create_gpadl_header(enum hv_gpadl_type type, void *kbuffer,
 
        pagecount = hv_gpadl_size(type, size) >> HV_HYP_PAGE_SHIFT;
 
-       /* do we need a gpadl body msg */
        pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
                  sizeof(struct vmbus_channel_gpadl_header) -
                  sizeof(struct gpa_range);
+       pfncount = umin(pagecount, pfnsize / sizeof(u64));
+
+       msgsize = sizeof(struct vmbus_channel_msginfo) +
+                 sizeof(struct vmbus_channel_gpadl_header) +
+                 sizeof(struct gpa_range) + pfncount * sizeof(u64);
+       msgheader =  kzalloc(msgsize, GFP_KERNEL);
+       if (!msgheader)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&msgheader->submsglist);
+       msgheader->msgsize = msgsize;
+
+       gpadl_header = (struct vmbus_channel_gpadl_header *)
+               msgheader->msg;
+       gpadl_header->rangecount = 1;
+       gpadl_header->range_buflen = sizeof(struct gpa_range) +
+                                pagecount * sizeof(u64);
+       gpadl_header->range[0].byte_offset = 0;
+       gpadl_header->range[0].byte_count = hv_gpadl_size(type, size);
+       for (i = 0; i < pfncount; i++)
+               gpadl_header->range[0].pfn_array[i] = hv_gpadl_hvpfn(
+                       type, kbuffer, size, send_offset, i);
+       *msginfo = msgheader;
+
+       pfnsum = pfncount;
+       pfnleft = pagecount - pfncount;
+
+       /* how many pfns can we fit in a body message */
+       pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
+                 sizeof(struct vmbus_channel_gpadl_body);
        pfncount = pfnsize / sizeof(u64);
 
-       if (pagecount > pfncount) {
-               /* we need a gpadl body */
-               /* fill in the header */
+       /*
+        * If pfnleft is zero, everything fits in the header and no body
+        * messages are needed
+        */
+       while (pfnleft) {
+               pfncurr = umin(pfncount, pfnleft);
                msgsize = sizeof(struct vmbus_channel_msginfo) +
-                         sizeof(struct vmbus_channel_gpadl_header) +
-                         sizeof(struct gpa_range) + pfncount * sizeof(u64);
-               msgheader =  kzalloc(msgsize, GFP_KERNEL);
-               if (!msgheader)
-                       goto nomem;
-
-               INIT_LIST_HEAD(&msgheader->submsglist);
-               msgheader->msgsize = msgsize;
-
-               gpadl_header = (struct vmbus_channel_gpadl_header *)
-                       msgheader->msg;
-               gpadl_header->rangecount = 1;
-               gpadl_header->range_buflen = sizeof(struct gpa_range) +
-                                        pagecount * sizeof(u64);
-               gpadl_header->range[0].byte_offset = 0;
-               gpadl_header->range[0].byte_count = hv_gpadl_size(type, size);
-               for (i = 0; i < pfncount; i++)
-                       gpadl_header->range[0].pfn_array[i] = hv_gpadl_hvpfn(
-                               type, kbuffer, size, send_offset, i);
-               *msginfo = msgheader;
-
-               pfnsum = pfncount;
-               pfnleft = pagecount - pfncount;
-
-               /* how many pfns can we fit */
-               pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
-                         sizeof(struct vmbus_channel_gpadl_body);
-               pfncount = pfnsize / sizeof(u64);
-
-               /* fill in the body */
-               while (pfnleft) {
-                       if (pfnleft > pfncount)
-                               pfncurr = pfncount;
-                       else
-                               pfncurr = pfnleft;
-
-                       msgsize = sizeof(struct vmbus_channel_msginfo) +
-                                 sizeof(struct vmbus_channel_gpadl_body) +
-                                 pfncurr * sizeof(u64);
-                       msgbody = kzalloc(msgsize, GFP_KERNEL);
-
-                       if (!msgbody) {
-                               struct vmbus_channel_msginfo *pos = NULL;
-                               struct vmbus_channel_msginfo *tmp = NULL;
-                               /*
-                                * Free up all the allocated messages.
-                                */
-                               list_for_each_entry_safe(pos, tmp,
-                                       &msgheader->submsglist,
-                                       msglistentry) {
-
-                                       list_del(&pos->msglistentry);
-                                       kfree(pos);
-                               }
-
-                               goto nomem;
-                       }
-
-                       msgbody->msgsize = msgsize;
-                       gpadl_body =
-                               (struct vmbus_channel_gpadl_body *)msgbody->msg;
+                         sizeof(struct vmbus_channel_gpadl_body) +
+                         pfncurr * sizeof(u64);
+               msgbody = kzalloc(msgsize, GFP_KERNEL);
 
+               if (!msgbody) {
+                       struct vmbus_channel_msginfo *pos = NULL;
+                       struct vmbus_channel_msginfo *tmp = NULL;
                        /*
-                        * Gpadl is u32 and we are using a pointer which could
-                        * be 64-bit
-                        * This is governed by the guest/host protocol and
-                        * so the hypervisor guarantees that this is ok.
+                        * Free up all the allocated messages.
                         */
-                       for (i = 0; i < pfncurr; i++)
-                               gpadl_body->pfn[i] = hv_gpadl_hvpfn(type,
-                                       kbuffer, size, send_offset, pfnsum + i);
-
-                       /* add to msg header */
-                       list_add_tail(&msgbody->msglistentry,
-                                     &msgheader->submsglist);
-                       pfnsum += pfncurr;
-                       pfnleft -= pfncurr;
+                       list_for_each_entry_safe(pos, tmp,
+                               &msgheader->submsglist,
+                               msglistentry) {
+
+                               list_del(&pos->msglistentry);
+                               kfree(pos);
+                       }
+                       kfree(msgheader);
+                       return -ENOMEM;
                }
-       } else {
-               /* everything fits in a header */
-               msgsize = sizeof(struct vmbus_channel_msginfo) +
-                         sizeof(struct vmbus_channel_gpadl_header) +
-                         sizeof(struct gpa_range) + pagecount * sizeof(u64);
-               msgheader = kzalloc(msgsize, GFP_KERNEL);
-               if (msgheader == NULL)
-                       goto nomem;
-
-               INIT_LIST_HEAD(&msgheader->submsglist);
-               msgheader->msgsize = msgsize;
-
-               gpadl_header = (struct vmbus_channel_gpadl_header *)
-                       msgheader->msg;
-               gpadl_header->rangecount = 1;
-               gpadl_header->range_buflen = sizeof(struct gpa_range) +
-                                        pagecount * sizeof(u64);
-               gpadl_header->range[0].byte_offset = 0;
-               gpadl_header->range[0].byte_count = hv_gpadl_size(type, size);
-               for (i = 0; i < pagecount; i++)
-                       gpadl_header->range[0].pfn_array[i] = hv_gpadl_hvpfn(
-                               type, kbuffer, size, send_offset, i);
-
-               *msginfo = msgheader;
+
+               msgbody->msgsize = msgsize;
+               gpadl_body = (struct vmbus_channel_gpadl_body *)msgbody->msg;
+
+               /*
+                * Gpadl is u32 and we are using a pointer which could
+                * be 64-bit
+                * This is governed by the guest/host protocol and
+                * so the hypervisor guarantees that this is ok.
+                */
+               for (i = 0; i < pfncurr; i++)
+                       gpadl_body->pfn[i] = hv_gpadl_hvpfn(type,
+                               kbuffer, size, send_offset, pfnsum + i);
+
+               /* add to msg header */
+               list_add_tail(&msgbody->msglistentry, &msgheader->submsglist);
+               pfnsum += pfncurr;
+               pfnleft -= pfncurr;
        }
 
        return 0;
-nomem:
-       kfree(msgheader);
-       kfree(msgbody);
-       return -ENOMEM;
 }
 
 /*
index 42aec2c5606af756cc89c88cd50d158a733d784e..9c97c4065fe736e7e076894999447a2def819c24 100644 (file)
@@ -296,6 +296,11 @@ static struct {
        spinlock_t                      lock;
 } host_ts;
 
+static bool timesync_implicit;
+
+module_param(timesync_implicit, bool, 0644);
+MODULE_PARM_DESC(timesync_implicit, "If set treat SAMPLE as SYNC when clock is behind");
+
 static inline u64 reftime_to_ns(u64 reftime)
 {
        return (reftime - WLTIMEDELTA) * 100;
@@ -344,6 +349,29 @@ static void hv_set_host_time(struct work_struct *work)
                do_settimeofday64(&ts);
 }
 
+/*
+ * Due to a bug on Hyper-V hosts, the sync flag may not always be sent on resume.
+ * Force a sync if the guest is behind.
+ */
+static inline bool hv_implicit_sync(u64 host_time)
+{
+       struct timespec64 new_ts;
+       struct timespec64 threshold_ts;
+
+       new_ts = ns_to_timespec64(reftime_to_ns(host_time));
+       ktime_get_real_ts64(&threshold_ts);
+
+       threshold_ts.tv_sec += 5;
+
+       /*
+        * If guest behind the host by 5 or more seconds.
+        */
+       if (timespec64_compare(&new_ts, &threshold_ts) >= 0)
+               return true;
+
+       return false;
+}
+
 /*
  * Synchronize time with host after reboot, restore, etc.
  *
@@ -384,7 +412,8 @@ static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 adj_flags)
        spin_unlock_irqrestore(&host_ts.lock, flags);
 
        /* Schedule work to do do_settimeofday64() */
-       if (adj_flags & ICTIMESYNCFLAG_SYNC)
+       if ((adj_flags & ICTIMESYNCFLAG_SYNC) ||
+           (timesync_implicit && hv_implicit_sync(host_ts.host_time)))
                schedule_work(&adj_time_work);
 }
 
index b33d5abd9beb234f98fdcb9d50636a3affc93c35..7f7965f3d187884d87a2a822c3479485e17cec62 100644 (file)
@@ -988,7 +988,7 @@ static const struct dev_pm_ops vmbus_pm = {
 };
 
 /* The one and only one */
-static struct bus_type  hv_bus = {
+static const struct bus_type  hv_bus = {
        .name =         "vmbus",
        .match =                vmbus_match,
        .shutdown =             vmbus_shutdown,
index b8fc8d1ef20dfcb6132a168425df2d7e2653afa4..b0991dde2e59d2a80b23ecdc8d2e9a10dd9547cb 100644 (file)
@@ -782,7 +782,7 @@ static int __init coretemp_init(void)
        if (!x86_match_cpu(coretemp_ids))
                return -ENODEV;
 
-       max_zones = topology_max_packages() * topology_max_die_per_package();
+       max_zones = topology_max_packages() * topology_max_dies_per_package();
        zone_devices = kcalloc(max_zones, sizeof(struct platform_device *),
                              GFP_KERNEL);
        if (!zone_devices)
index 6307112c2c0c61528cd5d6af929c7b85144792ba..9ed2c4b6734edb154cdc5180e0054fb2a123e37b 100644 (file)
@@ -209,7 +209,7 @@ static ssize_t power1_average_show(struct device *dev,
         * With the new x86 topology modelling, x86_max_cores is the
         * compute unit number.
         */
-       cu_num = boot_cpu_data.x86_max_cores;
+       cu_num = topology_num_cores_per_package();
 
        ret = read_registers(data);
        if (ret)
index 8d2ef3145bca3c71b0aee2d8a1fb466dd3f9cb3e..9fbab8f023340da24cf9623e8da882849358ccea 100644 (file)
@@ -3512,6 +3512,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
        const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
        const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
        int num_reg_temp, num_reg_temp_mon, num_reg_tsi_temp;
+       int num_reg_temp_config;
        struct device *hwmon_dev;
        struct sensor_template_group tsi_temp_tg;
 
@@ -3594,6 +3595,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
                reg_temp_over = NCT6106_REG_TEMP_OVER;
                reg_temp_hyst = NCT6106_REG_TEMP_HYST;
                reg_temp_config = NCT6106_REG_TEMP_CONFIG;
+               num_reg_temp_config = ARRAY_SIZE(NCT6106_REG_TEMP_CONFIG);
                reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
                reg_temp_crit = NCT6106_REG_TEMP_CRIT;
                reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
@@ -3669,6 +3671,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
                reg_temp_over = NCT6106_REG_TEMP_OVER;
                reg_temp_hyst = NCT6106_REG_TEMP_HYST;
                reg_temp_config = NCT6106_REG_TEMP_CONFIG;
+               num_reg_temp_config = ARRAY_SIZE(NCT6106_REG_TEMP_CONFIG);
                reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
                reg_temp_crit = NCT6106_REG_TEMP_CRIT;
                reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
@@ -3746,6 +3749,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
                reg_temp_over = NCT6775_REG_TEMP_OVER;
                reg_temp_hyst = NCT6775_REG_TEMP_HYST;
                reg_temp_config = NCT6775_REG_TEMP_CONFIG;
+               num_reg_temp_config = ARRAY_SIZE(NCT6775_REG_TEMP_CONFIG);
                reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
                reg_temp_crit = NCT6775_REG_TEMP_CRIT;
 
@@ -3821,6 +3825,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
                reg_temp_over = NCT6775_REG_TEMP_OVER;
                reg_temp_hyst = NCT6775_REG_TEMP_HYST;
                reg_temp_config = NCT6776_REG_TEMP_CONFIG;
+               num_reg_temp_config = ARRAY_SIZE(NCT6776_REG_TEMP_CONFIG);
                reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
                reg_temp_crit = NCT6776_REG_TEMP_CRIT;
 
@@ -3900,6 +3905,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
                reg_temp_over = NCT6779_REG_TEMP_OVER;
                reg_temp_hyst = NCT6779_REG_TEMP_HYST;
                reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+               num_reg_temp_config = ARRAY_SIZE(NCT6779_REG_TEMP_CONFIG);
                reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
                reg_temp_crit = NCT6779_REG_TEMP_CRIT;
 
@@ -4034,6 +4040,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
                reg_temp_over = NCT6779_REG_TEMP_OVER;
                reg_temp_hyst = NCT6779_REG_TEMP_HYST;
                reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+               num_reg_temp_config = ARRAY_SIZE(NCT6779_REG_TEMP_CONFIG);
                reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
                reg_temp_crit = NCT6779_REG_TEMP_CRIT;
 
@@ -4123,6 +4130,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
                reg_temp_over = NCT6798_REG_TEMP_OVER;
                reg_temp_hyst = NCT6798_REG_TEMP_HYST;
                reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+               num_reg_temp_config = ARRAY_SIZE(NCT6779_REG_TEMP_CONFIG);
                reg_temp_alternate = NCT6798_REG_TEMP_ALTERNATE;
                reg_temp_crit = NCT6798_REG_TEMP_CRIT;
 
@@ -4204,7 +4212,8 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
                                  = reg_temp_crit[src - 1];
                        if (reg_temp_crit_l && reg_temp_crit_l[i])
                                data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
-                       data->reg_temp_config[src - 1] = reg_temp_config[i];
+                       if (i < num_reg_temp_config)
+                               data->reg_temp_config[src - 1] = reg_temp_config[i];
                        data->temp_src[src - 1] = src;
                        continue;
                }
@@ -4217,7 +4226,8 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
                data->reg_temp[0][s] = reg_temp[i];
                data->reg_temp[1][s] = reg_temp_over[i];
                data->reg_temp[2][s] = reg_temp_hyst[i];
-               data->reg_temp_config[s] = reg_temp_config[i];
+               if (i < num_reg_temp_config)
+                       data->reg_temp_config[s] = reg_temp_config[i];
                if (reg_temp_crit_h && reg_temp_crit_h[i])
                        data->reg_temp[3][s] = reg_temp_crit_h[i];
                else if (reg_temp_crit[src - 1])
index 3757b9391e60ae9b0e1c2ec5e564e0ae55af0c2a..aa0ee8ecd6f2f53ea109cfeacffe5e2682ae228e 100644 (file)
@@ -90,10 +90,8 @@ obj-$(CONFIG_I2C_NPCM)               += i2c-npcm7xx.o
 obj-$(CONFIG_I2C_OCORES)       += i2c-ocores.o
 obj-$(CONFIG_I2C_OMAP)         += i2c-omap.o
 obj-$(CONFIG_I2C_OWL)          += i2c-owl.o
-i2c-pasemi-objs := i2c-pasemi-core.o i2c-pasemi-pci.o
-obj-$(CONFIG_I2C_PASEMI)       += i2c-pasemi.o
-i2c-apple-objs := i2c-pasemi-core.o i2c-pasemi-platform.o
-obj-$(CONFIG_I2C_APPLE)        += i2c-apple.o
+obj-$(CONFIG_I2C_PASEMI)       += i2c-pasemi-core.o i2c-pasemi-pci.o
+obj-$(CONFIG_I2C_APPLE)                += i2c-pasemi-core.o i2c-pasemi-platform.o
 obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
 obj-$(CONFIG_I2C_PNX)          += i2c-pnx.o
 obj-$(CONFIG_I2C_PXA)          += i2c-pxa.o
index 5511fd46a65eae66b46f3e3385fe15f0c8970a2b..ce8c4846b7fae4548e36ccd78ce59ce1c90532f3 100644 (file)
@@ -445,6 +445,7 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
                        irq_status);
                irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS);
                if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
+                       irq_handled = irq_status;
                        bus->cmd_err = ret;
                        bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
                        goto out_complete;
index 3932e8d96a17173fa3b4f7ad90ebcbb786e99370..274e987e4cfa0f9b90a576b83d2a96368b7f50a3 100644 (file)
@@ -498,11 +498,10 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
        /* Set block buffer mode */
        outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
 
-       inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
-
        if (read_write == I2C_SMBUS_WRITE) {
                len = data->block[0];
                outb_p(len, SMBHSTDAT0(priv));
+               inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
                for (i = 0; i < len; i++)
                        outb_p(data->block[i+1], SMBBLKDAT(priv));
        }
@@ -520,6 +519,7 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
                }
 
                data->block[0] = len;
+               inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
                for (i = 0; i < len; i++)
                        data->block[i + 1] = inb_p(SMBBLKDAT(priv));
        }
@@ -1416,7 +1416,6 @@ static void i801_add_mux(struct i801_priv *priv)
                lookup->table[i] = GPIO_LOOKUP(mux_config->gpio_chip,
                                               mux_config->gpios[i], "mux", 0);
        gpiod_add_lookup_table(lookup);
-       priv->lookup = lookup;
 
        /*
         * Register the mux device, we use PLATFORM_DEVID_NONE here
@@ -1430,7 +1429,10 @@ static void i801_add_mux(struct i801_priv *priv)
                                sizeof(struct i2c_mux_gpio_platform_data));
        if (IS_ERR(priv->mux_pdev)) {
                gpiod_remove_lookup_table(lookup);
+               devm_kfree(dev, lookup);
                dev_err(dev, "Failed to register i2c-mux-gpio device\n");
+       } else {
+               priv->lookup = lookup;
        }
 }
 
@@ -1742,9 +1744,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
        i801_enable_host_notify(&priv->adapter);
 
-       i801_probe_optional_slaves(priv);
        /* We ignore errors - multiplexing is optional */
        i801_add_mux(priv);
+       i801_probe_optional_slaves(priv);
 
        pci_set_drvdata(dev, priv);
 
index 88a053987403cc6f59c3def73fd52cd11e2b1359..60e813137f8442895b19c6e9d871252cc32c7f24 100644 (file)
@@ -803,6 +803,11 @@ static irqreturn_t i2c_imx_slave_handle(struct imx_i2c_struct *i2c_imx,
                ctl &= ~I2CR_MTX;
                imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
                imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+
+               /* flag the last byte as processed */
+               i2c_imx_slave_event(i2c_imx,
+                                   I2C_SLAVE_READ_PROCESSED, &value);
+
                i2c_imx_slave_finish_op(i2c_imx);
                return IRQ_HANDLED;
        }
index 7d54a9f34c74b5a3b074a469dca674eb286dd50d..bd8becbdeeb28f4aa7f094df18fa7d059113dcae 100644 (file)
@@ -369,6 +369,7 @@ int pasemi_i2c_common_probe(struct pasemi_smbus *smbus)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(pasemi_i2c_common_probe);
 
 irqreturn_t pasemi_irq_handler(int irq, void *dev_id)
 {
@@ -378,3 +379,8 @@ irqreturn_t pasemi_irq_handler(int irq, void *dev_id)
        complete(&smbus->irq_completion);
        return IRQ_HANDLED;
 }
+EXPORT_SYMBOL_GPL(pasemi_irq_handler);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver");
index 0d2e7171e3a6f94a66d2ff85861723e0f2caea00..da94df466e83c9d34c6212681c087cafc8a6b788 100644 (file)
@@ -613,20 +613,20 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
 
                peripheral.addr = msgs[i].addr;
 
+               ret =  geni_i2c_gpi(gi2c, &msgs[i], &config,
+                                   &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c);
+               if (ret)
+                       goto err;
+
                if (msgs[i].flags & I2C_M_RD) {
                        ret =  geni_i2c_gpi(gi2c, &msgs[i], &config,
                                            &rx_addr, &rx_buf, I2C_READ, gi2c->rx_c);
                        if (ret)
                                goto err;
-               }
-
-               ret =  geni_i2c_gpi(gi2c, &msgs[i], &config,
-                                   &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c);
-               if (ret)
-                       goto err;
 
-               if (msgs[i].flags & I2C_M_RD)
                        dma_async_issue_pending(gi2c->rx_c);
+               }
+
                dma_async_issue_pending(gi2c->tx_c);
 
                timeout = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
index ec2a8da134e56d01be06588551db26bca47caef4..198afee5233c3d65df7552eb3343fe4d4e5d7488 100644 (file)
@@ -378,11 +378,15 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
        err = i2c_add_adapter(adap);
        if (err)
-               return err;
+               goto err_disable_clk;
 
        platform_set_drvdata(pdev, i2c_dev);
 
        return 0;
+
+err_disable_clk:
+       clk_disable_unprepare(i2c_dev->clk);
+       return err;
 }
 
 static void wmt_i2c_remove(struct platform_device *pdev)
index 91adcac875a4130d75d887b80464b76dd1f422a0..c9d7afe489e832b4a9598ffe9266084dbebd9fd6 100644 (file)
@@ -219,10 +219,12 @@ config BMA400
 
 config BMA400_I2C
        tristate
+       select REGMAP_I2C
        depends on BMA400
 
 config BMA400_SPI
        tristate
+       select REGMAP_SPI
        depends on BMA400
 
 config BMC150_ACCEL
index 90b7ae6d42b7700c9cb0a328b093352a7cec419e..484fe2e9fb1742b9adbde28d737127a4fe1d6413 100644 (file)
@@ -1429,9 +1429,11 @@ static int adxl367_verify_devid(struct adxl367_state *st)
        unsigned int val;
        int ret;
 
-       ret = regmap_read_poll_timeout(st->regmap, ADXL367_REG_DEVID, val,
-                                      val == ADXL367_DEVID_AD, 1000, 10000);
+       ret = regmap_read(st->regmap, ADXL367_REG_DEVID, &val);
        if (ret)
+               return dev_err_probe(st->dev, ret, "Failed to read dev id\n");
+
+       if (val != ADXL367_DEVID_AD)
                return dev_err_probe(st->dev, -ENODEV,
                                     "Invalid dev id 0x%02X, expected 0x%02X\n",
                                     val, ADXL367_DEVID_AD);
@@ -1510,6 +1512,8 @@ int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
        if (ret)
                return ret;
 
+       fsleep(15000);
+
        ret = adxl367_verify_devid(st);
        if (ret)
                return ret;
index b595fe94f3a321b2d8fc986d64d29dbc4f024ccc..62c74bdc0d77bff87b822d1d6ed2502ffbed6687 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "adxl367.h"
 
-#define ADXL367_I2C_FIFO_DATA  0x42
+#define ADXL367_I2C_FIFO_DATA  0x18
 
 struct adxl367_i2c_state {
        struct regmap *regmap;
index feb86fe6c422df4ad3085b1c4ffea1651ad4cfd1..62490424b6aed44698c376560550af353073b72b 100644 (file)
@@ -1821,7 +1821,7 @@ static int ad4130_setup_int_clk(struct ad4130_state *st)
 {
        struct device *dev = &st->spi->dev;
        struct device_node *of_node = dev_of_node(dev);
-       struct clk_init_data init;
+       struct clk_init_data init = {};
        const char *clk_name;
        int ret;
 
@@ -1891,10 +1891,14 @@ static int ad4130_setup(struct iio_dev *indio_dev)
                return ret;
 
        /*
-        * Configure all GPIOs for output. If configured, the interrupt function
-        * of P2 takes priority over the GPIO out function.
+        * Configure unused GPIOs for output. If configured, the interrupt
+        * function of P2 takes priority over the GPIO out function.
         */
-       val =  AD4130_IO_CONTROL_GPIO_CTRL_MASK;
+       val = 0;
+       for (i = 0; i < AD4130_MAX_GPIOS; i++)
+               if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE)
+                       val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i));
+
        val |= FIELD_PREP(AD4130_IO_CONTROL_INT_PIN_SEL_MASK, st->int_pin_sel);
 
        ret = regmap_write(st->regmap, AD4130_IO_CONTROL_REG, val);
index 57700f12480382b82299c5822ae2fb42a8d7f391..70056430505752682f5fd2c3b2e56ef1db48c7b7 100644 (file)
@@ -195,7 +195,7 @@ static int ad7091r8_gpio_setup(struct ad7091r_state *st)
        st->reset_gpio = devm_gpiod_get_optional(st->dev, "reset",
                                                 GPIOD_OUT_HIGH);
        if (IS_ERR(st->reset_gpio))
-               return dev_err_probe(st->dev, PTR_ERR(st->convst_gpio),
+               return dev_err_probe(st->dev, PTR_ERR(st->reset_gpio),
                                     "Error on requesting reset GPIO\n");
 
        if (st->reset_gpio) {
index 2de5494e7c22585aa52f016dc18e30c4f8107f37..b15b7a3b66d5a4d84bf3b48d46d88b29ec7c00d7 100644 (file)
@@ -48,6 +48,18 @@ config HDC2010
          To compile this driver as a module, choose M here: the module
          will be called hdc2010.
 
+config HDC3020
+       tristate "TI HDC3020 relative humidity and temperature sensor"
+       depends on I2C
+       select CRC8
+       help
+         Say yes here to build support for the Texas Instruments
+         HDC3020, HDC3021 and HDC3022 relative humidity and temperature
+         sensors.
+
+         To compile this driver as a module, choose M here: the module
+         will be called hdc3020.
+
 config HID_SENSOR_HUMIDITY
        tristate "HID Environmental humidity sensor"
        depends on HID_SENSOR_HUB
index f19ff3de97c56743f0ac51e2768e11c7a2816846..5fbeef299f61bfff07c6dd1f2215cf147d015b4f 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_AM2315) += am2315.o
 obj-$(CONFIG_DHT11) += dht11.o
 obj-$(CONFIG_HDC100X) += hdc100x.o
 obj-$(CONFIG_HDC2010) += hdc2010.o
+obj-$(CONFIG_HDC3020) += hdc3020.o
 obj-$(CONFIG_HID_SENSOR_HUMIDITY) += hid-sensor-humidity.o
 
 hts221-y := hts221_core.o \
index 4e3311170725bc55fa3a5dd1c2a90dccb6c3aa19..ed70415512f687b6333078f9416b9a0fd6edbfdb 100644 (file)
@@ -322,7 +322,7 @@ static int hdc3020_read_raw(struct iio_dev *indio_dev,
                if (chan->type != IIO_TEMP)
                        return -EINVAL;
 
-               *val = 16852;
+               *val = -16852;
                return IIO_VAL_INT;
 
        default:
index 83e53acfbe88011f4306f19438b6f31d4cad5b22..c7f5866a177d90edef7c30bfe54ada71cc17870c 100644 (file)
@@ -8,6 +8,7 @@ config BOSCH_BNO055
 config BOSCH_BNO055_SERIAL
        tristate "Bosch BNO055 attached via UART"
        depends on SERIAL_DEV_BUS
+       select REGMAP
        select BOSCH_BNO055
        help
          Enable this to support Bosch BNO055 IMUs attached via UART.
index 66d4ba088e70ff8c0df12685af77e4372e87985d..d4f9b5d8d28d6d7850f8e5dbf2a4f3c5d9b32d50 100644 (file)
@@ -109,6 +109,8 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
        /* compute and process only all complete datum */
        nb = fifo_count / bytes_per_datum;
        fifo_count = nb * bytes_per_datum;
+       if (nb == 0)
+               goto end_session;
        /* Each FIFO data contains all sensors, so same number for FIFO and sensor data */
        fifo_period = NSEC_PER_SEC / INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider);
        inv_sensors_timestamp_interrupt(&st->timestamp, fifo_period, nb, nb, pf->timestamp);
index 676704f9151fcb4eb111cdd89d486a48fab91f28..e6e6e94452a32801ff7427112b33f0a4bb923d2f 100644 (file)
@@ -111,6 +111,7 @@ int inv_mpu6050_prepare_fifo(struct inv_mpu6050_state *st, bool enable)
        if (enable) {
                /* reset timestamping */
                inv_sensors_timestamp_reset(&st->timestamp);
+               inv_sensors_timestamp_apply_odr(&st->timestamp, 0, 0, 0);
                /* reset FIFO */
                d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_RST;
                ret = regmap_write(st->map, st->reg->user_ctrl, d);
@@ -184,6 +185,10 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
                if (result)
                        goto error_power_off;
        } else {
+               st->chip_config.gyro_fifo_enable = 0;
+               st->chip_config.accl_fifo_enable = 0;
+               st->chip_config.temp_fifo_enable = 0;
+               st->chip_config.magn_fifo_enable = 0;
                result = inv_mpu6050_prepare_fifo(st, false);
                if (result)
                        goto error_power_off;
index 9a85752124ddc43b10ecb12ed2c48f605395b170..173dc00762a152e414feac8f1d8d626e01d4bde8 100644 (file)
@@ -1584,10 +1584,13 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
        ret = iio_device_register_sysfs_group(indio_dev,
                                              &iio_dev_opaque->chan_attr_group);
        if (ret)
-               goto error_clear_attrs;
+               goto error_free_chan_attrs;
 
        return 0;
 
+error_free_chan_attrs:
+       kfree(iio_dev_opaque->chan_attr_group.attrs);
+       iio_dev_opaque->chan_attr_group.attrs = NULL;
 error_clear_attrs:
        iio_free_chan_devattr_list(&iio_dev_opaque->channel_attr_list);
 
index 5cd27f04b45e6d911ae53e7574a916455149c2a5..b6c4bef2a7bb22bbe42463ffc7d72e934e0a2591 100644 (file)
@@ -226,6 +226,7 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
        case HID_USAGE_SENSOR_TIME_TIMESTAMP:
                als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes,
                                                                    *(s64 *)raw_data);
+               ret = 0;
                break;
        default:
                break;
index 69938204456f8bb0c1c4777d93ee7d0b8f2421dd..42b70cd42b39359ddd542e273163cab829128ab4 100644 (file)
@@ -530,6 +530,7 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq)
        struct rm3100_data *data;
        unsigned int tmp;
        int ret;
+       int samp_rate_index;
 
        indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
        if (!indio_dev)
@@ -586,9 +587,14 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq)
        ret = regmap_read(regmap, RM3100_REG_TMRC, &tmp);
        if (ret < 0)
                return ret;
+
+       samp_rate_index = tmp - RM3100_TMRC_OFFSET;
+       if (samp_rate_index < 0 || samp_rate_index >=  RM3100_SAMP_NUM) {
+               dev_err(dev, "The value read from RM3100_REG_TMRC is invalid!\n");
+               return -EINVAL;
+       }
        /* Initializing max wait time, which is double conversion time. */
-       data->conversion_time = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][2]
-                               * 2;
+       data->conversion_time = rm3100_samp_rates[samp_rate_index][2] * 2;
 
        /* Cycle count values may not be what we want. */
        if ((tmp - RM3100_TMRC_OFFSET) == 0)
index 433d6fac83c4cd95f698e1063a78c36dde79b374..a444d4b2978b581ed8f4cd63b6821e23a45a0560 100644 (file)
@@ -4,6 +4,7 @@
  *
  * Inspired by the older BMP085 driver drivers/misc/bmp085-spi.c
  */
+#include <linux/bits.h>
 #include <linux/module.h>
 #include <linux/spi/spi.h>
 #include <linux/err.h>
@@ -35,6 +36,34 @@ static int bmp280_regmap_spi_read(void *context, const void *reg,
        return spi_write_then_read(spi, reg, reg_size, val, val_size);
 }
 
+static int bmp380_regmap_spi_read(void *context, const void *reg,
+                                 size_t reg_size, void *val, size_t val_size)
+{
+       struct spi_device *spi = to_spi_device(context);
+       u8 rx_buf[4];
+       ssize_t status;
+
+       /*
+        * Maximum number of consecutive bytes read for a temperature or
+        * pressure measurement is 3.
+        */
+       if (val_size > 3)
+               return -EINVAL;
+
+       /*
+        * According to the BMP3xx datasheets, for a basic SPI read opertion,
+        * the first byte needs to be dropped and the rest are the requested
+        * data.
+        */
+       status = spi_write_then_read(spi, reg, 1, rx_buf, val_size + 1);
+       if (status)
+               return status;
+
+       memcpy(val, rx_buf + 1, val_size);
+
+       return 0;
+}
+
 static struct regmap_bus bmp280_regmap_bus = {
        .write = bmp280_regmap_spi_write,
        .read = bmp280_regmap_spi_read,
@@ -42,10 +71,19 @@ static struct regmap_bus bmp280_regmap_bus = {
        .val_format_endian_default = REGMAP_ENDIAN_BIG,
 };
 
+static struct regmap_bus bmp380_regmap_bus = {
+       .write = bmp280_regmap_spi_write,
+       .read = bmp380_regmap_spi_read,
+       .read_flag_mask = BIT(7),
+       .reg_format_endian_default = REGMAP_ENDIAN_BIG,
+       .val_format_endian_default = REGMAP_ENDIAN_BIG,
+};
+
 static int bmp280_spi_probe(struct spi_device *spi)
 {
        const struct spi_device_id *id = spi_get_device_id(spi);
        const struct bmp280_chip_info *chip_info;
+       struct regmap_bus *bmp_regmap_bus;
        struct regmap *regmap;
        int ret;
 
@@ -58,8 +96,18 @@ static int bmp280_spi_probe(struct spi_device *spi)
 
        chip_info = spi_get_device_match_data(spi);
 
+       switch (chip_info->chip_id[0]) {
+       case BMP380_CHIP_ID:
+       case BMP390_CHIP_ID:
+               bmp_regmap_bus = &bmp380_regmap_bus;
+               break;
+       default:
+               bmp_regmap_bus = &bmp280_regmap_bus;
+               break;
+       }
+
        regmap = devm_regmap_init(&spi->dev,
-                                 &bmp280_regmap_bus,
+                                 bmp_regmap_bus,
                                  &spi->dev,
                                  chip_info->regmap_config);
        if (IS_ERR(regmap)) {
@@ -87,6 +135,7 @@ static const struct of_device_id bmp280_of_spi_match[] = {
 MODULE_DEVICE_TABLE(of, bmp280_of_spi_match);
 
 static const struct spi_device_id bmp280_spi_id[] = {
+       { "bmp085", (kernel_ulong_t)&bmp180_chip_info },
        { "bmp180", (kernel_ulong_t)&bmp180_chip_info },
        { "bmp181", (kernel_ulong_t)&bmp180_chip_info },
        { "bmp280", (kernel_ulong_t)&bmp280_chip_info },
index 28c8269ba65d31f1547fc0e35c0fc9465c4b9740..0bba4c5a8d4059ba24eebbc1acb5732ebd1efc31 100644 (file)
@@ -250,18 +250,17 @@ static irqreturn_t dlh_trigger_handler(int irq, void *private)
        struct dlh_state *st = iio_priv(indio_dev);
        int ret;
        unsigned int chn, i = 0;
-       __be32 tmp_buf[2];
+       __be32 tmp_buf[2] = { };
 
        ret = dlh_start_capture_and_read(st);
        if (ret)
                goto out;
 
        for_each_set_bit(chn, indio_dev->active_scan_mask,
-               indio_dev->masklength) {
-               memcpy(tmp_buf + i,
+                        indio_dev->masklength) {
+               memcpy(&tmp_buf[i++],
                        &st->rx_buf[1] + chn * DLH_NUM_DATA_BYTES,
                        DLH_NUM_DATA_BYTES);
-               i++;
        }
 
        iio_push_to_buffers(indio_dev, tmp_buf);
index 824349659d69dc8e9ea9c1b5254d469628a5f933..ce9c5bae83bf1b934338d465ce25c5fba4e6ab2c 100644 (file)
@@ -401,6 +401,10 @@ static void bnxt_re_create_fence_wqe(struct bnxt_re_pd *pd)
        struct bnxt_re_fence_data *fence = &pd->fence;
        struct ib_mr *ib_mr = &fence->mr->ib_mr;
        struct bnxt_qplib_swqe *wqe = &fence->bind_wqe;
+       struct bnxt_re_dev *rdev = pd->rdev;
+
+       if (bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))
+               return;
 
        memset(wqe, 0, sizeof(*wqe));
        wqe->type = BNXT_QPLIB_SWQE_TYPE_BIND_MW;
@@ -455,6 +459,9 @@ static void bnxt_re_destroy_fence_mr(struct bnxt_re_pd *pd)
        struct device *dev = &rdev->en_dev->pdev->dev;
        struct bnxt_re_mr *mr = fence->mr;
 
+       if (bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))
+               return;
+
        if (fence->mw) {
                bnxt_re_dealloc_mw(fence->mw);
                fence->mw = NULL;
@@ -486,6 +493,9 @@ static int bnxt_re_create_fence_mr(struct bnxt_re_pd *pd)
        struct ib_mw *mw;
        int rc;
 
+       if (bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))
+               return 0;
+
        dma_addr = dma_map_single(dev, fence->va, BNXT_RE_FENCE_BYTES,
                                  DMA_BIDIRECTIONAL);
        rc = dma_mapping_error(dev, dma_addr);
@@ -1817,7 +1827,7 @@ int bnxt_re_modify_srq(struct ib_srq *ib_srq, struct ib_srq_attr *srq_attr,
        switch (srq_attr_mask) {
        case IB_SRQ_MAX_WR:
                /* SRQ resize is not supported */
-               break;
+               return -EINVAL;
        case IB_SRQ_LIMIT:
                /* Change the SRQ threshold */
                if (srq_attr->srq_limit > srq->qplib_srq.max_wqe)
@@ -1832,13 +1842,12 @@ int bnxt_re_modify_srq(struct ib_srq *ib_srq, struct ib_srq_attr *srq_attr,
                /* On success, update the shadow */
                srq->srq_limit = srq_attr->srq_limit;
                /* No need to Build and send response back to udata */
-               break;
+               return 0;
        default:
                ibdev_err(&rdev->ibdev,
                          "Unsupported srq_attr_mask 0x%x", srq_attr_mask);
                return -EINVAL;
        }
-       return 0;
 }
 
 int bnxt_re_query_srq(struct ib_srq *ib_srq, struct ib_srq_attr *srq_attr)
@@ -2556,11 +2565,6 @@ static int bnxt_re_build_inv_wqe(const struct ib_send_wr *wr,
        wqe->type = BNXT_QPLIB_SWQE_TYPE_LOCAL_INV;
        wqe->local_inv.inv_l_key = wr->ex.invalidate_rkey;
 
-       /* Need unconditional fence for local invalidate
-        * opcode to work as expected.
-        */
-       wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE;
-
        if (wr->send_flags & IB_SEND_SIGNALED)
                wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP;
        if (wr->send_flags & IB_SEND_SOLICITED)
@@ -2583,12 +2587,6 @@ static int bnxt_re_build_reg_wqe(const struct ib_reg_wr *wr,
        wqe->frmr.levels = qplib_frpl->hwq.level;
        wqe->type = BNXT_QPLIB_SWQE_TYPE_REG_MR;
 
-       /* Need unconditional fence for reg_mr
-        * opcode to function as expected.
-        */
-
-       wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE;
-
        if (wr->wr.send_flags & IB_SEND_SIGNALED)
                wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP;
 
@@ -2719,6 +2717,18 @@ bad:
        return rc;
 }
 
+static void bnxt_re_legacy_set_uc_fence(struct bnxt_qplib_swqe *wqe)
+{
+       /* Need unconditional fence for non-wire memory opcode
+        * to work as expected.
+        */
+       if (wqe->type == BNXT_QPLIB_SWQE_TYPE_LOCAL_INV ||
+           wqe->type == BNXT_QPLIB_SWQE_TYPE_FAST_REG_MR ||
+           wqe->type == BNXT_QPLIB_SWQE_TYPE_REG_MR ||
+           wqe->type == BNXT_QPLIB_SWQE_TYPE_BIND_MW)
+               wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE;
+}
+
 int bnxt_re_post_send(struct ib_qp *ib_qp, const struct ib_send_wr *wr,
                      const struct ib_send_wr **bad_wr)
 {
@@ -2798,8 +2808,11 @@ int bnxt_re_post_send(struct ib_qp *ib_qp, const struct ib_send_wr *wr,
                        rc = -EINVAL;
                        goto bad;
                }
-               if (!rc)
+               if (!rc) {
+                       if (!bnxt_qplib_is_chip_gen_p5_p7(qp->rdev->chip_ctx))
+                               bnxt_re_legacy_set_uc_fence(&wqe);
                        rc = bnxt_qplib_post_send(&qp->qplib_qp, &wqe);
+               }
 bad:
                if (rc) {
                        ibdev_err(&qp->rdev->ibdev,
index f022c922fae5183cb6860092e5bd0662d22f1764..54b4d2f3a5d885d1f17643a2416420cb6b805b8a 100644 (file)
@@ -280,9 +280,6 @@ static void bnxt_re_set_resource_limits(struct bnxt_re_dev *rdev)
 
 static void bnxt_re_vf_res_config(struct bnxt_re_dev *rdev)
 {
-
-       if (test_bit(BNXT_RE_FLAG_ERR_DEVICE_DETACHED, &rdev->flags))
-               return;
        rdev->num_vfs = pci_sriov_get_totalvfs(rdev->en_dev->pdev);
        if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) {
                bnxt_re_set_resource_limits(rdev);
index c98e04fe2ddd477dd8457c09bef64c9339b992f4..439d0c7c5d0cab91e028b380435aaf898f9856c3 100644 (file)
@@ -744,7 +744,8 @@ int bnxt_qplib_query_srq(struct bnxt_qplib_res *res,
        bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, &sbuf, sizeof(req),
                                sizeof(resp), 0);
        rc = bnxt_qplib_rcfw_send_message(rcfw, &msg);
-       srq->threshold = le16_to_cpu(sb->srq_limit);
+       if (!rc)
+               srq->threshold = le16_to_cpu(sb->srq_limit);
        dma_free_coherent(&rcfw->pdev->dev, sbuf.size,
                          sbuf.sb, sbuf.dma_addr);
 
index 68c621ff59d03fea9340eb50a56363d24c9bc105..5a91cbda4aee6f769385d6a4eab9aa191d0e44d4 100644 (file)
@@ -2086,7 +2086,7 @@ int init_credit_return(struct hfi1_devdata *dd)
                                   "Unable to allocate credit return DMA range for NUMA %d\n",
                                   i);
                        ret = -ENOMEM;
-                       goto done;
+                       goto free_cr_base;
                }
        }
        set_dev_node(&dd->pcidev->dev, dd->node);
@@ -2094,6 +2094,10 @@ int init_credit_return(struct hfi1_devdata *dd)
        ret = 0;
 done:
        return ret;
+
+free_cr_base:
+       free_credit_return(dd);
+       goto done;
 }
 
 void free_credit_return(struct hfi1_devdata *dd)
index 6e5ac2023328a7d59d42f6532113dd9a95641b31..b67d23b1f28625c5ed7a4f15f8a07a32d074199b 100644 (file)
@@ -3158,7 +3158,7 @@ int _pad_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx)
 {
        int rval = 0;
 
-       if ((unlikely(tx->num_desc + 1 == tx->desc_limit))) {
+       if ((unlikely(tx->num_desc == tx->desc_limit))) {
                rval = _extend_sdma_tx_descs(dd, tx);
                if (rval) {
                        __sdma_txclean(dd, tx);
index 8fb752f2eda2999aed4f61bffcb53e105adde9a5..2cb4b96db7212163f1e207bb87dd0b1326ad26e1 100644 (file)
@@ -346,6 +346,7 @@ enum irdma_cqp_op_type {
 #define IRDMA_AE_LLP_TOO_MANY_KEEPALIVE_RETRIES                                0x050b
 #define IRDMA_AE_LLP_DOUBT_REACHABILITY                                        0x050c
 #define IRDMA_AE_LLP_CONNECTION_ESTABLISHED                            0x050e
+#define IRDMA_AE_LLP_TOO_MANY_RNRS                                     0x050f
 #define IRDMA_AE_RESOURCE_EXHAUSTION                                   0x0520
 #define IRDMA_AE_RESET_SENT                                            0x0601
 #define IRDMA_AE_TERMINATE_SENT                                                0x0602
index bd4b2b89644442341226e6c5716f5ddb221ea1a1..ad50b77282f8a1b5352e390080d208d0086152eb 100644 (file)
@@ -387,6 +387,7 @@ static void irdma_process_aeq(struct irdma_pci_f *rf)
                case IRDMA_AE_LLP_TOO_MANY_RETRIES:
                case IRDMA_AE_LCE_QP_CATASTROPHIC:
                case IRDMA_AE_LCE_FUNCTION_CATASTROPHIC:
+               case IRDMA_AE_LLP_TOO_MANY_RNRS:
                case IRDMA_AE_LCE_CQ_CATASTROPHIC:
                case IRDMA_AE_UDA_XMIT_DGRAM_TOO_LONG:
                default:
@@ -570,6 +571,13 @@ static void irdma_destroy_irq(struct irdma_pci_f *rf,
        dev->irq_ops->irdma_dis_irq(dev, msix_vec->idx);
        irq_update_affinity_hint(msix_vec->irq, NULL);
        free_irq(msix_vec->irq, dev_id);
+       if (rf == dev_id) {
+               tasklet_kill(&rf->dpc_tasklet);
+       } else {
+               struct irdma_ceq *iwceq = (struct irdma_ceq *)dev_id;
+
+               tasklet_kill(&iwceq->dpc_tasklet);
+       }
 }
 
 /**
index b5eb8d421988c1abd73cf4eb3a93adc6f2944089..0b046c061742be140251785f60ac25cff73aa2ba 100644 (file)
@@ -839,7 +839,9 @@ static int irdma_validate_qp_attrs(struct ib_qp_init_attr *init_attr,
 
        if (init_attr->cap.max_inline_data > uk_attrs->max_hw_inline ||
            init_attr->cap.max_send_sge > uk_attrs->max_hw_wq_frags ||
-           init_attr->cap.max_recv_sge > uk_attrs->max_hw_wq_frags)
+           init_attr->cap.max_recv_sge > uk_attrs->max_hw_wq_frags ||
+           init_attr->cap.max_send_wr > uk_attrs->max_hw_wq_quanta ||
+           init_attr->cap.max_recv_wr > uk_attrs->max_hw_rq_quanta)
                return -EINVAL;
 
        if (rdma_protocol_roce(&iwdev->ibdev, 1)) {
@@ -2184,9 +2186,8 @@ static int irdma_create_cq(struct ib_cq *ibcq,
                info.cq_base_pa = iwcq->kmem.pa;
        }
 
-       if (dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
-               info.shadow_read_threshold = min(info.cq_uk_init_info.cq_size / 2,
-                                                (u32)IRDMA_MAX_CQ_READ_THRESH);
+       info.shadow_read_threshold = min(info.cq_uk_init_info.cq_size / 2,
+                                        (u32)IRDMA_MAX_CQ_READ_THRESH);
 
        if (irdma_sc_cq_init(cq, &info)) {
                ibdev_dbg(&iwdev->ibdev, "VERBS: init cq fail\n");
index f87531318feb807c7c5a216c991e10f197e9f8f4..a78a067e3ce7f3abd260c09f552562050b7b78cc 100644 (file)
@@ -458,6 +458,12 @@ void mlx5_ib_init_cong_debugfs(struct mlx5_ib_dev *dev, u32 port_num)
        dbg_cc_params->root = debugfs_create_dir("cc_params", mlx5_debugfs_get_dev_root(mdev));
 
        for (i = 0; i < MLX5_IB_DBG_CC_MAX; i++) {
+               if ((i == MLX5_IB_DBG_CC_GENERAL_RTT_RESP_DSCP_VALID ||
+                    i == MLX5_IB_DBG_CC_GENERAL_RTT_RESP_DSCP))
+                       if (!MLX5_CAP_GEN(mdev, roce) ||
+                           !MLX5_CAP_ROCE(mdev, roce_cc_general))
+                               continue;
+
                dbg_cc_params->params[i].offset = i;
                dbg_cc_params->params[i].dev = dev;
                dbg_cc_params->params[i].port_num = port_num;
index 869369cb5b5fa4745aaca7bc5eb7032e684bb132..253fea374a72de1d1143b82601da2ce9caf1cf1f 100644 (file)
@@ -2949,7 +2949,7 @@ DECLARE_UVERBS_NAMED_METHOD(
        MLX5_IB_METHOD_DEVX_OBJ_MODIFY,
        UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_OBJ_MODIFY_HANDLE,
                        UVERBS_IDR_ANY_OBJECT,
-                       UVERBS_ACCESS_WRITE,
+                       UVERBS_ACCESS_READ,
                        UA_MANDATORY),
        UVERBS_ATTR_PTR_IN(
                MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN,
index df1d1b0a3ef72bfc938c6cb61b5589e5ef7b7ff4..9947feb7fb8a0bcd1ecf9e5d136e9ea7e326e8e7 100644 (file)
@@ -78,7 +78,7 @@ static void set_eth_seg(const struct ib_send_wr *wr, struct mlx5_ib_qp *qp,
                 */
                copysz = min_t(u64, *cur_edge - (void *)eseg->inline_hdr.start,
                               left);
-               memcpy(eseg->inline_hdr.start, pdata, copysz);
+               memcpy(eseg->inline_hdr.data, pdata, copysz);
                stride = ALIGN(sizeof(struct mlx5_wqe_eth_seg) -
                               sizeof(eseg->inline_hdr.start) + copysz, 16);
                *size += stride / 16;
index 7887a6786ed43d6917a97b2dfbd8770c49383fbd..f118ce0a9a617b4226d0195048299827f2a11d37 100644 (file)
@@ -1879,8 +1879,17 @@ static int qedr_create_user_qp(struct qedr_dev *dev,
                /* RQ - read access only (0) */
                rc = qedr_init_user_queue(udata, dev, &qp->urq, ureq.rq_addr,
                                          ureq.rq_len, true, 0, alloc_and_init);
-               if (rc)
+               if (rc) {
+                       ib_umem_release(qp->usq.umem);
+                       qp->usq.umem = NULL;
+                       if (rdma_protocol_roce(&dev->ibdev, 1)) {
+                               qedr_free_pbl(dev, &qp->usq.pbl_info,
+                                             qp->usq.pbl_tbl);
+                       } else {
+                               kfree(qp->usq.pbl_tbl);
+                       }
                        return rc;
+               }
        }
 
        memset(&in_params, 0, sizeof(in_params));
index 58f70cfec45a72abd8df2ba88098a92f7fcacb4a..040234c01be4d5a0cc6fb4a4124af4752f58e181 100644 (file)
@@ -79,12 +79,16 @@ module_param(srpt_srq_size, int, 0444);
 MODULE_PARM_DESC(srpt_srq_size,
                 "Shared receive queue (SRQ) size.");
 
+static int srpt_set_u64_x(const char *buffer, const struct kernel_param *kp)
+{
+       return kstrtou64(buffer, 16, (u64 *)kp->arg);
+}
 static int srpt_get_u64_x(char *buffer, const struct kernel_param *kp)
 {
        return sprintf(buffer, "0x%016llx\n", *(u64 *)kp->arg);
 }
-module_param_call(srpt_service_guid, NULL, srpt_get_u64_x, &srpt_service_guid,
-                 0444);
+module_param_call(srpt_service_guid, srpt_set_u64_x, srpt_get_u64_x,
+                 &srpt_service_guid, 0444);
 MODULE_PARM_DESC(srpt_service_guid,
                 "Using this value for ioc_guid, id_ext, and cm_listen_id instead of using the node_guid of the first HCA.");
 
@@ -210,10 +214,12 @@ static const char *get_ch_state_name(enum rdma_ch_state s)
 /**
  * srpt_qp_event - QP event callback function
  * @event: Description of the event that occurred.
- * @ch: SRPT RDMA channel.
+ * @ptr: SRPT RDMA channel.
  */
-static void srpt_qp_event(struct ib_event *event, struct srpt_rdma_ch *ch)
+static void srpt_qp_event(struct ib_event *event, void *ptr)
 {
+       struct srpt_rdma_ch *ch = ptr;
+
        pr_debug("QP event %d on ch=%p sess_name=%s-%d state=%s\n",
                 event->event, ch, ch->sess_name, ch->qp->qp_num,
                 get_ch_state_name(ch->state));
@@ -1807,8 +1813,7 @@ retry:
        ch->cq_size = ch->rq_size + sq_size;
 
        qp_init->qp_context = (void *)ch;
-       qp_init->event_handler
-               = (void(*)(struct ib_event *, void*))srpt_qp_event;
+       qp_init->event_handler = srpt_qp_event;
        qp_init->send_cq = ch->cq;
        qp_init->recv_cq = ch->cq;
        qp_init->sq_sig_type = IB_SIGNAL_REQ_WR;
index 7c4b2a5cc1b54a1c98a92b38076df6a7b0424b49..14c828adebf7829269b7bace9b1bcbda0c7c506c 100644 (file)
@@ -130,7 +130,12 @@ static const struct xpad_device {
        { 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
        { 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 },
        { 0x03eb, 0xff02, "Wooting Two (Legacy)", 0, XTYPE_XBOX360 },
+       { 0x03f0, 0x038D, "HyperX Clutch", 0, XTYPE_XBOX360 },                  /* wired */
+       { 0x03f0, 0x048D, "HyperX Clutch", 0, XTYPE_XBOX360 },                  /* wireless */
        { 0x03f0, 0x0495, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE },
+       { 0x03f0, 0x07A0, "HyperX Clutch Gladiate RGB", 0, XTYPE_XBOXONE },
+       { 0x03f0, 0x08B6, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE },         /* v2 */
+       { 0x03f0, 0x09B4, "HyperX Clutch Tanto", 0, XTYPE_XBOXONE },
        { 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX },
        { 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX },
        { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
@@ -463,6 +468,7 @@ static const struct usb_device_id xpad_table[] = {
        { USB_INTERFACE_INFO('X', 'B', 0) },    /* Xbox USB-IF not-approved class */
        XPAD_XBOX360_VENDOR(0x0079),            /* GPD Win 2 controller */
        XPAD_XBOX360_VENDOR(0x03eb),            /* Wooting Keyboards (Legacy) */
+       XPAD_XBOX360_VENDOR(0x03f0),            /* HP HyperX Xbox 360 controllers */
        XPAD_XBOXONE_VENDOR(0x03f0),            /* HP HyperX Xbox One controllers */
        XPAD_XBOX360_VENDOR(0x044f),            /* Thrustmaster Xbox 360 controllers */
        XPAD_XBOX360_VENDOR(0x045e),            /* Microsoft Xbox 360 controllers */
index ba00ecfbd343bc796fd48f77db92659a1c36bccc..b41fd1240f4312e06935685d00aded64076c3513 100644 (file)
@@ -315,12 +315,10 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
 
                        error = devm_gpio_request_one(dev, button->gpio,
                                        flags, button->desc ? : DRV_NAME);
-                       if (error) {
-                               dev_err(dev,
-                                       "unable to claim gpio %u, err=%d\n",
-                                       button->gpio, error);
-                               return error;
-                       }
+                       if (error)
+                               return dev_err_probe(dev, error,
+                                                    "unable to claim gpio %u\n",
+                                                    button->gpio);
 
                        bdata->gpiod = gpio_to_desc(button->gpio);
                        if (!bdata->gpiod) {
index 953992b458e9f2c46900204e926da7c665468709..ca150618d32f1863795f390b4ebf4687ea0e36c1 100644 (file)
@@ -19,7 +19,6 @@
  * Copyright (C) 2006     Nicolas Boichat (nicolas@boichat.ch)
  */
 
-#include "linux/usb.h"
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
@@ -194,8 +193,6 @@ enum tp_type {
 
 /* list of device capability bits */
 #define HAS_INTEGRATED_BUTTON  1
-/* maximum number of supported endpoints (currently trackpad and button) */
-#define MAX_ENDPOINTS  2
 
 /* trackpad finger data block size */
 #define FSIZE_TYPE1            (14 * sizeof(__le16))
@@ -894,18 +891,6 @@ static int bcm5974_resume(struct usb_interface *iface)
        return error;
 }
 
-static bool bcm5974_check_endpoints(struct usb_interface *iface,
-                                   const struct bcm5974_config *cfg)
-{
-       u8 ep_addr[MAX_ENDPOINTS + 1] = {0};
-
-       ep_addr[0] = cfg->tp_ep;
-       if (cfg->tp_type == TYPE1)
-               ep_addr[1] = cfg->bt_ep;
-
-       return usb_check_int_endpoints(iface, ep_addr);
-}
-
 static int bcm5974_probe(struct usb_interface *iface,
                         const struct usb_device_id *id)
 {
@@ -918,11 +903,6 @@ static int bcm5974_probe(struct usb_interface *iface,
        /* find the product index */
        cfg = bcm5974_get_config(udev);
 
-       if (!bcm5974_check_endpoints(iface, cfg)) {
-               dev_err(&iface->dev, "Unexpected non-int endpoint\n");
-               return -ENODEV;
-       }
-
        /* allocate memory for our device state and initialize it */
        dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL);
        input_dev = input_allocate_device();
index 258d5fe3d395c4670088aa0d736cac69c7d24550..42eaebb3bf5cc82efabccff777a8ee23b016bf49 100644 (file)
@@ -978,12 +978,12 @@ static int rmi_driver_remove(struct device *dev)
 
        rmi_disable_irq(rmi_dev, false);
 
-       irq_domain_remove(data->irqdomain);
-       data->irqdomain = NULL;
-
        rmi_f34_remove_sysfs(rmi_dev);
        rmi_free_function_list(rmi_dev);
 
+       irq_domain_remove(data->irqdomain);
+       data->irqdomain = NULL;
+
        return 0;
 }
 
index 20331e119beb694945b196df9fb2c7efff60feda..03d626776ba17a3ff18c91c1e685a0230e8fcbbb 100644 (file)
@@ -1372,6 +1372,7 @@ static struct qcom_icc_bcm bcm_mm0 = {
 
 static struct qcom_icc_bcm bcm_co0 = {
        .name = "CO0",
+       .keepalive = true,
        .num_nodes = 1,
        .nodes = { &slv_qns_cdsp_mem_noc }
 };
index 629faa4c9aaee280e7514695dcd2c96e9125d1dd..fc22cecf650fc4eedaf3970a6a8f025f7e9d849e 100644 (file)
@@ -2223,6 +2223,7 @@ static struct platform_driver qnoc_driver = {
        .driver = {
                .name = "qnoc-sm8550",
                .of_match_table = qnoc_of_match,
+               .sync_state = icc_sync_state,
        },
 };
 
index b83de54577b6874553624390e0e0145fd966a38a..b962e6c233ef78ed3ed44cf0b0777bb62fbd50a6 100644 (file)
@@ -1160,7 +1160,7 @@ static struct qcom_icc_node qns_gemnoc_sf = {
 
 static struct qcom_icc_bcm bcm_acv = {
        .name = "ACV",
-       .enable_mask = BIT(3),
+       .enable_mask = BIT(0),
        .num_nodes = 1,
        .nodes = { &ebi },
 };
index d19501d913b39c696a337ff4f5d3a54aa07915c4..cbaf4f9c41be656212b50dce683273911e1e1cd6 100644 (file)
@@ -1586,6 +1586,7 @@ static struct qcom_icc_node qns_pcie_south_gem_noc_pcie = {
 
 static struct qcom_icc_bcm bcm_acv = {
        .name = "ACV",
+       .enable_mask = BIT(3),
        .num_nodes = 1,
        .nodes = { &ebi },
 };
index 9a29d742617e3d34e3c9a28d25857230b06d2a68..0d6095290b6ad0262e6d6bdff71abf344b7eec22 100644 (file)
@@ -179,7 +179,7 @@ config FSL_PAMU
 config MSM_IOMMU
        bool "MSM IOMMU Support"
        depends on ARM
-       depends on ARCH_MSM8X60 || ARCH_MSM8960 || COMPILE_TEST
+       depends on ARCH_QCOM || COMPILE_TEST
        select IOMMU_API
        select IOMMU_IO_PGTABLE_ARMV7S
        help
index 8b3601f285fd699dd4d9d4d32e1ac62c2c5e3058..c970eae2313d7052db5862c7928ce0b0fae8dbb7 100644 (file)
@@ -164,5 +164,4 @@ void amd_iommu_domain_set_pgtable(struct protection_domain *domain,
                                  u64 *root, int mode);
 struct dev_table_entry *get_dev_table(struct amd_iommu *iommu);
 
-extern bool amd_iommu_snp_en;
 #endif
index c83bd0c2a1c9214df007c7ac29e31641adf23702..480e7681f4f3869f9e03540d195f3dfd82f16f85 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/io_apic.h>
 #include <asm/irq_remapping.h>
 #include <asm/set_memory.h>
+#include <asm/sev.h>
 
 #include <linux/crash_dump.h>
 
@@ -3221,6 +3222,36 @@ out:
        return true;
 }
 
+static void iommu_snp_enable(void)
+{
+#ifdef CONFIG_KVM_AMD_SEV
+       if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP))
+               return;
+       /*
+        * The SNP support requires that IOMMU must be enabled, and is
+        * not configured in the passthrough mode.
+        */
+       if (no_iommu || iommu_default_passthrough()) {
+               pr_err("SNP: IOMMU disabled or configured in passthrough mode, SNP cannot be supported.\n");
+               return;
+       }
+
+       amd_iommu_snp_en = check_feature(FEATURE_SNP);
+       if (!amd_iommu_snp_en) {
+               pr_err("SNP: IOMMU SNP feature not enabled, SNP cannot be supported.\n");
+               return;
+       }
+
+       pr_info("IOMMU SNP support enabled.\n");
+
+       /* Enforce IOMMU v1 pagetable when SNP is enabled. */
+       if (amd_iommu_pgtable != AMD_IOMMU_V1) {
+               pr_warn("Forcing use of AMD IOMMU v1 page table due to SNP.\n");
+               amd_iommu_pgtable = AMD_IOMMU_V1;
+       }
+#endif
+}
+
 /****************************************************************************
  *
  * AMD IOMMU Initialization State Machine
@@ -3256,6 +3287,7 @@ static int __init state_next(void)
                break;
        case IOMMU_ENABLED:
                register_syscore_ops(&amd_iommu_syscore_ops);
+               iommu_snp_enable();
                ret = amd_iommu_init_pci();
                init_state = ret ? IOMMU_INIT_ERROR : IOMMU_PCI_INIT;
                break;
@@ -3767,40 +3799,85 @@ int amd_iommu_pc_set_reg(struct amd_iommu *iommu, u8 bank, u8 cntr, u8 fxn, u64
        return iommu_pc_get_set_reg(iommu, bank, cntr, fxn, value, true);
 }
 
-#ifdef CONFIG_AMD_MEM_ENCRYPT
-int amd_iommu_snp_enable(void)
+#ifdef CONFIG_KVM_AMD_SEV
+static int iommu_page_make_shared(void *page)
 {
-       /*
-        * The SNP support requires that IOMMU must be enabled, and is
-        * not configured in the passthrough mode.
-        */
-       if (no_iommu || iommu_default_passthrough()) {
-               pr_err("SNP: IOMMU is disabled or configured in passthrough mode, SNP cannot be supported");
-               return -EINVAL;
+       unsigned long paddr, pfn;
+
+       paddr = iommu_virt_to_phys(page);
+       /* Cbit maybe set in the paddr */
+       pfn = __sme_clr(paddr) >> PAGE_SHIFT;
+
+       if (!(pfn % PTRS_PER_PMD)) {
+               int ret, level;
+               bool assigned;
+
+               ret = snp_lookup_rmpentry(pfn, &assigned, &level);
+               if (ret) {
+                       pr_warn("IOMMU PFN %lx RMP lookup failed, ret %d\n", pfn, ret);
+                       return ret;
+               }
+
+               if (!assigned) {
+                       pr_warn("IOMMU PFN %lx not assigned in RMP table\n", pfn);
+                       return -EINVAL;
+               }
+
+               if (level > PG_LEVEL_4K) {
+                       ret = psmash(pfn);
+                       if (!ret)
+                               goto done;
+
+                       pr_warn("PSMASH failed for IOMMU PFN %lx huge RMP entry, ret: %d, level: %d\n",
+                               pfn, ret, level);
+                       return ret;
+               }
        }
 
-       /*
-        * Prevent enabling SNP after IOMMU_ENABLED state because this process
-        * affect how IOMMU driver sets up data structures and configures
-        * IOMMU hardware.
-        */
-       if (init_state > IOMMU_ENABLED) {
-               pr_err("SNP: Too late to enable SNP for IOMMU.\n");
-               return -EINVAL;
+done:
+       return rmp_make_shared(pfn, PG_LEVEL_4K);
+}
+
+static int iommu_make_shared(void *va, size_t size)
+{
+       void *page;
+       int ret;
+
+       if (!va)
+               return 0;
+
+       for (page = va; page < (va + size); page += PAGE_SIZE) {
+               ret = iommu_page_make_shared(page);
+               if (ret)
+                       return ret;
        }
 
-       amd_iommu_snp_en = check_feature(FEATURE_SNP);
+       return 0;
+}
+
+int amd_iommu_snp_disable(void)
+{
+       struct amd_iommu *iommu;
+       int ret;
+
        if (!amd_iommu_snp_en)
-               return -EINVAL;
+               return 0;
+
+       for_each_iommu(iommu) {
+               ret = iommu_make_shared(iommu->evt_buf, EVT_BUFFER_SIZE);
+               if (ret)
+                       return ret;
 
-       pr_info("SNP enabled\n");
+               ret = iommu_make_shared(iommu->ppr_log, PPR_LOG_SIZE);
+               if (ret)
+                       return ret;
 
-       /* Enforce IOMMU v1 pagetable when SNP is enabled. */
-       if (amd_iommu_pgtable != AMD_IOMMU_V1) {
-               pr_warn("Force to using AMD IOMMU v1 page table due to SNP\n");
-               amd_iommu_pgtable = AMD_IOMMU_V1;
+               ret = iommu_make_shared((void *)iommu->cmd_sem, PAGE_SIZE);
+               if (ret)
+                       return ret;
        }
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(amd_iommu_snp_disable);
 #endif
index 05722121f00e70689680ce7a45cc5e953f50210b..4a27fbdb2d8446cb6af2b0e287580615c7da47c1 100644 (file)
@@ -292,10 +292,8 @@ arm_smmu_mmu_notifier_get(struct arm_smmu_domain *smmu_domain,
                          struct mm_struct *mm)
 {
        int ret;
-       unsigned long flags;
        struct arm_smmu_ctx_desc *cd;
        struct arm_smmu_mmu_notifier *smmu_mn;
-       struct arm_smmu_master *master;
 
        list_for_each_entry(smmu_mn, &smmu_domain->mmu_notifiers, list) {
                if (smmu_mn->mn.mm == mm) {
@@ -325,28 +323,9 @@ arm_smmu_mmu_notifier_get(struct arm_smmu_domain *smmu_domain,
                goto err_free_cd;
        }
 
-       spin_lock_irqsave(&smmu_domain->devices_lock, flags);
-       list_for_each_entry(master, &smmu_domain->devices, domain_head) {
-               ret = arm_smmu_write_ctx_desc(master, mm_get_enqcmd_pasid(mm),
-                                             cd);
-               if (ret) {
-                       list_for_each_entry_from_reverse(
-                               master, &smmu_domain->devices, domain_head)
-                               arm_smmu_write_ctx_desc(
-                                       master, mm_get_enqcmd_pasid(mm), NULL);
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
-       if (ret)
-               goto err_put_notifier;
-
        list_add(&smmu_mn->list, &smmu_domain->mmu_notifiers);
        return smmu_mn;
 
-err_put_notifier:
-       /* Frees smmu_mn */
-       mmu_notifier_put(&smmu_mn->mn);
 err_free_cd:
        arm_smmu_free_shared_cd(cd);
        return ERR_PTR(ret);
@@ -363,9 +342,6 @@ static void arm_smmu_mmu_notifier_put(struct arm_smmu_mmu_notifier *smmu_mn)
 
        list_del(&smmu_mn->list);
 
-       arm_smmu_update_ctx_desc_devices(smmu_domain, mm_get_enqcmd_pasid(mm),
-                                        NULL);
-
        /*
         * If we went through clear(), we've already invalidated, and no
         * new TLB entry can have been formed.
@@ -381,7 +357,8 @@ static void arm_smmu_mmu_notifier_put(struct arm_smmu_mmu_notifier *smmu_mn)
        arm_smmu_free_shared_cd(cd);
 }
 
-static int __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm)
+static int __arm_smmu_sva_bind(struct device *dev, ioasid_t pasid,
+                              struct mm_struct *mm)
 {
        int ret;
        struct arm_smmu_bond *bond;
@@ -404,9 +381,15 @@ static int __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm)
                goto err_free_bond;
        }
 
+       ret = arm_smmu_write_ctx_desc(master, pasid, bond->smmu_mn->cd);
+       if (ret)
+               goto err_put_notifier;
+
        list_add(&bond->list, &master->bonds);
        return 0;
 
+err_put_notifier:
+       arm_smmu_mmu_notifier_put(bond->smmu_mn);
 err_free_bond:
        kfree(bond);
        return ret;
@@ -568,6 +551,9 @@ void arm_smmu_sva_remove_dev_pasid(struct iommu_domain *domain,
        struct arm_smmu_master *master = dev_iommu_priv_get(dev);
 
        mutex_lock(&sva_lock);
+
+       arm_smmu_write_ctx_desc(master, id, NULL);
+
        list_for_each_entry(t, &master->bonds, list) {
                if (t->mm == mm) {
                        bond = t;
@@ -590,7 +576,7 @@ static int arm_smmu_sva_set_dev_pasid(struct iommu_domain *domain,
        struct mm_struct *mm = domain->mm;
 
        mutex_lock(&sva_lock);
-       ret = __arm_smmu_sva_bind(dev, mm);
+       ret = __arm_smmu_sva_bind(dev, id, mm);
        mutex_unlock(&sva_lock);
 
        return ret;
index 0ffb1cf17e0b2e6687b1c5ff12ff87405e2552b6..a74a509bcd630a212e65b82fb27dea9cb5517fa6 100644 (file)
@@ -3125,7 +3125,8 @@ static int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr)
 static void arm_smmu_free_msis(void *data)
 {
        struct device *dev = data;
-       platform_msi_domain_free_irqs(dev);
+
+       platform_device_msi_free_irqs_all(dev);
 }
 
 static void arm_smmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
@@ -3166,7 +3167,7 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
        }
 
        /* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */
-       ret = platform_msi_domain_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg);
+       ret = platform_device_msi_init_and_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg);
        if (ret) {
                dev_warn(dev, "failed to allocate MSIs - falling back to wired irqs\n");
                return;
index 68b6bc5e7c71016b8d58a6a077e921b27fb51447..6317aaf7b3ab1c7bed6f5f33b9a4bdca14cc171e 100644 (file)
@@ -859,10 +859,14 @@ static void arm_smmu_destroy_domain_context(struct arm_smmu_domain *smmu_domain)
        arm_smmu_rpm_put(smmu);
 }
 
-static struct iommu_domain *arm_smmu_domain_alloc_paging(struct device *dev)
+static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
 {
        struct arm_smmu_domain *smmu_domain;
 
+       if (type != IOMMU_DOMAIN_UNMANAGED) {
+               if (using_legacy_binding || type != IOMMU_DOMAIN_DMA)
+                       return NULL;
+       }
        /*
         * Allocate the domain and initialise some of its data structures.
         * We can't really do anything meaningful until we've added a
@@ -875,15 +879,6 @@ static struct iommu_domain *arm_smmu_domain_alloc_paging(struct device *dev)
        mutex_init(&smmu_domain->init_mutex);
        spin_lock_init(&smmu_domain->cb_lock);
 
-       if (dev) {
-               struct arm_smmu_master_cfg *cfg = dev_iommu_priv_get(dev);
-
-               if (arm_smmu_init_domain_context(smmu_domain, cfg->smmu, dev)) {
-                       kfree(smmu_domain);
-                       return NULL;
-               }
-       }
-
        return &smmu_domain->domain;
 }
 
@@ -1600,7 +1595,7 @@ static struct iommu_ops arm_smmu_ops = {
        .identity_domain        = &arm_smmu_identity_domain,
        .blocked_domain         = &arm_smmu_blocked_domain,
        .capable                = arm_smmu_capable,
-       .domain_alloc_paging    = arm_smmu_domain_alloc_paging,
+       .domain_alloc           = arm_smmu_domain_alloc,
        .probe_device           = arm_smmu_probe_device,
        .release_device         = arm_smmu_release_device,
        .probe_finalize         = arm_smmu_probe_finalize,
index 6fb5f6fceea11fb7865d92d8451a5de98a655556..11652e0bcab3a6e3113c70fb80971853df012f57 100644 (file)
@@ -396,8 +396,6 @@ static int domain_update_device_node(struct dmar_domain *domain)
        return nid;
 }
 
-static void domain_update_iotlb(struct dmar_domain *domain);
-
 /* Return the super pagesize bitmap if supported. */
 static unsigned long domain_super_pgsize_bitmap(struct dmar_domain *domain)
 {
@@ -1218,7 +1216,7 @@ domain_lookup_dev_info(struct dmar_domain *domain,
        return NULL;
 }
 
-static void domain_update_iotlb(struct dmar_domain *domain)
+void domain_update_iotlb(struct dmar_domain *domain)
 {
        struct dev_pasid_info *dev_pasid;
        struct device_domain_info *info;
@@ -1368,6 +1366,46 @@ static void domain_flush_pasid_iotlb(struct intel_iommu *iommu,
        spin_unlock_irqrestore(&domain->lock, flags);
 }
 
+static void __iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
+                                   unsigned long pfn, unsigned int pages,
+                                   int ih)
+{
+       unsigned int aligned_pages = __roundup_pow_of_two(pages);
+       unsigned long bitmask = aligned_pages - 1;
+       unsigned int mask = ilog2(aligned_pages);
+       u64 addr = (u64)pfn << VTD_PAGE_SHIFT;
+
+       /*
+        * PSI masks the low order bits of the base address. If the
+        * address isn't aligned to the mask, then compute a mask value
+        * needed to ensure the target range is flushed.
+        */
+       if (unlikely(bitmask & pfn)) {
+               unsigned long end_pfn = pfn + pages - 1, shared_bits;
+
+               /*
+                * Since end_pfn <= pfn + bitmask, the only way bits
+                * higher than bitmask can differ in pfn and end_pfn is
+                * by carrying. This means after masking out bitmask,
+                * high bits starting with the first set bit in
+                * shared_bits are all equal in both pfn and end_pfn.
+                */
+               shared_bits = ~(pfn ^ end_pfn) & ~bitmask;
+               mask = shared_bits ? __ffs(shared_bits) : BITS_PER_LONG;
+       }
+
+       /*
+        * Fallback to domain selective flush if no PSI support or
+        * the size is too big.
+        */
+       if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap))
+               iommu->flush.flush_iotlb(iommu, did, 0, 0,
+                                        DMA_TLB_DSI_FLUSH);
+       else
+               iommu->flush.flush_iotlb(iommu, did, addr | ih, mask,
+                                        DMA_TLB_PSI_FLUSH);
+}
+
 static void iommu_flush_iotlb_psi(struct intel_iommu *iommu,
                                  struct dmar_domain *domain,
                                  unsigned long pfn, unsigned int pages,
@@ -1384,42 +1422,10 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu,
        if (ih)
                ih = 1 << 6;
 
-       if (domain->use_first_level) {
+       if (domain->use_first_level)
                domain_flush_pasid_iotlb(iommu, domain, addr, pages, ih);
-       } else {
-               unsigned long bitmask = aligned_pages - 1;
-
-               /*
-                * PSI masks the low order bits of the base address. If the
-                * address isn't aligned to the mask, then compute a mask value
-                * needed to ensure the target range is flushed.
-                */
-               if (unlikely(bitmask & pfn)) {
-                       unsigned long end_pfn = pfn + pages - 1, shared_bits;
-
-                       /*
-                        * Since end_pfn <= pfn + bitmask, the only way bits
-                        * higher than bitmask can differ in pfn and end_pfn is
-                        * by carrying. This means after masking out bitmask,
-                        * high bits starting with the first set bit in
-                        * shared_bits are all equal in both pfn and end_pfn.
-                        */
-                       shared_bits = ~(pfn ^ end_pfn) & ~bitmask;
-                       mask = shared_bits ? __ffs(shared_bits) : BITS_PER_LONG;
-               }
-
-               /*
-                * Fallback to domain selective flush if no PSI support or
-                * the size is too big.
-                */
-               if (!cap_pgsel_inv(iommu->cap) ||
-                   mask > cap_max_amask_val(iommu->cap))
-                       iommu->flush.flush_iotlb(iommu, did, 0, 0,
-                                                       DMA_TLB_DSI_FLUSH);
-               else
-                       iommu->flush.flush_iotlb(iommu, did, addr | ih, mask,
-                                                       DMA_TLB_PSI_FLUSH);
-       }
+       else
+               __iommu_flush_iotlb_psi(iommu, did, pfn, pages, ih);
 
        /*
         * In caching mode, changes of pages from non-present to present require
@@ -1443,6 +1449,46 @@ static void __mapping_notify_one(struct intel_iommu *iommu, struct dmar_domain *
                iommu_flush_write_buffer(iommu);
 }
 
+/*
+ * Flush the relevant caches in nested translation if the domain
+ * also serves as a parent
+ */
+static void parent_domain_flush(struct dmar_domain *domain,
+                               unsigned long pfn,
+                               unsigned long pages, int ih)
+{
+       struct dmar_domain *s1_domain;
+
+       spin_lock(&domain->s1_lock);
+       list_for_each_entry(s1_domain, &domain->s1_domains, s2_link) {
+               struct device_domain_info *device_info;
+               struct iommu_domain_info *info;
+               unsigned long flags;
+               unsigned long i;
+
+               xa_for_each(&s1_domain->iommu_array, i, info)
+                       __iommu_flush_iotlb_psi(info->iommu, info->did,
+                                               pfn, pages, ih);
+
+               if (!s1_domain->has_iotlb_device)
+                       continue;
+
+               spin_lock_irqsave(&s1_domain->lock, flags);
+               list_for_each_entry(device_info, &s1_domain->devices, link)
+                       /*
+                        * Address translation cache in device side caches the
+                        * result of nested translation. There is no easy way
+                        * to identify the exact set of nested translations
+                        * affected by a change in S2. So just flush the entire
+                        * device cache.
+                        */
+                       __iommu_flush_dev_iotlb(device_info, 0,
+                                               MAX_AGAW_PFN_WIDTH);
+               spin_unlock_irqrestore(&s1_domain->lock, flags);
+       }
+       spin_unlock(&domain->s1_lock);
+}
+
 static void intel_flush_iotlb_all(struct iommu_domain *domain)
 {
        struct dmar_domain *dmar_domain = to_dmar_domain(domain);
@@ -1462,6 +1508,9 @@ static void intel_flush_iotlb_all(struct iommu_domain *domain)
                if (!cap_caching_mode(iommu->cap))
                        iommu_flush_dev_iotlb(dmar_domain, 0, MAX_AGAW_PFN_WIDTH);
        }
+
+       if (dmar_domain->nested_parent)
+               parent_domain_flush(dmar_domain, 0, -1, 0);
 }
 
 static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
@@ -1985,6 +2034,9 @@ static void switch_to_super_page(struct dmar_domain *domain,
                                iommu_flush_iotlb_psi(info->iommu, domain,
                                                      start_pfn, lvl_pages,
                                                      0, 0);
+                       if (domain->nested_parent)
+                               parent_domain_flush(domain, start_pfn,
+                                                   lvl_pages, 0);
                }
 
                pte++;
@@ -3883,6 +3935,7 @@ intel_iommu_domain_alloc_user(struct device *dev, u32 flags,
        bool dirty_tracking = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
        bool nested_parent = flags & IOMMU_HWPT_ALLOC_NEST_PARENT;
        struct intel_iommu *iommu = info->iommu;
+       struct dmar_domain *dmar_domain;
        struct iommu_domain *domain;
 
        /* Must be NESTING domain */
@@ -3908,11 +3961,16 @@ intel_iommu_domain_alloc_user(struct device *dev, u32 flags,
        if (!domain)
                return ERR_PTR(-ENOMEM);
 
-       if (nested_parent)
-               to_dmar_domain(domain)->nested_parent = true;
+       dmar_domain = to_dmar_domain(domain);
+
+       if (nested_parent) {
+               dmar_domain->nested_parent = true;
+               INIT_LIST_HEAD(&dmar_domain->s1_domains);
+               spin_lock_init(&dmar_domain->s1_lock);
+       }
 
        if (dirty_tracking) {
-               if (to_dmar_domain(domain)->use_first_level) {
+               if (dmar_domain->use_first_level) {
                        iommu_domain_free(domain);
                        return ERR_PTR(-EOPNOTSUPP);
                }
@@ -3924,8 +3982,12 @@ intel_iommu_domain_alloc_user(struct device *dev, u32 flags,
 
 static void intel_iommu_domain_free(struct iommu_domain *domain)
 {
+       struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+
+       WARN_ON(dmar_domain->nested_parent &&
+               !list_empty(&dmar_domain->s1_domains));
        if (domain != &si_domain->domain)
-               domain_exit(to_dmar_domain(domain));
+               domain_exit(dmar_domain);
 }
 
 int prepare_domain_attach_device(struct iommu_domain *domain,
@@ -4107,6 +4169,9 @@ static void intel_iommu_tlb_sync(struct iommu_domain *domain,
                                      start_pfn, nrpages,
                                      list_empty(&gather->freelist), 0);
 
+       if (dmar_domain->nested_parent)
+               parent_domain_flush(dmar_domain, start_pfn, nrpages,
+                                   list_empty(&gather->freelist));
        put_pages_list(&gather->freelist);
 }
 
@@ -4664,21 +4729,70 @@ static void *intel_iommu_hw_info(struct device *dev, u32 *length, u32 *type)
        return vtd;
 }
 
+/*
+ * Set dirty tracking for the device list of a domain. The caller must
+ * hold the domain->lock when calling it.
+ */
+static int device_set_dirty_tracking(struct list_head *devices, bool enable)
+{
+       struct device_domain_info *info;
+       int ret = 0;
+
+       list_for_each_entry(info, devices, link) {
+               ret = intel_pasid_setup_dirty_tracking(info->iommu, info->dev,
+                                                      IOMMU_NO_PASID, enable);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static int parent_domain_set_dirty_tracking(struct dmar_domain *domain,
+                                           bool enable)
+{
+       struct dmar_domain *s1_domain;
+       unsigned long flags;
+       int ret;
+
+       spin_lock(&domain->s1_lock);
+       list_for_each_entry(s1_domain, &domain->s1_domains, s2_link) {
+               spin_lock_irqsave(&s1_domain->lock, flags);
+               ret = device_set_dirty_tracking(&s1_domain->devices, enable);
+               spin_unlock_irqrestore(&s1_domain->lock, flags);
+               if (ret)
+                       goto err_unwind;
+       }
+       spin_unlock(&domain->s1_lock);
+       return 0;
+
+err_unwind:
+       list_for_each_entry(s1_domain, &domain->s1_domains, s2_link) {
+               spin_lock_irqsave(&s1_domain->lock, flags);
+               device_set_dirty_tracking(&s1_domain->devices,
+                                         domain->dirty_tracking);
+               spin_unlock_irqrestore(&s1_domain->lock, flags);
+       }
+       spin_unlock(&domain->s1_lock);
+       return ret;
+}
+
 static int intel_iommu_set_dirty_tracking(struct iommu_domain *domain,
                                          bool enable)
 {
        struct dmar_domain *dmar_domain = to_dmar_domain(domain);
-       struct device_domain_info *info;
        int ret;
 
        spin_lock(&dmar_domain->lock);
        if (dmar_domain->dirty_tracking == enable)
                goto out_unlock;
 
-       list_for_each_entry(info, &dmar_domain->devices, link) {
-               ret = intel_pasid_setup_dirty_tracking(info->iommu,
-                                                      info->domain, info->dev,
-                                                      IOMMU_NO_PASID, enable);
+       ret = device_set_dirty_tracking(&dmar_domain->devices, enable);
+       if (ret)
+               goto err_unwind;
+
+       if (dmar_domain->nested_parent) {
+               ret = parent_domain_set_dirty_tracking(dmar_domain, enable);
                if (ret)
                        goto err_unwind;
        }
@@ -4690,10 +4804,8 @@ out_unlock:
        return 0;
 
 err_unwind:
-       list_for_each_entry(info, &dmar_domain->devices, link)
-               intel_pasid_setup_dirty_tracking(info->iommu, dmar_domain,
-                                                info->dev, IOMMU_NO_PASID,
-                                                dmar_domain->dirty_tracking);
+       device_set_dirty_tracking(&dmar_domain->devices,
+                                 dmar_domain->dirty_tracking);
        spin_unlock(&dmar_domain->lock);
        return ret;
 }
index d02f916d8e59a914d2441fa2b81af9ac31dfbf86..4145c04cb1c6818fea0ce420d31c41acec8836a3 100644 (file)
@@ -627,6 +627,10 @@ struct dmar_domain {
                        int             agaw;
                        /* maximum mapped address */
                        u64             max_addr;
+                       /* Protect the s1_domains list */
+                       spinlock_t      s1_lock;
+                       /* Track s1_domains nested on this domain */
+                       struct list_head s1_domains;
                };
 
                /* Nested user domain */
@@ -637,6 +641,8 @@ struct dmar_domain {
                        unsigned long s1_pgtbl;
                        /* page table attributes */
                        struct iommu_hwpt_vtd_s1 s1_cfg;
+                       /* link to parent domain siblings */
+                       struct list_head s2_link;
                };
        };
 
@@ -1060,6 +1066,7 @@ int qi_submit_sync(struct intel_iommu *iommu, struct qi_desc *desc,
  */
 #define QI_OPT_WAIT_DRAIN              BIT(0)
 
+void domain_update_iotlb(struct dmar_domain *domain);
 int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu);
 void domain_detach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu);
 void device_block_translation(struct device *dev);
index f26c7f1c46ccaf43b0a4db5209b5c85b484277ed..a7d68f3d518acd9fc5af6f03ebbf71c825a4afcc 100644 (file)
@@ -65,12 +65,20 @@ static int intel_nested_attach_dev(struct iommu_domain *domain,
        list_add(&info->link, &dmar_domain->devices);
        spin_unlock_irqrestore(&dmar_domain->lock, flags);
 
+       domain_update_iotlb(dmar_domain);
+
        return 0;
 }
 
 static void intel_nested_domain_free(struct iommu_domain *domain)
 {
-       kfree(to_dmar_domain(domain));
+       struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+       struct dmar_domain *s2_domain = dmar_domain->s2_domain;
+
+       spin_lock(&s2_domain->s1_lock);
+       list_del(&dmar_domain->s2_link);
+       spin_unlock(&s2_domain->s1_lock);
+       kfree(dmar_domain);
 }
 
 static void nested_flush_dev_iotlb(struct dmar_domain *domain, u64 addr,
@@ -95,7 +103,7 @@ static void nested_flush_dev_iotlb(struct dmar_domain *domain, u64 addr,
 }
 
 static void intel_nested_flush_cache(struct dmar_domain *domain, u64 addr,
-                                    unsigned long npages, bool ih)
+                                    u64 npages, bool ih)
 {
        struct iommu_domain_info *info;
        unsigned int mask;
@@ -201,5 +209,9 @@ struct iommu_domain *intel_nested_domain_alloc(struct iommu_domain *parent,
        spin_lock_init(&domain->lock);
        xa_init(&domain->iommu_array);
 
+       spin_lock(&s2_domain->s1_lock);
+       list_add(&domain->s2_link, &s2_domain->s1_domains);
+       spin_unlock(&s2_domain->s1_lock);
+
        return &domain->domain;
 }
index 3239cefa4c337897dda048ebec7aeb1fc075a955..108158e2b907d0744467d88e8ec35b419185555b 100644 (file)
@@ -428,7 +428,6 @@ int intel_pasid_setup_second_level(struct intel_iommu *iommu,
  * Set up dirty tracking on a second only or nested translation type.
  */
 int intel_pasid_setup_dirty_tracking(struct intel_iommu *iommu,
-                                    struct dmar_domain *domain,
                                     struct device *dev, u32 pasid,
                                     bool enabled)
 {
@@ -445,7 +444,7 @@ int intel_pasid_setup_dirty_tracking(struct intel_iommu *iommu,
                return -ENODEV;
        }
 
-       did = domain_id_iommu(domain, iommu);
+       did = pasid_get_domain_id(pte);
        pgtt = pasid_pte_get_pgtt(pte);
        if (pgtt != PASID_ENTRY_PGTT_SL_ONLY &&
            pgtt != PASID_ENTRY_PGTT_NESTED) {
@@ -658,6 +657,8 @@ int intel_pasid_setup_nested(struct intel_iommu *iommu, struct device *dev,
        pasid_set_domain_id(pte, did);
        pasid_set_address_width(pte, s2_domain->agaw);
        pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap));
+       if (s2_domain->dirty_tracking)
+               pasid_set_ssade(pte);
        pasid_set_translation_type(pte, PASID_ENTRY_PGTT_NESTED);
        pasid_set_present(pte);
        spin_unlock(&iommu->lock);
index 8d40d4c66e3198a7ce90c83168a3f86491d79f71..487ede039bdde5733ec1f6af0905ade24c806200 100644 (file)
@@ -307,7 +307,6 @@ int intel_pasid_setup_second_level(struct intel_iommu *iommu,
                                   struct dmar_domain *domain,
                                   struct device *dev, u32 pasid);
 int intel_pasid_setup_dirty_tracking(struct intel_iommu *iommu,
-                                    struct dmar_domain *domain,
                                     struct device *dev, u32 pasid,
                                     bool enabled);
 int intel_pasid_setup_pass_through(struct intel_iommu *iommu,
index c3fc9201d0be97e59395750cda0fc29940c0b844..65814cbc84020021df67d0b7dab9db2c61351b56 100644 (file)
@@ -41,6 +41,7 @@ static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm, struct de
        }
        iommu_mm->pasid = pasid;
        INIT_LIST_HEAD(&iommu_mm->sva_domains);
+       INIT_LIST_HEAD(&iommu_mm->sva_handles);
        /*
         * Make sure the write to mm->iommu_mm is not reordered in front of
         * initialization to iommu_mm fields. If it does, readers may see a
@@ -82,6 +83,14 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
                goto out_unlock;
        }
 
+       list_for_each_entry(handle, &mm->iommu_mm->sva_handles, handle_item) {
+               if (handle->dev == dev) {
+                       refcount_inc(&handle->users);
+                       mutex_unlock(&iommu_sva_lock);
+                       return handle;
+               }
+       }
+
        handle = kzalloc(sizeof(*handle), GFP_KERNEL);
        if (!handle) {
                ret = -ENOMEM;
@@ -111,6 +120,8 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
        list_add(&domain->next, &mm->iommu_mm->sva_domains);
 
 out:
+       refcount_set(&handle->users, 1);
+       list_add(&handle->handle_item, &mm->iommu_mm->sva_handles);
        mutex_unlock(&iommu_sva_lock);
        handle->dev = dev;
        handle->domain = domain;
@@ -141,6 +152,12 @@ void iommu_sva_unbind_device(struct iommu_sva *handle)
        struct device *dev = handle->dev;
 
        mutex_lock(&iommu_sva_lock);
+       if (!refcount_dec_and_test(&handle->users)) {
+               mutex_unlock(&iommu_sva_lock);
+               return;
+       }
+       list_del(&handle->handle_item);
+
        iommu_detach_device_pasid(domain, dev, iommu_mm->pasid);
        if (--domain->users == 0) {
                list_del(&domain->next);
index 3f3f1fa1a0a946a43eb48ee324ab4979683bb566..33d142f8057d70a77f44e842afdd84b1bee0a970 100644 (file)
@@ -263,7 +263,8 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd)
 
        if (cmd->__reserved)
                return -EOPNOTSUPP;
-       if (cmd->data_type == IOMMU_HWPT_DATA_NONE && cmd->data_len)
+       if ((cmd->data_type == IOMMU_HWPT_DATA_NONE && cmd->data_len) ||
+           (cmd->data_type != IOMMU_HWPT_DATA_NONE && !cmd->data_len))
                return -EINVAL;
 
        idev = iommufd_get_device(ucmd, cmd->dev_id);
index 504ac1b01b2d2ab45fbc22fde2bdcf324ce2d973..05fd9d3abf1b809614cced9e9387679797866103 100644 (file)
@@ -1330,20 +1330,23 @@ out_unlock:
 
 int iopt_add_access(struct io_pagetable *iopt, struct iommufd_access *access)
 {
+       u32 new_id;
        int rc;
 
        down_write(&iopt->domains_rwsem);
        down_write(&iopt->iova_rwsem);
-       rc = xa_alloc(&iopt->access_list, &access->iopt_access_list_id, access,
-                     xa_limit_16b, GFP_KERNEL_ACCOUNT);
+       rc = xa_alloc(&iopt->access_list, &new_id, access, xa_limit_16b,
+                     GFP_KERNEL_ACCOUNT);
+
        if (rc)
                goto out_unlock;
 
        rc = iopt_calculate_iova_alignment(iopt);
        if (rc) {
-               xa_erase(&iopt->access_list, access->iopt_access_list_id);
+               xa_erase(&iopt->access_list, new_id);
                goto out_unlock;
        }
+       access->iopt_access_list_id = new_id;
 
 out_unlock:
        up_write(&iopt->iova_rwsem);
index 482d4059f5db6aed38ee8aa60f25b791f1e7556d..e854d3f672051b5223e0fec8af741abf03bbffbd 100644 (file)
@@ -45,6 +45,7 @@ enum {
 
 enum {
        MOCK_FLAGS_DEVICE_NO_DIRTY = 1 << 0,
+       MOCK_FLAGS_DEVICE_HUGE_IOVA = 1 << 1,
 };
 
 enum {
index 0a92c9eeaf7f50a6fe05c266b9ec39d1021844a9..db8c46bee1559ac46fb148d2474668b5a994ae15 100644 (file)
@@ -100,7 +100,7 @@ struct iova_bitmap {
        struct iova_bitmap_map mapped;
 
        /* userspace address of the bitmap */
-       u64 __user *bitmap;
+       u8 __user *bitmap;
 
        /* u64 index that @mapped points to */
        unsigned long mapped_base_index;
@@ -113,6 +113,9 @@ struct iova_bitmap {
 
        /* length of the IOVA range for the whole bitmap */
        size_t length;
+
+       /* length of the IOVA range set ahead the pinned pages */
+       unsigned long set_ahead_length;
 };
 
 /*
@@ -162,7 +165,7 @@ static int iova_bitmap_get(struct iova_bitmap *bitmap)
 {
        struct iova_bitmap_map *mapped = &bitmap->mapped;
        unsigned long npages;
-       u64 __user *addr;
+       u8 __user *addr;
        long ret;
 
        /*
@@ -175,18 +178,19 @@ static int iova_bitmap_get(struct iova_bitmap *bitmap)
                               bitmap->mapped_base_index) *
                               sizeof(*bitmap->bitmap), PAGE_SIZE);
 
-       /*
-        * We always cap at max number of 'struct page' a base page can fit.
-        * This is, for example, on x86 means 2M of bitmap data max.
-        */
-       npages = min(npages,  PAGE_SIZE / sizeof(struct page *));
-
        /*
         * Bitmap address to be pinned is calculated via pointer arithmetic
         * with bitmap u64 word index.
         */
        addr = bitmap->bitmap + bitmap->mapped_base_index;
 
+       /*
+        * We always cap at max number of 'struct page' a base page can fit.
+        * This is, for example, on x86 means 2M of bitmap data max.
+        */
+       npages = min(npages + !!offset_in_page(addr),
+                    PAGE_SIZE / sizeof(struct page *));
+
        ret = pin_user_pages_fast((unsigned long)addr, npages,
                                  FOLL_WRITE, mapped->pages);
        if (ret <= 0)
@@ -247,7 +251,7 @@ struct iova_bitmap *iova_bitmap_alloc(unsigned long iova, size_t length,
 
        mapped = &bitmap->mapped;
        mapped->pgshift = __ffs(page_size);
-       bitmap->bitmap = data;
+       bitmap->bitmap = (u8 __user *)data;
        bitmap->mapped_total_index =
                iova_bitmap_offset_to_index(bitmap, length - 1) + 1;
        bitmap->iova = iova;
@@ -304,7 +308,7 @@ static unsigned long iova_bitmap_mapped_remaining(struct iova_bitmap *bitmap)
 
        remaining = bitmap->mapped_total_index - bitmap->mapped_base_index;
        remaining = min_t(unsigned long, remaining,
-                         bytes / sizeof(*bitmap->bitmap));
+                         DIV_ROUND_UP(bytes, sizeof(*bitmap->bitmap)));
 
        return remaining;
 }
@@ -341,6 +345,32 @@ static bool iova_bitmap_done(struct iova_bitmap *bitmap)
        return bitmap->mapped_base_index >= bitmap->mapped_total_index;
 }
 
+static int iova_bitmap_set_ahead(struct iova_bitmap *bitmap,
+                                size_t set_ahead_length)
+{
+       int ret = 0;
+
+       while (set_ahead_length > 0 && !iova_bitmap_done(bitmap)) {
+               unsigned long length = iova_bitmap_mapped_length(bitmap);
+               unsigned long iova = iova_bitmap_mapped_iova(bitmap);
+
+               ret = iova_bitmap_get(bitmap);
+               if (ret)
+                       break;
+
+               length = min(length, set_ahead_length);
+               iova_bitmap_set(bitmap, iova, length);
+
+               set_ahead_length -= length;
+               bitmap->mapped_base_index +=
+                       iova_bitmap_offset_to_index(bitmap, length - 1) + 1;
+               iova_bitmap_put(bitmap);
+       }
+
+       bitmap->set_ahead_length = 0;
+       return ret;
+}
+
 /*
  * Advances to the next range, releases the current pinned
  * pages and pins the next set of bitmap pages.
@@ -357,6 +387,15 @@ static int iova_bitmap_advance(struct iova_bitmap *bitmap)
        if (iova_bitmap_done(bitmap))
                return 0;
 
+       /* Iterate, set and skip any bits requested for next iteration */
+       if (bitmap->set_ahead_length) {
+               int ret;
+
+               ret = iova_bitmap_set_ahead(bitmap, bitmap->set_ahead_length);
+               if (ret)
+                       return ret;
+       }
+
        /* When advancing the index we pin the next set of bitmap pages */
        return iova_bitmap_get(bitmap);
 }
@@ -409,6 +448,7 @@ void iova_bitmap_set(struct iova_bitmap *bitmap,
                        mapped->pgshift) + mapped->pgoff * BITS_PER_BYTE;
        unsigned long last_bit = (((iova + length - 1) - mapped->iova) >>
                        mapped->pgshift) + mapped->pgoff * BITS_PER_BYTE;
+       unsigned long last_page_idx = mapped->npages - 1;
 
        do {
                unsigned int page_idx = cur_bit / BITS_PER_PAGE;
@@ -417,10 +457,18 @@ void iova_bitmap_set(struct iova_bitmap *bitmap,
                                         last_bit - cur_bit + 1);
                void *kaddr;
 
+               if (unlikely(page_idx > last_page_idx))
+                       break;
+
                kaddr = kmap_local_page(mapped->pages[page_idx]);
                bitmap_set(kaddr, offset, nbits);
                kunmap_local(kaddr);
                cur_bit += nbits;
        } while (cur_bit <= last_bit);
+
+       if (unlikely(cur_bit <= last_bit)) {
+               bitmap->set_ahead_length =
+                       ((last_bit - cur_bit + 1) << bitmap->mapped.pgshift);
+       }
 }
 EXPORT_SYMBOL_NS_GPL(iova_bitmap_set, IOMMUFD);
index d9e9920c7eba413eaf25b7840eefdf36a3999a9e..7a2199470f3121da91e060bca82315a6944e37b8 100644 (file)
@@ -36,11 +36,12 @@ static struct mock_bus_type iommufd_mock_bus_type = {
        },
 };
 
-static atomic_t mock_dev_num;
+static DEFINE_IDA(mock_dev_ida);
 
 enum {
        MOCK_DIRTY_TRACK = 1,
        MOCK_IO_PAGE_SIZE = PAGE_SIZE / 2,
+       MOCK_HUGE_PAGE_SIZE = 512 * MOCK_IO_PAGE_SIZE,
 
        /*
         * Like a real page table alignment requires the low bits of the address
@@ -53,6 +54,7 @@ enum {
        MOCK_PFN_START_IOVA = _MOCK_PFN_START,
        MOCK_PFN_LAST_IOVA = _MOCK_PFN_START,
        MOCK_PFN_DIRTY_IOVA = _MOCK_PFN_START << 1,
+       MOCK_PFN_HUGE_IOVA = _MOCK_PFN_START << 2,
 };
 
 /*
@@ -61,8 +63,8 @@ enum {
  * In syzkaller mode the 64 bit IOVA is converted into an nth area and offset
  * value. This has a much smaller randomization space and syzkaller can hit it.
  */
-static unsigned long iommufd_test_syz_conv_iova(struct io_pagetable *iopt,
-                                               u64 *iova)
+static unsigned long __iommufd_test_syz_conv_iova(struct io_pagetable *iopt,
+                                                 u64 *iova)
 {
        struct syz_layout {
                __u32 nth_area;
@@ -86,6 +88,21 @@ static unsigned long iommufd_test_syz_conv_iova(struct io_pagetable *iopt,
        return 0;
 }
 
+static unsigned long iommufd_test_syz_conv_iova(struct iommufd_access *access,
+                                               u64 *iova)
+{
+       unsigned long ret;
+
+       mutex_lock(&access->ioas_lock);
+       if (!access->ioas) {
+               mutex_unlock(&access->ioas_lock);
+               return 0;
+       }
+       ret = __iommufd_test_syz_conv_iova(&access->ioas->iopt, iova);
+       mutex_unlock(&access->ioas_lock);
+       return ret;
+}
+
 void iommufd_test_syz_conv_iova_id(struct iommufd_ucmd *ucmd,
                                   unsigned int ioas_id, u64 *iova, u32 *flags)
 {
@@ -98,7 +115,7 @@ void iommufd_test_syz_conv_iova_id(struct iommufd_ucmd *ucmd,
        ioas = iommufd_get_ioas(ucmd->ictx, ioas_id);
        if (IS_ERR(ioas))
                return;
-       *iova = iommufd_test_syz_conv_iova(&ioas->iopt, iova);
+       *iova = __iommufd_test_syz_conv_iova(&ioas->iopt, iova);
        iommufd_put_object(ucmd->ictx, &ioas->obj);
 }
 
@@ -121,6 +138,7 @@ enum selftest_obj_type {
 struct mock_dev {
        struct device dev;
        unsigned long flags;
+       int id;
 };
 
 struct selftest_obj {
@@ -191,6 +209,34 @@ static int mock_domain_set_dirty_tracking(struct iommu_domain *domain,
        return 0;
 }
 
+static bool mock_test_and_clear_dirty(struct mock_iommu_domain *mock,
+                                     unsigned long iova, size_t page_size,
+                                     unsigned long flags)
+{
+       unsigned long cur, end = iova + page_size - 1;
+       bool dirty = false;
+       void *ent, *old;
+
+       for (cur = iova; cur < end; cur += MOCK_IO_PAGE_SIZE) {
+               ent = xa_load(&mock->pfns, cur / MOCK_IO_PAGE_SIZE);
+               if (!ent || !(xa_to_value(ent) & MOCK_PFN_DIRTY_IOVA))
+                       continue;
+
+               dirty = true;
+               /* Clear dirty */
+               if (!(flags & IOMMU_DIRTY_NO_CLEAR)) {
+                       unsigned long val;
+
+                       val = xa_to_value(ent) & ~MOCK_PFN_DIRTY_IOVA;
+                       old = xa_store(&mock->pfns, cur / MOCK_IO_PAGE_SIZE,
+                                      xa_mk_value(val), GFP_KERNEL);
+                       WARN_ON_ONCE(ent != old);
+               }
+       }
+
+       return dirty;
+}
+
 static int mock_domain_read_and_clear_dirty(struct iommu_domain *domain,
                                            unsigned long iova, size_t size,
                                            unsigned long flags,
@@ -198,31 +244,31 @@ static int mock_domain_read_and_clear_dirty(struct iommu_domain *domain,
 {
        struct mock_iommu_domain *mock =
                container_of(domain, struct mock_iommu_domain, domain);
-       unsigned long i, max = size / MOCK_IO_PAGE_SIZE;
-       void *ent, *old;
+       unsigned long end = iova + size;
+       void *ent;
 
        if (!(mock->flags & MOCK_DIRTY_TRACK) && dirty->bitmap)
                return -EINVAL;
 
-       for (i = 0; i < max; i++) {
-               unsigned long cur = iova + i * MOCK_IO_PAGE_SIZE;
+       do {
+               unsigned long pgsize = MOCK_IO_PAGE_SIZE;
+               unsigned long head;
 
-               ent = xa_load(&mock->pfns, cur / MOCK_IO_PAGE_SIZE);
-               if (ent && (xa_to_value(ent) & MOCK_PFN_DIRTY_IOVA)) {
-                       /* Clear dirty */
-                       if (!(flags & IOMMU_DIRTY_NO_CLEAR)) {
-                               unsigned long val;
-
-                               val = xa_to_value(ent) & ~MOCK_PFN_DIRTY_IOVA;
-                               old = xa_store(&mock->pfns,
-                                              cur / MOCK_IO_PAGE_SIZE,
-                                              xa_mk_value(val), GFP_KERNEL);
-                               WARN_ON_ONCE(ent != old);
-                       }
-                       iommu_dirty_bitmap_record(dirty, cur,
-                                                 MOCK_IO_PAGE_SIZE);
+               ent = xa_load(&mock->pfns, iova / MOCK_IO_PAGE_SIZE);
+               if (!ent) {
+                       iova += pgsize;
+                       continue;
                }
-       }
+
+               if (xa_to_value(ent) & MOCK_PFN_HUGE_IOVA)
+                       pgsize = MOCK_HUGE_PAGE_SIZE;
+               head = iova & ~(pgsize - 1);
+
+               /* Clear dirty */
+               if (mock_test_and_clear_dirty(mock, head, pgsize, flags))
+                       iommu_dirty_bitmap_record(dirty, head, pgsize);
+               iova = head + pgsize;
+       } while (iova < end);
 
        return 0;
 }
@@ -234,6 +280,7 @@ const struct iommu_dirty_ops dirty_ops = {
 
 static struct iommu_domain *mock_domain_alloc_paging(struct device *dev)
 {
+       struct mock_dev *mdev = container_of(dev, struct mock_dev, dev);
        struct mock_iommu_domain *mock;
 
        mock = kzalloc(sizeof(*mock), GFP_KERNEL);
@@ -242,6 +289,8 @@ static struct iommu_domain *mock_domain_alloc_paging(struct device *dev)
        mock->domain.geometry.aperture_start = MOCK_APERTURE_START;
        mock->domain.geometry.aperture_end = MOCK_APERTURE_LAST;
        mock->domain.pgsize_bitmap = MOCK_IO_PAGE_SIZE;
+       if (dev && mdev->flags & MOCK_FLAGS_DEVICE_HUGE_IOVA)
+               mock->domain.pgsize_bitmap |= MOCK_HUGE_PAGE_SIZE;
        mock->domain.ops = mock_ops.default_domain_ops;
        mock->domain.type = IOMMU_DOMAIN_UNMANAGED;
        xa_init(&mock->pfns);
@@ -287,7 +336,7 @@ mock_domain_alloc_user(struct device *dev, u32 flags,
                        return ERR_PTR(-EOPNOTSUPP);
                if (user_data || (has_dirty_flag && no_dirty_ops))
                        return ERR_PTR(-EOPNOTSUPP);
-               domain = mock_domain_alloc_paging(NULL);
+               domain = mock_domain_alloc_paging(dev);
                if (!domain)
                        return ERR_PTR(-ENOMEM);
                if (has_dirty_flag)
@@ -350,6 +399,9 @@ static int mock_domain_map_pages(struct iommu_domain *domain,
 
                        if (pgcount == 1 && cur + MOCK_IO_PAGE_SIZE == pgsize)
                                flags = MOCK_PFN_LAST_IOVA;
+                       if (pgsize != MOCK_IO_PAGE_SIZE) {
+                               flags |= MOCK_PFN_HUGE_IOVA;
+                       }
                        old = xa_store(&mock->pfns, iova / MOCK_IO_PAGE_SIZE,
                                       xa_mk_value((paddr / MOCK_IO_PAGE_SIZE) |
                                                   flags),
@@ -394,20 +446,27 @@ static size_t mock_domain_unmap_pages(struct iommu_domain *domain,
 
                        /*
                         * iommufd generates unmaps that must be a strict
-                        * superset of the map's performend So every starting
-                        * IOVA should have been an iova passed to map, and the
+                        * superset of the map's performend So every
+                        * starting/ending IOVA should have been an iova passed
+                        * to map.
                         *
-                        * First IOVA must be present and have been a first IOVA
-                        * passed to map_pages
+                        * This simple logic doesn't work when the HUGE_PAGE is
+                        * turned on since the core code will automatically
+                        * switch between the two page sizes creating a break in
+                        * the unmap calls. The break can land in the middle of
+                        * contiguous IOVA.
                         */
-                       if (first) {
-                               WARN_ON(ent && !(xa_to_value(ent) &
-                                                MOCK_PFN_START_IOVA));
-                               first = false;
+                       if (!(domain->pgsize_bitmap & MOCK_HUGE_PAGE_SIZE)) {
+                               if (first) {
+                                       WARN_ON(ent && !(xa_to_value(ent) &
+                                                        MOCK_PFN_START_IOVA));
+                                       first = false;
+                               }
+                               if (pgcount == 1 &&
+                                   cur + MOCK_IO_PAGE_SIZE == pgsize)
+                                       WARN_ON(ent && !(xa_to_value(ent) &
+                                                        MOCK_PFN_LAST_IOVA));
                        }
-                       if (pgcount == 1 && cur + MOCK_IO_PAGE_SIZE == pgsize)
-                               WARN_ON(ent && !(xa_to_value(ent) &
-                                                MOCK_PFN_LAST_IOVA));
 
                        iova += MOCK_IO_PAGE_SIZE;
                        ret += MOCK_IO_PAGE_SIZE;
@@ -595,7 +654,7 @@ static void mock_dev_release(struct device *dev)
 {
        struct mock_dev *mdev = container_of(dev, struct mock_dev, dev);
 
-       atomic_dec(&mock_dev_num);
+       ida_free(&mock_dev_ida, mdev->id);
        kfree(mdev);
 }
 
@@ -604,7 +663,8 @@ static struct mock_dev *mock_dev_create(unsigned long dev_flags)
        struct mock_dev *mdev;
        int rc;
 
-       if (dev_flags & ~(MOCK_FLAGS_DEVICE_NO_DIRTY))
+       if (dev_flags &
+           ~(MOCK_FLAGS_DEVICE_NO_DIRTY | MOCK_FLAGS_DEVICE_HUGE_IOVA))
                return ERR_PTR(-EINVAL);
 
        mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
@@ -616,8 +676,12 @@ static struct mock_dev *mock_dev_create(unsigned long dev_flags)
        mdev->dev.release = mock_dev_release;
        mdev->dev.bus = &iommufd_mock_bus_type.bus;
 
-       rc = dev_set_name(&mdev->dev, "iommufd_mock%u",
-                         atomic_inc_return(&mock_dev_num));
+       rc = ida_alloc(&mock_dev_ida, GFP_KERNEL);
+       if (rc < 0)
+               goto err_put;
+       mdev->id = rc;
+
+       rc = dev_set_name(&mdev->dev, "iommufd_mock%u", mdev->id);
        if (rc)
                goto err_put;
 
@@ -1119,7 +1183,7 @@ static int iommufd_test_access_pages(struct iommufd_ucmd *ucmd,
        }
 
        if (flags & MOCK_FLAGS_ACCESS_SYZ)
-               iova = iommufd_test_syz_conv_iova(&staccess->access->ioas->iopt,
+               iova = iommufd_test_syz_conv_iova(staccess->access,
                                        &cmd->access_pages.iova);
 
        npages = (ALIGN(iova + length, PAGE_SIZE) -
@@ -1221,8 +1285,8 @@ static int iommufd_test_access_rw(struct iommufd_ucmd *ucmd,
        }
 
        if (flags & MOCK_FLAGS_ACCESS_SYZ)
-               iova = iommufd_test_syz_conv_iova(&staccess->access->ioas->iopt,
-                                       &cmd->access_rw.iova);
+               iova = iommufd_test_syz_conv_iova(staccess->access,
+                               &cmd->access_rw.iova);
 
        rc = iommufd_access_rw(staccess->access, iova, tmp, length, flags);
        if (rc)
index f7149d0f3d45ca2358e220a5f229491d86271a7e..72c07a12f5e18e7af52a80ce24d7e1f77c42416d 100644 (file)
@@ -546,6 +546,17 @@ config SIFIVE_PLIC
        select IRQ_DOMAIN_HIERARCHY
        select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
 
+config STARFIVE_JH8100_INTC
+       bool "StarFive JH8100 External Interrupt Controller"
+       depends on ARCH_STARFIVE || COMPILE_TEST
+       default ARCH_STARFIVE
+       select IRQ_DOMAIN_HIERARCHY
+       help
+         This enables support for the INTC chip found in StarFive JH8100
+         SoC.
+
+         If you don't know what to do here, say Y.
+
 config EXYNOS_IRQ_COMBINER
        bool "Samsung Exynos IRQ combiner support" if COMPILE_TEST
        depends on (ARCH_EXYNOS && ARM) || COMPILE_TEST
index ffd945fe71aa2ce7e97d1c7e86509886b2fecb23..ec4a183809981d201701fd8d1b2224fd5cc92bf2 100644 (file)
@@ -96,6 +96,7 @@ obj-$(CONFIG_CSKY_MPINTC)             += irq-csky-mpintc.o
 obj-$(CONFIG_CSKY_APB_INTC)            += irq-csky-apb-intc.o
 obj-$(CONFIG_RISCV_INTC)               += irq-riscv-intc.o
 obj-$(CONFIG_SIFIVE_PLIC)              += irq-sifive-plic.o
+obj-$(CONFIG_STARFIVE_JH8100_INTC)     += irq-starfive-jh8100-intc.o
 obj-$(CONFIG_IMX_IRQSTEER)             += irq-imx-irqsteer.o
 obj-$(CONFIG_IMX_INTMUX)               += irq-imx-intmux.o
 obj-$(CONFIG_IMX_MU_MSI)               += irq-imx-mu-msi.o
index 9745a119d0e66131524c5999458d42eda2c4b570..eb02d203c9634fb649a27ce03c6a9c00785b60e0 100644 (file)
@@ -242,7 +242,7 @@ static int __init bcm6345_l1_init_one(struct device_node *dn,
        else if (intc->n_words != n_words)
                return -EINVAL;
 
-       cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32),
+       cpu = intc->cpus[idx] = kzalloc(struct_size(cpu, enable_cache, n_words),
                                        GFP_KERNEL);
        if (!cpu)
                return -ENOMEM;
index 24ca1d656adc5ef6680b4653417f18c8e7ef09d3..36e71af054e9794248e4ea8a2b2efb77c6895e14 100644 (file)
@@ -249,7 +249,7 @@ static int __init bcm7038_l1_init_one(struct device_node *dn,
                return -EINVAL;
        }
 
-       cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32),
+       cpu = intc->cpus[idx] = kzalloc(struct_size(cpu, mask_cache, n_words),
                                        GFP_KERNEL);
        if (!cpu)
                return -ENOMEM;
index 5559c943f03f973137432de01f1972aec58f94b6..2b0b3175cea068eb571d8ec5f82a4d45a01e5719 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Generic Broadcom Set Top Box Level 2 Interrupt controller driver
  *
- * Copyright (C) 2014-2017 Broadcom
+ * Copyright (C) 2014-2024 Broadcom
  */
 
 #define pr_fmt(fmt)    KBUILD_MODNAME  ": " fmt
@@ -112,6 +112,9 @@ static void brcmstb_l2_intc_irq_handle(struct irq_desc *desc)
                generic_handle_domain_irq(b->domain, irq);
        } while (status);
 out:
+       /* Don't ack parent before all device writes are done */
+       wmb();
+
        chained_irq_exit(chip, desc);
 }
 
index d097001c1e3ee7e1d1380a891660dfc522a37554..fca888b36680df813c952d8d29e1cf74cd81e167 100644 (file)
@@ -207,6 +207,11 @@ static bool require_its_list_vmovp(struct its_vm *vm, struct its_node *its)
        return (gic_rdists->has_rvpeid || vm->vlpi_count[its->list_nr]);
 }
 
+static bool rdists_support_shareable(void)
+{
+       return !(gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE);
+}
+
 static u16 get_its_list(struct its_vm *vm)
 {
        struct its_node *its;
@@ -2710,10 +2715,12 @@ static u64 inherit_vpe_l1_table_from_its(void)
                        break;
                }
                val |= FIELD_PREP(GICR_VPROPBASER_4_1_ADDR, addr >> 12);
-               val |= FIELD_PREP(GICR_VPROPBASER_SHAREABILITY_MASK,
-                                 FIELD_GET(GITS_BASER_SHAREABILITY_MASK, baser));
-               val |= FIELD_PREP(GICR_VPROPBASER_INNER_CACHEABILITY_MASK,
-                                 FIELD_GET(GITS_BASER_INNER_CACHEABILITY_MASK, baser));
+               if (rdists_support_shareable()) {
+                       val |= FIELD_PREP(GICR_VPROPBASER_SHAREABILITY_MASK,
+                                         FIELD_GET(GITS_BASER_SHAREABILITY_MASK, baser));
+                       val |= FIELD_PREP(GICR_VPROPBASER_INNER_CACHEABILITY_MASK,
+                                         FIELD_GET(GITS_BASER_INNER_CACHEABILITY_MASK, baser));
+               }
                val |= FIELD_PREP(GICR_VPROPBASER_4_1_SIZE, GITS_BASER_NR_PAGES(baser) - 1);
 
                return val;
@@ -2936,8 +2943,10 @@ static int allocate_vpe_l1_table(void)
        WARN_ON(!IS_ALIGNED(pa, psz));
 
        val |= FIELD_PREP(GICR_VPROPBASER_4_1_ADDR, pa >> 12);
-       val |= GICR_VPROPBASER_RaWb;
-       val |= GICR_VPROPBASER_InnerShareable;
+       if (rdists_support_shareable()) {
+               val |= GICR_VPROPBASER_RaWb;
+               val |= GICR_VPROPBASER_InnerShareable;
+       }
        val |= GICR_VPROPBASER_4_1_Z;
        val |= GICR_VPROPBASER_4_1_VALID;
 
@@ -3126,7 +3135,7 @@ static void its_cpu_init_lpis(void)
        gicr_write_propbaser(val, rbase + GICR_PROPBASER);
        tmp = gicr_read_propbaser(rbase + GICR_PROPBASER);
 
-       if (gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE)
+       if (!rdists_support_shareable())
                tmp &= ~GICR_PROPBASER_SHAREABILITY_MASK;
 
        if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) {
@@ -3153,7 +3162,7 @@ static void its_cpu_init_lpis(void)
        gicr_write_pendbaser(val, rbase + GICR_PENDBASER);
        tmp = gicr_read_pendbaser(rbase + GICR_PENDBASER);
 
-       if (gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE)
+       if (!rdists_support_shareable())
                tmp &= ~GICR_PENDBASER_SHAREABILITY_MASK;
 
        if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) {
@@ -3172,6 +3181,7 @@ static void its_cpu_init_lpis(void)
        val |= GICR_CTLR_ENABLE_LPIS;
        writel_relaxed(val, rbase + GICR_CTLR);
 
+out:
        if (gic_rdists->has_vlpis && !gic_rdists->has_rvpeid) {
                void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
 
@@ -3207,7 +3217,6 @@ static void its_cpu_init_lpis(void)
 
        /* Make sure the GIC has seen the above */
        dsb(sy);
-out:
        gic_data_rdist()->flags |= RD_LOCAL_LPI_ENABLED;
        pr_info("GICv3: CPU%d: using %s LPI pending table @%pa\n",
                smp_processor_id(),
@@ -3817,8 +3826,9 @@ static int its_vpe_set_affinity(struct irq_data *d,
                                bool force)
 {
        struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
-       int from, cpu = cpumask_first(mask_val);
+       struct cpumask common, *table_mask;
        unsigned long flags;
+       int from, cpu;
 
        /*
         * Changing affinity is mega expensive, so let's be as lazy as
@@ -3834,19 +3844,22 @@ static int its_vpe_set_affinity(struct irq_data *d,
         * taken on any vLPI handling path that evaluates vpe->col_idx.
         */
        from = vpe_to_cpuid_lock(vpe, &flags);
-       if (from == cpu)
-               goto out;
-
-       vpe->col_idx = cpu;
+       table_mask = gic_data_rdist_cpu(from)->vpe_table_mask;
 
        /*
-        * GICv4.1 allows us to skip VMOVP if moving to a cpu whose RD
-        * is sharing its VPE table with the current one.
+        * If we are offered another CPU in the same GICv4.1 ITS
+        * affinity, pick this one. Otherwise, any CPU will do.
         */
-       if (gic_data_rdist_cpu(cpu)->vpe_table_mask &&
-           cpumask_test_cpu(from, gic_data_rdist_cpu(cpu)->vpe_table_mask))
+       if (table_mask && cpumask_and(&common, mask_val, table_mask))
+               cpu = cpumask_test_cpu(from, &common) ? from : cpumask_first(&common);
+       else
+               cpu = cpumask_first(mask_val);
+
+       if (from == cpu)
                goto out;
 
+       vpe->col_idx = cpu;
+
        its_send_vmovp(vpe);
        its_vpe_db_proxy_move(vpe, from, cpu);
 
@@ -3880,14 +3893,18 @@ static void its_vpe_schedule(struct its_vpe *vpe)
        val  = virt_to_phys(page_address(vpe->its_vm->vprop_page)) &
                GENMASK_ULL(51, 12);
        val |= (LPI_NRBITS - 1) & GICR_VPROPBASER_IDBITS_MASK;
-       val |= GICR_VPROPBASER_RaWb;
-       val |= GICR_VPROPBASER_InnerShareable;
+       if (rdists_support_shareable()) {
+               val |= GICR_VPROPBASER_RaWb;
+               val |= GICR_VPROPBASER_InnerShareable;
+       }
        gicr_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
 
        val  = virt_to_phys(page_address(vpe->vpt_page)) &
                GENMASK_ULL(51, 16);
-       val |= GICR_VPENDBASER_RaWaWb;
-       val |= GICR_VPENDBASER_InnerShareable;
+       if (rdists_support_shareable()) {
+               val |= GICR_VPENDBASER_RaWaWb;
+               val |= GICR_VPENDBASER_InnerShareable;
+       }
        /*
         * There is no good way of finding out if the pending table is
         * empty as we can race against the doorbell interrupt very
@@ -4419,12 +4436,12 @@ static const struct irq_domain_ops its_sgi_domain_ops = {
 
 static int its_vpe_id_alloc(void)
 {
-       return ida_simple_get(&its_vpeid_ida, 0, ITS_MAX_VPEID, GFP_KERNEL);
+       return ida_alloc_max(&its_vpeid_ida, ITS_MAX_VPEID - 1, GFP_KERNEL);
 }
 
 static void its_vpe_id_free(u16 id)
 {
-       ida_simple_remove(&its_vpeid_ida, id);
+       ida_free(&its_vpeid_ida, id);
 }
 
 static int its_vpe_init(struct its_vpe *vpe)
@@ -5078,6 +5095,8 @@ static int __init its_probe_one(struct its_node *its)
        u32 ctlr;
        int err;
 
+       its_enable_quirks(its);
+
        if (is_v4(its)) {
                if (!(its->typer & GITS_TYPER_VMOVP)) {
                        err = its_compute_its_list_map(its);
@@ -5429,7 +5448,6 @@ static int __init its_of_probe(struct device_node *node)
                if (!its)
                        return -ENOMEM;
 
-               its_enable_quirks(its);
                err = its_probe_one(its);
                if (err)  {
                        its_node_destroy(its);
index 98b0329b7154a4377afaa6b3cf5622e304dd2110..6fb276504bcc834d058589d81f62213e70d071d3 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/percpu.h>
 #include <linux/refcount.h>
 #include <linux/slab.h>
+#include <linux/iopoll.h>
 
 #include <linux/irqchip.h>
 #include <linux/irqchip/arm-gic-common.h>
@@ -180,11 +181,6 @@ static enum gic_intid_range get_intid_range(struct irq_data *d)
        return __get_intid_range(d->hwirq);
 }
 
-static inline unsigned int gic_irq(struct irq_data *d)
-{
-       return d->hwirq;
-}
-
 static inline bool gic_irq_in_rdist(struct irq_data *d)
 {
        switch (get_intid_range(d)) {
@@ -251,17 +247,13 @@ static inline void __iomem *gic_dist_base(struct irq_data *d)
 
 static void gic_do_wait_for_rwp(void __iomem *base, u32 bit)
 {
-       u32 count = 1000000;    /* 1s! */
+       u32 val;
+       int ret;
 
-       while (readl_relaxed(base + GICD_CTLR) & bit) {
-               count--;
-               if (!count) {
-                       pr_err_ratelimited("RWP timeout, gone fishing\n");
-                       return;
-               }
-               cpu_relax();
-               udelay(1);
-       }
+       ret = readl_relaxed_poll_timeout_atomic(base + GICD_CTLR, val, !(val & bit),
+                                               1, USEC_PER_SEC);
+       if (ret == -ETIMEDOUT)
+               pr_err_ratelimited("RWP timeout, gone fishing\n");
 }
 
 /* Wait for completion of a distributor change */
@@ -279,8 +271,8 @@ static void gic_redist_wait_for_rwp(void)
 static void gic_enable_redist(bool enable)
 {
        void __iomem *rbase;
-       u32 count = 1000000;    /* 1s! */
        u32 val;
+       int ret;
 
        if (gic_data.flags & FLAGS_WORKAROUND_GICR_WAKER_MSM8996)
                return;
@@ -301,16 +293,13 @@ static void gic_enable_redist(bool enable)
                        return; /* No PM support in this redistributor */
        }
 
-       while (--count) {
-               val = readl_relaxed(rbase + GICR_WAKER);
-               if (enable ^ (bool)(val & GICR_WAKER_ChildrenAsleep))
-                       break;
-               cpu_relax();
-               udelay(1);
-       }
-       if (!count)
+       ret = readl_relaxed_poll_timeout_atomic(rbase + GICR_WAKER, val,
+                                               enable ^ (bool)(val & GICR_WAKER_ChildrenAsleep),
+                                               1, USEC_PER_SEC);
+       if (ret == -ETIMEDOUT) {
                pr_err_ratelimited("redistributor failed to %s...\n",
                                   enable ? "wakeup" : "sleep");
+       }
 }
 
 /*
@@ -548,7 +537,7 @@ static int gic_irq_nmi_setup(struct irq_data *d)
         * A secondary irq_chip should be in charge of LPI request,
         * it should not be possible to get there
         */
-       if (WARN_ON(gic_irq(d) >= 8192))
+       if (WARN_ON(irqd_to_hwirq(d) >= 8192))
                return -EINVAL;
 
        /* desc lock should already be held */
@@ -588,7 +577,7 @@ static void gic_irq_nmi_teardown(struct irq_data *d)
         * A secondary irq_chip should be in charge of LPI request,
         * it should not be possible to get there
         */
-       if (WARN_ON(gic_irq(d) >= 8192))
+       if (WARN_ON(irqd_to_hwirq(d) >= 8192))
                return;
 
        /* desc lock should already be held */
@@ -626,7 +615,7 @@ static bool gic_arm64_erratum_2941627_needed(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-       write_gicreg(gic_irq(d), ICC_EOIR1_EL1);
+       write_gicreg(irqd_to_hwirq(d), ICC_EOIR1_EL1);
        isb();
 
        if (gic_arm64_erratum_2941627_needed(d)) {
@@ -646,19 +635,19 @@ static void gic_eoimode1_eoi_irq(struct irq_data *d)
         * No need to deactivate an LPI, or an interrupt that
         * is is getting forwarded to a vcpu.
         */
-       if (gic_irq(d) >= 8192 || irqd_is_forwarded_to_vcpu(d))
+       if (irqd_to_hwirq(d) >= 8192 || irqd_is_forwarded_to_vcpu(d))
                return;
 
        if (!gic_arm64_erratum_2941627_needed(d))
-               gic_write_dir(gic_irq(d));
+               gic_write_dir(irqd_to_hwirq(d));
        else
                gic_poke_irq(d, GICD_ICACTIVER);
 }
 
 static int gic_set_type(struct irq_data *d, unsigned int type)
 {
+       irq_hw_number_t irq = irqd_to_hwirq(d);
        enum gic_intid_range range;
-       unsigned int irq = gic_irq(d);
        void __iomem *base;
        u32 offset, index;
        int ret;
@@ -684,7 +673,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
        ret = gic_configure_irq(index, type, base + offset, NULL);
        if (ret && (range == PPI_RANGE || range == EPPI_RANGE)) {
                /* Misconfigured PPIs are usually not fatal */
-               pr_warn("GIC: PPI INTID%d is secure or misconfigured\n", irq);
+               pr_warn("GIC: PPI INTID%ld is secure or misconfigured\n", irq);
                ret = 0;
        }
 
@@ -1702,9 +1691,13 @@ static int gic_irq_domain_select(struct irq_domain *d,
        irq_hw_number_t hwirq;
 
        /* Not for us */
-        if (fwspec->fwnode != d->fwnode)
+       if (fwspec->fwnode != d->fwnode)
                return 0;
 
+       /* Handle pure domain searches */
+       if (!fwspec->param_count)
+               return d->bus_token == bus_token;
+
        /* If this is not DT, then we have a single domain */
        if (!is_of_node(fwspec->fwnode))
                return 1;
index 412196a7dad587dca5773dcd71e6b2f9d3d95b5f..98aa383e39db1c274e871258635e218962076998 100644 (file)
@@ -162,11 +162,6 @@ static inline void __iomem *gic_cpu_base(struct irq_data *d)
        return gic_data_cpu_base(gic_data);
 }
 
-static inline unsigned int gic_irq(struct irq_data *d)
-{
-       return d->hwirq;
-}
-
 static inline bool cascading_gic_irq(struct irq_data *d)
 {
        void *data = irq_data_get_irq_handler_data(d);
@@ -183,14 +178,16 @@ static inline bool cascading_gic_irq(struct irq_data *d)
  */
 static void gic_poke_irq(struct irq_data *d, u32 offset)
 {
-       u32 mask = 1 << (gic_irq(d) % 32);
-       writel_relaxed(mask, gic_dist_base(d) + offset + (gic_irq(d) / 32) * 4);
+       u32 mask = 1 << (irqd_to_hwirq(d) % 32);
+
+       writel_relaxed(mask, gic_dist_base(d) + offset + (irqd_to_hwirq(d) / 32) * 4);
 }
 
 static int gic_peek_irq(struct irq_data *d, u32 offset)
 {
-       u32 mask = 1 << (gic_irq(d) % 32);
-       return !!(readl_relaxed(gic_dist_base(d) + offset + (gic_irq(d) / 32) * 4) & mask);
+       u32 mask = 1 << (irqd_to_hwirq(d) % 32);
+
+       return !!(readl_relaxed(gic_dist_base(d) + offset + (irqd_to_hwirq(d) / 32) * 4) & mask);
 }
 
 static void gic_mask_irq(struct irq_data *d)
@@ -220,7 +217,7 @@ static void gic_unmask_irq(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-       u32 hwirq = gic_irq(d);
+       irq_hw_number_t hwirq = irqd_to_hwirq(d);
 
        if (hwirq < 16)
                hwirq = this_cpu_read(sgi_intid);
@@ -230,7 +227,7 @@ static void gic_eoi_irq(struct irq_data *d)
 
 static void gic_eoimode1_eoi_irq(struct irq_data *d)
 {
-       u32 hwirq = gic_irq(d);
+       irq_hw_number_t hwirq = irqd_to_hwirq(d);
 
        /* Do not deactivate an IRQ forwarded to a vcpu. */
        if (irqd_is_forwarded_to_vcpu(d))
@@ -293,8 +290,8 @@ static int gic_irq_get_irqchip_state(struct irq_data *d,
 
 static int gic_set_type(struct irq_data *d, unsigned int type)
 {
+       irq_hw_number_t gicirq = irqd_to_hwirq(d);
        void __iomem *base = gic_dist_base(d);
-       unsigned int gicirq = gic_irq(d);
        int ret;
 
        /* Interrupt configuration for SGIs can't be changed */
@@ -309,7 +306,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
        ret = gic_configure_irq(gicirq, type, base + GIC_DIST_CONFIG, NULL);
        if (ret && gicirq < 32) {
                /* Misconfigured PPIs are usually not fatal */
-               pr_warn("GIC: PPI%d is secure or misconfigured\n", gicirq - 16);
+               pr_warn("GIC: PPI%ld is secure or misconfigured\n", gicirq - 16);
                ret = 0;
        }
 
@@ -319,7 +316,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
 static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
 {
        /* Only interrupts on the primary GIC can be forwarded to a vcpu. */
-       if (cascading_gic_irq(d) || gic_irq(d) < 16)
+       if (cascading_gic_irq(d) || irqd_to_hwirq(d) < 16)
                return -EINVAL;
 
        if (vcpu)
@@ -796,7 +793,7 @@ static void rmw_writeb(u8 bval, void __iomem *addr)
 static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
                            bool force)
 {
-       void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + gic_irq(d);
+       void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + irqd_to_hwirq(d);
        struct gic_chip_data *gic = irq_data_get_irq_chip_data(d);
        unsigned int cpu;
 
index 5831be4546736936beef68e36fc25d38f7a0f08a..b42ed68acfa66767e73b063705e031dfd6883fdb 100644 (file)
@@ -461,12 +461,11 @@ err_generic:
        return ret;
 }
 
-static int pdc_intc_remove(struct platform_device *pdev)
+static void pdc_intc_remove(struct platform_device *pdev)
 {
        struct pdc_intc_priv *priv = platform_get_drvdata(pdev);
 
        irq_domain_remove(priv->domain);
-       return 0;
 }
 
 static const struct of_device_id pdc_intc_match[] = {
@@ -479,8 +478,8 @@ static struct platform_driver pdc_intc_driver = {
                .name           = "pdc-intc",
                .of_match_table = pdc_intc_match,
        },
-       .probe = pdc_intc_probe,
-       .remove = pdc_intc_remove,
+       .probe          = pdc_intc_probe,
+       .remove_new     = pdc_intc_remove,
 };
 
 static int __init pdc_intc_init(void)
index aa041e4dfee0916659358687e8e9cdf857828d0d..511adfaeec8227f018a07c1d8fb472c86323bf3c 100644 (file)
@@ -166,6 +166,10 @@ static int imx_intmux_irq_select(struct irq_domain *d, struct irq_fwspec *fwspec
        if (fwspec->fwnode != d->fwnode)
                return false;
 
+       /* Handle pure domain searches */
+       if (!fwspec->param_count)
+               return d->bus_token == bus_token;
+
        return irqchip_data->chanidx == fwspec->param[1];
 }
 
@@ -282,7 +286,7 @@ out:
        return ret;
 }
 
-static int imx_intmux_remove(struct platform_device *pdev)
+static void imx_intmux_remove(struct platform_device *pdev)
 {
        struct intmux_data *data = platform_get_drvdata(pdev);
        int i;
@@ -298,8 +302,6 @@ static int imx_intmux_remove(struct platform_device *pdev)
        }
 
        pm_runtime_disable(&pdev->dev);
-
-       return 0;
 }
 
 #ifdef CONFIG_PM
@@ -354,11 +356,11 @@ static const struct of_device_id imx_intmux_id[] = {
 
 static struct platform_driver imx_intmux_driver = {
        .driver = {
-               .name = "imx-intmux",
-               .of_match_table = imx_intmux_id,
-               .pm = &imx_intmux_pm_ops,
+               .name           = "imx-intmux",
+               .of_match_table = imx_intmux_id,
+               .pm             = &imx_intmux_pm_ops,
        },
-       .probe = imx_intmux_probe,
-       .remove = imx_intmux_remove,
+       .probe          = imx_intmux_probe,
+       .remove_new     = imx_intmux_remove,
 };
 builtin_platform_driver(imx_intmux_driver);
index bd9543314539925a3772f389631dc8681f82b956..20cf7a9e9ece26f1b0dfbc564ed2f0258e480d16 100644 (file)
@@ -231,7 +231,7 @@ out:
        return ret;
 }
 
-static int imx_irqsteer_remove(struct platform_device *pdev)
+static void imx_irqsteer_remove(struct platform_device *pdev)
 {
        struct irqsteer_data *irqsteer_data = platform_get_drvdata(pdev);
        int i;
@@ -243,8 +243,6 @@ static int imx_irqsteer_remove(struct platform_device *pdev)
        irq_domain_remove(irqsteer_data->domain);
 
        clk_disable_unprepare(irqsteer_data->ipg_clk);
-
-       return 0;
 }
 
 #ifdef CONFIG_PM
@@ -307,11 +305,11 @@ static const struct of_device_id imx_irqsteer_dt_ids[] = {
 
 static struct platform_driver imx_irqsteer_driver = {
        .driver = {
-               .name = "imx-irqsteer",
-               .of_match_table = imx_irqsteer_dt_ids,
-               .pm = &imx_irqsteer_pm_ops,
+               .name           = "imx-irqsteer",
+               .of_match_table = imx_irqsteer_dt_ids,
+               .pm             = &imx_irqsteer_pm_ops,
        },
-       .probe = imx_irqsteer_probe,
-       .remove = imx_irqsteer_remove,
+       .probe          = imx_irqsteer_probe,
+       .remove_new     = imx_irqsteer_remove,
 };
 builtin_platform_driver(imx_irqsteer_driver);
index a36396db4b081a6c3fdd3137afe9be4732bb8eb6..30f1979fa1240a3d8d7642fb60e34025d10bf138 100644 (file)
@@ -190,7 +190,7 @@ static int keystone_irq_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int keystone_irq_remove(struct platform_device *pdev)
+static void keystone_irq_remove(struct platform_device *pdev)
 {
        struct keystone_irq_device *kirq = platform_get_drvdata(pdev);
        int hwirq;
@@ -201,7 +201,6 @@ static int keystone_irq_remove(struct platform_device *pdev)
                irq_dispose_mapping(irq_find_mapping(kirq->irqd, hwirq));
 
        irq_domain_remove(kirq->irqd);
-       return 0;
 }
 
 static const struct of_device_id keystone_irq_dt_ids[] = {
@@ -212,7 +211,7 @@ MODULE_DEVICE_TABLE(of, keystone_irq_dt_ids);
 
 static struct platform_driver keystone_irq_device_driver = {
        .probe          = keystone_irq_probe,
-       .remove         = keystone_irq_remove,
+       .remove_new     = keystone_irq_remove,
        .driver         = {
                .name   = "keystone_irq",
                .of_match_table = of_match_ptr(keystone_irq_dt_ids),
index 1623cd77917523f42419cb958ecbc0ce32ba8809..b64cbe3052e84161aa36229a93e4cfc9fa731f17 100644 (file)
@@ -198,6 +198,12 @@ static void eiointc_irq_dispatch(struct irq_desc *desc)
 
        for (i = 0; i < eiointc_priv[0]->vec_count / VEC_COUNT_PER_REG; i++) {
                pending = iocsr_read64(EIOINTC_REG_ISR + (i << 3));
+
+               /* Skip handling if pending bitmap is zero */
+               if (!pending)
+                       continue;
+
+               /* Clear the IRQs */
                iocsr_write64(pending, EIOINTC_REG_ISR + (i << 3));
                while (pending) {
                        int bit = __ffs(pending);
@@ -241,7 +247,7 @@ static int eiointc_domain_alloc(struct irq_domain *domain, unsigned int virq,
        int ret;
        unsigned int i, type;
        unsigned long hwirq = 0;
-       struct eiointc *priv = domain->host_data;
+       struct eiointc_priv *priv = domain->host_data;
 
        ret = irq_domain_translate_onecell(domain, arg, &hwirq, &type);
        if (ret)
@@ -304,23 +310,7 @@ static int eiointc_suspend(void)
 
 static void eiointc_resume(void)
 {
-       int i, j;
-       struct irq_desc *desc;
-       struct irq_data *irq_data;
-
        eiointc_router_init(0);
-
-       for (i = 0; i < nr_pics; i++) {
-               for (j = 0; j < eiointc_priv[0]->vec_count; j++) {
-                       desc = irq_resolve_mapping(eiointc_priv[i]->eiointc_domain, j);
-                       if (desc && desc->handle_irq && desc->handle_irq != handle_bad_irq) {
-                               raw_spin_lock(&desc->lock);
-                               irq_data = irq_domain_get_irq_data(eiointc_priv[i]->eiointc_domain, irq_desc_get_irq(desc));
-                               eiointc_set_irq_affinity(irq_data, irq_data->common->affinity, 0);
-                               raw_spin_unlock(&desc->lock);
-                       }
-               }
-       }
 }
 
 static struct syscore_ops eiointc_syscore_ops = {
index 15cf80b463225c1a295e3d1c757d70e3fbfb17e5..1aef5c4d27c63130648093e24bdb8f89cda75aef 100644 (file)
@@ -398,7 +398,7 @@ static int ls_scfg_msi_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int ls_scfg_msi_remove(struct platform_device *pdev)
+static void ls_scfg_msi_remove(struct platform_device *pdev)
 {
        struct ls_scfg_msi *msi_data = platform_get_drvdata(pdev);
        int i;
@@ -410,17 +410,15 @@ static int ls_scfg_msi_remove(struct platform_device *pdev)
        irq_domain_remove(msi_data->parent);
 
        platform_set_drvdata(pdev, NULL);
-
-       return 0;
 }
 
 static struct platform_driver ls_scfg_msi_driver = {
        .driver = {
-               .name = "ls-scfg-msi",
-               .of_match_table = ls_scfg_msi_id,
+               .name           = "ls-scfg-msi",
+               .of_match_table = ls_scfg_msi_id,
        },
-       .probe = ls_scfg_msi_probe,
-       .remove = ls_scfg_msi_remove,
+       .probe          = ls_scfg_msi_probe,
+       .remove_new     = ls_scfg_msi_remove,
 };
 
 module_platform_driver(ls_scfg_msi_driver);
index 3eb1f8cdf674b03e90bbb489d1d765f7f6168b4d..acceb6e7fa95f5af6e1c76065a43701e225f7922 100644 (file)
@@ -222,7 +222,7 @@ static int madera_irq_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int madera_irq_remove(struct platform_device *pdev)
+static void madera_irq_remove(struct platform_device *pdev)
 {
        struct madera *madera = dev_get_drvdata(pdev->dev.parent);
 
@@ -232,13 +232,11 @@ static int madera_irq_remove(struct platform_device *pdev)
         */
        madera->irq_dev = NULL;
        regmap_del_irq_chip(madera->irq, madera->irq_data);
-
-       return 0;
 }
 
 static struct platform_driver madera_irq_driver = {
-       .probe  = &madera_irq_probe,
-       .remove = &madera_irq_remove,
+       .probe          = madera_irq_probe,
+       .remove_new     = madera_irq_remove,
        .driver = {
                .name   = "madera-irq",
                .pm     = &madera_irq_pm_ops,
index 5101a3fb11df5bef53122db9db3c194669d754e7..58881d3139792074bf6ae1430a4de3760d3eb220 100644 (file)
@@ -235,22 +235,17 @@ static const struct irq_domain_ops mbigen_domain_ops = {
 static int mbigen_of_create_domain(struct platform_device *pdev,
                                   struct mbigen_device *mgn_chip)
 {
-       struct device *parent;
        struct platform_device *child;
        struct irq_domain *domain;
        struct device_node *np;
        u32 num_pins;
        int ret = 0;
 
-       parent = bus_get_dev_root(&platform_bus_type);
-       if (!parent)
-               return -ENODEV;
-
        for_each_child_of_node(pdev->dev.of_node, np) {
                if (!of_property_read_bool(np, "interrupt-controller"))
                        continue;
 
-               child = of_platform_device_create(np, NULL, parent);
+               child = of_platform_device_create(np, NULL, NULL);
                if (!child) {
                        ret = -ENOMEM;
                        break;
@@ -273,7 +268,6 @@ static int mbigen_of_create_domain(struct platform_device *pdev,
                }
        }
 
-       put_device(parent);
        if (ret)
                of_node_put(np);
 
index f88df39f41291ecf4643c257fe4a20aed509c90f..9a1791908598d5d080aff474ae5d682c0f646ebc 100644 (file)
@@ -154,6 +154,10 @@ static const struct meson_gpio_irq_params c3_params = {
        INIT_MESON_S4_COMMON_DATA(55)
 };
 
+static const struct meson_gpio_irq_params t7_params = {
+       INIT_MESON_S4_COMMON_DATA(157)
+};
+
 static const struct of_device_id meson_irq_gpio_matches[] __maybe_unused = {
        { .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params },
        { .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params },
@@ -165,6 +169,7 @@ static const struct of_device_id meson_irq_gpio_matches[] __maybe_unused = {
        { .compatible = "amlogic,meson-a1-gpio-intc", .data = &a1_params },
        { .compatible = "amlogic,meson-s4-gpio-intc", .data = &s4_params },
        { .compatible = "amlogic,c3-gpio-intc", .data = &c3_params },
+       { .compatible = "amlogic,t7-gpio-intc", .data = &t7_params },
        { }
 };
 
index ef3d3646ccc2f62fd29cd05fc137da8bd8b0dafb..d17d9c0e2880926893b1101c731a20629100ef8f 100644 (file)
@@ -167,14 +167,12 @@ static int mvebu_pic_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int mvebu_pic_remove(struct platform_device *pdev)
+static void mvebu_pic_remove(struct platform_device *pdev)
 {
        struct mvebu_pic *pic = platform_get_drvdata(pdev);
 
        on_each_cpu(mvebu_pic_disable_percpu_irq, pic, 1);
        irq_domain_remove(pic->domain);
-
-       return 0;
 }
 
 static const struct of_device_id mvebu_pic_of_match[] = {
@@ -184,11 +182,11 @@ static const struct of_device_id mvebu_pic_of_match[] = {
 MODULE_DEVICE_TABLE(of, mvebu_pic_of_match);
 
 static struct platform_driver mvebu_pic_driver = {
-       .probe  = mvebu_pic_probe,
-       .remove = mvebu_pic_remove,
+       .probe          = mvebu_pic_probe,
+       .remove_new     = mvebu_pic_remove,
        .driver = {
-               .name = "mvebu-pic",
-               .of_match_table = mvebu_pic_of_match,
+               .name           = "mvebu-pic",
+               .of_match_table = mvebu_pic_of_match,
        },
 };
 module_platform_driver(mvebu_pic_driver);
index 0f64ecb9b1f4e929d7002057f67f3d57239efcb1..060eb000e9d359ec54d59f4a31ad6b7be44dd8c3 100644 (file)
@@ -599,7 +599,7 @@ fail_irq:
        return ret;
 }
 
-static int pruss_intc_remove(struct platform_device *pdev)
+static void pruss_intc_remove(struct platform_device *pdev)
 {
        struct pruss_intc *intc = platform_get_drvdata(pdev);
        u8 max_system_events = intc->soc_config->num_system_events;
@@ -616,8 +616,6 @@ static int pruss_intc_remove(struct platform_device *pdev)
                irq_dispose_mapping(irq_find_mapping(intc->domain, hwirq));
 
        irq_domain_remove(intc->domain);
-
-       return 0;
 }
 
 static const struct pruss_intc_match_data pruss_intc_data = {
@@ -645,12 +643,12 @@ MODULE_DEVICE_TABLE(of, pruss_intc_of_match);
 
 static struct platform_driver pruss_intc_driver = {
        .driver = {
-               .name = "pruss-intc",
-               .of_match_table = pruss_intc_of_match,
-               .suppress_bind_attrs = true,
+               .name                   = "pruss-intc",
+               .of_match_table         = pruss_intc_of_match,
+               .suppress_bind_attrs    = true,
        },
-       .probe  = pruss_intc_probe,
-       .remove = pruss_intc_remove,
+       .probe          = pruss_intc_probe,
+       .remove_new     = pruss_intc_remove,
 };
 module_platform_driver(pruss_intc_driver);
 
index cda5838d2232dc1971369b4c6e872d004263b8de..7942d8eb3d00eae5fa7e5718a05ef889bb8a82f0 100644 (file)
@@ -389,8 +389,8 @@ static int qcom_mpm_init(struct device_node *np, struct device_node *parent)
                /* Don't use devm_ioremap_resource, as we're accessing a shared region. */
                priv->base = devm_ioremap(dev, res.start, resource_size(&res));
                of_node_put(msgram_np);
-               if (IS_ERR(priv->base))
-                       return PTR_ERR(priv->base);
+               if (!priv->base)
+                       return -ENOMEM;
        } else {
                /* Otherwise, fall back to simple MMIO. */
                priv->base = devm_platform_ioremap_resource(pdev, 0);
index fa19585f3dee2b69f85727662974cf65ea0d2bf7..9ad37237ba9547d235a41bfd5ed2201a2b34c5e8 100644 (file)
@@ -561,14 +561,13 @@ err0:
        return ret;
 }
 
-static int intc_irqpin_remove(struct platform_device *pdev)
+static void intc_irqpin_remove(struct platform_device *pdev)
 {
        struct intc_irqpin_priv *p = platform_get_drvdata(pdev);
 
        irq_domain_remove(p->irq_domain);
        pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
-       return 0;
 }
 
 static int __maybe_unused intc_irqpin_suspend(struct device *dev)
@@ -585,11 +584,11 @@ static SIMPLE_DEV_PM_OPS(intc_irqpin_pm_ops, intc_irqpin_suspend, NULL);
 
 static struct platform_driver intc_irqpin_device_driver = {
        .probe          = intc_irqpin_probe,
-       .remove         = intc_irqpin_remove,
+       .remove_new     = intc_irqpin_remove,
        .driver         = {
-               .name   = "renesas_intc_irqpin",
-               .of_match_table = intc_irqpin_dt_ids,
-               .pm     = &intc_irqpin_pm_ops,
+               .name           = "renesas_intc_irqpin",
+               .of_match_table = intc_irqpin_dt_ids,
+               .pm             = &intc_irqpin_pm_ops,
        }
 };
 
index 49b446b396f98874566f59c9a75241d88dc779d1..76026e0b8e2010649889b0285463d0219dbf8b01 100644 (file)
@@ -218,14 +218,13 @@ err_runtime_pm_disable:
        return ret;
 }
 
-static int irqc_remove(struct platform_device *pdev)
+static void irqc_remove(struct platform_device *pdev)
 {
        struct irqc_priv *p = platform_get_drvdata(pdev);
 
        irq_domain_remove(p->irq_domain);
        pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
-       return 0;
 }
 
 static int __maybe_unused irqc_suspend(struct device *dev)
@@ -248,11 +247,11 @@ MODULE_DEVICE_TABLE(of, irqc_dt_ids);
 
 static struct platform_driver irqc_device_driver = {
        .probe          = irqc_probe,
-       .remove         = irqc_remove,
+       .remove_new     = irqc_remove,
        .driver         = {
-               .name   = "renesas_irqc",
+               .name           = "renesas_irqc",
                .of_match_table = irqc_dt_ids,
-               .pm     = &irqc_pm_ops,
+               .pm             = &irqc_pm_ops,
        }
 };
 
index e4c99c2e0373bf8a5ff68228ccb78c3e06cef3ab..f05afe82db4d1ddd1a4ec0f2de251fd5878b0651 100644 (file)
@@ -244,12 +244,11 @@ out_put_node:
        return ret;
 }
 
-static int rza1_irqc_remove(struct platform_device *pdev)
+static void rza1_irqc_remove(struct platform_device *pdev)
 {
        struct rza1_irqc_priv *priv = platform_get_drvdata(pdev);
 
        irq_domain_remove(priv->irq_domain);
-       return 0;
 }
 
 static const struct of_device_id rza1_irqc_dt_ids[] = {
@@ -260,9 +259,9 @@ MODULE_DEVICE_TABLE(of, rza1_irqc_dt_ids);
 
 static struct platform_driver rza1_irqc_device_driver = {
        .probe          = rza1_irqc_probe,
-       .remove         = rza1_irqc_remove,
+       .remove_new     = rza1_irqc_remove,
        .driver         = {
-               .name   = "renesas_rza1_irqc",
+               .name           = "renesas_rza1_irqc",
                .of_match_table = rza1_irqc_dt_ids,
        }
 };
index e8d01b14ccdde7848c7fb14489a5a015b86e8e95..f87aeab460eb8bb5419e3c74fdbc8f3034665a2b 100644 (file)
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/smp.h>
+#include <linux/soc/andes/irq.h>
+
+#include <asm/hwcap.h>
 
 static struct irq_domain *intc_domain;
+static unsigned int riscv_intc_nr_irqs __ro_after_init = BITS_PER_LONG;
+static unsigned int riscv_intc_custom_base __ro_after_init = BITS_PER_LONG;
+static unsigned int riscv_intc_custom_nr_irqs __ro_after_init;
 
 static asmlinkage void riscv_intc_irq(struct pt_regs *regs)
 {
        unsigned long cause = regs->cause & ~CAUSE_IRQ_FLAG;
 
-       if (unlikely(cause >= BITS_PER_LONG))
-               panic("unexpected interrupt cause");
+       if (generic_handle_domain_irq(intc_domain, cause))
+               pr_warn_ratelimited("Failed to handle interrupt (cause: %ld)\n", cause);
+}
+
+static asmlinkage void riscv_intc_aia_irq(struct pt_regs *regs)
+{
+       unsigned long topi;
 
-       generic_handle_domain_irq(intc_domain, cause);
+       while ((topi = csr_read(CSR_TOPI)))
+               generic_handle_domain_irq(intc_domain, topi >> TOPI_IID_SHIFT);
 }
 
 /*
@@ -39,12 +51,43 @@ static asmlinkage void riscv_intc_irq(struct pt_regs *regs)
 
 static void riscv_intc_irq_mask(struct irq_data *d)
 {
-       csr_clear(CSR_IE, BIT(d->hwirq));
+       if (IS_ENABLED(CONFIG_32BIT) && d->hwirq >= BITS_PER_LONG)
+               csr_clear(CSR_IEH, BIT(d->hwirq - BITS_PER_LONG));
+       else
+               csr_clear(CSR_IE, BIT(d->hwirq));
 }
 
 static void riscv_intc_irq_unmask(struct irq_data *d)
 {
-       csr_set(CSR_IE, BIT(d->hwirq));
+       if (IS_ENABLED(CONFIG_32BIT) && d->hwirq >= BITS_PER_LONG)
+               csr_set(CSR_IEH, BIT(d->hwirq - BITS_PER_LONG));
+       else
+               csr_set(CSR_IE, BIT(d->hwirq));
+}
+
+static void andes_intc_irq_mask(struct irq_data *d)
+{
+       /*
+        * Andes specific S-mode local interrupt causes (hwirq)
+        * are defined as (256 + n) and controlled by n-th bit
+        * of SLIE.
+        */
+       unsigned int mask = BIT(d->hwirq % BITS_PER_LONG);
+
+       if (d->hwirq < ANDES_SLI_CAUSE_BASE)
+               csr_clear(CSR_IE, mask);
+       else
+               csr_clear(ANDES_CSR_SLIE, mask);
+}
+
+static void andes_intc_irq_unmask(struct irq_data *d)
+{
+       unsigned int mask = BIT(d->hwirq % BITS_PER_LONG);
+
+       if (d->hwirq < ANDES_SLI_CAUSE_BASE)
+               csr_set(CSR_IE, mask);
+       else
+               csr_set(ANDES_CSR_SLIE, mask);
 }
 
 static void riscv_intc_irq_eoi(struct irq_data *d)
@@ -70,12 +113,21 @@ static struct irq_chip riscv_intc_chip = {
        .irq_eoi = riscv_intc_irq_eoi,
 };
 
+static struct irq_chip andes_intc_chip = {
+       .name           = "RISC-V INTC",
+       .irq_mask       = andes_intc_irq_mask,
+       .irq_unmask     = andes_intc_irq_unmask,
+       .irq_eoi        = riscv_intc_irq_eoi,
+};
+
 static int riscv_intc_domain_map(struct irq_domain *d, unsigned int irq,
                                 irq_hw_number_t hwirq)
 {
+       struct irq_chip *chip = d->host_data;
+
        irq_set_percpu_devid(irq);
-       irq_domain_set_info(d, irq, hwirq, &riscv_intc_chip, d->host_data,
-                           handle_percpu_devid_irq, NULL, NULL);
+       irq_domain_set_info(d, irq, hwirq, chip, NULL, handle_percpu_devid_irq,
+                           NULL, NULL);
 
        return 0;
 }
@@ -93,6 +145,14 @@ static int riscv_intc_domain_alloc(struct irq_domain *domain,
        if (ret)
                return ret;
 
+       /*
+        * Only allow hwirq for which we have corresponding standard or
+        * custom interrupt enable register.
+        */
+       if ((hwirq >= riscv_intc_nr_irqs && hwirq < riscv_intc_custom_base) ||
+           (hwirq >= riscv_intc_custom_base + riscv_intc_custom_nr_irqs))
+               return -EINVAL;
+
        for (i = 0; i < nr_irqs; i++) {
                ret = riscv_intc_domain_map(domain, virq + i, hwirq + i);
                if (ret)
@@ -113,18 +173,20 @@ static struct fwnode_handle *riscv_intc_hwnode(void)
        return intc_domain->fwnode;
 }
 
-static int __init riscv_intc_init_common(struct fwnode_handle *fn)
+static int __init riscv_intc_init_common(struct fwnode_handle *fn, struct irq_chip *chip)
 {
        int rc;
 
-       intc_domain = irq_domain_create_linear(fn, BITS_PER_LONG,
-                                              &riscv_intc_domain_ops, NULL);
+       intc_domain = irq_domain_create_tree(fn, &riscv_intc_domain_ops, chip);
        if (!intc_domain) {
                pr_err("unable to add IRQ domain\n");
                return -ENXIO;
        }
 
-       rc = set_handle_irq(&riscv_intc_irq);
+       if (riscv_isa_extension_available(NULL, SxAIA))
+               rc = set_handle_irq(&riscv_intc_aia_irq);
+       else
+               rc = set_handle_irq(&riscv_intc_irq);
        if (rc) {
                pr_err("failed to set irq handler\n");
                return rc;
@@ -132,7 +194,11 @@ static int __init riscv_intc_init_common(struct fwnode_handle *fn)
 
        riscv_set_intc_hwnode_fn(riscv_intc_hwnode);
 
-       pr_info("%d local interrupts mapped\n", BITS_PER_LONG);
+       pr_info("%d local interrupts mapped%s\n",
+               riscv_isa_extension_available(NULL, SxAIA) ? 64 : riscv_intc_nr_irqs,
+               riscv_isa_extension_available(NULL, SxAIA) ? " using AIA" : "");
+       if (riscv_intc_custom_nr_irqs)
+               pr_info("%d custom local interrupts mapped\n", riscv_intc_custom_nr_irqs);
 
        return 0;
 }
@@ -140,8 +206,9 @@ static int __init riscv_intc_init_common(struct fwnode_handle *fn)
 static int __init riscv_intc_init(struct device_node *node,
                                  struct device_node *parent)
 {
-       int rc;
+       struct irq_chip *chip = &riscv_intc_chip;
        unsigned long hartid;
+       int rc;
 
        rc = riscv_of_parent_hartid(node, &hartid);
        if (rc < 0) {
@@ -166,10 +233,17 @@ static int __init riscv_intc_init(struct device_node *node,
                return 0;
        }
 
-       return riscv_intc_init_common(of_node_to_fwnode(node));
+       if (of_device_is_compatible(node, "andestech,cpu-intc")) {
+               riscv_intc_custom_base = ANDES_SLI_CAUSE_BASE;
+               riscv_intc_custom_nr_irqs = ANDES_RV_IRQ_LAST;
+               chip = &andes_intc_chip;
+       }
+
+       return riscv_intc_init_common(of_node_to_fwnode(node), chip);
 }
 
 IRQCHIP_DECLARE(riscv, "riscv,cpu-intc", riscv_intc_init);
+IRQCHIP_DECLARE(andes, "andestech,cpu-intc", riscv_intc_init);
 
 #ifdef CONFIG_ACPI
 
@@ -196,7 +270,7 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
                return -ENOMEM;
        }
 
-       return riscv_intc_init_common(fn);
+       return riscv_intc_init_common(fn, &riscv_intc_chip);
 }
 
 IRQCHIP_ACPI_DECLARE(riscv_intc, ACPI_MADT_TYPE_RINTC, NULL,
index 5b7bc4fd9517c8972680ad7a503eebf2ca47a518..f3d4cb9e34f7d8b824ad4fbb8e2e9b10b71232d2 100644 (file)
@@ -3,7 +3,6 @@
  * Copyright (C) 2017 SiFive
  * Copyright (C) 2018 Christoph Hellwig
  */
-#define pr_fmt(fmt) "plic: " fmt
 #include <linux/cpu.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -64,6 +63,7 @@
 #define PLIC_QUIRK_EDGE_INTERRUPT      0
 
 struct plic_priv {
+       struct device *dev;
        struct cpumask lmask;
        struct irq_domain *irqdomain;
        void __iomem *regs;
@@ -103,9 +103,11 @@ static void __plic_toggle(void __iomem *enable_base, int hwirq, int enable)
 
 static void plic_toggle(struct plic_handler *handler, int hwirq, int enable)
 {
-       raw_spin_lock(&handler->enable_lock);
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&handler->enable_lock, flags);
        __plic_toggle(handler->enable_base, hwirq, enable);
-       raw_spin_unlock(&handler->enable_lock);
+       raw_spin_unlock_irqrestore(&handler->enable_lock, flags);
 }
 
 static inline void plic_irq_toggle(const struct cpumask *mask,
@@ -148,7 +150,13 @@ static void plic_irq_eoi(struct irq_data *d)
 {
        struct plic_handler *handler = this_cpu_ptr(&plic_handlers);
 
-       writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
+       if (unlikely(irqd_irq_disabled(d))) {
+               plic_toggle(handler, d->hwirq, 1);
+               writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
+               plic_toggle(handler, d->hwirq, 0);
+       } else {
+               writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
+       }
 }
 
 #ifdef CONFIG_SMP
@@ -236,6 +244,7 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type)
 static int plic_irq_suspend(void)
 {
        unsigned int i, cpu;
+       unsigned long flags;
        u32 __iomem *reg;
        struct plic_priv *priv;
 
@@ -253,12 +262,12 @@ static int plic_irq_suspend(void)
                if (!handler->present)
                        continue;
 
-               raw_spin_lock(&handler->enable_lock);
+               raw_spin_lock_irqsave(&handler->enable_lock, flags);
                for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) {
                        reg = handler->enable_base + i * sizeof(u32);
                        handler->enable_save[i] = readl(reg);
                }
-               raw_spin_unlock(&handler->enable_lock);
+               raw_spin_unlock_irqrestore(&handler->enable_lock, flags);
        }
 
        return 0;
@@ -267,6 +276,7 @@ static int plic_irq_suspend(void)
 static void plic_irq_resume(void)
 {
        unsigned int i, index, cpu;
+       unsigned long flags;
        u32 __iomem *reg;
        struct plic_priv *priv;
 
@@ -284,12 +294,12 @@ static void plic_irq_resume(void)
                if (!handler->present)
                        continue;
 
-               raw_spin_lock(&handler->enable_lock);
+               raw_spin_lock_irqsave(&handler->enable_lock, flags);
                for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) {
                        reg = handler->enable_base + i * sizeof(u32);
                        writel(handler->enable_save[i], reg);
                }
-               raw_spin_unlock(&handler->enable_lock);
+               raw_spin_unlock_irqrestore(&handler->enable_lock, flags);
        }
 }
 
@@ -370,9 +380,10 @@ static void plic_handle_irq(struct irq_desc *desc)
        while ((hwirq = readl(claim))) {
                int err = generic_handle_domain_irq(handler->priv->irqdomain,
                                                    hwirq);
-               if (unlikely(err))
-                       pr_warn_ratelimited("can't find mapping for hwirq %lu\n",
-                                       hwirq);
+               if (unlikely(err)) {
+                       dev_warn_ratelimited(handler->priv->dev,
+                                            "can't find mapping for hwirq %lu\n", hwirq);
+               }
        }
 
        chained_irq_exit(chip, desc);
@@ -400,63 +411,122 @@ static int plic_starting_cpu(unsigned int cpu)
                enable_percpu_irq(plic_parent_irq,
                                  irq_get_trigger_type(plic_parent_irq));
        else
-               pr_warn("cpu%d: parent irq not available\n", cpu);
+               dev_warn(handler->priv->dev, "cpu%d: parent irq not available\n", cpu);
        plic_set_threshold(handler, PLIC_ENABLE_THRESHOLD);
 
        return 0;
 }
 
-static int __init __plic_init(struct device_node *node,
-                             struct device_node *parent,
-                             unsigned long plic_quirks)
+static const struct of_device_id plic_match[] = {
+       { .compatible = "sifive,plic-1.0.0" },
+       { .compatible = "riscv,plic0" },
+       { .compatible = "andestech,nceplic100",
+         .data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) },
+       { .compatible = "thead,c900-plic",
+         .data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) },
+       {}
+};
+
+static int plic_parse_nr_irqs_and_contexts(struct platform_device *pdev,
+                                          u32 *nr_irqs, u32 *nr_contexts)
 {
-       int error = 0, nr_contexts, nr_handlers = 0, i;
-       u32 nr_irqs;
-       struct plic_priv *priv;
-       struct plic_handler *handler;
-       unsigned int cpu;
+       struct device *dev = &pdev->dev;
+       int rc;
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
+       /*
+        * Currently, only OF fwnode is supported so extend this
+        * function for ACPI support.
+        */
+       if (!is_of_node(dev->fwnode))
+               return -EINVAL;
 
-       priv->plic_quirks = plic_quirks;
+       rc = of_property_read_u32(to_of_node(dev->fwnode), "riscv,ndev", nr_irqs);
+       if (rc) {
+               dev_err(dev, "riscv,ndev property not available\n");
+               return rc;
+       }
 
-       priv->regs = of_iomap(node, 0);
-       if (WARN_ON(!priv->regs)) {
-               error = -EIO;
-               goto out_free_priv;
+       *nr_contexts = of_irq_count(to_of_node(dev->fwnode));
+       if (WARN_ON(!(*nr_contexts))) {
+               dev_err(dev, "no PLIC context available\n");
+               return -EINVAL;
        }
 
-       error = -EINVAL;
-       of_property_read_u32(node, "riscv,ndev", &nr_irqs);
-       if (WARN_ON(!nr_irqs))
-               goto out_iounmap;
+       return 0;
+}
 
-       priv->nr_irqs = nr_irqs;
+static int plic_parse_context_parent(struct platform_device *pdev, u32 context,
+                                    u32 *parent_hwirq, int *parent_cpu)
+{
+       struct device *dev = &pdev->dev;
+       struct of_phandle_args parent;
+       unsigned long hartid;
+       int rc;
 
-       priv->prio_save = bitmap_alloc(nr_irqs, GFP_KERNEL);
-       if (!priv->prio_save)
-               goto out_free_priority_reg;
+       /*
+        * Currently, only OF fwnode is supported so extend this
+        * function for ACPI support.
+        */
+       if (!is_of_node(dev->fwnode))
+               return -EINVAL;
 
-       nr_contexts = of_irq_count(node);
-       if (WARN_ON(!nr_contexts))
-               goto out_free_priority_reg;
+       rc = of_irq_parse_one(to_of_node(dev->fwnode), context, &parent);
+       if (rc)
+               return rc;
 
-       error = -ENOMEM;
-       priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1,
-                       &plic_irqdomain_ops, priv);
-       if (WARN_ON(!priv->irqdomain))
-               goto out_free_priority_reg;
+       rc = riscv_of_parent_hartid(parent.np, &hartid);
+       if (rc)
+               return rc;
 
-       for (i = 0; i < nr_contexts; i++) {
-               struct of_phandle_args parent;
-               irq_hw_number_t hwirq;
-               int cpu;
-               unsigned long hartid;
+       *parent_hwirq = parent.args[0];
+       *parent_cpu = riscv_hartid_to_cpuid(hartid);
+       return 0;
+}
+
+static int plic_probe(struct platform_device *pdev)
+{
+       int error = 0, nr_contexts, nr_handlers = 0, cpu, i;
+       struct device *dev = &pdev->dev;
+       unsigned long plic_quirks = 0;
+       struct plic_handler *handler;
+       u32 nr_irqs, parent_hwirq;
+       struct irq_domain *domain;
+       struct plic_priv *priv;
+       irq_hw_number_t hwirq;
+       bool cpuhp_setup;
 
-               if (of_irq_parse_one(node, i, &parent)) {
-                       pr_err("failed to parse parent for context %d.\n", i);
+       if (is_of_node(dev->fwnode)) {
+               const struct of_device_id *id;
+
+               id = of_match_node(plic_match, to_of_node(dev->fwnode));
+               if (id)
+                       plic_quirks = (unsigned long)id->data;
+       }
+
+       error = plic_parse_nr_irqs_and_contexts(pdev, &nr_irqs, &nr_contexts);
+       if (error)
+               return error;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->dev = dev;
+       priv->plic_quirks = plic_quirks;
+       priv->nr_irqs = nr_irqs;
+
+       priv->regs = devm_platform_ioremap_resource(pdev, 0);
+       if (WARN_ON(!priv->regs))
+               return -EIO;
+
+       priv->prio_save = devm_bitmap_zalloc(dev, nr_irqs, GFP_KERNEL);
+       if (!priv->prio_save)
+               return -ENOMEM;
+
+       for (i = 0; i < nr_contexts; i++) {
+               error = plic_parse_context_parent(pdev, i, &parent_hwirq, &cpu);
+               if (error) {
+                       dev_warn(dev, "hwirq for context%d not found\n", i);
                        continue;
                }
 
@@ -464,7 +534,7 @@ static int __init __plic_init(struct device_node *node,
                 * Skip contexts other than external interrupts for our
                 * privilege level.
                 */
-               if (parent.args[0] != RV_IRQ_EXT) {
+               if (parent_hwirq != RV_IRQ_EXT) {
                        /* Disable S-mode enable bits if running in M-mode. */
                        if (IS_ENABLED(CONFIG_RISCV_M_MODE)) {
                                void __iomem *enable_base = priv->regs +
@@ -477,24 +547,17 @@ static int __init __plic_init(struct device_node *node,
                        continue;
                }
 
-               error = riscv_of_parent_hartid(parent.np, &hartid);
-               if (error < 0) {
-                       pr_warn("failed to parse hart ID for context %d.\n", i);
-                       continue;
-               }
-
-               cpu = riscv_hartid_to_cpuid(hartid);
                if (cpu < 0) {
-                       pr_warn("Invalid cpuid for context %d\n", i);
+                       dev_warn(dev, "Invalid cpuid for context %d\n", i);
                        continue;
                }
 
                /* Find parent domain and register chained handler */
-               if (!plic_parent_irq && irq_find_host(parent.np)) {
-                       plic_parent_irq = irq_of_parse_and_map(node, i);
+               domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY);
+               if (!plic_parent_irq && domain) {
+                       plic_parent_irq = irq_create_mapping(domain, RV_IRQ_EXT);
                        if (plic_parent_irq)
-                               irq_set_chained_handler(plic_parent_irq,
-                                                       plic_handle_irq);
+                               irq_set_chained_handler(plic_parent_irq, plic_handle_irq);
                }
 
                /*
@@ -504,7 +567,7 @@ static int __init __plic_init(struct device_node *node,
                 */
                handler = per_cpu_ptr(&plic_handlers, cpu);
                if (handler->present) {
-                       pr_warn("handler already present for context %d.\n", i);
+                       dev_warn(dev, "handler already present for context %d.\n", i);
                        plic_set_threshold(handler, PLIC_DISABLE_THRESHOLD);
                        goto done;
                }
@@ -518,10 +581,10 @@ static int __init __plic_init(struct device_node *node,
                        i * CONTEXT_ENABLE_SIZE;
                handler->priv = priv;
 
-               handler->enable_save =  kcalloc(DIV_ROUND_UP(nr_irqs, 32),
-                                               sizeof(*handler->enable_save), GFP_KERNEL);
+               handler->enable_save = devm_kcalloc(dev, DIV_ROUND_UP(nr_irqs, 32),
+                                                   sizeof(*handler->enable_save), GFP_KERNEL);
                if (!handler->enable_save)
-                       goto out_free_enable_reg;
+                       goto fail_cleanup_contexts;
 done:
                for (hwirq = 1; hwirq <= nr_irqs; hwirq++) {
                        plic_toggle(handler, hwirq, 0);
@@ -531,52 +594,60 @@ done:
                nr_handlers++;
        }
 
+       priv->irqdomain = irq_domain_add_linear(to_of_node(dev->fwnode), nr_irqs + 1,
+                                               &plic_irqdomain_ops, priv);
+       if (WARN_ON(!priv->irqdomain))
+               goto fail_cleanup_contexts;
+
        /*
         * We can have multiple PLIC instances so setup cpuhp state
-        * and register syscore operations only when context handler
-        * for current/boot CPU is present.
+        * and register syscore operations only once after context
+        * handlers of all online CPUs are initialized.
         */
-       handler = this_cpu_ptr(&plic_handlers);
-       if (handler->present && !plic_cpuhp_setup_done) {
-               cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
-                                 "irqchip/sifive/plic:starting",
-                                 plic_starting_cpu, plic_dying_cpu);
-               register_syscore_ops(&plic_irq_syscore_ops);
-               plic_cpuhp_setup_done = true;
+       if (!plic_cpuhp_setup_done) {
+               cpuhp_setup = true;
+               for_each_online_cpu(cpu) {
+                       handler = per_cpu_ptr(&plic_handlers, cpu);
+                       if (!handler->present) {
+                               cpuhp_setup = false;
+                               break;
+                       }
+               }
+               if (cpuhp_setup) {
+                       cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
+                                         "irqchip/sifive/plic:starting",
+                                         plic_starting_cpu, plic_dying_cpu);
+                       register_syscore_ops(&plic_irq_syscore_ops);
+                       plic_cpuhp_setup_done = true;
+               }
        }
 
-       pr_info("%pOFP: mapped %d interrupts with %d handlers for"
-               " %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts);
+       dev_info(dev, "mapped %d interrupts with %d handlers for %d contexts.\n",
+                nr_irqs, nr_handlers, nr_contexts);
        return 0;
 
-out_free_enable_reg:
-       for_each_cpu(cpu, cpu_present_mask) {
+fail_cleanup_contexts:
+       for (i = 0; i < nr_contexts; i++) {
+               if (plic_parse_context_parent(pdev, i, &parent_hwirq, &cpu))
+                       continue;
+               if (parent_hwirq != RV_IRQ_EXT || cpu < 0)
+                       continue;
+
                handler = per_cpu_ptr(&plic_handlers, cpu);
-               kfree(handler->enable_save);
+               handler->present = false;
+               handler->hart_base = NULL;
+               handler->enable_base = NULL;
+               handler->enable_save = NULL;
+               handler->priv = NULL;
        }
-out_free_priority_reg:
-       kfree(priv->prio_save);
-out_iounmap:
-       iounmap(priv->regs);
-out_free_priv:
-       kfree(priv);
-       return error;
+       return -ENOMEM;
 }
 
-static int __init plic_init(struct device_node *node,
-                           struct device_node *parent)
-{
-       return __plic_init(node, parent, 0);
-}
-
-IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init);
-IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */
-
-static int __init plic_edge_init(struct device_node *node,
-                                struct device_node *parent)
-{
-       return __plic_init(node, parent, BIT(PLIC_QUIRK_EDGE_INTERRUPT));
-}
-
-IRQCHIP_DECLARE(andestech_nceplic100, "andestech,nceplic100", plic_edge_init);
-IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_edge_init);
+static struct platform_driver plic_driver = {
+       .driver = {
+               .name           = "riscv-plic",
+               .of_match_table = plic_match,
+       },
+       .probe = plic_probe,
+};
+builtin_platform_driver(plic_driver);
diff --git a/drivers/irqchip/irq-starfive-jh8100-intc.c b/drivers/irqchip/irq-starfive-jh8100-intc.c
new file mode 100644 (file)
index 0000000..0f58371
--- /dev/null
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * StarFive JH8100 External Interrupt Controller driver
+ *
+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
+ *
+ * Author: Changhuang Liang <changhuang.liang@starfivetech.com>
+ */
+
+#define pr_fmt(fmt) "irq-starfive-jh8100: " fmt
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+
+#define STARFIVE_INTC_SRC0_CLEAR       0x10
+#define STARFIVE_INTC_SRC0_MASK                0x14
+#define STARFIVE_INTC_SRC0_INT         0x1c
+
+#define STARFIVE_INTC_SRC_IRQ_NUM      32
+
+struct starfive_irq_chip {
+       void __iomem            *base;
+       struct irq_domain       *domain;
+       raw_spinlock_t          lock;
+};
+
+static void starfive_intc_bit_set(struct starfive_irq_chip *irqc,
+                                 u32 reg, u32 bit_mask)
+{
+       u32 value;
+
+       value = ioread32(irqc->base + reg);
+       value |= bit_mask;
+       iowrite32(value, irqc->base + reg);
+}
+
+static void starfive_intc_bit_clear(struct starfive_irq_chip *irqc,
+                                   u32 reg, u32 bit_mask)
+{
+       u32 value;
+
+       value = ioread32(irqc->base + reg);
+       value &= ~bit_mask;
+       iowrite32(value, irqc->base + reg);
+}
+
+static void starfive_intc_unmask(struct irq_data *d)
+{
+       struct starfive_irq_chip *irqc = irq_data_get_irq_chip_data(d);
+
+       raw_spin_lock(&irqc->lock);
+       starfive_intc_bit_clear(irqc, STARFIVE_INTC_SRC0_MASK, BIT(d->hwirq));
+       raw_spin_unlock(&irqc->lock);
+}
+
+static void starfive_intc_mask(struct irq_data *d)
+{
+       struct starfive_irq_chip *irqc = irq_data_get_irq_chip_data(d);
+
+       raw_spin_lock(&irqc->lock);
+       starfive_intc_bit_set(irqc, STARFIVE_INTC_SRC0_MASK, BIT(d->hwirq));
+       raw_spin_unlock(&irqc->lock);
+}
+
+static struct irq_chip intc_dev = {
+       .name           = "StarFive JH8100 INTC",
+       .irq_unmask     = starfive_intc_unmask,
+       .irq_mask       = starfive_intc_mask,
+};
+
+static int starfive_intc_map(struct irq_domain *d, unsigned int irq,
+                            irq_hw_number_t hwirq)
+{
+       irq_domain_set_info(d, irq, hwirq, &intc_dev, d->host_data,
+                           handle_level_irq, NULL, NULL);
+
+       return 0;
+}
+
+static const struct irq_domain_ops starfive_intc_domain_ops = {
+       .xlate  = irq_domain_xlate_onecell,
+       .map    = starfive_intc_map,
+};
+
+static void starfive_intc_irq_handler(struct irq_desc *desc)
+{
+       struct starfive_irq_chip *irqc = irq_data_get_irq_handler_data(&desc->irq_data);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       unsigned long value;
+       int hwirq;
+
+       chained_irq_enter(chip, desc);
+
+       value = ioread32(irqc->base + STARFIVE_INTC_SRC0_INT);
+       while (value) {
+               hwirq = ffs(value) - 1;
+
+               generic_handle_domain_irq(irqc->domain, hwirq);
+
+               starfive_intc_bit_set(irqc, STARFIVE_INTC_SRC0_CLEAR, BIT(hwirq));
+               starfive_intc_bit_clear(irqc, STARFIVE_INTC_SRC0_CLEAR, BIT(hwirq));
+
+               __clear_bit(hwirq, &value);
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static int __init starfive_intc_init(struct device_node *intc,
+                                    struct device_node *parent)
+{
+       struct starfive_irq_chip *irqc;
+       struct reset_control *rst;
+       struct clk *clk;
+       int parent_irq;
+       int ret;
+
+       irqc = kzalloc(sizeof(*irqc), GFP_KERNEL);
+       if (!irqc)
+               return -ENOMEM;
+
+       irqc->base = of_iomap(intc, 0);
+       if (!irqc->base) {
+               pr_err("Unable to map registers\n");
+               ret = -ENXIO;
+               goto err_free;
+       }
+
+       rst = of_reset_control_get_exclusive(intc, NULL);
+       if (IS_ERR(rst)) {
+               pr_err("Unable to get reset control %pe\n", rst);
+               ret = PTR_ERR(rst);
+               goto err_unmap;
+       }
+
+       clk = of_clk_get(intc, 0);
+       if (IS_ERR(clk)) {
+               pr_err("Unable to get clock %pe\n", clk);
+               ret = PTR_ERR(clk);
+               goto err_reset_put;
+       }
+
+       ret = reset_control_deassert(rst);
+       if (ret)
+               goto err_clk_put;
+
+       ret = clk_prepare_enable(clk);
+       if (ret)
+               goto err_reset_assert;
+
+       raw_spin_lock_init(&irqc->lock);
+
+       irqc->domain = irq_domain_add_linear(intc, STARFIVE_INTC_SRC_IRQ_NUM,
+                                            &starfive_intc_domain_ops, irqc);
+       if (!irqc->domain) {
+               pr_err("Unable to create IRQ domain\n");
+               ret = -EINVAL;
+               goto err_clk_disable;
+       }
+
+       parent_irq = of_irq_get(intc, 0);
+       if (parent_irq < 0) {
+               pr_err("Failed to get main IRQ: %d\n", parent_irq);
+               ret = parent_irq;
+               goto err_remove_domain;
+       }
+
+       irq_set_chained_handler_and_data(parent_irq, starfive_intc_irq_handler,
+                                        irqc);
+
+       pr_info("Interrupt controller register, nr_irqs %d\n",
+               STARFIVE_INTC_SRC_IRQ_NUM);
+
+       return 0;
+
+err_remove_domain:
+       irq_domain_remove(irqc->domain);
+err_clk_disable:
+       clk_disable_unprepare(clk);
+err_reset_assert:
+       reset_control_assert(rst);
+err_clk_put:
+       clk_put(clk);
+err_reset_put:
+       reset_control_put(rst);
+err_unmap:
+       iounmap(irqc->base);
+err_free:
+       kfree(irqc);
+       return ret;
+}
+
+IRQCHIP_PLATFORM_DRIVER_BEGIN(starfive_intc)
+IRQCHIP_MATCH("starfive,jh8100-intc", starfive_intc_init)
+IRQCHIP_PLATFORM_DRIVER_END(starfive_intc)
+
+MODULE_DESCRIPTION("StarFive JH8100 External Interrupt Controller");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Changhuang Liang <changhuang.liang@starfivetech.com>");
index 971240e2e31b48ef284d06f406eb62e41ff7cc53..26a5193d0ae412006df5b4a790626ae4ff581992 100644 (file)
@@ -898,10 +898,9 @@ static void stm32_exti_remove_irq(void *data)
        irq_domain_remove(domain);
 }
 
-static int stm32_exti_remove(struct platform_device *pdev)
+static void stm32_exti_remove(struct platform_device *pdev)
 {
        stm32_exti_h_syscore_deinit();
-       return 0;
 }
 
 static int stm32_exti_probe(struct platform_device *pdev)
@@ -991,10 +990,10 @@ MODULE_DEVICE_TABLE(of, stm32_exti_ids);
 
 static struct platform_driver stm32_exti_driver = {
        .probe          = stm32_exti_probe,
-       .remove         = stm32_exti_remove,
+       .remove_new     = stm32_exti_remove,
        .driver         = {
-               .name   = "stm32_exti",
-               .of_match_table = stm32_exti_ids,
+               .name           = "stm32_exti",
+               .of_match_table = stm32_exti_ids,
        },
 };
 
index b2d61d4f6fe6f063bf05891cce0310318f9d0736..57f610dab6b804341f6d2abf250b3798bc84d2c6 100644 (file)
@@ -139,13 +139,11 @@ static int ts4800_ic_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int ts4800_ic_remove(struct platform_device *pdev)
+static void ts4800_ic_remove(struct platform_device *pdev)
 {
        struct ts4800_irq_data *data = platform_get_drvdata(pdev);
 
        irq_domain_remove(data->domain);
-
-       return 0;
 }
 
 static const struct of_device_id ts4800_ic_of_match[] = {
@@ -155,11 +153,11 @@ static const struct of_device_id ts4800_ic_of_match[] = {
 MODULE_DEVICE_TABLE(of, ts4800_ic_of_match);
 
 static struct platform_driver ts4800_ic_driver = {
-       .probe  = ts4800_ic_probe,
-       .remove = ts4800_ic_remove,
+       .probe          = ts4800_ic_probe,
+       .remove_new     = ts4800_ic_remove,
        .driver = {
-               .name = "ts4800-irqc",
-               .of_match_table = ts4800_ic_of_match,
+               .name           = "ts4800-irqc",
+               .of_match_table = ts4800_ic_of_match,
        },
 };
 module_platform_driver(ts4800_ic_driver);
index 9e3d5561e04eae159ecf3a34108fcac7486999a4..ea93e7236c4ac9378a39343c9808ac3bd0e6e99d 100644 (file)
@@ -47,9 +47,8 @@
 
 /**
  * struct vic_device - VIC PM device
- * @parent_irq: The parent IRQ number of the VIC if cascaded, or 0.
- * @irq: The IRQ number for the base of the VIC.
  * @base: The register base for the VIC.
+ * @irq: The IRQ number for the base of the VIC.
  * @valid_sources: A bitmask of valid interrupts
  * @resume_sources: A bitmask of interrupts for resume.
  * @resume_irqs: The IRQs enabled for resume.
index e3e28a4f7d017cc12751c3eb331f0046c8df93ec..b1abc2a0c971a528a64d7d7aec1bcdfcc8822393 100644 (file)
@@ -1587,8 +1587,8 @@ static int flexrm_mbox_probe(struct platform_device *pdev)
        }
 
        /* Allocate platform MSIs for each ring */
-       ret = platform_msi_domain_alloc_irqs(dev, mbox->num_rings,
-                                               flexrm_mbox_msi_write);
+       ret = platform_device_msi_init_and_alloc_irqs(dev, mbox->num_rings,
+                                                     flexrm_mbox_msi_write);
        if (ret)
                goto fail_destroy_cmpl_pool;
 
@@ -1641,7 +1641,7 @@ skip_debugfs:
 
 fail_free_debugfs_root:
        debugfs_remove_recursive(mbox->root);
-       platform_msi_domain_free_irqs(dev);
+       platform_device_msi_free_irqs_all(dev);
 fail_destroy_cmpl_pool:
        dma_pool_destroy(mbox->cmpl_pool);
 fail_destroy_bd_pool:
@@ -1657,7 +1657,7 @@ static void flexrm_mbox_remove(struct platform_device *pdev)
 
        debugfs_remove_recursive(mbox->root);
 
-       platform_msi_domain_free_irqs(dev);
+       platform_device_msi_free_irqs_all(dev);
 
        dma_pool_destroy(mbox->cmpl_pool);
        dma_pool_destroy(mbox->bd_pool);
index 6ae2329052c92c3c2724694c11f586bed8c5c15a..4e6afa89921fe0b79c4a760163d66565a2092d53 100644 (file)
@@ -300,7 +300,7 @@ struct cached_dev {
        struct list_head        list;
        struct bcache_device    disk;
        struct block_device     *bdev;
-       struct bdev_handle      *bdev_handle;
+       struct file             *bdev_file;
 
        struct cache_sb         sb;
        struct cache_sb_disk    *sb_disk;
@@ -423,7 +423,7 @@ struct cache {
 
        struct kobject          kobj;
        struct block_device     *bdev;
-       struct bdev_handle      *bdev_handle;
+       struct file             *bdev_file;
 
        struct task_struct      *alloc_thread;
 
index dc3f50f69714174cd0d649b4d003a9ed5b2d4992..330bcd9ea4a9ccd0366e9c5d28d0e7b1fb061fe6 100644 (file)
@@ -900,9 +900,23 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
        struct request_queue *q;
        const size_t max_stripes = min_t(size_t, INT_MAX,
                                         SIZE_MAX / sizeof(atomic_t));
+       struct queue_limits lim = {
+               .max_hw_sectors         = UINT_MAX,
+               .max_sectors            = UINT_MAX,
+               .max_segment_size       = UINT_MAX,
+               .max_segments           = BIO_MAX_VECS,
+               .max_hw_discard_sectors = UINT_MAX,
+               .io_min                 = block_size,
+               .logical_block_size     = block_size,
+               .physical_block_size    = block_size,
+       };
        uint64_t n;
        int idx;
 
+       if (cached_bdev) {
+               d->stripe_size = bdev_io_opt(cached_bdev) >> SECTOR_SHIFT;
+               lim.io_opt = umax(block_size, bdev_io_opt(cached_bdev));
+       }
        if (!d->stripe_size)
                d->stripe_size = 1 << 31;
        else if (d->stripe_size < BCH_MIN_STRIPE_SZ)
@@ -935,8 +949,21 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
                        BIOSET_NEED_BVECS|BIOSET_NEED_RESCUER))
                goto out_ida_remove;
 
-       d->disk = blk_alloc_disk(NUMA_NO_NODE);
-       if (!d->disk)
+       if (lim.logical_block_size > PAGE_SIZE && cached_bdev) {
+               /*
+                * This should only happen with BCACHE_SB_VERSION_BDEV.
+                * Block/page size is checked for BCACHE_SB_VERSION_CDEV.
+                */
+               pr_info("bcache%i: sb/logical block size (%u) greater than page size (%lu) falling back to device logical block size (%u)\n",
+                       idx, lim.logical_block_size,
+                       PAGE_SIZE, bdev_logical_block_size(cached_bdev));
+
+               /* This also adjusts physical block size/min io size if needed */
+               lim.logical_block_size = bdev_logical_block_size(cached_bdev);
+       }
+
+       d->disk = blk_alloc_disk(&lim, NUMA_NO_NODE);
+       if (IS_ERR(d->disk))
                goto out_bioset_exit;
 
        set_capacity(d->disk, sectors);
@@ -949,27 +976,6 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
        d->disk->private_data   = d;
 
        q = d->disk->queue;
-       q->limits.max_hw_sectors        = UINT_MAX;
-       q->limits.max_sectors           = UINT_MAX;
-       q->limits.max_segment_size      = UINT_MAX;
-       q->limits.max_segments          = BIO_MAX_VECS;
-       blk_queue_max_discard_sectors(q, UINT_MAX);
-       q->limits.io_min                = block_size;
-       q->limits.logical_block_size    = block_size;
-       q->limits.physical_block_size   = block_size;
-
-       if (q->limits.logical_block_size > PAGE_SIZE && cached_bdev) {
-               /*
-                * This should only happen with BCACHE_SB_VERSION_BDEV.
-                * Block/page size is checked for BCACHE_SB_VERSION_CDEV.
-                */
-               pr_info("%s: sb/logical block size (%u) greater than page size (%lu) falling back to device logical block size (%u)\n",
-                       d->disk->disk_name, q->limits.logical_block_size,
-                       PAGE_SIZE, bdev_logical_block_size(cached_bdev));
-
-               /* This also adjusts physical block size/min io size if needed */
-               blk_queue_logical_block_size(q, bdev_logical_block_size(cached_bdev));
-       }
 
        blk_queue_flag_set(QUEUE_FLAG_NONROT, d->disk->queue);
 
@@ -1369,8 +1375,8 @@ static CLOSURE_CALLBACK(cached_dev_free)
        if (dc->sb_disk)
                put_page(virt_to_page(dc->sb_disk));
 
-       if (dc->bdev_handle)
-               bdev_release(dc->bdev_handle);
+       if (dc->bdev_file)
+               fput(dc->bdev_file);
 
        wake_up(&unregister_wait);
 
@@ -1416,9 +1422,7 @@ static int cached_dev_init(struct cached_dev *dc, unsigned int block_size)
                hlist_add_head(&io->hash, dc->io_hash + RECENT_IO);
        }
 
-       dc->disk.stripe_size = q->limits.io_opt >> 9;
-
-       if (dc->disk.stripe_size)
+       if (bdev_io_opt(dc->bdev))
                dc->partial_stripes_expensive =
                        q->limits.raid_partial_stripes_expensive;
 
@@ -1428,9 +1432,6 @@ static int cached_dev_init(struct cached_dev *dc, unsigned int block_size)
        if (ret)
                return ret;
 
-       blk_queue_io_opt(dc->disk.disk->queue,
-               max(queue_io_opt(dc->disk.disk->queue), queue_io_opt(q)));
-
        atomic_set(&dc->io_errors, 0);
        dc->io_disable = false;
        dc->error_limit = DEFAULT_CACHED_DEV_ERROR_LIMIT;
@@ -1445,7 +1446,7 @@ static int cached_dev_init(struct cached_dev *dc, unsigned int block_size)
 /* Cached device - bcache superblock */
 
 static int register_bdev(struct cache_sb *sb, struct cache_sb_disk *sb_disk,
-                                struct bdev_handle *bdev_handle,
+                                struct file *bdev_file,
                                 struct cached_dev *dc)
 {
        const char *err = "cannot allocate memory";
@@ -1453,8 +1454,8 @@ static int register_bdev(struct cache_sb *sb, struct cache_sb_disk *sb_disk,
        int ret = -ENOMEM;
 
        memcpy(&dc->sb, sb, sizeof(struct cache_sb));
-       dc->bdev_handle = bdev_handle;
-       dc->bdev = bdev_handle->bdev;
+       dc->bdev_file = bdev_file;
+       dc->bdev = file_bdev(bdev_file);
        dc->sb_disk = sb_disk;
 
        if (cached_dev_init(dc, sb->block_size << 9))
@@ -2218,8 +2219,8 @@ void bch_cache_release(struct kobject *kobj)
        if (ca->sb_disk)
                put_page(virt_to_page(ca->sb_disk));
 
-       if (ca->bdev_handle)
-               bdev_release(ca->bdev_handle);
+       if (ca->bdev_file)
+               fput(ca->bdev_file);
 
        kfree(ca);
        module_put(THIS_MODULE);
@@ -2339,18 +2340,18 @@ err_free:
 }
 
 static int register_cache(struct cache_sb *sb, struct cache_sb_disk *sb_disk,
-                               struct bdev_handle *bdev_handle,
+                               struct file *bdev_file,
                                struct cache *ca)
 {
        const char *err = NULL; /* must be set for any error case */
        int ret = 0;
 
        memcpy(&ca->sb, sb, sizeof(struct cache_sb));
-       ca->bdev_handle = bdev_handle;
-       ca->bdev = bdev_handle->bdev;
+       ca->bdev_file = bdev_file;
+       ca->bdev = file_bdev(bdev_file);
        ca->sb_disk = sb_disk;
 
-       if (bdev_max_discard_sectors((bdev_handle->bdev)))
+       if (bdev_max_discard_sectors(file_bdev(bdev_file)))
                ca->discard = CACHE_DISCARD(&ca->sb);
 
        ret = cache_alloc(ca);
@@ -2361,20 +2362,20 @@ static int register_cache(struct cache_sb *sb, struct cache_sb_disk *sb_disk,
                        err = "cache_alloc(): cache device is too small";
                else
                        err = "cache_alloc(): unknown error";
-               pr_notice("error %pg: %s\n", bdev_handle->bdev, err);
+               pr_notice("error %pg: %s\n", file_bdev(bdev_file), err);
                /*
                 * If we failed here, it means ca->kobj is not initialized yet,
                 * kobject_put() won't be called and there is no chance to
-                * call bdev_release() to bdev in bch_cache_release(). So
-                * we explicitly call bdev_release() here.
+                * call fput() to bdev in bch_cache_release(). So
+                * we explicitly call fput() on the block device here.
                 */
-               bdev_release(bdev_handle);
+               fput(bdev_file);
                return ret;
        }
 
-       if (kobject_add(&ca->kobj, bdev_kobj(bdev_handle->bdev), "bcache")) {
+       if (kobject_add(&ca->kobj, bdev_kobj(file_bdev(bdev_file)), "bcache")) {
                pr_notice("error %pg: error calling kobject_add\n",
-                         bdev_handle->bdev);
+                         file_bdev(bdev_file));
                ret = -ENOMEM;
                goto out;
        }
@@ -2388,7 +2389,7 @@ static int register_cache(struct cache_sb *sb, struct cache_sb_disk *sb_disk,
                goto out;
        }
 
-       pr_info("registered cache device %pg\n", ca->bdev_handle->bdev);
+       pr_info("registered cache device %pg\n", file_bdev(ca->bdev_file));
 
 out:
        kobject_put(&ca->kobj);
@@ -2446,7 +2447,7 @@ struct async_reg_args {
        char *path;
        struct cache_sb *sb;
        struct cache_sb_disk *sb_disk;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        void *holder;
 };
 
@@ -2457,7 +2458,7 @@ static void register_bdev_worker(struct work_struct *work)
                container_of(work, struct async_reg_args, reg_work.work);
 
        mutex_lock(&bch_register_lock);
-       if (register_bdev(args->sb, args->sb_disk, args->bdev_handle,
+       if (register_bdev(args->sb, args->sb_disk, args->bdev_file,
                          args->holder) < 0)
                fail = true;
        mutex_unlock(&bch_register_lock);
@@ -2478,7 +2479,7 @@ static void register_cache_worker(struct work_struct *work)
                container_of(work, struct async_reg_args, reg_work.work);
 
        /* blkdev_put() will be called in bch_cache_release() */
-       if (register_cache(args->sb, args->sb_disk, args->bdev_handle,
+       if (register_cache(args->sb, args->sb_disk, args->bdev_file,
                           args->holder))
                fail = true;
 
@@ -2516,7 +2517,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
        char *path = NULL;
        struct cache_sb *sb;
        struct cache_sb_disk *sb_disk;
-       struct bdev_handle *bdev_handle, *bdev_handle2;
+       struct file *bdev_file, *bdev_file2;
        void *holder = NULL;
        ssize_t ret;
        bool async_registration = false;
@@ -2549,15 +2550,15 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
 
        ret = -EINVAL;
        err = "failed to open device";
-       bdev_handle = bdev_open_by_path(strim(path), BLK_OPEN_READ, NULL, NULL);
-       if (IS_ERR(bdev_handle))
+       bdev_file = bdev_file_open_by_path(strim(path), BLK_OPEN_READ, NULL, NULL);
+       if (IS_ERR(bdev_file))
                goto out_free_sb;
 
        err = "failed to set blocksize";
-       if (set_blocksize(bdev_handle->bdev, 4096))
+       if (set_blocksize(file_bdev(bdev_file), 4096))
                goto out_blkdev_put;
 
-       err = read_super(sb, bdev_handle->bdev, &sb_disk);
+       err = read_super(sb, file_bdev(bdev_file), &sb_disk);
        if (err)
                goto out_blkdev_put;
 
@@ -2569,13 +2570,13 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
        }
 
        /* Now reopen in exclusive mode with proper holder */
-       bdev_handle2 = bdev_open_by_dev(bdev_handle->bdev->bd_dev,
+       bdev_file2 = bdev_file_open_by_dev(file_bdev(bdev_file)->bd_dev,
                        BLK_OPEN_READ | BLK_OPEN_WRITE, holder, NULL);
-       bdev_release(bdev_handle);
-       bdev_handle = bdev_handle2;
-       if (IS_ERR(bdev_handle)) {
-               ret = PTR_ERR(bdev_handle);
-               bdev_handle = NULL;
+       fput(bdev_file);
+       bdev_file = bdev_file2;
+       if (IS_ERR(bdev_file)) {
+               ret = PTR_ERR(bdev_file);
+               bdev_file = NULL;
                if (ret == -EBUSY) {
                        dev_t dev;
 
@@ -2610,7 +2611,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
                args->path      = path;
                args->sb        = sb;
                args->sb_disk   = sb_disk;
-               args->bdev_handle       = bdev_handle;
+               args->bdev_file = bdev_file;
                args->holder    = holder;
                register_device_async(args);
                /* No wait and returns to user space */
@@ -2619,14 +2620,14 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
 
        if (SB_IS_BDEV(sb)) {
                mutex_lock(&bch_register_lock);
-               ret = register_bdev(sb, sb_disk, bdev_handle, holder);
+               ret = register_bdev(sb, sb_disk, bdev_file, holder);
                mutex_unlock(&bch_register_lock);
                /* blkdev_put() will be called in cached_dev_free() */
                if (ret < 0)
                        goto out_free_sb;
        } else {
                /* blkdev_put() will be called in bch_cache_release() */
-               ret = register_cache(sb, sb_disk, bdev_handle, holder);
+               ret = register_cache(sb, sb_disk, bdev_file, holder);
                if (ret)
                        goto out_free_sb;
        }
@@ -2642,8 +2643,8 @@ out_free_holder:
 out_put_sb_page:
        put_page(virt_to_page(sb_disk));
 out_blkdev_put:
-       if (bdev_handle)
-               bdev_release(bdev_handle);
+       if (bdev_file)
+               fput(bdev_file);
 out_free_sb:
        kfree(sb);
 out_free_path:
index f745f85082434dca8fb6d6bf9efe30db79b2a81e..59445763e55a65de49e79cc2436c8a03131a5a15 100644 (file)
 struct convert_context {
        struct completion restart;
        struct bio *bio_in;
-       struct bio *bio_out;
        struct bvec_iter iter_in;
+       struct bio *bio_out;
        struct bvec_iter iter_out;
-       u64 cc_sector;
        atomic_t cc_pending;
+       u64 cc_sector;
        union {
                struct skcipher_request *req;
                struct aead_request *req_aead;
        } r;
+       bool aead_recheck;
+       bool aead_failed;
 
 };
 
@@ -82,6 +84,8 @@ struct dm_crypt_io {
        blk_status_t error;
        sector_t sector;
 
+       struct bvec_iter saved_bi_iter;
+
        struct rb_node rb_node;
 } CRYPTO_MINALIGN_ATTR;
 
@@ -1370,10 +1374,13 @@ static int crypt_convert_block_aead(struct crypt_config *cc,
        if (r == -EBADMSG) {
                sector_t s = le64_to_cpu(*sector);
 
-               DMERR_LIMIT("%pg: INTEGRITY AEAD ERROR, sector %llu",
-                           ctx->bio_in->bi_bdev, s);
-               dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead",
-                                ctx->bio_in, s, 0);
+               ctx->aead_failed = true;
+               if (ctx->aead_recheck) {
+                       DMERR_LIMIT("%pg: INTEGRITY AEAD ERROR, sector %llu",
+                                   ctx->bio_in->bi_bdev, s);
+                       dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead",
+                                        ctx->bio_in, s, 0);
+               }
        }
 
        if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post)
@@ -1757,6 +1764,8 @@ static void crypt_io_init(struct dm_crypt_io *io, struct crypt_config *cc,
        io->base_bio = bio;
        io->sector = sector;
        io->error = 0;
+       io->ctx.aead_recheck = false;
+       io->ctx.aead_failed = false;
        io->ctx.r.req = NULL;
        io->integrity_metadata = NULL;
        io->integrity_metadata_from_pool = false;
@@ -1768,6 +1777,8 @@ static void crypt_inc_pending(struct dm_crypt_io *io)
        atomic_inc(&io->io_pending);
 }
 
+static void kcryptd_queue_read(struct dm_crypt_io *io);
+
 /*
  * One of the bios was finished. Check for completion of
  * the whole request and correctly clean up the buffer.
@@ -1781,6 +1792,15 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
        if (!atomic_dec_and_test(&io->io_pending))
                return;
 
+       if (likely(!io->ctx.aead_recheck) && unlikely(io->ctx.aead_failed) &&
+           cc->on_disk_tag_size && bio_data_dir(base_bio) == READ) {
+               io->ctx.aead_recheck = true;
+               io->ctx.aead_failed = false;
+               io->error = 0;
+               kcryptd_queue_read(io);
+               return;
+       }
+
        if (io->ctx.r.req)
                crypt_free_req(cc, io->ctx.r.req, base_bio);
 
@@ -1816,15 +1836,19 @@ static void crypt_endio(struct bio *clone)
        struct dm_crypt_io *io = clone->bi_private;
        struct crypt_config *cc = io->cc;
        unsigned int rw = bio_data_dir(clone);
-       blk_status_t error;
+       blk_status_t error = clone->bi_status;
+
+       if (io->ctx.aead_recheck && !error) {
+               kcryptd_queue_crypt(io);
+               return;
+       }
 
        /*
         * free the processed pages
         */
-       if (rw == WRITE)
+       if (rw == WRITE || io->ctx.aead_recheck)
                crypt_free_buffer_pages(cc, clone);
 
-       error = clone->bi_status;
        bio_put(clone);
 
        if (rw == READ && !error) {
@@ -1845,6 +1869,22 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
        struct crypt_config *cc = io->cc;
        struct bio *clone;
 
+       if (io->ctx.aead_recheck) {
+               if (!(gfp & __GFP_DIRECT_RECLAIM))
+                       return 1;
+               crypt_inc_pending(io);
+               clone = crypt_alloc_buffer(io, io->base_bio->bi_iter.bi_size);
+               if (unlikely(!clone)) {
+                       crypt_dec_pending(io);
+                       return 1;
+               }
+               clone->bi_iter.bi_sector = cc->start + io->sector;
+               crypt_convert_init(cc, &io->ctx, clone, clone, io->sector);
+               io->saved_bi_iter = clone->bi_iter;
+               dm_submit_bio_remap(io->base_bio, clone);
+               return 0;
+       }
+
        /*
         * We need the original biovec array in order to decrypt the whole bio
         * data *afterwards* -- thanks to immutable biovecs we don't need to
@@ -2071,6 +2111,12 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
        io->ctx.bio_out = clone;
        io->ctx.iter_out = clone->bi_iter;
 
+       if (crypt_integrity_aead(cc)) {
+               bio_copy_data(clone, io->base_bio);
+               io->ctx.bio_in = clone;
+               io->ctx.iter_in = clone->bi_iter;
+       }
+
        sector += bio_sectors(clone);
 
        crypt_inc_pending(io);
@@ -2107,6 +2153,14 @@ dec:
 
 static void kcryptd_crypt_read_done(struct dm_crypt_io *io)
 {
+       if (io->ctx.aead_recheck) {
+               if (!io->error) {
+                       io->ctx.bio_in->bi_iter = io->saved_bi_iter;
+                       bio_copy_data(io->base_bio, io->ctx.bio_in);
+               }
+               crypt_free_buffer_pages(io->cc, io->ctx.bio_in);
+               bio_put(io->ctx.bio_in);
+       }
        crypt_dec_pending(io);
 }
 
@@ -2136,11 +2190,17 @@ static void kcryptd_crypt_read_convert(struct dm_crypt_io *io)
 
        crypt_inc_pending(io);
 
-       crypt_convert_init(cc, &io->ctx, io->base_bio, io->base_bio,
-                          io->sector);
+       if (io->ctx.aead_recheck) {
+               io->ctx.cc_sector = io->sector + cc->iv_offset;
+               r = crypt_convert(cc, &io->ctx,
+                                 test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags), true);
+       } else {
+               crypt_convert_init(cc, &io->ctx, io->base_bio, io->base_bio,
+                                  io->sector);
 
-       r = crypt_convert(cc, &io->ctx,
-                         test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags), true);
+               r = crypt_convert(cc, &io->ctx,
+                                 test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags), true);
+       }
        /*
         * Crypto API backlogged the request, because its queue was full
         * and we're in softirq context, so continue from a workqueue
@@ -2182,10 +2242,13 @@ static void kcryptd_async_done(void *data, int error)
        if (error == -EBADMSG) {
                sector_t s = le64_to_cpu(*org_sector_of_dmreq(cc, dmreq));
 
-               DMERR_LIMIT("%pg: INTEGRITY AEAD ERROR, sector %llu",
-                           ctx->bio_in->bi_bdev, s);
-               dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead",
-                                ctx->bio_in, s, 0);
+               ctx->aead_failed = true;
+               if (ctx->aead_recheck) {
+                       DMERR_LIMIT("%pg: INTEGRITY AEAD ERROR, sector %llu",
+                                   ctx->bio_in->bi_bdev, s);
+                       dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead",
+                                        ctx->bio_in, s, 0);
+               }
                io->error = BLK_STS_PROTECTION;
        } else if (error < 0)
                io->error = BLK_STS_IOERR;
@@ -3110,7 +3173,7 @@ static int crypt_ctr_optional(struct dm_target *ti, unsigned int argc, char **ar
                        sval = strchr(opt_string + strlen("integrity:"), ':') + 1;
                        if (!strcasecmp(sval, "aead")) {
                                set_bit(CRYPT_MODE_INTEGRITY_AEAD, &cc->cipher_flags);
-                       } else  if (strcasecmp(sval, "none")) {
+                       } else if (strcasecmp(sval, "none")) {
                                ti->error = "Unknown integrity profile";
                                return -EINVAL;
                        }
@@ -3639,7 +3702,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
 static struct target_type crypt_target = {
        .name   = "crypt",
-       .version = {1, 24, 0},
+       .version = {1, 25, 0},
        .module = THIS_MODULE,
        .ctr    = crypt_ctr,
        .dtr    = crypt_dtr,
index c5f03aab455256ff1b0abc606b7728438be347f0..1fc901df84eb163c833e364d21e0a48e65c06239 100644 (file)
@@ -278,6 +278,8 @@ struct dm_integrity_c {
 
        atomic64_t number_of_mismatches;
 
+       mempool_t recheck_pool;
+
        struct notifier_block reboot_notifier;
 };
 
@@ -1689,6 +1691,77 @@ failed:
        get_random_bytes(result, ic->tag_size);
 }
 
+static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checksum)
+{
+       struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
+       struct dm_integrity_c *ic = dio->ic;
+       struct bvec_iter iter;
+       struct bio_vec bv;
+       sector_t sector, logical_sector, area, offset;
+       struct page *page;
+       void *buffer;
+
+       get_area_and_offset(ic, dio->range.logical_sector, &area, &offset);
+       dio->metadata_block = get_metadata_sector_and_offset(ic, area, offset,
+                                                            &dio->metadata_offset);
+       sector = get_data_sector(ic, area, offset);
+       logical_sector = dio->range.logical_sector;
+
+       page = mempool_alloc(&ic->recheck_pool, GFP_NOIO);
+       buffer = page_to_virt(page);
+
+       __bio_for_each_segment(bv, bio, iter, dio->bio_details.bi_iter) {
+               unsigned pos = 0;
+
+               do {
+                       char *mem;
+                       int r;
+                       struct dm_io_request io_req;
+                       struct dm_io_region io_loc;
+                       io_req.bi_opf = REQ_OP_READ;
+                       io_req.mem.type = DM_IO_KMEM;
+                       io_req.mem.ptr.addr = buffer;
+                       io_req.notify.fn = NULL;
+                       io_req.client = ic->io;
+                       io_loc.bdev = ic->dev->bdev;
+                       io_loc.sector = sector;
+                       io_loc.count = ic->sectors_per_block;
+
+                       r = dm_io(&io_req, 1, &io_loc, NULL);
+                       if (unlikely(r)) {
+                               dio->bi_status = errno_to_blk_status(r);
+                               goto free_ret;
+                       }
+
+                       integrity_sector_checksum(ic, logical_sector, buffer, checksum);
+                       r = dm_integrity_rw_tag(ic, checksum, &dio->metadata_block,
+                                               &dio->metadata_offset, ic->tag_size, TAG_CMP);
+                       if (r) {
+                               if (r > 0) {
+                                       DMERR_LIMIT("%pg: Checksum failed at sector 0x%llx",
+                                                   bio->bi_bdev, logical_sector);
+                                       atomic64_inc(&ic->number_of_mismatches);
+                                       dm_audit_log_bio(DM_MSG_PREFIX, "integrity-checksum",
+                                                        bio, logical_sector, 0);
+                                       r = -EILSEQ;
+                               }
+                               dio->bi_status = errno_to_blk_status(r);
+                               goto free_ret;
+                       }
+
+                       mem = bvec_kmap_local(&bv);
+                       memcpy(mem + pos, buffer, ic->sectors_per_block << SECTOR_SHIFT);
+                       kunmap_local(mem);
+
+                       pos += ic->sectors_per_block << SECTOR_SHIFT;
+                       sector += ic->sectors_per_block;
+                       logical_sector += ic->sectors_per_block;
+               } while (pos < bv.bv_len);
+       }
+free_ret:
+       mempool_free(page, &ic->recheck_pool);
+}
+
 static void integrity_metadata(struct work_struct *w)
 {
        struct dm_integrity_io *dio = container_of(w, struct dm_integrity_io, work);
@@ -1776,15 +1849,8 @@ again:
                                                checksums_ptr - checksums, dio->op == REQ_OP_READ ? TAG_CMP : TAG_WRITE);
                        if (unlikely(r)) {
                                if (r > 0) {
-                                       sector_t s;
-
-                                       s = sector - ((r + ic->tag_size - 1) / ic->tag_size);
-                                       DMERR_LIMIT("%pg: Checksum failed at sector 0x%llx",
-                                                   bio->bi_bdev, s);
-                                       r = -EILSEQ;
-                                       atomic64_inc(&ic->number_of_mismatches);
-                                       dm_audit_log_bio(DM_MSG_PREFIX, "integrity-checksum",
-                                                        bio, s, 0);
+                                       integrity_recheck(dio, checksums);
+                                       goto skip_io;
                                }
                                if (likely(checksums != checksums_onstack))
                                        kfree(checksums);
@@ -4261,6 +4327,12 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
                goto bad;
        }
 
+       r = mempool_init_page_pool(&ic->recheck_pool, 1, 0);
+       if (r) {
+               ti->error = "Cannot allocate mempool";
+               goto bad;
+       }
+
        ic->metadata_wq = alloc_workqueue("dm-integrity-metadata",
                                          WQ_MEM_RECLAIM, METADATA_WORKQUEUE_MAX_ACTIVE);
        if (!ic->metadata_wq) {
@@ -4609,6 +4681,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
        kvfree(ic->bbs);
        if (ic->bufio)
                dm_bufio_client_destroy(ic->bufio);
+       mempool_exit(&ic->recheck_pool);
        mempool_exit(&ic->journal_io_mempool);
        if (ic->io)
                dm_io_client_destroy(ic->io);
@@ -4661,7 +4734,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
 
 static struct target_type integrity_target = {
        .name                   = "integrity",
-       .version                = {1, 10, 0},
+       .version                = {1, 11, 0},
        .module                 = THIS_MODULE,
        .features               = DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY,
        .ctr                    = dm_integrity_ctr,
index eb009d6bb03a17b72a06b9a932cd15242be10e26..17e9af60bbf7f07a7b4a567c1cb7672d7d6deb67 100644 (file)
@@ -213,6 +213,7 @@ struct raid_dev {
 #define RT_FLAG_RS_IN_SYNC             6
 #define RT_FLAG_RS_RESYNCING           7
 #define RT_FLAG_RS_GROW                        8
+#define RT_FLAG_RS_FROZEN              9
 
 /* Array elements of 64 bit needed for rebuild/failed disk bits */
 #define DISKS_ARRAY_ELEMS ((MAX_RAID_DEVICES + (sizeof(uint64_t) * 8 - 1)) / sizeof(uint64_t) / 8)
@@ -3240,11 +3241,12 @@ size_check:
        rs->md.ro = 1;
        rs->md.in_sync = 1;
 
-       /* Keep array frozen until resume. */
-       set_bit(MD_RECOVERY_FROZEN, &rs->md.recovery);
-
        /* Has to be held on running the array */
        mddev_suspend_and_lock_nointr(&rs->md);
+
+       /* Keep array frozen until resume. */
+       md_frozen_sync_thread(&rs->md);
+
        r = md_run(&rs->md);
        rs->md.in_sync = 0; /* Assume already marked dirty */
        if (r) {
@@ -3339,7 +3341,8 @@ static int raid_map(struct dm_target *ti, struct bio *bio)
        if (unlikely(bio_end_sector(bio) > mddev->array_sectors))
                return DM_MAPIO_REQUEUE;
 
-       md_handle_request(mddev, bio);
+       if (unlikely(!md_handle_request(mddev, bio)))
+               return DM_MAPIO_REQUEUE;
 
        return DM_MAPIO_SUBMITTED;
 }
@@ -3718,21 +3721,33 @@ static int raid_message(struct dm_target *ti, unsigned int argc, char **argv,
 {
        struct raid_set *rs = ti->private;
        struct mddev *mddev = &rs->md;
+       int ret = 0;
 
        if (!mddev->pers || !mddev->pers->sync_request)
                return -EINVAL;
 
-       if (!strcasecmp(argv[0], "frozen"))
-               set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
-       else
-               clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+       if (test_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags) ||
+           test_bit(RT_FLAG_RS_FROZEN, &rs->runtime_flags))
+               return -EBUSY;
 
-       if (!strcasecmp(argv[0], "idle") || !strcasecmp(argv[0], "frozen")) {
-               if (mddev->sync_thread) {
-                       set_bit(MD_RECOVERY_INTR, &mddev->recovery);
-                       md_reap_sync_thread(mddev);
-               }
-       } else if (decipher_sync_action(mddev, mddev->recovery) != st_idle)
+       if (!strcasecmp(argv[0], "frozen")) {
+               ret = mddev_lock(mddev);
+               if (ret)
+                       return ret;
+
+               md_frozen_sync_thread(mddev);
+               mddev_unlock(mddev);
+       } else if (!strcasecmp(argv[0], "idle")) {
+               ret = mddev_lock(mddev);
+               if (ret)
+                       return ret;
+
+               md_idle_sync_thread(mddev);
+               mddev_unlock(mddev);
+       }
+
+       clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+       if (decipher_sync_action(mddev, mddev->recovery) != st_idle)
                return -EBUSY;
        else if (!strcasecmp(argv[0], "resync"))
                ; /* MD_RECOVERY_NEEDED set below */
@@ -3791,15 +3806,46 @@ static void raid_io_hints(struct dm_target *ti, struct queue_limits *limits)
        blk_limits_io_opt(limits, chunk_size_bytes * mddev_data_stripes(rs));
 }
 
+static void raid_presuspend(struct dm_target *ti)
+{
+       struct raid_set *rs = ti->private;
+       struct mddev *mddev = &rs->md;
+
+       /*
+        * From now on, disallow raid_message() to change sync_thread until
+        * resume, raid_postsuspend() is too late.
+        */
+       set_bit(RT_FLAG_RS_FROZEN, &rs->runtime_flags);
+
+       if (!reshape_interrupted(mddev))
+               return;
+
+       /*
+        * For raid456, if reshape is interrupted, IO across reshape position
+        * will never make progress, while caller will wait for IO to be done.
+        * Inform raid456 to handle those IO to prevent deadlock.
+        */
+       if (mddev->pers && mddev->pers->prepare_suspend)
+               mddev->pers->prepare_suspend(mddev);
+}
+
+static void raid_presuspend_undo(struct dm_target *ti)
+{
+       struct raid_set *rs = ti->private;
+
+       clear_bit(RT_FLAG_RS_FROZEN, &rs->runtime_flags);
+}
+
 static void raid_postsuspend(struct dm_target *ti)
 {
        struct raid_set *rs = ti->private;
 
        if (!test_and_set_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags)) {
-               /* Writes have to be stopped before suspending to avoid deadlocks. */
-               if (!test_bit(MD_RECOVERY_FROZEN, &rs->md.recovery))
-                       md_stop_writes(&rs->md);
-
+               /*
+                * sync_thread must be stopped during suspend, and writes have
+                * to be stopped before suspending to avoid deadlocks.
+                */
+               md_stop_writes(&rs->md);
                mddev_suspend(&rs->md, false);
        }
 }
@@ -4012,8 +4058,6 @@ static int raid_preresume(struct dm_target *ti)
        }
 
        /* Check for any resize/reshape on @rs and adjust/initiate */
-       /* Be prepared for mddev_resume() in raid_resume() */
-       set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
        if (mddev->recovery_cp && mddev->recovery_cp < MaxSector) {
                set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
                mddev->resync_min = mddev->recovery_cp;
@@ -4047,7 +4091,9 @@ static void raid_resume(struct dm_target *ti)
                 * Take this opportunity to check whether any failed
                 * devices are reachable again.
                 */
+               mddev_lock_nointr(mddev);
                attempt_restore_of_faulty_devices(rs);
+               mddev_unlock(mddev);
        }
 
        if (test_and_clear_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags)) {
@@ -4055,10 +4101,13 @@ static void raid_resume(struct dm_target *ti)
                if (mddev->delta_disks < 0)
                        rs_set_capacity(rs);
 
+               WARN_ON_ONCE(!test_bit(MD_RECOVERY_FROZEN, &mddev->recovery));
+               WARN_ON_ONCE(test_bit(MD_RECOVERY_RUNNING, &mddev->recovery));
+               clear_bit(RT_FLAG_RS_FROZEN, &rs->runtime_flags);
                mddev_lock_nointr(mddev);
-               clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
                mddev->ro = 0;
                mddev->in_sync = 0;
+               md_unfrozen_sync_thread(mddev);
                mddev_unlock_and_resume(mddev);
        }
 }
@@ -4074,6 +4123,8 @@ static struct target_type raid_target = {
        .message = raid_message,
        .iterate_devices = raid_iterate_devices,
        .io_hints = raid_io_hints,
+       .presuspend = raid_presuspend,
+       .presuspend_undo = raid_presuspend_undo,
        .postsuspend = raid_postsuspend,
        .preresume = raid_preresume,
        .resume = raid_resume,
index 82662f5769c4af7f5456fc97e044c63574162060..1b591bfa90d5d6463016e22183dbb5f071e94a75 100644 (file)
@@ -482,6 +482,63 @@ int verity_for_bv_block(struct dm_verity *v, struct dm_verity_io *io,
        return 0;
 }
 
+static int verity_recheck_copy(struct dm_verity *v, struct dm_verity_io *io,
+                              u8 *data, size_t len)
+{
+       memcpy(data, io->recheck_buffer, len);
+       io->recheck_buffer += len;
+
+       return 0;
+}
+
+static noinline int verity_recheck(struct dm_verity *v, struct dm_verity_io *io,
+                                  struct bvec_iter start, sector_t cur_block)
+{
+       struct page *page;
+       void *buffer;
+       int r;
+       struct dm_io_request io_req;
+       struct dm_io_region io_loc;
+
+       page = mempool_alloc(&v->recheck_pool, GFP_NOIO);
+       buffer = page_to_virt(page);
+
+       io_req.bi_opf = REQ_OP_READ;
+       io_req.mem.type = DM_IO_KMEM;
+       io_req.mem.ptr.addr = buffer;
+       io_req.notify.fn = NULL;
+       io_req.client = v->io;
+       io_loc.bdev = v->data_dev->bdev;
+       io_loc.sector = cur_block << (v->data_dev_block_bits - SECTOR_SHIFT);
+       io_loc.count = 1 << (v->data_dev_block_bits - SECTOR_SHIFT);
+       r = dm_io(&io_req, 1, &io_loc, NULL);
+       if (unlikely(r))
+               goto free_ret;
+
+       r = verity_hash(v, verity_io_hash_req(v, io), buffer,
+                       1 << v->data_dev_block_bits,
+                       verity_io_real_digest(v, io), true);
+       if (unlikely(r))
+               goto free_ret;
+
+       if (memcmp(verity_io_real_digest(v, io),
+                  verity_io_want_digest(v, io), v->digest_size)) {
+               r = -EIO;
+               goto free_ret;
+       }
+
+       io->recheck_buffer = buffer;
+       r = verity_for_bv_block(v, io, &start, verity_recheck_copy);
+       if (unlikely(r))
+               goto free_ret;
+
+       r = 0;
+free_ret:
+       mempool_free(page, &v->recheck_pool);
+
+       return r;
+}
+
 static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io,
                          u8 *data, size_t len)
 {
@@ -508,9 +565,7 @@ static int verity_verify_io(struct dm_verity_io *io)
 {
        bool is_zero;
        struct dm_verity *v = io->v;
-#if defined(CONFIG_DM_VERITY_FEC)
        struct bvec_iter start;
-#endif
        struct bvec_iter iter_copy;
        struct bvec_iter *iter;
        struct crypto_wait wait;
@@ -561,10 +616,7 @@ static int verity_verify_io(struct dm_verity_io *io)
                if (unlikely(r < 0))
                        return r;
 
-#if defined(CONFIG_DM_VERITY_FEC)
-               if (verity_fec_is_enabled(v))
-                       start = *iter;
-#endif
+               start = *iter;
                r = verity_for_io_block(v, io, iter, &wait);
                if (unlikely(r < 0))
                        return r;
@@ -586,6 +638,10 @@ static int verity_verify_io(struct dm_verity_io *io)
                         * tasklet since it may sleep, so fallback to work-queue.
                         */
                        return -EAGAIN;
+               } else if (verity_recheck(v, io, start, cur_block) == 0) {
+                       if (v->validated_blocks)
+                               set_bit(cur_block, v->validated_blocks);
+                       continue;
 #if defined(CONFIG_DM_VERITY_FEC)
                } else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA,
                                             cur_block, NULL, &start) == 0) {
@@ -941,6 +997,10 @@ static void verity_dtr(struct dm_target *ti)
        if (v->verify_wq)
                destroy_workqueue(v->verify_wq);
 
+       mempool_exit(&v->recheck_pool);
+       if (v->io)
+               dm_io_client_destroy(v->io);
+
        if (v->bufio)
                dm_bufio_client_destroy(v->bufio);
 
@@ -1379,6 +1439,20 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
        v->hash_blocks = hash_position;
 
+       r = mempool_init_page_pool(&v->recheck_pool, 1, 0);
+       if (unlikely(r)) {
+               ti->error = "Cannot allocate mempool";
+               goto bad;
+       }
+
+       v->io = dm_io_client_create();
+       if (IS_ERR(v->io)) {
+               r = PTR_ERR(v->io);
+               v->io = NULL;
+               ti->error = "Cannot allocate dm io";
+               goto bad;
+       }
+
        v->bufio = dm_bufio_client_create(v->hash_dev->bdev,
                1 << v->hash_dev_block_bits, 1, sizeof(struct buffer_aux),
                dm_bufio_alloc_callback, NULL,
@@ -1486,7 +1560,7 @@ int dm_verity_get_root_digest(struct dm_target *ti, u8 **root_digest, unsigned i
 static struct target_type verity_target = {
        .name           = "verity",
        .features       = DM_TARGET_IMMUTABLE,
-       .version        = {1, 9, 0},
+       .version        = {1, 10, 0},
        .module         = THIS_MODULE,
        .ctr            = verity_ctr,
        .dtr            = verity_dtr,
index f3f6070084196825f21dcc17947f67974a90cbde..db93a91169d5e6de31d344a6f37589bbc0bdb654 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef DM_VERITY_H
 #define DM_VERITY_H
 
+#include <linux/dm-io.h>
 #include <linux/dm-bufio.h>
 #include <linux/device-mapper.h>
 #include <linux/interrupt.h>
@@ -68,6 +69,9 @@ struct dm_verity {
        unsigned long *validated_blocks; /* bitset blocks validated */
 
        char *signature_key_desc; /* signature keyring reference */
+
+       struct dm_io_client *io;
+       mempool_t recheck_pool;
 };
 
 struct dm_verity_io {
@@ -76,14 +80,16 @@ struct dm_verity_io {
        /* original value of bio->bi_end_io */
        bio_end_io_t *orig_bi_end_io;
 
+       struct bvec_iter iter;
+
        sector_t block;
        unsigned int n_blocks;
        bool in_tasklet;
 
-       struct bvec_iter iter;
-
        struct work_struct work;
 
+       char *recheck_buffer;
+
        /*
         * Three variably-size fields follow this struct:
         *
index fdfe30f7b6973d76fac4a50f6b41f6b2f4102168..8156881a31de93d4b155051e8085ceb90216aa46 100644 (file)
@@ -1655,10 +1655,13 @@ static int dmz_reset_zone(struct dmz_metadata *zmd, struct dm_zone *zone)
 
        if (!dmz_is_empty(zone) || dmz_seq_write_err(zone)) {
                struct dmz_dev *dev = zone->dev;
+               unsigned int noio_flag;
 
+               noio_flag = memalloc_noio_save();
                ret = blkdev_zone_mgmt(dev->bdev, REQ_OP_ZONE_RESET,
                                       dmz_start_sect(zmd, zone),
-                                      zmd->zone_nr_sectors, GFP_NOIO);
+                                      zmd->zone_nr_sectors);
+               memalloc_noio_restore(noio_flag);
                if (ret) {
                        dmz_dev_err(dev, "Reset zone %u failed %d",
                                    zone->id, ret);
index 8dcabf84d866e6d2ac863a98790b16b838475d23..447e132d09b53732f9d3eff3dc8aa85644ff3135 100644 (file)
@@ -726,7 +726,8 @@ static struct table_device *open_table_device(struct mapped_device *md,
                dev_t dev, blk_mode_t mode)
 {
        struct table_device *td;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
+       struct block_device *bdev;
        u64 part_off;
        int r;
 
@@ -735,34 +736,36 @@ static struct table_device *open_table_device(struct mapped_device *md,
                return ERR_PTR(-ENOMEM);
        refcount_set(&td->count, 1);
 
-       bdev_handle = bdev_open_by_dev(dev, mode, _dm_claim_ptr, NULL);
-       if (IS_ERR(bdev_handle)) {
-               r = PTR_ERR(bdev_handle);
+       bdev_file = bdev_file_open_by_dev(dev, mode, _dm_claim_ptr, NULL);
+       if (IS_ERR(bdev_file)) {
+               r = PTR_ERR(bdev_file);
                goto out_free_td;
        }
 
+       bdev = file_bdev(bdev_file);
+
        /*
         * We can be called before the dm disk is added.  In that case we can't
         * register the holder relation here.  It will be done once add_disk was
         * called.
         */
        if (md->disk->slave_dir) {
-               r = bd_link_disk_holder(bdev_handle->bdev, md->disk);
+               r = bd_link_disk_holder(bdev, md->disk);
                if (r)
                        goto out_blkdev_put;
        }
 
        td->dm_dev.mode = mode;
-       td->dm_dev.bdev = bdev_handle->bdev;
-       td->dm_dev.bdev_handle = bdev_handle;
-       td->dm_dev.dax_dev = fs_dax_get_by_bdev(bdev_handle->bdev, &part_off,
+       td->dm_dev.bdev = bdev;
+       td->dm_dev.bdev_file = bdev_file;
+       td->dm_dev.dax_dev = fs_dax_get_by_bdev(bdev, &part_off,
                                                NULL, NULL);
        format_dev_t(td->dm_dev.name, dev);
        list_add(&td->list, &md->table_devices);
        return td;
 
 out_blkdev_put:
-       bdev_release(bdev_handle);
+       fput(bdev_file);
 out_free_td:
        kfree(td);
        return ERR_PTR(r);
@@ -775,7 +778,7 @@ static void close_table_device(struct table_device *td, struct mapped_device *md
 {
        if (md->disk->slave_dir)
                bd_unlink_disk_holder(td->dm_dev.bdev, md->disk);
-       bdev_release(td->dm_dev.bdev_handle);
+       fput(td->dm_dev.bdev_file);
        put_dax(td->dm_dev.dax_dev);
        list_del(&td->list);
        kfree(td);
@@ -2098,8 +2101,8 @@ static struct mapped_device *alloc_dev(int minor)
         * established. If request-based table is loaded: blk-mq will
         * override accordingly.
         */
-       md->disk = blk_alloc_disk(md->numa_node_id);
-       if (!md->disk)
+       md->disk = blk_alloc_disk(NULL, md->numa_node_id);
+       if (IS_ERR(md->disk))
                goto bad;
        md->queue = md->disk->queue;
 
index 9672f75c30503cefc197ed0c3234d7a254b9fbe4..059afc24c08bec85ba2739002043619053ca0f1d 100644 (file)
@@ -234,7 +234,8 @@ static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,
        sector_t doff;
 
        bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev;
-       if (pg_index == store->file_pages - 1) {
+       /* we compare length (page numbers), not page offset. */
+       if ((pg_index - store->sb_index) == store->file_pages - 1) {
                unsigned int last_page_size = store->bytes & (PAGE_SIZE - 1);
 
                if (last_page_size == 0)
@@ -438,8 +439,8 @@ static void filemap_write_page(struct bitmap *bitmap, unsigned long pg_index,
        struct page *page = store->filemap[pg_index];
 
        if (mddev_is_clustered(bitmap->mddev)) {
-               pg_index += bitmap->cluster_slot *
-                       DIV_ROUND_UP(store->bytes, PAGE_SIZE);
+               /* go to node bitmap area starting point */
+               pg_index += store->sb_index;
        }
 
        if (store->file)
@@ -952,6 +953,7 @@ static void md_bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
        unsigned long index = file_page_index(store, chunk);
        unsigned long node_offset = 0;
 
+       index += store->sb_index;
        if (mddev_is_clustered(bitmap->mddev))
                node_offset = bitmap->cluster_slot * store->file_pages;
 
@@ -982,6 +984,7 @@ static void md_bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block)
        unsigned long index = file_page_index(store, chunk);
        unsigned long node_offset = 0;
 
+       index += store->sb_index;
        if (mddev_is_clustered(bitmap->mddev))
                node_offset = bitmap->cluster_slot * store->file_pages;
 
@@ -1043,9 +1046,8 @@ void md_bitmap_unplug(struct bitmap *bitmap)
                if (dirty || need_write) {
                        if (!writing) {
                                md_bitmap_wait_writes(bitmap);
-                               if (bitmap->mddev->queue)
-                                       blk_add_trace_msg(bitmap->mddev->queue,
-                                                         "md bitmap_unplug");
+                               mddev_add_trace_msg(bitmap->mddev,
+                                       "md bitmap_unplug");
                        }
                        clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING);
                        filemap_write_page(bitmap, i, false);
@@ -1316,9 +1318,7 @@ void md_bitmap_daemon_work(struct mddev *mddev)
        }
        bitmap->allclean = 1;
 
-       if (bitmap->mddev->queue)
-               blk_add_trace_msg(bitmap->mddev->queue,
-                                 "md bitmap_daemon_work");
+       mddev_add_trace_msg(bitmap->mddev, "md bitmap_daemon_work");
 
        /* Any file-page which is PENDING now needs to be written.
         * So set NEEDWRITE now, then after we make any last-minute changes
diff --git a/drivers/md/md-linear.h b/drivers/md/md-linear.h
deleted file mode 100644 (file)
index 5587eee..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _LINEAR_H
-#define _LINEAR_H
-
-struct dev_info {
-       struct md_rdev  *rdev;
-       sector_t        end_sector;
-};
-
-struct linear_conf
-{
-       struct rcu_head         rcu;
-       sector_t                array_sectors;
-       int                     raid_disks; /* a copy of mddev->raid_disks */
-       struct dev_info         disks[] __counted_by(raid_disks);
-};
-#endif
diff --git a/drivers/md/md-multipath.h b/drivers/md/md-multipath.h
deleted file mode 100644 (file)
index b3099e5..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _MULTIPATH_H
-#define _MULTIPATH_H
-
-struct multipath_info {
-       struct md_rdev  *rdev;
-};
-
-struct mpconf {
-       struct mddev                    *mddev;
-       struct multipath_info   *multipaths;
-       int                     raid_disks;
-       spinlock_t              device_lock;
-       struct list_head        retry_list;
-
-       mempool_t               pool;
-};
-
-/*
- * this is our 'private' 'collective' MULTIPATH buffer head.
- * it contains information about what kind of IO operations were started
- * for this MULTIPATH operation, and about their status:
- */
-
-struct multipath_bh {
-       struct mddev                    *mddev;
-       struct bio              *master_bio;
-       struct bio              bio;
-       int                     path;
-       struct list_head        retry_list;
-};
-#endif
index 2266358d807466f95d02b431d09ee39805dff5e8..e575e74aabf5efc8f6660b73166f59cffcbc4d19 100644 (file)
@@ -65,7 +65,6 @@
 #include <linux/percpu-refcount.h>
 #include <linux/part_stat.h>
 
-#include <trace/events/block.h>
 #include "md.h"
 #include "md-bitmap.h"
 #include "md-cluster.h"
@@ -99,18 +98,6 @@ static void mddev_detach(struct mddev *mddev);
 static void export_rdev(struct md_rdev *rdev, struct mddev *mddev);
 static void md_wakeup_thread_directly(struct md_thread __rcu *thread);
 
-enum md_ro_state {
-       MD_RDWR,
-       MD_RDONLY,
-       MD_AUTO_READ,
-       MD_MAX_STATE
-};
-
-static bool md_is_rdwr(struct mddev *mddev)
-{
-       return (mddev->ro == MD_RDWR);
-}
-
 /*
  * Default number of read corrections we'll attempt on an rdev
  * before ejecting it from the array. We divide the read error
@@ -378,7 +365,7 @@ static bool is_suspended(struct mddev *mddev, struct bio *bio)
        return true;
 }
 
-void md_handle_request(struct mddev *mddev, struct bio *bio)
+bool md_handle_request(struct mddev *mddev, struct bio *bio)
 {
 check_suspended:
        if (is_suspended(mddev, bio)) {
@@ -386,7 +373,7 @@ check_suspended:
                /* Bail out if REQ_NOWAIT is set for the bio */
                if (bio->bi_opf & REQ_NOWAIT) {
                        bio_wouldblock_error(bio);
-                       return;
+                       return true;
                }
                for (;;) {
                        prepare_to_wait(&mddev->sb_wait, &__wait,
@@ -402,10 +389,13 @@ check_suspended:
 
        if (!mddev->pers->make_request(mddev, bio)) {
                percpu_ref_put(&mddev->active_io);
+               if (!mddev->gendisk && mddev->pers->prepare_suspend)
+                       return false;
                goto check_suspended;
        }
 
        percpu_ref_put(&mddev->active_io);
+       return true;
 }
 EXPORT_SYMBOL(md_handle_request);
 
@@ -529,6 +519,24 @@ void mddev_resume(struct mddev *mddev)
 }
 EXPORT_SYMBOL_GPL(mddev_resume);
 
+/* sync bdev before setting device to readonly or stopping raid*/
+static int mddev_set_closing_and_sync_blockdev(struct mddev *mddev, int opener_num)
+{
+       mutex_lock(&mddev->open_mutex);
+       if (mddev->pers && atomic_read(&mddev->openers) > opener_num) {
+               mutex_unlock(&mddev->open_mutex);
+               return -EBUSY;
+       }
+       if (test_and_set_bit(MD_CLOSING, &mddev->flags)) {
+               mutex_unlock(&mddev->open_mutex);
+               return -EBUSY;
+       }
+       mutex_unlock(&mddev->open_mutex);
+
+       sync_blockdev(mddev->gendisk->part0);
+       return 0;
+}
+
 /*
  * Generic flush handling for md
  */
@@ -579,8 +587,12 @@ static void submit_flushes(struct work_struct *ws)
                        rcu_read_lock();
                }
        rcu_read_unlock();
-       if (atomic_dec_and_test(&mddev->flush_pending))
+       if (atomic_dec_and_test(&mddev->flush_pending)) {
+               /* The pair is percpu_ref_get() from md_flush_request() */
+               percpu_ref_put(&mddev->active_io);
+
                queue_work(md_wq, &mddev->flush_work);
+       }
 }
 
 static void md_submit_flush_data(struct work_struct *ws)
@@ -2402,7 +2414,7 @@ int md_integrity_register(struct mddev *mddev)
 
        if (list_empty(&mddev->disks))
                return 0; /* nothing to do */
-       if (!mddev->gendisk || blk_get_integrity(mddev->gendisk))
+       if (mddev_is_dm(mddev) || blk_get_integrity(mddev->gendisk))
                return 0; /* shouldn't register, or already is */
        rdev_for_each(rdev, mddev) {
                /* skip spares and non-functional disks */
@@ -2455,7 +2467,7 @@ int md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev)
 {
        struct blk_integrity *bi_mddev;
 
-       if (!mddev->gendisk)
+       if (mddev_is_dm(mddev))
                return 0;
 
        bi_mddev = blk_get_integrity(mddev->gendisk);
@@ -2562,6 +2574,7 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
  fail:
        pr_warn("md: failed to register dev-%s for %s\n",
                b, mdname(mddev));
+       mddev_destroy_serial_pool(mddev, rdev);
        return err;
 }
 
@@ -2578,7 +2591,7 @@ static void export_rdev(struct md_rdev *rdev, struct mddev *mddev)
        if (test_bit(AutoDetected, &rdev->flags))
                md_autodetect_dev(rdev->bdev->bd_dev);
 #endif
-       bdev_release(rdev->bdev_handle);
+       fput(rdev->bdev_file);
        rdev->bdev = NULL;
        kobject_put(&rdev->kobj);
 }
@@ -2591,7 +2604,7 @@ static void md_kick_rdev_from_array(struct md_rdev *rdev)
        list_del_rcu(&rdev->same_set);
        pr_debug("md: unbind<%pg>\n", rdev->bdev);
        mddev_destroy_serial_pool(rdev->mddev, rdev);
-       rdev->mddev = NULL;
+       WRITE_ONCE(rdev->mddev, NULL);
        sysfs_remove_link(&rdev->kobj, "block");
        sysfs_put(rdev->sysfs_state);
        sysfs_put(rdev->sysfs_unack_badblocks);
@@ -2847,8 +2860,7 @@ repeat:
        pr_debug("md: updating %s RAID superblock on device (in sync %d)\n",
                 mdname(mddev), mddev->in_sync);
 
-       if (mddev->queue)
-               blk_add_trace_msg(mddev->queue, "md md_update_sb");
+       mddev_add_trace_msg(mddev, "md md_update_sb");
 rewrite:
        md_bitmap_update_sb(mddev->bitmap);
        rdev_for_each(rdev, mddev) {
@@ -2929,7 +2941,6 @@ static int add_bound_rdev(struct md_rdev *rdev)
                set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
        set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        md_new_event();
-       md_wakeup_thread(mddev->thread);
        return 0;
 }
 
@@ -3044,10 +3055,8 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
 
                        if (err == 0) {
                                md_kick_rdev_from_array(rdev);
-                               if (mddev->pers) {
+                               if (mddev->pers)
                                        set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
-                                       md_wakeup_thread(mddev->thread);
-                               }
                                md_new_event();
                        }
                }
@@ -3077,7 +3086,6 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
                clear_bit(BlockedBadBlocks, &rdev->flags);
                wake_up(&rdev->blocked_wait);
                set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
-               md_wakeup_thread(rdev->mddev->thread);
 
                err = 0;
        } else if (cmd_match(buf, "insync") && rdev->raid_disk == -1) {
@@ -3115,7 +3123,6 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
                    !test_bit(Replacement, &rdev->flags))
                        set_bit(WantReplacement, &rdev->flags);
                set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
-               md_wakeup_thread(rdev->mddev->thread);
                err = 0;
        } else if (cmd_match(buf, "-want_replacement")) {
                /* Clearing 'want_replacement' is always allowed.
@@ -3245,7 +3252,6 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len)
                if (rdev->raid_disk >= 0)
                        return -EBUSY;
                set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
-               md_wakeup_thread(rdev->mddev->thread);
        } else if (rdev->mddev->pers) {
                /* Activating a spare .. or possibly reactivating
                 * if we ever get bitmaps working here.
@@ -3339,8 +3345,7 @@ static ssize_t new_offset_store(struct md_rdev *rdev,
        if (kstrtoull(buf, 10, &new_offset) < 0)
                return -EINVAL;
 
-       if (mddev->sync_thread ||
-           test_bit(MD_RECOVERY_RUNNING,&mddev->recovery))
+       if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
                return -EBUSY;
        if (new_offset == rdev->data_offset)
                /* reset is always permitted */
@@ -3671,7 +3676,7 @@ rdev_attr_store(struct kobject *kobj, struct attribute *attr,
        struct kernfs_node *kn = NULL;
        bool suspend = false;
        ssize_t rv;
-       struct mddev *mddev = rdev->mddev;
+       struct mddev *mddev = READ_ONCE(rdev->mddev);
 
        if (!entry->store)
                return -EIO;
@@ -3773,16 +3778,16 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe
        if (err)
                goto out_clear_rdev;
 
-       rdev->bdev_handle = bdev_open_by_dev(newdev,
+       rdev->bdev_file = bdev_file_open_by_dev(newdev,
                        BLK_OPEN_READ | BLK_OPEN_WRITE,
                        super_format == -2 ? &claim_rdev : rdev, NULL);
-       if (IS_ERR(rdev->bdev_handle)) {
+       if (IS_ERR(rdev->bdev_file)) {
                pr_warn("md: could not open device unknown-block(%u,%u).\n",
                        MAJOR(newdev), MINOR(newdev));
-               err = PTR_ERR(rdev->bdev_handle);
+               err = PTR_ERR(rdev->bdev_file);
                goto out_clear_rdev;
        }
-       rdev->bdev = rdev->bdev_handle->bdev;
+       rdev->bdev = file_bdev(rdev->bdev_file);
 
        kobject_init(&rdev->kobj, &rdev_ktype);
 
@@ -3813,7 +3818,7 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe
        return rdev;
 
 out_blkdev_put:
-       bdev_release(rdev->bdev_handle);
+       fput(rdev->bdev_file);
 out_clear_rdev:
        md_rdev_clear(rdev);
 out_free_rdev:
@@ -4013,8 +4018,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
         */
 
        rv = -EBUSY;
-       if (mddev->sync_thread ||
-           test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+       if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
            mddev->reshape_position != MaxSector ||
            mddev->sysfs_active)
                goto out_unlock;
@@ -4164,7 +4168,6 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
                mddev->in_sync = 1;
                del_timer_sync(&mddev->safemode_timer);
        }
-       blk_set_stacking_limits(&mddev->queue->limits);
        pers->run(mddev);
        set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
        if (!mddev->thread)
@@ -4471,8 +4474,8 @@ array_state_show(struct mddev *mddev, char *page)
        return sprintf(page, "%s\n", array_states[st]);
 }
 
-static int do_md_stop(struct mddev *mddev, int ro, struct block_device *bdev);
-static int md_set_readonly(struct mddev *mddev, struct block_device *bdev);
+static int do_md_stop(struct mddev *mddev, int ro);
+static int md_set_readonly(struct mddev *mddev);
 static int restart_array(struct mddev *mddev);
 
 static ssize_t
@@ -4489,6 +4492,17 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
        case broken:            /* cannot be set */
        case bad_word:
                return -EINVAL;
+       case clear:
+       case readonly:
+       case inactive:
+       case read_auto:
+               if (!mddev->pers || !md_is_rdwr(mddev))
+                       break;
+               /* write sysfs will not open mddev and opener should be 0 */
+               err = mddev_set_closing_and_sync_blockdev(mddev, 0);
+               if (err)
+                       return err;
+               break;
        default:
                break;
        }
@@ -4522,14 +4536,14 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
        case inactive:
                /* stop an active array, return 0 otherwise */
                if (mddev->pers)
-                       err = do_md_stop(mddev, 2, NULL);
+                       err = do_md_stop(mddev, 2);
                break;
        case clear:
-               err = do_md_stop(mddev, 0, NULL);
+               err = do_md_stop(mddev, 0);
                break;
        case readonly:
                if (mddev->pers)
-                       err = md_set_readonly(mddev, NULL);
+                       err = md_set_readonly(mddev);
                else {
                        mddev->ro = MD_RDONLY;
                        set_disk_ro(mddev->gendisk, 1);
@@ -4539,7 +4553,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
        case read_auto:
                if (mddev->pers) {
                        if (md_is_rdwr(mddev))
-                               err = md_set_readonly(mddev, NULL);
+                               err = md_set_readonly(mddev);
                        else if (mddev->ro == MD_RDONLY)
                                err = restart_array(mddev);
                        if (err == 0) {
@@ -4588,6 +4602,11 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
                sysfs_notify_dirent_safe(mddev->sysfs_state);
        }
        mddev_unlock(mddev);
+
+       if (st == readonly || st == read_auto || st == inactive ||
+           (err && st == clear))
+               clear_bit(MD_CLOSING, &mddev->flags);
+
        return err ?: len;
 }
 static struct md_sysfs_entry md_array_state =
@@ -4915,6 +4934,35 @@ static void stop_sync_thread(struct mddev *mddev, bool locked, bool check_seq)
                mddev_lock_nointr(mddev);
 }
 
+void md_idle_sync_thread(struct mddev *mddev)
+{
+       lockdep_assert_held(&mddev->reconfig_mutex);
+
+       clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+       stop_sync_thread(mddev, true, true);
+}
+EXPORT_SYMBOL_GPL(md_idle_sync_thread);
+
+void md_frozen_sync_thread(struct mddev *mddev)
+{
+       lockdep_assert_held(&mddev->reconfig_mutex);
+
+       set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+       stop_sync_thread(mddev, true, false);
+}
+EXPORT_SYMBOL_GPL(md_frozen_sync_thread);
+
+void md_unfrozen_sync_thread(struct mddev *mddev)
+{
+       lockdep_assert_held(&mddev->reconfig_mutex);
+
+       clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+       set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+       md_wakeup_thread(mddev->thread);
+       sysfs_notify_dirent_safe(mddev->sysfs_action);
+}
+EXPORT_SYMBOL_GPL(md_unfrozen_sync_thread);
+
 static void idle_sync_thread(struct mddev *mddev)
 {
        mutex_lock(&mddev->sync_mutex);
@@ -5706,6 +5754,51 @@ static const struct kobj_type md_ktype = {
 
 int mdp_major = 0;
 
+/* stack the limit for all rdevs into lim */
+void mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim)
+{
+       struct md_rdev *rdev;
+
+       rdev_for_each(rdev, mddev) {
+               queue_limits_stack_bdev(lim, rdev->bdev, rdev->data_offset,
+                                       mddev->gendisk->disk_name);
+       }
+}
+EXPORT_SYMBOL_GPL(mddev_stack_rdev_limits);
+
+/* apply the extra stacking limits from a new rdev into mddev */
+int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev)
+{
+       struct queue_limits lim;
+
+       if (mddev_is_dm(mddev))
+               return 0;
+
+       lim = queue_limits_start_update(mddev->gendisk->queue);
+       queue_limits_stack_bdev(&lim, rdev->bdev, rdev->data_offset,
+                               mddev->gendisk->disk_name);
+       return queue_limits_commit_update(mddev->gendisk->queue, &lim);
+}
+EXPORT_SYMBOL_GPL(mddev_stack_new_rdev);
+
+/* update the optimal I/O size after a reshape */
+void mddev_update_io_opt(struct mddev *mddev, unsigned int nr_stripes)
+{
+       struct queue_limits lim;
+
+       if (mddev_is_dm(mddev))
+               return;
+
+       /* don't bother updating io_opt if we can't suspend the array */
+       if (mddev_suspend(mddev, false) < 0)
+               return;
+       lim = queue_limits_start_update(mddev->gendisk->queue);
+       lim.io_opt = lim.io_min * nr_stripes;
+       queue_limits_commit_update(mddev->gendisk->queue, &lim);
+       mddev_resume(mddev);
+}
+EXPORT_SYMBOL_GPL(mddev_update_io_opt);
+
 static void mddev_delayed_delete(struct work_struct *ws)
 {
        struct mddev *mddev = container_of(ws, struct mddev, del_work);
@@ -5770,10 +5863,11 @@ struct mddev *md_alloc(dev_t dev, char *name)
                 */
                mddev->hold_active = UNTIL_STOP;
 
-       error = -ENOMEM;
-       disk = blk_alloc_disk(NUMA_NO_NODE);
-       if (!disk)
+       disk = blk_alloc_disk(NULL, NUMA_NO_NODE);
+       if (IS_ERR(disk)) {
+               error = PTR_ERR(disk);
                goto out_free_mddev;
+       }
 
        disk->major = MAJOR(mddev->unit);
        disk->first_minor = unit << shift;
@@ -5787,9 +5881,7 @@ struct mddev *md_alloc(dev_t dev, char *name)
        disk->fops = &md_fops;
        disk->private_data = mddev;
 
-       mddev->queue = disk->queue;
-       blk_set_stacking_limits(&mddev->queue->limits);
-       blk_queue_write_cache(mddev->queue, true, true);
+       blk_queue_write_cache(disk->queue, true, true);
        disk->events |= DISK_EVENT_MEDIA_CHANGE;
        mddev->gendisk = disk;
        error = add_disk(disk);
@@ -5931,7 +6023,7 @@ int md_run(struct mddev *mddev)
                invalidate_bdev(rdev->bdev);
                if (mddev->ro != MD_RDONLY && rdev_read_only(rdev)) {
                        mddev->ro = MD_RDONLY;
-                       if (mddev->gendisk)
+                       if (!mddev_is_dm(mddev))
                                set_disk_ro(mddev->gendisk, 1);
                }
 
@@ -6034,7 +6126,10 @@ int md_run(struct mddev *mddev)
                        pr_warn("True protection against single-disk failure might be compromised.\n");
        }
 
-       mddev->recovery = 0;
+       /* dm-raid expect sync_thread to be frozen until resume */
+       if (mddev->gendisk)
+               mddev->recovery = 0;
+
        /* may be over-ridden by personality */
        mddev->resync_max_sectors = mddev->dev_sectors;
 
@@ -6090,7 +6185,8 @@ int md_run(struct mddev *mddev)
                }
        }
 
-       if (mddev->queue) {
+       if (!mddev_is_dm(mddev)) {
+               struct request_queue *q = mddev->gendisk->queue;
                bool nonrot = true;
 
                rdev_for_each(rdev, mddev) {
@@ -6102,14 +6198,14 @@ int md_run(struct mddev *mddev)
                if (mddev->degraded)
                        nonrot = false;
                if (nonrot)
-                       blk_queue_flag_set(QUEUE_FLAG_NONROT, mddev->queue);
+                       blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
                else
-                       blk_queue_flag_clear(QUEUE_FLAG_NONROT, mddev->queue);
-               blk_queue_flag_set(QUEUE_FLAG_IO_STAT, mddev->queue);
+                       blk_queue_flag_clear(QUEUE_FLAG_NONROT, q);
+               blk_queue_flag_set(QUEUE_FLAG_IO_STAT, q);
 
                /* Set the NOWAIT flags if all underlying devices support it */
                if (nowait)
-                       blk_queue_flag_set(QUEUE_FLAG_NOWAIT, mddev->queue);
+                       blk_queue_flag_set(QUEUE_FLAG_NOWAIT, q);
        }
        if (pers->sync_request) {
                if (mddev->kobj.sd &&
@@ -6188,7 +6284,6 @@ int do_md_run(struct mddev *mddev)
        /* run start up tasks that require md_thread */
        md_start(mddev);
 
-       md_wakeup_thread(mddev->thread);
        md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
 
        set_capacity_and_notify(mddev->gendisk, mddev->array_sectors);
@@ -6209,7 +6304,6 @@ int md_start(struct mddev *mddev)
 
        if (mddev->pers->start) {
                set_bit(MD_RECOVERY_WAIT, &mddev->recovery);
-               md_wakeup_thread(mddev->thread);
                ret = mddev->pers->start(mddev);
                clear_bit(MD_RECOVERY_WAIT, &mddev->recovery);
                md_wakeup_thread(mddev->sync_thread);
@@ -6254,7 +6348,6 @@ static int restart_array(struct mddev *mddev)
        pr_debug("md: %s switched to read-write mode.\n", mdname(mddev));
        /* Kick recovery or resync if necessary */
        set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
-       md_wakeup_thread(mddev->thread);
        md_wakeup_thread(mddev->sync_thread);
        sysfs_notify_dirent_safe(mddev->sysfs_state);
        return 0;
@@ -6274,7 +6367,15 @@ static void md_clean(struct mddev *mddev)
        mddev->persistent = 0;
        mddev->level = LEVEL_NONE;
        mddev->clevel[0] = 0;
-       mddev->flags = 0;
+       /*
+        * Don't clear MD_CLOSING, or mddev can be opened again.
+        * 'hold_active != 0' means mddev is still in the creation
+        * process and will be used later.
+        */
+       if (mddev->hold_active)
+               mddev->flags = 0;
+       else
+               mddev->flags &= BIT_ULL_MASK(MD_CLOSING);
        mddev->sb_flags = 0;
        mddev->ro = MD_RDWR;
        mddev->metadata_type[0] = 0;
@@ -6311,7 +6412,6 @@ static void md_clean(struct mddev *mddev)
 
 static void __md_stop_writes(struct mddev *mddev)
 {
-       stop_sync_thread(mddev, true, false);
        del_timer_sync(&mddev->safemode_timer);
 
        if (mddev->pers && mddev->pers->quiesce) {
@@ -6336,6 +6436,8 @@ static void __md_stop_writes(struct mddev *mddev)
 void md_stop_writes(struct mddev *mddev)
 {
        mddev_lock_nointr(mddev);
+       set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+       stop_sync_thread(mddev, true, false);
        __md_stop_writes(mddev);
        mddev_unlock(mddev);
 }
@@ -6349,8 +6451,10 @@ static void mddev_detach(struct mddev *mddev)
                mddev->pers->quiesce(mddev, 0);
        }
        md_unregister_thread(mddev, &mddev->thread);
-       if (mddev->queue)
-               blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
+
+       /* the unplug fn references 'conf' */
+       if (!mddev_is_dm(mddev))
+               blk_sync_queue(mddev->gendisk->queue);
 }
 
 static void __md_stop(struct mddev *mddev)
@@ -6387,7 +6491,8 @@ void md_stop(struct mddev *mddev)
 
 EXPORT_SYMBOL_GPL(md_stop);
 
-static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
+/* ensure 'mddev->pers' exist before calling md_set_readonly() */
+static int md_set_readonly(struct mddev *mddev)
 {
        int err = 0;
        int did_freeze = 0;
@@ -6398,7 +6503,6 @@ static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
        if (!test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) {
                did_freeze = 1;
                set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
-               md_wakeup_thread(mddev->thread);
        }
 
        stop_sync_thread(mddev, false, false);
@@ -6406,36 +6510,29 @@ static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
                   !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
        mddev_lock_nointr(mddev);
 
-       mutex_lock(&mddev->open_mutex);
-       if ((mddev->pers && atomic_read(&mddev->openers) > !!bdev) ||
-           mddev->sync_thread ||
-           test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
+       if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
                pr_warn("md: %s still in use.\n",mdname(mddev));
                err = -EBUSY;
                goto out;
        }
 
-       if (mddev->pers) {
-               __md_stop_writes(mddev);
-
-               if (mddev->ro == MD_RDONLY) {
-                       err  = -ENXIO;
-                       goto out;
-               }
+       __md_stop_writes(mddev);
 
-               mddev->ro = MD_RDONLY;
-               set_disk_ro(mddev->gendisk, 1);
+       if (mddev->ro == MD_RDONLY) {
+               err  = -ENXIO;
+               goto out;
        }
 
+       mddev->ro = MD_RDONLY;
+       set_disk_ro(mddev->gendisk, 1);
+
 out:
-       if ((mddev->pers && !err) || did_freeze) {
+       if (!err || did_freeze) {
                clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
                set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
-               md_wakeup_thread(mddev->thread);
                sysfs_notify_dirent_safe(mddev->sysfs_state);
        }
 
-       mutex_unlock(&mddev->open_mutex);
        return err;
 }
 
@@ -6443,8 +6540,7 @@ out:
  *   0 - completely stop and dis-assemble array
  *   2 - stop but do not disassemble array
  */
-static int do_md_stop(struct mddev *mddev, int mode,
-                     struct block_device *bdev)
+static int do_md_stop(struct mddev *mddev, int mode)
 {
        struct gendisk *disk = mddev->gendisk;
        struct md_rdev *rdev;
@@ -6453,22 +6549,16 @@ static int do_md_stop(struct mddev *mddev, int mode,
        if (!test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) {
                did_freeze = 1;
                set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
-               md_wakeup_thread(mddev->thread);
        }
 
        stop_sync_thread(mddev, true, false);
 
-       mutex_lock(&mddev->open_mutex);
-       if ((mddev->pers && atomic_read(&mddev->openers) > !!bdev) ||
-           mddev->sysfs_active ||
-           mddev->sync_thread ||
+       if (mddev->sysfs_active ||
            test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
                pr_warn("md: %s still in use.\n",mdname(mddev));
-               mutex_unlock(&mddev->open_mutex);
                if (did_freeze) {
                        clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
                        set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
-                       md_wakeup_thread(mddev->thread);
                }
                return -EBUSY;
        }
@@ -6487,13 +6577,11 @@ static int do_md_stop(struct mddev *mddev, int mode,
                                sysfs_unlink_rdev(mddev, rdev);
 
                set_capacity_and_notify(disk, 0);
-               mutex_unlock(&mddev->open_mutex);
                mddev->changed = 1;
 
                if (!md_is_rdwr(mddev))
                        mddev->ro = MD_RDWR;
-       } else
-               mutex_unlock(&mddev->open_mutex);
+       }
        /*
         * Free resources if final stop
         */
@@ -6539,7 +6627,7 @@ static void autorun_array(struct mddev *mddev)
        err = do_md_run(mddev);
        if (err) {
                pr_warn("md: do_md_run() returned %d\n", err);
-               do_md_stop(mddev, 0, NULL);
+               do_md_stop(mddev, 0);
        }
 }
 
@@ -7009,9 +7097,7 @@ kick_rdev:
 
        md_kick_rdev_from_array(rdev);
        set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
-       if (mddev->thread)
-               md_wakeup_thread(mddev->thread);
-       else
+       if (!mddev->thread)
                md_update_sb(mddev, 1);
        md_new_event();
 
@@ -7086,14 +7172,13 @@ static int hot_add_disk(struct mddev *mddev, dev_t dev)
        if (!bdev_nowait(rdev->bdev)) {
                pr_info("%s: Disabling nowait because %pg does not support nowait\n",
                        mdname(mddev), rdev->bdev);
-               blk_queue_flag_clear(QUEUE_FLAG_NOWAIT, mddev->queue);
+               blk_queue_flag_clear(QUEUE_FLAG_NOWAIT, mddev->gendisk->queue);
        }
        /*
         * Kick recovery, maybe this spare has to be added to the
         * array immediately.
         */
        set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
-       md_wakeup_thread(mddev->thread);
        md_new_event();
        return 0;
 
@@ -7307,8 +7392,7 @@ static int update_size(struct mddev *mddev, sector_t num_sectors)
         * of each device.  If num_sectors is zero, we find the largest size
         * that fits.
         */
-       if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
-           mddev->sync_thread)
+       if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
                return -EBUSY;
        if (!md_is_rdwr(mddev))
                return -EROFS;
@@ -7325,10 +7409,9 @@ static int update_size(struct mddev *mddev, sector_t num_sectors)
        if (!rv) {
                if (mddev_is_clustered(mddev))
                        md_cluster_ops->update_size(mddev, old_dev_sectors);
-               else if (mddev->queue) {
+               else if (!mddev_is_dm(mddev))
                        set_capacity_and_notify(mddev->gendisk,
                                                mddev->array_sectors);
-               }
        }
        return rv;
 }
@@ -7345,8 +7428,7 @@ static int update_raid_disks(struct mddev *mddev, int raid_disks)
        if (raid_disks <= 0 ||
            (mddev->max_disks && raid_disks >= mddev->max_disks))
                return -EINVAL;
-       if (mddev->sync_thread ||
-           test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+       if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
            test_bit(MD_RESYNCING_REMOTE, &mddev->recovery) ||
            mddev->reshape_position != MaxSector)
                return -EBUSY;
@@ -7542,16 +7624,17 @@ static int md_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
-static inline bool md_ioctl_valid(unsigned int cmd)
+static inline int md_ioctl_valid(unsigned int cmd)
 {
        switch (cmd) {
-       case ADD_NEW_DISK:
        case GET_ARRAY_INFO:
-       case GET_BITMAP_FILE:
        case GET_DISK_INFO:
+       case RAID_VERSION:
+               return 0;
+       case ADD_NEW_DISK:
+       case GET_BITMAP_FILE:
        case HOT_ADD_DISK:
        case HOT_REMOVE_DISK:
-       case RAID_VERSION:
        case RESTART_ARRAY_RW:
        case RUN_ARRAY:
        case SET_ARRAY_INFO:
@@ -7560,9 +7643,11 @@ static inline bool md_ioctl_valid(unsigned int cmd)
        case STOP_ARRAY:
        case STOP_ARRAY_RO:
        case CLUSTERED_DISK_NACK:
-               return true;
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EACCES;
+               return 0;
        default:
-               return false;
+               return -ENOTTY;
        }
 }
 
@@ -7620,31 +7705,17 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
        int err = 0;
        void __user *argp = (void __user *)arg;
        struct mddev *mddev = NULL;
-       bool did_set_md_closing = false;
-
-       if (!md_ioctl_valid(cmd))
-               return -ENOTTY;
 
-       switch (cmd) {
-       case RAID_VERSION:
-       case GET_ARRAY_INFO:
-       case GET_DISK_INFO:
-               break;
-       default:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EACCES;
-       }
+       err = md_ioctl_valid(cmd);
+       if (err)
+               return err;
 
        /*
         * Commands dealing with the RAID driver but not any
         * particular array:
         */
-       switch (cmd) {
-       case RAID_VERSION:
-               err = get_version(argp);
-               goto out;
-       default:;
-       }
+       if (cmd == RAID_VERSION)
+               return get_version(argp);
 
        /*
         * Commands creating/starting a new array:
@@ -7652,35 +7723,23 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
 
        mddev = bdev->bd_disk->private_data;
 
-       if (!mddev) {
-               BUG();
-               goto out;
-       }
-
        /* Some actions do not requires the mutex */
        switch (cmd) {
        case GET_ARRAY_INFO:
                if (!mddev->raid_disks && !mddev->external)
-                       err = -ENODEV;
-               else
-                       err = get_array_info(mddev, argp);
-               goto out;
+                       return -ENODEV;
+               return get_array_info(mddev, argp);
 
        case GET_DISK_INFO:
                if (!mddev->raid_disks && !mddev->external)
-                       err = -ENODEV;
-               else
-                       err = get_disk_info(mddev, argp);
-               goto out;
+                       return -ENODEV;
+               return get_disk_info(mddev, argp);
 
        case SET_DISK_FAULTY:
-               err = set_disk_faulty(mddev, new_decode_dev(arg));
-               goto out;
+               return set_disk_faulty(mddev, new_decode_dev(arg));
 
        case GET_BITMAP_FILE:
-               err = get_bitmap_file(mddev, argp);
-               goto out;
-
+               return get_bitmap_file(mddev, argp);
        }
 
        if (cmd == HOT_REMOVE_DISK)
@@ -7693,20 +7752,9 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
                /* Need to flush page cache, and ensure no-one else opens
                 * and writes
                 */
-               mutex_lock(&mddev->open_mutex);
-               if (mddev->pers && atomic_read(&mddev->openers) > 1) {
-                       mutex_unlock(&mddev->open_mutex);
-                       err = -EBUSY;
-                       goto out;
-               }
-               if (test_and_set_bit(MD_CLOSING, &mddev->flags)) {
-                       mutex_unlock(&mddev->open_mutex);
-                       err = -EBUSY;
-                       goto out;
-               }
-               did_set_md_closing = true;
-               mutex_unlock(&mddev->open_mutex);
-               sync_blockdev(bdev);
+               err = mddev_set_closing_and_sync_blockdev(mddev, 1);
+               if (err)
+                       return err;
        }
 
        if (!md_is_rdwr(mddev))
@@ -7747,11 +7795,12 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
                goto unlock;
 
        case STOP_ARRAY:
-               err = do_md_stop(mddev, 0, bdev);
+               err = do_md_stop(mddev, 0);
                goto unlock;
 
        case STOP_ARRAY_RO:
-               err = md_set_readonly(mddev, bdev);
+               if (mddev->pers)
+                       err = md_set_readonly(mddev);
                goto unlock;
 
        case HOT_REMOVE_DISK:
@@ -7846,7 +7895,7 @@ unlock:
                                     mddev_unlock(mddev);
 
 out:
-       if(did_set_md_closing)
+       if (cmd == STOP_ARRAY_RO || (err && cmd == STOP_ARRAY))
                clear_bit(MD_CLOSING, &mddev->flags);
        return err;
 }
@@ -8683,10 +8732,7 @@ void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
 
        bio_chain(discard_bio, bio);
        bio_clone_blkg_association(discard_bio, bio);
-       if (mddev->gendisk)
-               trace_block_bio_remap(discard_bio,
-                               disk_devt(mddev->gendisk),
-                               bio->bi_iter.bi_sector);
+       mddev_trace_remap(mddev, discard_bio, bio->bi_iter.bi_sector);
        submit_bio_noacct(discard_bio);
 }
 EXPORT_SYMBOL_GPL(md_submit_discard_bio);
@@ -8733,6 +8779,23 @@ void md_account_bio(struct mddev *mddev, struct bio **bio)
 }
 EXPORT_SYMBOL_GPL(md_account_bio);
 
+void md_free_cloned_bio(struct bio *bio)
+{
+       struct md_io_clone *md_io_clone = bio->bi_private;
+       struct bio *orig_bio = md_io_clone->orig_bio;
+       struct mddev *mddev = md_io_clone->mddev;
+
+       if (bio->bi_status && !orig_bio->bi_status)
+               orig_bio->bi_status = bio->bi_status;
+
+       if (md_io_clone->start_time)
+               bio_end_io_acct(orig_bio, md_io_clone->start_time);
+
+       bio_put(bio);
+       percpu_ref_put(&mddev->active_io);
+}
+EXPORT_SYMBOL_GPL(md_free_cloned_bio);
+
 /* md_allow_write(mddev)
  * Calling this ensures that the array is marked 'active' so that writes
  * may proceed without blocking.  It is important to call this before
@@ -8788,12 +8851,16 @@ void md_do_sync(struct md_thread *thread)
        int ret;
 
        /* just incase thread restarts... */
-       if (test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
-           test_bit(MD_RECOVERY_WAIT, &mddev->recovery))
+       if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
                return;
-       if (!md_is_rdwr(mddev)) {/* never try to sync a read-only array */
+
+       if (test_bit(MD_RECOVERY_INTR, &mddev->recovery))
+               goto skip;
+
+       if (test_bit(MD_RECOVERY_WAIT, &mddev->recovery) ||
+           !md_is_rdwr(mddev)) {/* never try to sync a read-only array */
                set_bit(MD_RECOVERY_INTR, &mddev->recovery);
-               return;
+               goto skip;
        }
 
        if (mddev_is_clustered(mddev)) {
@@ -9162,7 +9229,7 @@ void md_do_sync(struct md_thread *thread)
                        mddev->delta_disks > 0 &&
                        mddev->pers->finish_reshape &&
                        mddev->pers->size &&
-                       mddev->queue) {
+                       !mddev_is_dm(mddev)) {
                mddev_lock_nointr(mddev);
                md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0));
                mddev_unlock(mddev);
@@ -9262,9 +9329,14 @@ static bool md_spares_need_change(struct mddev *mddev)
 {
        struct md_rdev *rdev;
 
-       rdev_for_each(rdev, mddev)
-               if (rdev_removeable(rdev) || rdev_addable(rdev))
+       rcu_read_lock();
+       rdev_for_each_rcu(rdev, mddev) {
+               if (rdev_removeable(rdev) || rdev_addable(rdev)) {
+                       rcu_read_unlock();
                        return true;
+               }
+       }
+       rcu_read_unlock();
        return false;
 }
 
@@ -9368,13 +9440,19 @@ static void md_start_sync(struct work_struct *ws)
        struct mddev *mddev = container_of(ws, struct mddev, sync_work);
        int spares = 0;
        bool suspend = false;
+       char *name;
 
-       if (md_spares_need_change(mddev))
+       /*
+        * If reshape is still in progress, spares won't be added or removed
+        * from conf until reshape is done.
+        */
+       if (mddev->reshape_position == MaxSector &&
+           md_spares_need_change(mddev)) {
                suspend = true;
+               mddev_suspend(mddev, false);
+       }
 
-       suspend ? mddev_suspend_and_lock_nointr(mddev) :
-                 mddev_lock_nointr(mddev);
-
+       mddev_lock_nointr(mddev);
        if (!md_is_rdwr(mddev)) {
                /*
                 * On a read-only array we can:
@@ -9400,8 +9478,10 @@ static void md_start_sync(struct work_struct *ws)
        if (spares)
                md_bitmap_write_all(mddev->bitmap);
 
+       name = test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) ?
+                       "reshape" : "resync";
        rcu_assign_pointer(mddev->sync_thread,
-                          md_register_thread(md_do_sync, mddev, "resync"));
+                          md_register_thread(md_do_sync, mddev, name));
        if (!mddev->sync_thread) {
                pr_warn("%s: could not start resync thread...\n",
                        mdname(mddev));
@@ -9445,6 +9525,20 @@ not_running:
                sysfs_notify_dirent_safe(mddev->sysfs_action);
 }
 
+static void unregister_sync_thread(struct mddev *mddev)
+{
+       if (!test_bit(MD_RECOVERY_DONE, &mddev->recovery)) {
+               /* resync/recovery still happening */
+               clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+               return;
+       }
+
+       if (WARN_ON_ONCE(!mddev->sync_thread))
+               return;
+
+       md_reap_sync_thread(mddev);
+}
+
 /*
  * This routine is regularly called by all per-raid-array threads to
  * deal with generic issues like resync and super-block update.
@@ -9469,9 +9563,6 @@ not_running:
  */
 void md_check_recovery(struct mddev *mddev)
 {
-       if (READ_ONCE(mddev->suspended))
-               return;
-
        if (mddev->bitmap)
                md_bitmap_daemon_work(mddev);
 
@@ -9485,7 +9576,8 @@ void md_check_recovery(struct mddev *mddev)
        }
 
        if (!md_is_rdwr(mddev) &&
-           !test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
+           !test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) &&
+           !test_bit(MD_RECOVERY_DONE, &mddev->recovery))
                return;
        if ( ! (
                (mddev->sb_flags & ~ (1<<MD_SB_CHANGE_PENDING)) ||
@@ -9507,8 +9599,7 @@ void md_check_recovery(struct mddev *mddev)
                        struct md_rdev *rdev;
 
                        if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
-                               /* sync_work already queued. */
-                               clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+                               unregister_sync_thread(mddev);
                                goto unlock;
                        }
 
@@ -9571,16 +9662,7 @@ void md_check_recovery(struct mddev *mddev)
                 * still set.
                 */
                if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
-                       if (!test_bit(MD_RECOVERY_DONE, &mddev->recovery)) {
-                               /* resync/recovery still happening */
-                               clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
-                               goto unlock;
-                       }
-
-                       if (WARN_ON_ONCE(!mddev->sync_thread))
-                               goto unlock;
-
-                       md_reap_sync_thread(mddev);
+                       unregister_sync_thread(mddev);
                        goto unlock;
                }
 
index 8d881cc597992f1a2af08cb05d07081182860ebd..097d9dbd69b8363df9ba69ed0d89cab05577151b 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
+#include <trace/events/block.h>
 #include "md-cluster.h"
 
 #define MaxSector (~(sector_t)0)
@@ -59,7 +60,7 @@ struct md_rdev {
         */
        struct block_device *meta_bdev;
        struct block_device *bdev;      /* block device handle */
-       struct bdev_handle *bdev_handle;        /* Handle from open for bdev */
+       struct file *bdev_file;         /* Handle from open for bdev */
 
        struct page     *sb_page, *bb_page;
        int             sb_loaded;
@@ -207,6 +208,7 @@ enum flag_bits {
                                 * check if there is collision between raid1
                                 * serial bios.
                                 */
+       Nonrot,                 /* non-rotational device (SSD) */
 };
 
 static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors,
@@ -222,6 +224,16 @@ static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors,
        }
        return 0;
 }
+
+static inline int rdev_has_badblock(struct md_rdev *rdev, sector_t s,
+                                   int sectors)
+{
+       sector_t first_bad;
+       int bad_sectors;
+
+       return is_badblock(rdev, s, sectors, &first_bad, &bad_sectors);
+}
+
 extern int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
                              int is_new);
 extern int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
@@ -468,7 +480,6 @@ struct mddev {
        struct timer_list               safemode_timer;
        struct percpu_ref               writes_pending;
        int                             sync_checkers;  /* # of threads checking writes_pending */
-       struct request_queue            *queue; /* for plugging ... */
 
        struct bitmap                   *bitmap; /* the bitmap for the device */
        struct {
@@ -558,6 +569,37 @@ enum recovery_flags {
        MD_RESYNCING_REMOTE,    /* remote node is running resync thread */
 };
 
+enum md_ro_state {
+       MD_RDWR,
+       MD_RDONLY,
+       MD_AUTO_READ,
+       MD_MAX_STATE
+};
+
+static inline bool md_is_rdwr(struct mddev *mddev)
+{
+       return (mddev->ro == MD_RDWR);
+}
+
+static inline bool reshape_interrupted(struct mddev *mddev)
+{
+       /* reshape never start */
+       if (mddev->reshape_position == MaxSector)
+               return false;
+
+       /* interrupted */
+       if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+               return true;
+
+       /* running reshape will be interrupted soon. */
+       if (test_bit(MD_RECOVERY_WAIT, &mddev->recovery) ||
+           test_bit(MD_RECOVERY_INTR, &mddev->recovery) ||
+           test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))
+               return true;
+
+       return false;
+}
+
 static inline int __must_check mddev_lock(struct mddev *mddev)
 {
        return mutex_lock_interruptible(&mddev->reconfig_mutex);
@@ -617,6 +659,7 @@ struct md_personality
        int (*start_reshape) (struct mddev *mddev);
        void (*finish_reshape) (struct mddev *mddev);
        void (*update_reshape_pos) (struct mddev *mddev);
+       void (*prepare_suspend) (struct mddev *mddev);
        /* quiesce suspends or resumes internal processing.
         * 1 - stop new actions and wait for action io to complete
         * 0 - return to normal behaviour
@@ -750,6 +793,7 @@ extern void md_finish_reshape(struct mddev *mddev);
 void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
                        struct bio *bio, sector_t start, sector_t size);
 void md_account_bio(struct mddev *mddev, struct bio **bio);
+void md_free_cloned_bio(struct bio *bio);
 
 extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
 extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
@@ -778,9 +822,12 @@ extern void md_stop_writes(struct mddev *mddev);
 extern int md_rdev_init(struct md_rdev *rdev);
 extern void md_rdev_clear(struct md_rdev *rdev);
 
-extern void md_handle_request(struct mddev *mddev, struct bio *bio);
+extern bool md_handle_request(struct mddev *mddev, struct bio *bio);
 extern int mddev_suspend(struct mddev *mddev, bool interruptible);
 extern void mddev_resume(struct mddev *mddev);
+extern void md_idle_sync_thread(struct mddev *mddev);
+extern void md_frozen_sync_thread(struct mddev *mddev);
+extern void md_unfrozen_sync_thread(struct mddev *mddev);
 
 extern void md_reload_sb(struct mddev *mddev, int raid_disk);
 extern void md_update_sb(struct mddev *mddev, int force);
@@ -821,7 +868,7 @@ static inline void mddev_check_write_zeroes(struct mddev *mddev, struct bio *bio
 {
        if (bio_op(bio) == REQ_OP_WRITE_ZEROES &&
            !bio->bi_bdev->bd_disk->queue->limits.max_write_zeroes_sectors)
-               mddev->queue->limits.max_write_zeroes_sectors = 0;
+               mddev->gendisk->queue->limits.max_write_zeroes_sectors = 0;
 }
 
 static inline int mddev_suspend_and_lock(struct mddev *mddev)
@@ -860,7 +907,31 @@ void md_autostart_arrays(int part);
 int md_set_array_info(struct mddev *mddev, struct mdu_array_info_s *info);
 int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info);
 int do_md_run(struct mddev *mddev);
+void mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim);
+int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev);
+void mddev_update_io_opt(struct mddev *mddev, unsigned int nr_stripes);
 
 extern const struct block_device_operations md_fops;
 
+/*
+ * MD devices can be used undeneath by DM, in which case ->gendisk is NULL.
+ */
+static inline bool mddev_is_dm(struct mddev *mddev)
+{
+       return !mddev->gendisk;
+}
+
+static inline void mddev_trace_remap(struct mddev *mddev, struct bio *bio,
+               sector_t sector)
+{
+       if (!mddev_is_dm(mddev))
+               trace_block_bio_remap(bio, disk_devt(mddev->gendisk), sector);
+}
+
+#define mddev_add_trace_msg(mddev, fmt, args...)                       \
+do {                                                                   \
+       if (!mddev_is_dm(mddev))                                        \
+               blk_add_trace_msg((mddev)->gendisk->queue, fmt, ##args); \
+} while (0)
+
 #endif /* _MD_MD_H */
index c50a7abda744ad13262378a83fec2dbde0e00b9a..c5d4aeb68404c9cbd3f79797672013f965b45bbb 100644 (file)
@@ -379,6 +379,19 @@ static void raid0_free(struct mddev *mddev, void *priv)
        free_conf(mddev, conf);
 }
 
+static int raid0_set_limits(struct mddev *mddev)
+{
+       struct queue_limits lim;
+
+       blk_set_stacking_limits(&lim);
+       lim.max_hw_sectors = mddev->chunk_sectors;
+       lim.max_write_zeroes_sectors = mddev->chunk_sectors;
+       lim.io_min = mddev->chunk_sectors << 9;
+       lim.io_opt = lim.io_min * mddev->raid_disks;
+       mddev_stack_rdev_limits(mddev, &lim);
+       return queue_limits_set(mddev->gendisk->queue, &lim);
+}
+
 static int raid0_run(struct mddev *mddev)
 {
        struct r0conf *conf;
@@ -399,20 +412,10 @@ static int raid0_run(struct mddev *mddev)
                mddev->private = conf;
        }
        conf = mddev->private;
-       if (mddev->queue) {
-               struct md_rdev *rdev;
-
-               blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
-               blk_queue_max_write_zeroes_sectors(mddev->queue, mddev->chunk_sectors);
-
-               blk_queue_io_min(mddev->queue, mddev->chunk_sectors << 9);
-               blk_queue_io_opt(mddev->queue,
-                                (mddev->chunk_sectors << 9) * mddev->raid_disks);
-
-               rdev_for_each(rdev, mddev) {
-                       disk_stack_limits(mddev->gendisk, rdev->bdev,
-                                         rdev->data_offset << 9);
-               }
+       if (!mddev_is_dm(mddev)) {
+               ret = raid0_set_limits(mddev);
+               if (ret)
+                       goto out_free_conf;
        }
 
        /* calculate array device size */
@@ -426,8 +429,10 @@ static int raid0_run(struct mddev *mddev)
 
        ret = md_integrity_register(mddev);
        if (ret)
-               free_conf(mddev, conf);
-
+               goto out_free_conf;
+       return 0;
+out_free_conf:
+       free_conf(mddev, conf);
        return ret;
 }
 
@@ -578,10 +583,7 @@ static void raid0_map_submit_bio(struct mddev *mddev, struct bio *bio)
        bio_set_dev(bio, tmp_dev->bdev);
        bio->bi_iter.bi_sector = sector + zone->dev_start +
                tmp_dev->data_offset;
-
-       if (mddev->gendisk)
-               trace_block_bio_remap(bio, disk_devt(mddev->gendisk),
-                                     bio_sector);
+       mddev_trace_remap(mddev, bio, bio_sector);
        mddev_check_write_zeroes(mddev, bio);
        submit_bio_noacct(bio);
 }
index 512746551f36a754d9e655f220f260b6896dcd10..2ea1710a3b705e9c68d7ed4a05fcd0bc16e32e2b 100644 (file)
@@ -227,3 +227,72 @@ static inline bool exceed_read_errors(struct mddev *mddev, struct md_rdev *rdev)
 
        return false;
 }
+
+/**
+ * raid1_check_read_range() - check a given read range for bad blocks,
+ * available read length is returned;
+ * @rdev: the rdev to read;
+ * @this_sector: read position;
+ * @len: read length;
+ *
+ * helper function for read_balance()
+ *
+ * 1) If there are no bad blocks in the range, @len is returned;
+ * 2) If the range are all bad blocks, 0 is returned;
+ * 3) If there are partial bad blocks:
+ *  - If the bad block range starts after @this_sector, the length of first
+ *  good region is returned;
+ *  - If the bad block range starts before @this_sector, 0 is returned and
+ *  the @len is updated to the offset into the region before we get to the
+ *  good blocks;
+ */
+static inline int raid1_check_read_range(struct md_rdev *rdev,
+                                        sector_t this_sector, int *len)
+{
+       sector_t first_bad;
+       int bad_sectors;
+
+       /* no bad block overlap */
+       if (!is_badblock(rdev, this_sector, *len, &first_bad, &bad_sectors))
+               return *len;
+
+       /*
+        * bad block range starts offset into our range so we can return the
+        * number of sectors before the bad blocks start.
+        */
+       if (first_bad > this_sector)
+               return first_bad - this_sector;
+
+       /* read range is fully consumed by bad blocks. */
+       if (this_sector + *len <= first_bad + bad_sectors)
+               return 0;
+
+       /*
+        * final case, bad block range starts before or at the start of our
+        * range but does not cover our entire range so we still return 0 but
+        * update the length with the number of sectors before we get to the
+        * good ones.
+        */
+       *len = first_bad + bad_sectors - this_sector;
+       return 0;
+}
+
+/*
+ * Check if read should choose the first rdev.
+ *
+ * Balance on the whole device if no resync is going on (recovery is ok) or
+ * below the resync window. Otherwise, take the first readable disk.
+ */
+static inline bool raid1_should_read_first(struct mddev *mddev,
+                                          sector_t this_sector, int len)
+{
+       if ((mddev->recovery_cp < this_sector + len))
+               return true;
+
+       if (mddev_is_clustered(mddev) &&
+           md_cluster_ops->area_resyncing(mddev, READ, this_sector,
+                                          this_sector + len))
+               return true;
+
+       return false;
+}
index 286f8b16c7bde7fbc0bca0705d470748d9f5eeb5..be8ac24f50b6ad651fd107f9af9a448bb1f7780a 100644 (file)
@@ -46,9 +46,6 @@
 static void allow_barrier(struct r1conf *conf, sector_t sector_nr);
 static void lower_barrier(struct r1conf *conf, sector_t sector_nr);
 
-#define raid1_log(md, fmt, args...)                            \
-       do { if ((md)->queue) blk_add_trace_msg((md)->queue, "raid1 " fmt, ##args); } while (0)
-
 #define RAID_1_10_NAME "raid1"
 #include "raid1-10.c"
 
@@ -498,9 +495,6 @@ static void raid1_end_write_request(struct bio *bio)
                 * to user-side. So if something waits for IO, then it
                 * will wait for the 'master' bio.
                 */
-               sector_t first_bad;
-               int bad_sectors;
-
                r1_bio->bios[mirror] = NULL;
                to_put = bio;
                /*
@@ -516,8 +510,8 @@ static void raid1_end_write_request(struct bio *bio)
                        set_bit(R1BIO_Uptodate, &r1_bio->state);
 
                /* Maybe we can clear some bad blocks. */
-               if (is_badblock(rdev, r1_bio->sector, r1_bio->sectors,
-                               &first_bad, &bad_sectors) && !discard_error) {
+               if (rdev_has_badblock(rdev, r1_bio->sector, r1_bio->sectors) &&
+                   !discard_error) {
                        r1_bio->bios[mirror] = IO_MADE_GOOD;
                        set_bit(R1BIO_MadeGood, &r1_bio->state);
                }
@@ -582,211 +576,312 @@ static sector_t align_to_barrier_unit_end(sector_t start_sector,
        return len;
 }
 
-/*
- * This routine returns the disk from which the requested read should
- * be done. There is a per-array 'next expected sequential IO' sector
- * number - if this matches on the next IO then we use the last disk.
- * There is also a per-disk 'last know head position' sector that is
- * maintained from IRQ contexts, both the normal and the resync IO
- * completion handlers update this position correctly. If there is no
- * perfect sequential match then we pick the disk whose head is closest.
- *
- * If there are 2 mirrors in the same 2 devices, performance degrades
- * because position is mirror, not device based.
- *
- * The rdev for the device selected will have nr_pending incremented.
- */
-static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sectors)
+static void update_read_sectors(struct r1conf *conf, int disk,
+                               sector_t this_sector, int len)
 {
-       const sector_t this_sector = r1_bio->sector;
-       int sectors;
-       int best_good_sectors;
-       int best_disk, best_dist_disk, best_pending_disk;
-       int has_nonrot_disk;
+       struct raid1_info *info = &conf->mirrors[disk];
+
+       atomic_inc(&info->rdev->nr_pending);
+       if (info->next_seq_sect != this_sector)
+               info->seq_start = this_sector;
+       info->next_seq_sect = this_sector + len;
+}
+
+static int choose_first_rdev(struct r1conf *conf, struct r1bio *r1_bio,
+                            int *max_sectors)
+{
+       sector_t this_sector = r1_bio->sector;
+       int len = r1_bio->sectors;
        int disk;
-       sector_t best_dist;
-       unsigned int min_pending;
-       struct md_rdev *rdev;
-       int choose_first;
-       int choose_next_idle;
 
-       /*
-        * Check if we can balance. We can balance on the whole
-        * device if no resync is going on, or below the resync window.
-        * We take the first readable disk when above the resync window.
-        */
- retry:
-       sectors = r1_bio->sectors;
-       best_disk = -1;
-       best_dist_disk = -1;
-       best_dist = MaxSector;
-       best_pending_disk = -1;
-       min_pending = UINT_MAX;
-       best_good_sectors = 0;
-       has_nonrot_disk = 0;
-       choose_next_idle = 0;
-       clear_bit(R1BIO_FailFast, &r1_bio->state);
+       for (disk = 0 ; disk < conf->raid_disks * 2 ; disk++) {
+               struct md_rdev *rdev;
+               int read_len;
 
-       if ((conf->mddev->recovery_cp < this_sector + sectors) ||
-           (mddev_is_clustered(conf->mddev) &&
-           md_cluster_ops->area_resyncing(conf->mddev, READ, this_sector,
-                   this_sector + sectors)))
-               choose_first = 1;
-       else
-               choose_first = 0;
+               if (r1_bio->bios[disk] == IO_BLOCKED)
+                       continue;
+
+               rdev = conf->mirrors[disk].rdev;
+               if (!rdev || test_bit(Faulty, &rdev->flags))
+                       continue;
+
+               /* choose the first disk even if it has some bad blocks. */
+               read_len = raid1_check_read_range(rdev, this_sector, &len);
+               if (read_len > 0) {
+                       update_read_sectors(conf, disk, this_sector, read_len);
+                       *max_sectors = read_len;
+                       return disk;
+               }
+       }
+
+       return -1;
+}
+
+static int choose_bb_rdev(struct r1conf *conf, struct r1bio *r1_bio,
+                         int *max_sectors)
+{
+       sector_t this_sector = r1_bio->sector;
+       int best_disk = -1;
+       int best_len = 0;
+       int disk;
 
        for (disk = 0 ; disk < conf->raid_disks * 2 ; disk++) {
-               sector_t dist;
-               sector_t first_bad;
-               int bad_sectors;
-               unsigned int pending;
-               bool nonrot;
+               struct md_rdev *rdev;
+               int len;
+               int read_len;
+
+               if (r1_bio->bios[disk] == IO_BLOCKED)
+                       continue;
 
                rdev = conf->mirrors[disk].rdev;
-               if (r1_bio->bios[disk] == IO_BLOCKED
-                   || rdev == NULL
-                   || test_bit(Faulty, &rdev->flags))
+               if (!rdev || test_bit(Faulty, &rdev->flags) ||
+                   test_bit(WriteMostly, &rdev->flags))
                        continue;
-               if (!test_bit(In_sync, &rdev->flags) &&
-                   rdev->recovery_offset < this_sector + sectors)
+
+               /* keep track of the disk with the most readable sectors. */
+               len = r1_bio->sectors;
+               read_len = raid1_check_read_range(rdev, this_sector, &len);
+               if (read_len > best_len) {
+                       best_disk = disk;
+                       best_len = read_len;
+               }
+       }
+
+       if (best_disk != -1) {
+               *max_sectors = best_len;
+               update_read_sectors(conf, best_disk, this_sector, best_len);
+       }
+
+       return best_disk;
+}
+
+static int choose_slow_rdev(struct r1conf *conf, struct r1bio *r1_bio,
+                           int *max_sectors)
+{
+       sector_t this_sector = r1_bio->sector;
+       int bb_disk = -1;
+       int bb_read_len = 0;
+       int disk;
+
+       for (disk = 0 ; disk < conf->raid_disks * 2 ; disk++) {
+               struct md_rdev *rdev;
+               int len;
+               int read_len;
+
+               if (r1_bio->bios[disk] == IO_BLOCKED)
                        continue;
-               if (test_bit(WriteMostly, &rdev->flags)) {
-                       /* Don't balance among write-mostly, just
-                        * use the first as a last resort */
-                       if (best_dist_disk < 0) {
-                               if (is_badblock(rdev, this_sector, sectors,
-                                               &first_bad, &bad_sectors)) {
-                                       if (first_bad <= this_sector)
-                                               /* Cannot use this */
-                                               continue;
-                                       best_good_sectors = first_bad - this_sector;
-                               } else
-                                       best_good_sectors = sectors;
-                               best_dist_disk = disk;
-                               best_pending_disk = disk;
-                       }
+
+               rdev = conf->mirrors[disk].rdev;
+               if (!rdev || test_bit(Faulty, &rdev->flags) ||
+                   !test_bit(WriteMostly, &rdev->flags))
                        continue;
+
+               /* there are no bad blocks, we can use this disk */
+               len = r1_bio->sectors;
+               read_len = raid1_check_read_range(rdev, this_sector, &len);
+               if (read_len == r1_bio->sectors) {
+                       update_read_sectors(conf, disk, this_sector, read_len);
+                       return disk;
                }
-               /* This is a reasonable device to use.  It might
-                * even be best.
+
+               /*
+                * there are partial bad blocks, choose the rdev with largest
+                * read length.
                 */
-               if (is_badblock(rdev, this_sector, sectors,
-                               &first_bad, &bad_sectors)) {
-                       if (best_dist < MaxSector)
-                               /* already have a better device */
-                               continue;
-                       if (first_bad <= this_sector) {
-                               /* cannot read here. If this is the 'primary'
-                                * device, then we must not read beyond
-                                * bad_sectors from another device..
-                                */
-                               bad_sectors -= (this_sector - first_bad);
-                               if (choose_first && sectors > bad_sectors)
-                                       sectors = bad_sectors;
-                               if (best_good_sectors > sectors)
-                                       best_good_sectors = sectors;
-
-                       } else {
-                               sector_t good_sectors = first_bad - this_sector;
-                               if (good_sectors > best_good_sectors) {
-                                       best_good_sectors = good_sectors;
-                                       best_disk = disk;
-                               }
-                               if (choose_first)
-                                       break;
-                       }
-                       continue;
-               } else {
-                       if ((sectors > best_good_sectors) && (best_disk >= 0))
-                               best_disk = -1;
-                       best_good_sectors = sectors;
+               if (read_len > bb_read_len) {
+                       bb_disk = disk;
+                       bb_read_len = read_len;
                }
+       }
+
+       if (bb_disk != -1) {
+               *max_sectors = bb_read_len;
+               update_read_sectors(conf, bb_disk, this_sector, bb_read_len);
+       }
+
+       return bb_disk;
+}
+
+static bool is_sequential(struct r1conf *conf, int disk, struct r1bio *r1_bio)
+{
+       /* TODO: address issues with this check and concurrency. */
+       return conf->mirrors[disk].next_seq_sect == r1_bio->sector ||
+              conf->mirrors[disk].head_position == r1_bio->sector;
+}
+
+/*
+ * If buffered sequential IO size exceeds optimal iosize, check if there is idle
+ * disk. If yes, choose the idle disk.
+ */
+static bool should_choose_next(struct r1conf *conf, int disk)
+{
+       struct raid1_info *mirror = &conf->mirrors[disk];
+       int opt_iosize;
+
+       if (!test_bit(Nonrot, &mirror->rdev->flags))
+               return false;
+
+       opt_iosize = bdev_io_opt(mirror->rdev->bdev) >> 9;
+       return opt_iosize > 0 && mirror->seq_start != MaxSector &&
+              mirror->next_seq_sect > opt_iosize &&
+              mirror->next_seq_sect - opt_iosize >= mirror->seq_start;
+}
+
+static bool rdev_readable(struct md_rdev *rdev, struct r1bio *r1_bio)
+{
+       if (!rdev || test_bit(Faulty, &rdev->flags))
+               return false;
+
+       /* still in recovery */
+       if (!test_bit(In_sync, &rdev->flags) &&
+           rdev->recovery_offset < r1_bio->sector + r1_bio->sectors)
+               return false;
+
+       /* don't read from slow disk unless have to */
+       if (test_bit(WriteMostly, &rdev->flags))
+               return false;
+
+       /* don't split IO for bad blocks unless have to */
+       if (rdev_has_badblock(rdev, r1_bio->sector, r1_bio->sectors))
+               return false;
+
+       return true;
+}
+
+struct read_balance_ctl {
+       sector_t closest_dist;
+       int closest_dist_disk;
+       int min_pending;
+       int min_pending_disk;
+       int sequential_disk;
+       int readable_disks;
+};
+
+static int choose_best_rdev(struct r1conf *conf, struct r1bio *r1_bio)
+{
+       int disk;
+       struct read_balance_ctl ctl = {
+               .closest_dist_disk      = -1,
+               .closest_dist           = MaxSector,
+               .min_pending_disk       = -1,
+               .min_pending            = UINT_MAX,
+               .sequential_disk        = -1,
+       };
+
+       for (disk = 0 ; disk < conf->raid_disks * 2 ; disk++) {
+               struct md_rdev *rdev;
+               sector_t dist;
+               unsigned int pending;
 
-               if (best_disk >= 0)
-                       /* At least two disks to choose from so failfast is OK */
+               if (r1_bio->bios[disk] == IO_BLOCKED)
+                       continue;
+
+               rdev = conf->mirrors[disk].rdev;
+               if (!rdev_readable(rdev, r1_bio))
+                       continue;
+
+               /* At least two disks to choose from so failfast is OK */
+               if (ctl.readable_disks++ == 1)
                        set_bit(R1BIO_FailFast, &r1_bio->state);
 
-               nonrot = bdev_nonrot(rdev->bdev);
-               has_nonrot_disk |= nonrot;
                pending = atomic_read(&rdev->nr_pending);
-               dist = abs(this_sector - conf->mirrors[disk].head_position);
-               if (choose_first) {
-                       best_disk = disk;
-                       break;
-               }
+               dist = abs(r1_bio->sector - conf->mirrors[disk].head_position);
+
                /* Don't change to another disk for sequential reads */
-               if (conf->mirrors[disk].next_seq_sect == this_sector
-                   || dist == 0) {
-                       int opt_iosize = bdev_io_opt(rdev->bdev) >> 9;
-                       struct raid1_info *mirror = &conf->mirrors[disk];
+               if (is_sequential(conf, disk, r1_bio)) {
+                       if (!should_choose_next(conf, disk))
+                               return disk;
 
-                       best_disk = disk;
                        /*
-                        * If buffered sequential IO size exceeds optimal
-                        * iosize, check if there is idle disk. If yes, choose
-                        * the idle disk. read_balance could already choose an
-                        * idle disk before noticing it's a sequential IO in
-                        * this disk. This doesn't matter because this disk
-                        * will idle, next time it will be utilized after the
-                        * first disk has IO size exceeds optimal iosize. In
-                        * this way, iosize of the first disk will be optimal
-                        * iosize at least. iosize of the second disk might be
-                        * small, but not a big deal since when the second disk
-                        * starts IO, the first disk is likely still busy.
+                        * Add 'pending' to avoid choosing this disk if
+                        * there is other idle disk.
                         */
-                       if (nonrot && opt_iosize > 0 &&
-                           mirror->seq_start != MaxSector &&
-                           mirror->next_seq_sect > opt_iosize &&
-                           mirror->next_seq_sect - opt_iosize >=
-                           mirror->seq_start) {
-                               choose_next_idle = 1;
-                               continue;
-                       }
-                       break;
+                       pending++;
+                       /*
+                        * If there is no other idle disk, this disk
+                        * will be chosen.
+                        */
+                       ctl.sequential_disk = disk;
                }
 
-               if (choose_next_idle)
-                       continue;
-
-               if (min_pending > pending) {
-                       min_pending = pending;
-                       best_pending_disk = disk;
+               if (ctl.min_pending > pending) {
+                       ctl.min_pending = pending;
+                       ctl.min_pending_disk = disk;
                }
 
-               if (dist < best_dist) {
-                       best_dist = dist;
-                       best_dist_disk = disk;
+               if (ctl.closest_dist > dist) {
+                       ctl.closest_dist = dist;
+                       ctl.closest_dist_disk = disk;
                }
        }
 
+       /*
+        * sequential IO size exceeds optimal iosize, however, there is no other
+        * idle disk, so choose the sequential disk.
+        */
+       if (ctl.sequential_disk != -1 && ctl.min_pending != 0)
+               return ctl.sequential_disk;
+
        /*
         * If all disks are rotational, choose the closest disk. If any disk is
         * non-rotational, choose the disk with less pending request even the
         * disk is rotational, which might/might not be optimal for raids with
         * mixed ratation/non-rotational disks depending on workload.
         */
-       if (best_disk == -1) {
-               if (has_nonrot_disk || min_pending == 0)
-                       best_disk = best_pending_disk;
-               else
-                       best_disk = best_dist_disk;
-       }
+       if (ctl.min_pending_disk != -1 &&
+           (READ_ONCE(conf->nonrot_disks) || ctl.min_pending == 0))
+               return ctl.min_pending_disk;
+       else
+               return ctl.closest_dist_disk;
+}
 
-       if (best_disk >= 0) {
-               rdev = conf->mirrors[best_disk].rdev;
-               if (!rdev)
-                       goto retry;
-               atomic_inc(&rdev->nr_pending);
-               sectors = best_good_sectors;
+/*
+ * This routine returns the disk from which the requested read should be done.
+ *
+ * 1) If resync is in progress, find the first usable disk and use it even if it
+ * has some bad blocks.
+ *
+ * 2) Now that there is no resync, loop through all disks and skipping slow
+ * disks and disks with bad blocks for now. Only pay attention to key disk
+ * choice.
+ *
+ * 3) If we've made it this far, now look for disks with bad blocks and choose
+ * the one with most number of sectors.
+ *
+ * 4) If we are all the way at the end, we have no choice but to use a disk even
+ * if it is write mostly.
+ *
+ * The rdev for the device selected will have nr_pending incremented.
+ */
+static int read_balance(struct r1conf *conf, struct r1bio *r1_bio,
+                       int *max_sectors)
+{
+       int disk;
 
-               if (conf->mirrors[best_disk].next_seq_sect != this_sector)
-                       conf->mirrors[best_disk].seq_start = this_sector;
+       clear_bit(R1BIO_FailFast, &r1_bio->state);
+
+       if (raid1_should_read_first(conf->mddev, r1_bio->sector,
+                                   r1_bio->sectors))
+               return choose_first_rdev(conf, r1_bio, max_sectors);
 
-               conf->mirrors[best_disk].next_seq_sect = this_sector + sectors;
+       disk = choose_best_rdev(conf, r1_bio);
+       if (disk >= 0) {
+               *max_sectors = r1_bio->sectors;
+               update_read_sectors(conf, disk, r1_bio->sector,
+                                   r1_bio->sectors);
+               return disk;
        }
-       *max_sectors = sectors;
 
-       return best_disk;
+       /*
+        * If we are here it means we didn't find a perfectly good disk so
+        * now spend a bit more time trying to find one with the most good
+        * sectors.
+        */
+       disk = choose_bb_rdev(conf, r1_bio, max_sectors);
+       if (disk >= 0)
+               return disk;
+
+       return choose_slow_rdev(conf, r1_bio, max_sectors);
 }
 
 static void wake_up_barrier(struct r1conf *conf)
@@ -1098,7 +1193,7 @@ static void freeze_array(struct r1conf *conf, int extra)
         */
        spin_lock_irq(&conf->resync_lock);
        conf->array_frozen = 1;
-       raid1_log(conf->mddev, "wait freeze");
+       mddev_add_trace_msg(conf->mddev, "raid1 wait freeze");
        wait_event_lock_irq_cmd(
                conf->wait_barrier,
                get_unqueued_pending(conf) == extra,
@@ -1287,7 +1382,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
                 * Reading from a write-mostly device must take care not to
                 * over-take any writes that are 'behind'
                 */
-               raid1_log(mddev, "wait behind writes");
+               mddev_add_trace_msg(mddev, "raid1 wait behind writes");
                wait_event(bitmap->behind_wait,
                           atomic_read(&bitmap->behind_writes) == 0);
        }
@@ -1320,11 +1415,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
            test_bit(R1BIO_FailFast, &r1_bio->state))
                read_bio->bi_opf |= MD_FAILFAST;
        read_bio->bi_private = r1_bio;
-
-       if (mddev->gendisk)
-               trace_block_bio_remap(read_bio, disk_devt(mddev->gendisk),
-                                     r1_bio->sector);
-
+       mddev_trace_remap(mddev, read_bio, r1_bio->sector);
        submit_bio_noacct(read_bio);
 }
 
@@ -1474,7 +1565,8 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
                        bio_wouldblock_error(bio);
                        return;
                }
-               raid1_log(mddev, "wait rdev %d blocked", blocked_rdev->raid_disk);
+               mddev_add_trace_msg(mddev, "raid1 wait rdev %d blocked",
+                               blocked_rdev->raid_disk);
                md_wait_for_blocked_rdev(blocked_rdev, mddev);
                wait_barrier(conf, bio->bi_iter.bi_sector, false);
                goto retry_write;
@@ -1557,10 +1649,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
                mbio->bi_private = r1_bio;
 
                atomic_inc(&r1_bio->remaining);
-
-               if (mddev->gendisk)
-                       trace_block_bio_remap(mbio, disk_devt(mddev->gendisk),
-                                             r1_bio->sector);
+               mddev_trace_remap(mddev, mbio, r1_bio->sector);
                /* flush_pending_writes() needs access to the rdev so...*/
                mbio->bi_bdev = (void *)rdev;
                if (!raid1_add_bio_to_plug(mddev, mbio, raid1_unplug, disks)) {
@@ -1760,6 +1849,52 @@ static int raid1_spare_active(struct mddev *mddev)
        return count;
 }
 
+static bool raid1_add_conf(struct r1conf *conf, struct md_rdev *rdev, int disk,
+                          bool replacement)
+{
+       struct raid1_info *info = conf->mirrors + disk;
+
+       if (replacement)
+               info += conf->raid_disks;
+
+       if (info->rdev)
+               return false;
+
+       if (bdev_nonrot(rdev->bdev)) {
+               set_bit(Nonrot, &rdev->flags);
+               WRITE_ONCE(conf->nonrot_disks, conf->nonrot_disks + 1);
+       }
+
+       rdev->raid_disk = disk;
+       info->head_position = 0;
+       info->seq_start = MaxSector;
+       WRITE_ONCE(info->rdev, rdev);
+
+       return true;
+}
+
+static bool raid1_remove_conf(struct r1conf *conf, int disk)
+{
+       struct raid1_info *info = conf->mirrors + disk;
+       struct md_rdev *rdev = info->rdev;
+
+       if (!rdev || test_bit(In_sync, &rdev->flags) ||
+           atomic_read(&rdev->nr_pending))
+               return false;
+
+       /* Only remove non-faulty devices if recovery is not possible. */
+       if (!test_bit(Faulty, &rdev->flags) &&
+           rdev->mddev->recovery_disabled != conf->recovery_disabled &&
+           rdev->mddev->degraded < conf->raid_disks)
+               return false;
+
+       if (test_and_clear_bit(Nonrot, &rdev->flags))
+               WRITE_ONCE(conf->nonrot_disks, conf->nonrot_disks - 1);
+
+       WRITE_ONCE(info->rdev, NULL);
+       return true;
+}
+
 static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
 {
        struct r1conf *conf = mddev->private;
@@ -1791,19 +1926,16 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
        for (mirror = first; mirror <= last; mirror++) {
                p = conf->mirrors + mirror;
                if (!p->rdev) {
-                       if (mddev->gendisk)
-                               disk_stack_limits(mddev->gendisk, rdev->bdev,
-                                                 rdev->data_offset << 9);
+                       err = mddev_stack_new_rdev(mddev, rdev);
+                       if (err)
+                               return err;
 
-                       p->head_position = 0;
-                       rdev->raid_disk = mirror;
-                       err = 0;
+                       raid1_add_conf(conf, rdev, mirror, false);
                        /* As all devices are equivalent, we don't need a full recovery
                         * if this was recently any drive of the array
                         */
                        if (rdev->saved_raid_disk < 0)
                                conf->fullsync = 1;
-                       WRITE_ONCE(p->rdev, rdev);
                        break;
                }
                if (test_bit(WantReplacement, &p->rdev->flags) &&
@@ -1813,13 +1945,11 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
 
        if (err && repl_slot >= 0) {
                /* Add this device as a replacement */
-               p = conf->mirrors + repl_slot;
                clear_bit(In_sync, &rdev->flags);
                set_bit(Replacement, &rdev->flags);
-               rdev->raid_disk = repl_slot;
+               raid1_add_conf(conf, rdev, repl_slot, true);
                err = 0;
                conf->fullsync = 1;
-               WRITE_ONCE(p[conf->raid_disks].rdev, rdev);
        }
 
        print_conf(conf);
@@ -1836,27 +1966,20 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
        if (unlikely(number >= conf->raid_disks))
                goto abort;
 
-       if (rdev != p->rdev)
-               p = conf->mirrors + conf->raid_disks + number;
+       if (rdev != p->rdev) {
+               number += conf->raid_disks;
+               p = conf->mirrors + number;
+       }
 
        print_conf(conf);
        if (rdev == p->rdev) {
-               if (test_bit(In_sync, &rdev->flags) ||
-                   atomic_read(&rdev->nr_pending)) {
+               if (!raid1_remove_conf(conf, number)) {
                        err = -EBUSY;
                        goto abort;
                }
-               /* Only remove non-faulty devices if recovery
-                * is not possible.
-                */
-               if (!test_bit(Faulty, &rdev->flags) &&
-                   mddev->recovery_disabled != conf->recovery_disabled &&
-                   mddev->degraded < conf->raid_disks) {
-                       err = -EBUSY;
-                       goto abort;
-               }
-               WRITE_ONCE(p->rdev, NULL);
-               if (conf->mirrors[conf->raid_disks + number].rdev) {
+
+               if (number < conf->raid_disks &&
+                   conf->mirrors[conf->raid_disks + number].rdev) {
                        /* We just removed a device that is being replaced.
                         * Move down the replacement.  We drain all IO before
                         * doing this to avoid confusion.
@@ -1944,8 +2067,6 @@ static void end_sync_write(struct bio *bio)
        struct r1bio *r1_bio = get_resync_r1bio(bio);
        struct mddev *mddev = r1_bio->mddev;
        struct r1conf *conf = mddev->private;
-       sector_t first_bad;
-       int bad_sectors;
        struct md_rdev *rdev = conf->mirrors[find_bio_disk(r1_bio, bio)].rdev;
 
        if (!uptodate) {
@@ -1955,14 +2076,11 @@ static void end_sync_write(struct bio *bio)
                        set_bit(MD_RECOVERY_NEEDED, &
                                mddev->recovery);
                set_bit(R1BIO_WriteError, &r1_bio->state);
-       } else if (is_badblock(rdev, r1_bio->sector, r1_bio->sectors,
-                              &first_bad, &bad_sectors) &&
-                  !is_badblock(conf->mirrors[r1_bio->read_disk].rdev,
-                               r1_bio->sector,
-                               r1_bio->sectors,
-                               &first_bad, &bad_sectors)
-               )
+       } else if (rdev_has_badblock(rdev, r1_bio->sector, r1_bio->sectors) &&
+                  !rdev_has_badblock(conf->mirrors[r1_bio->read_disk].rdev,
+                                     r1_bio->sector, r1_bio->sectors)) {
                set_bit(R1BIO_MadeGood, &r1_bio->state);
+       }
 
        put_sync_write_buf(r1_bio, uptodate);
 }
@@ -2279,16 +2397,12 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
                        s = PAGE_SIZE >> 9;
 
                do {
-                       sector_t first_bad;
-                       int bad_sectors;
-
                        rdev = conf->mirrors[d].rdev;
                        if (rdev &&
                            (test_bit(In_sync, &rdev->flags) ||
                             (!test_bit(Faulty, &rdev->flags) &&
                              rdev->recovery_offset >= sect + s)) &&
-                           is_badblock(rdev, sect, s,
-                                       &first_bad, &bad_sectors) == 0) {
+                           rdev_has_badblock(rdev, sect, s) == 0) {
                                atomic_inc(&rdev->nr_pending);
                                if (sync_page_io(rdev, sect, s<<9,
                                         conf->tmppage, REQ_OP_READ, false))
@@ -3006,23 +3120,17 @@ static struct r1conf *setup_conf(struct mddev *mddev)
 
        err = -EINVAL;
        spin_lock_init(&conf->device_lock);
+       conf->raid_disks = mddev->raid_disks;
        rdev_for_each(rdev, mddev) {
                int disk_idx = rdev->raid_disk;
-               if (disk_idx >= mddev->raid_disks
-                   || disk_idx < 0)
+
+               if (disk_idx >= conf->raid_disks || disk_idx < 0)
                        continue;
-               if (test_bit(Replacement, &rdev->flags))
-                       disk = conf->mirrors + mddev->raid_disks + disk_idx;
-               else
-                       disk = conf->mirrors + disk_idx;
 
-               if (disk->rdev)
+               if (!raid1_add_conf(conf, rdev, disk_idx,
+                                   test_bit(Replacement, &rdev->flags)))
                        goto abort;
-               disk->rdev = rdev;
-               disk->head_position = 0;
-               disk->seq_start = MaxSector;
        }
-       conf->raid_disks = mddev->raid_disks;
        conf->mddev = mddev;
        INIT_LIST_HEAD(&conf->retry_list);
        INIT_LIST_HEAD(&conf->bio_end_io_list);
@@ -3086,12 +3194,21 @@ static struct r1conf *setup_conf(struct mddev *mddev)
        return ERR_PTR(err);
 }
 
+static int raid1_set_limits(struct mddev *mddev)
+{
+       struct queue_limits lim;
+
+       blk_set_stacking_limits(&lim);
+       lim.max_write_zeroes_sectors = 0;
+       mddev_stack_rdev_limits(mddev, &lim);
+       return queue_limits_set(mddev->gendisk->queue, &lim);
+}
+
 static void raid1_free(struct mddev *mddev, void *priv);
 static int raid1_run(struct mddev *mddev)
 {
        struct r1conf *conf;
        int i;
-       struct md_rdev *rdev;
        int ret;
 
        if (mddev->level != 1) {
@@ -3118,14 +3235,10 @@ static int raid1_run(struct mddev *mddev)
        if (IS_ERR(conf))
                return PTR_ERR(conf);
 
-       if (mddev->queue)
-               blk_queue_max_write_zeroes_sectors(mddev->queue, 0);
-
-       rdev_for_each(rdev, mddev) {
-               if (!mddev->gendisk)
-                       continue;
-               disk_stack_limits(mddev->gendisk, rdev->bdev,
-                                 rdev->data_offset << 9);
+       if (!mddev_is_dm(mddev)) {
+               ret = raid1_set_limits(mddev);
+               if (ret)
+                       goto abort;
        }
 
        mddev->degraded = 0;
index 14d4211a123a8e4007689919d5f86092c7feb659..5300cbaa58a415a0c6f3f41078d59394418bcb3a 100644 (file)
@@ -71,6 +71,7 @@ struct r1conf {
                                                 * allow for replacements.
                                                 */
        int                     raid_disks;
+       int                     nonrot_disks;
 
        spinlock_t              device_lock;
 
index 7412066ea22c7a525ed3e9ff1cfc1b5db2b2b527..a4556d2e46bf95f3bb8020941a00119c050cf662 100644 (file)
@@ -76,9 +76,6 @@ static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio);
 static void end_reshape_write(struct bio *bio);
 static void end_reshape(struct r10conf *conf);
 
-#define raid10_log(md, fmt, args...)                           \
-       do { if ((md)->queue) blk_add_trace_msg((md)->queue, "raid10 " fmt, ##args); } while (0)
-
 #include "raid1-10.c"
 
 #define NULL_CMD
@@ -518,11 +515,7 @@ static void raid10_end_write_request(struct bio *bio)
                 * The 'master' represents the composite IO operation to
                 * user-side. So if something waits for IO, then it will
                 * wait for the 'master' bio.
-                */
-               sector_t first_bad;
-               int bad_sectors;
-
-               /*
+                *
                 * Do not set R10BIO_Uptodate if the current device is
                 * rebuilding or Faulty. This is because we cannot use
                 * such device for properly reading the data back (we could
@@ -535,10 +528,9 @@ static void raid10_end_write_request(struct bio *bio)
                        set_bit(R10BIO_Uptodate, &r10_bio->state);
 
                /* Maybe we can clear some bad blocks. */
-               if (is_badblock(rdev,
-                               r10_bio->devs[slot].addr,
-                               r10_bio->sectors,
-                               &first_bad, &bad_sectors) && !discard_error) {
+               if (rdev_has_badblock(rdev, r10_bio->devs[slot].addr,
+                                     r10_bio->sectors) &&
+                   !discard_error) {
                        bio_put(bio);
                        if (repl)
                                r10_bio->devs[slot].repl_bio = IO_MADE_GOOD;
@@ -753,17 +745,8 @@ static struct md_rdev *read_balance(struct r10conf *conf,
        best_good_sectors = 0;
        do_balance = 1;
        clear_bit(R10BIO_FailFast, &r10_bio->state);
-       /*
-        * Check if we can balance. We can balance on the whole
-        * device if no resync is going on (recovery is ok), or below
-        * the resync window. We take the first readable disk when
-        * above the resync window.
-        */
-       if ((conf->mddev->recovery_cp < MaxSector
-            && (this_sector + sectors >= conf->next_resync)) ||
-           (mddev_is_clustered(conf->mddev) &&
-            md_cluster_ops->area_resyncing(conf->mddev, READ, this_sector,
-                                           this_sector + sectors)))
+
+       if (raid1_should_read_first(conf->mddev, this_sector, sectors))
                do_balance = 0;
 
        for (slot = 0; slot < conf->copies ; slot++) {
@@ -1033,7 +1016,7 @@ static bool wait_barrier(struct r10conf *conf, bool nowait)
                        ret = false;
                } else {
                        conf->nr_waiting++;
-                       raid10_log(conf->mddev, "wait barrier");
+                       mddev_add_trace_msg(conf->mddev, "raid10 wait barrier");
                        wait_event_barrier(conf, stop_waiting_barrier(conf));
                        conf->nr_waiting--;
                }
@@ -1152,7 +1135,7 @@ static bool regular_request_wait(struct mddev *mddev, struct r10conf *conf,
                        bio_wouldblock_error(bio);
                        return false;
                }
-               raid10_log(conf->mddev, "wait reshape");
+               mddev_add_trace_msg(conf->mddev, "raid10 wait reshape");
                wait_event(conf->wait_barrier,
                           conf->reshape_progress <= bio->bi_iter.bi_sector ||
                           conf->reshape_progress >= bio->bi_iter.bi_sector +
@@ -1249,10 +1232,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
            test_bit(R10BIO_FailFast, &r10_bio->state))
                read_bio->bi_opf |= MD_FAILFAST;
        read_bio->bi_private = r10_bio;
-
-       if (mddev->gendisk)
-               trace_block_bio_remap(read_bio, disk_devt(mddev->gendisk),
-                                     r10_bio->sector);
+       mddev_trace_remap(mddev, read_bio, r10_bio->sector);
        submit_bio_noacct(read_bio);
        return;
 }
@@ -1288,10 +1268,7 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio,
                         && enough(conf, devnum))
                mbio->bi_opf |= MD_FAILFAST;
        mbio->bi_private = r10_bio;
-
-       if (conf->mddev->gendisk)
-               trace_block_bio_remap(mbio, disk_devt(conf->mddev->gendisk),
-                                     r10_bio->sector);
+       mddev_trace_remap(mddev, mbio, r10_bio->sector);
        /* flush_pending_writes() needs access to the rdev so...*/
        mbio->bi_bdev = (void *)rdev;
 
@@ -1330,10 +1307,7 @@ retry_wait:
                }
 
                if (rdev && test_bit(WriteErrorSeen, &rdev->flags)) {
-                       sector_t first_bad;
                        sector_t dev_sector = r10_bio->devs[i].addr;
-                       int bad_sectors;
-                       int is_bad;
 
                        /*
                         * Discard request doesn't care the write result
@@ -1342,9 +1316,8 @@ retry_wait:
                        if (!r10_bio->sectors)
                                continue;
 
-                       is_bad = is_badblock(rdev, dev_sector, r10_bio->sectors,
-                                            &first_bad, &bad_sectors);
-                       if (is_bad < 0) {
+                       if (rdev_has_badblock(rdev, dev_sector,
+                                             r10_bio->sectors) < 0) {
                                /*
                                 * Mustn't write here until the bad block
                                 * is acknowledged
@@ -1360,8 +1333,9 @@ retry_wait:
        if (unlikely(blocked_rdev)) {
                /* Have to wait for this device to get unblocked, then retry */
                allow_barrier(conf);
-               raid10_log(conf->mddev, "%s wait rdev %d blocked",
-                               __func__, blocked_rdev->raid_disk);
+               mddev_add_trace_msg(conf->mddev,
+                       "raid10 %s wait rdev %d blocked",
+                       __func__, blocked_rdev->raid_disk);
                md_wait_for_blocked_rdev(blocked_rdev, mddev);
                wait_barrier(conf, false);
                goto retry_wait;
@@ -1416,7 +1390,8 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
                        bio_wouldblock_error(bio);
                        return;
                }
-               raid10_log(conf->mddev, "wait reshape metadata");
+               mddev_add_trace_msg(conf->mddev,
+                       "raid10 wait reshape metadata");
                wait_event(mddev->sb_wait,
                           !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
 
@@ -2131,10 +2106,9 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
                        continue;
                }
 
-               if (mddev->gendisk)
-                       disk_stack_limits(mddev->gendisk, rdev->bdev,
-                                         rdev->data_offset << 9);
-
+               err = mddev_stack_new_rdev(mddev, rdev);
+               if (err)
+                       return err;
                p->head_position = 0;
                p->recovery_disabled = mddev->recovery_disabled - 1;
                rdev->raid_disk = mirror;
@@ -2150,10 +2124,9 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
                clear_bit(In_sync, &rdev->flags);
                set_bit(Replacement, &rdev->flags);
                rdev->raid_disk = repl_slot;
-               err = 0;
-               if (mddev->gendisk)
-                       disk_stack_limits(mddev->gendisk, rdev->bdev,
-                                         rdev->data_offset << 9);
+               err = mddev_stack_new_rdev(mddev, rdev);
+               if (err)
+                       return err;
                conf->fullsync = 1;
                WRITE_ONCE(p->replacement, rdev);
        }
@@ -2290,8 +2263,6 @@ static void end_sync_write(struct bio *bio)
        struct mddev *mddev = r10_bio->mddev;
        struct r10conf *conf = mddev->private;
        int d;
-       sector_t first_bad;
-       int bad_sectors;
        int slot;
        int repl;
        struct md_rdev *rdev = NULL;
@@ -2312,11 +2283,10 @@ static void end_sync_write(struct bio *bio)
                                        &rdev->mddev->recovery);
                        set_bit(R10BIO_WriteError, &r10_bio->state);
                }
-       } else if (is_badblock(rdev,
-                            r10_bio->devs[slot].addr,
-                            r10_bio->sectors,
-                            &first_bad, &bad_sectors))
+       } else if (rdev_has_badblock(rdev, r10_bio->devs[slot].addr,
+                                    r10_bio->sectors)) {
                set_bit(R10BIO_MadeGood, &r10_bio->state);
+       }
 
        rdev_dec_pending(rdev, mddev);
 
@@ -2597,11 +2567,8 @@ static void recovery_request_write(struct mddev *mddev, struct r10bio *r10_bio)
 static int r10_sync_page_io(struct md_rdev *rdev, sector_t sector,
                            int sectors, struct page *page, enum req_op op)
 {
-       sector_t first_bad;
-       int bad_sectors;
-
-       if (is_badblock(rdev, sector, sectors, &first_bad, &bad_sectors)
-           && (op == REQ_OP_READ || test_bit(WriteErrorSeen, &rdev->flags)))
+       if (rdev_has_badblock(rdev, sector, sectors) &&
+           (op == REQ_OP_READ || test_bit(WriteErrorSeen, &rdev->flags)))
                return -1;
        if (sync_page_io(rdev, sector, sectors << 9, page, op, false))
                /* success */
@@ -2658,16 +2625,14 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
                        s = PAGE_SIZE >> 9;
 
                do {
-                       sector_t first_bad;
-                       int bad_sectors;
-
                        d = r10_bio->devs[sl].devnum;
                        rdev = conf->mirrors[d].rdev;
                        if (rdev &&
                            test_bit(In_sync, &rdev->flags) &&
                            !test_bit(Faulty, &rdev->flags) &&
-                           is_badblock(rdev, r10_bio->devs[sl].addr + sect, s,
-                                       &first_bad, &bad_sectors) == 0) {
+                           rdev_has_badblock(rdev,
+                                             r10_bio->devs[sl].addr + sect,
+                                             s) == 0) {
                                atomic_inc(&rdev->nr_pending);
                                success = sync_page_io(rdev,
                                                       r10_bio->devs[sl].addr +
@@ -4002,14 +3967,26 @@ static struct r10conf *setup_conf(struct mddev *mddev)
        return ERR_PTR(err);
 }
 
-static void raid10_set_io_opt(struct r10conf *conf)
+static unsigned int raid10_nr_stripes(struct r10conf *conf)
 {
-       int raid_disks = conf->geo.raid_disks;
+       unsigned int raid_disks = conf->geo.raid_disks;
+
+       if (conf->geo.raid_disks % conf->geo.near_copies)
+               return raid_disks;
+       return raid_disks / conf->geo.near_copies;
+}
 
-       if (!(conf->geo.raid_disks % conf->geo.near_copies))
-               raid_disks /= conf->geo.near_copies;
-       blk_queue_io_opt(conf->mddev->queue, (conf->mddev->chunk_sectors << 9) *
-                        raid_disks);
+static int raid10_set_queue_limits(struct mddev *mddev)
+{
+       struct r10conf *conf = mddev->private;
+       struct queue_limits lim;
+
+       blk_set_stacking_limits(&lim);
+       lim.max_write_zeroes_sectors = 0;
+       lim.io_min = mddev->chunk_sectors << 9;
+       lim.io_opt = lim.io_min * raid10_nr_stripes(conf);
+       mddev_stack_rdev_limits(mddev, &lim);
+       return queue_limits_set(mddev->gendisk->queue, &lim);
 }
 
 static int raid10_run(struct mddev *mddev)
@@ -4021,6 +3998,7 @@ static int raid10_run(struct mddev *mddev)
        sector_t size;
        sector_t min_offset_diff = 0;
        int first = 1;
+       int ret = -EIO;
 
        if (mddev->private == NULL) {
                conf = setup_conf(mddev);
@@ -4047,12 +4025,6 @@ static int raid10_run(struct mddev *mddev)
                }
        }
 
-       if (mddev->queue) {
-               blk_queue_max_write_zeroes_sectors(mddev->queue, 0);
-               blk_queue_io_min(mddev->queue, mddev->chunk_sectors << 9);
-               raid10_set_io_opt(conf);
-       }
-
        rdev_for_each(rdev, mddev) {
                long long diff;
 
@@ -4081,14 +4053,16 @@ static int raid10_run(struct mddev *mddev)
                if (first || diff < min_offset_diff)
                        min_offset_diff = diff;
 
-               if (mddev->gendisk)
-                       disk_stack_limits(mddev->gendisk, rdev->bdev,
-                                         rdev->data_offset << 9);
-
                disk->head_position = 0;
                first = 0;
        }
 
+       if (!mddev_is_dm(conf->mddev)) {
+               ret = raid10_set_queue_limits(mddev);
+               if (ret)
+                       goto out_free_conf;
+       }
+
        /* need to check that every block has at least one working mirror */
        if (!enough(conf, -1)) {
                pr_err("md/raid10:%s: not enough operational mirrors.\n",
@@ -4175,11 +4149,7 @@ static int raid10_run(struct mddev *mddev)
                clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
                clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
                set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
-               set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
-               rcu_assign_pointer(mddev->sync_thread,
-                       md_register_thread(md_do_sync, mddev, "reshape"));
-               if (!mddev->sync_thread)
-                       goto out_free_conf;
+               set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        }
 
        return 0;
@@ -4189,7 +4159,7 @@ out_free_conf:
        raid10_free_conf(conf);
        mddev->private = NULL;
 out:
-       return -EIO;
+       return ret;
 }
 
 static void raid10_free(struct mddev *mddev, void *priv)
@@ -4573,16 +4543,8 @@ out:
        clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
        clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
        set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
-       set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
-
-       rcu_assign_pointer(mddev->sync_thread,
-                          md_register_thread(md_do_sync, mddev, "reshape"));
-       if (!mddev->sync_thread) {
-               ret = -EAGAIN;
-               goto abort;
-       }
+       set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        conf->reshape_checkpoint = jiffies;
-       md_wakeup_thread(mddev->sync_thread);
        md_new_event();
        return 0;
 
@@ -4966,8 +4928,7 @@ static void end_reshape(struct r10conf *conf)
        conf->reshape_safe = MaxSector;
        spin_unlock_irq(&conf->device_lock);
 
-       if (conf->mddev->queue)
-               raid10_set_io_opt(conf);
+       mddev_update_io_opt(conf->mddev, raid10_nr_stripes(conf));
        conf->fullsync = 0;
 }
 
index da4ba736c4f0c942e15fca6c4ce65649e82ffe93..a70cbec12ed01737874659ed2ac3c65987a5dc9f 100644 (file)
@@ -1393,7 +1393,8 @@ int ppl_init_log(struct r5conf *conf)
                ppl_conf->signature = ~crc32c_le(~0, mddev->uuid, sizeof(mddev->uuid));
                ppl_conf->block_size = 512;
        } else {
-               ppl_conf->block_size = queue_logical_block_size(mddev->queue);
+               ppl_conf->block_size =
+                       queue_logical_block_size(mddev->gendisk->queue);
        }
 
        for (i = 0; i < ppl_conf->count; i++) {
index 8497880135ee4269ef329e58a10757870ae2df18..d874abfc18364ec17cd91b4b5d11930259859305 100644 (file)
@@ -36,6 +36,7 @@
  */
 
 #include <linux/blkdev.h>
+#include <linux/delay.h>
 #include <linux/kthread.h>
 #include <linux/raid/pq.h>
 #include <linux/async_tx.h>
@@ -760,6 +761,7 @@ enum stripe_result {
        STRIPE_RETRY,
        STRIPE_SCHEDULE_AND_RETRY,
        STRIPE_FAIL,
+       STRIPE_WAIT_RESHAPE,
 };
 
 struct stripe_request_ctx {
@@ -1210,10 +1212,8 @@ again:
                 */
                while (op_is_write(op) && rdev &&
                       test_bit(WriteErrorSeen, &rdev->flags)) {
-                       sector_t first_bad;
-                       int bad_sectors;
-                       int bad = is_badblock(rdev, sh->sector, RAID5_STRIPE_SECTORS(conf),
-                                             &first_bad, &bad_sectors);
+                       int bad = rdev_has_badblock(rdev, sh->sector,
+                                                   RAID5_STRIPE_SECTORS(conf));
                        if (!bad)
                                break;
 
@@ -1295,10 +1295,7 @@ again:
                        if (rrdev)
                                set_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags);
 
-                       if (conf->mddev->gendisk)
-                               trace_block_bio_remap(bi,
-                                               disk_devt(conf->mddev->gendisk),
-                                               sh->dev[i].sector);
+                       mddev_trace_remap(conf->mddev, bi, sh->dev[i].sector);
                        if (should_defer && op_is_write(op))
                                bio_list_add(&pending_bios, bi);
                        else
@@ -1342,10 +1339,7 @@ again:
                         */
                        if (op == REQ_OP_DISCARD)
                                rbi->bi_vcnt = 0;
-                       if (conf->mddev->gendisk)
-                               trace_block_bio_remap(rbi,
-                                               disk_devt(conf->mddev->gendisk),
-                                               sh->dev[i].sector);
+                       mddev_trace_remap(conf->mddev, rbi, sh->dev[i].sector);
                        if (should_defer && op_is_write(op))
                                bio_list_add(&pending_bios, rbi);
                        else
@@ -2412,7 +2406,7 @@ static int grow_one_stripe(struct r5conf *conf, gfp_t gfp)
        atomic_inc(&conf->active_stripes);
 
        raid5_release_stripe(sh);
-       conf->max_nr_stripes++;
+       WRITE_ONCE(conf->max_nr_stripes, conf->max_nr_stripes + 1);
        return 1;
 }
 
@@ -2422,12 +2416,12 @@ static int grow_stripes(struct r5conf *conf, int num)
        size_t namelen = sizeof(conf->cache_name[0]);
        int devs = max(conf->raid_disks, conf->previous_raid_disks);
 
-       if (conf->mddev->gendisk)
+       if (mddev_is_dm(conf->mddev))
                snprintf(conf->cache_name[0], namelen,
-                       "raid%d-%s", conf->level, mdname(conf->mddev));
+                       "raid%d-%p", conf->level, conf->mddev);
        else
                snprintf(conf->cache_name[0], namelen,
-                       "raid%d-%p", conf->level, conf->mddev);
+                       "raid%d-%s", conf->level, mdname(conf->mddev));
        snprintf(conf->cache_name[1], namelen, "%.27s-alt", conf->cache_name[0]);
 
        conf->active_name = 0;
@@ -2707,7 +2701,7 @@ static int drop_one_stripe(struct r5conf *conf)
        shrink_buffers(sh);
        free_stripe(conf->slab_cache, sh);
        atomic_dec(&conf->active_stripes);
-       conf->max_nr_stripes--;
+       WRITE_ONCE(conf->max_nr_stripes, conf->max_nr_stripes - 1);
        return 1;
 }
 
@@ -2855,8 +2849,6 @@ static void raid5_end_write_request(struct bio *bi)
        struct r5conf *conf = sh->raid_conf;
        int disks = sh->disks, i;
        struct md_rdev *rdev;
-       sector_t first_bad;
-       int bad_sectors;
        int replacement = 0;
 
        for (i = 0 ; i < disks; i++) {
@@ -2888,9 +2880,8 @@ static void raid5_end_write_request(struct bio *bi)
        if (replacement) {
                if (bi->bi_status)
                        md_error(conf->mddev, rdev);
-               else if (is_badblock(rdev, sh->sector,
-                                    RAID5_STRIPE_SECTORS(conf),
-                                    &first_bad, &bad_sectors))
+               else if (rdev_has_badblock(rdev, sh->sector,
+                                          RAID5_STRIPE_SECTORS(conf)))
                        set_bit(R5_MadeGoodRepl, &sh->dev[i].flags);
        } else {
                if (bi->bi_status) {
@@ -2900,9 +2891,8 @@ static void raid5_end_write_request(struct bio *bi)
                        if (!test_and_set_bit(WantReplacement, &rdev->flags))
                                set_bit(MD_RECOVERY_NEEDED,
                                        &rdev->mddev->recovery);
-               } else if (is_badblock(rdev, sh->sector,
-                                      RAID5_STRIPE_SECTORS(conf),
-                                      &first_bad, &bad_sectors)) {
+               } else if (rdev_has_badblock(rdev, sh->sector,
+                                            RAID5_STRIPE_SECTORS(conf))) {
                        set_bit(R5_MadeGood, &sh->dev[i].flags);
                        if (test_bit(R5_ReadError, &sh->dev[i].flags))
                                /* That was a successful write so make
@@ -4205,10 +4195,9 @@ static int handle_stripe_dirtying(struct r5conf *conf,
        set_bit(STRIPE_HANDLE, &sh->state);
        if ((rmw < rcw || (rmw == rcw && conf->rmw_level == PARITY_PREFER_RMW)) && rmw > 0) {
                /* prefer read-modify-write, but need to get some data */
-               if (conf->mddev->queue)
-                       blk_add_trace_msg(conf->mddev->queue,
-                                         "raid5 rmw %llu %d",
-                                         (unsigned long long)sh->sector, rmw);
+               mddev_add_trace_msg(conf->mddev, "raid5 rmw %llu %d",
+                               sh->sector, rmw);
+
                for (i = disks; i--; ) {
                        struct r5dev *dev = &sh->dev[i];
                        if (test_bit(R5_InJournal, &dev->flags) &&
@@ -4285,10 +4274,11 @@ static int handle_stripe_dirtying(struct r5conf *conf,
                                        set_bit(STRIPE_DELAYED, &sh->state);
                        }
                }
-               if (rcw && conf->mddev->queue)
-                       blk_add_trace_msg(conf->mddev->queue, "raid5 rcw %llu %d %d %d",
-                                         (unsigned long long)sh->sector,
-                                         rcw, qread, test_bit(STRIPE_DELAYED, &sh->state));
+               if (rcw && !mddev_is_dm(conf->mddev))
+                       blk_add_trace_msg(conf->mddev->gendisk->queue,
+                               "raid5 rcw %llu %d %d %d",
+                               (unsigned long long)sh->sector, rcw, qread,
+                               test_bit(STRIPE_DELAYED, &sh->state));
        }
 
        if (rcw > disks && rmw > disks &&
@@ -4674,8 +4664,6 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
        /* Now to look around and see what can be done */
        for (i=disks; i--; ) {
                struct md_rdev *rdev;
-               sector_t first_bad;
-               int bad_sectors;
                int is_bad = 0;
 
                dev = &sh->dev[i];
@@ -4719,8 +4707,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
                rdev = conf->disks[i].replacement;
                if (rdev && !test_bit(Faulty, &rdev->flags) &&
                    rdev->recovery_offset >= sh->sector + RAID5_STRIPE_SECTORS(conf) &&
-                   !is_badblock(rdev, sh->sector, RAID5_STRIPE_SECTORS(conf),
-                                &first_bad, &bad_sectors))
+                   !rdev_has_badblock(rdev, sh->sector,
+                                      RAID5_STRIPE_SECTORS(conf)))
                        set_bit(R5_ReadRepl, &dev->flags);
                else {
                        if (rdev && !test_bit(Faulty, &rdev->flags))
@@ -4733,8 +4721,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
                if (rdev && test_bit(Faulty, &rdev->flags))
                        rdev = NULL;
                if (rdev) {
-                       is_bad = is_badblock(rdev, sh->sector, RAID5_STRIPE_SECTORS(conf),
-                                            &first_bad, &bad_sectors);
+                       is_bad = rdev_has_badblock(rdev, sh->sector,
+                                                  RAID5_STRIPE_SECTORS(conf));
                        if (s->blocked_rdev == NULL
                            && (test_bit(Blocked, &rdev->flags)
                                || is_bad < 0)) {
@@ -5463,8 +5451,8 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio)
        struct r5conf *conf = mddev->private;
        struct bio *align_bio;
        struct md_rdev *rdev;
-       sector_t sector, end_sector, first_bad;
-       int bad_sectors, dd_idx;
+       sector_t sector, end_sector;
+       int dd_idx;
        bool did_inc;
 
        if (!in_chunk_boundary(mddev, raid_bio)) {
@@ -5493,8 +5481,7 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio)
 
        atomic_inc(&rdev->nr_pending);
 
-       if (is_badblock(rdev, sector, bio_sectors(raid_bio), &first_bad,
-                       &bad_sectors)) {
+       if (rdev_has_badblock(rdev, sector, bio_sectors(raid_bio))) {
                rdev_dec_pending(rdev, mddev);
                return 0;
        }
@@ -5530,9 +5517,7 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio)
                spin_unlock_irq(&conf->device_lock);
        }
 
-       if (mddev->gendisk)
-               trace_block_bio_remap(align_bio, disk_devt(mddev->gendisk),
-                                     raid_bio->bi_iter.bi_sector);
+       mddev_trace_remap(mddev, align_bio, raid_bio->bi_iter.bi_sector);
        submit_bio_noacct(align_bio);
        return 1;
 }
@@ -5701,8 +5686,8 @@ static void raid5_unplug(struct blk_plug_cb *blk_cb, bool from_schedule)
        }
        release_inactive_stripe_list(conf, cb->temp_inactive_list,
                                     NR_STRIPE_HASH_LOCKS);
-       if (mddev->queue)
-               trace_block_unplug(mddev->queue, cnt, !from_schedule);
+       if (!mddev_is_dm(mddev))
+               trace_block_unplug(mddev->gendisk->queue, cnt, !from_schedule);
        kfree(cb);
 }
 
@@ -5946,7 +5931,8 @@ static enum stripe_result make_stripe_request(struct mddev *mddev,
                        if (ahead_of_reshape(mddev, logical_sector,
                                             conf->reshape_safe)) {
                                spin_unlock_irq(&conf->device_lock);
-                               return STRIPE_SCHEDULE_AND_RETRY;
+                               ret = STRIPE_SCHEDULE_AND_RETRY;
+                               goto out;
                        }
                }
                spin_unlock_irq(&conf->device_lock);
@@ -6025,6 +6011,12 @@ static enum stripe_result make_stripe_request(struct mddev *mddev,
 
 out_release:
        raid5_release_stripe(sh);
+out:
+       if (ret == STRIPE_SCHEDULE_AND_RETRY && reshape_interrupted(mddev)) {
+               bi->bi_status = BLK_STS_RESOURCE;
+               ret = STRIPE_WAIT_RESHAPE;
+               pr_err_ratelimited("dm-raid456: io across reshape position while reshape can't make progress");
+       }
        return ret;
 }
 
@@ -6146,7 +6138,7 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
        while (1) {
                res = make_stripe_request(mddev, conf, &ctx, logical_sector,
                                          bi);
-               if (res == STRIPE_FAIL)
+               if (res == STRIPE_FAIL || res == STRIPE_WAIT_RESHAPE)
                        break;
 
                if (res == STRIPE_RETRY)
@@ -6184,6 +6176,11 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
 
        if (rw == WRITE)
                md_write_end(mddev);
+       if (res == STRIPE_WAIT_RESHAPE) {
+               md_free_cloned_bio(bi);
+               return false;
+       }
+
        bio_endio(bi);
        return true;
 }
@@ -6773,7 +6770,18 @@ static void raid5d(struct md_thread *thread)
                        spin_unlock_irq(&conf->device_lock);
                        md_check_recovery(mddev);
                        spin_lock_irq(&conf->device_lock);
+
+                       /*
+                        * Waiting on MD_SB_CHANGE_PENDING below may deadlock
+                        * seeing md_check_recovery() is needed to clear
+                        * the flag when using mdmon.
+                        */
+                       continue;
                }
+
+               wait_event_lock_irq(mddev->sb_wait,
+                       !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags),
+                       conf->device_lock);
        }
        pr_debug("%d stripes handled\n", handled);
 
@@ -6820,7 +6828,7 @@ raid5_set_cache_size(struct mddev *mddev, int size)
        if (size <= 16 || size > 32768)
                return -EINVAL;
 
-       conf->min_nr_stripes = size;
+       WRITE_ONCE(conf->min_nr_stripes, size);
        mutex_lock(&conf->cache_size_mutex);
        while (size < conf->max_nr_stripes &&
               drop_one_stripe(conf))
@@ -6832,7 +6840,7 @@ raid5_set_cache_size(struct mddev *mddev, int size)
        mutex_lock(&conf->cache_size_mutex);
        while (size > conf->max_nr_stripes)
                if (!grow_one_stripe(conf, GFP_KERNEL)) {
-                       conf->min_nr_stripes = conf->max_nr_stripes;
+                       WRITE_ONCE(conf->min_nr_stripes, conf->max_nr_stripes);
                        result = -ENOMEM;
                        break;
                }
@@ -6967,10 +6975,8 @@ raid5_store_stripe_size(struct mddev  *mddev, const char *page, size_t len)
        pr_debug("md/raid: change stripe_size from %lu to %lu\n",
                        conf->stripe_size, new);
 
-       if (mddev->sync_thread ||
-               test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
-               mddev->reshape_position != MaxSector ||
-               mddev->sysfs_active) {
+       if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+           mddev->reshape_position != MaxSector || mddev->sysfs_active) {
                err = -EBUSY;
                goto out_unlock;
        }
@@ -7084,7 +7090,7 @@ raid5_store_skip_copy(struct mddev *mddev, const char *page, size_t len)
        if (!conf)
                err = -ENODEV;
        else if (new != conf->skip_copy) {
-               struct request_queue *q = mddev->queue;
+               struct request_queue *q = mddev->gendisk->queue;
 
                conf->skip_copy = new;
                if (new)
@@ -7390,11 +7396,13 @@ static unsigned long raid5_cache_count(struct shrinker *shrink,
                                       struct shrink_control *sc)
 {
        struct r5conf *conf = shrink->private_data;
+       int max_stripes = READ_ONCE(conf->max_nr_stripes);
+       int min_stripes = READ_ONCE(conf->min_nr_stripes);
 
-       if (conf->max_nr_stripes < conf->min_nr_stripes)
+       if (max_stripes < min_stripes)
                /* unlikely, but not impossible */
                return 0;
-       return conf->max_nr_stripes - conf->min_nr_stripes;
+       return max_stripes - min_stripes;
 }
 
 static struct r5conf *setup_conf(struct mddev *mddev)
@@ -7684,10 +7692,65 @@ static int only_parity(int raid_disk, int algo, int raid_disks, int max_degraded
        return 0;
 }
 
-static void raid5_set_io_opt(struct r5conf *conf)
+static int raid5_set_limits(struct mddev *mddev)
 {
-       blk_queue_io_opt(conf->mddev->queue, (conf->chunk_sectors << 9) *
-                        (conf->raid_disks - conf->max_degraded));
+       struct r5conf *conf = mddev->private;
+       struct queue_limits lim;
+       int data_disks, stripe;
+       struct md_rdev *rdev;
+
+       /*
+        * The read-ahead size must cover two whole stripes, which is
+        * 2 * (datadisks) * chunksize where 'n' is the number of raid devices.
+        */
+       data_disks = conf->previous_raid_disks - conf->max_degraded;
+
+       /*
+        * We can only discard a whole stripe. It doesn't make sense to
+        * discard data disk but write parity disk
+        */
+       stripe = roundup_pow_of_two(data_disks * (mddev->chunk_sectors << 9));
+
+       blk_set_stacking_limits(&lim);
+       lim.io_min = mddev->chunk_sectors << 9;
+       lim.io_opt = lim.io_min * (conf->raid_disks - conf->max_degraded);
+       lim.raid_partial_stripes_expensive = 1;
+       lim.discard_granularity = stripe;
+       lim.max_write_zeroes_sectors = 0;
+       mddev_stack_rdev_limits(mddev, &lim);
+       rdev_for_each(rdev, mddev)
+               queue_limits_stack_bdev(&lim, rdev->bdev, rdev->new_data_offset,
+                               mddev->gendisk->disk_name);
+
+       /*
+        * Zeroing is required for discard, otherwise data could be lost.
+        *
+        * Consider a scenario: discard a stripe (the stripe could be
+        * inconsistent if discard_zeroes_data is 0); write one disk of the
+        * stripe (the stripe could be inconsistent again depending on which
+        * disks are used to calculate parity); the disk is broken; The stripe
+        * data of this disk is lost.
+        *
+        * We only allow DISCARD if the sysadmin has confirmed that only safe
+        * devices are in use by setting a module parameter.  A better idea
+        * might be to turn DISCARD into WRITE_ZEROES requests, as that is
+        * required to be safe.
+        */
+       if (!devices_handle_discard_safely ||
+           lim.max_discard_sectors < (stripe >> 9) ||
+           lim.discard_granularity < stripe)
+               lim.max_hw_discard_sectors = 0;
+
+       /*
+        * Requests require having a bitmap for each stripe.
+        * Limit the max sectors based on this.
+        */
+       lim.max_hw_sectors = RAID5_MAX_REQ_STRIPES << RAID5_STRIPE_SHIFT(conf);
+
+       /* No restrictions on the number of segments in the request */
+       lim.max_segments = USHRT_MAX;
+
+       return queue_limits_set(mddev->gendisk->queue, &lim);
 }
 
 static int raid5_run(struct mddev *mddev)
@@ -7700,6 +7763,7 @@ static int raid5_run(struct mddev *mddev)
        int i;
        long long min_offset_diff = 0;
        int first = 1;
+       int ret = -EIO;
 
        if (mddev->recovery_cp != MaxSector)
                pr_notice("md/raid:%s: not clean -- starting background reconstruction\n",
@@ -7936,11 +8000,7 @@ static int raid5_run(struct mddev *mddev)
                clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
                clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
                set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
-               set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
-               rcu_assign_pointer(mddev->sync_thread,
-                       md_register_thread(md_do_sync, mddev, "reshape"));
-               if (!mddev->sync_thread)
-                       goto abort;
+               set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        }
 
        /* Ok, everything is just fine now */
@@ -7952,66 +8012,10 @@ static int raid5_run(struct mddev *mddev)
                        mdname(mddev));
        md_set_array_sectors(mddev, raid5_size(mddev, 0, 0));
 
-       if (mddev->queue) {
-               int chunk_size;
-               /* read-ahead size must cover two whole stripes, which
-                * is 2 * (datadisks) * chunksize where 'n' is the
-                * number of raid devices
-                */
-               int data_disks = conf->previous_raid_disks - conf->max_degraded;
-               int stripe = data_disks *
-                       ((mddev->chunk_sectors << 9) / PAGE_SIZE);
-
-               chunk_size = mddev->chunk_sectors << 9;
-               blk_queue_io_min(mddev->queue, chunk_size);
-               raid5_set_io_opt(conf);
-               mddev->queue->limits.raid_partial_stripes_expensive = 1;
-               /*
-                * We can only discard a whole stripe. It doesn't make sense to
-                * discard data disk but write parity disk
-                */
-               stripe = stripe * PAGE_SIZE;
-               stripe = roundup_pow_of_two(stripe);
-               mddev->queue->limits.discard_granularity = stripe;
-
-               blk_queue_max_write_zeroes_sectors(mddev->queue, 0);
-
-               rdev_for_each(rdev, mddev) {
-                       disk_stack_limits(mddev->gendisk, rdev->bdev,
-                                         rdev->data_offset << 9);
-                       disk_stack_limits(mddev->gendisk, rdev->bdev,
-                                         rdev->new_data_offset << 9);
-               }
-
-               /*
-                * zeroing is required, otherwise data
-                * could be lost. Consider a scenario: discard a stripe
-                * (the stripe could be inconsistent if
-                * discard_zeroes_data is 0); write one disk of the
-                * stripe (the stripe could be inconsistent again
-                * depending on which disks are used to calculate
-                * parity); the disk is broken; The stripe data of this
-                * disk is lost.
-                *
-                * We only allow DISCARD if the sysadmin has confirmed that
-                * only safe devices are in use by setting a module parameter.
-                * A better idea might be to turn DISCARD into WRITE_ZEROES
-                * requests, as that is required to be safe.
-                */
-               if (!devices_handle_discard_safely ||
-                   mddev->queue->limits.max_discard_sectors < (stripe >> 9) ||
-                   mddev->queue->limits.discard_granularity < stripe)
-                       blk_queue_max_discard_sectors(mddev->queue, 0);
-
-               /*
-                * Requests require having a bitmap for each stripe.
-                * Limit the max sectors based on this.
-                */
-               blk_queue_max_hw_sectors(mddev->queue,
-                       RAID5_MAX_REQ_STRIPES << RAID5_STRIPE_SHIFT(conf));
-
-               /* No restrictions on the number of segments in the request */
-               blk_queue_max_segments(mddev->queue, USHRT_MAX);
+       if (!mddev_is_dm(mddev)) {
+               ret = raid5_set_limits(mddev);
+               if (ret)
+                       goto abort;
        }
 
        if (log_init(conf, journal_dev, raid5_has_ppl(conf)))
@@ -8024,7 +8028,7 @@ abort:
        free_conf(conf);
        mddev->private = NULL;
        pr_warn("md/raid:%s: failed to run raid set.\n", mdname(mddev));
-       return -EIO;
+       return ret;
 }
 
 static void raid5_free(struct mddev *mddev, void *priv)
@@ -8506,29 +8510,8 @@ static int raid5_start_reshape(struct mddev *mddev)
        clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
        clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
        set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
-       set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
-       rcu_assign_pointer(mddev->sync_thread,
-                          md_register_thread(md_do_sync, mddev, "reshape"));
-       if (!mddev->sync_thread) {
-               mddev->recovery = 0;
-               spin_lock_irq(&conf->device_lock);
-               write_seqcount_begin(&conf->gen_lock);
-               mddev->raid_disks = conf->raid_disks = conf->previous_raid_disks;
-               mddev->new_chunk_sectors =
-                       conf->chunk_sectors = conf->prev_chunk_sectors;
-               mddev->new_layout = conf->algorithm = conf->prev_algo;
-               rdev_for_each(rdev, mddev)
-                       rdev->new_data_offset = rdev->data_offset;
-               smp_wmb();
-               conf->generation --;
-               conf->reshape_progress = MaxSector;
-               mddev->reshape_position = MaxSector;
-               write_seqcount_end(&conf->gen_lock);
-               spin_unlock_irq(&conf->device_lock);
-               return -EAGAIN;
-       }
+       set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        conf->reshape_checkpoint = jiffies;
-       md_wakeup_thread(mddev->sync_thread);
        md_new_event();
        return 0;
 }
@@ -8556,8 +8539,8 @@ static void end_reshape(struct r5conf *conf)
                spin_unlock_irq(&conf->device_lock);
                wake_up(&conf->wait_for_overlap);
 
-               if (conf->mddev->queue)
-                       raid5_set_io_opt(conf);
+               mddev_update_io_opt(conf->mddev,
+                       conf->raid_disks - conf->max_degraded);
        }
 }
 
@@ -8934,6 +8917,18 @@ static int raid5_start(struct mddev *mddev)
        return r5l_start(conf->log);
 }
 
+/*
+ * This is only used for dm-raid456, caller already frozen sync_thread, hence
+ * if rehsape is still in progress, io that is waiting for reshape can never be
+ * done now, hence wake up and handle those IO.
+ */
+static void raid5_prepare_suspend(struct mddev *mddev)
+{
+       struct r5conf *conf = mddev->private;
+
+       wake_up(&conf->wait_for_overlap);
+}
+
 static struct md_personality raid6_personality =
 {
        .name           = "raid6",
@@ -8957,6 +8952,7 @@ static struct md_personality raid6_personality =
        .quiesce        = raid5_quiesce,
        .takeover       = raid6_takeover,
        .change_consistency_policy = raid5_change_consistency_policy,
+       .prepare_suspend = raid5_prepare_suspend,
 };
 static struct md_personality raid5_personality =
 {
@@ -8981,6 +8977,7 @@ static struct md_personality raid5_personality =
        .quiesce        = raid5_quiesce,
        .takeover       = raid5_takeover,
        .change_consistency_policy = raid5_change_consistency_policy,
+       .prepare_suspend = raid5_prepare_suspend,
 };
 
 static struct md_personality raid4_personality =
@@ -9006,6 +9003,7 @@ static struct md_personality raid4_personality =
        .quiesce        = raid5_quiesce,
        .takeover       = raid4_takeover,
        .change_consistency_policy = raid5_change_consistency_policy,
+       .prepare_suspend = raid5_prepare_suspend,
 };
 
 static int __init raid5_init(void)
index aebd3c12020bfd5d104c089354da0557de93547d..c381c22135a217b71e82f8282699cfbe14749ded 100644 (file)
@@ -725,6 +725,9 @@ irqreturn_t rkisp1_capture_isr(int irq, void *ctx)
        unsigned int i;
        u32 status;
 
+       if (!rkisp1->irqs_enabled)
+               return IRQ_NONE;
+
        status = rkisp1_read(rkisp1, RKISP1_CIF_MI_MIS);
        if (!status)
                return IRQ_NONE;
index 4b6b28c05b8916b7e5e079b6d2791009907c22db..b757f75edecf75256525e378151fe217c88ef2c4 100644 (file)
@@ -450,6 +450,7 @@ struct rkisp1_debug {
  * @debug:        debug params to be exposed on debugfs
  * @info:         version-specific ISP information
  * @irqs:          IRQ line numbers
+ * @irqs_enabled:  the hardware is enabled and can cause interrupts
  */
 struct rkisp1_device {
        void __iomem *base_addr;
@@ -471,6 +472,7 @@ struct rkisp1_device {
        struct rkisp1_debug debug;
        const struct rkisp1_info *info;
        int irqs[RKISP1_NUM_IRQS];
+       bool irqs_enabled;
 };
 
 /*
index b6e47e2f1b94916e51ec86b38d12b37ae186609d..4202642e052392a946761ecb76d3cfa771956e07 100644 (file)
@@ -196,6 +196,9 @@ irqreturn_t rkisp1_csi_isr(int irq, void *ctx)
        struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
        u32 val, status;
 
+       if (!rkisp1->irqs_enabled)
+               return IRQ_NONE;
+
        status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS);
        if (!status)
                return IRQ_NONE;
index f96f821a7b50d0f10db51932d2b82986dcb16957..73cf08a740118c05328fdd3f1a9d52a6e935c4e0 100644 (file)
@@ -305,6 +305,24 @@ static int __maybe_unused rkisp1_runtime_suspend(struct device *dev)
 {
        struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
 
+       rkisp1->irqs_enabled = false;
+       /* Make sure the IRQ handler will see the above */
+       mb();
+
+       /*
+        * Wait until any running IRQ handler has returned. The IRQ handler
+        * may get called even after this (as it's a shared interrupt line)
+        * but the 'irqs_enabled' flag will make the handler return immediately.
+        */
+       for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) {
+               if (rkisp1->irqs[il] == -1)
+                       continue;
+
+               /* Skip if the irq line is the same as previous */
+               if (il == 0 || rkisp1->irqs[il - 1] != rkisp1->irqs[il])
+                       synchronize_irq(rkisp1->irqs[il]);
+       }
+
        clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks);
        return pinctrl_pm_select_sleep_state(dev);
 }
@@ -321,6 +339,10 @@ static int __maybe_unused rkisp1_runtime_resume(struct device *dev)
        if (ret)
                return ret;
 
+       rkisp1->irqs_enabled = true;
+       /* Make sure the IRQ handler will see the above */
+       mb();
+
        return 0;
 }
 
@@ -559,7 +581,7 @@ static int rkisp1_probe(struct platform_device *pdev)
                                rkisp1->irqs[il] = irq;
                }
 
-               ret = devm_request_irq(dev, irq, info->isrs[i].isr, 0,
+               ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED,
                                       dev_driver_string(dev), dev);
                if (ret) {
                        dev_err(dev, "request irq failed: %d\n", ret);
index f00873d31c42b702d239e9e9fefcb8eddb599275..78a1f7a1499be84f15b94d75b30266dfb8c720ce 100644 (file)
@@ -976,6 +976,9 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx)
        struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
        u32 status, isp_err;
 
+       if (!rkisp1->irqs_enabled)
+               return IRQ_NONE;
+
        status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS);
        if (!status)
                return IRQ_NONE;
index 2afe67ffa285e3755f35c5842827160b93f573b5..74d69ce22a33e801762bc156c8c40289b2b2d4cb 100644 (file)
@@ -319,6 +319,7 @@ config IR_PWM_TX
        tristate "PWM IR transmitter"
        depends on LIRC
        depends on PWM
+       depends on HIGH_RES_TIMERS
        depends on OF
        help
           Say Y if you want to use a PWM based IR transmitter. This is
index fe17c7f98e8101afdae3d608ab12a2ef7f971d0e..52d82cbe7685f5b5adadf4448a171fcb146612b8 100644 (file)
@@ -253,7 +253,7 @@ int lirc_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog)
        if (attr->attach_flags)
                return -EINVAL;
 
-       rcdev = rc_dev_get_from_fd(attr->target_fd);
+       rcdev = rc_dev_get_from_fd(attr->target_fd, true);
        if (IS_ERR(rcdev))
                return PTR_ERR(rcdev);
 
@@ -278,7 +278,7 @@ int lirc_prog_detach(const union bpf_attr *attr)
        if (IS_ERR(prog))
                return PTR_ERR(prog);
 
-       rcdev = rc_dev_get_from_fd(attr->target_fd);
+       rcdev = rc_dev_get_from_fd(attr->target_fd, true);
        if (IS_ERR(rcdev)) {
                bpf_prog_put(prog);
                return PTR_ERR(rcdev);
@@ -303,7 +303,7 @@ int lirc_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr)
        if (attr->query.query_flags)
                return -EINVAL;
 
-       rcdev = rc_dev_get_from_fd(attr->query.target_fd);
+       rcdev = rc_dev_get_from_fd(attr->query.target_fd, false);
        if (IS_ERR(rcdev))
                return PTR_ERR(rcdev);
 
index 1968067092594979942f030af29bf4b484b5fd09..69e630d85262f65f413ee8c9d092ea85cee01c91 100644 (file)
@@ -332,6 +332,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count)
                            sizeof(COMMAND_SMODE_EXIT), STATE_COMMAND_NO_RESP);
        if (err) {
                dev_err(irtoy->dev, "exit sample mode: %d\n", err);
+               kfree(buf);
                return err;
        }
 
@@ -339,6 +340,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count)
                            sizeof(COMMAND_SMODE_ENTER), STATE_COMMAND);
        if (err) {
                dev_err(irtoy->dev, "enter sample mode: %d\n", err);
+               kfree(buf);
                return err;
        }
 
index a537734832c5080498d263428a96d7b1d13dcb88..caad59f76793f750f757c8fe5e58fe569b6b4322 100644 (file)
@@ -814,7 +814,7 @@ void __exit lirc_dev_exit(void)
        unregister_chrdev_region(lirc_base_dev, RC_DEV_MAX);
 }
 
-struct rc_dev *rc_dev_get_from_fd(int fd)
+struct rc_dev *rc_dev_get_from_fd(int fd, bool write)
 {
        struct fd f = fdget(fd);
        struct lirc_fh *fh;
@@ -828,6 +828,9 @@ struct rc_dev *rc_dev_get_from_fd(int fd)
                return ERR_PTR(-EINVAL);
        }
 
+       if (write && !(f.file->f_mode & FMODE_WRITE))
+               return ERR_PTR(-EPERM);
+
        fh = f.file->private_data;
        dev = fh->rc;
 
index ef1e95e1af7fcccda49324e375b940cc92c627f2..7df949fc65e2b68bf88c12643410330fc1ad4635 100644 (file)
@@ -325,7 +325,7 @@ void lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev);
 void lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc);
 int lirc_register(struct rc_dev *dev);
 void lirc_unregister(struct rc_dev *dev);
-struct rc_dev *rc_dev_get_from_fd(int fd);
+struct rc_dev *rc_dev_get_from_fd(int fd, bool write);
 #else
 static inline int lirc_dev_init(void) { return 0; }
 static inline void lirc_dev_exit(void) {}
index 434982545be637331e535e13218d57b3e780d314..8c5ad5c025fad1636b94f19dd5a365ccb18cc973 100644 (file)
@@ -72,7 +72,6 @@ static DEFINE_SPINLOCK(emif_lock);
 static unsigned long   irq_state;
 static LIST_HEAD(device_list);
 
-#ifdef CONFIG_DEBUG_FS
 static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif,
        struct emif_regs *regs)
 {
@@ -140,31 +139,24 @@ static int emif_mr4_show(struct seq_file *s, void *unused)
 
 DEFINE_SHOW_ATTRIBUTE(emif_mr4);
 
-static int __init_or_module emif_debugfs_init(struct emif_data *emif)
+static void emif_debugfs_init(struct emif_data *emif)
 {
-       emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL);
-       debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif,
-                           &emif_regdump_fops);
-       debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif,
-                           &emif_mr4_fops);
-       return 0;
-}
-
-static void __exit emif_debugfs_exit(struct emif_data *emif)
-{
-       debugfs_remove_recursive(emif->debugfs_root);
-       emif->debugfs_root = NULL;
-}
-#else
-static inline int __init_or_module emif_debugfs_init(struct emif_data *emif)
-{
-       return 0;
+       if (IS_ENABLED(CONFIG_DEBUG_FS)) {
+               emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL);
+               debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif,
+                                   &emif_regdump_fops);
+               debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif,
+                                   &emif_mr4_fops);
+       }
 }
 
-static inline void __exit emif_debugfs_exit(struct emif_data *emif)
+static void emif_debugfs_exit(struct emif_data *emif)
 {
+       if (IS_ENABLED(CONFIG_DEBUG_FS)) {
+               debugfs_remove_recursive(emif->debugfs_root);
+               emif->debugfs_root = NULL;
+       }
 }
-#endif
 
 /*
  * Get bus width used by EMIF. Note that this may be different from the
@@ -679,7 +671,7 @@ static void disable_and_clear_all_interrupts(struct emif_data *emif)
        clear_all_interrupts(emif);
 }
 
-static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq)
+static int setup_interrupts(struct emif_data *emif, u32 irq)
 {
        u32             interrupts, type;
        void __iomem    *base = emif->base;
@@ -710,7 +702,7 @@ static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq)
 
 }
 
-static void __init_or_module emif_onetime_settings(struct emif_data *emif)
+static void emif_onetime_settings(struct emif_data *emif)
 {
        u32                             pwr_mgmt_ctrl, zq, temp_alert_cfg;
        void __iomem                    *base = emif->base;
@@ -834,8 +826,7 @@ static int is_custom_config_valid(struct emif_custom_configs *cust_cfgs,
        return valid;
 }
 
-#if defined(CONFIG_OF)
-static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
+static void of_get_custom_configs(struct device_node *np_emif,
                struct emif_data *emif)
 {
        struct emif_custom_configs      *cust_cfgs = NULL;
@@ -884,7 +875,7 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
        emif->plat_data->custom_configs = cust_cfgs;
 }
 
-static void __init_or_module of_get_ddr_info(struct device_node *np_emif,
+static void of_get_ddr_info(struct device_node *np_emif,
                struct device_node *np_ddr,
                struct ddr_device_info *dev_info)
 {
@@ -918,7 +909,7 @@ static void __init_or_module of_get_ddr_info(struct device_node *np_emif,
                dev_info->io_width = __fls(io_width) - 1;
 }
 
-static struct emif_data * __init_or_module of_get_memory_device_details(
+static struct emif_data *of_get_memory_device_details(
                struct device_node *np_emif, struct device *dev)
 {
        struct emif_data                *emif = NULL;
@@ -991,16 +982,7 @@ out:
        return emif;
 }
 
-#else
-
-static struct emif_data * __init_or_module of_get_memory_device_details(
-               struct device_node *np_emif, struct device *dev)
-{
-       return NULL;
-}
-#endif
-
-static struct emif_data *__init_or_module get_device_details(
+static struct emif_data *get_device_details(
                struct platform_device *pdev)
 {
        u32                             size;
@@ -1104,7 +1086,7 @@ error:
        return NULL;
 }
 
-static int __init_or_module emif_probe(struct platform_device *pdev)
+static int emif_probe(struct platform_device *pdev)
 {
        struct emif_data        *emif;
        int                     irq, ret;
@@ -1159,7 +1141,7 @@ error:
        return -ENODEV;
 }
 
-static void __exit emif_remove(struct platform_device *pdev)
+static void emif_remove(struct platform_device *pdev)
 {
        struct emif_data *emif = platform_get_drvdata(pdev);
 
@@ -1183,7 +1165,8 @@ MODULE_DEVICE_TABLE(of, emif_of_match);
 #endif
 
 static struct platform_driver emif_driver = {
-       .remove_new     = __exit_p(emif_remove),
+       .probe          = emif_probe,
+       .remove_new     = emif_remove,
        .shutdown       = emif_shutdown,
        .driver = {
                .name = "emif",
@@ -1191,7 +1174,7 @@ static struct platform_driver emif_driver = {
        },
 };
 
-module_platform_driver_probe(emif_driver, emif_probe);
+module_platform_driver(emif_driver);
 
 MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver");
 MODULE_LICENSE("GPL");
index 47d0ea5f16168461eaebdd842884e0cca0636ba8..1c63eeacd071cc080ce243d4eef9e0945bfe6bc9 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/of_platform.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/reset.h>
 
 #define FMC2_BCR(x)                    ((x) * 0x8 + FMC2_BCR1)
 #define FMC2_BTR(x)                    ((x) * 0x8 + FMC2_BTR1)
 #define FMC2_PCSCNTR                   0x20
+#define FMC2_CFGR                      0x20
+#define FMC2_SR                                0x84
 #define FMC2_BWTR1                     0x104
 #define FMC2_BWTR(x)                   ((x) * 0x8 + FMC2_BWTR1)
+#define FMC2_SECCFGR                   0x300
+#define FMC2_CIDCFGR0                  0x30c
+#define FMC2_CIDCFGR(x)                        ((x) * 0x8 + FMC2_CIDCFGR0)
+#define FMC2_SEMCR0                    0x310
+#define FMC2_SEMCR(x)                  ((x) * 0x8 + FMC2_SEMCR0)
 
 /* Register: FMC2_BCR1 */
 #define FMC2_BCR1_CCLKEN               BIT(20)
@@ -42,6 +50,7 @@
 #define FMC2_BCR_ASYNCWAIT             BIT(15)
 #define FMC2_BCR_CPSIZE                        GENMASK(18, 16)
 #define FMC2_BCR_CBURSTRW              BIT(19)
+#define FMC2_BCR_CSCOUNT               GENMASK(21, 20)
 #define FMC2_BCR_NBLSET                        GENMASK(23, 22)
 
 /* Register: FMC2_BTRx/FMC2_BWTRx */
 #define FMC2_PCSCNTR_CSCOUNT           GENMASK(15, 0)
 #define FMC2_PCSCNTR_CNTBEN(x)         BIT((x) + 16)
 
+/* Register: FMC2_CFGR */
+#define FMC2_CFGR_CLKDIV               GENMASK(19, 16)
+#define FMC2_CFGR_CCLKEN               BIT(20)
+#define FMC2_CFGR_FMC2EN               BIT(31)
+
+/* Register: FMC2_SR */
+#define FMC2_SR_ISOST                  GENMASK(1, 0)
+
+/* Register: FMC2_CIDCFGR */
+#define FMC2_CIDCFGR_CFEN              BIT(0)
+#define FMC2_CIDCFGR_SEMEN             BIT(1)
+#define FMC2_CIDCFGR_SCID              GENMASK(6, 4)
+#define FMC2_CIDCFGR_SEMWLC1           BIT(17)
+
+/* Register: FMC2_SEMCR */
+#define FMC2_SEMCR_SEM_MUTEX           BIT(0)
+#define FMC2_SEMCR_SEMCID              GENMASK(6, 4)
+
 #define FMC2_MAX_EBI_CE                        4
 #define FMC2_MAX_BANKS                 5
+#define FMC2_MAX_RESOURCES             6
+#define FMC2_CID1                      1
 
 #define FMC2_BCR_CPSIZE_0              0x0
 #define FMC2_BCR_CPSIZE_128            0x1
 #define FMC2_BCR_MTYP_PSRAM            0x1
 #define FMC2_BCR_MTYP_NOR              0x2
 
+#define FMC2_BCR_CSCOUNT_0             0x0
+#define FMC2_BCR_CSCOUNT_1             0x1
+#define FMC2_BCR_CSCOUNT_64            0x2
+#define FMC2_BCR_CSCOUNT_256           0x3
+
 #define FMC2_BXTR_EXTMOD_A             0x0
 #define FMC2_BXTR_EXTMOD_B             0x1
 #define FMC2_BXTR_EXTMOD_C             0x2
 #define FMC2_BTR_CLKDIV_MAX            0xf
 #define FMC2_BTR_DATLAT_MAX            0xf
 #define FMC2_PCSCNTR_CSCOUNT_MAX       0xff
+#define FMC2_CFGR_CLKDIV_MAX           0xf
 
 enum stm32_fmc2_ebi_bank {
        FMC2_EBI1 = 0,
@@ -101,7 +136,8 @@ enum stm32_fmc2_ebi_register_type {
        FMC2_REG_BCR = 1,
        FMC2_REG_BTR,
        FMC2_REG_BWTR,
-       FMC2_REG_PCSCNTR
+       FMC2_REG_PCSCNTR,
+       FMC2_REG_CFGR
 };
 
 enum stm32_fmc2_ebi_transaction_type {
@@ -132,16 +168,42 @@ enum stm32_fmc2_ebi_cpsize {
        FMC2_CPSIZE_1024 = 1024
 };
 
+enum stm32_fmc2_ebi_cscount {
+       FMC2_CSCOUNT_0 = 0,
+       FMC2_CSCOUNT_1 = 1,
+       FMC2_CSCOUNT_64 = 64,
+       FMC2_CSCOUNT_256 = 256
+};
+
+struct stm32_fmc2_ebi;
+
+struct stm32_fmc2_ebi_data {
+       const struct stm32_fmc2_prop *child_props;
+       unsigned int nb_child_props;
+       u32 fmc2_enable_reg;
+       u32 fmc2_enable_bit;
+       int (*nwait_used_by_ctrls)(struct stm32_fmc2_ebi *ebi);
+       void (*set_setup)(struct stm32_fmc2_ebi *ebi);
+       int (*save_setup)(struct stm32_fmc2_ebi *ebi);
+       int (*check_rif)(struct stm32_fmc2_ebi *ebi, u32 resource);
+       void (*put_sems)(struct stm32_fmc2_ebi *ebi);
+       void (*get_sems)(struct stm32_fmc2_ebi *ebi);
+};
+
 struct stm32_fmc2_ebi {
        struct device *dev;
        struct clk *clk;
        struct regmap *regmap;
+       const struct stm32_fmc2_ebi_data *data;
        u8 bank_assigned;
+       u8 sem_taken;
+       bool access_granted;
 
        u32 bcr[FMC2_MAX_EBI_CE];
        u32 btr[FMC2_MAX_EBI_CE];
        u32 bwtr[FMC2_MAX_EBI_CE];
        u32 pcscntr;
+       u32 cfgr;
 };
 
 /*
@@ -181,8 +243,11 @@ static int stm32_fmc2_ebi_check_mux(struct stm32_fmc2_ebi *ebi,
                                    int cs)
 {
        u32 bcr;
+       int ret;
 
-       regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       if (ret)
+               return ret;
 
        if (bcr & FMC2_BCR_MTYP)
                return 0;
@@ -195,8 +260,11 @@ static int stm32_fmc2_ebi_check_waitcfg(struct stm32_fmc2_ebi *ebi,
                                        int cs)
 {
        u32 bcr, val = FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR);
+       int ret;
 
-       regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       if (ret)
+               return ret;
 
        if ((bcr & FMC2_BCR_MTYP) == val && bcr & FMC2_BCR_BURSTEN)
                return 0;
@@ -209,8 +277,11 @@ static int stm32_fmc2_ebi_check_sync_trans(struct stm32_fmc2_ebi *ebi,
                                           int cs)
 {
        u32 bcr;
+       int ret;
 
-       regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       if (ret)
+               return ret;
 
        if (bcr & FMC2_BCR_BURSTEN)
                return 0;
@@ -218,13 +289,43 @@ static int stm32_fmc2_ebi_check_sync_trans(struct stm32_fmc2_ebi *ebi,
        return -EINVAL;
 }
 
+static int stm32_fmc2_ebi_mp25_check_cclk(struct stm32_fmc2_ebi *ebi,
+                                         const struct stm32_fmc2_prop *prop,
+                                         int cs)
+{
+       if (!ebi->access_granted)
+               return -EACCES;
+
+       return stm32_fmc2_ebi_check_sync_trans(ebi, prop, cs);
+}
+
+static int stm32_fmc2_ebi_mp25_check_clk_period(struct stm32_fmc2_ebi *ebi,
+                                               const struct stm32_fmc2_prop *prop,
+                                               int cs)
+{
+       u32 cfgr;
+       int ret;
+
+       ret = regmap_read(ebi->regmap, FMC2_CFGR, &cfgr);
+       if (ret)
+               return ret;
+
+       if (cfgr & FMC2_CFGR_CCLKEN && !ebi->access_granted)
+               return -EACCES;
+
+       return stm32_fmc2_ebi_check_sync_trans(ebi, prop, cs);
+}
+
 static int stm32_fmc2_ebi_check_async_trans(struct stm32_fmc2_ebi *ebi,
                                            const struct stm32_fmc2_prop *prop,
                                            int cs)
 {
        u32 bcr;
+       int ret;
 
-       regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       if (ret)
+               return ret;
 
        if (!(bcr & FMC2_BCR_BURSTEN) || !(bcr & FMC2_BCR_CBURSTRW))
                return 0;
@@ -237,8 +338,11 @@ static int stm32_fmc2_ebi_check_cpsize(struct stm32_fmc2_ebi *ebi,
                                       int cs)
 {
        u32 bcr, val = FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM);
+       int ret;
 
-       regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       if (ret)
+               return ret;
 
        if ((bcr & FMC2_BCR_MTYP) == val && bcr & FMC2_BCR_BURSTEN)
                return 0;
@@ -251,12 +355,18 @@ static int stm32_fmc2_ebi_check_address_hold(struct stm32_fmc2_ebi *ebi,
                                             int cs)
 {
        u32 bcr, bxtr, val = FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_D);
+       int ret;
+
+       ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       if (ret)
+               return ret;
 
-       regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
        if (prop->reg_type == FMC2_REG_BWTR)
-               regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr);
+               ret = regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr);
        else
-               regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr);
+               ret = regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr);
+       if (ret)
+               return ret;
 
        if ((!(bcr & FMC2_BCR_BURSTEN) || !(bcr & FMC2_BCR_CBURSTRW)) &&
            ((bxtr & FMC2_BXTR_ACCMOD) == val || bcr & FMC2_BCR_MUXEN))
@@ -270,12 +380,19 @@ static int stm32_fmc2_ebi_check_clk_period(struct stm32_fmc2_ebi *ebi,
                                           int cs)
 {
        u32 bcr, bcr1;
+       int ret;
 
-       regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
-       if (cs)
-               regmap_read(ebi->regmap, FMC2_BCR1, &bcr1);
-       else
+       ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       if (ret)
+               return ret;
+
+       if (cs) {
+               ret = regmap_read(ebi->regmap, FMC2_BCR1, &bcr1);
+               if (ret)
+                       return ret;
+       } else {
                bcr1 = bcr;
+       }
 
        if (bcr & FMC2_BCR_BURSTEN && (!cs || !(bcr1 & FMC2_BCR1_CCLKEN)))
                return 0;
@@ -307,18 +424,48 @@ static u32 stm32_fmc2_ebi_ns_to_clk_period(struct stm32_fmc2_ebi *ebi,
 {
        u32 nb_clk_cycles = stm32_fmc2_ebi_ns_to_clock_cycles(ebi, cs, setup);
        u32 bcr, btr, clk_period;
+       int ret;
+
+       ret = regmap_read(ebi->regmap, FMC2_BCR1, &bcr);
+       if (ret)
+               return ret;
 
-       regmap_read(ebi->regmap, FMC2_BCR1, &bcr);
        if (bcr & FMC2_BCR1_CCLKEN || !cs)
-               regmap_read(ebi->regmap, FMC2_BTR1, &btr);
+               ret = regmap_read(ebi->regmap, FMC2_BTR1, &btr);
        else
-               regmap_read(ebi->regmap, FMC2_BTR(cs), &btr);
+               ret = regmap_read(ebi->regmap, FMC2_BTR(cs), &btr);
+       if (ret)
+               return ret;
 
        clk_period = FIELD_GET(FMC2_BTR_CLKDIV, btr) + 1;
 
        return DIV_ROUND_UP(nb_clk_cycles, clk_period);
 }
 
+static u32 stm32_fmc2_ebi_mp25_ns_to_clk_period(struct stm32_fmc2_ebi *ebi,
+                                               int cs, u32 setup)
+{
+       u32 nb_clk_cycles = stm32_fmc2_ebi_ns_to_clock_cycles(ebi, cs, setup);
+       u32 cfgr, btr, clk_period;
+       int ret;
+
+       ret = regmap_read(ebi->regmap, FMC2_CFGR, &cfgr);
+       if (ret)
+               return ret;
+
+       if (cfgr & FMC2_CFGR_CCLKEN) {
+               clk_period = FIELD_GET(FMC2_CFGR_CLKDIV, cfgr) + 1;
+       } else {
+               ret = regmap_read(ebi->regmap, FMC2_BTR(cs), &btr);
+               if (ret)
+                       return ret;
+
+               clk_period = FIELD_GET(FMC2_BTR_CLKDIV, btr) + 1;
+       }
+
+       return DIV_ROUND_UP(nb_clk_cycles, clk_period);
+}
+
 static int stm32_fmc2_ebi_get_reg(int reg_type, int cs, u32 *reg)
 {
        switch (reg_type) {
@@ -334,6 +481,9 @@ static int stm32_fmc2_ebi_get_reg(int reg_type, int cs, u32 *reg)
        case FMC2_REG_PCSCNTR:
                *reg = FMC2_PCSCNTR;
                break;
+       case FMC2_REG_CFGR:
+               *reg = FMC2_CFGR;
+               break;
        default:
                return -EINVAL;
        }
@@ -571,11 +721,16 @@ static int stm32_fmc2_ebi_set_address_setup(struct stm32_fmc2_ebi *ebi,
        if (ret)
                return ret;
 
-       regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+       if (ret)
+               return ret;
+
        if (prop->reg_type == FMC2_REG_BWTR)
-               regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr);
+               ret = regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr);
        else
-               regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr);
+               ret = regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr);
+       if (ret)
+               return ret;
 
        if ((bxtr & FMC2_BXTR_ACCMOD) == val || bcr & FMC2_BCR_MUXEN)
                val = clamp_val(setup, 1, FMC2_BXTR_ADDSET_MAX);
@@ -675,6 +830,30 @@ static int stm32_fmc2_ebi_set_clk_period(struct stm32_fmc2_ebi *ebi,
        return 0;
 }
 
+static int stm32_fmc2_ebi_mp25_set_clk_period(struct stm32_fmc2_ebi *ebi,
+                                             const struct stm32_fmc2_prop *prop,
+                                             int cs, u32 setup)
+{
+       u32 val, cfgr;
+       int ret;
+
+       ret = regmap_read(ebi->regmap, FMC2_CFGR, &cfgr);
+       if (ret)
+               return ret;
+
+       if (cfgr & FMC2_CFGR_CCLKEN) {
+               val = setup ? clamp_val(setup - 1, 1, FMC2_CFGR_CLKDIV_MAX) : 1;
+               val = FIELD_PREP(FMC2_CFGR_CLKDIV, val);
+               regmap_update_bits(ebi->regmap, FMC2_CFGR, FMC2_CFGR_CLKDIV, val);
+       } else {
+               val = setup ? clamp_val(setup - 1, 1, FMC2_BTR_CLKDIV_MAX) : 1;
+               val = FIELD_PREP(FMC2_BTR_CLKDIV, val);
+               regmap_update_bits(ebi->regmap, FMC2_BTR(cs), FMC2_BTR_CLKDIV, val);
+       }
+
+       return 0;
+}
+
 static int stm32_fmc2_ebi_set_data_latency(struct stm32_fmc2_ebi *ebi,
                                           const struct stm32_fmc2_prop *prop,
                                           int cs, u32 setup)
@@ -693,11 +872,14 @@ static int stm32_fmc2_ebi_set_max_low_pulse(struct stm32_fmc2_ebi *ebi,
                                            int cs, u32 setup)
 {
        u32 old_val, new_val, pcscntr;
+       int ret;
 
        if (setup < 1)
                return 0;
 
-       regmap_read(ebi->regmap, FMC2_PCSCNTR, &pcscntr);
+       ret = regmap_read(ebi->regmap, FMC2_PCSCNTR, &pcscntr);
+       if (ret)
+               return ret;
 
        /* Enable counter for the bank */
        regmap_update_bits(ebi->regmap, FMC2_PCSCNTR,
@@ -717,6 +899,27 @@ static int stm32_fmc2_ebi_set_max_low_pulse(struct stm32_fmc2_ebi *ebi,
        return 0;
 }
 
+static int stm32_fmc2_ebi_mp25_set_max_low_pulse(struct stm32_fmc2_ebi *ebi,
+                                                const struct stm32_fmc2_prop *prop,
+                                                int cs, u32 setup)
+{
+       u32 val;
+
+       if (setup == FMC2_CSCOUNT_0)
+               val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_0);
+       else if (setup == FMC2_CSCOUNT_1)
+               val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_1);
+       else if (setup <= FMC2_CSCOUNT_64)
+               val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_64);
+       else
+               val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_256);
+
+       regmap_update_bits(ebi->regmap, FMC2_BCR(cs),
+                          FMC2_BCR_CSCOUNT, val);
+
+       return 0;
+}
+
 static const struct stm32_fmc2_prop stm32_fmc2_child_props[] = {
        /* st,fmc2-ebi-cs-trans-type must be the first property */
        {
@@ -882,6 +1085,275 @@ static const struct stm32_fmc2_prop stm32_fmc2_child_props[] = {
        },
 };
 
+static const struct stm32_fmc2_prop stm32_fmc2_mp25_child_props[] = {
+       /* st,fmc2-ebi-cs-trans-type must be the first property */
+       {
+               .name = "st,fmc2-ebi-cs-transaction-type",
+               .mprop = true,
+               .set = stm32_fmc2_ebi_set_trans_type,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-cclk-enable",
+               .bprop = true,
+               .reg_type = FMC2_REG_CFGR,
+               .reg_mask = FMC2_CFGR_CCLKEN,
+               .check = stm32_fmc2_ebi_mp25_check_cclk,
+               .set = stm32_fmc2_ebi_set_bit_field,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-mux-enable",
+               .bprop = true,
+               .reg_type = FMC2_REG_BCR,
+               .reg_mask = FMC2_BCR_MUXEN,
+               .check = stm32_fmc2_ebi_check_mux,
+               .set = stm32_fmc2_ebi_set_bit_field,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-buswidth",
+               .reset_val = FMC2_BUSWIDTH_16,
+               .set = stm32_fmc2_ebi_set_buswidth,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-waitpol-high",
+               .bprop = true,
+               .reg_type = FMC2_REG_BCR,
+               .reg_mask = FMC2_BCR_WAITPOL,
+               .set = stm32_fmc2_ebi_set_bit_field,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-waitcfg-enable",
+               .bprop = true,
+               .reg_type = FMC2_REG_BCR,
+               .reg_mask = FMC2_BCR_WAITCFG,
+               .check = stm32_fmc2_ebi_check_waitcfg,
+               .set = stm32_fmc2_ebi_set_bit_field,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-wait-enable",
+               .bprop = true,
+               .reg_type = FMC2_REG_BCR,
+               .reg_mask = FMC2_BCR_WAITEN,
+               .check = stm32_fmc2_ebi_check_sync_trans,
+               .set = stm32_fmc2_ebi_set_bit_field,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-asyncwait-enable",
+               .bprop = true,
+               .reg_type = FMC2_REG_BCR,
+               .reg_mask = FMC2_BCR_ASYNCWAIT,
+               .check = stm32_fmc2_ebi_check_async_trans,
+               .set = stm32_fmc2_ebi_set_bit_field,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-cpsize",
+               .check = stm32_fmc2_ebi_check_cpsize,
+               .set = stm32_fmc2_ebi_set_cpsize,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-byte-lane-setup-ns",
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_set_bl_setup,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-address-setup-ns",
+               .reg_type = FMC2_REG_BTR,
+               .reset_val = FMC2_BXTR_ADDSET_MAX,
+               .check = stm32_fmc2_ebi_check_async_trans,
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_set_address_setup,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-address-hold-ns",
+               .reg_type = FMC2_REG_BTR,
+               .reset_val = FMC2_BXTR_ADDHLD_MAX,
+               .check = stm32_fmc2_ebi_check_address_hold,
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_set_address_hold,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-data-setup-ns",
+               .reg_type = FMC2_REG_BTR,
+               .reset_val = FMC2_BXTR_DATAST_MAX,
+               .check = stm32_fmc2_ebi_check_async_trans,
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_set_data_setup,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-bus-turnaround-ns",
+               .reg_type = FMC2_REG_BTR,
+               .reset_val = FMC2_BXTR_BUSTURN_MAX + 1,
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_set_bus_turnaround,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-data-hold-ns",
+               .reg_type = FMC2_REG_BTR,
+               .check = stm32_fmc2_ebi_check_async_trans,
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_set_data_hold,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-clk-period-ns",
+               .reset_val = FMC2_CFGR_CLKDIV_MAX + 1,
+               .check = stm32_fmc2_ebi_mp25_check_clk_period,
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_mp25_set_clk_period,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-data-latency-ns",
+               .check = stm32_fmc2_ebi_check_sync_trans,
+               .calculate = stm32_fmc2_ebi_mp25_ns_to_clk_period,
+               .set = stm32_fmc2_ebi_set_data_latency,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-write-address-setup-ns",
+               .reg_type = FMC2_REG_BWTR,
+               .reset_val = FMC2_BXTR_ADDSET_MAX,
+               .check = stm32_fmc2_ebi_check_async_trans,
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_set_address_setup,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-write-address-hold-ns",
+               .reg_type = FMC2_REG_BWTR,
+               .reset_val = FMC2_BXTR_ADDHLD_MAX,
+               .check = stm32_fmc2_ebi_check_address_hold,
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_set_address_hold,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-write-data-setup-ns",
+               .reg_type = FMC2_REG_BWTR,
+               .reset_val = FMC2_BXTR_DATAST_MAX,
+               .check = stm32_fmc2_ebi_check_async_trans,
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_set_data_setup,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-write-bus-turnaround-ns",
+               .reg_type = FMC2_REG_BWTR,
+               .reset_val = FMC2_BXTR_BUSTURN_MAX + 1,
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_set_bus_turnaround,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-write-data-hold-ns",
+               .reg_type = FMC2_REG_BWTR,
+               .check = stm32_fmc2_ebi_check_async_trans,
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_set_data_hold,
+       },
+       {
+               .name = "st,fmc2-ebi-cs-max-low-pulse-ns",
+               .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
+               .set = stm32_fmc2_ebi_mp25_set_max_low_pulse,
+       },
+};
+
+static int stm32_fmc2_ebi_mp25_check_rif(struct stm32_fmc2_ebi *ebi, u32 resource)
+{
+       u32 seccfgr, cidcfgr, semcr;
+       int cid, ret;
+
+       if (resource >= FMC2_MAX_RESOURCES)
+               return -EINVAL;
+
+       ret = regmap_read(ebi->regmap, FMC2_SECCFGR, &seccfgr);
+       if (ret)
+               return ret;
+
+       if (seccfgr & BIT(resource)) {
+               if (resource)
+                       dev_err(ebi->dev, "resource %d is configured as secure\n",
+                               resource);
+
+               return -EACCES;
+       }
+
+       ret = regmap_read(ebi->regmap, FMC2_CIDCFGR(resource), &cidcfgr);
+       if (ret)
+               return ret;
+
+       if (!(cidcfgr & FMC2_CIDCFGR_CFEN))
+               /* CID filtering is turned off: access granted */
+               return 0;
+
+       if (!(cidcfgr & FMC2_CIDCFGR_SEMEN)) {
+               /* Static CID mode */
+               cid = FIELD_GET(FMC2_CIDCFGR_SCID, cidcfgr);
+               if (cid != FMC2_CID1) {
+                       if (resource)
+                               dev_err(ebi->dev, "static CID%d set for resource %d\n",
+                                       cid, resource);
+
+                       return -EACCES;
+               }
+
+               return 0;
+       }
+
+       /* Pass-list with semaphore mode */
+       if (!(cidcfgr & FMC2_CIDCFGR_SEMWLC1)) {
+               if (resource)
+                       dev_err(ebi->dev, "CID1 is block-listed for resource %d\n",
+                               resource);
+
+               return -EACCES;
+       }
+
+       ret = regmap_read(ebi->regmap, FMC2_SEMCR(resource), &semcr);
+       if (ret)
+               return ret;
+
+       if (!(semcr & FMC2_SEMCR_SEM_MUTEX)) {
+               regmap_update_bits(ebi->regmap, FMC2_SEMCR(resource),
+                                  FMC2_SEMCR_SEM_MUTEX, FMC2_SEMCR_SEM_MUTEX);
+
+               ret = regmap_read(ebi->regmap, FMC2_SEMCR(resource), &semcr);
+               if (ret)
+                       return ret;
+       }
+
+       cid = FIELD_GET(FMC2_SEMCR_SEMCID, semcr);
+       if (cid != FMC2_CID1) {
+               if (resource)
+                       dev_err(ebi->dev, "resource %d is already used by CID%d\n",
+                               resource, cid);
+
+               return -EACCES;
+       }
+
+       ebi->sem_taken |= BIT(resource);
+
+       return 0;
+}
+
+static void stm32_fmc2_ebi_mp25_put_sems(struct stm32_fmc2_ebi *ebi)
+{
+       unsigned int resource;
+
+       for (resource = 0; resource < FMC2_MAX_RESOURCES; resource++) {
+               if (!(ebi->sem_taken & BIT(resource)))
+                       continue;
+
+               regmap_update_bits(ebi->regmap, FMC2_SEMCR(resource),
+                                  FMC2_SEMCR_SEM_MUTEX, 0);
+       }
+}
+
+static void stm32_fmc2_ebi_mp25_get_sems(struct stm32_fmc2_ebi *ebi)
+{
+       unsigned int resource;
+
+       for (resource = 0; resource < FMC2_MAX_RESOURCES; resource++) {
+               if (!(ebi->sem_taken & BIT(resource)))
+                       continue;
+
+               regmap_update_bits(ebi->regmap, FMC2_SEMCR(resource),
+                                  FMC2_SEMCR_SEM_MUTEX, FMC2_SEMCR_SEM_MUTEX);
+       }
+}
+
 static int stm32_fmc2_ebi_parse_prop(struct stm32_fmc2_ebi *ebi,
                                     struct device_node *dev_node,
                                     const struct stm32_fmc2_prop *prop,
@@ -944,17 +1416,48 @@ static void stm32_fmc2_ebi_disable_bank(struct stm32_fmc2_ebi *ebi, int cs)
        regmap_update_bits(ebi->regmap, FMC2_BCR(cs), FMC2_BCR_MBKEN, 0);
 }
 
-static void stm32_fmc2_ebi_save_setup(struct stm32_fmc2_ebi *ebi)
+static int stm32_fmc2_ebi_save_setup(struct stm32_fmc2_ebi *ebi)
 {
        unsigned int cs;
+       int ret;
 
        for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) {
-               regmap_read(ebi->regmap, FMC2_BCR(cs), &ebi->bcr[cs]);
-               regmap_read(ebi->regmap, FMC2_BTR(cs), &ebi->btr[cs]);
-               regmap_read(ebi->regmap, FMC2_BWTR(cs), &ebi->bwtr[cs]);
+               if (!(ebi->bank_assigned & BIT(cs)))
+                       continue;
+
+               ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &ebi->bcr[cs]);
+               ret |= regmap_read(ebi->regmap, FMC2_BTR(cs), &ebi->btr[cs]);
+               ret |= regmap_read(ebi->regmap, FMC2_BWTR(cs), &ebi->bwtr[cs]);
+               if (ret)
+                       return ret;
        }
 
-       regmap_read(ebi->regmap, FMC2_PCSCNTR, &ebi->pcscntr);
+       return 0;
+}
+
+static int stm32_fmc2_ebi_mp1_save_setup(struct stm32_fmc2_ebi *ebi)
+{
+       int ret;
+
+       ret = stm32_fmc2_ebi_save_setup(ebi);
+       if (ret)
+               return ret;
+
+       return regmap_read(ebi->regmap, FMC2_PCSCNTR, &ebi->pcscntr);
+}
+
+static int stm32_fmc2_ebi_mp25_save_setup(struct stm32_fmc2_ebi *ebi)
+{
+       int ret;
+
+       ret = stm32_fmc2_ebi_save_setup(ebi);
+       if (ret)
+               return ret;
+
+       if (ebi->access_granted)
+               ret = regmap_read(ebi->regmap, FMC2_CFGR, &ebi->cfgr);
+
+       return ret;
 }
 
 static void stm32_fmc2_ebi_set_setup(struct stm32_fmc2_ebi *ebi)
@@ -962,14 +1465,29 @@ static void stm32_fmc2_ebi_set_setup(struct stm32_fmc2_ebi *ebi)
        unsigned int cs;
 
        for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) {
+               if (!(ebi->bank_assigned & BIT(cs)))
+                       continue;
+
                regmap_write(ebi->regmap, FMC2_BCR(cs), ebi->bcr[cs]);
                regmap_write(ebi->regmap, FMC2_BTR(cs), ebi->btr[cs]);
                regmap_write(ebi->regmap, FMC2_BWTR(cs), ebi->bwtr[cs]);
        }
+}
 
+static void stm32_fmc2_ebi_mp1_set_setup(struct stm32_fmc2_ebi *ebi)
+{
+       stm32_fmc2_ebi_set_setup(ebi);
        regmap_write(ebi->regmap, FMC2_PCSCNTR, ebi->pcscntr);
 }
 
+static void stm32_fmc2_ebi_mp25_set_setup(struct stm32_fmc2_ebi *ebi)
+{
+       stm32_fmc2_ebi_set_setup(ebi);
+
+       if (ebi->access_granted)
+               regmap_write(ebi->regmap, FMC2_CFGR, ebi->cfgr);
+}
+
 static void stm32_fmc2_ebi_disable_banks(struct stm32_fmc2_ebi *ebi)
 {
        unsigned int cs;
@@ -983,33 +1501,48 @@ static void stm32_fmc2_ebi_disable_banks(struct stm32_fmc2_ebi *ebi)
 }
 
 /* NWAIT signal can not be connected to EBI controller and NAND controller */
-static bool stm32_fmc2_ebi_nwait_used_by_ctrls(struct stm32_fmc2_ebi *ebi)
+static int stm32_fmc2_ebi_nwait_used_by_ctrls(struct stm32_fmc2_ebi *ebi)
 {
+       struct device *dev = ebi->dev;
        unsigned int cs;
        u32 bcr;
+       int ret;
 
        for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) {
                if (!(ebi->bank_assigned & BIT(cs)))
                        continue;
 
-               regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+               ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr);
+               if (ret)
+                       return ret;
+
                if ((bcr & FMC2_BCR_WAITEN || bcr & FMC2_BCR_ASYNCWAIT) &&
-                   ebi->bank_assigned & BIT(FMC2_NAND))
-                       return true;
+                   ebi->bank_assigned & BIT(FMC2_NAND)) {
+                       dev_err(dev, "NWAIT signal connected to EBI and NAND controllers\n");
+                       return -EINVAL;
+               }
        }
 
-       return false;
+       return 0;
 }
 
 static void stm32_fmc2_ebi_enable(struct stm32_fmc2_ebi *ebi)
 {
-       regmap_update_bits(ebi->regmap, FMC2_BCR1,
-                          FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN);
+       if (!ebi->access_granted)
+               return;
+
+       regmap_update_bits(ebi->regmap, ebi->data->fmc2_enable_reg,
+                          ebi->data->fmc2_enable_bit,
+                          ebi->data->fmc2_enable_bit);
 }
 
 static void stm32_fmc2_ebi_disable(struct stm32_fmc2_ebi *ebi)
 {
-       regmap_update_bits(ebi->regmap, FMC2_BCR1, FMC2_BCR1_FMC2EN, 0);
+       if (!ebi->access_granted)
+               return;
+
+       regmap_update_bits(ebi->regmap, ebi->data->fmc2_enable_reg,
+                          ebi->data->fmc2_enable_bit, 0);
 }
 
 static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi,
@@ -1021,8 +1554,8 @@ static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi,
 
        stm32_fmc2_ebi_disable_bank(ebi, cs);
 
-       for (i = 0; i < ARRAY_SIZE(stm32_fmc2_child_props); i++) {
-               const struct stm32_fmc2_prop *p = &stm32_fmc2_child_props[i];
+       for (i = 0; i < ebi->data->nb_child_props; i++) {
+               const struct stm32_fmc2_prop *p = &ebi->data->child_props[i];
 
                ret = stm32_fmc2_ebi_parse_prop(ebi, dev_node, p, cs);
                if (ret) {
@@ -1066,6 +1599,15 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi)
                        return -EINVAL;
                }
 
+               if (ebi->data->check_rif) {
+                       ret = ebi->data->check_rif(ebi, bank + 1);
+                       if (ret) {
+                               dev_err(dev, "bank access failed: %d\n", bank);
+                               of_node_put(child);
+                               return ret;
+                       }
+               }
+
                if (bank < FMC2_MAX_EBI_CE) {
                        ret = stm32_fmc2_ebi_setup_cs(ebi, child, bank);
                        if (ret) {
@@ -1085,9 +1627,10 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi)
                return -ENODEV;
        }
 
-       if (stm32_fmc2_ebi_nwait_used_by_ctrls(ebi)) {
-               dev_err(dev, "NWAIT signal connected to EBI and NAND controllers\n");
-               return -EINVAL;
+       if (ebi->data->nwait_used_by_ctrls) {
+               ret = ebi->data->nwait_used_by_ctrls(ebi);
+               if (ret)
+                       return ret;
        }
 
        stm32_fmc2_ebi_enable(ebi);
@@ -1107,6 +1650,11 @@ static int stm32_fmc2_ebi_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        ebi->dev = dev;
+       platform_set_drvdata(pdev, ebi);
+
+       ebi->data = of_device_get_match_data(dev);
+       if (!ebi->data)
+               return -EINVAL;
 
        ebi->regmap = device_node_to_regmap(dev->of_node);
        if (IS_ERR(ebi->regmap))
@@ -1120,28 +1668,57 @@ static int stm32_fmc2_ebi_probe(struct platform_device *pdev)
        if (PTR_ERR(rstc) == -EPROBE_DEFER)
                return -EPROBE_DEFER;
 
-       ret = clk_prepare_enable(ebi->clk);
+       ret = devm_pm_runtime_enable(dev);
        if (ret)
                return ret;
 
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret < 0)
+               return ret;
+
        if (!IS_ERR(rstc)) {
                reset_control_assert(rstc);
                reset_control_deassert(rstc);
        }
 
+       /* Check if CFGR register can be modified */
+       ebi->access_granted = true;
+       if (ebi->data->check_rif) {
+               ret = ebi->data->check_rif(ebi, 0);
+               if (ret) {
+                       u32 sr;
+
+                       ebi->access_granted = false;
+
+                       ret = regmap_read(ebi->regmap, FMC2_SR, &sr);
+                       if (ret)
+                               goto err_release;
+
+                       /* In case of CFGR is secure, just check that the FMC2 is enabled */
+                       if (sr & FMC2_SR_ISOST) {
+                               dev_err(dev, "FMC2 is not ready to be used.\n");
+                               ret = -EACCES;
+                               goto err_release;
+                       }
+               }
+       }
+
        ret = stm32_fmc2_ebi_parse_dt(ebi);
        if (ret)
                goto err_release;
 
-       stm32_fmc2_ebi_save_setup(ebi);
-       platform_set_drvdata(pdev, ebi);
+       ret = ebi->data->save_setup(ebi);
+       if (ret)
+               goto err_release;
 
        return 0;
 
 err_release:
        stm32_fmc2_ebi_disable_banks(ebi);
        stm32_fmc2_ebi_disable(ebi);
-       clk_disable_unprepare(ebi->clk);
+       if (ebi->data->put_sems)
+               ebi->data->put_sems(ebi);
+       pm_runtime_put_sync_suspend(dev);
 
        return ret;
 }
@@ -1153,7 +1730,25 @@ static void stm32_fmc2_ebi_remove(struct platform_device *pdev)
        of_platform_depopulate(&pdev->dev);
        stm32_fmc2_ebi_disable_banks(ebi);
        stm32_fmc2_ebi_disable(ebi);
+       if (ebi->data->put_sems)
+               ebi->data->put_sems(ebi);
+       pm_runtime_put_sync_suspend(&pdev->dev);
+}
+
+static int __maybe_unused stm32_fmc2_ebi_runtime_suspend(struct device *dev)
+{
+       struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev);
+
        clk_disable_unprepare(ebi->clk);
+
+       return 0;
+}
+
+static int __maybe_unused stm32_fmc2_ebi_runtime_resume(struct device *dev)
+{
+       struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev);
+
+       return clk_prepare_enable(ebi->clk);
 }
 
 static int __maybe_unused stm32_fmc2_ebi_suspend(struct device *dev)
@@ -1161,7 +1756,9 @@ static int __maybe_unused stm32_fmc2_ebi_suspend(struct device *dev)
        struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev);
 
        stm32_fmc2_ebi_disable(ebi);
-       clk_disable_unprepare(ebi->clk);
+       if (ebi->data->put_sems)
+               ebi->data->put_sems(ebi);
+       pm_runtime_put_sync_suspend(dev);
        pinctrl_pm_select_sleep_state(dev);
 
        return 0;
@@ -1174,21 +1771,55 @@ static int __maybe_unused stm32_fmc2_ebi_resume(struct device *dev)
 
        pinctrl_pm_select_default_state(dev);
 
-       ret = clk_prepare_enable(ebi->clk);
-       if (ret)
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret < 0)
                return ret;
 
-       stm32_fmc2_ebi_set_setup(ebi);
+       if (ebi->data->get_sems)
+               ebi->data->get_sems(ebi);
+       ebi->data->set_setup(ebi);
        stm32_fmc2_ebi_enable(ebi);
 
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(stm32_fmc2_ebi_pm_ops, stm32_fmc2_ebi_suspend,
-                        stm32_fmc2_ebi_resume);
+static const struct dev_pm_ops stm32_fmc2_ebi_pm_ops = {
+       SET_RUNTIME_PM_OPS(stm32_fmc2_ebi_runtime_suspend,
+                          stm32_fmc2_ebi_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(stm32_fmc2_ebi_suspend, stm32_fmc2_ebi_resume)
+};
+
+static const struct stm32_fmc2_ebi_data stm32_fmc2_ebi_mp1_data = {
+       .child_props = stm32_fmc2_child_props,
+       .nb_child_props = ARRAY_SIZE(stm32_fmc2_child_props),
+       .fmc2_enable_reg = FMC2_BCR1,
+       .fmc2_enable_bit = FMC2_BCR1_FMC2EN,
+       .nwait_used_by_ctrls = stm32_fmc2_ebi_nwait_used_by_ctrls,
+       .set_setup = stm32_fmc2_ebi_mp1_set_setup,
+       .save_setup = stm32_fmc2_ebi_mp1_save_setup,
+};
+
+static const struct stm32_fmc2_ebi_data stm32_fmc2_ebi_mp25_data = {
+       .child_props = stm32_fmc2_mp25_child_props,
+       .nb_child_props = ARRAY_SIZE(stm32_fmc2_mp25_child_props),
+       .fmc2_enable_reg = FMC2_CFGR,
+       .fmc2_enable_bit = FMC2_CFGR_FMC2EN,
+       .set_setup = stm32_fmc2_ebi_mp25_set_setup,
+       .save_setup = stm32_fmc2_ebi_mp25_save_setup,
+       .check_rif = stm32_fmc2_ebi_mp25_check_rif,
+       .put_sems = stm32_fmc2_ebi_mp25_put_sems,
+       .get_sems = stm32_fmc2_ebi_mp25_get_sems,
+};
 
 static const struct of_device_id stm32_fmc2_ebi_match[] = {
-       {.compatible = "st,stm32mp1-fmc2-ebi"},
+       {
+               .compatible = "st,stm32mp1-fmc2-ebi",
+               .data = &stm32_fmc2_ebi_mp1_data,
+       },
+       {
+               .compatible = "st,stm32mp25-fmc2-ebi",
+               .data = &stm32_fmc2_ebi_mp25_data,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, stm32_fmc2_ebi_match);
index abff87f917cb45ccbec4d665b540f92175ebea08..5f57cea48b629740c50ce0f951df812c9c7dfde7 100644 (file)
@@ -92,6 +92,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA0RDB,
                .name = "dla0rdb",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA0,
                .regs = {
                        .sid = {
@@ -102,6 +104,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA0RDB1,
                .name = "dla0rdb1",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA0,
                .regs = {
                        .sid = {
@@ -112,6 +116,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA0WRB,
                .name = "dla0wrb",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA0,
                .regs = {
                        .sid = {
@@ -121,7 +127,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
                },
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA1RDB,
-               .name = "dla0rdb",
+               .name = "dla1rdb",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA1,
                .regs = {
                        .sid = {
@@ -407,7 +415,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
                },
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA1RDB1,
-               .name = "dla0rdb1",
+               .name = "dla1rdb1",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA1,
                .regs = {
                        .sid = {
@@ -417,7 +427,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
                },
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA1WRB,
-               .name = "dla0wrb",
+               .name = "dla1wrb",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA1,
                .regs = {
                        .sid = {
@@ -539,7 +551,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
                .bpmp_id = TEGRA_ICC_BPMP_NVJPG_0,
                .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVJPG,
-                       .regs = {
+               .regs = {
                        .sid = {
                                .override = 0x3f8,
                                .security = 0x3fc,
@@ -660,6 +672,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA0RDA,
                .name = "dla0rda",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA0,
                .regs = {
                        .sid = {
@@ -670,6 +684,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA0FALRDB,
                .name = "dla0falrdb",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA0,
                .regs = {
                        .sid = {
@@ -680,6 +696,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA0WRA,
                .name = "dla0wra",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA0,
                .regs = {
                        .sid = {
@@ -690,6 +708,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA0FALWRB,
                .name = "dla0falwrb",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA0,
                .regs = {
                        .sid = {
@@ -699,7 +719,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
                },
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA1RDA,
-               .name = "dla0rda",
+               .name = "dla1rda",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA1,
                .regs = {
                        .sid = {
@@ -709,7 +731,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
                },
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA1FALRDB,
-               .name = "dla0falrdb",
+               .name = "dla1falrdb",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA1,
                .regs = {
                        .sid = {
@@ -719,7 +743,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
                },
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA1WRA,
-               .name = "dla0wra",
+               .name = "dla1wra",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA1,
                .regs = {
                        .sid = {
@@ -729,7 +755,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
                },
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA1FALWRB,
-               .name = "dla0falwrb",
+               .name = "dla1falwrb",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_1,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA1,
                .regs = {
                        .sid = {
@@ -908,6 +936,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA0RDA1,
                .name = "dla0rda1",
+               .bpmp_id = TEGRA_ICC_BPMP_DLA_0,
+               .type = TEGRA_ICC_NISO,
                .sid = TEGRA234_SID_NVDLA0,
                .regs = {
                        .sid = {
@@ -917,7 +947,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
                },
        }, {
                .id = TEGRA234_MEMORY_CLIENT_DLA1RDA1,
-               .name = "dla0rda1",
+               .name = "dla1rda1",
                .sid = TEGRA234_SID_NVDLA1,
                .regs = {
                        .sid = {
index 04115cd92433bfb9134708f0e3373bb21baa7c19..47a314a4eb6fafc76482ff3010b35298d3423ec7 100644 (file)
@@ -2078,6 +2078,12 @@ static const struct blk_mq_ops msb_mq_ops = {
 static int msb_init_disk(struct memstick_dev *card)
 {
        struct msb_data *msb = memstick_get_drvdata(card);
+       struct queue_limits lim = {
+               .logical_block_size     = msb->page_size,
+               .max_hw_sectors         = MS_BLOCK_MAX_PAGES,
+               .max_segments           = MS_BLOCK_MAX_SEGS,
+               .max_segment_size       = MS_BLOCK_MAX_PAGES * msb->page_size,
+       };
        int rc;
        unsigned long capacity;
 
@@ -2093,19 +2099,13 @@ static int msb_init_disk(struct memstick_dev *card)
        if (rc)
                goto out_release_id;
 
-       msb->disk = blk_mq_alloc_disk(&msb->tag_set, card);
+       msb->disk = blk_mq_alloc_disk(&msb->tag_set, &lim, card);
        if (IS_ERR(msb->disk)) {
                rc = PTR_ERR(msb->disk);
                goto out_free_tag_set;
        }
        msb->queue = msb->disk->queue;
 
-       blk_queue_max_hw_sectors(msb->queue, MS_BLOCK_MAX_PAGES);
-       blk_queue_max_segments(msb->queue, MS_BLOCK_MAX_SEGS);
-       blk_queue_max_segment_size(msb->queue,
-                                  MS_BLOCK_MAX_PAGES * msb->page_size);
-       blk_queue_logical_block_size(msb->queue, msb->page_size);
-
        sprintf(msb->disk->disk_name, "msblk%d", msb->disk_id);
        msb->disk->fops = &msb_bdops;
        msb->disk->private_data = msb;
index 5a69ed33999b4c4c0e5565dc9a3b58f2e8e0871d..49accfdc89d616cea5eb307a56ce85f68b2b5c6e 100644 (file)
@@ -1103,6 +1103,12 @@ static const struct blk_mq_ops mspro_mq_ops = {
 static int mspro_block_init_disk(struct memstick_dev *card)
 {
        struct mspro_block_data *msb = memstick_get_drvdata(card);
+       struct queue_limits lim = {
+               .logical_block_size     = msb->page_size,
+               .max_hw_sectors         = MSPRO_BLOCK_MAX_PAGES,
+               .max_segments           = MSPRO_BLOCK_MAX_SEGS,
+               .max_segment_size       = MSPRO_BLOCK_MAX_PAGES * msb->page_size,
+       };
        struct mspro_devinfo *dev_info = NULL;
        struct mspro_sys_info *sys_info = NULL;
        struct mspro_sys_attr *s_attr = NULL;
@@ -1138,18 +1144,13 @@ static int mspro_block_init_disk(struct memstick_dev *card)
        if (rc)
                goto out_release_id;
 
-       msb->disk = blk_mq_alloc_disk(&msb->tag_set, card);
+       msb->disk = blk_mq_alloc_disk(&msb->tag_set, &lim, card);
        if (IS_ERR(msb->disk)) {
                rc = PTR_ERR(msb->disk);
                goto out_free_tag_set;
        }
        msb->queue = msb->disk->queue;
 
-       blk_queue_max_hw_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES);
-       blk_queue_max_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS);
-       blk_queue_max_segment_size(msb->queue,
-                                  MSPRO_BLOCK_MAX_PAGES * msb->page_size);
-
        msb->disk->major = major;
        msb->disk->first_minor = disk_id << MSPRO_BLOCK_PART_SHIFT;
        msb->disk->minors = 1 << MSPRO_BLOCK_PART_SHIFT;
@@ -1158,8 +1159,6 @@ static int mspro_block_init_disk(struct memstick_dev *card)
 
        sprintf(msb->disk->disk_name, "mspblk%d", disk_id);
 
-       blk_queue_logical_block_size(msb->queue, msb->page_size);
-
        capacity = be16_to_cpu(sys_info->user_block_count);
        capacity *= be16_to_cpu(sys_info->block_size);
        capacity *= msb->page_size >> 9;
index 03319a1fa97fda2bf967dd425af9aef83fc1602d..dbd26c3b245bca56adffc8288d5657dd3c61d3b8 100644 (file)
@@ -263,7 +263,6 @@ struct fastrpc_channel_ctx {
        int domain_id;
        int sesscount;
        int vmcount;
-       u64 perms;
        struct qcom_scm_vmperm vmperms[FASTRPC_MAX_VMIDS];
        struct rpmsg_device *rpdev;
        struct fastrpc_session_ctx session[FASTRPC_MAX_SESSIONS];
@@ -1279,9 +1278,11 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
 
                /* Map if we have any heap VMIDs associated with this ADSP Static Process. */
                if (fl->cctx->vmcount) {
+                       u64 src_perms = BIT(QCOM_SCM_VMID_HLOS);
+
                        err = qcom_scm_assign_mem(fl->cctx->remote_heap->phys,
                                                        (u64)fl->cctx->remote_heap->size,
-                                                       &fl->cctx->perms,
+                                                       &src_perms,
                                                        fl->cctx->vmperms, fl->cctx->vmcount);
                        if (err) {
                                dev_err(fl->sctx->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d",
@@ -1915,8 +1916,10 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
 
        /* Add memory to static PD pool, protection thru hypervisor */
        if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) {
+               u64 src_perms = BIT(QCOM_SCM_VMID_HLOS);
+
                err = qcom_scm_assign_mem(buf->phys, (u64)buf->size,
-                       &fl->cctx->perms, fl->cctx->vmperms, fl->cctx->vmcount);
+                       &src_perms, fl->cctx->vmperms, fl->cctx->vmcount);
                if (err) {
                        dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d",
                                        buf->phys, buf->size, err);
@@ -2290,7 +2293,6 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
 
        if (vmcount) {
                data->vmcount = vmcount;
-               data->perms = BIT(QCOM_SCM_VMID_HLOS);
                for (i = 0; i < data->vmcount; i++) {
                        data->vmperms[i].vmid = vmids[i];
                        data->vmperms[i].perm = QCOM_SCM_PERM_RWX;
index c6eb27d46cb06de4ade9c0cdbbdd270ffe8ab474..15119584473cafbaaa96ce18f059571cfc2196bc 100644 (file)
@@ -198,8 +198,14 @@ static int lis3lv02d_i2c_suspend(struct device *dev)
        struct i2c_client *client = to_i2c_client(dev);
        struct lis3lv02d *lis3 = i2c_get_clientdata(client);
 
-       if (!lis3->pdata || !lis3->pdata->wakeup_flags)
+       /* Turn on for wakeup if turned off by runtime suspend */
+       if (lis3->pdata && lis3->pdata->wakeup_flags) {
+               if (pm_runtime_suspended(dev))
+                       lis3lv02d_poweron(lis3);
+       /* For non wakeup turn off if not already turned off by runtime suspend */
+       } else if (!pm_runtime_suspended(dev))
                lis3lv02d_poweroff(lis3);
+
        return 0;
 }
 
@@ -208,13 +214,12 @@ static int lis3lv02d_i2c_resume(struct device *dev)
        struct i2c_client *client = to_i2c_client(dev);
        struct lis3lv02d *lis3 = i2c_get_clientdata(client);
 
-       /*
-        * pm_runtime documentation says that devices should always
-        * be powered on at resume. Pm_runtime turns them off after system
-        * wide resume is complete.
-        */
-       if (!lis3->pdata || !lis3->pdata->wakeup_flags ||
-               pm_runtime_suspended(dev))
+       /* Turn back off if turned on for wakeup and runtime suspended*/
+       if (lis3->pdata && lis3->pdata->wakeup_flags) {
+               if (pm_runtime_suspended(dev))
+                       lis3lv02d_poweroff(lis3);
+       /* For non wakeup turn back on if not runtime suspended */
+       } else if (!pm_runtime_suspended(dev))
                lis3lv02d_poweron(lis3);
 
        return 0;
index be52b113aea937c7c658e06c012815cec8552f28..89364bdbb1290f5726a34945679e341b17289493 100644 (file)
@@ -96,7 +96,8 @@ static const struct component_master_ops mei_component_master_ops = {
  *
  *    The function checks if the device is pci device and
  *    Intel VGA adapter, the subcomponent is SW Proxy
- *    and the parent of MEI PCI and the parent of VGA are the same PCH device.
+ *    and the VGA is on the bus 0 reserved for built-in devices
+ *    to reject discrete GFX.
  *
  * @dev: master device
  * @subcomponent: subcomponent to match (I915_COMPONENT_SWPROXY)
@@ -123,7 +124,8 @@ static int mei_gsc_proxy_component_match(struct device *dev, int subcomponent,
        if (subcomponent != I915_COMPONENT_GSC_PROXY)
                return 0;
 
-       return component_compare_dev(dev->parent, ((struct device *)data)->parent);
+       /* Only built-in GFX */
+       return (pdev->bus->number == 0);
 }
 
 static int mei_gsc_proxy_probe(struct mei_cl_device *cldev,
@@ -146,7 +148,7 @@ static int mei_gsc_proxy_probe(struct mei_cl_device *cldev,
        }
 
        component_match_add_typed(&cldev->dev, &master_match,
-                                 mei_gsc_proxy_component_match, cldev->dev.parent);
+                                 mei_gsc_proxy_component_match, NULL);
        if (IS_ERR_OR_NULL(master_match)) {
                ret = -ENOMEM;
                goto err_exit;
index 961e5d53a27a8c4221b4b33c9d4e70f0f0155ee7..aac36750d2c54a658debcca55063d2e2a02bf1ce 100644 (file)
 #define MEI_DEV_ID_RPL_S      0x7A68  /* Raptor Lake Point S */
 
 #define MEI_DEV_ID_MTL_M      0x7E70  /* Meteor Lake Point M */
+#define MEI_DEV_ID_ARL_S      0x7F68  /* Arrow Lake Point S */
+#define MEI_DEV_ID_ARL_H      0x7770  /* Arrow Lake Point H */
 
 /*
  * MEI HW Section
index 676d566f38ddfd2cbb5c167f5691f737b4fcf01c..8cf636c5403225f7588a2428318cec1ff7fd2700 100644 (file)
@@ -119,6 +119,8 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
        {MEI_PCI_DEVICE(MEI_DEV_ID_RPL_S, MEI_ME_PCH15_CFG)},
 
        {MEI_PCI_DEVICE(MEI_DEV_ID_MTL_M, MEI_ME_PCH15_CFG)},
+       {MEI_PCI_DEVICE(MEI_DEV_ID_ARL_S, MEI_ME_PCH15_CFG)},
+       {MEI_PCI_DEVICE(MEI_DEV_ID_ARL_H, MEI_ME_PCH15_CFG)},
 
        /* required last entry */
        {0, }
index 6f4a4be6ccb5508dbc8857ce21b7643e93c1ea63..55f7db490d3bbbabd08b7bd2ba6ff078abb93ad6 100644 (file)
@@ -535,6 +535,7 @@ static const struct acpi_device_id vsc_tp_acpi_ids[] = {
        { "INTC1009" }, /* Raptor Lake */
        { "INTC1058" }, /* Tiger Lake */
        { "INTC1094" }, /* Alder Lake */
+       { "INTC10D0" }, /* Meteor Lake */
        {}
 };
 MODULE_DEVICE_TABLE(acpi, vsc_tp_acpi_ids);
index f410bee501328f6af96b4f0029d4856e45e06766..58ed7193a3ca460fe58a46427306b385a40a2d3e 100644 (file)
@@ -1015,10 +1015,12 @@ static int mmc_select_bus_width(struct mmc_card *card)
        static unsigned ext_csd_bits[] = {
                EXT_CSD_BUS_WIDTH_8,
                EXT_CSD_BUS_WIDTH_4,
+               EXT_CSD_BUS_WIDTH_1,
        };
        static unsigned bus_widths[] = {
                MMC_BUS_WIDTH_8,
                MMC_BUS_WIDTH_4,
+               MMC_BUS_WIDTH_1,
        };
        struct mmc_host *host = card->host;
        unsigned idx, bus_width = 0;
index a0a2412f62a7304278220a9f72e0ea84d4e2a508..2ae60d208cdf1ee2243aa99a340bd5be06d8bbc3 100644 (file)
@@ -174,8 +174,8 @@ static struct scatterlist *mmc_alloc_sg(unsigned short sg_len, gfp_t gfp)
        return sg;
 }
 
-static void mmc_queue_setup_discard(struct request_queue *q,
-                                   struct mmc_card *card)
+static void mmc_queue_setup_discard(struct mmc_card *card,
+               struct queue_limits *lim)
 {
        unsigned max_discard;
 
@@ -183,15 +183,17 @@ static void mmc_queue_setup_discard(struct request_queue *q,
        if (!max_discard)
                return;
 
-       blk_queue_max_discard_sectors(q, max_discard);
-       q->limits.discard_granularity = card->pref_erase << 9;
-       /* granularity must not be greater than max. discard */
-       if (card->pref_erase > max_discard)
-               q->limits.discard_granularity = SECTOR_SIZE;
+       lim->max_hw_discard_sectors = max_discard;
        if (mmc_can_secure_erase_trim(card))
-               blk_queue_max_secure_erase_sectors(q, max_discard);
+               lim->max_secure_erase_sectors = max_discard;
        if (mmc_can_trim(card) && card->erased_byte == 0)
-               blk_queue_max_write_zeroes_sectors(q, max_discard);
+               lim->max_write_zeroes_sectors = max_discard;
+
+       /* granularity must not be greater than max. discard */
+       if (card->pref_erase > max_discard)
+               lim->discard_granularity = SECTOR_SIZE;
+       else
+               lim->discard_granularity = card->pref_erase << 9;
 }
 
 static unsigned short mmc_get_max_segments(struct mmc_host *host)
@@ -341,40 +343,53 @@ static const struct blk_mq_ops mmc_mq_ops = {
        .timeout        = mmc_mq_timed_out,
 };
 
-static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
+static struct gendisk *mmc_alloc_disk(struct mmc_queue *mq,
+               struct mmc_card *card)
 {
        struct mmc_host *host = card->host;
-       unsigned block_size = 512;
+       struct queue_limits lim = { };
+       struct gendisk *disk;
 
-       blk_queue_flag_set(QUEUE_FLAG_NONROT, mq->queue);
-       blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, mq->queue);
        if (mmc_can_erase(card))
-               mmc_queue_setup_discard(mq->queue, card);
+               mmc_queue_setup_discard(card, &lim);
 
        if (!mmc_dev(host)->dma_mask || !*mmc_dev(host)->dma_mask)
-               blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH);
-       blk_queue_max_hw_sectors(mq->queue,
-               min(host->max_blk_count, host->max_req_size / 512));
-       if (host->can_dma_map_merge)
-               WARN(!blk_queue_can_use_dma_map_merging(mq->queue,
-                                                       mmc_dev(host)),
-                    "merging was advertised but not possible");
-       blk_queue_max_segments(mq->queue, mmc_get_max_segments(host));
-
-       if (mmc_card_mmc(card) && card->ext_csd.data_sector_size) {
-               block_size = card->ext_csd.data_sector_size;
-               WARN_ON(block_size != 512 && block_size != 4096);
-       }
+               lim.bounce = BLK_BOUNCE_HIGH;
+
+       lim.max_hw_sectors = min(host->max_blk_count, host->max_req_size / 512);
+
+       if (mmc_card_mmc(card) && card->ext_csd.data_sector_size)
+               lim.logical_block_size = card->ext_csd.data_sector_size;
+       else
+               lim.logical_block_size = 512;
+
+       WARN_ON_ONCE(lim.logical_block_size != 512 &&
+                    lim.logical_block_size != 4096);
 
-       blk_queue_logical_block_size(mq->queue, block_size);
        /*
-        * After blk_queue_can_use_dma_map_merging() was called with succeed,
-        * since it calls blk_queue_virt_boundary(), the mmc should not call
-        * both blk_queue_max_segment_size().
+        * Setting a virt_boundary implicity sets a max_segment_size, so try
+        * to set the hardware one here.
         */
-       if (!host->can_dma_map_merge)
-               blk_queue_max_segment_size(mq->queue,
-                       round_down(host->max_seg_size, block_size));
+       if (host->can_dma_map_merge) {
+               lim.virt_boundary_mask = dma_get_merge_boundary(mmc_dev(host));
+               lim.max_segments = MMC_DMA_MAP_MERGE_SEGMENTS;
+       } else {
+               lim.max_segment_size =
+                       round_down(host->max_seg_size, lim.logical_block_size);
+               lim.max_segments = host->max_segs;
+       }
+
+       disk = blk_mq_alloc_disk(&mq->tag_set, &lim, mq);
+       if (IS_ERR(disk))
+               return disk;
+       mq->queue = disk->queue;
+
+       if (mmc_host_is_spi(host) && host->use_spi_crc)
+               blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, mq->queue);
+       blk_queue_rq_timeout(mq->queue, 60 * HZ);
+
+       blk_queue_flag_set(QUEUE_FLAG_NONROT, mq->queue);
+       blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, mq->queue);
 
        dma_set_max_seg_size(mmc_dev(host), queue_max_segment_size(mq->queue));
 
@@ -386,6 +401,7 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
        init_waitqueue_head(&mq->wait);
 
        mmc_crypto_setup_queue(mq->queue, host);
+       return disk;
 }
 
 static inline bool mmc_merge_capable(struct mmc_host *host)
@@ -447,18 +463,9 @@ struct gendisk *mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)
                return ERR_PTR(ret);
                
 
-       disk = blk_mq_alloc_disk(&mq->tag_set, mq);
-       if (IS_ERR(disk)) {
+       disk = mmc_alloc_disk(mq, card);
+       if (IS_ERR(disk))
                blk_mq_free_tag_set(&mq->tag_set);
-               return disk;
-       }
-       mq->queue = disk->queue;
-
-       if (mmc_host_is_spi(host) && host->use_spi_crc)
-               blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, mq->queue);
-       blk_queue_rq_timeout(mq->queue, 60 * HZ);
-
-       mmc_setup_queue(mq, card);
        return disk;
 }
 
index 35067e1e6cd8017b1bb37683f9dda6169af5cbf1..f5da7f9baa52d4b29cd396f0aa88e1ff7891666c 100644 (file)
@@ -225,6 +225,8 @@ static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl)
        struct scatterlist *sg;
        int i;
 
+       host->dma_in_progress = true;
+
        if (!host->variant->dma_lli || data->sg_len == 1 ||
            idma->use_bounce_buffer) {
                u32 dma_addr;
@@ -263,9 +265,30 @@ static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl)
        return 0;
 }
 
+static void sdmmc_idma_error(struct mmci_host *host)
+{
+       struct mmc_data *data = host->data;
+       struct sdmmc_idma *idma = host->dma_priv;
+
+       if (!dma_inprogress(host))
+               return;
+
+       writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR);
+       host->dma_in_progress = false;
+       data->host_cookie = 0;
+
+       if (!idma->use_bounce_buffer)
+               dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+                            mmc_get_dma_dir(data));
+}
+
 static void sdmmc_idma_finalize(struct mmci_host *host, struct mmc_data *data)
 {
+       if (!dma_inprogress(host))
+               return;
+
        writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR);
+       host->dma_in_progress = false;
 
        if (!data->host_cookie)
                sdmmc_idma_unprep_data(host, data, 0);
@@ -676,6 +699,7 @@ static struct mmci_host_ops sdmmc_variant_ops = {
        .dma_setup = sdmmc_idma_setup,
        .dma_start = sdmmc_idma_start,
        .dma_finalize = sdmmc_idma_finalize,
+       .dma_error = sdmmc_idma_error,
        .set_clkreg = mmci_sdmmc_set_clkreg,
        .set_pwrreg = mmci_sdmmc_set_pwrreg,
        .busy_complete = sdmmc_busy_complete,
index 8cf3a375de659a6d98b7dcfc2f4e2be09f7c4a5d..cc9d28b75eb911733d847a1d0c19cf24d9a3f755 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/ktime.h>
+#include <linux/iopoll.h>
 #include <linux/of_address.h>
 
 #include "sdhci-pltfm.h"
 #define XENON_EMMC_PHY_LOGIC_TIMING_ADJUST     (XENON_EMMC_PHY_REG_BASE + 0x18)
 #define XENON_LOGIC_TIMING_VALUE               0x00AA8977
 
+#define XENON_MAX_PHY_TIMEOUT_LOOPS            100
+
 /*
  * List offset of PHY registers and some special register values
  * in eMMC PHY 5.0 or eMMC PHY 5.1
@@ -216,6 +219,19 @@ static int xenon_alloc_emmc_phy(struct sdhci_host *host)
        return 0;
 }
 
+static int xenon_check_stability_internal_clk(struct sdhci_host *host)
+{
+       u32 reg;
+       int err;
+
+       err = read_poll_timeout(sdhci_readw, reg, reg & SDHCI_CLOCK_INT_STABLE,
+                               1100, 20000, false, host, SDHCI_CLOCK_CONTROL);
+       if (err)
+               dev_err(mmc_dev(host->mmc), "phy_init: Internal clock never stabilized.\n");
+
+       return err;
+}
+
 /*
  * eMMC 5.0/5.1 PHY init/re-init.
  * eMMC PHY init should be executed after:
@@ -232,6 +248,11 @@ static int xenon_emmc_phy_init(struct sdhci_host *host)
        struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
        struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs;
 
+       int ret = xenon_check_stability_internal_clk(host);
+
+       if (ret)
+               return ret;
+
        reg = sdhci_readl(host, phy_regs->timing_adj);
        reg |= XENON_PHY_INITIALIZAION;
        sdhci_writel(host, reg, phy_regs->timing_adj);
@@ -259,18 +280,27 @@ static int xenon_emmc_phy_init(struct sdhci_host *host)
        /* get the wait time */
        wait /= clock;
        wait++;
-       /* wait for host eMMC PHY init completes */
-       udelay(wait);
 
-       reg = sdhci_readl(host, phy_regs->timing_adj);
-       reg &= XENON_PHY_INITIALIZAION;
-       if (reg) {
+       /*
+        * AC5X spec says bit must be polled until zero.
+        * We see cases in which timeout can take longer
+        * than the standard calculation on AC5X, which is
+        * expected following the spec comment above.
+        * According to the spec, we must wait as long as
+        * it takes for that bit to toggle on AC5X.
+        * Cap that with 100 delay loops so we won't get
+        * stuck here forever:
+        */
+
+       ret = read_poll_timeout(sdhci_readl, reg,
+                               !(reg & XENON_PHY_INITIALIZAION),
+                               wait, XENON_MAX_PHY_TIMEOUT_LOOPS * wait,
+                               false, host, phy_regs->timing_adj);
+       if (ret)
                dev_err(mmc_dev(host->mmc), "eMMC PHY init cannot complete after %d us\n",
-                       wait);
-               return -ETIMEDOUT;
-       }
+                       wait * XENON_MAX_PHY_TIMEOUT_LOOPS);
 
-       return 0;
+       return ret;
 }
 
 #define ARMADA_3700_SOC_PAD_1_8V       0x1
index aa44a23ec0451e70a11da895e64dc5a14d2dcbd7..97a00ec9a4d48944a8233b49c5fa0106493abb47 100644 (file)
@@ -37,7 +37,7 @@
 /* Info for the block device */
 struct block2mtd_dev {
        struct list_head list;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct mtd_info mtd;
        struct mutex write_mutex;
 };
@@ -55,8 +55,7 @@ static struct page *page_read(struct address_space *mapping, pgoff_t index)
 /* erase a specified part of the device */
 static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
 {
-       struct address_space *mapping =
-                               dev->bdev_handle->bdev->bd_inode->i_mapping;
+       struct address_space *mapping = dev->bdev_file->f_mapping;
        struct page *page;
        pgoff_t index = to >> PAGE_SHIFT;       // page index
        int pages = len >> PAGE_SHIFT;
@@ -106,8 +105,7 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, u_char *buf)
 {
        struct block2mtd_dev *dev = mtd->priv;
-       struct address_space *mapping =
-                               dev->bdev_handle->bdev->bd_inode->i_mapping;
+       struct address_space *mapping = dev->bdev_file->f_mapping;
        struct page *page;
        pgoff_t index = from >> PAGE_SHIFT;
        int offset = from & (PAGE_SIZE-1);
@@ -142,8 +140,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
                loff_t to, size_t len, size_t *retlen)
 {
        struct page *page;
-       struct address_space *mapping =
-                               dev->bdev_handle->bdev->bd_inode->i_mapping;
+       struct address_space *mapping = dev->bdev_file->f_mapping;
        pgoff_t index = to >> PAGE_SHIFT;       // page index
        int offset = to & ~PAGE_MASK;   // page offset
        int cpylen;
@@ -198,7 +195,7 @@ static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
 static void block2mtd_sync(struct mtd_info *mtd)
 {
        struct block2mtd_dev *dev = mtd->priv;
-       sync_blockdev(dev->bdev_handle->bdev);
+       sync_blockdev(file_bdev(dev->bdev_file));
        return;
 }
 
@@ -210,10 +207,9 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
 
        kfree(dev->mtd.name);
 
-       if (dev->bdev_handle) {
-               invalidate_mapping_pages(
-                       dev->bdev_handle->bdev->bd_inode->i_mapping, 0, -1);
-               bdev_release(dev->bdev_handle);
+       if (dev->bdev_file) {
+               invalidate_mapping_pages(dev->bdev_file->f_mapping, 0, -1);
+               fput(dev->bdev_file);
        }
 
        kfree(dev);
@@ -223,10 +219,10 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
  * This function is marked __ref because it calls the __init marked
  * early_lookup_bdev when called from the early boot code.
  */
-static struct bdev_handle __ref *mdtblock_early_get_bdev(const char *devname,
+static struct file __ref *mdtblock_early_get_bdev(const char *devname,
                blk_mode_t mode, int timeout, struct block2mtd_dev *dev)
 {
-       struct bdev_handle *bdev_handle = ERR_PTR(-ENODEV);
+       struct file *bdev_file = ERR_PTR(-ENODEV);
 #ifndef MODULE
        int i;
 
@@ -234,7 +230,7 @@ static struct bdev_handle __ref *mdtblock_early_get_bdev(const char *devname,
         * We can't use early_lookup_bdev from a running system.
         */
        if (system_state >= SYSTEM_RUNNING)
-               return bdev_handle;
+               return bdev_file;
 
        /*
         * We might not have the root device mounted at this point.
@@ -253,20 +249,20 @@ static struct bdev_handle __ref *mdtblock_early_get_bdev(const char *devname,
                wait_for_device_probe();
 
                if (!early_lookup_bdev(devname, &devt)) {
-                       bdev_handle = bdev_open_by_dev(devt, mode, dev, NULL);
-                       if (!IS_ERR(bdev_handle))
+                       bdev_file = bdev_file_open_by_dev(devt, mode, dev, NULL);
+                       if (!IS_ERR(bdev_file))
                                break;
                }
        }
 #endif
-       return bdev_handle;
+       return bdev_file;
 }
 
 static struct block2mtd_dev *add_device(char *devname, int erase_size,
                char *label, int timeout)
 {
        const blk_mode_t mode = BLK_OPEN_READ | BLK_OPEN_WRITE;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct block_device *bdev;
        struct block2mtd_dev *dev;
        char *name;
@@ -279,16 +275,16 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size,
                return NULL;
 
        /* Get a handle on the device */
-       bdev_handle = bdev_open_by_path(devname, mode, dev, NULL);
-       if (IS_ERR(bdev_handle))
-               bdev_handle = mdtblock_early_get_bdev(devname, mode, timeout,
+       bdev_file = bdev_file_open_by_path(devname, mode, dev, NULL);
+       if (IS_ERR(bdev_file))
+               bdev_file = mdtblock_early_get_bdev(devname, mode, timeout,
                                                      dev);
-       if (IS_ERR(bdev_handle)) {
+       if (IS_ERR(bdev_file)) {
                pr_err("error: cannot open device %s\n", devname);
                goto err_free_block2mtd;
        }
-       dev->bdev_handle = bdev_handle;
-       bdev = bdev_handle->bdev;
+       dev->bdev_file = bdev_file;
+       bdev = file_bdev(bdev_file);
 
        if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
                pr_err("attempting to use an MTD device as a block device\n");
index f0526dcc216276fa212f3cc5d21c8a9bc250d64b..3caa0717d46c012fcf882ee504d743574d072023 100644 (file)
@@ -277,6 +277,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
 {
        struct mtd_blktrans_ops *tr = new->tr;
        struct mtd_blktrans_dev *d;
+       struct queue_limits lim = { };
        int last_devnum = -1;
        struct gendisk *gd;
        int ret;
@@ -331,9 +332,13 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
                        BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);
        if (ret)
                goto out_kfree_tag_set;
+       
+       lim.logical_block_size = tr->blksize;
+       if (tr->discard)
+               lim.max_hw_discard_sectors = UINT_MAX;
 
        /* Create gendisk */
-       gd = blk_mq_alloc_disk(new->tag_set, new);
+       gd = blk_mq_alloc_disk(new->tag_set, &lim, new);
        if (IS_ERR(gd)) {
                ret = PTR_ERR(gd);
                goto out_free_tag_set;
@@ -371,14 +376,9 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
        if (tr->flush)
                blk_queue_write_cache(new->rq, true, false);
 
-       blk_queue_logical_block_size(new->rq, tr->blksize);
-
        blk_queue_flag_set(QUEUE_FLAG_NONROT, new->rq);
        blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, new->rq);
 
-       if (tr->discard)
-               blk_queue_max_discard_sectors(new->rq, UINT_MAX);
-
        gd->queue = new->rq;
 
        if (new->readonly)
index e451b28840d58b2b0e6b5fdd4d50fe809dd29de4..5887feb347a4e42aa1dcc779bc7f5b252402b16e 100644 (file)
@@ -621,6 +621,7 @@ static void mtd_check_of_node(struct mtd_info *mtd)
                if (plen == mtd_name_len &&
                    !strncmp(mtd->name, pname + offset, plen)) {
                        mtd_set_of_node(mtd, mtd_dn);
+                       of_node_put(mtd_dn);
                        break;
                }
        }
index a466987448502e0b576b612f42139f878d4014ff..5b0f5a9cef81b5fbc1494cb9f00b123ea06f0d35 100644 (file)
@@ -290,16 +290,13 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
        MARVELL_LAYOUT( 2048,   512,  4,  1,  1, 2048, 32, 30,  0,  0,  0),
        MARVELL_LAYOUT( 2048,   512,  8,  2,  1, 1024,  0, 30,1024,32, 30),
        MARVELL_LAYOUT( 2048,   512,  8,  2,  1, 1024,  0, 30,1024,64, 30),
-       MARVELL_LAYOUT( 2048,   512,  12, 3,  2, 704,   0, 30,640,  0, 30),
-       MARVELL_LAYOUT( 2048,   512,  16, 5,  4, 512,   0, 30,  0, 32, 30),
+       MARVELL_LAYOUT( 2048,   512,  16, 4,  4, 512,   0, 30,  0, 32, 30),
        MARVELL_LAYOUT( 4096,   512,  4,  2,  2, 2048, 32, 30,  0,  0,  0),
-       MARVELL_LAYOUT( 4096,   512,  8,  5,  4, 1024,  0, 30,  0, 64, 30),
-       MARVELL_LAYOUT( 4096,   512,  12, 6,  5, 704,   0, 30,576, 32, 30),
-       MARVELL_LAYOUT( 4096,   512,  16, 9,  8, 512,   0, 30,  0, 32, 30),
+       MARVELL_LAYOUT( 4096,   512,  8,  4,  4, 1024,  0, 30,  0, 64, 30),
+       MARVELL_LAYOUT( 4096,   512,  16, 8,  8, 512,   0, 30,  0, 32, 30),
        MARVELL_LAYOUT( 8192,   512,  4,  4,  4, 2048,  0, 30,  0,  0,  0),
-       MARVELL_LAYOUT( 8192,   512,  8,  9,  8, 1024,  0, 30,  0, 160, 30),
-       MARVELL_LAYOUT( 8192,   512,  12, 12, 11, 704,  0, 30,448,  64, 30),
-       MARVELL_LAYOUT( 8192,   512,  16, 17, 16, 512,  0, 30,  0,  32, 30),
+       MARVELL_LAYOUT( 8192,   512,  8,  8,  8, 1024,  0, 30,  0, 160, 30),
+       MARVELL_LAYOUT( 8192,   512,  16, 16, 16, 512,  0, 30,  0,  32, 30),
 };
 
 /**
index 987710e09441adefbf238948e759fec4d049b126..6023cba748bb858373a54dd58c5808057d9841fc 100644 (file)
@@ -186,7 +186,7 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
 {
        u8 status2;
        struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
-                                                     &status2);
+                                                     spinand->scratchbuf);
        int ret;
 
        switch (status & STATUS_ECC_MASK) {
@@ -207,6 +207,7 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
                 * report the maximum of 4 in this case
                 */
                /* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */
+               status2 = *(spinand->scratchbuf);
                return ((status & STATUS_ECC_MASK) >> 2) |
                        ((status2 & STATUS_ECC_MASK) >> 4);
 
@@ -228,7 +229,7 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
 {
        u8 status2;
        struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
-                                                     &status2);
+                                                     spinand->scratchbuf);
        int ret;
 
        switch (status & STATUS_ECC_MASK) {
@@ -248,6 +249,7 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
                 * 1 ... 4 bits are flipped (and corrected)
                 */
                /* bits sorted this way (1...0): ECCSE1, ECCSE0 */
+               status2 = *(spinand->scratchbuf);
                return ((status2 & STATUS_ECC_MASK) >> 4) + 1;
 
        case STATUS_ECC_UNCOR_ERROR:
index 654bd7372cd8c09c69bf7c205a728f263dcc3dfc..5c8fdcc088a0df73e4ee4684a4406780fddd978e 100644 (file)
@@ -348,6 +348,9 @@ static int calc_disk_capacity(struct ubi_volume_info *vi, u64 *disk_capacity)
 
 int ubiblock_create(struct ubi_volume_info *vi)
 {
+       struct queue_limits lim = {
+               .max_segments           = UBI_MAX_SG_COUNT,
+       };
        struct ubiblock *dev;
        struct gendisk *gd;
        u64 disk_capacity;
@@ -393,7 +396,7 @@ int ubiblock_create(struct ubi_volume_info *vi)
 
 
        /* Initialize the gendisk of this ubiblock device */
-       gd = blk_mq_alloc_disk(&dev->tag_set, dev);
+       gd = blk_mq_alloc_disk(&dev->tag_set, &lim, dev);
        if (IS_ERR(gd)) {
                ret = PTR_ERR(gd);
                goto out_free_tags;
@@ -416,7 +419,6 @@ int ubiblock_create(struct ubi_volume_info *vi)
        dev->gd = gd;
 
        dev->rq = gd->queue;
-       blk_queue_max_segments(dev->rq, UBI_MAX_SG_COUNT);
 
        list_add_tail(&dev->list, &ubiblock_devices);
 
index 8c651fdee039aab85019b9a574b813c51aa04ef6..57f1729066f28b76de26bd3c5145cbe6bcc2f9ac 100644 (file)
@@ -186,4 +186,5 @@ static void __exit arcnet_raw_exit(void)
 module_init(arcnet_raw_init);
 module_exit(arcnet_raw_exit);
 
+MODULE_DESCRIPTION("ARCnet raw mode packet interface module");
 MODULE_LICENSE("GPL");
index 8c3ccc7c83cd3cd92e73c44ebd09a6fa8f8c0c41..53d10a04d1bd0a765e34dd6e56217a59d5485cc9 100644 (file)
@@ -312,6 +312,7 @@ module_param(node, int, 0);
 module_param(io, int, 0);
 module_param(irq, int, 0);
 module_param_string(device, device, sizeof(device), 0);
+MODULE_DESCRIPTION("ARCnet COM90xx RIM I chipset driver");
 MODULE_LICENSE("GPL");
 
 static struct net_device *my_dev;
index c09b567845e1eeb025eff26c77ad5e22f6db150f..7a0a799737698f8ebb834b592d86c849aaf8f371 100644 (file)
@@ -265,4 +265,5 @@ static void __exit capmode_module_exit(void)
 module_init(capmode_module_init);
 module_exit(capmode_module_exit);
 
+MODULE_DESCRIPTION("ARCnet CAP mode packet interface module");
 MODULE_LICENSE("GPL");
index 7b5c8bb02f11941f6210200c23ee2f74272d49a3..c5e571ec94c990d0a76a19e3ab418730548c0ce1 100644 (file)
@@ -61,6 +61,7 @@ module_param(timeout, int, 0);
 module_param(backplane, int, 0);
 module_param(clockp, int, 0);
 module_param(clockm, int, 0);
+MODULE_DESCRIPTION("ARCnet COM20020 chipset PCI driver");
 MODULE_LICENSE("GPL");
 
 static void led_tx_set(struct led_classdev *led_cdev,
index 06e1651b594ba813fc5a0d75931c12ec299c100a..a0053e3992a364ef3e1d3c4328b4baf8956d248d 100644 (file)
@@ -399,6 +399,7 @@ EXPORT_SYMBOL(com20020_found);
 EXPORT_SYMBOL(com20020_netdev_ops);
 #endif
 
+MODULE_DESCRIPTION("ARCnet COM20020 chipset core driver");
 MODULE_LICENSE("GPL");
 
 #ifdef MODULE
index dc3253b318dafc3e668df035880a8bccabeb0fdc..75f08aa7528b4620180da471e87e225a39fcd06b 100644 (file)
@@ -97,6 +97,7 @@ module_param(backplane, int, 0);
 module_param(clockp, int, 0);
 module_param(clockm, int, 0);
 
+MODULE_DESCRIPTION("ARCnet COM20020 chipset PCMCIA driver");
 MODULE_LICENSE("GPL");
 
 /*====================================================================*/
index 37b47749fc8b4afb24ae60151ac5b316554ab391..3b463fbc6402114322278a6648a422f4a7ea2bff 100644 (file)
@@ -350,6 +350,7 @@ static char device[9];              /* use eg. device=arc1 to change name */
 module_param_hw(io, int, ioport, 0);
 module_param_hw(irq, int, irq, 0);
 module_param_string(device, device, sizeof(device), 0);
+MODULE_DESCRIPTION("ARCnet COM90xx IO mapped chipset driver");
 MODULE_LICENSE("GPL");
 
 #ifndef MODULE
index f49dae1942846d866d11aad4d619202fd7a8cb01..b3b287c1656179b6656d62a53e488ffcd85178ac 100644 (file)
@@ -645,6 +645,7 @@ static void com90xx_copy_from_card(struct net_device *dev, int bufnum,
        TIME(dev, "memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
 }
 
+MODULE_DESCRIPTION("ARCnet COM90xx normal chipset driver");
 MODULE_LICENSE("GPL");
 
 static int __init com90xx_init(void)
index a7752a5b647fcd4128e3e0c7b59961ad0a83c660..46519ca63a0aa5459732fd140d62ad679bc3a519 100644 (file)
@@ -78,6 +78,7 @@ static void __exit arcnet_rfc1051_exit(void)
 module_init(arcnet_rfc1051_init);
 module_exit(arcnet_rfc1051_exit);
 
+MODULE_DESCRIPTION("ARCNet packet format (RFC 1051) module");
 MODULE_LICENSE("GPL");
 
 /* Determine a packet's protocol ID.
index a4c856282674b3d3d74007f43fb7c7272ea046b8..0edf35d971c56ef15a11814167a2100927975f61 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "arcdevice.h"
 
+MODULE_DESCRIPTION("ARCNet packet format (RFC 1201) module");
 MODULE_LICENSE("GPL");
 
 static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
index 4e0600c7b050f21c82a8862e224bb055e95d5039..cd0683bcca038d59336ee548b4aaa6acdb2c21a5 100644 (file)
@@ -1811,7 +1811,7 @@ void bond_xdp_set_features(struct net_device *bond_dev)
 
        ASSERT_RTNL();
 
-       if (!bond_xdp_check(bond)) {
+       if (!bond_xdp_check(bond) || !bond_has_slaves(bond)) {
                xdp_clear_features_flag(bond_dev);
                return;
        }
@@ -1819,6 +1819,8 @@ void bond_xdp_set_features(struct net_device *bond_dev)
        bond_for_each_slave(bond, slave, iter)
                val &= slave->dev->xdp_features;
 
+       val &= ~NETDEV_XDP_ACT_XSK_ZEROCOPY;
+
        xdp_set_features_flag(bond_dev, val);
 }
 
@@ -5909,9 +5911,6 @@ void bond_setup(struct net_device *bond_dev)
        if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP)
                bond_dev->features |= BOND_XFRM_FEATURES;
 #endif /* CONFIG_XFRM_OFFLOAD */
-
-       if (bond_xdp_check(bond))
-               bond_dev->xdp_features = NETDEV_XDP_ACT_MASK;
 }
 
 /* Destroy a bonding device.
index 036d85ef07f5ba676611e4a20ea470ab7691ffc1..dfdc039d92a6c114a1d5204c3a42ad170ca1b400 100644 (file)
@@ -346,7 +346,7 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
                        /* Neither of TDC parameters nor TDC flags are
                         * provided: do calculation
                         */
-                       can_calc_tdco(&priv->tdc, priv->tdc_const, &priv->data_bittiming,
+                       can_calc_tdco(&priv->tdc, priv->tdc_const, &dbt,
                                      &priv->ctrlmode, priv->ctrlmode_supported);
                } /* else: both CAN_CTRLMODE_TDC_{AUTO,MANUAL} are explicitly
                   * turned off. TDC is disabled: do nothing
index 237066d307044583167923fcfc54d88a1ff53bc4..14ca42491512c62d71dac84e6e7d4dd91b2eb19b 100644 (file)
@@ -32,4 +32,5 @@ static int __init dsa_loop_bdinfo_init(void)
 }
 arch_initcall(dsa_loop_bdinfo_init)
 
+MODULE_DESCRIPTION("DSA mock-up switch driver");
 MODULE_LICENSE("GPL");
index 61b71bcfe39625b271e0d932f92ee4564d9d87e2..c3da97abce2027a1ed9173a98b4d08fc755dc1d0 100644 (file)
@@ -49,9 +49,9 @@ static int ksz8_ind_write8(struct ksz_device *dev, u8 table, u16 addr, u8 data)
        mutex_lock(&dev->alu_mutex);
 
        ctrl_addr = IND_ACC_TABLE(table) | addr;
-       ret = ksz_write8(dev, regs[REG_IND_BYTE], data);
+       ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
        if (!ret)
-               ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+               ret = ksz_write8(dev, regs[REG_IND_BYTE], data);
 
        mutex_unlock(&dev->alu_mutex);
 
index da3bdd3025022c3dd7286c3b7873e1a108767025..760a9a60bc15c1849f6b70e7d3f5b99c58667523 100644 (file)
@@ -21,6 +21,7 @@ config ADIN1110
        tristate "Analog Devices ADIN1110 MAC-PHY"
        depends on SPI && NET_SWITCHDEV
        select CRC8
+       select PHYLIB
        help
          Say yes here to build support for Analog Devices ADIN1110
          Low Power 10BASE-T1L Ethernet MAC-PHY.
index 11c23a7f3172d39a200b85baad84c3cb3cc0db07..fd1a5149c00319d3c0c32a784f1d819869c85b44 100644 (file)
@@ -160,23 +160,19 @@ static struct pds_auxiliary_dev *pdsc_auxbus_dev_register(struct pdsc *cf,
        if (err < 0) {
                dev_warn(cf->dev, "auxiliary_device_init of %s failed: %pe\n",
                         name, ERR_PTR(err));
-               goto err_out;
+               kfree(padev);
+               return ERR_PTR(err);
        }
 
        err = auxiliary_device_add(aux_dev);
        if (err) {
                dev_warn(cf->dev, "auxiliary_device_add of %s failed: %pe\n",
                         name, ERR_PTR(err));
-               goto err_out_uninit;
+               auxiliary_device_uninit(aux_dev);
+               return ERR_PTR(err);
        }
 
        return padev;
-
-err_out_uninit:
-       auxiliary_device_uninit(aux_dev);
-err_out:
-       kfree(padev);
-       return ERR_PTR(err);
 }
 
 int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf)
index cdbf053b5376c51c91deadb0d9ce6ab752b90745..0050c5894563b8a54c21a6b8933b844d63804098 100644 (file)
@@ -451,6 +451,9 @@ static void pdsc_remove(struct pci_dev *pdev)
 
 static void pdsc_stop_health_thread(struct pdsc *pdsc)
 {
+       if (pdsc->pdev->is_virtfn)
+               return;
+
        timer_shutdown_sync(&pdsc->wdtimer);
        if (pdsc->health_work.func)
                cancel_work_sync(&pdsc->health_work);
@@ -458,6 +461,9 @@ static void pdsc_stop_health_thread(struct pdsc *pdsc)
 
 static void pdsc_restart_health_thread(struct pdsc *pdsc)
 {
+       if (pdsc->pdev->is_virtfn)
+               return;
+
        timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0);
        mod_timer(&pdsc->wdtimer, jiffies + 1);
 }
index 29b04a274d077375d9658ea91c16df1ccd963969..80245c65cc904defdec4637eb66a9c1edd6eb03f 100644 (file)
@@ -535,9 +535,6 @@ int bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs,
        int j = 0, i;
 
        for (i = 0; i < NUM_NET_FILTERS; i++) {
-               if (j == *rule_cnt)
-                       return -EMSGSIZE;
-
                if (!priv->net_filters[i].claimed ||
                    priv->net_filters[i].port != intf->port)
                        continue;
@@ -547,6 +544,9 @@ int bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs,
                    priv->net_filters[i - 1].wake_filter)
                        continue;
 
+               if (j == *rule_cnt)
+                       return -EMSGSIZE;
+
                rule_locs[j++] = priv->net_filters[i].fs.location;
        }
 
index 53e5428812552b56de4c7809c5c3f49f7c65379b..6ad1366270f79cba0579bac6088743b1645203ef 100644 (file)
@@ -684,6 +684,8 @@ static int bcmasp_init_rx(struct bcmasp_intf *intf)
 
        intf->rx_buf_order = get_order(RING_BUFFER_SIZE);
        buffer_pg = alloc_pages(GFP_KERNEL, intf->rx_buf_order);
+       if (!buffer_pg)
+               return -ENOMEM;
 
        dma = dma_map_page(kdev, buffer_pg, 0, RING_BUFFER_SIZE,
                           DMA_FROM_DEVICE);
@@ -1048,6 +1050,9 @@ static int bcmasp_netif_init(struct net_device *dev, bool phy_connect)
                        netdev_err(dev, "could not attach to PHY\n");
                        goto err_phy_disable;
                }
+
+               /* Indicate that the MAC is responsible for PHY PM */
+               phydev->mac_managed_pm = true;
        } else if (!intf->wolopts) {
                ret = phy_resume(dev->phydev);
                if (ret)
@@ -1092,6 +1097,7 @@ static int bcmasp_netif_init(struct net_device *dev, bool phy_connect)
        return 0;
 
 err_reclaim_tx:
+       netif_napi_del(&intf->tx_napi);
        bcmasp_reclaim_free_all_tx(intf);
 err_phy_disconnect:
        if (phydev)
index 31191b520b5875a72f08e22ce316a103ccee68ea..c32174484a967ae4cf49f6025bf0892333d1fd89 100644 (file)
@@ -1091,10 +1091,10 @@ bnad_cb_tx_resume(struct bnad *bnad, struct bna_tx *tx)
  * Free all TxQs buffers and then notify TX_E_CLEANUP_DONE to Tx fsm.
  */
 static void
-bnad_tx_cleanup(struct delayed_work *work)
+bnad_tx_cleanup(struct work_struct *work)
 {
        struct bnad_tx_info *tx_info =
-               container_of(work, struct bnad_tx_info, tx_cleanup_work);
+               container_of(work, struct bnad_tx_info, tx_cleanup_work.work);
        struct bnad *bnad = NULL;
        struct bna_tcb *tcb;
        unsigned long flags;
@@ -1170,7 +1170,7 @@ bnad_cb_rx_stall(struct bnad *bnad, struct bna_rx *rx)
  * Free all RxQs buffers and then notify RX_E_CLEANUP_DONE to Rx fsm.
  */
 static void
-bnad_rx_cleanup(void *work)
+bnad_rx_cleanup(struct work_struct *work)
 {
        struct bnad_rx_info *rx_info =
                container_of(work, struct bnad_rx_info, rx_cleanup_work);
@@ -1991,8 +1991,7 @@ bnad_setup_tx(struct bnad *bnad, u32 tx_id)
        }
        tx_info->tx = tx;
 
-       INIT_DELAYED_WORK(&tx_info->tx_cleanup_work,
-                       (work_func_t)bnad_tx_cleanup);
+       INIT_DELAYED_WORK(&tx_info->tx_cleanup_work, bnad_tx_cleanup);
 
        /* Register ISR for the Tx object */
        if (intr_info->intr_type == BNA_INTR_T_MSIX) {
@@ -2248,8 +2247,7 @@ bnad_setup_rx(struct bnad *bnad, u32 rx_id)
        rx_info->rx = rx;
        spin_unlock_irqrestore(&bnad->bna_lock, flags);
 
-       INIT_WORK(&rx_info->rx_cleanup_work,
-                       (work_func_t)(bnad_rx_cleanup));
+       INIT_WORK(&rx_info->rx_cleanup_work, bnad_rx_cleanup);
 
        /*
         * Init NAPI, so that state is set to NAPI_STATE_SCHED,
index 20fcb20b42edee5129fcf6e5edde9f3a0ecd2764..66b57783533897e6399ec12505441004646b8ebc 100644 (file)
@@ -49,7 +49,8 @@ int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
 
        tlv->type = htons(type);
        tlv->length = htons(length);
-       memcpy(tlv->value, value, length);
+       unsafe_memcpy(tlv->value, value, length,
+                     /* Flexible array of flexible arrays */);
 
        vp->num_tlvs = htonl(ntohl(vp->num_tlvs) + 1);
        vp->length = htonl(ntohl(vp->length) +
index 9ba15d3183d75726fd88fa6b27a6efaf1fc30790..758535adc9ff5bb0a043683e1875ff1f3c9c2005 100644 (file)
@@ -1073,6 +1073,14 @@ int memac_initialization(struct mac_device *mac_dev,
        unsigned long            capabilities;
        unsigned long           *supported;
 
+       /* The internal connection to the serdes is XGMII, but this isn't
+        * really correct for the phy mode (which is the external connection).
+        * However, this is how all older device trees say that they want
+        * 10GBASE-R (aka XFI), so just convert it for them.
+        */
+       if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
+               mac_dev->phy_if = PHY_INTERFACE_MODE_10GBASER;
+
        mac_dev->phylink_ops            = &memac_mac_ops;
        mac_dev->set_promisc            = memac_set_promiscuous;
        mac_dev->change_addr            = memac_modify_mac_address;
@@ -1139,7 +1147,7 @@ int memac_initialization(struct mac_device *mac_dev,
         * (and therefore that xfi_pcs cannot be set). If we are defaulting to
         * XGMII, assume this is for XFI. Otherwise, assume it is for SGMII.
         */
-       if (err && mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
+       if (err && mac_dev->phy_if == PHY_INTERFACE_MODE_10GBASER)
                memac->xfi_pcs = pcs;
        else
                memac->sgmii_pcs = pcs;
@@ -1153,14 +1161,6 @@ int memac_initialization(struct mac_device *mac_dev,
                goto _return_fm_mac_free;
        }
 
-       /* The internal connection to the serdes is XGMII, but this isn't
-        * really correct for the phy mode (which is the external connection).
-        * However, this is how all older device trees say that they want
-        * 10GBASE-R (aka XFI), so just convert it for them.
-        */
-       if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
-               mac_dev->phy_if = PHY_INTERFACE_MODE_10GBASER;
-
        /* TODO: The following interface modes are supported by (some) hardware
         * but not by this driver:
         * - 1000BASE-KX
index a2788fd5f8bb857510e6c4b4af362188be996e68..19e450a5bd314ff67676843a767ec1c5c2bd84d4 100644 (file)
@@ -2559,7 +2559,7 @@ void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
                hw->phy.ops.write_reg_page(hw, BM_RAR_H(i),
                                           (u16)(mac_reg & 0xFFFF));
                hw->phy.ops.write_reg_page(hw, BM_RAR_CTRL(i),
-                                          FIELD_GET(E1000_RAH_AV, mac_reg));
+                                          (u16)((mac_reg & E1000_RAH_AV) >> 16));
        }
 
        e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
index 9d88ed6105fd8f25ac8724827a9467f5043ee8b5..8db1eb0c1768c9869d7bf09820b4324b91bf788c 100644 (file)
@@ -1523,7 +1523,7 @@ void i40e_dcb_hw_rx_ets_bw_config(struct i40e_hw *hw, u8 *bw_share,
                reg = rd32(hw, I40E_PRTDCB_RETSTCC(i));
                reg &= ~(I40E_PRTDCB_RETSTCC_BWSHARE_MASK     |
                         I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK |
-                        I40E_PRTDCB_RETSTCC_ETSTC_SHIFT);
+                        I40E_PRTDCB_RETSTCC_ETSTC_MASK);
                reg |= FIELD_PREP(I40E_PRTDCB_RETSTCC_BWSHARE_MASK,
                                  bw_share[i]);
                reg |= FIELD_PREP(I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK,
index 6e7fd473abfd001eb45e8b5bda8978fff9eec26b..89a3401d20ab4b1b429802930345c74e823f53e1 100644 (file)
@@ -4926,27 +4926,23 @@ int i40e_vsi_start_rings(struct i40e_vsi *vsi)
 void i40e_vsi_stop_rings(struct i40e_vsi *vsi)
 {
        struct i40e_pf *pf = vsi->back;
-       int pf_q, err, q_end;
+       u32 pf_q, tx_q_end, rx_q_end;
 
        /* When port TX is suspended, don't wait */
        if (test_bit(__I40E_PORT_SUSPENDED, vsi->back->state))
                return i40e_vsi_stop_rings_no_wait(vsi);
 
-       q_end = vsi->base_queue + vsi->num_queue_pairs;
-       for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
-               i40e_pre_tx_queue_cfg(&pf->hw, (u32)pf_q, false);
+       tx_q_end = vsi->base_queue +
+               vsi->alloc_queue_pairs * (i40e_enabled_xdp_vsi(vsi) ? 2 : 1);
+       for (pf_q = vsi->base_queue; pf_q < tx_q_end; pf_q++)
+               i40e_pre_tx_queue_cfg(&pf->hw, pf_q, false);
 
-       for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++) {
-               err = i40e_control_wait_rx_q(pf, pf_q, false);
-               if (err)
-                       dev_info(&pf->pdev->dev,
-                                "VSI seid %d Rx ring %d disable timeout\n",
-                                vsi->seid, pf_q);
-       }
+       rx_q_end = vsi->base_queue + vsi->num_queue_pairs;
+       for (pf_q = vsi->base_queue; pf_q < rx_q_end; pf_q++)
+               i40e_control_rx_q(pf, pf_q, false);
 
        msleep(I40E_DISABLE_TX_GAP_MSEC);
-       pf_q = vsi->base_queue;
-       for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
+       for (pf_q = vsi->base_queue; pf_q < tx_q_end; pf_q++)
                wr32(&pf->hw, I40E_QTX_ENA(pf_q), 0);
 
        i40e_vsi_wait_queues_disabled(vsi);
@@ -5360,7 +5356,7 @@ static int i40e_pf_wait_queues_disabled(struct i40e_pf *pf)
 {
        int v, ret = 0;
 
-       for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
+       for (v = 0; v < pf->num_alloc_vsi; v++) {
                if (pf->vsi[v]) {
                        ret = i40e_vsi_wait_queues_disabled(pf->vsi[v]);
                        if (ret)
@@ -13564,9 +13560,9 @@ int i40e_queue_pair_disable(struct i40e_vsi *vsi, int queue_pair)
                return err;
 
        i40e_queue_pair_disable_irq(vsi, queue_pair);
+       i40e_queue_pair_toggle_napi(vsi, queue_pair, false /* off */);
        err = i40e_queue_pair_toggle_rings(vsi, queue_pair, false /* off */);
        i40e_clean_rx_ring(vsi->rx_rings[queue_pair]);
-       i40e_queue_pair_toggle_napi(vsi, queue_pair, false /* off */);
        i40e_queue_pair_clean_rings(vsi, queue_pair);
        i40e_queue_pair_reset_stats(vsi, queue_pair);
 
index af42693305815ca8711bb80d25b7221ca8981e16..ce1f11b8ad65c213bc0090e64dabe6e7295d736c 100644 (file)
@@ -567,8 +567,7 @@ static inline bool i40e_is_fw_ver_lt(struct i40e_hw *hw, u16 maj, u16 min)
  **/
 static inline bool i40e_is_fw_ver_eq(struct i40e_hw *hw, u16 maj, u16 min)
 {
-       return (hw->aq.fw_maj_ver > maj ||
-               (hw->aq.fw_maj_ver == maj && hw->aq.fw_min_ver == min));
+       return (hw->aq.fw_maj_ver == maj && hw->aq.fw_min_ver == min);
 }
 
 #endif /* _I40E_PROTOTYPE_H_ */
index 908cdbd3ec5d4fafe26fa03b4a41433f04ef5d31..b34c7177088745468ad33817302a631a5162322a 100644 (file)
@@ -2848,6 +2848,24 @@ error_param:
                                      (u8 *)&stats, sizeof(stats));
 }
 
+/**
+ * i40e_can_vf_change_mac
+ * @vf: pointer to the VF info
+ *
+ * Return true if the VF is allowed to change its MAC filters, false otherwise
+ */
+static bool i40e_can_vf_change_mac(struct i40e_vf *vf)
+{
+       /* If the VF MAC address has been set administratively (via the
+        * ndo_set_vf_mac command), then deny permission to the VF to
+        * add/delete unicast MAC addresses, unless the VF is trusted
+        */
+       if (vf->pf_set_mac && !vf->trusted)
+               return false;
+
+       return true;
+}
+
 #define I40E_MAX_MACVLAN_PER_HW 3072
 #define I40E_MAX_MACVLAN_PER_PF(num_ports) (I40E_MAX_MACVLAN_PER_HW /  \
        (num_ports))
@@ -2907,8 +2925,8 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf,
                 * The VF may request to set the MAC address filter already
                 * assigned to it so do not return an error in that case.
                 */
-               if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) &&
-                   !is_multicast_ether_addr(addr) && vf->pf_set_mac &&
+               if (!i40e_can_vf_change_mac(vf) &&
+                   !is_multicast_ether_addr(addr) &&
                    !ether_addr_equal(addr, vf->default_lan_addr.addr)) {
                        dev_err(&pf->pdev->dev,
                                "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n");
@@ -3114,19 +3132,29 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
                        ret = -EINVAL;
                        goto error_param;
                }
-               if (ether_addr_equal(al->list[i].addr, vf->default_lan_addr.addr))
-                       was_unimac_deleted = true;
        }
        vsi = pf->vsi[vf->lan_vsi_idx];
 
        spin_lock_bh(&vsi->mac_filter_hash_lock);
        /* delete addresses from the list */
-       for (i = 0; i < al->num_elements; i++)
+       for (i = 0; i < al->num_elements; i++) {
+               const u8 *addr = al->list[i].addr;
+
+               /* Allow to delete VF primary MAC only if it was not set
+                * administratively by PF or if VF is trusted.
+                */
+               if (ether_addr_equal(addr, vf->default_lan_addr.addr) &&
+                   i40e_can_vf_change_mac(vf))
+                       was_unimac_deleted = true;
+               else
+                       continue;
+
                if (i40e_del_mac_filter(vsi, al->list[i].addr)) {
                        ret = -EINVAL;
                        spin_unlock_bh(&vsi->mac_filter_hash_lock);
                        goto error_param;
                }
+       }
 
        spin_unlock_bh(&vsi->mac_filter_hash_lock);
 
index 7ac847718882e29b38071ca6b8adb47ca063f1d7..c979192e44d108b370ad132ec900c19d8452db32 100644 (file)
@@ -190,15 +190,13 @@ static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx)
        q_vector = vsi->q_vectors[v_idx];
 
        ice_for_each_tx_ring(tx_ring, q_vector->tx) {
-               if (vsi->netdev)
-                       netif_queue_set_napi(vsi->netdev, tx_ring->q_index,
-                                            NETDEV_QUEUE_TYPE_TX, NULL);
+               ice_queue_set_napi(vsi, tx_ring->q_index, NETDEV_QUEUE_TYPE_TX,
+                                  NULL);
                tx_ring->q_vector = NULL;
        }
        ice_for_each_rx_ring(rx_ring, q_vector->rx) {
-               if (vsi->netdev)
-                       netif_queue_set_napi(vsi->netdev, rx_ring->q_index,
-                                            NETDEV_QUEUE_TYPE_RX, NULL);
+               ice_queue_set_napi(vsi, rx_ring->q_index, NETDEV_QUEUE_TYPE_RX,
+                                  NULL);
                rx_ring->q_vector = NULL;
        }
 
index b9c5eced6326f8fe3958c446f3e8b8bb0c517f90..bd9b1fed74ab86d3da3d9941f4139bbd46f3115e 100644 (file)
@@ -30,6 +30,26 @@ static const char * const pin_type_name[] = {
        [ICE_DPLL_PIN_TYPE_RCLK_INPUT] = "rclk-input",
 };
 
+/**
+ * ice_dpll_is_reset - check if reset is in progress
+ * @pf: private board structure
+ * @extack: error reporting
+ *
+ * If reset is in progress, fill extack with error.
+ *
+ * Return:
+ * * false - no reset in progress
+ * * true - reset in progress
+ */
+static bool ice_dpll_is_reset(struct ice_pf *pf, struct netlink_ext_ack *extack)
+{
+       if (ice_is_reset_in_progress(pf->state)) {
+               NL_SET_ERR_MSG(extack, "PF reset in progress");
+               return true;
+       }
+       return false;
+}
+
 /**
  * ice_dpll_pin_freq_set - set pin's frequency
  * @pf: private board structure
@@ -109,6 +129,9 @@ ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv,
        struct ice_pf *pf = d->pf;
        int ret;
 
+       if (ice_dpll_is_reset(pf, extack))
+               return -EBUSY;
+
        mutex_lock(&pf->dplls.lock);
        ret = ice_dpll_pin_freq_set(pf, p, pin_type, frequency, extack);
        mutex_unlock(&pf->dplls.lock);
@@ -254,6 +277,7 @@ ice_dpll_output_frequency_get(const struct dpll_pin *pin, void *pin_priv,
  * ice_dpll_pin_enable - enable a pin on dplls
  * @hw: board private hw structure
  * @pin: pointer to a pin
+ * @dpll_idx: dpll index to connect to output pin
  * @pin_type: type of pin being enabled
  * @extack: error reporting
  *
@@ -266,7 +290,7 @@ ice_dpll_output_frequency_get(const struct dpll_pin *pin, void *pin_priv,
  */
 static int
 ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin,
-                   enum ice_dpll_pin_type pin_type,
+                   u8 dpll_idx, enum ice_dpll_pin_type pin_type,
                    struct netlink_ext_ack *extack)
 {
        u8 flags = 0;
@@ -280,10 +304,12 @@ ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin,
                ret = ice_aq_set_input_pin_cfg(hw, pin->idx, 0, flags, 0, 0);
                break;
        case ICE_DPLL_PIN_TYPE_OUTPUT:
+               flags = ICE_AQC_SET_CGU_OUT_CFG_UPDATE_SRC_SEL;
                if (pin->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN)
                        flags |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN;
                flags |= ICE_AQC_SET_CGU_OUT_CFG_OUT_EN;
-               ret = ice_aq_set_output_pin_cfg(hw, pin->idx, flags, 0, 0, 0);
+               ret = ice_aq_set_output_pin_cfg(hw, pin->idx, flags, dpll_idx,
+                                               0, 0);
                break;
        default:
                return -EINVAL;
@@ -370,7 +396,7 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin,
        case ICE_DPLL_PIN_TYPE_INPUT:
                ret = ice_aq_get_input_pin_cfg(&pf->hw, pin->idx, NULL, NULL,
                                               NULL, &pin->flags[0],
-                                              &pin->freq, NULL);
+                                              &pin->freq, &pin->phase_adjust);
                if (ret)
                        goto err;
                if (ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN & pin->flags[0]) {
@@ -398,14 +424,27 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin,
                break;
        case ICE_DPLL_PIN_TYPE_OUTPUT:
                ret = ice_aq_get_output_pin_cfg(&pf->hw, pin->idx,
-                                               &pin->flags[0], NULL,
+                                               &pin->flags[0], &parent,
                                                &pin->freq, NULL);
                if (ret)
                        goto err;
-               if (ICE_AQC_SET_CGU_OUT_CFG_OUT_EN & pin->flags[0])
-                       pin->state[0] = DPLL_PIN_STATE_CONNECTED;
-               else
-                       pin->state[0] = DPLL_PIN_STATE_DISCONNECTED;
+
+               parent &= ICE_AQC_GET_CGU_OUT_CFG_DPLL_SRC_SEL;
+               if (ICE_AQC_SET_CGU_OUT_CFG_OUT_EN & pin->flags[0]) {
+                       pin->state[pf->dplls.eec.dpll_idx] =
+                               parent == pf->dplls.eec.dpll_idx ?
+                               DPLL_PIN_STATE_CONNECTED :
+                               DPLL_PIN_STATE_DISCONNECTED;
+                       pin->state[pf->dplls.pps.dpll_idx] =
+                               parent == pf->dplls.pps.dpll_idx ?
+                               DPLL_PIN_STATE_CONNECTED :
+                               DPLL_PIN_STATE_DISCONNECTED;
+               } else {
+                       pin->state[pf->dplls.eec.dpll_idx] =
+                               DPLL_PIN_STATE_DISCONNECTED;
+                       pin->state[pf->dplls.pps.dpll_idx] =
+                               DPLL_PIN_STATE_DISCONNECTED;
+               }
                break;
        case ICE_DPLL_PIN_TYPE_RCLK_INPUT:
                for (parent = 0; parent < pf->dplls.rclk.num_parents;
@@ -568,9 +607,13 @@ ice_dpll_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
        struct ice_pf *pf = d->pf;
        int ret;
 
+       if (ice_dpll_is_reset(pf, extack))
+               return -EBUSY;
+
        mutex_lock(&pf->dplls.lock);
        if (enable)
-               ret = ice_dpll_pin_enable(&pf->hw, p, pin_type, extack);
+               ret = ice_dpll_pin_enable(&pf->hw, p, d->dpll_idx, pin_type,
+                                         extack);
        else
                ret = ice_dpll_pin_disable(&pf->hw, p, pin_type, extack);
        if (!ret)
@@ -603,6 +646,11 @@ ice_dpll_output_state_set(const struct dpll_pin *pin, void *pin_priv,
                          struct netlink_ext_ack *extack)
 {
        bool enable = state == DPLL_PIN_STATE_CONNECTED;
+       struct ice_dpll_pin *p = pin_priv;
+       struct ice_dpll *d = dpll_priv;
+
+       if (!enable && p->state[d->dpll_idx] == DPLL_PIN_STATE_DISCONNECTED)
+               return 0;
 
        return ice_dpll_pin_state_set(pin, pin_priv, dpll, dpll_priv, enable,
                                      extack, ICE_DPLL_PIN_TYPE_OUTPUT);
@@ -665,14 +713,16 @@ ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv,
        struct ice_pf *pf = d->pf;
        int ret;
 
+       if (ice_dpll_is_reset(pf, extack))
+               return -EBUSY;
+
        mutex_lock(&pf->dplls.lock);
        ret = ice_dpll_pin_state_update(pf, p, pin_type, extack);
        if (ret)
                goto unlock;
-       if (pin_type == ICE_DPLL_PIN_TYPE_INPUT)
+       if (pin_type == ICE_DPLL_PIN_TYPE_INPUT ||
+           pin_type == ICE_DPLL_PIN_TYPE_OUTPUT)
                *state = p->state[d->dpll_idx];
-       else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT)
-               *state = p->state[0];
        ret = 0;
 unlock:
        mutex_unlock(&pf->dplls.lock);
@@ -790,6 +840,9 @@ ice_dpll_input_prio_set(const struct dpll_pin *pin, void *pin_priv,
        struct ice_pf *pf = d->pf;
        int ret;
 
+       if (ice_dpll_is_reset(pf, extack))
+               return -EBUSY;
+
        mutex_lock(&pf->dplls.lock);
        ret = ice_dpll_hw_input_prio_set(pf, d, p, prio, extack);
        mutex_unlock(&pf->dplls.lock);
@@ -910,6 +963,9 @@ ice_dpll_pin_phase_adjust_set(const struct dpll_pin *pin, void *pin_priv,
        u8 flag, flags_en = 0;
        int ret;
 
+       if (ice_dpll_is_reset(pf, extack))
+               return -EBUSY;
+
        mutex_lock(&pf->dplls.lock);
        switch (type) {
        case ICE_DPLL_PIN_TYPE_INPUT:
@@ -1069,6 +1125,9 @@ ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, void *pin_priv,
        int ret = -EINVAL;
        u32 hw_idx;
 
+       if (ice_dpll_is_reset(pf, extack))
+               return -EBUSY;
+
        mutex_lock(&pf->dplls.lock);
        hw_idx = parent->idx - pf->dplls.base_rclk_idx;
        if (hw_idx >= pf->dplls.num_inputs)
@@ -1123,6 +1182,9 @@ ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, void *pin_priv,
        int ret = -EINVAL;
        u32 hw_idx;
 
+       if (ice_dpll_is_reset(pf, extack))
+               return -EBUSY;
+
        mutex_lock(&pf->dplls.lock);
        hw_idx = parent->idx - pf->dplls.base_rclk_idx;
        if (hw_idx >= pf->dplls.num_inputs)
@@ -1305,8 +1367,10 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
        struct ice_pf *pf = container_of(d, struct ice_pf, dplls);
        struct ice_dpll *de = &pf->dplls.eec;
        struct ice_dpll *dp = &pf->dplls.pps;
-       int ret;
+       int ret = 0;
 
+       if (ice_is_reset_in_progress(pf->state))
+               goto resched;
        mutex_lock(&pf->dplls.lock);
        ret = ice_dpll_update_state(pf, de, false);
        if (!ret)
@@ -1326,6 +1390,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
        ice_dpll_notify_changes(de);
        ice_dpll_notify_changes(dp);
 
+resched:
        /* Run twice a second or reschedule if update failed */
        kthread_queue_delayed_work(d->kworker, &d->work,
                                   ret ? msecs_to_jiffies(10) :
@@ -1532,7 +1597,7 @@ static void ice_dpll_deinit_rclk_pin(struct ice_pf *pf)
        }
        if (WARN_ON_ONCE(!vsi || !vsi->netdev))
                return;
-       netdev_dpll_pin_clear(vsi->netdev);
+       dpll_netdev_pin_clear(vsi->netdev);
        dpll_pin_put(rclk->pin);
 }
 
@@ -1576,7 +1641,7 @@ ice_dpll_init_rclk_pins(struct ice_pf *pf, struct ice_dpll_pin *pin,
        }
        if (WARN_ON((!vsi || !vsi->netdev)))
                return -EINVAL;
-       netdev_dpll_pin_set(vsi->netdev, pf->dplls.rclk.pin);
+       dpll_netdev_pin_set(vsi->netdev, pf->dplls.rclk.pin);
 
        return 0;
 
@@ -2055,6 +2120,7 @@ void ice_dpll_init(struct ice_pf *pf)
        struct ice_dplls *d = &pf->dplls;
        int err = 0;
 
+       mutex_init(&d->lock);
        err = ice_dpll_init_info(pf, cgu);
        if (err)
                goto err_exit;
@@ -2067,7 +2133,6 @@ void ice_dpll_init(struct ice_pf *pf)
        err = ice_dpll_init_pins(pf, cgu);
        if (err)
                goto deinit_pps;
-       mutex_init(&d->lock);
        if (cgu) {
                err = ice_dpll_init_worker(pf);
                if (err)
index 2a25323105e5b9bd5a1dbf072f097ddd90872210..467372d541d21f9c26416275f945b12e684079ef 100644 (file)
@@ -151,6 +151,27 @@ ice_lag_find_hw_by_lport(struct ice_lag *lag, u8 lport)
        return NULL;
 }
 
+/**
+ * ice_pkg_has_lport_extract - check if lport extraction supported
+ * @hw: HW struct
+ */
+static bool ice_pkg_has_lport_extract(struct ice_hw *hw)
+{
+       int i;
+
+       for (i = 0; i < hw->blk[ICE_BLK_SW].es.count; i++) {
+               u16 offset;
+               u8 fv_prot;
+
+               ice_find_prot_off(hw, ICE_BLK_SW, ICE_SW_DEFAULT_PROFILE, i,
+                                 &fv_prot, &offset);
+               if (fv_prot == ICE_FV_PROT_MDID &&
+                   offset == ICE_LP_EXT_BUF_OFFSET)
+                       return true;
+       }
+       return false;
+}
+
 /**
  * ice_lag_find_primary - returns pointer to primary interfaces lag struct
  * @lag: local interfaces lag struct
@@ -1206,7 +1227,7 @@ static void ice_lag_del_prune_list(struct ice_lag *lag, struct ice_pf *event_pf)
 }
 
 /**
- * ice_lag_init_feature_support_flag - Check for NVM support for LAG
+ * ice_lag_init_feature_support_flag - Check for package and NVM support for LAG
  * @pf: PF struct
  */
 static void ice_lag_init_feature_support_flag(struct ice_pf *pf)
@@ -1219,7 +1240,7 @@ static void ice_lag_init_feature_support_flag(struct ice_pf *pf)
        else
                ice_clear_feature_support(pf, ICE_F_ROCE_LAG);
 
-       if (caps->sriov_lag)
+       if (caps->sriov_lag && ice_pkg_has_lport_extract(&pf->hw))
                ice_set_feature_support(pf, ICE_F_SRIOV_LAG);
        else
                ice_clear_feature_support(pf, ICE_F_SRIOV_LAG);
index ede833dfa65866da00d8f4a6d77a90470906f863..183b38792ef22d9ac54daa0ea4a8156039681e7c 100644 (file)
@@ -17,6 +17,9 @@ enum ice_lag_role {
 #define ICE_LAG_INVALID_PORT 0xFF
 
 #define ICE_LAG_RESET_RETRIES          5
+#define ICE_SW_DEFAULT_PROFILE         0
+#define ICE_FV_PROT_MDID               255
+#define ICE_LP_EXT_BUF_OFFSET          32
 
 struct ice_pf;
 struct ice_vf;
index 9be724291ef82ac7e05c198d9febe029b4946a5e..fc23dbe302b46fa35e97ea425add87711abf66ee 100644 (file)
@@ -2426,7 +2426,7 @@ ice_vsi_cfg_def(struct ice_vsi *vsi, struct ice_vsi_cfg_params *params)
                ice_vsi_map_rings_to_vectors(vsi);
 
                /* Associate q_vector rings to napi */
-               ice_vsi_set_napi_queues(vsi, true);
+               ice_vsi_set_napi_queues(vsi);
 
                vsi->stat_offsets_loaded = false;
 
@@ -2904,19 +2904,19 @@ void ice_vsi_dis_irq(struct ice_vsi *vsi)
 }
 
 /**
- * ice_queue_set_napi - Set the napi instance for the queue
+ * __ice_queue_set_napi - Set the napi instance for the queue
  * @dev: device to which NAPI and queue belong
  * @queue_index: Index of queue
  * @type: queue type as RX or TX
  * @napi: NAPI context
  * @locked: is the rtnl_lock already held
  *
- * Set the napi instance for the queue
+ * Set the napi instance for the queue. Caller indicates the lock status.
  */
 static void
-ice_queue_set_napi(struct net_device *dev, unsigned int queue_index,
-                  enum netdev_queue_type type, struct napi_struct *napi,
-                  bool locked)
+__ice_queue_set_napi(struct net_device *dev, unsigned int queue_index,
+                    enum netdev_queue_type type, struct napi_struct *napi,
+                    bool locked)
 {
        if (!locked)
                rtnl_lock();
@@ -2926,26 +2926,79 @@ ice_queue_set_napi(struct net_device *dev, unsigned int queue_index,
 }
 
 /**
- * ice_q_vector_set_napi_queues - Map queue[s] associated with the napi
+ * ice_queue_set_napi - Set the napi instance for the queue
+ * @vsi: VSI being configured
+ * @queue_index: Index of queue
+ * @type: queue type as RX or TX
+ * @napi: NAPI context
+ *
+ * Set the napi instance for the queue. The rtnl lock state is derived from the
+ * execution path.
+ */
+void
+ice_queue_set_napi(struct ice_vsi *vsi, unsigned int queue_index,
+                  enum netdev_queue_type type, struct napi_struct *napi)
+{
+       struct ice_pf *pf = vsi->back;
+
+       if (!vsi->netdev)
+               return;
+
+       if (current_work() == &pf->serv_task ||
+           test_bit(ICE_PREPARED_FOR_RESET, pf->state) ||
+           test_bit(ICE_DOWN, pf->state) ||
+           test_bit(ICE_SUSPENDED, pf->state))
+               __ice_queue_set_napi(vsi->netdev, queue_index, type, napi,
+                                    false);
+       else
+               __ice_queue_set_napi(vsi->netdev, queue_index, type, napi,
+                                    true);
+}
+
+/**
+ * __ice_q_vector_set_napi_queues - Map queue[s] associated with the napi
  * @q_vector: q_vector pointer
  * @locked: is the rtnl_lock already held
  *
+ * Associate the q_vector napi with all the queue[s] on the vector.
+ * Caller indicates the lock status.
+ */
+void __ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector, bool locked)
+{
+       struct ice_rx_ring *rx_ring;
+       struct ice_tx_ring *tx_ring;
+
+       ice_for_each_rx_ring(rx_ring, q_vector->rx)
+               __ice_queue_set_napi(q_vector->vsi->netdev, rx_ring->q_index,
+                                    NETDEV_QUEUE_TYPE_RX, &q_vector->napi,
+                                    locked);
+
+       ice_for_each_tx_ring(tx_ring, q_vector->tx)
+               __ice_queue_set_napi(q_vector->vsi->netdev, tx_ring->q_index,
+                                    NETDEV_QUEUE_TYPE_TX, &q_vector->napi,
+                                    locked);
+       /* Also set the interrupt number for the NAPI */
+       netif_napi_set_irq(&q_vector->napi, q_vector->irq.virq);
+}
+
+/**
+ * ice_q_vector_set_napi_queues - Map queue[s] associated with the napi
+ * @q_vector: q_vector pointer
+ *
  * Associate the q_vector napi with all the queue[s] on the vector
  */
-void ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector, bool locked)
+void ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector)
 {
        struct ice_rx_ring *rx_ring;
        struct ice_tx_ring *tx_ring;
 
        ice_for_each_rx_ring(rx_ring, q_vector->rx)
-               ice_queue_set_napi(q_vector->vsi->netdev, rx_ring->q_index,
-                                  NETDEV_QUEUE_TYPE_RX, &q_vector->napi,
-                                  locked);
+               ice_queue_set_napi(q_vector->vsi, rx_ring->q_index,
+                                  NETDEV_QUEUE_TYPE_RX, &q_vector->napi);
 
        ice_for_each_tx_ring(tx_ring, q_vector->tx)
-               ice_queue_set_napi(q_vector->vsi->netdev, tx_ring->q_index,
-                                  NETDEV_QUEUE_TYPE_TX, &q_vector->napi,
-                                  locked);
+               ice_queue_set_napi(q_vector->vsi, tx_ring->q_index,
+                                  NETDEV_QUEUE_TYPE_TX, &q_vector->napi);
        /* Also set the interrupt number for the NAPI */
        netif_napi_set_irq(&q_vector->napi, q_vector->irq.virq);
 }
@@ -2953,11 +3006,10 @@ void ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector, bool locked)
 /**
  * ice_vsi_set_napi_queues
  * @vsi: VSI pointer
- * @locked: is the rtnl_lock already held
  *
  * Associate queue[s] with napi for all vectors
  */
-void ice_vsi_set_napi_queues(struct ice_vsi *vsi, bool locked)
+void ice_vsi_set_napi_queues(struct ice_vsi *vsi)
 {
        int i;
 
@@ -2965,7 +3017,7 @@ void ice_vsi_set_napi_queues(struct ice_vsi *vsi, bool locked)
                return;
 
        ice_for_each_q_vector(vsi, i)
-               ice_q_vector_set_napi_queues(vsi->q_vectors[i], locked);
+               ice_q_vector_set_napi_queues(vsi->q_vectors[i]);
 }
 
 /**
@@ -3140,7 +3192,7 @@ ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi)
                }
        }
 
-       tx_ring_stats = vsi_stat->rx_ring_stats;
+       tx_ring_stats = vsi_stat->tx_ring_stats;
        vsi_stat->tx_ring_stats =
                krealloc_array(vsi_stat->tx_ring_stats, req_txq,
                               sizeof(*vsi_stat->tx_ring_stats),
index 71bd27244941d549d9253af900629ccb36278072..bfcfc582a4c04ff143390e394d0b65a1d0970391 100644 (file)
@@ -91,9 +91,15 @@ void ice_vsi_cfg_netdev_tc(struct ice_vsi *vsi, u8 ena_tc);
 struct ice_vsi *
 ice_vsi_setup(struct ice_pf *pf, struct ice_vsi_cfg_params *params);
 
-void ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector, bool locked);
+void
+ice_queue_set_napi(struct ice_vsi *vsi, unsigned int queue_index,
+                  enum netdev_queue_type type, struct napi_struct *napi);
+
+void __ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector, bool locked);
+
+void ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector);
 
-void ice_vsi_set_napi_queues(struct ice_vsi *vsi, bool locked);
+void ice_vsi_set_napi_queues(struct ice_vsi *vsi);
 
 int ice_vsi_release(struct ice_vsi *vsi);
 
index dd4a9bc0dfdc661b2d2f3c48a2df5b773e4f75bb..df6a68ab747eeea289595765bc033473cef37165 100644 (file)
@@ -3495,7 +3495,7 @@ static void ice_napi_add(struct ice_vsi *vsi)
        ice_for_each_q_vector(vsi, v_idx) {
                netif_napi_add(vsi->netdev, &vsi->q_vectors[v_idx]->napi,
                               ice_napi_poll);
-               ice_q_vector_set_napi_queues(vsi->q_vectors[v_idx], false);
+               __ice_q_vector_set_napi_queues(vsi->q_vectors[v_idx], false);
        }
 }
 
@@ -5447,6 +5447,7 @@ static int ice_reinit_interrupt_scheme(struct ice_pf *pf)
                if (ret)
                        goto err_reinit;
                ice_vsi_map_rings_to_vectors(pf->vsi[v]);
+               ice_vsi_set_napi_queues(pf->vsi[v]);
        }
 
        ret = ice_req_irq_msix_misc(pf);
@@ -8012,6 +8013,8 @@ ice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
        pf_sw = pf->first_sw;
        /* find the attribute in the netlink message */
        br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+       if (!br_spec)
+               return -EINVAL;
 
        nla_for_each_nested(attr, br_spec, rem) {
                __u16 mode;
index a94a1c48c3de50db27c4373fef33632c5ae40f70..b0f78c2f2790949c4ed891d2bac789c9d2f2646d 100644 (file)
@@ -1068,6 +1068,7 @@ int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count)
        struct ice_pf *pf = pci_get_drvdata(pdev);
        u16 prev_msix, prev_queues, queues;
        bool needs_rebuild = false;
+       struct ice_vsi *vsi;
        struct ice_vf *vf;
        int id;
 
@@ -1102,6 +1103,10 @@ int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count)
        if (!vf)
                return -ENOENT;
 
+       vsi = ice_get_vf_vsi(vf);
+       if (!vsi)
+               return -ENOENT;
+
        prev_msix = vf->num_msix;
        prev_queues = vf->num_vf_qs;
 
@@ -1122,7 +1127,7 @@ int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count)
        if (vf->first_vector_idx < 0)
                goto unroll;
 
-       if (ice_vf_reconfig_vsi(vf)) {
+       if (ice_vf_reconfig_vsi(vf) || ice_vf_init_host_cfg(vf, vsi)) {
                /* Try to rebuild with previous values */
                needs_rebuild = true;
                goto unroll;
@@ -1148,8 +1153,10 @@ unroll:
        if (vf->first_vector_idx < 0)
                return -EINVAL;
 
-       if (needs_rebuild)
+       if (needs_rebuild) {
                ice_vf_reconfig_vsi(vf);
+               ice_vf_init_host_cfg(vf, vsi);
+       }
 
        ice_ena_vf_mappings(vf);
        ice_put_vf(vf);
index c925813ec9caf06d11199ca066a5096e6d034b4e..6f2328a049bf10e7604f3f33a91ce943944f0e37 100644 (file)
@@ -440,7 +440,6 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
                vf->driver_caps = *(u32 *)msg;
        else
                vf->driver_caps = VIRTCHNL_VF_OFFLOAD_L2 |
-                                 VIRTCHNL_VF_OFFLOAD_RSS_REG |
                                  VIRTCHNL_VF_OFFLOAD_VLAN;
 
        vfres->vf_cap_flags = VIRTCHNL_VF_OFFLOAD_L2;
@@ -453,14 +452,8 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
        vfres->vf_cap_flags |= ice_vc_get_vlan_caps(hw, vf, vsi,
                                                    vf->driver_caps);
 
-       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
+       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF)
                vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF;
-       } else {
-               if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_AQ)
-                       vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_AQ;
-               else
-                       vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_REG;
-       }
 
        if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC)
                vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC;
index 5e19d48a05b45939f3bf72882bb7c9234312a230..d796dbd2a440cd550a9147956c6968286ae9cfa2 100644 (file)
@@ -13,8 +13,6 @@
  * - opcodes needed by VF when caps are activated
  *
  * Caps that don't use new opcodes (no opcodes should be allowed):
- * - VIRTCHNL_VF_OFFLOAD_RSS_AQ
- * - VIRTCHNL_VF_OFFLOAD_RSS_REG
  * - VIRTCHNL_VF_OFFLOAD_WB_ON_ITR
  * - VIRTCHNL_VF_OFFLOAD_CRC
  * - VIRTCHNL_VF_OFFLOAD_RX_POLLING
index 8b81a16770459373026f2436099c0280e29f9022..2eecd0f39aa696e1c24083f03bf9a1908c121fdd 100644 (file)
@@ -179,6 +179,10 @@ static int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx)
                        return -EBUSY;
                usleep_range(1000, 2000);
        }
+
+       ice_qvec_dis_irq(vsi, rx_ring, q_vector);
+       ice_qvec_toggle_napi(vsi, q_vector, false);
+
        netif_tx_stop_queue(netdev_get_tx_queue(vsi->netdev, q_idx));
 
        ice_fill_txq_meta(vsi, tx_ring, &txq_meta);
@@ -195,13 +199,10 @@ static int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx)
                if (err)
                        return err;
        }
-       ice_qvec_dis_irq(vsi, rx_ring, q_vector);
-
        err = ice_vsi_ctrl_one_rx_ring(vsi, false, q_idx, true);
        if (err)
                return err;
 
-       ice_qvec_toggle_napi(vsi, q_vector, false);
        ice_qp_clean_rings(vsi, q_idx);
        ice_qp_reset_stats(vsi, q_idx);
 
@@ -259,11 +260,11 @@ static int ice_qp_ena(struct ice_vsi *vsi, u16 q_idx)
        if (err)
                return err;
 
-       clear_bit(ICE_CFG_BUSY, vsi->state);
        ice_qvec_toggle_napi(vsi, q_vector, true);
        ice_qvec_ena_irq(vsi, q_vector);
 
        netif_tx_start_queue(netdev_get_tx_queue(vsi->netdev, q_idx));
+       clear_bit(ICE_CFG_BUSY, vsi->state);
 
        return 0;
 }
index d0cdd63b3d5b24108ae4832a5e09f4b417e82dfe..390977a76de25a42766c314ab94c42e6528ab4c9 100644 (file)
@@ -2087,8 +2087,10 @@ int idpf_send_disable_queues_msg(struct idpf_vport *vport)
                set_bit(__IDPF_Q_POLL_MODE, vport->txqs[i]->flags);
 
        /* schedule the napi to receive all the marker packets */
+       local_bh_disable();
        for (i = 0; i < vport->num_q_vectors; i++)
                napi_schedule(&vport->q_vectors[i].napi);
+       local_bh_enable();
 
        return idpf_wait_for_marker_event(vport);
 }
index a2b759531cb7ba44720f000018597d5222bec900..3c2dc7bdebb50eb9f08ec49ce6590f2b35445e53 100644 (file)
@@ -637,7 +637,7 @@ struct igb_adapter {
                struct timespec64 period;
        } perout[IGB_N_PEROUT];
 
-       char fw_version[32];
+       char fw_version[48];
 #ifdef CONFIG_IGB_HWMON
        struct hwmon_buff *igb_hwmon_buff;
        bool ets;
index 4df8d4153aa5f5ce7ac9dd566180d552be9f5b4f..cebb44f51d5f5bbd1177b0caeb1e08f7a2fc30db 100644 (file)
@@ -3069,7 +3069,6 @@ void igb_set_fw_version(struct igb_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
        struct e1000_fw_version fw;
-       char *lbuf;
 
        igb_get_fw_version(hw, &fw);
 
@@ -3077,34 +3076,36 @@ void igb_set_fw_version(struct igb_adapter *adapter)
        case e1000_i210:
        case e1000_i211:
                if (!(igb_get_flash_presence_i210(hw))) {
-                       lbuf = kasprintf(GFP_KERNEL, "%2d.%2d-%d",
-                                        fw.invm_major, fw.invm_minor,
-                                        fw.invm_img_type);
+                       snprintf(adapter->fw_version,
+                                sizeof(adapter->fw_version),
+                                "%2d.%2d-%d",
+                                fw.invm_major, fw.invm_minor,
+                                fw.invm_img_type);
                        break;
                }
                fallthrough;
        default:
                /* if option rom is valid, display its version too */
                if (fw.or_valid) {
-                       lbuf = kasprintf(GFP_KERNEL, "%d.%d, 0x%08x, %d.%d.%d",
-                                        fw.eep_major, fw.eep_minor,
-                                        fw.etrack_id, fw.or_major, fw.or_build,
-                                        fw.or_patch);
+                       snprintf(adapter->fw_version,
+                                sizeof(adapter->fw_version),
+                                "%d.%d, 0x%08x, %d.%d.%d",
+                                fw.eep_major, fw.eep_minor, fw.etrack_id,
+                                fw.or_major, fw.or_build, fw.or_patch);
                /* no option rom */
                } else if (fw.etrack_id != 0X0000) {
-                       lbuf = kasprintf(GFP_KERNEL, "%d.%d, 0x%08x",
-                                        fw.eep_major, fw.eep_minor,
-                                        fw.etrack_id);
+                       snprintf(adapter->fw_version,
+                                sizeof(adapter->fw_version),
+                                "%d.%d, 0x%08x",
+                                fw.eep_major, fw.eep_minor, fw.etrack_id);
                } else {
-                       lbuf = kasprintf(GFP_KERNEL, "%d.%d.%d", fw.eep_major,
-                                        fw.eep_minor, fw.eep_build);
+                       snprintf(adapter->fw_version,
+                                sizeof(adapter->fw_version),
+                                "%d.%d.%d",
+                                fw.eep_major, fw.eep_minor, fw.eep_build);
                }
                break;
        }
-
-       /* the truncate happens here if it doesn't fit */
-       strscpy(adapter->fw_version, lbuf, sizeof(adapter->fw_version));
-       kfree(lbuf);
 }
 
 /**
index 319c544b9f04ce5e9ef6f09a9fa3e3f641583f47..f9457055612004c10f74379122063e8136fe7d76 100644 (file)
@@ -957,7 +957,7 @@ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
 
        igb_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
        /* adjust timestamp for the TX latency based on link speed */
-       if (adapter->hw.mac.type == e1000_i210) {
+       if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211) {
                switch (adapter->link_speed) {
                case SPEED_10:
                        adjust = IGB_I210_TX_LATENCY_10;
@@ -1003,6 +1003,7 @@ int igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va,
                        ktime_t *timestamp)
 {
        struct igb_adapter *adapter = q_vector->adapter;
+       struct e1000_hw *hw = &adapter->hw;
        struct skb_shared_hwtstamps ts;
        __le64 *regval = (__le64 *)va;
        int adjust = 0;
@@ -1022,7 +1023,7 @@ int igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va,
        igb_ptp_systim_to_hwtstamp(adapter, &ts, le64_to_cpu(regval[1]));
 
        /* adjust timestamp for the RX latency based on link speed */
-       if (adapter->hw.mac.type == e1000_i210) {
+       if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211) {
                switch (adapter->link_speed) {
                case SPEED_10:
                        adjust = IGB_I210_RX_LATENCY_10;
index ba8d3fe186aedacd5a7959e6fd9da3408fe71843..81c21a893ede9c0c432d26e03f3baecc3293b27f 100644 (file)
@@ -6487,7 +6487,7 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
        int cpu = smp_processor_id();
        struct netdev_queue *nq;
        struct igc_ring *ring;
-       int i, drops;
+       int i, nxmit;
 
        if (unlikely(!netif_carrier_ok(dev)))
                return -ENETDOWN;
@@ -6503,16 +6503,15 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
        /* Avoid transmit queue timeout since we share it with the slow path */
        txq_trans_cond_update(nq);
 
-       drops = 0;
+       nxmit = 0;
        for (i = 0; i < num_frames; i++) {
                int err;
                struct xdp_frame *xdpf = frames[i];
 
                err = igc_xdp_init_tx_descriptor(ring, xdpf);
-               if (err) {
-                       xdp_return_frame_rx_napi(xdpf);
-                       drops++;
-               }
+               if (err)
+                       break;
+               nxmit++;
        }
 
        if (flags & XDP_XMIT_FLUSH)
@@ -6520,7 +6519,7 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
 
        __netif_tx_unlock(nq);
 
-       return num_frames - drops;
+       return nxmit;
 }
 
 static void igc_trigger_rxtxq_interrupt(struct igc_adapter *adapter,
index 7cd8716d2ffa3a90b35cea6218922a8cf656b9eb..861f37076861655df235fed77f6e7d0cb4bb3dc4 100644 (file)
@@ -130,11 +130,7 @@ void igc_power_down_phy_copper(struct igc_hw *hw)
        /* The PHY will retain its settings across a power down/up cycle */
        hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
        mii_reg |= MII_CR_POWER_DOWN;
-
-       /* Temporary workaround - should be removed when PHY will implement
-        * IEEE registers as properly
-        */
-       /* hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);*/
+       hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
        usleep_range(1000, 2000);
 }
 
index bd541527c8c74d6922e8683e2f4493d9b361f67b..99876b765b08bc94e9ba1673205f56e9d140a49d 100644 (file)
@@ -2939,8 +2939,8 @@ static void ixgbe_check_lsc(struct ixgbe_adapter *adapter)
 static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter,
                                           u64 qmask)
 {
-       u32 mask;
        struct ixgbe_hw *hw = &adapter->hw;
+       u32 mask;
 
        switch (hw->mac.type) {
        case ixgbe_mac_82598EB:
@@ -10524,6 +10524,44 @@ static void ixgbe_reset_rxr_stats(struct ixgbe_ring *rx_ring)
        memset(&rx_ring->rx_stats, 0, sizeof(rx_ring->rx_stats));
 }
 
+/**
+ * ixgbe_irq_disable_single - Disable single IRQ vector
+ * @adapter: adapter structure
+ * @ring: ring index
+ **/
+static void ixgbe_irq_disable_single(struct ixgbe_adapter *adapter, u32 ring)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u64 qmask = BIT_ULL(ring);
+       u32 mask;
+
+       switch (adapter->hw.mac.type) {
+       case ixgbe_mac_82598EB:
+               mask = qmask & IXGBE_EIMC_RTX_QUEUE;
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, mask);
+               break;
+       case ixgbe_mac_82599EB:
+       case ixgbe_mac_X540:
+       case ixgbe_mac_X550:
+       case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
+               mask = (qmask & 0xFFFFFFFF);
+               if (mask)
+                       IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask);
+               mask = (qmask >> 32);
+               if (mask)
+                       IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask);
+               break;
+       default:
+               break;
+       }
+       IXGBE_WRITE_FLUSH(&adapter->hw);
+       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+               synchronize_irq(adapter->msix_entries[ring].vector);
+       else
+               synchronize_irq(adapter->pdev->irq);
+}
+
 /**
  * ixgbe_txrx_ring_disable - Disable Rx/Tx/XDP Tx rings
  * @adapter: adapter structure
@@ -10540,6 +10578,11 @@ void ixgbe_txrx_ring_disable(struct ixgbe_adapter *adapter, int ring)
        tx_ring = adapter->tx_ring[ring];
        xdp_ring = adapter->xdp_ring[ring];
 
+       ixgbe_irq_disable_single(adapter, ring);
+
+       /* Rx/Tx/XDP Tx share the same napi context. */
+       napi_disable(&rx_ring->q_vector->napi);
+
        ixgbe_disable_txr(adapter, tx_ring);
        if (xdp_ring)
                ixgbe_disable_txr(adapter, xdp_ring);
@@ -10548,9 +10591,6 @@ void ixgbe_txrx_ring_disable(struct ixgbe_adapter *adapter, int ring)
        if (xdp_ring)
                synchronize_rcu();
 
-       /* Rx/Tx/XDP Tx share the same napi context. */
-       napi_disable(&rx_ring->q_vector->napi);
-
        ixgbe_clean_tx_ring(tx_ring);
        if (xdp_ring)
                ixgbe_clean_tx_ring(xdp_ring);
@@ -10578,9 +10618,6 @@ void ixgbe_txrx_ring_enable(struct ixgbe_adapter *adapter, int ring)
        tx_ring = adapter->tx_ring[ring];
        xdp_ring = adapter->xdp_ring[ring];
 
-       /* Rx/Tx/XDP Tx share the same napi context. */
-       napi_enable(&rx_ring->q_vector->napi);
-
        ixgbe_configure_tx_ring(adapter, tx_ring);
        if (xdp_ring)
                ixgbe_configure_tx_ring(adapter, xdp_ring);
@@ -10589,6 +10626,11 @@ void ixgbe_txrx_ring_enable(struct ixgbe_adapter *adapter, int ring)
        clear_bit(__IXGBE_TX_DISABLED, &tx_ring->state);
        if (xdp_ring)
                clear_bit(__IXGBE_TX_DISABLED, &xdp_ring->state);
+
+       /* Rx/Tx/XDP Tx share the same napi context. */
+       napi_enable(&rx_ring->q_vector->napi);
+       ixgbe_irq_enable_queues(adapter, BIT_ULL(ring));
+       IXGBE_WRITE_FLUSH(&adapter->hw);
 }
 
 /**
index 8cfd74ad991cc8c5a9052a7076c358d372feb804..516adb50f9f6b2b8d4c43f12b51d83da30aae904 100644 (file)
@@ -61,28 +61,6 @@ int rvu_npc_get_tx_nibble_cfg(struct rvu *rvu, u64 nibble_ena)
        return 0;
 }
 
-static int npc_mcam_verify_pf_func(struct rvu *rvu,
-                                  struct mcam_entry *entry_data, u8 intf,
-                                  u16 pcifunc)
-{
-       u16 pf_func, pf_func_mask;
-
-       if (is_npc_intf_rx(intf))
-               return 0;
-
-       pf_func_mask = (entry_data->kw_mask[0] >> 32) &
-               NPC_KEX_PF_FUNC_MASK;
-       pf_func = (entry_data->kw[0] >> 32) & NPC_KEX_PF_FUNC_MASK;
-
-       pf_func = be16_to_cpu((__force __be16)pf_func);
-       if (pf_func_mask != NPC_KEX_PF_FUNC_MASK ||
-           ((pf_func & ~RVU_PFVF_FUNC_MASK) !=
-            (pcifunc & ~RVU_PFVF_FUNC_MASK)))
-               return -EINVAL;
-
-       return 0;
-}
-
 void rvu_npc_set_pkind(struct rvu *rvu, int pkind, struct rvu_pfvf *pfvf)
 {
        int blkaddr;
@@ -437,6 +415,10 @@ static void npc_fixup_vf_rule(struct rvu *rvu, struct npc_mcam *mcam,
                        return;
        }
 
+       /* AF modifies given action iff PF/VF has requested for it */
+       if ((entry->action & 0xFULL) != NIX_RX_ACTION_DEFAULT)
+               return;
+
        /* copy VF default entry action to the VF mcam entry */
        rx_action = npc_get_default_entry_action(rvu, mcam, blkaddr,
                                                 target_func);
@@ -2851,12 +2833,6 @@ int rvu_mbox_handler_npc_mcam_write_entry(struct rvu *rvu,
        else
                nix_intf = pfvf->nix_rx_intf;
 
-       if (!is_pffunc_af(pcifunc) &&
-           npc_mcam_verify_pf_func(rvu, &req->entry_data, req->intf, pcifunc)) {
-               rc = NPC_MCAM_INVALID_REQ;
-               goto exit;
-       }
-
        /* For AF installed rules, the nix_intf should be set to target NIX */
        if (is_pffunc_af(req->hdr.pcifunc))
                nix_intf = req->intf;
@@ -3208,10 +3184,6 @@ int rvu_mbox_handler_npc_mcam_alloc_and_write_entry(struct rvu *rvu,
        if (!is_npc_interface_valid(rvu, req->intf))
                return NPC_MCAM_INVALID_REQ;
 
-       if (npc_mcam_verify_pf_func(rvu, &req->entry_data, req->intf,
-                                   req->hdr.pcifunc))
-               return NPC_MCAM_INVALID_REQ;
-
        /* Try to allocate a MCAM entry */
        entry_req.hdr.pcifunc = req->hdr.pcifunc;
        entry_req.contig = true;
index 3e064234f6fe950273e16a80f31b365e3cad4865..98d4306929f3edf3782d573b5f207a04d64fecdb 100644 (file)
@@ -157,6 +157,12 @@ static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change,
                return -EOPNOTSUPP;
        }
 
+       if (action == DEVLINK_RELOAD_ACTION_FW_ACTIVATE &&
+           !dev->priv.fw_reset) {
+               NL_SET_ERR_MSG_MOD(extack, "FW activate is unsupported for this function");
+               return -EOPNOTSUPP;
+       }
+
        if (mlx5_core_is_pf(dev) && pci_num_vf(pdev))
                NL_SET_ERR_MSG_MOD(extack, "reload while VFs are present is unfavorable");
 
index 18fed2b34fb1cad6319f972ca5b6d604701bbce5..d74a5aaf426863681eac1be35a8ac64054087828 100644 (file)
@@ -261,7 +261,7 @@ static void mlx5_dpll_netdev_dpll_pin_set(struct mlx5_dpll *mdpll,
 {
        if (mdpll->tracking_netdev)
                return;
-       netdev_dpll_pin_set(netdev, mdpll->dpll_pin);
+       dpll_netdev_pin_set(netdev, mdpll->dpll_pin);
        mdpll->tracking_netdev = netdev;
 }
 
@@ -269,7 +269,7 @@ static void mlx5_dpll_netdev_dpll_pin_clear(struct mlx5_dpll *mdpll)
 {
        if (!mdpll->tracking_netdev)
                return;
-       netdev_dpll_pin_clear(mdpll->tracking_netdev);
+       dpll_netdev_pin_clear(mdpll->tracking_netdev);
        mdpll->tracking_netdev = NULL;
 }
 
@@ -389,7 +389,7 @@ static void mlx5_dpll_remove(struct auxiliary_device *adev)
        struct mlx5_dpll *mdpll = auxiliary_get_drvdata(adev);
        struct mlx5_core_dev *mdev = mdpll->mdev;
 
-       cancel_delayed_work(&mdpll->work);
+       cancel_delayed_work_sync(&mdpll->work);
        mlx5_dpll_mdev_netdev_untrack(mdpll, mdev);
        destroy_workqueue(mdpll->wq);
        dpll_pin_unregister(mdpll->dpll, mdpll->dpll_pin,
index 078f56a3cbb2b389499c0b609908972af691a41c..ca05b3252a1b0bd395d07ec37f02edfaa40f477c 100644 (file)
@@ -42,9 +42,9 @@ mlx5e_ptp_port_ts_cqe_list_add(struct mlx5e_ptp_port_ts_cqe_list *list, u8 metad
 
        WARN_ON_ONCE(tracker->inuse);
        tracker->inuse = true;
-       spin_lock(&list->tracker_list_lock);
+       spin_lock_bh(&list->tracker_list_lock);
        list_add_tail(&tracker->entry, &list->tracker_list_head);
-       spin_unlock(&list->tracker_list_lock);
+       spin_unlock_bh(&list->tracker_list_lock);
 }
 
 static void
@@ -54,9 +54,9 @@ mlx5e_ptp_port_ts_cqe_list_remove(struct mlx5e_ptp_port_ts_cqe_list *list, u8 me
 
        WARN_ON_ONCE(!tracker->inuse);
        tracker->inuse = false;
-       spin_lock(&list->tracker_list_lock);
+       spin_lock_bh(&list->tracker_list_lock);
        list_del(&tracker->entry);
-       spin_unlock(&list->tracker_list_lock);
+       spin_unlock_bh(&list->tracker_list_lock);
 }
 
 void mlx5e_ptpsq_track_metadata(struct mlx5e_ptpsq *ptpsq, u8 metadata)
@@ -155,7 +155,7 @@ static void mlx5e_ptpsq_mark_ts_cqes_undelivered(struct mlx5e_ptpsq *ptpsq,
        struct mlx5e_ptp_metadata_map *metadata_map = &ptpsq->metadata_map;
        struct mlx5e_ptp_port_ts_cqe_tracker *pos, *n;
 
-       spin_lock(&cqe_list->tracker_list_lock);
+       spin_lock_bh(&cqe_list->tracker_list_lock);
        list_for_each_entry_safe(pos, n, &cqe_list->tracker_list_head, entry) {
                struct sk_buff *skb =
                        mlx5e_ptp_metadata_map_lookup(metadata_map, pos->metadata_id);
@@ -170,7 +170,7 @@ static void mlx5e_ptpsq_mark_ts_cqes_undelivered(struct mlx5e_ptpsq *ptpsq,
                pos->inuse = false;
                list_del(&pos->entry);
        }
-       spin_unlock(&cqe_list->tracker_list_lock);
+       spin_unlock_bh(&cqe_list->tracker_list_lock);
 }
 
 #define PTP_WQE_CTR2IDX(val) ((val) & ptpsq->ts_cqe_ctr_mask)
index 86bf007fd05b7327a79918b5de9beea9353b70e1..b500cc2c9689d1973d8736b7fa4b421e92d4c5ea 100644 (file)
@@ -37,7 +37,7 @@ mlx5e_tc_post_act_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
 
        if (!MLX5_CAP_FLOWTABLE_TYPE(priv->mdev, ignore_flow_level, table_type)) {
                if (priv->mdev->coredev_type == MLX5_COREDEV_PF)
-                       mlx5_core_warn(priv->mdev, "firmware level support is missing\n");
+                       mlx5_core_dbg(priv->mdev, "firmware flow level support is missing\n");
                err = -EOPNOTSUPP;
                goto err_check;
        }
index d4ebd8743114573e6da44b6eb2418653ab1c4922..b2cabd6ab86cb9044f8d0dc404fa8a052d31938c 100644 (file)
@@ -310,9 +310,9 @@ static void mlx5e_macsec_destroy_object(struct mlx5_core_dev *mdev, u32 macsec_o
        mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
 }
 
-static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec,
-                                   struct mlx5e_macsec_sa *sa,
-                                   bool is_tx, struct net_device *netdev, u32 fs_id)
+static void mlx5e_macsec_cleanup_sa_fs(struct mlx5e_macsec *macsec,
+                                      struct mlx5e_macsec_sa *sa, bool is_tx,
+                                      struct net_device *netdev, u32 fs_id)
 {
        int action =  (is_tx) ?  MLX5_ACCEL_MACSEC_ACTION_ENCRYPT :
                                 MLX5_ACCEL_MACSEC_ACTION_DECRYPT;
@@ -322,20 +322,49 @@ static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec,
 
        mlx5_macsec_fs_del_rule(macsec->mdev->macsec_fs, sa->macsec_rule, action, netdev,
                                fs_id);
-       mlx5e_macsec_destroy_object(macsec->mdev, sa->macsec_obj_id);
        sa->macsec_rule = NULL;
 }
 
+static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec,
+                                   struct mlx5e_macsec_sa *sa, bool is_tx,
+                                   struct net_device *netdev, u32 fs_id)
+{
+       mlx5e_macsec_cleanup_sa_fs(macsec, sa, is_tx, netdev, fs_id);
+       mlx5e_macsec_destroy_object(macsec->mdev, sa->macsec_obj_id);
+}
+
+static int mlx5e_macsec_init_sa_fs(struct macsec_context *ctx,
+                                  struct mlx5e_macsec_sa *sa, bool encrypt,
+                                  bool is_tx, u32 *fs_id)
+{
+       struct mlx5e_priv *priv = macsec_netdev_priv(ctx->netdev);
+       struct mlx5_macsec_fs *macsec_fs = priv->mdev->macsec_fs;
+       struct mlx5_macsec_rule_attrs rule_attrs;
+       union mlx5_macsec_rule *macsec_rule;
+
+       rule_attrs.macsec_obj_id = sa->macsec_obj_id;
+       rule_attrs.sci = sa->sci;
+       rule_attrs.assoc_num = sa->assoc_num;
+       rule_attrs.action = (is_tx) ? MLX5_ACCEL_MACSEC_ACTION_ENCRYPT :
+                                     MLX5_ACCEL_MACSEC_ACTION_DECRYPT;
+
+       macsec_rule = mlx5_macsec_fs_add_rule(macsec_fs, ctx, &rule_attrs, fs_id);
+       if (!macsec_rule)
+               return -ENOMEM;
+
+       sa->macsec_rule = macsec_rule;
+
+       return 0;
+}
+
 static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
                                struct mlx5e_macsec_sa *sa,
                                bool encrypt, bool is_tx, u32 *fs_id)
 {
        struct mlx5e_priv *priv = macsec_netdev_priv(ctx->netdev);
        struct mlx5e_macsec *macsec = priv->macsec;
-       struct mlx5_macsec_rule_attrs rule_attrs;
        struct mlx5_core_dev *mdev = priv->mdev;
        struct mlx5_macsec_obj_attrs obj_attrs;
-       union mlx5_macsec_rule *macsec_rule;
        int err;
 
        obj_attrs.next_pn = sa->next_pn;
@@ -357,20 +386,12 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
        if (err)
                return err;
 
-       rule_attrs.macsec_obj_id = sa->macsec_obj_id;
-       rule_attrs.sci = sa->sci;
-       rule_attrs.assoc_num = sa->assoc_num;
-       rule_attrs.action = (is_tx) ? MLX5_ACCEL_MACSEC_ACTION_ENCRYPT :
-                                     MLX5_ACCEL_MACSEC_ACTION_DECRYPT;
-
-       macsec_rule = mlx5_macsec_fs_add_rule(mdev->macsec_fs, ctx, &rule_attrs, fs_id);
-       if (!macsec_rule) {
-               err = -ENOMEM;
-               goto destroy_macsec_object;
+       if (sa->active) {
+               err = mlx5e_macsec_init_sa_fs(ctx, sa, encrypt, is_tx, fs_id);
+               if (err)
+                       goto destroy_macsec_object;
        }
 
-       sa->macsec_rule = macsec_rule;
-
        return 0;
 
 destroy_macsec_object:
@@ -526,9 +547,7 @@ static int mlx5e_macsec_add_txsa(struct macsec_context *ctx)
                goto destroy_sa;
 
        macsec_device->tx_sa[assoc_num] = tx_sa;
-       if (!secy->operational ||
-           assoc_num != tx_sc->encoding_sa ||
-           !tx_sa->active)
+       if (!secy->operational)
                goto out;
 
        err = mlx5e_macsec_init_sa(ctx, tx_sa, tx_sc->encrypt, true, NULL);
@@ -595,7 +614,7 @@ static int mlx5e_macsec_upd_txsa(struct macsec_context *ctx)
                goto out;
 
        if (ctx_tx_sa->active) {
-               err = mlx5e_macsec_init_sa(ctx, tx_sa, tx_sc->encrypt, true, NULL);
+               err = mlx5e_macsec_init_sa_fs(ctx, tx_sa, tx_sc->encrypt, true, NULL);
                if (err)
                        goto out;
        } else {
@@ -604,7 +623,7 @@ static int mlx5e_macsec_upd_txsa(struct macsec_context *ctx)
                        goto out;
                }
 
-               mlx5e_macsec_cleanup_sa(macsec, tx_sa, true, ctx->secy->netdev, 0);
+               mlx5e_macsec_cleanup_sa_fs(macsec, tx_sa, true, ctx->secy->netdev, 0);
        }
 out:
        mutex_unlock(&macsec->lock);
@@ -1030,8 +1049,9 @@ static int mlx5e_macsec_del_rxsa(struct macsec_context *ctx)
                goto out;
        }
 
-       mlx5e_macsec_cleanup_sa(macsec, rx_sa, false, ctx->secy->netdev,
-                               rx_sc->sc_xarray_element->fs_id);
+       if (rx_sa->active)
+               mlx5e_macsec_cleanup_sa(macsec, rx_sa, false, ctx->secy->netdev,
+                                       rx_sc->sc_xarray_element->fs_id);
        mlx5_destroy_encryption_key(macsec->mdev, rx_sa->enc_key_id);
        kfree(rx_sa);
        rx_sc->rx_sa[assoc_num] = NULL;
@@ -1112,8 +1132,8 @@ static int macsec_upd_secy_hw_address(struct macsec_context *ctx,
                        if (!rx_sa || !rx_sa->macsec_rule)
                                continue;
 
-                       mlx5e_macsec_cleanup_sa(macsec, rx_sa, false, ctx->secy->netdev,
-                                               rx_sc->sc_xarray_element->fs_id);
+                       mlx5e_macsec_cleanup_sa_fs(macsec, rx_sa, false, ctx->secy->netdev,
+                                                  rx_sc->sc_xarray_element->fs_id);
                }
        }
 
@@ -1124,8 +1144,8 @@ static int macsec_upd_secy_hw_address(struct macsec_context *ctx,
                                continue;
 
                        if (rx_sa->active) {
-                               err = mlx5e_macsec_init_sa(ctx, rx_sa, true, false,
-                                                          &rx_sc->sc_xarray_element->fs_id);
+                               err = mlx5e_macsec_init_sa_fs(ctx, rx_sa, true, false,
+                                                             &rx_sc->sc_xarray_element->fs_id);
                                if (err)
                                        goto out;
                        }
@@ -1178,7 +1198,7 @@ static int mlx5e_macsec_upd_secy(struct macsec_context *ctx)
                if (!tx_sa)
                        continue;
 
-               mlx5e_macsec_cleanup_sa(macsec, tx_sa, true, ctx->secy->netdev, 0);
+               mlx5e_macsec_cleanup_sa_fs(macsec, tx_sa, true, ctx->secy->netdev, 0);
        }
 
        for (i = 0; i < MACSEC_NUM_AN; ++i) {
@@ -1187,7 +1207,7 @@ static int mlx5e_macsec_upd_secy(struct macsec_context *ctx)
                        continue;
 
                if (tx_sa->assoc_num == tx_sc->encoding_sa && tx_sa->active) {
-                       err = mlx5e_macsec_init_sa(ctx, tx_sa, tx_sc->encrypt, true, NULL);
+                       err = mlx5e_macsec_init_sa_fs(ctx, tx_sa, tx_sc->encrypt, true, NULL);
                        if (err)
                                goto out;
                }
index 5c166d9d2dca62a8db671c7cb62476781a8d1b97..2fa076b23fbead06bceb6697e0ebb0238bb5be7e 100644 (file)
@@ -401,6 +401,8 @@ mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb,
                mlx5e_skb_cb_hwtstamp_init(skb);
                mlx5e_ptp_metadata_map_put(&sq->ptpsq->metadata_map, skb,
                                           metadata_index);
+               /* ensure skb is put on metadata_map before tracking the index */
+               wmb();
                mlx5e_ptpsq_track_metadata(sq->ptpsq, metadata_index);
                if (!netif_tx_queue_stopped(sq->txq) &&
                    mlx5e_ptpsq_metadata_freelist_empty(sq->ptpsq)) {
index 190f10aba17028211fc6c34abaa7b35d44310ba2..5a0047bdcb5105ae4992578003007d21dd4fa1b5 100644 (file)
@@ -152,7 +152,7 @@ void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev)
 
        xa_for_each(&esw->offloads.vport_reps, i, rep) {
                rpriv = rep->rep_data[REP_ETH].priv;
-               if (!rpriv || !rpriv->netdev || !atomic_read(&rpriv->tc_ht.nelems))
+               if (!rpriv || !rpriv->netdev)
                        continue;
 
                rhashtable_walk_enter(&rpriv->tc_ht, &iter);
index b0455134c98eff62c82b3d35bc8c600dc059d960..baaae628b0a0f6510e2c350cbab0b6309b32da52 100644 (file)
@@ -535,21 +535,26 @@ esw_src_port_rewrite_supported(struct mlx5_eswitch *esw)
 }
 
 static bool
-esw_dests_to_vf_pf_vports(struct mlx5_flow_destination *dests, int max_dest)
+esw_dests_to_int_external(struct mlx5_flow_destination *dests, int max_dest)
 {
-       bool vf_dest = false, pf_dest = false;
+       bool internal_dest = false, external_dest = false;
        int i;
 
        for (i = 0; i < max_dest; i++) {
-               if (dests[i].type != MLX5_FLOW_DESTINATION_TYPE_VPORT)
+               if (dests[i].type != MLX5_FLOW_DESTINATION_TYPE_VPORT &&
+                   dests[i].type != MLX5_FLOW_DESTINATION_TYPE_UPLINK)
                        continue;
 
-               if (dests[i].vport.num == MLX5_VPORT_UPLINK)
-                       pf_dest = true;
+               /* Uplink dest is external, but considered as internal
+                * if there is reformat because firmware uses LB+hairpin to support it.
+                */
+               if (dests[i].vport.num == MLX5_VPORT_UPLINK &&
+                   !(dests[i].vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID))
+                       external_dest = true;
                else
-                       vf_dest = true;
+                       internal_dest = true;
 
-               if (vf_dest && pf_dest)
+               if (internal_dest && external_dest)
                        return true;
        }
 
@@ -695,9 +700,9 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
 
                /* Header rewrite with combined wire+loopback in FDB is not allowed */
                if ((flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) &&
-                   esw_dests_to_vf_pf_vports(dest, i)) {
+                   esw_dests_to_int_external(dest, i)) {
                        esw_warn(esw->dev,
-                                "FDB: Header rewrite with forwarding to both PF and VF is not allowed\n");
+                                "FDB: Header rewrite with forwarding to both internal and external dests is not allowed\n");
                        rule = ERR_PTR(-EINVAL);
                        goto err_esw_get;
                }
@@ -3658,22 +3663,6 @@ static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
        return 0;
 }
 
-static bool esw_offloads_devlink_ns_eq_netdev_ns(struct devlink *devlink)
-{
-       struct mlx5_core_dev *dev = devlink_priv(devlink);
-       struct net *devl_net, *netdev_net;
-       bool ret = false;
-
-       mutex_lock(&dev->mlx5e_res.uplink_netdev_lock);
-       if (dev->mlx5e_res.uplink_netdev) {
-               netdev_net = dev_net(dev->mlx5e_res.uplink_netdev);
-               devl_net = devlink_net(devlink);
-               ret = net_eq(devl_net, netdev_net);
-       }
-       mutex_unlock(&dev->mlx5e_res.uplink_netdev_lock);
-       return ret;
-}
-
 int mlx5_eswitch_block_mode(struct mlx5_core_dev *dev)
 {
        struct mlx5_eswitch *esw = dev->priv.eswitch;
@@ -3718,13 +3707,6 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
        if (esw_mode_from_devlink(mode, &mlx5_mode))
                return -EINVAL;
 
-       if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV &&
-           !esw_offloads_devlink_ns_eq_netdev_ns(devlink)) {
-               NL_SET_ERR_MSG_MOD(extack,
-                                  "Can't change E-Switch mode to switchdev when netdev net namespace has diverged from the devlink's.");
-               return -EPERM;
-       }
-
        mlx5_lag_disable_change(esw->dev);
        err = mlx5_esw_try_lock(esw);
        if (err < 0) {
index f27eab6e49299059ed26ed5edc0cf767b997a08f..2911aa34a5be3f9738b07635a421ba996e4f749a 100644 (file)
@@ -703,19 +703,30 @@ void mlx5_fw_reset_events_start(struct mlx5_core_dev *dev)
 {
        struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
 
+       if (!fw_reset)
+               return;
+
        MLX5_NB_INIT(&fw_reset->nb, fw_reset_event_notifier, GENERAL_EVENT);
        mlx5_eq_notifier_register(dev, &fw_reset->nb);
 }
 
 void mlx5_fw_reset_events_stop(struct mlx5_core_dev *dev)
 {
-       mlx5_eq_notifier_unregister(dev, &dev->priv.fw_reset->nb);
+       struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
+
+       if (!fw_reset)
+               return;
+
+       mlx5_eq_notifier_unregister(dev, &fw_reset->nb);
 }
 
 void mlx5_drain_fw_reset(struct mlx5_core_dev *dev)
 {
        struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
 
+       if (!fw_reset)
+               return;
+
        set_bit(MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS, &fw_reset->reset_flags);
        cancel_work_sync(&fw_reset->fw_live_patch_work);
        cancel_work_sync(&fw_reset->reset_request_work);
@@ -733,9 +744,13 @@ static const struct devlink_param mlx5_fw_reset_devlink_params[] = {
 
 int mlx5_fw_reset_init(struct mlx5_core_dev *dev)
 {
-       struct mlx5_fw_reset *fw_reset = kzalloc(sizeof(*fw_reset), GFP_KERNEL);
+       struct mlx5_fw_reset *fw_reset;
        int err;
 
+       if (!MLX5_CAP_MCAM_REG(dev, mfrl))
+               return 0;
+
+       fw_reset = kzalloc(sizeof(*fw_reset), GFP_KERNEL);
        if (!fw_reset)
                return -ENOMEM;
        fw_reset->wq = create_singlethread_workqueue("mlx5_fw_reset_events");
@@ -771,6 +786,9 @@ void mlx5_fw_reset_cleanup(struct mlx5_core_dev *dev)
 {
        struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
 
+       if (!fw_reset)
+               return;
+
        devl_params_unregister(priv_to_devlink(dev),
                               mlx5_fw_reset_devlink_params,
                               ARRAY_SIZE(mlx5_fw_reset_devlink_params));
index 8ff6dc9bc8033e74d20c2c5423e4a87d64d05b78..b5c709bba1553e1811767a82d07470f4648b0ca5 100644 (file)
@@ -452,10 +452,10 @@ mlx5_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
        struct health_buffer __iomem *h = health->health;
        u8 synd = ioread8(&h->synd);
 
+       devlink_fmsg_u8_pair_put(fmsg, "Syndrome", synd);
        if (!synd)
                return 0;
 
-       devlink_fmsg_u8_pair_put(fmsg, "Syndrome", synd);
        devlink_fmsg_string_pair_put(fmsg, "Description", hsynd_str(synd));
 
        return 0;
index 41fa2523d91d3bf57479dd7d66c1903786aa98b2..5f2cd9a8cf8fb39cef3d6be0806f3a6f9b7cdac7 100644 (file)
@@ -37,19 +37,24 @@ static void lan966x_lag_set_aggr_pgids(struct lan966x *lan966x)
 
        /* Now, set PGIDs for each active LAG */
        for (lag = 0; lag < lan966x->num_phys_ports; ++lag) {
-               struct net_device *bond = lan966x->ports[lag]->bond;
+               struct lan966x_port *port = lan966x->ports[lag];
                int num_active_ports = 0;
+               struct net_device *bond;
                unsigned long bond_mask;
                u8 aggr_idx[16];
 
-               if (!bond || (visited & BIT(lag)))
+               if (!port || !port->bond || (visited & BIT(lag)))
                        continue;
 
+               bond = port->bond;
                bond_mask = lan966x_lag_get_mask(lan966x, bond);
 
                for_each_set_bit(p, &bond_mask, lan966x->num_phys_ports) {
                        struct lan966x_port *port = lan966x->ports[p];
 
+                       if (!port)
+                               continue;
+
                        lan_wr(ANA_PGID_PGID_SET(bond_mask),
                               lan966x, ANA_PGID(p));
                        if (port->lag_tx_active)
index 4af285918ea2a45cae16ca01ec1ab8fd3f5370c9..75868b3f548ec40549c02ad1ac2a3c5c388eade4 100644 (file)
@@ -347,10 +347,10 @@ int sparx5_del_mact_entry(struct sparx5 *sparx5,
                                 list) {
                if ((vid == 0 || mact_entry->vid == vid) &&
                    ether_addr_equal(addr, mact_entry->mac)) {
+                       sparx5_mact_forget(sparx5, addr, mact_entry->vid);
+
                        list_del(&mact_entry->list);
                        devm_kfree(sparx5->dev, mact_entry);
-
-                       sparx5_mact_forget(sparx5, addr, mact_entry->vid);
                }
        }
        mutex_unlock(&sparx5->mact_lock);
index d1f7fc8b1b71ab68775f40ad592ebc8aa0e57211..3c066b62e68947cf81fc34c1169cc2edd2991d5a 100644 (file)
@@ -757,6 +757,7 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, sparx5);
        sparx5->pdev = pdev;
        sparx5->dev = &pdev->dev;
+       spin_lock_init(&sparx5->tx_lock);
 
        /* Do switch core reset if available */
        reset = devm_reset_control_get_optional_shared(&pdev->dev, "switch");
index 6f565c0c0c3dcd3d3889abb1bf8eac72899037fc..316fed5f27355207146875ee80b3636420ca4945 100644 (file)
@@ -280,6 +280,7 @@ struct sparx5 {
        int xtr_irq;
        /* Frame DMA */
        int fdma_irq;
+       spinlock_t tx_lock; /* lock for frame transmission */
        struct sparx5_rx rx;
        struct sparx5_tx tx;
        /* PTP */
index 6db6ac6a3bbc26db972e2f611ddd7c72fac29c16..ac7e1cffbcecf0ccc4f89e394730d90ec2ada2f8 100644 (file)
@@ -244,10 +244,12 @@ netdev_tx_t sparx5_port_xmit_impl(struct sk_buff *skb, struct net_device *dev)
        }
 
        skb_tx_timestamp(skb);
+       spin_lock(&sparx5->tx_lock);
        if (sparx5->fdma_irq > 0)
                ret = sparx5_fdma_xmit(sparx5, ifh, skb);
        else
                ret = sparx5_inject(sparx5, ifh, skb, dev);
+       spin_unlock(&sparx5->tx_lock);
 
        if (ret == -EBUSY)
                goto busy;
index c49aa358e42444de33b3a3dd08832bf8f56af394..6ba8d4aca0a038b88e7f3ae3a8299ea0a55bd7e0 100644 (file)
@@ -93,6 +93,7 @@ static void ionic_unmap_bars(struct ionic *ionic)
                        bars[i].len = 0;
                }
        }
+       ionic->num_bars = 0;
 }
 
 void __iomem *ionic_bus_map_dbpage(struct ionic *ionic, int page_num)
@@ -215,15 +216,17 @@ out:
 
 static void ionic_clear_pci(struct ionic *ionic)
 {
-       ionic->idev.dev_info_regs = NULL;
-       ionic->idev.dev_cmd_regs = NULL;
-       ionic->idev.intr_status = NULL;
-       ionic->idev.intr_ctrl = NULL;
-
-       ionic_unmap_bars(ionic);
-       pci_release_regions(ionic->pdev);
+       if (ionic->num_bars) {
+               ionic->idev.dev_info_regs = NULL;
+               ionic->idev.dev_cmd_regs = NULL;
+               ionic->idev.intr_status = NULL;
+               ionic->idev.intr_ctrl = NULL;
+
+               ionic_unmap_bars(ionic);
+               pci_release_regions(ionic->pdev);
+       }
 
-       if (atomic_read(&ionic->pdev->enable_cnt) > 0)
+       if (pci_is_enabled(ionic->pdev))
                pci_disable_device(ionic->pdev);
 }
 
index 1e7c71f7f081b159e83271eeeb47eb35ac401d69..746072b4dbd0e0d37352bc771aa0c7e963eaa26f 100644 (file)
@@ -319,22 +319,32 @@ do_check_time:
 
 u8 ionic_dev_cmd_status(struct ionic_dev *idev)
 {
+       if (!idev->dev_cmd_regs)
+               return (u8)PCI_ERROR_RESPONSE;
        return ioread8(&idev->dev_cmd_regs->comp.comp.status);
 }
 
 bool ionic_dev_cmd_done(struct ionic_dev *idev)
 {
+       if (!idev->dev_cmd_regs)
+               return false;
        return ioread32(&idev->dev_cmd_regs->done) & IONIC_DEV_CMD_DONE;
 }
 
 void ionic_dev_cmd_comp(struct ionic_dev *idev, union ionic_dev_cmd_comp *comp)
 {
+       if (!idev->dev_cmd_regs)
+               return;
        memcpy_fromio(comp, &idev->dev_cmd_regs->comp, sizeof(*comp));
 }
 
 void ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd)
 {
        idev->opcode = cmd->cmd.opcode;
+
+       if (!idev->dev_cmd_regs)
+               return;
+
        memcpy_toio(&idev->dev_cmd_regs->cmd, cmd, sizeof(*cmd));
        iowrite32(0, &idev->dev_cmd_regs->done);
        iowrite32(1, &idev->dev_cmd_regs->doorbell);
index cd3c0b01402e64360c9104a069f0a9bd5b23b65f..0ffc9c4904ac80320cc9c26f51ea6e52abf60784 100644 (file)
@@ -90,18 +90,23 @@ static void ionic_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
                           void *p)
 {
        struct ionic_lif *lif = netdev_priv(netdev);
+       struct ionic_dev *idev;
        unsigned int offset;
        unsigned int size;
 
        regs->version = IONIC_DEV_CMD_REG_VERSION;
 
+       idev = &lif->ionic->idev;
+       if (!idev->dev_info_regs)
+               return;
+
        offset = 0;
        size = IONIC_DEV_INFO_REG_COUNT * sizeof(u32);
        memcpy_fromio(p + offset, lif->ionic->idev.dev_info_regs->words, size);
 
        offset += size;
        size = IONIC_DEV_CMD_REG_COUNT * sizeof(u32);
-       memcpy_fromio(p + offset, lif->ionic->idev.dev_cmd_regs->words, size);
+       memcpy_fromio(p + offset, idev->dev_cmd_regs->words, size);
 }
 
 static void ionic_get_link_ext_stats(struct net_device *netdev,
index 5f40324cd243fe2f2f79b924920951304d25df45..3c209c1a23373339b8455387105128f2dd9057be 100644 (file)
@@ -109,6 +109,11 @@ int ionic_firmware_update(struct ionic_lif *lif, const struct firmware *fw,
        dl = priv_to_devlink(ionic);
        devlink_flash_update_status_notify(dl, "Preparing to flash", NULL, 0, 0);
 
+       if (!idev->dev_cmd_regs) {
+               err = -ENXIO;
+               goto err_out;
+       }
+
        buf_sz = sizeof(idev->dev_cmd_regs->data);
 
        netdev_dbg(netdev,
index cf2d5ad7b68cc85195e516697d82238c6a7f5924..fcb44ceeb6aa51d944a12b411d904f2715a43be7 100644 (file)
@@ -3559,7 +3559,10 @@ int ionic_lif_init(struct ionic_lif *lif)
                        goto err_out_notifyq_deinit;
        }
 
-       err = ionic_init_nic_features(lif);
+       if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
+               err = ionic_set_nic_features(lif, lif->netdev->features);
+       else
+               err = ionic_init_nic_features(lif);
        if (err)
                goto err_out_notifyq_deinit;
 
index 165ab08ad2dda8ea15cca7aba88f586b0010c3f2..2f479de329fec5ef039c5e4ebaa3ea79d88a04a5 100644 (file)
@@ -416,6 +416,9 @@ static void ionic_dev_cmd_clean(struct ionic *ionic)
 {
        struct ionic_dev *idev = &ionic->idev;
 
+       if (!idev->dev_cmd_regs)
+               return;
+
        iowrite32(0, &idev->dev_cmd_regs->doorbell);
        memset_io(&idev->dev_cmd_regs->cmd, 0, sizeof(idev->dev_cmd_regs->cmd));
 }
index 54cd96b035d680a61297723b46adc16bf10ab3fa..6f47767598637ed3d2a961f6815cc183f066067b 100644 (file)
@@ -579,6 +579,9 @@ int ionic_tx_napi(struct napi_struct *napi, int budget)
        work_done = ionic_cq_service(cq, budget,
                                     ionic_tx_service, NULL, NULL);
 
+       if (unlikely(!budget))
+               return budget;
+
        if (work_done < budget && napi_complete_done(napi, work_done)) {
                ionic_dim_update(qcq, IONIC_LIF_F_TX_DIM_INTR);
                flags |= IONIC_INTR_CRED_UNMASK;
@@ -607,6 +610,9 @@ int ionic_rx_napi(struct napi_struct *napi, int budget)
        u32 work_done = 0;
        u32 flags = 0;
 
+       if (unlikely(!budget))
+               return budget;
+
        lif = cq->bound_q->lif;
        idev = &lif->ionic->idev;
 
@@ -656,6 +662,9 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget)
        tx_work_done = ionic_cq_service(txcq, IONIC_TX_BUDGET_DEFAULT,
                                        ionic_tx_service, NULL, NULL);
 
+       if (unlikely(!budget))
+               return budget;
+
        rx_work_done = ionic_cq_service(rxcq, budget,
                                        ionic_rx_service, NULL, NULL);
 
index 0e3731f50fc2873dc3c4c06c16ffe1f4a8707e83..f7566cfa45ca37a3cfd02331c24f49bf576393a7 100644 (file)
@@ -772,29 +772,25 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q)
        struct ravb_rx_desc *desc;
        struct sk_buff *skb;
        dma_addr_t dma_addr;
+       int rx_packets = 0;
        u8  desc_status;
-       int boguscnt;
        u16 pkt_len;
        u8  die_dt;
        int entry;
        int limit;
+       int i;
 
        entry = priv->cur_rx[q] % priv->num_rx_ring[q];
-       boguscnt = priv->dirty_rx[q] + priv->num_rx_ring[q] - priv->cur_rx[q];
+       limit = priv->dirty_rx[q] + priv->num_rx_ring[q] - priv->cur_rx[q];
        stats = &priv->stats[q];
 
-       boguscnt = min(boguscnt, *quota);
-       limit = boguscnt;
        desc = &priv->gbeth_rx_ring[entry];
-       while (desc->die_dt != DT_FEMPTY) {
+       for (i = 0; i < limit && rx_packets < *quota && desc->die_dt != DT_FEMPTY; i++) {
                /* Descriptor type must be checked before all other reads */
                dma_rmb();
                desc_status = desc->msc;
                pkt_len = le16_to_cpu(desc->ds_cc) & RX_DS;
 
-               if (--boguscnt < 0)
-                       break;
-
                /* We use 0-byte descriptors to mark the DMA mapping errors */
                if (!pkt_len)
                        continue;
@@ -820,7 +816,7 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q)
                                skb_put(skb, pkt_len);
                                skb->protocol = eth_type_trans(skb, ndev);
                                napi_gro_receive(&priv->napi[q], skb);
-                               stats->rx_packets++;
+                               rx_packets++;
                                stats->rx_bytes += pkt_len;
                                break;
                        case DT_FSTART:
@@ -848,7 +844,7 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q)
                                        eth_type_trans(priv->rx_1st_skb, ndev);
                                napi_gro_receive(&priv->napi[q],
                                                 priv->rx_1st_skb);
-                               stats->rx_packets++;
+                               rx_packets++;
                                stats->rx_bytes += pkt_len;
                                break;
                        }
@@ -887,9 +883,9 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q)
                desc->die_dt = DT_FEMPTY;
        }
 
-       *quota -= limit - (++boguscnt);
-
-       return boguscnt <= 0;
+       stats->rx_packets += rx_packets;
+       *quota -= rx_packets;
+       return *quota == 0;
 }
 
 /* Packet receive function for Ethernet AVB */
index 323c57f03c93c8d83c9736cbc8e0a62e8a8344f6..1af2f89a0504ab4c7ad6042e52f5898ba064df6c 100644 (file)
@@ -830,41 +830,42 @@ static const struct dwxgmac3_error_desc dwxgmac3_dma_errors[32]= {
        { false, "UNKNOWN", "Unknown Error" }, /* 31 */
 };
 
-static const char * const dpp_rx_err = "Read Rx Descriptor Parity checker Error";
-static const char * const dpp_tx_err = "Read Tx Descriptor Parity checker Error";
+#define DPP_RX_ERR "Read Rx Descriptor Parity checker Error"
+#define DPP_TX_ERR "Read Tx Descriptor Parity checker Error"
+
 static const struct dwxgmac3_error_desc dwxgmac3_dma_dpp_errors[32] = {
-       { true, "TDPES0", dpp_tx_err },
-       { true, "TDPES1", dpp_tx_err },
-       { true, "TDPES2", dpp_tx_err },
-       { true, "TDPES3", dpp_tx_err },
-       { true, "TDPES4", dpp_tx_err },
-       { true, "TDPES5", dpp_tx_err },
-       { true, "TDPES6", dpp_tx_err },
-       { true, "TDPES7", dpp_tx_err },
-       { true, "TDPES8", dpp_tx_err },
-       { true, "TDPES9", dpp_tx_err },
-       { true, "TDPES10", dpp_tx_err },
-       { true, "TDPES11", dpp_tx_err },
-       { true, "TDPES12", dpp_tx_err },
-       { true, "TDPES13", dpp_tx_err },
-       { true, "TDPES14", dpp_tx_err },
-       { true, "TDPES15", dpp_tx_err },
-       { true, "RDPES0", dpp_rx_err },
-       { true, "RDPES1", dpp_rx_err },
-       { true, "RDPES2", dpp_rx_err },
-       { true, "RDPES3", dpp_rx_err },
-       { true, "RDPES4", dpp_rx_err },
-       { true, "RDPES5", dpp_rx_err },
-       { true, "RDPES6", dpp_rx_err },
-       { true, "RDPES7", dpp_rx_err },
-       { true, "RDPES8", dpp_rx_err },
-       { true, "RDPES9", dpp_rx_err },
-       { true, "RDPES10", dpp_rx_err },
-       { true, "RDPES11", dpp_rx_err },
-       { true, "RDPES12", dpp_rx_err },
-       { true, "RDPES13", dpp_rx_err },
-       { true, "RDPES14", dpp_rx_err },
-       { true, "RDPES15", dpp_rx_err },
+       { true, "TDPES0", DPP_TX_ERR },
+       { true, "TDPES1", DPP_TX_ERR },
+       { true, "TDPES2", DPP_TX_ERR },
+       { true, "TDPES3", DPP_TX_ERR },
+       { true, "TDPES4", DPP_TX_ERR },
+       { true, "TDPES5", DPP_TX_ERR },
+       { true, "TDPES6", DPP_TX_ERR },
+       { true, "TDPES7", DPP_TX_ERR },
+       { true, "TDPES8", DPP_TX_ERR },
+       { true, "TDPES9", DPP_TX_ERR },
+       { true, "TDPES10", DPP_TX_ERR },
+       { true, "TDPES11", DPP_TX_ERR },
+       { true, "TDPES12", DPP_TX_ERR },
+       { true, "TDPES13", DPP_TX_ERR },
+       { true, "TDPES14", DPP_TX_ERR },
+       { true, "TDPES15", DPP_TX_ERR },
+       { true, "RDPES0", DPP_RX_ERR },
+       { true, "RDPES1", DPP_RX_ERR },
+       { true, "RDPES2", DPP_RX_ERR },
+       { true, "RDPES3", DPP_RX_ERR },
+       { true, "RDPES4", DPP_RX_ERR },
+       { true, "RDPES5", DPP_RX_ERR },
+       { true, "RDPES6", DPP_RX_ERR },
+       { true, "RDPES7", DPP_RX_ERR },
+       { true, "RDPES8", DPP_RX_ERR },
+       { true, "RDPES9", DPP_RX_ERR },
+       { true, "RDPES10", DPP_RX_ERR },
+       { true, "RDPES11", DPP_RX_ERR },
+       { true, "RDPES12", DPP_RX_ERR },
+       { true, "RDPES13", DPP_RX_ERR },
+       { true, "RDPES14", DPP_RX_ERR },
+       { true, "RDPES15", DPP_RX_ERR },
 };
 
 static void dwxgmac3_handle_dma_err(struct net_device *ndev,
index 1bd34b2a47e81494eeddf72814b585e47d0b8c60..29367105df548271d3aa22cfad80a40dece256c1 100644 (file)
@@ -224,7 +224,7 @@ static const struct stmmac_hwif_entry {
                .regs = {
                        .ptp_off = PTP_GMAC4_OFFSET,
                        .mmc_off = MMC_GMAC4_OFFSET,
-                       .est_off = EST_XGMAC_OFFSET,
+                       .est_off = EST_GMAC4_OFFSET,
                },
                .desc = &dwmac4_desc_ops,
                .dma = &dwmac410_dma_ops,
index 75d02970450321be0e8f8e3bc2b0e0330f17e4af..7c6aef033a456455e4334466bf276755f33dbd47 100644 (file)
@@ -2672,7 +2672,8 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue,
                        }
                        if (skb) {
                                stmmac_get_tx_hwtstamp(priv, p, skb);
-                       } else {
+                       } else if (tx_q->xsk_pool &&
+                                  xp_tx_metadata_enabled(tx_q->xsk_pool)) {
                                struct stmmac_xsk_tx_complete tx_compl = {
                                        .priv = priv,
                                        .desc = p,
@@ -4005,8 +4006,10 @@ static void stmmac_fpe_stop_wq(struct stmmac_priv *priv)
 {
        set_bit(__FPE_REMOVING, &priv->fpe_task_state);
 
-       if (priv->fpe_wq)
+       if (priv->fpe_wq) {
                destroy_workqueue(priv->fpe_wq);
+               priv->fpe_wq = NULL;
+       }
 
        netdev_info(priv->dev, "FPE workqueue stop");
 }
@@ -6059,11 +6062,6 @@ static irqreturn_t stmmac_mac_interrupt(int irq, void *dev_id)
        struct net_device *dev = (struct net_device *)dev_id;
        struct stmmac_priv *priv = netdev_priv(dev);
 
-       if (unlikely(!dev)) {
-               netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
-               return IRQ_NONE;
-       }
-
        /* Check if adapter is up */
        if (test_bit(STMMAC_DOWN, &priv->state))
                return IRQ_HANDLED;
@@ -6079,11 +6077,6 @@ static irqreturn_t stmmac_safety_interrupt(int irq, void *dev_id)
        struct net_device *dev = (struct net_device *)dev_id;
        struct stmmac_priv *priv = netdev_priv(dev);
 
-       if (unlikely(!dev)) {
-               netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
-               return IRQ_NONE;
-       }
-
        /* Check if adapter is up */
        if (test_bit(STMMAC_DOWN, &priv->state))
                return IRQ_HANDLED;
@@ -6105,11 +6098,6 @@ static irqreturn_t stmmac_msi_intr_tx(int irq, void *data)
        dma_conf = container_of(tx_q, struct stmmac_dma_conf, tx_queue[chan]);
        priv = container_of(dma_conf, struct stmmac_priv, dma_conf);
 
-       if (unlikely(!data)) {
-               netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
-               return IRQ_NONE;
-       }
-
        /* Check if adapter is up */
        if (test_bit(STMMAC_DOWN, &priv->state))
                return IRQ_HANDLED;
@@ -6136,11 +6124,6 @@ static irqreturn_t stmmac_msi_intr_rx(int irq, void *data)
        dma_conf = container_of(rx_q, struct stmmac_dma_conf, rx_queue[chan]);
        priv = container_of(dma_conf, struct stmmac_priv, dma_conf);
 
-       if (unlikely(!data)) {
-               netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
-               return IRQ_NONE;
-       }
-
        /* Check if adapter is up */
        if (test_bit(STMMAC_DOWN, &priv->state))
                return IRQ_HANDLED;
index be01450c20dc0199ebc5d1d731eca04a47781539..1530d13984d42606f6e4b4d1d28ca3f8c6461ac0 100644 (file)
@@ -189,6 +189,7 @@ config TI_ICSSG_PRUETH
        select TI_K3_CPPI_DESC_POOL
        depends on PRU_REMOTEPROC
        depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER
+       depends on PTP_1588_CLOCK_OPTIONAL
        help
          Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem.
          This subsystem is available starting with the AM65 platform.
index 9d2f4ac783e43502586b27283a4db73351ca0583..2939a21ca74f3cf0f627981df74a949e9c61011e 100644 (file)
@@ -294,7 +294,7 @@ static void am65_cpsw_nuss_ndo_host_tx_timeout(struct net_device *ndev,
                   txqueue,
                   netif_tx_queue_stopped(netif_txq),
                   jiffies_to_msecs(jiffies - trans_start),
-                  dql_avail(&netif_txq->dql),
+                  netdev_queue_dql_avail(netif_txq),
                   k3_cppi_desc_pool_avail(tx_chn->desc_pool));
 
        if (netif_tx_queue_stopped(netif_txq)) {
index bcccf43d368b7e2a9efc3a6e855a5b2299e9cdc4..dbbea914604057ca97823c5c6e164be50303df08 100644 (file)
@@ -638,6 +638,16 @@ static void cpts_calc_mult_shift(struct cpts *cpts)
                 freq, cpts->cc.mult, cpts->cc.shift, (ns - NSEC_PER_SEC));
 }
 
+static void cpts_clk_unregister(void *clk)
+{
+       clk_hw_unregister_mux(clk);
+}
+
+static void cpts_clk_del_provider(void *np)
+{
+       of_clk_del_provider(np);
+}
+
 static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node)
 {
        struct device_node *refclk_np;
@@ -687,9 +697,7 @@ static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node)
                goto mux_fail;
        }
 
-       ret = devm_add_action_or_reset(cpts->dev,
-                                      (void(*)(void *))clk_hw_unregister_mux,
-                                      clk_hw);
+       ret = devm_add_action_or_reset(cpts->dev, cpts_clk_unregister, clk_hw);
        if (ret) {
                dev_err(cpts->dev, "add clkmux unreg action %d", ret);
                goto mux_fail;
@@ -699,8 +707,7 @@ static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node)
        if (ret)
                goto mux_fail;
 
-       ret = devm_add_action_or_reset(cpts->dev,
-                                      (void(*)(void *))of_clk_del_provider,
+       ret = devm_add_action_or_reset(cpts->dev, cpts_clk_del_provider,
                                       refclk_np);
        if (ret) {
                dev_err(cpts->dev, "add clkmux provider unreg action %d", ret);
index d5b75af163d35e6b257e9d3dcb48ada80f8a0f20..c1b0d35c8d05207b351b9313f6ae24b986ff3ca1 100644 (file)
@@ -384,18 +384,18 @@ static int gelic_descr_prepare_rx(struct gelic_card *card,
        if (gelic_descr_get_status(descr) !=  GELIC_DESCR_DMA_NOT_IN_USE)
                dev_info(ctodev(card), "%s: ERROR status\n", __func__);
 
-       descr->skb = netdev_alloc_skb(*card->netdev, rx_skb_size);
-       if (!descr->skb) {
-               descr->hw_regs.payload.dev_addr = 0; /* tell DMAC don't touch memory */
-               return -ENOMEM;
-       }
        descr->hw_regs.dmac_cmd_status = 0;
        descr->hw_regs.result_size = 0;
        descr->hw_regs.valid_size = 0;
        descr->hw_regs.data_error = 0;
        descr->hw_regs.payload.dev_addr = 0;
        descr->hw_regs.payload.size = 0;
-       descr->skb = NULL;
+
+       descr->skb = netdev_alloc_skb(*card->netdev, rx_skb_size);
+       if (!descr->skb) {
+               descr->hw_regs.payload.dev_addr = 0; /* tell DMAC don't touch memory */
+               return -ENOMEM;
+       }
 
        offset = ((unsigned long)descr->skb->data) &
                (GELIC_NET_RXBUF_ALIGN - 1);
index 2b6a607ac0b78848d8694af42df349aaa24f16d8..a273362c9e703ce8f807ae86e4705565ab51c605 100644 (file)
@@ -153,6 +153,7 @@ static const struct pci_device_id skfddi_pci_tbl[] = {
        { }                     /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl);
+MODULE_DESCRIPTION("SysKonnect FDDI PCI driver");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>");
 
index 32c51c244153bd760b9f58001906c04c8b0f37ff..c4ed36c71897439fc8f6c11d069c88996e2a2a3c 100644 (file)
@@ -221,7 +221,7 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
        struct genevehdr *gnvh = geneve_hdr(skb);
        struct metadata_dst *tun_dst = NULL;
        unsigned int len;
-       int err = 0;
+       int nh, err = 0;
        void *oiph;
 
        if (ip_tunnel_collect_metadata() || gs->collect_md) {
@@ -272,9 +272,23 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
                skb->pkt_type = PACKET_HOST;
        }
 
-       oiph = skb_network_header(skb);
+       /* Save offset of outer header relative to skb->head,
+        * because we are going to reset the network header to the inner header
+        * and might change skb->head.
+        */
+       nh = skb_network_header(skb) - skb->head;
+
        skb_reset_network_header(skb);
 
+       if (!pskb_inet_may_pull(skb)) {
+               DEV_STATS_INC(geneve->dev, rx_length_errors);
+               DEV_STATS_INC(geneve->dev, rx_errors);
+               goto drop;
+       }
+
+       /* Get the outer header. */
+       oiph = skb->head + nh;
+
        if (geneve_get_sk_family(gs) == AF_INET)
                err = IP_ECN_decapsulate(oiph, skb);
 #if IS_ENABLED(CONFIG_IPV6)
index b1919278e931f4e9fb6b2d2ec2feb2193b2cda61..2b5357d94ff5683049510c71c932be05abe0f211 100644 (file)
@@ -1903,26 +1903,26 @@ static int __init gtp_init(void)
 
        get_random_bytes(&gtp_h_initval, sizeof(gtp_h_initval));
 
-       err = rtnl_link_register(&gtp_link_ops);
+       err = register_pernet_subsys(&gtp_net_ops);
        if (err < 0)
                goto error_out;
 
-       err = genl_register_family(&gtp_genl_family);
+       err = rtnl_link_register(&gtp_link_ops);
        if (err < 0)
-               goto unreg_rtnl_link;
+               goto unreg_pernet_subsys;
 
-       err = register_pernet_subsys(&gtp_net_ops);
+       err = genl_register_family(&gtp_genl_family);
        if (err < 0)
-               goto unreg_genl_family;
+               goto unreg_rtnl_link;
 
        pr_info("GTP module loaded (pdp ctx size %zd bytes)\n",
                sizeof(struct pdp_ctx));
        return 0;
 
-unreg_genl_family:
-       genl_unregister_family(&gtp_genl_family);
 unreg_rtnl_link:
        rtnl_link_unregister(&gtp_link_ops);
+unreg_pernet_subsys:
+       unregister_pernet_subsys(&gtp_net_ops);
 error_out:
        pr_err("error loading GTP module loaded\n");
        return err;
index 35e55f198e05cea45ddb747dff34963eabfac92e..2930141d7dd2d30201e4bd1d4492cbd681fb7c0a 100644 (file)
@@ -259,4 +259,5 @@ static __exit void fake_remove_module(void)
 
 module_init(fakelb_init_module);
 module_exit(fake_remove_module);
+MODULE_DESCRIPTION("IEEE 802.15.4 loopback driver");
 MODULE_LICENSE("GPL");
index 4bc05948f772d8b009e692a62fec564c7380aae3..a78c692f2d3c5dde24879254cab725bc97072634 100644 (file)
@@ -212,7 +212,7 @@ void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt)
        u32 unit_count;
        u32 unit;
 
-       unit_count = roundup(ipa->endpoint_count, 32);
+       unit_count = DIV_ROUND_UP(ipa->endpoint_count, 32);
        for (unit = 0; unit < unit_count; unit++) {
                const struct reg *reg;
                u32 val;
index 60944a4beadae611b2c2dd012683cb30052d0f6b..1afc4c47be73f906f58721aa227dd35fd30eff73 100644 (file)
@@ -237,4 +237,5 @@ static void __exit ipvtap_exit(void)
 module_exit(ipvtap_exit);
 MODULE_ALIAS_RTNL_LINK("ipvtap");
 MODULE_AUTHOR("Sainath Grandhi <sainath.grandhi@intel.com>");
+MODULE_DESCRIPTION("IP-VLAN based tap driver");
 MODULE_LICENSE("GPL");
index 69b829e6ab35b84a07f0063f3a6f7b48ea1a6de1..7fd3377dbd7960adb2af9f19999b1a940b55fc33 100644 (file)
@@ -131,4 +131,5 @@ int __devm_of_mdiobus_register(struct device *dev, struct mii_bus *mdio,
 EXPORT_SYMBOL(__devm_of_mdiobus_register);
 #endif /* CONFIG_OF_MDIO */
 
+MODULE_DESCRIPTION("Network MDIO bus devres helpers");
 MODULE_LICENSE("GPL");
index 894172a3e15fe8a6a86e38b64246ebefcb65362b..337899c69738ec46c2b585db76e11fa25738560e 100644 (file)
@@ -421,9 +421,11 @@ static int rtl8211f_config_init(struct phy_device *phydev)
                                ERR_PTR(ret));
                        return ret;
                }
+
+               return genphy_soft_reset(phydev);
        }
 
-       return genphy_soft_reset(phydev);
+       return 0;
 }
 
 static int rtl821x_suspend(struct phy_device *phydev)
index 40ce8abe699954d106b216e8351925ec1cd9d3a1..cc7d1113ece0ee7d6cfa0e1830bbbdc664c28514 100644 (file)
@@ -1437,4 +1437,5 @@ static int __init plip_init (void)
 
 module_init(plip_init);
 module_exit(plip_cleanup_module);
+MODULE_DESCRIPTION("PLIP (parallel port) network module");
 MODULE_LICENSE("GPL");
index db0dc36d12e33ed7a481319c2d3a219ff88f3782..55954594e157e2eb6a4331e6da3b2d2ff547a4a3 100644 (file)
@@ -1166,5 +1166,6 @@ static void __exit bsdcomp_cleanup(void)
 
 module_init(bsdcomp_init);
 module_exit(bsdcomp_cleanup);
+MODULE_DESCRIPTION("PPP BSD-Compress compression module");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_ALIAS("ppp-compress-" __stringify(CI_BSD_COMPRESS));
index 125793d8aefa77fd961a708f9f7c689d5644e5c0..c33c3db3cc0896d9b033aa2b188fbf46be8afd68 100644 (file)
@@ -87,6 +87,7 @@ struct asyncppp {
 static int flag_time = HZ;
 module_param(flag_time, int, 0);
 MODULE_PARM_DESC(flag_time, "ppp_async: interval between flagged packets (in clock ticks)");
+MODULE_DESCRIPTION("PPP async serial channel module");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_LDISC(N_PPP);
 
index e6d48e5c65a3379e12bbbd4679b1d0b326d3e93b..4d2ff63f2ee2f6bb02a07419513549890956d32e 100644 (file)
@@ -630,6 +630,7 @@ static void __exit deflate_cleanup(void)
 
 module_init(deflate_init);
 module_exit(deflate_cleanup);
+MODULE_DESCRIPTION("PPP Deflate compression module");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE));
 MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE_DRAFT));
index 0193af2d31c9bcf5dc8864da49ba4e75ba0192fc..3dd52bf28f15bf9f260719f1bf61e45d6d48b3f7 100644 (file)
@@ -3604,6 +3604,7 @@ EXPORT_SYMBOL(ppp_input_error);
 EXPORT_SYMBOL(ppp_output_wakeup);
 EXPORT_SYMBOL(ppp_register_compressor);
 EXPORT_SYMBOL(ppp_unregister_compressor);
+MODULE_DESCRIPTION("Generic PPP layer driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0);
 MODULE_ALIAS_RTNL_LINK("ppp");
index 52d05ce4a2819815963eebf4df399058835ff350..45bf59ac8f5711867ed1ba433d3f5e7800b769e4 100644 (file)
@@ -724,5 +724,6 @@ ppp_sync_cleanup(void)
 
 module_init(ppp_sync_init);
 module_exit(ppp_sync_cleanup);
+MODULE_DESCRIPTION("PPP synchronous TTY channel module");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_LDISC(N_SYNC_PPP);
index 8e7238e97d0a71708ebcddda9b1e1a50ab28c17d..2ea4f4890d23b5f1c5229c7f8b303ee85a954037 100644 (file)
@@ -1007,26 +1007,21 @@ static int pppoe_recvmsg(struct socket *sock, struct msghdr *m,
        struct sk_buff *skb;
        int error = 0;
 
-       if (sk->sk_state & PPPOX_BOUND) {
-               error = -EIO;
-               goto end;
-       }
+       if (sk->sk_state & PPPOX_BOUND)
+               return -EIO;
 
        skb = skb_recv_datagram(sk, flags, &error);
-       if (error < 0)
-               goto end;
+       if (!skb)
+               return error;
 
-       if (skb) {
-               total_len = min_t(size_t, total_len, skb->len);
-               error = skb_copy_datagram_msg(skb, 0, m, total_len);
-               if (error == 0) {
-                       consume_skb(skb);
-                       return total_len;
-               }
+       total_len = min_t(size_t, total_len, skb->len);
+       error = skb_copy_datagram_msg(skb, 0, m, total_len);
+       if (error == 0) {
+               consume_skb(skb);
+               return total_len;
        }
 
        kfree_skb(skb);
-end:
        return error;
 }
 
index 4a4f8c8e79fa12dc84a8c83cefbf964dd40e1aa2..8f95a562b8d0c471c44591629e04809f7faef9b2 100644 (file)
@@ -653,6 +653,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
                                   tun->tfiles[tun->numqueues - 1]);
                ntfile = rtnl_dereference(tun->tfiles[index]);
                ntfile->queue_index = index;
+               ntfile->xdp_rxq.queue_index = index;
                rcu_assign_pointer(tun->tfiles[tun->numqueues - 1],
                                   NULL);
 
index 99ec1d4a972db8c1232ce8ee8eb8d97385a9b5f0..8b6d6a1b3c2eca086e77915e26428c1110127f4d 100644 (file)
@@ -232,7 +232,7 @@ static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc)
        err = dm_read_shared_word(dev, 1, loc, &res);
        if (err < 0) {
                netdev_err(dev->net, "MDIO read error: %d\n", err);
-               return err;
+               return 0;
        }
 
        netdev_dbg(dev->net,
index a6d653ff552a261ca50d331dd7d7aa875ca3c362..d2aa2c5b1989da8a7e099dfdef88c087da3cf37b 100644 (file)
@@ -1501,7 +1501,9 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
 
                lan78xx_rx_urb_submit_all(dev);
 
+               local_bh_disable();
                napi_schedule(&dev->napi);
+               local_bh_enable();
        }
 
        return 0;
@@ -3033,7 +3035,8 @@ static int lan78xx_reset(struct lan78xx_net *dev)
        if (dev->chipid == ID_REV_CHIP_ID_7801_)
                buf &= ~MAC_CR_GMII_EN_;
 
-       if (dev->chipid == ID_REV_CHIP_ID_7800_) {
+       if (dev->chipid == ID_REV_CHIP_ID_7800_ ||
+           dev->chipid == ID_REV_CHIP_ID_7850_) {
                ret = lan78xx_read_raw_eeprom(dev, 0, 1, &sig);
                if (!ret && sig != EEPROM_INDICATOR) {
                        /* Implies there is no external eeprom. Set mac speed */
@@ -3132,7 +3135,8 @@ static int lan78xx_open(struct net_device *net)
 done:
        mutex_unlock(&dev->dev_mutex);
 
-       usb_autopm_put_interface(dev->intf);
+       if (ret < 0)
+               usb_autopm_put_interface(dev->intf);
 
        return ret;
 }
index a530f20ee257550141e5ec7c17b5fba0087db248..2fa46baa589e5e87e12e145fe46268bdaf9fc219 100644 (file)
@@ -2104,6 +2104,11 @@ static const struct usb_device_id products[] = {
                USB_DEVICE(0x0424, 0x9E08),
                .driver_info = (unsigned long) &smsc95xx_info,
        },
+       {
+               /* SYSTEC USB-SPEmodule1 10BASE-T1L Ethernet Device */
+               USB_DEVICE(0x0878, 0x1400),
+               .driver_info = (unsigned long)&smsc95xx_info,
+       },
        {
                /* Microchip's EVB-LAN8670-USB 10BASE-T1S Ethernet Device */
                USB_DEVICE(0x184F, 0x0051),
index 578e36ea1589c11f1ca26b6e05a84b455d22999e..cd4a6fe458f95d7bbc3c468ae8585d06cf0ac097 100644 (file)
@@ -1208,14 +1208,6 @@ static int veth_enable_xdp(struct net_device *dev)
                                veth_disable_xdp_range(dev, 0, dev->real_num_rx_queues, true);
                                return err;
                        }
-
-                       if (!veth_gro_requested(dev)) {
-                               /* user-space did not require GRO, but adding XDP
-                                * is supposed to get GRO working
-                                */
-                               dev->features |= NETIF_F_GRO;
-                               netdev_features_change(dev);
-                       }
                }
        }
 
@@ -1235,18 +1227,9 @@ static void veth_disable_xdp(struct net_device *dev)
        for (i = 0; i < dev->real_num_rx_queues; i++)
                rcu_assign_pointer(priv->rq[i].xdp_prog, NULL);
 
-       if (!netif_running(dev) || !veth_gro_requested(dev)) {
+       if (!netif_running(dev) || !veth_gro_requested(dev))
                veth_napi_del(dev);
 
-               /* if user-space did not require GRO, since adding XDP
-                * enabled it, clear it now
-                */
-               if (!veth_gro_requested(dev) && netif_running(dev)) {
-                       dev->features &= ~NETIF_F_GRO;
-                       netdev_features_change(dev);
-               }
-       }
-
        veth_disable_xdp_range(dev, 0, dev->real_num_rx_queues, false);
 }
 
@@ -1478,7 +1461,8 @@ static int veth_alloc_queues(struct net_device *dev)
        struct veth_priv *priv = netdev_priv(dev);
        int i;
 
-       priv->rq = kcalloc(dev->num_rx_queues, sizeof(*priv->rq), GFP_KERNEL_ACCOUNT);
+       priv->rq = kvcalloc(dev->num_rx_queues, sizeof(*priv->rq),
+                           GFP_KERNEL_ACCOUNT | __GFP_RETRY_MAYFAIL);
        if (!priv->rq)
                return -ENOMEM;
 
@@ -1494,7 +1478,7 @@ static void veth_free_queues(struct net_device *dev)
 {
        struct veth_priv *priv = netdev_priv(dev);
 
-       kfree(priv->rq);
+       kvfree(priv->rq);
 }
 
 static int veth_dev_init(struct net_device *dev)
@@ -1654,6 +1638,14 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
                }
 
                if (!old_prog) {
+                       if (!veth_gro_requested(dev)) {
+                               /* user-space did not require GRO, but adding
+                                * XDP is supposed to get GRO working
+                                */
+                               dev->features |= NETIF_F_GRO;
+                               netdev_features_change(dev);
+                       }
+
                        peer->hw_features &= ~NETIF_F_GSO_SOFTWARE;
                        peer->max_mtu = max_mtu;
                }
@@ -1669,6 +1661,14 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
                        if (dev->flags & IFF_UP)
                                veth_disable_xdp(dev);
 
+                       /* if user-space did not require GRO, since adding XDP
+                        * enabled it, clear it now
+                        */
+                       if (!veth_gro_requested(dev)) {
+                               dev->features &= ~NETIF_F_GRO;
+                               netdev_features_change(dev);
+                       }
+
                        if (peer) {
                                peer->hw_features |= NETIF_F_GSO_SOFTWARE;
                                peer->max_mtu = ETH_MAX_MTU;
index b96f30d11644e24eb3886e5f2536d6eaad4d01db..dcc4810cb32472dbe8ee374091a2d58241af80c8 100644 (file)
@@ -618,7 +618,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt)
                                         &tbl_rev);
        if (!IS_ERR(wifi_pkg)) {
                if (tbl_rev != 2) {
-                       ret = PTR_ERR(wifi_pkg);
+                       ret = -EINVAL;
                        goto out_free;
                }
 
@@ -634,7 +634,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt)
                                         &tbl_rev);
        if (!IS_ERR(wifi_pkg)) {
                if (tbl_rev != 1) {
-                       ret = PTR_ERR(wifi_pkg);
+                       ret = -EINVAL;
                        goto out_free;
                }
 
@@ -650,7 +650,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt)
                                         &tbl_rev);
        if (!IS_ERR(wifi_pkg)) {
                if (tbl_rev != 0) {
-                       ret = PTR_ERR(wifi_pkg);
+                       ret = -EINVAL;
                        goto out_free;
                }
 
@@ -707,7 +707,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt)
                                         &tbl_rev);
        if (!IS_ERR(wifi_pkg)) {
                if (tbl_rev != 2) {
-                       ret = PTR_ERR(wifi_pkg);
+                       ret = -EINVAL;
                        goto out_free;
                }
 
@@ -723,7 +723,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt)
                                         &tbl_rev);
        if (!IS_ERR(wifi_pkg)) {
                if (tbl_rev != 1) {
-                       ret = PTR_ERR(wifi_pkg);
+                       ret = -EINVAL;
                        goto out_free;
                }
 
@@ -739,7 +739,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt)
                                         &tbl_rev);
        if (!IS_ERR(wifi_pkg)) {
                if (tbl_rev != 0) {
-                       ret = PTR_ERR(wifi_pkg);
+                       ret = -EINVAL;
                        goto out_free;
                }
 
@@ -1116,6 +1116,9 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
                goto read_table;
        }
 
+       ret = PTR_ERR(wifi_pkg);
+       goto out_free;
+
 read_table:
        fwrt->ppag_ver = tbl_rev;
        flags = &wifi_pkg->package.elements[1];
index 9c69d3674384609b8a7c376900e07a04441c24b0..e6c0f928a6bbf338ca240214635313c05c4e8751 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2005-2014, 2019-2021, 2023 Intel Corporation
+ * Copyright (C) 2005-2014, 2019-2021, 2023-2024 Intel Corporation
  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2016-2017 Intel Deutschland GmbH
  */
@@ -66,6 +66,16 @@ enum iwl_gen2_tx_fifo {
        IWL_GEN2_TRIG_TX_FIFO_VO,
 };
 
+enum iwl_bz_tx_fifo {
+       IWL_BZ_EDCA_TX_FIFO_BK,
+       IWL_BZ_EDCA_TX_FIFO_BE,
+       IWL_BZ_EDCA_TX_FIFO_VI,
+       IWL_BZ_EDCA_TX_FIFO_VO,
+       IWL_BZ_TRIG_TX_FIFO_BK,
+       IWL_BZ_TRIG_TX_FIFO_BE,
+       IWL_BZ_TRIG_TX_FIFO_VI,
+       IWL_BZ_TRIG_TX_FIFO_VO,
+};
 /**
  * enum iwl_tx_queue_cfg_actions - TXQ config options
  * @TX_QUEUE_CFG_ENABLE_QUEUE: enable a queue
index 4582afb149d720d077f30c0e7bb1814e5106d453..05b64176859e809986082c002f91eef247e83add 100644 (file)
@@ -1279,7 +1279,9 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
 
                mvm->net_detect = true;
        } else {
-               struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
+               struct iwl_wowlan_config_cmd wowlan_config_cmd = {
+                       .offloading_tid = 0,
+               };
 
                wowlan_config_cmd.sta_id = mvmvif->deflink.ap_sta_id;
 
@@ -1291,6 +1293,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
                        goto out_noreset;
                }
 
+               ret = iwl_mvm_sta_ensure_queue(
+                       mvm, ap_sta->txq[wowlan_config_cmd.offloading_tid]);
+               if (ret)
+                       goto out_noreset;
+
                ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
                                                vif, mvmvif, ap_sta);
                if (ret)
index c4f96125cf33af0eb066c3950e6dba18d505c4f4..25a5a31e63c2a33a0fc0bbe7317f65df62b9e8de 100644 (file)
@@ -31,6 +31,17 @@ const u8 iwl_mvm_ac_to_gen2_tx_fifo[] = {
        IWL_GEN2_TRIG_TX_FIFO_BK,
 };
 
+const u8 iwl_mvm_ac_to_bz_tx_fifo[] = {
+       IWL_BZ_EDCA_TX_FIFO_VO,
+       IWL_BZ_EDCA_TX_FIFO_VI,
+       IWL_BZ_EDCA_TX_FIFO_BE,
+       IWL_BZ_EDCA_TX_FIFO_BK,
+       IWL_BZ_TRIG_TX_FIFO_VO,
+       IWL_BZ_TRIG_TX_FIFO_VI,
+       IWL_BZ_TRIG_TX_FIFO_BE,
+       IWL_BZ_TRIG_TX_FIFO_BK,
+};
+
 struct iwl_mvm_mac_iface_iterator_data {
        struct iwl_mvm *mvm;
        struct ieee80211_vif *vif;
index 3447d67a8b311be1ceaf0b232e71c9121e38bd71..53e26c3c3a9af616ac057428503edf6270d53b3d 100644 (file)
@@ -3687,6 +3687,9 @@ iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm,
                                           NL80211_TDLS_SETUP);
        }
 
+       if (ret)
+               return ret;
+
        for_each_sta_active_link(vif, sta, link_sta, i)
                link_sta->agg.max_rc_amsdu_len = 1;
 
index 40627961b834a2ee860445b4557cf19498f4e166..81dbef6947f5578dd50e12f157124fa48fcdb728 100644 (file)
@@ -1581,12 +1581,16 @@ static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm,
 
 extern const u8 iwl_mvm_ac_to_tx_fifo[];
 extern const u8 iwl_mvm_ac_to_gen2_tx_fifo[];
+extern const u8 iwl_mvm_ac_to_bz_tx_fifo[];
 
 static inline u8 iwl_mvm_mac_ac_to_tx_fifo(struct iwl_mvm *mvm,
                                           enum ieee80211_ac_numbers ac)
 {
-       return iwl_mvm_has_new_tx_api(mvm) ?
-               iwl_mvm_ac_to_gen2_tx_fifo[ac] : iwl_mvm_ac_to_tx_fifo[ac];
+       if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
+               return iwl_mvm_ac_to_bz_tx_fifo[ac];
+       if (iwl_mvm_has_new_tx_api(mvm))
+               return iwl_mvm_ac_to_gen2_tx_fifo[ac];
+       return iwl_mvm_ac_to_tx_fifo[ac];
 }
 
 struct iwl_rate_info {
index 886d0009852872a5fc91a5f2f11476b3fdda78d8..af15d470c69bd60ea3737753b70832b9ffcf7d7f 100644 (file)
@@ -505,6 +505,10 @@ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue,
                return false;
 
        mvm_sta = iwl_mvm_sta_from_mac80211(sta);
+
+       if (WARN_ON_ONCE(!mvm_sta->dup_data))
+               return false;
+
        dup_data = &mvm_sta->dup_data[queue];
 
        /*
index 2a3ca97859749749fff954e097a9d62ae86f5d24..c2e0cff740e9281ee7f73a2a9db4d0add160fee1 100644 (file)
@@ -1502,6 +1502,34 @@ out_err:
        return ret;
 }
 
+int iwl_mvm_sta_ensure_queue(struct iwl_mvm *mvm,
+                            struct ieee80211_txq *txq)
+{
+       struct iwl_mvm_txq *mvmtxq = iwl_mvm_txq_from_mac80211(txq);
+       int ret = -EINVAL;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       if (likely(test_bit(IWL_MVM_TXQ_STATE_READY, &mvmtxq->state)) ||
+           !txq->sta) {
+               return 0;
+       }
+
+       if (!iwl_mvm_sta_alloc_queue(mvm, txq->sta, txq->ac, txq->tid)) {
+               set_bit(IWL_MVM_TXQ_STATE_READY, &mvmtxq->state);
+               ret = 0;
+       }
+
+       local_bh_disable();
+       spin_lock(&mvm->add_stream_lock);
+       if (!list_empty(&mvmtxq->list))
+               list_del_init(&mvmtxq->list);
+       spin_unlock(&mvm->add_stream_lock);
+       local_bh_enable();
+
+       return ret;
+}
+
 void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk)
 {
        struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm,
index b33a0ce096d46c2f92eb127d8942062b42f39345..3cf8a70274ce888833014b4492348c233be0a4c0 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2024 Intel Corporation
  * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
  * Copyright (C) 2015-2016 Intel Deutschland GmbH
  */
@@ -571,6 +571,7 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
                                       bool disable);
 
 void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_sta_ensure_queue(struct iwl_mvm *mvm, struct ieee80211_txq *txq);
 void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk);
 int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                         struct iwl_mvm_int_sta *sta, u8 *addr, u32 cipher,
index 218fdf1ed5304f333008c8015ae796ff59583db0..2e653a417d6269b333ec12e7d15f43f3c66be46b 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2024 Intel Corporation
  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2017 Intel Deutschland GmbH
  */
@@ -972,6 +972,7 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,
        if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) {
                /* End TE, notify mac80211 */
                mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID;
+               mvmvif->time_event_data.link_id = -1;
                iwl_mvm_p2p_roc_finished(mvm);
                ieee80211_remain_on_channel_expired(mvm->hw);
        } else if (le32_to_cpu(notif->start)) {
index db986bfc4dc3fe4374e22b071ecbf178fbb796dd..461f26d9214e4ab81e32033c00629b92f7e31700 100644 (file)
@@ -520,13 +520,24 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
        }
 }
 
+static void iwl_mvm_copy_hdr(void *cmd, const void *hdr, int hdrlen,
+                            const u8 *addr3_override)
+{
+       struct ieee80211_hdr *out_hdr = cmd;
+
+       memcpy(cmd, hdr, hdrlen);
+       if (addr3_override)
+               memcpy(out_hdr->addr3, addr3_override, ETH_ALEN);
+}
+
 /*
  * Allocates and sets the Tx cmd the driver data pointers in the skb
  */
 static struct iwl_device_tx_cmd *
 iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
                      struct ieee80211_tx_info *info, int hdrlen,
-                     struct ieee80211_sta *sta, u8 sta_id)
+                     struct ieee80211_sta *sta, u8 sta_id,
+                     const u8 *addr3_override)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct iwl_device_tx_cmd *dev_cmd;
@@ -584,7 +595,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
                        cmd->len = cpu_to_le16((u16)skb->len);
 
                        /* Copy MAC header from skb into command buffer */
-                       memcpy(cmd->hdr, hdr, hdrlen);
+                       iwl_mvm_copy_hdr(cmd->hdr, hdr, hdrlen, addr3_override);
 
                        cmd->flags = cpu_to_le16(flags);
                        cmd->rate_n_flags = cpu_to_le32(rate_n_flags);
@@ -599,7 +610,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
                        cmd->len = cpu_to_le16((u16)skb->len);
 
                        /* Copy MAC header from skb into command buffer */
-                       memcpy(cmd->hdr, hdr, hdrlen);
+                       iwl_mvm_copy_hdr(cmd->hdr, hdr, hdrlen, addr3_override);
 
                        cmd->flags = cpu_to_le32(flags);
                        cmd->rate_n_flags = cpu_to_le32(rate_n_flags);
@@ -617,7 +628,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
        iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control);
 
        /* Copy MAC header from skb into command buffer */
-       memcpy(tx_cmd->hdr, hdr, hdrlen);
+       iwl_mvm_copy_hdr(tx_cmd->hdr, hdr, hdrlen, addr3_override);
 
 out:
        return dev_cmd;
@@ -820,7 +831,8 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
 
        IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, queue);
 
-       dev_cmd = iwl_mvm_set_tx_params(mvm, skb, &info, hdrlen, NULL, sta_id);
+       dev_cmd = iwl_mvm_set_tx_params(mvm, skb, &info, hdrlen, NULL, sta_id,
+                                       NULL);
        if (!dev_cmd)
                return -1;
 
@@ -1140,7 +1152,8 @@ static int iwl_mvm_tx_pkt_queued(struct iwl_mvm *mvm,
  */
 static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
                           struct ieee80211_tx_info *info,
-                          struct ieee80211_sta *sta)
+                          struct ieee80211_sta *sta,
+                          const u8 *addr3_override)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct iwl_mvm_sta *mvmsta;
@@ -1172,7 +1185,8 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
                iwl_mvm_probe_resp_set_noa(mvm, skb);
 
        dev_cmd = iwl_mvm_set_tx_params(mvm, skb, info, hdrlen,
-                                       sta, mvmsta->deflink.sta_id);
+                                       sta, mvmsta->deflink.sta_id,
+                                       addr3_override);
        if (!dev_cmd)
                goto drop;
 
@@ -1294,9 +1308,11 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
        struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
        struct ieee80211_tx_info info;
        struct sk_buff_head mpdus_skbs;
+       struct ieee80211_vif *vif;
        unsigned int payload_len;
        int ret;
        struct sk_buff *orig_skb = skb;
+       const u8 *addr3;
 
        if (WARN_ON_ONCE(!mvmsta))
                return -1;
@@ -1307,26 +1323,59 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
        memcpy(&info, skb->cb, sizeof(info));
 
        if (!skb_is_gso(skb))
-               return iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
+               return iwl_mvm_tx_mpdu(mvm, skb, &info, sta, NULL);
 
        payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
                tcp_hdrlen(skb) + skb->data_len;
 
        if (payload_len <= skb_shinfo(skb)->gso_size)
-               return iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
+               return iwl_mvm_tx_mpdu(mvm, skb, &info, sta, NULL);
 
        __skb_queue_head_init(&mpdus_skbs);
 
+       vif = info.control.vif;
+       if (!vif)
+               return -1;
+
        ret = iwl_mvm_tx_tso(mvm, skb, &info, sta, &mpdus_skbs);
        if (ret)
                return ret;
 
        WARN_ON(skb_queue_empty(&mpdus_skbs));
 
+       /*
+        * As described in IEEE sta 802.11-2020, table 9-30 (Address
+        * field contents), A-MSDU address 3 should contain the BSSID
+        * address.
+        * Pass address 3 down to iwl_mvm_tx_mpdu() and further to set it
+        * in the command header. We need to preserve the original
+        * address 3 in the skb header to correctly create all the
+        * A-MSDU subframe headers from it.
+        */
+       switch (vif->type) {
+       case NL80211_IFTYPE_STATION:
+               addr3 = vif->cfg.ap_addr;
+               break;
+       case NL80211_IFTYPE_AP:
+               addr3 = vif->addr;
+               break;
+       default:
+               addr3 = NULL;
+               break;
+       }
+
        while (!skb_queue_empty(&mpdus_skbs)) {
+               struct ieee80211_hdr *hdr;
+               bool amsdu;
+
                skb = __skb_dequeue(&mpdus_skbs);
+               hdr = (void *)skb->data;
+               amsdu = ieee80211_is_data_qos(hdr->frame_control) &&
+                       (*ieee80211_get_qos_ctl(hdr) &
+                        IEEE80211_QOS_CTL_A_MSDU_PRESENT);
 
-               ret = iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
+               ret = iwl_mvm_tx_mpdu(mvm, skb, &info, sta,
+                                     amsdu ? addr3 : NULL);
                if (ret) {
                        /* Free skbs created as part of TSO logic that have not yet been dequeued */
                        __skb_queue_purge(&mpdus_skbs);
index fab361a250d6054e03a40e451efda2eb3678fda6..ef76850d9bcd232e84f00c4576c5a98ace51458f 100644 (file)
@@ -1778,5 +1778,6 @@ static void __exit netback_fini(void)
 }
 module_exit(netback_fini);
 
+MODULE_DESCRIPTION("Xen backend network device module");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_ALIAS("xen-backend:vif");
index bb3726b622ad9f0d9bdaeb23c91d7bff1b61d2cb..4d0c527e8576785fbff56eadf9cdf0412290f831 100644 (file)
@@ -1496,19 +1496,21 @@ static int btt_blk_init(struct btt *btt)
 {
        struct nd_btt *nd_btt = btt->nd_btt;
        struct nd_namespace_common *ndns = nd_btt->ndns;
-       int rc = -ENOMEM;
+       struct queue_limits lim = {
+               .logical_block_size     = btt->sector_size,
+               .max_hw_sectors         = UINT_MAX,
+       };
+       int rc;
 
-       btt->btt_disk = blk_alloc_disk(NUMA_NO_NODE);
-       if (!btt->btt_disk)
-               return -ENOMEM;
+       btt->btt_disk = blk_alloc_disk(&lim, NUMA_NO_NODE);
+       if (IS_ERR(btt->btt_disk))
+               return PTR_ERR(btt->btt_disk);
 
        nvdimm_namespace_disk_name(ndns, btt->btt_disk->disk_name);
        btt->btt_disk->first_minor = 0;
        btt->btt_disk->fops = &btt_fops;
        btt->btt_disk->private_data = btt;
 
-       blk_queue_logical_block_size(btt->btt_disk->queue, btt->sector_size);
-       blk_queue_max_hw_sectors(btt->btt_disk->queue, UINT_MAX);
        blk_queue_flag_set(QUEUE_FLAG_NONROT, btt->btt_disk->queue);
        blk_queue_flag_set(QUEUE_FLAG_SYNCHRONOUS, btt->btt_disk->queue);
 
index 4e8fdcb3f1c8276ea6e8b5992867cf976449925b..8dcc10b6db5b12c6994e2a6e1283be3eda73af29 100644 (file)
@@ -451,6 +451,11 @@ static int pmem_attach_disk(struct device *dev,
 {
        struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
        struct nd_region *nd_region = to_nd_region(dev->parent);
+       struct queue_limits lim = {
+               .logical_block_size     = pmem_sector_size(ndns),
+               .physical_block_size    = PAGE_SIZE,
+               .max_hw_sectors         = UINT_MAX,
+       };
        int nid = dev_to_node(dev), fua;
        struct resource *res = &nsio->res;
        struct range bb_range;
@@ -497,9 +502,9 @@ static int pmem_attach_disk(struct device *dev,
                return -EBUSY;
        }
 
-       disk = blk_alloc_disk(nid);
-       if (!disk)
-               return -ENOMEM;
+       disk = blk_alloc_disk(&lim, nid);
+       if (IS_ERR(disk))
+               return PTR_ERR(disk);
        q = disk->queue;
 
        pmem->disk = disk;
@@ -539,9 +544,6 @@ static int pmem_attach_disk(struct device *dev,
        pmem->virt_addr = addr;
 
        blk_queue_write_cache(q, true, fua);
-       blk_queue_physical_block_size(q, PAGE_SIZE);
-       blk_queue_logical_block_size(q, pmem_sector_size(ndns));
-       blk_queue_max_hw_sectors(q, UINT_MAX);
        blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
        blk_queue_flag_set(QUEUE_FLAG_SYNCHRONOUS, q);
        if (pmem->pfn_flags & PFN_MAP)
index c727cd1f264bf6221d2043d1f65bb70a51f00c1d..a480cdeac2883c0eb08dbfd32fc4c1adaece7a88 100644 (file)
@@ -1516,7 +1516,7 @@ static int apple_nvme_probe(struct platform_device *pdev)
                goto put_dev;
        }
 
-       anv->ctrl.admin_q = blk_mq_init_queue(&anv->admin_tagset);
+       anv->ctrl.admin_q = blk_mq_alloc_queue(&anv->admin_tagset, NULL, NULL);
        if (IS_ERR(anv->ctrl.admin_q)) {
                ret = -ENOMEM;
                goto put_dev;
index 60537c9224bf9341de0c01449f47e05032020e43..00864a63447099bca59fa45f8f6076933b58f836 100644 (file)
@@ -114,12 +114,21 @@ static DEFINE_MUTEX(nvme_subsystems_lock);
 
 static DEFINE_IDA(nvme_instance_ida);
 static dev_t nvme_ctrl_base_chr_devt;
-static struct class *nvme_class;
-static struct class *nvme_subsys_class;
+static int nvme_class_uevent(const struct device *dev, struct kobj_uevent_env *env);
+static const struct class nvme_class = {
+       .name = "nvme",
+       .dev_uevent = nvme_class_uevent,
+};
+
+static const struct class nvme_subsys_class = {
+       .name = "nvme-subsystem",
+};
 
 static DEFINE_IDA(nvme_ns_chr_minor_ida);
 static dev_t nvme_ns_chr_devt;
-static struct class *nvme_ns_chr_class;
+static const struct class nvme_ns_chr_class = {
+       .name = "nvme-generic",
+};
 
 static void nvme_put_subsystem(struct nvme_subsystem *subsys);
 static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl,
@@ -1153,6 +1162,10 @@ u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode)
                effects &= ~NVME_CMD_EFFECTS_CSE_MASK;
        } else {
                effects = le32_to_cpu(ctrl->effects->acs[opcode]);
+
+               /* Ignore execution restrictions if any relaxation bits are set */
+               if (effects & NVME_CMD_EFFECTS_CSER_MASK)
+                       effects &= ~NVME_CMD_EFFECTS_CSE_MASK;
        }
 
        return effects;
@@ -1394,8 +1407,10 @@ static int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id)
 
        error = nvme_submit_sync_cmd(dev->admin_q, &c, *id,
                        sizeof(struct nvme_id_ctrl));
-       if (error)
+       if (error) {
                kfree(*id);
+               *id = NULL;
+       }
        return error;
 }
 
@@ -1524,6 +1539,7 @@ int nvme_identify_ns(struct nvme_ctrl *ctrl, unsigned nsid,
        if (error) {
                dev_warn(ctrl->device, "Identify namespace failed (%d)\n", error);
                kfree(*id);
+               *id = NULL;
        }
        return error;
 }
@@ -1723,12 +1739,23 @@ int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
-#ifdef CONFIG_BLK_DEV_INTEGRITY
-static void nvme_init_integrity(struct gendisk *disk,
-               struct nvme_ns_head *head, u32 max_integrity_segments)
+static bool nvme_init_integrity(struct gendisk *disk, struct nvme_ns_head *head)
 {
        struct blk_integrity integrity = { };
 
+       blk_integrity_unregister(disk);
+
+       if (!head->ms)
+               return true;
+
+       /*
+        * PI can always be supported as we can ask the controller to simply
+        * insert/strip it, which is not possible for other kinds of metadata.
+        */
+       if (!IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) ||
+           !(head->features & NVME_NS_METADATA_SUPPORTED))
+               return nvme_ns_has_pi(head);
+
        switch (head->pi_type) {
        case NVME_NS_DPS_PI_TYPE3:
                switch (head->guard_type) {
@@ -1771,53 +1798,32 @@ static void nvme_init_integrity(struct gendisk *disk,
        }
 
        integrity.tuple_size = head->ms;
+       integrity.pi_offset = head->pi_offset;
        blk_integrity_register(disk, &integrity);
-       blk_queue_max_integrity_segments(disk->queue, max_integrity_segments);
-}
-#else
-static void nvme_init_integrity(struct gendisk *disk,
-               struct nvme_ns_head *head, u32 max_integrity_segments)
-{
+       return true;
 }
-#endif /* CONFIG_BLK_DEV_INTEGRITY */
 
-static void nvme_config_discard(struct nvme_ctrl *ctrl, struct gendisk *disk,
-               struct nvme_ns_head *head)
+static void nvme_config_discard(struct nvme_ns *ns, struct queue_limits *lim)
 {
-       struct request_queue *queue = disk->queue;
-       u32 max_discard_sectors;
-
-       if (ctrl->dmrsl && ctrl->dmrsl <= nvme_sect_to_lba(head, UINT_MAX)) {
-               max_discard_sectors = nvme_lba_to_sect(head, ctrl->dmrsl);
-       } else if (ctrl->oncs & NVME_CTRL_ONCS_DSM) {
-               max_discard_sectors = UINT_MAX;
-       } else {
-               blk_queue_max_discard_sectors(queue, 0);
-               return;
-       }
+       struct nvme_ctrl *ctrl = ns->ctrl;
 
        BUILD_BUG_ON(PAGE_SIZE / sizeof(struct nvme_dsm_range) <
                        NVME_DSM_MAX_RANGES);
 
-       /*
-        * If discard is already enabled, don't reset queue limits.
-        *
-        * This works around the fact that the block layer can't cope well with
-        * updating the hardware limits when overridden through sysfs.  This is
-        * harmless because discard limits in NVMe are purely advisory.
-        */
-       if (queue->limits.max_discard_sectors)
-               return;
+       if (ctrl->dmrsl && ctrl->dmrsl <= nvme_sect_to_lba(ns->head, UINT_MAX))
+               lim->max_hw_discard_sectors =
+                       nvme_lba_to_sect(ns->head, ctrl->dmrsl);
+       else if (ctrl->oncs & NVME_CTRL_ONCS_DSM)
+               lim->max_hw_discard_sectors = UINT_MAX;
+       else
+               lim->max_hw_discard_sectors = 0;
+
+       lim->discard_granularity = lim->logical_block_size;
 
-       blk_queue_max_discard_sectors(queue, max_discard_sectors);
        if (ctrl->dmrl)
-               blk_queue_max_discard_segments(queue, ctrl->dmrl);
+               lim->max_discard_segments = ctrl->dmrl;
        else
-               blk_queue_max_discard_segments(queue, NVME_DSM_MAX_RANGES);
-       queue->limits.discard_granularity = queue_logical_block_size(queue);
-
-       if (ctrl->quirks & NVME_QUIRK_DEALLOCATE_ZEROES)
-               blk_queue_max_write_zeroes_sectors(queue, UINT_MAX);
+               lim->max_discard_segments = NVME_DSM_MAX_RANGES;
 }
 
 static bool nvme_ns_ids_equal(struct nvme_ns_ids *a, struct nvme_ns_ids *b)
@@ -1828,42 +1834,38 @@ static bool nvme_ns_ids_equal(struct nvme_ns_ids *a, struct nvme_ns_ids *b)
                a->csi == b->csi;
 }
 
-static int nvme_init_ms(struct nvme_ctrl *ctrl, struct nvme_ns_head *head,
-               struct nvme_id_ns *id)
+static int nvme_identify_ns_nvm(struct nvme_ctrl *ctrl, unsigned int nsid,
+               struct nvme_id_ns_nvm **nvmp)
 {
-       bool first = id->dps & NVME_NS_DPS_PI_FIRST;
-       unsigned lbaf = nvme_lbaf_index(id->flbas);
-       struct nvme_command c = { };
+       struct nvme_command c = {
+               .identify.opcode        = nvme_admin_identify,
+               .identify.nsid          = cpu_to_le32(nsid),
+               .identify.cns           = NVME_ID_CNS_CS_NS,
+               .identify.csi           = NVME_CSI_NVM,
+       };
        struct nvme_id_ns_nvm *nvm;
-       int ret = 0;
-       u32 elbaf;
-
-       head->pi_size = 0;
-       head->ms = le16_to_cpu(id->lbaf[lbaf].ms);
-       if (!(ctrl->ctratt & NVME_CTRL_ATTR_ELBAS)) {
-               head->pi_size = sizeof(struct t10_pi_tuple);
-               head->guard_type = NVME_NVM_NS_16B_GUARD;
-               goto set_pi;
-       }
+       int ret;
 
        nvm = kzalloc(sizeof(*nvm), GFP_KERNEL);
        if (!nvm)
                return -ENOMEM;
 
-       c.identify.opcode = nvme_admin_identify;
-       c.identify.nsid = cpu_to_le32(head->ns_id);
-       c.identify.cns = NVME_ID_CNS_CS_NS;
-       c.identify.csi = NVME_CSI_NVM;
-
        ret = nvme_submit_sync_cmd(ctrl->admin_q, &c, nvm, sizeof(*nvm));
        if (ret)
-               goto free_data;
+               kfree(nvm);
+       else
+               *nvmp = nvm;
+       return ret;
+}
 
-       elbaf = le32_to_cpu(nvm->elbaf[lbaf]);
+static void nvme_configure_pi_elbas(struct nvme_ns_head *head,
+               struct nvme_id_ns *id, struct nvme_id_ns_nvm *nvm)
+{
+       u32 elbaf = le32_to_cpu(nvm->elbaf[nvme_lbaf_index(id->flbas)]);
 
        /* no support for storage tag formats right now */
        if (nvme_elbaf_sts(elbaf))
-               goto free_data;
+               return;
 
        head->guard_type = nvme_elbaf_guard_type(elbaf);
        switch (head->guard_type) {
@@ -1876,30 +1878,31 @@ static int nvme_init_ms(struct nvme_ctrl *ctrl, struct nvme_ns_head *head,
        default:
                break;
        }
-
-free_data:
-       kfree(nvm);
-set_pi:
-       if (head->pi_size && (first || head->ms == head->pi_size))
-               head->pi_type = id->dps & NVME_NS_DPS_PI_MASK;
-       else
-               head->pi_type = 0;
-
-       return ret;
 }
 
-static int nvme_configure_metadata(struct nvme_ctrl *ctrl,
-               struct nvme_ns_head *head, struct nvme_id_ns *id)
+static void nvme_configure_metadata(struct nvme_ctrl *ctrl,
+               struct nvme_ns_head *head, struct nvme_id_ns *id,
+               struct nvme_id_ns_nvm *nvm)
 {
-       int ret;
-
-       ret = nvme_init_ms(ctrl, head, id);
-       if (ret)
-               return ret;
-
        head->features &= ~(NVME_NS_METADATA_SUPPORTED | NVME_NS_EXT_LBAS);
+       head->pi_type = 0;
+       head->pi_size = 0;
+       head->pi_offset = 0;
+       head->ms = le16_to_cpu(id->lbaf[nvme_lbaf_index(id->flbas)].ms);
        if (!head->ms || !(ctrl->ops->flags & NVME_F_METADATA_SUPPORTED))
-               return 0;
+               return;
+
+       if (nvm && (ctrl->ctratt & NVME_CTRL_ATTR_ELBAS)) {
+               nvme_configure_pi_elbas(head, id, nvm);
+       } else {
+               head->pi_size = sizeof(struct t10_pi_tuple);
+               head->guard_type = NVME_NVM_NS_16B_GUARD;
+       }
+
+       if (head->pi_size && head->ms >= head->pi_size)
+               head->pi_type = id->dps & NVME_NS_DPS_PI_MASK;
+       if (!(id->dps & NVME_NS_DPS_PI_FIRST))
+               head->pi_offset = head->ms - head->pi_size;
 
        if (ctrl->ops->flags & NVME_F_FABRICS) {
                /*
@@ -1908,7 +1911,7 @@ static int nvme_configure_metadata(struct nvme_ctrl *ctrl,
                 * remap the separate metadata buffer from the block layer.
                 */
                if (WARN_ON_ONCE(!(id->flbas & NVME_NS_FLBAS_META_EXT)))
-                       return 0;
+                       return;
 
                head->features |= NVME_NS_EXT_LBAS;
 
@@ -1935,33 +1938,32 @@ static int nvme_configure_metadata(struct nvme_ctrl *ctrl,
                else
                        head->features |= NVME_NS_METADATA_SUPPORTED;
        }
-       return 0;
 }
 
-static void nvme_set_queue_limits(struct nvme_ctrl *ctrl,
-               struct request_queue *q)
+static u32 nvme_max_drv_segments(struct nvme_ctrl *ctrl)
 {
-       bool vwc = ctrl->vwc & NVME_CTRL_VWC_PRESENT;
-
-       if (ctrl->max_hw_sectors) {
-               u32 max_segments =
-                       (ctrl->max_hw_sectors / (NVME_CTRL_PAGE_SIZE >> 9)) + 1;
+       return ctrl->max_hw_sectors / (NVME_CTRL_PAGE_SIZE >> SECTOR_SHIFT) + 1;
+}
 
-               max_segments = min_not_zero(max_segments, ctrl->max_segments);
-               blk_queue_max_hw_sectors(q, ctrl->max_hw_sectors);
-               blk_queue_max_segments(q, min_t(u32, max_segments, USHRT_MAX));
-       }
-       blk_queue_virt_boundary(q, NVME_CTRL_PAGE_SIZE - 1);
-       blk_queue_dma_alignment(q, 3);
-       blk_queue_write_cache(q, vwc, vwc);
+static void nvme_set_ctrl_limits(struct nvme_ctrl *ctrl,
+               struct queue_limits *lim)
+{
+       lim->max_hw_sectors = ctrl->max_hw_sectors;
+       lim->max_segments = min_t(u32, USHRT_MAX,
+               min_not_zero(nvme_max_drv_segments(ctrl), ctrl->max_segments));
+       lim->max_integrity_segments = ctrl->max_integrity_segments;
+       lim->virt_boundary_mask = NVME_CTRL_PAGE_SIZE - 1;
+       lim->max_segment_size = UINT_MAX;
+       lim->dma_alignment = 3;
 }
 
-static void nvme_update_disk_info(struct nvme_ctrl *ctrl, struct gendisk *disk,
-               struct nvme_ns_head *head, struct nvme_id_ns *id)
+static bool nvme_update_disk_info(struct nvme_ns *ns, struct nvme_id_ns *id,
+               struct queue_limits *lim)
 {
-       sector_t capacity = nvme_lba_to_sect(head, le64_to_cpu(id->nsze));
+       struct nvme_ns_head *head = ns->head;
        u32 bs = 1U << head->lba_shift;
        u32 atomic_bs, phys_bs, io_opt = 0;
+       bool valid = true;
 
        /*
         * The block layer can't support LBA sizes larger than the page size
@@ -1969,12 +1971,10 @@ static void nvme_update_disk_info(struct nvme_ctrl *ctrl, struct gendisk *disk,
         * allow block I/O.
         */
        if (head->lba_shift > PAGE_SHIFT || head->lba_shift < SECTOR_SHIFT) {
-               capacity = 0;
                bs = (1 << 9);
+               valid = false;
        }
 
-       blk_integrity_unregister(disk);
-
        atomic_bs = phys_bs = bs;
        if (id->nabo == 0) {
                /*
@@ -1985,7 +1985,7 @@ static void nvme_update_disk_info(struct nvme_ctrl *ctrl, struct gendisk *disk,
                if (id->nsfeat & NVME_NS_FEAT_ATOMICS && id->nawupf)
                        atomic_bs = (1 + le16_to_cpu(id->nawupf)) * bs;
                else
-                       atomic_bs = (1 + ctrl->subsys->awupf) * bs;
+                       atomic_bs = (1 + ns->ctrl->subsys->awupf) * bs;
        }
 
        if (id->nsfeat & NVME_NS_FEAT_IO_OPT) {
@@ -1995,36 +1995,20 @@ static void nvme_update_disk_info(struct nvme_ctrl *ctrl, struct gendisk *disk,
                io_opt = bs * (1 + le16_to_cpu(id->nows));
        }
 
-       blk_queue_logical_block_size(disk->queue, bs);
        /*
         * Linux filesystems assume writing a single physical block is
         * an atomic operation. Hence limit the physical block size to the
         * value of the Atomic Write Unit Power Fail parameter.
         */
-       blk_queue_physical_block_size(disk->queue, min(phys_bs, atomic_bs));
-       blk_queue_io_min(disk->queue, phys_bs);
-       blk_queue_io_opt(disk->queue, io_opt);
-
-       /*
-        * Register a metadata profile for PI, or the plain non-integrity NVMe
-        * metadata masquerading as Type 0 if supported, otherwise reject block
-        * I/O to namespaces with metadata except when the namespace supports
-        * PI, as it can strip/insert in that case.
-        */
-       if (head->ms) {
-               if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) &&
-                   (head->features & NVME_NS_METADATA_SUPPORTED))
-                       nvme_init_integrity(disk, head,
-                                           ctrl->max_integrity_segments);
-               else if (!nvme_ns_has_pi(head))
-                       capacity = 0;
-       }
-
-       set_capacity_and_notify(disk, capacity);
-
-       nvme_config_discard(ctrl, disk, head);
-       blk_queue_max_write_zeroes_sectors(disk->queue,
-                                          ctrl->max_zeroes_sectors);
+       lim->logical_block_size = bs;
+       lim->physical_block_size = min(phys_bs, atomic_bs);
+       lim->io_min = phys_bs;
+       lim->io_opt = io_opt;
+       if (ns->ctrl->quirks & NVME_QUIRK_DEALLOCATE_ZEROES)
+               lim->max_write_zeroes_sectors = UINT_MAX;
+       else
+               lim->max_write_zeroes_sectors = ns->ctrl->max_zeroes_sectors;
+       return valid;
 }
 
 static bool nvme_ns_is_readonly(struct nvme_ns *ns, struct nvme_ns_info *info)
@@ -2038,7 +2022,8 @@ static inline bool nvme_first_scan(struct gendisk *disk)
        return !disk_live(disk);
 }
 
-static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id)
+static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id,
+               struct queue_limits *lim)
 {
        struct nvme_ctrl *ctrl = ns->ctrl;
        u32 iob;
@@ -2066,38 +2051,36 @@ static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id)
                return;
        }
 
-       blk_queue_chunk_sectors(ns->queue, iob);
+       lim->chunk_sectors = iob;
 }
 
 static int nvme_update_ns_info_generic(struct nvme_ns *ns,
                struct nvme_ns_info *info)
 {
+       struct queue_limits lim;
+       int ret;
+
        blk_mq_freeze_queue(ns->disk->queue);
-       nvme_set_queue_limits(ns->ctrl, ns->queue);
+       lim = queue_limits_start_update(ns->disk->queue);
+       nvme_set_ctrl_limits(ns->ctrl, &lim);
+       ret = queue_limits_commit_update(ns->disk->queue, &lim);
        set_disk_ro(ns->disk, nvme_ns_is_readonly(ns, info));
        blk_mq_unfreeze_queue(ns->disk->queue);
 
-       if (nvme_ns_head_multipath(ns->head)) {
-               blk_mq_freeze_queue(ns->head->disk->queue);
-               set_disk_ro(ns->head->disk, nvme_ns_is_readonly(ns, info));
-               nvme_mpath_revalidate_paths(ns);
-               blk_stack_limits(&ns->head->disk->queue->limits,
-                                &ns->queue->limits, 0);
-               ns->head->disk->flags |= GENHD_FL_HIDDEN;
-               blk_mq_unfreeze_queue(ns->head->disk->queue);
-       }
-
        /* Hide the block-interface for these devices */
-       ns->disk->flags |= GENHD_FL_HIDDEN;
-       set_bit(NVME_NS_READY, &ns->flags);
-
-       return 0;
+       if (!ret)
+               ret = -ENODEV;
+       return ret;
 }
 
 static int nvme_update_ns_info_block(struct nvme_ns *ns,
                struct nvme_ns_info *info)
 {
+       bool vwc = ns->ctrl->vwc & NVME_CTRL_VWC_PRESENT;
+       struct queue_limits lim;
+       struct nvme_id_ns_nvm *nvm = NULL;
        struct nvme_id_ns *id;
+       sector_t capacity;
        unsigned lbaf;
        int ret;
 
@@ -2109,30 +2092,52 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
                /* namespace not allocated or attached */
                info->is_removed = true;
                ret = -ENODEV;
-               goto error;
+               goto out;
+       }
+
+       if (ns->ctrl->ctratt & NVME_CTRL_ATTR_ELBAS) {
+               ret = nvme_identify_ns_nvm(ns->ctrl, info->nsid, &nvm);
+               if (ret < 0)
+                       goto out;
        }
 
        blk_mq_freeze_queue(ns->disk->queue);
        lbaf = nvme_lbaf_index(id->flbas);
        ns->head->lba_shift = id->lbaf[lbaf].ds;
        ns->head->nuse = le64_to_cpu(id->nuse);
-       nvme_set_queue_limits(ns->ctrl, ns->queue);
-
-       ret = nvme_configure_metadata(ns->ctrl, ns->head, id);
-       if (ret < 0) {
-               blk_mq_unfreeze_queue(ns->disk->queue);
-               goto out;
-       }
-       nvme_set_chunk_sectors(ns, id);
-       nvme_update_disk_info(ns->ctrl, ns->disk, ns->head, id);
+       capacity = nvme_lba_to_sect(ns->head, le64_to_cpu(id->nsze));
 
-       if (ns->head->ids.csi == NVME_CSI_ZNS) {
-               ret = nvme_update_zone_info(ns, lbaf);
+       lim = queue_limits_start_update(ns->disk->queue);
+       nvme_set_ctrl_limits(ns->ctrl, &lim);
+       nvme_configure_metadata(ns->ctrl, ns->head, id, nvm);
+       nvme_set_chunk_sectors(ns, id, &lim);
+       if (!nvme_update_disk_info(ns, id, &lim))
+               capacity = 0;
+       nvme_config_discard(ns, &lim);
+       if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
+           ns->head->ids.csi == NVME_CSI_ZNS) {
+               ret = nvme_update_zone_info(ns, lbaf, &lim);
                if (ret) {
                        blk_mq_unfreeze_queue(ns->disk->queue);
                        goto out;
                }
        }
+       ret = queue_limits_commit_update(ns->disk->queue, &lim);
+       if (ret) {
+               blk_mq_unfreeze_queue(ns->disk->queue);
+               goto out;
+       }
+
+       /*
+        * Register a metadata profile for PI, or the plain non-integrity NVMe
+        * metadata masquerading as Type 0 if supported, otherwise reject block
+        * I/O to namespaces with metadata except when the namespace supports
+        * PI, as it can strip/insert in that case.
+        */
+       if (!nvme_init_integrity(ns->disk, ns->head))
+               capacity = 0;
+
+       set_capacity_and_notify(ns->disk, capacity);
 
        /*
         * Only set the DEAC bit if the device guarantees that reads from
@@ -2143,62 +2148,81 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
        if ((id->dlfeat & 0x7) == 0x1 && (id->dlfeat & (1 << 3)))
                ns->head->features |= NVME_NS_DEAC;
        set_disk_ro(ns->disk, nvme_ns_is_readonly(ns, info));
+       blk_queue_write_cache(ns->disk->queue, vwc, vwc);
        set_bit(NVME_NS_READY, &ns->flags);
        blk_mq_unfreeze_queue(ns->disk->queue);
 
        if (blk_queue_is_zoned(ns->queue)) {
-               ret = nvme_revalidate_zones(ns);
+               ret = blk_revalidate_disk_zones(ns->disk, NULL);
                if (ret && !nvme_first_scan(ns->disk))
                        goto out;
        }
 
-       if (nvme_ns_head_multipath(ns->head)) {
-               blk_mq_freeze_queue(ns->head->disk->queue);
-               nvme_update_disk_info(ns->ctrl, ns->head->disk, ns->head, id);
-               set_disk_ro(ns->head->disk, nvme_ns_is_readonly(ns, info));
-               nvme_mpath_revalidate_paths(ns);
-               blk_stack_limits(&ns->head->disk->queue->limits,
-                                &ns->queue->limits, 0);
-               disk_update_readahead(ns->head->disk);
-               blk_mq_unfreeze_queue(ns->head->disk->queue);
-       }
-
        ret = 0;
 out:
-       /*
-        * If probing fails due an unsupported feature, hide the block device,
-        * but still allow other access.
-        */
-       if (ret == -ENODEV) {
-               ns->disk->flags |= GENHD_FL_HIDDEN;
-               set_bit(NVME_NS_READY, &ns->flags);
-               ret = 0;
-       }
-
-error:
+       kfree(nvm);
        kfree(id);
        return ret;
 }
 
 static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info)
 {
+       bool unsupported = false;
+       int ret;
+
        switch (info->ids.csi) {
        case NVME_CSI_ZNS:
                if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
                        dev_info(ns->ctrl->device,
        "block device for nsid %u not supported without CONFIG_BLK_DEV_ZONED\n",
                                info->nsid);
-                       return nvme_update_ns_info_generic(ns, info);
+                       ret = nvme_update_ns_info_generic(ns, info);
+                       break;
                }
-               return nvme_update_ns_info_block(ns, info);
+               ret = nvme_update_ns_info_block(ns, info);
+               break;
        case NVME_CSI_NVM:
-               return nvme_update_ns_info_block(ns, info);
+               ret = nvme_update_ns_info_block(ns, info);
+               break;
        default:
                dev_info(ns->ctrl->device,
                        "block device for nsid %u not supported (csi %u)\n",
                        info->nsid, info->ids.csi);
-               return nvme_update_ns_info_generic(ns, info);
+               ret = nvme_update_ns_info_generic(ns, info);
+               break;
+       }
+
+       /*
+        * If probing fails due an unsupported feature, hide the block device,
+        * but still allow other access.
+        */
+       if (ret == -ENODEV) {
+               ns->disk->flags |= GENHD_FL_HIDDEN;
+               set_bit(NVME_NS_READY, &ns->flags);
+               unsupported = true;
+               ret = 0;
        }
+
+       if (!ret && nvme_ns_head_multipath(ns->head)) {
+               struct queue_limits lim;
+
+               blk_mq_freeze_queue(ns->head->disk->queue);
+               if (unsupported)
+                       ns->head->disk->flags |= GENHD_FL_HIDDEN;
+               else
+                       nvme_init_integrity(ns->head->disk, ns->head);
+               set_capacity_and_notify(ns->head->disk, get_capacity(ns->disk));
+               set_disk_ro(ns->head->disk, nvme_ns_is_readonly(ns, info));
+               nvme_mpath_revalidate_paths(ns);
+
+               lim = queue_limits_start_update(ns->head->disk->queue);
+               queue_limits_stack_bdev(&lim, ns->disk->part0, 0,
+                                       ns->head->disk->disk_name);
+               ret = queue_limits_commit_update(ns->head->disk->queue, &lim);
+               blk_mq_unfreeze_queue(ns->head->disk->queue);
+       }
+
+       return ret;
 }
 
 #ifdef CONFIG_BLK_SED_OPAL
@@ -2873,7 +2897,7 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
        subsys->awupf = le16_to_cpu(id->awupf);
        nvme_mpath_default_iopolicy(subsys);
 
-       subsys->dev.class = nvme_subsys_class;
+       subsys->dev.class = &nvme_subsys_class;
        subsys->dev.release = nvme_release_subsystem;
        subsys->dev.groups = nvme_subsys_attrs_groups;
        dev_set_name(&subsys->dev, "nvme-subsys%d", ctrl->instance);
@@ -3113,11 +3137,17 @@ static int nvme_check_ctrl_fabric_info(struct nvme_ctrl *ctrl, struct nvme_id_ct
                return -EINVAL;
        }
 
+       if (!ctrl->maxcmd) {
+               dev_err(ctrl->device, "Maximum outstanding commands is 0\n");
+               return -EINVAL;
+       }
+
        return 0;
 }
 
 static int nvme_init_identify(struct nvme_ctrl *ctrl)
 {
+       struct queue_limits lim;
        struct nvme_id_ctrl *id;
        u32 max_hw_sectors;
        bool prev_apst_enabled;
@@ -3184,7 +3214,12 @@ static int nvme_init_identify(struct nvme_ctrl *ctrl)
        ctrl->max_hw_sectors =
                min_not_zero(ctrl->max_hw_sectors, max_hw_sectors);
 
-       nvme_set_queue_limits(ctrl, ctrl->admin_q);
+       lim = queue_limits_start_update(ctrl->admin_q);
+       nvme_set_ctrl_limits(ctrl, &lim);
+       ret = queue_limits_commit_update(ctrl->admin_q, &lim);
+       if (ret)
+               goto out_free;
+
        ctrl->sgls = le32_to_cpu(id->sgls);
        ctrl->kas = le16_to_cpu(id->kas);
        ctrl->max_namespaces = le32_to_cpu(id->mnan);
@@ -3416,7 +3451,7 @@ int nvme_cdev_add(struct cdev *cdev, struct device *cdev_device,
        if (minor < 0)
                return minor;
        cdev_device->devt = MKDEV(MAJOR(nvme_ns_chr_devt), minor);
-       cdev_device->class = nvme_ns_chr_class;
+       cdev_device->class = &nvme_ns_chr_class;
        cdev_device->release = nvme_cdev_rel;
        device_initialize(cdev_device);
        cdev_init(cdev, fops);
@@ -3688,7 +3723,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, struct nvme_ns_info *info)
        if (!ns)
                return;
 
-       disk = blk_mq_alloc_disk(ctrl->tagset, ns);
+       disk = blk_mq_alloc_disk(ctrl->tagset, NULL, ns);
        if (IS_ERR(disk))
                goto out_free_ns;
        disk->fops = &nvme_bdev_ops;
@@ -4349,6 +4384,7 @@ EXPORT_SYMBOL_GPL(nvme_complete_async_event);
 int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
                const struct blk_mq_ops *ops, unsigned int cmd_size)
 {
+       struct queue_limits lim = {};
        int ret;
 
        memset(set, 0, sizeof(*set));
@@ -4368,14 +4404,14 @@ int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
        if (ret)
                return ret;
 
-       ctrl->admin_q = blk_mq_init_queue(set);
+       ctrl->admin_q = blk_mq_alloc_queue(set, &lim, NULL);
        if (IS_ERR(ctrl->admin_q)) {
                ret = PTR_ERR(ctrl->admin_q);
                goto out_free_tagset;
        }
 
        if (ctrl->ops->flags & NVME_F_FABRICS) {
-               ctrl->fabrics_q = blk_mq_init_queue(set);
+               ctrl->fabrics_q = blk_mq_alloc_queue(set, NULL, NULL);
                if (IS_ERR(ctrl->fabrics_q)) {
                        ret = PTR_ERR(ctrl->fabrics_q);
                        goto out_cleanup_admin_q;
@@ -4439,7 +4475,7 @@ int nvme_alloc_io_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
                return ret;
 
        if (ctrl->ops->flags & NVME_F_FABRICS) {
-               ctrl->connect_q = blk_mq_init_queue(set);
+               ctrl->connect_q = blk_mq_alloc_queue(set, NULL, NULL);
                if (IS_ERR(ctrl->connect_q)) {
                        ret = PTR_ERR(ctrl->connect_q);
                        goto out_free_tag_set;
@@ -4609,7 +4645,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
        ctrl->device = &ctrl->ctrl_device;
        ctrl->device->devt = MKDEV(MAJOR(nvme_ctrl_base_chr_devt),
                        ctrl->instance);
-       ctrl->device->class = nvme_class;
+       ctrl->device->class = &nvme_class;
        ctrl->device->parent = ctrl->dev;
        if (ops->dev_attr_groups)
                ctrl->device->groups = ops->dev_attr_groups;
@@ -4842,42 +4878,36 @@ static int __init nvme_core_init(void)
        if (result < 0)
                goto destroy_delete_wq;
 
-       nvme_class = class_create("nvme");
-       if (IS_ERR(nvme_class)) {
-               result = PTR_ERR(nvme_class);
+       result = class_register(&nvme_class);
+       if (result)
                goto unregister_chrdev;
-       }
-       nvme_class->dev_uevent = nvme_class_uevent;
 
-       nvme_subsys_class = class_create("nvme-subsystem");
-       if (IS_ERR(nvme_subsys_class)) {
-               result = PTR_ERR(nvme_subsys_class);
+       result = class_register(&nvme_subsys_class);
+       if (result)
                goto destroy_class;
-       }
 
        result = alloc_chrdev_region(&nvme_ns_chr_devt, 0, NVME_MINORS,
                                     "nvme-generic");
        if (result < 0)
                goto destroy_subsys_class;
 
-       nvme_ns_chr_class = class_create("nvme-generic");
-       if (IS_ERR(nvme_ns_chr_class)) {
-               result = PTR_ERR(nvme_ns_chr_class);
+       result = class_register(&nvme_ns_chr_class);
+       if (result)
                goto unregister_generic_ns;
-       }
+
        result = nvme_init_auth();
        if (result)
                goto destroy_ns_chr;
        return 0;
 
 destroy_ns_chr:
-       class_destroy(nvme_ns_chr_class);
+       class_unregister(&nvme_ns_chr_class);
 unregister_generic_ns:
        unregister_chrdev_region(nvme_ns_chr_devt, NVME_MINORS);
 destroy_subsys_class:
-       class_destroy(nvme_subsys_class);
+       class_unregister(&nvme_subsys_class);
 destroy_class:
-       class_destroy(nvme_class);
+       class_unregister(&nvme_class);
 unregister_chrdev:
        unregister_chrdev_region(nvme_ctrl_base_chr_devt, NVME_MINORS);
 destroy_delete_wq:
@@ -4893,9 +4923,9 @@ out:
 static void __exit nvme_core_exit(void)
 {
        nvme_exit_auth();
-       class_destroy(nvme_ns_chr_class);
-       class_destroy(nvme_subsys_class);
-       class_destroy(nvme_class);
+       class_unregister(&nvme_ns_chr_class);
+       class_unregister(&nvme_subsys_class);
+       class_unregister(&nvme_class);
        unregister_chrdev_region(nvme_ns_chr_devt, NVME_MINORS);
        unregister_chrdev_region(nvme_ctrl_base_chr_devt, NVME_MINORS);
        destroy_workqueue(nvme_delete_wq);
index 3499acbf6a822fc1a45d93894f4870a9a5f7857c..1f0ea1f32d22f5badee3af7b7827172c31c9ecf7 100644 (file)
@@ -534,6 +534,7 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid)
        if (ret) {
                nvmf_log_connect_error(ctrl, ret, le32_to_cpu(res.u32),
                                       &cmd, data);
+               goto out_free_data;
        }
        result = le32_to_cpu(res.u32);
        if (result & (NVME_CONNECT_AUTHREQ_ATR | NVME_CONNECT_AUTHREQ_ASCR)) {
@@ -637,7 +638,7 @@ static struct key *nvmf_parse_key(int key_id)
        }
 
        key = key_lookup(key_id);
-       if (!IS_ERR(key))
+       if (IS_ERR(key))
                pr_err("key id %08x not found\n", key_id);
        else
                pr_debug("Using key id %08x\n", key_id);
@@ -1318,7 +1319,10 @@ out_free_opts:
        return ERR_PTR(ret);
 }
 
-static struct class *nvmf_class;
+static const struct class nvmf_class = {
+       .name = "nvme-fabrics",
+};
+
 static struct device *nvmf_device;
 static DEFINE_MUTEX(nvmf_dev_mutex);
 
@@ -1438,15 +1442,14 @@ static int __init nvmf_init(void)
        if (!nvmf_default_host)
                return -ENOMEM;
 
-       nvmf_class = class_create("nvme-fabrics");
-       if (IS_ERR(nvmf_class)) {
+       ret = class_register(&nvmf_class);
+       if (ret) {
                pr_err("couldn't register class nvme-fabrics\n");
-               ret = PTR_ERR(nvmf_class);
                goto out_free_host;
        }
 
        nvmf_device =
-               device_create(nvmf_class, NULL, MKDEV(0, 0), NULL, "ctl");
+               device_create(&nvmf_class, NULL, MKDEV(0, 0), NULL, "ctl");
        if (IS_ERR(nvmf_device)) {
                pr_err("couldn't create nvme-fabrics device!\n");
                ret = PTR_ERR(nvmf_device);
@@ -1462,9 +1465,9 @@ static int __init nvmf_init(void)
        return 0;
 
 out_destroy_device:
-       device_destroy(nvmf_class, MKDEV(0, 0));
+       device_destroy(&nvmf_class, MKDEV(0, 0));
 out_destroy_class:
-       class_destroy(nvmf_class);
+       class_unregister(&nvmf_class);
 out_free_host:
        nvmf_host_put(nvmf_default_host);
        return ret;
@@ -1473,8 +1476,8 @@ out_free_host:
 static void __exit nvmf_exit(void)
 {
        misc_deregister(&nvmf_misc);
-       device_destroy(nvmf_class, MKDEV(0, 0));
-       class_destroy(nvmf_class);
+       device_destroy(&nvmf_class, MKDEV(0, 0));
+       class_unregister(&nvmf_class);
        nvmf_host_put(nvmf_default_host);
 
        BUILD_BUG_ON(sizeof(struct nvmf_common_command) != 64);
index 74de1e64aeead77c604ec31e30bac179a0de245b..5397fb428b242cea36f8c36997e134f6463e9f39 100644 (file)
@@ -516,6 +516,7 @@ static void nvme_requeue_work(struct work_struct *work)
 
 int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
 {
+       struct queue_limits lim;
        bool vwc = false;
 
        mutex_init(&head->lock);
@@ -532,9 +533,14 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
            !nvme_is_unique_nsid(ctrl, head) || !multipath)
                return 0;
 
-       head->disk = blk_alloc_disk(ctrl->numa_node);
-       if (!head->disk)
-               return -ENOMEM;
+       blk_set_stacking_limits(&lim);
+       lim.dma_alignment = 3;
+       if (head->ids.csi != NVME_CSI_ZNS)
+               lim.max_zone_append_sectors = 0;
+
+       head->disk = blk_alloc_disk(&lim, ctrl->numa_node);
+       if (IS_ERR(head->disk))
+               return PTR_ERR(head->disk);
        head->disk->fops = &nvme_ns_head_ops;
        head->disk->private_data = head;
        sprintf(head->disk->disk_name, "nvme%dn%d",
@@ -553,11 +559,6 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
            ctrl->tagset->map[HCTX_TYPE_POLL].nr_queues)
                blk_queue_flag_set(QUEUE_FLAG_POLL, head->disk->queue);
 
-       /* set to a default value of 512 until the disk is validated */
-       blk_queue_logical_block_size(head->disk->queue, 512);
-       blk_set_stacking_limits(&head->disk->queue->limits);
-       blk_queue_dma_alignment(head->disk->queue, 3);
-
        /* we need to propagate up the VMC settings */
        if (ctrl->vwc & NVME_CTRL_VWC_PRESENT)
                vwc = true;
index 7b87763e2f8a69f5edef68e2e657ed417e911cb8..24193fcb8bd584de277606d57738c1aea5a9cb49 100644 (file)
@@ -464,6 +464,7 @@ struct nvme_ns_head {
        u16                     ms;
        u16                     pi_size;
        u8                      pi_type;
+       u8                      pi_offset;
        u8                      guard_type;
        u16                     sgs;
        u32                     sws;
@@ -1035,11 +1036,11 @@ static inline bool nvme_disk_is_ns_head(struct gendisk *disk)
 }
 #endif /* CONFIG_NVME_MULTIPATH */
 
-int nvme_revalidate_zones(struct nvme_ns *ns);
 int nvme_ns_report_zones(struct nvme_ns *ns, sector_t sector,
                unsigned int nr_zones, report_zones_cb cb, void *data);
+int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf,
+               struct queue_limits *lim);
 #ifdef CONFIG_BLK_DEV_ZONED
-int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf);
 blk_status_t nvme_setup_zone_mgmt_send(struct nvme_ns *ns, struct request *req,
                                       struct nvme_command *cmnd,
                                       enum nvme_zone_mgmt_action action);
@@ -1050,13 +1051,6 @@ static inline blk_status_t nvme_setup_zone_mgmt_send(struct nvme_ns *ns,
 {
        return BLK_STS_NOTSUPP;
 }
-
-static inline int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf)
-{
-       dev_warn(ns->ctrl->device,
-                "Please enable CONFIG_BLK_DEV_ZONED to support ZNS devices\n");
-       return -EPROTONOSUPPORT;
-}
 #endif
 
 static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
index 20fdd40b1879f5796ab768acade2096eefde9e93..366f0bb4ebfc1d9757aad5bdce2287785142403a 100644 (file)
@@ -1006,6 +1006,7 @@ static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new)
 {
        int ret;
        bool changed;
+       u16 max_queue_size;
 
        ret = nvme_rdma_configure_admin_queue(ctrl, new);
        if (ret)
@@ -1030,11 +1031,16 @@ static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new)
                        ctrl->ctrl.opts->queue_size, ctrl->ctrl.sqsize + 1);
        }
 
-       if (ctrl->ctrl.sqsize + 1 > NVME_RDMA_MAX_QUEUE_SIZE) {
+       if (ctrl->ctrl.max_integrity_segments)
+               max_queue_size = NVME_RDMA_MAX_METADATA_QUEUE_SIZE;
+       else
+               max_queue_size = NVME_RDMA_MAX_QUEUE_SIZE;
+
+       if (ctrl->ctrl.sqsize + 1 > max_queue_size) {
                dev_warn(ctrl->ctrl.device,
-                       "ctrl sqsize %u > max queue size %u, clamping down\n",
-                       ctrl->ctrl.sqsize + 1, NVME_RDMA_MAX_QUEUE_SIZE);
-               ctrl->ctrl.sqsize = NVME_RDMA_MAX_QUEUE_SIZE - 1;
+                        "ctrl sqsize %u > max queue size %u, clamping down\n",
+                        ctrl->ctrl.sqsize + 1, max_queue_size);
+               ctrl->ctrl.sqsize = max_queue_size - 1;
        }
 
        if (ctrl->ctrl.sqsize + 1 > ctrl->ctrl.maxcmd) {
index f2832f70e7e0a861070d066bf1ee71c19fbf5ae2..09fcaa519e5bc26618eae900a0830a89e6aebbb5 100644 (file)
@@ -221,14 +221,11 @@ static int ns_update_nuse(struct nvme_ns *ns)
 
        ret = nvme_identify_ns(ns->ctrl, ns->head->ns_id, &id);
        if (ret)
-               goto out_free_id;
+               return ret;
 
        ns->head->nuse = le64_to_cpu(id->nuse);
-
-out_free_id:
        kfree(id);
-
-       return ret;
+       return 0;
 }
 
 static ssize_t nuse_show(struct device *dev, struct device_attribute *attr,
index 499bbb0eee8d09b9dc12c09337ba796d1832339b..722384bcc765cda778972c8a86345eaaf18a7353 100644 (file)
@@ -7,16 +7,6 @@
 #include <linux/vmalloc.h>
 #include "nvme.h"
 
-int nvme_revalidate_zones(struct nvme_ns *ns)
-{
-       struct request_queue *q = ns->queue;
-
-       blk_queue_chunk_sectors(q, ns->head->zsze);
-       blk_queue_max_zone_append_sectors(q, ns->ctrl->max_zone_append);
-
-       return blk_revalidate_disk_zones(ns->disk, NULL);
-}
-
 static int nvme_set_max_append(struct nvme_ctrl *ctrl)
 {
        struct nvme_command c = { };
@@ -45,10 +35,10 @@ static int nvme_set_max_append(struct nvme_ctrl *ctrl)
        return 0;
 }
 
-int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf)
+int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf,
+               struct queue_limits *lim)
 {
        struct nvme_effects_log *log = ns->head->effects;
-       struct request_queue *q = ns->queue;
        struct nvme_command c = { };
        struct nvme_id_ns_zns *id;
        int status;
@@ -109,10 +99,12 @@ int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf)
                goto free_data;
        }
 
-       disk_set_zoned(ns->disk);
-       blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
-       disk_set_max_open_zones(ns->disk, le32_to_cpu(id->mor) + 1);
-       disk_set_max_active_zones(ns->disk, le32_to_cpu(id->mar) + 1);
+       blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, ns->queue);
+       lim->zoned = 1;
+       lim->max_open_zones = le32_to_cpu(id->mor) + 1;
+       lim->max_active_zones = le32_to_cpu(id->mar) + 1;
+       lim->chunk_sectors = ns->head->zsze;
+       lim->max_zone_append_sectors = ns->ctrl->max_zone_append;
 free_data:
        kfree(id);
        return status;
index 39cb570f833dde9ec57ed406547ffbbf705e546f..f5b7054a4a05e38f25c0a3a0a831458138bebcca 100644 (file)
@@ -428,7 +428,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
        id->cqes = (0x4 << 4) | 0x4;
 
        /* no enforcement soft-limit for maxcmd - pick arbitrary high value */
-       id->maxcmd = cpu_to_le16(NVMET_MAX_CMD);
+       id->maxcmd = cpu_to_le16(NVMET_MAX_CMD(ctrl));
 
        id->nn = cpu_to_le32(NVMET_MAX_NAMESPACES);
        id->mnan = cpu_to_le32(NVMET_MAX_NAMESPACES);
index 2482a0db25043c88f2cb3fa3fd0bda3adf8abbbf..77a6e817b31596998e4424aa8205f8cfd9219f1d 100644 (file)
@@ -273,6 +273,32 @@ static ssize_t nvmet_param_inline_data_size_store(struct config_item *item,
 
 CONFIGFS_ATTR(nvmet_, param_inline_data_size);
 
+static ssize_t nvmet_param_max_queue_size_show(struct config_item *item,
+               char *page)
+{
+       struct nvmet_port *port = to_nvmet_port(item);
+
+       return snprintf(page, PAGE_SIZE, "%d\n", port->max_queue_size);
+}
+
+static ssize_t nvmet_param_max_queue_size_store(struct config_item *item,
+               const char *page, size_t count)
+{
+       struct nvmet_port *port = to_nvmet_port(item);
+       int ret;
+
+       if (nvmet_is_port_enabled(port, __func__))
+               return -EACCES;
+       ret = kstrtoint(page, 0, &port->max_queue_size);
+       if (ret) {
+               pr_err("Invalid value '%s' for max_queue_size\n", page);
+               return -EINVAL;
+       }
+       return count;
+}
+
+CONFIGFS_ATTR(nvmet_, param_max_queue_size);
+
 #ifdef CONFIG_BLK_DEV_INTEGRITY
 static ssize_t nvmet_param_pi_enable_show(struct config_item *item,
                char *page)
@@ -1859,6 +1885,7 @@ static struct configfs_attribute *nvmet_port_attrs[] = {
        &nvmet_attr_addr_trtype,
        &nvmet_attr_addr_tsas,
        &nvmet_attr_param_inline_data_size,
+       &nvmet_attr_param_max_queue_size,
 #ifdef CONFIG_BLK_DEV_INTEGRITY
        &nvmet_attr_param_pi_enable,
 #endif
@@ -1917,6 +1944,7 @@ static struct config_group *nvmet_ports_make(struct config_group *group,
        INIT_LIST_HEAD(&port->subsystems);
        INIT_LIST_HEAD(&port->referrals);
        port->inline_data_size = -1;    /* < 0 == let the transport choose */
+       port->max_queue_size = -1;      /* < 0 == let the transport choose */
 
        port->disc_addr.portid = cpu_to_le16(portid);
        port->disc_addr.adrfam = NVMF_ADDR_FAMILY_MAX;
index 8658e9c08534df50c466314c6c70d18d79525324..6bbe4df0166ca56949a5f5b14ad90f68305d6f36 100644 (file)
@@ -358,6 +358,18 @@ int nvmet_enable_port(struct nvmet_port *port)
        if (port->inline_data_size < 0)
                port->inline_data_size = 0;
 
+       /*
+        * If the transport didn't set the max_queue_size properly, then clamp
+        * it to the target limits. Also set default values in case the
+        * transport didn't set it at all.
+        */
+       if (port->max_queue_size < 0)
+               port->max_queue_size = NVMET_MAX_QUEUE_SIZE;
+       else
+               port->max_queue_size = clamp_t(int, port->max_queue_size,
+                                              NVMET_MIN_QUEUE_SIZE,
+                                              NVMET_MAX_QUEUE_SIZE);
+
        port->enabled = true;
        port->tr_ops = ops;
        return 0;
@@ -1223,9 +1235,10 @@ static void nvmet_init_cap(struct nvmet_ctrl *ctrl)
        ctrl->cap |= (15ULL << 24);
        /* maximum queue entries supported: */
        if (ctrl->ops->get_max_queue_size)
-               ctrl->cap |= ctrl->ops->get_max_queue_size(ctrl) - 1;
+               ctrl->cap |= min_t(u16, ctrl->ops->get_max_queue_size(ctrl),
+                                  ctrl->port->max_queue_size) - 1;
        else
-               ctrl->cap |= NVMET_QUEUE_SIZE - 1;
+               ctrl->cap |= ctrl->port->max_queue_size - 1;
 
        if (nvmet_is_passthru_subsys(ctrl->subsys))
                nvmet_passthrough_override_cap(ctrl);
@@ -1411,6 +1424,7 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
 
        kref_init(&ctrl->ref);
        ctrl->subsys = subsys;
+       ctrl->pi_support = ctrl->port->pi_enable && ctrl->subsys->pi_support;
        nvmet_init_cap(ctrl);
        WRITE_ONCE(ctrl->aen_enabled, NVMET_AEN_CFG_OPTIONAL);
 
index 68e82ccc0e4e38ffcb2018cce0080741a5984925..ce54da8c6b3661e3a83e4cf53ac101f9262b7176 100644 (file)
@@ -282,7 +282,7 @@ static void nvmet_execute_disc_identify(struct nvmet_req *req)
        id->lpa = (1 << 2);
 
        /* no enforcement soft-limit for maxcmd - pick arbitrary high value */
-       id->maxcmd = cpu_to_le16(NVMET_MAX_CMD);
+       id->maxcmd = cpu_to_le16(NVMET_MAX_CMD(ctrl));
 
        id->sgls = cpu_to_le32(1 << 0); /* we always support SGLs */
        if (ctrl->ops->flags & NVMF_KEYED_SGLS)
index d8da840a1c0ed1e9c383d59c11227f7fddfe607d..b23f4cf840bd541ca3f0215cda994549273a43b3 100644 (file)
@@ -157,7 +157,8 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
                return NVME_SC_CMD_SEQ_ERROR | NVME_SC_DNR;
        }
 
-       if (sqsize > mqes) {
+       /* for fabrics, this value applies to only the I/O Submission Queues */
+       if (qid && sqsize > mqes) {
                pr_warn("sqsize %u is larger than MQES supported %u cntlid %d\n",
                                sqsize, mqes, ctrl->cntlid);
                req->error_loc = offsetof(struct nvmf_connect_command, sqsize);
@@ -209,7 +210,7 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req)
        struct nvmf_connect_command *c = &req->cmd->connect;
        struct nvmf_connect_data *d;
        struct nvmet_ctrl *ctrl = NULL;
-       u16 status = 0;
+       u16 status;
        int ret;
 
        if (!nvmet_check_transfer_len(req, sizeof(struct nvmf_connect_data)))
@@ -251,8 +252,6 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req)
        if (status)
                goto out;
 
-       ctrl->pi_support = ctrl->port->pi_enable && ctrl->subsys->pi_support;
-
        uuid_copy(&ctrl->hostid, &d->hostid);
 
        ret = nvmet_setup_auth(ctrl);
@@ -290,7 +289,7 @@ static void nvmet_execute_io_connect(struct nvmet_req *req)
        struct nvmf_connect_data *d;
        struct nvmet_ctrl *ctrl;
        u16 qid = le16_to_cpu(c->qid);
-       u16 status = 0;
+       u16 status;
 
        if (!nvmet_check_transfer_len(req, sizeof(struct nvmf_connect_data)))
                return;
index 1471af250ea62267a812bdb402b05ff9099cfcb6..913cd2ec7a6f618db7a274dd234f335c263bdba0 100644 (file)
@@ -1556,7 +1556,9 @@ static const struct attribute_group *fcloop_dev_attr_groups[] = {
        NULL,
 };
 
-static struct class *fcloop_class;
+static const struct class fcloop_class = {
+       .name = "fcloop",
+};
 static struct device *fcloop_device;
 
 
@@ -1564,15 +1566,14 @@ static int __init fcloop_init(void)
 {
        int ret;
 
-       fcloop_class = class_create("fcloop");
-       if (IS_ERR(fcloop_class)) {
+       ret = class_register(&fcloop_class);
+       if (ret) {
                pr_err("couldn't register class fcloop\n");
-               ret = PTR_ERR(fcloop_class);
                return ret;
        }
 
        fcloop_device = device_create_with_groups(
-                               fcloop_class, NULL, MKDEV(0, 0), NULL,
+                               &fcloop_class, NULL, MKDEV(0, 0), NULL,
                                fcloop_dev_attr_groups, "ctl");
        if (IS_ERR(fcloop_device)) {
                pr_err("couldn't create ctl device!\n");
@@ -1585,7 +1586,7 @@ static int __init fcloop_init(void)
        return 0;
 
 out_destroy_class:
-       class_destroy(fcloop_class);
+       class_unregister(&fcloop_class);
        return ret;
 }
 
@@ -1643,8 +1644,8 @@ static void __exit fcloop_exit(void)
 
        put_device(fcloop_device);
 
-       device_destroy(fcloop_class, MKDEV(0, 0));
-       class_destroy(fcloop_class);
+       device_destroy(&fcloop_class, MKDEV(0, 0));
+       class_unregister(&fcloop_class);
 }
 
 module_init(fcloop_init);
index f11400a908f269f74138226079d3000f648f73b3..6426aac2634aeb501c673852d6eb99a79a437de4 100644 (file)
@@ -50,10 +50,10 @@ void nvmet_bdev_set_limits(struct block_device *bdev, struct nvme_id_ns *id)
 
 void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
 {
-       if (ns->bdev_handle) {
-               bdev_release(ns->bdev_handle);
+       if (ns->bdev_file) {
+               fput(ns->bdev_file);
                ns->bdev = NULL;
-               ns->bdev_handle = NULL;
+               ns->bdev_file = NULL;
        }
 }
 
@@ -85,18 +85,18 @@ int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
        if (ns->buffered_io)
                return -ENOTBLK;
 
-       ns->bdev_handle = bdev_open_by_path(ns->device_path,
+       ns->bdev_file = bdev_file_open_by_path(ns->device_path,
                                BLK_OPEN_READ | BLK_OPEN_WRITE, NULL, NULL);
-       if (IS_ERR(ns->bdev_handle)) {
-               ret = PTR_ERR(ns->bdev_handle);
+       if (IS_ERR(ns->bdev_file)) {
+               ret = PTR_ERR(ns->bdev_file);
                if (ret != -ENOTBLK) {
                        pr_err("failed to open block device %s: (%d)\n",
                                        ns->device_path, ret);
                }
-               ns->bdev_handle = NULL;
+               ns->bdev_file = NULL;
                return ret;
        }
-       ns->bdev = ns->bdev_handle->bdev;
+       ns->bdev = file_bdev(ns->bdev_file);
        ns->size = bdev_nr_bytes(ns->bdev);
        ns->blksize_shift = blksize_bits(bdev_logical_block_size(ns->bdev));
 
index 6c8acebe1a1a61b8742d892c1ba2f7eb5d1e9364..f460728e1df1fd87e24969e782203c7684a23326 100644 (file)
@@ -58,7 +58,7 @@
 
 struct nvmet_ns {
        struct percpu_ref       ref;
-       struct bdev_handle      *bdev_handle;
+       struct file             *bdev_file;
        struct block_device     *bdev;
        struct file             *file;
        bool                    readonly;
@@ -163,6 +163,7 @@ struct nvmet_port {
        void                            *priv;
        bool                            enabled;
        int                             inline_data_size;
+       int                             max_queue_size;
        const struct nvmet_fabrics_ops  *tr_ops;
        bool                            pi_enable;
 };
@@ -543,9 +544,10 @@ void nvmet_subsys_disc_changed(struct nvmet_subsys *subsys,
 void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type,
                u8 event_info, u8 log_page);
 
-#define NVMET_QUEUE_SIZE       1024
+#define NVMET_MIN_QUEUE_SIZE   16
+#define NVMET_MAX_QUEUE_SIZE   1024
 #define NVMET_NR_QUEUES                128
-#define NVMET_MAX_CMD          NVMET_QUEUE_SIZE
+#define NVMET_MAX_CMD(ctrl)    (NVME_CAP_MQES(ctrl->cap) + 1)
 
 /*
  * Nice round number that makes a list of nsids fit into a page.
index f2d963e1fe94e1a88cc7fa4aa6ef9b4d18c16054..bb4a69d538fd101087b34d55021f71559f302b84 100644 (file)
@@ -132,7 +132,7 @@ static u16 nvmet_passthru_override_id_ctrl(struct nvmet_req *req)
 
        id->sqes = min_t(__u8, ((0x6 << 4) | 0x6), id->sqes);
        id->cqes = min_t(__u8, ((0x4 << 4) | 0x4), id->cqes);
-       id->maxcmd = cpu_to_le16(NVMET_MAX_CMD);
+       id->maxcmd = cpu_to_le16(NVMET_MAX_CMD(ctrl));
 
        /* don't support fuse commands */
        id->fuses = 0;
index 3a0f2c170f4c16f6c1fa6f09c2cac948403550fb..f2bb9d95ecf4bc6cde907d1f9af3e2d89998f376 100644 (file)
@@ -1956,6 +1956,14 @@ static int nvmet_rdma_add_port(struct nvmet_port *nport)
                nport->inline_data_size = NVMET_RDMA_MAX_INLINE_DATA_SIZE;
        }
 
+       if (nport->max_queue_size < 0) {
+               nport->max_queue_size = NVME_RDMA_DEFAULT_QUEUE_SIZE;
+       } else if (nport->max_queue_size > NVME_RDMA_MAX_QUEUE_SIZE) {
+               pr_warn("max_queue_size %u is too large, reducing to %u\n",
+                       nport->max_queue_size, NVME_RDMA_MAX_QUEUE_SIZE);
+               nport->max_queue_size = NVME_RDMA_MAX_QUEUE_SIZE;
+       }
+
        ret = inet_pton_with_scope(&init_net, af, nport->disc_addr.traddr,
                        nport->disc_addr.trsvcid, &port->addr);
        if (ret) {
@@ -2015,6 +2023,8 @@ static u8 nvmet_rdma_get_mdts(const struct nvmet_ctrl *ctrl)
 
 static u16 nvmet_rdma_get_max_queue_size(const struct nvmet_ctrl *ctrl)
 {
+       if (ctrl->pi_support)
+               return NVME_RDMA_MAX_METADATA_QUEUE_SIZE;
        return NVME_RDMA_MAX_QUEUE_SIZE;
 }
 
index 5b5c1e48172213df20683d8c117a9586b733bfa5..3148d9f1bde66ac44d114b71f45c98ab52a6ed24 100644 (file)
@@ -456,8 +456,7 @@ static u16 nvmet_bdev_execute_zmgmt_send_all(struct nvmet_req *req)
        switch (zsa_req_op(req->cmd->zms.zsa)) {
        case REQ_OP_ZONE_RESET:
                ret = blkdev_zone_mgmt(req->ns->bdev, REQ_OP_ZONE_RESET, 0,
-                                      get_capacity(req->ns->bdev->bd_disk),
-                                      GFP_KERNEL);
+                                      get_capacity(req->ns->bdev->bd_disk));
                if (ret < 0)
                        return blkdev_zone_mgmt_errno_to_nvme_status(ret);
                break;
@@ -508,7 +507,7 @@ static void nvmet_bdev_zmgmt_send_work(struct work_struct *w)
                goto out;
        }
 
-       ret = blkdev_zone_mgmt(bdev, op, sect, zone_sectors, GFP_KERNEL);
+       ret = blkdev_zone_mgmt(bdev, op, sect, zone_sectors);
        if (ret < 0)
                status = blkdev_zone_mgmt_errno_to_nvme_status(ret);
 
index 980123fb4dde05d0e5cd4e0cfe5645b24a8d55dc..eb357ac2e54a2a827ad07b9a073d3e76415a000f 100644 (file)
@@ -460,8 +460,9 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
        list_for_each_entry(entry, &nvmem->cells, node) {
                sysfs_bin_attr_init(&attrs[i]);
                attrs[i].attr.name = devm_kasprintf(&nvmem->dev, GFP_KERNEL,
-                                                   "%s@%x", entry->name,
-                                                   entry->offset);
+                                                   "%s@%x,%x", entry->name,
+                                                   entry->offset,
+                                                   entry->bit_offset);
                attrs[i].attr.mode = 0444;
                attrs[i].size = entry->bytes;
                attrs[i].read = &nvmem_cell_attr_read;
index 641a40cf5cf34a7d0aa3bf94362a95ae58065fe1..fa8cd33be1312dc57f075cf6557270794dcc2939 100644 (file)
@@ -763,7 +763,9 @@ struct device_node *of_graph_get_port_parent(struct device_node *node)
        /* Walk 3 levels up only if there is 'ports' node. */
        for (depth = 3; depth && node; depth--) {
                node = of_get_next_parent(node);
-               if (depth == 2 && !of_node_name_eq(node, "ports"))
+               if (depth == 2 && !of_node_name_eq(node, "ports") &&
+                   !of_node_name_eq(node, "in-ports") &&
+                   !of_node_name_eq(node, "out-ports"))
                        break;
        }
        return node;
@@ -1063,36 +1065,6 @@ of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
        return of_device_get_match_data(dev);
 }
 
-static struct device_node *of_get_compat_node(struct device_node *np)
-{
-       of_node_get(np);
-
-       while (np) {
-               if (!of_device_is_available(np)) {
-                       of_node_put(np);
-                       np = NULL;
-               }
-
-               if (of_property_present(np, "compatible"))
-                       break;
-
-               np = of_get_next_parent(np);
-       }
-
-       return np;
-}
-
-static struct device_node *of_get_compat_node_parent(struct device_node *np)
-{
-       struct device_node *parent, *node;
-
-       parent = of_get_parent(np);
-       node = of_get_compat_node(parent);
-       of_node_put(parent);
-
-       return node;
-}
-
 static void of_link_to_phandle(struct device_node *con_np,
                              struct device_node *sup_np)
 {
@@ -1222,10 +1194,10 @@ static struct device_node *parse_##fname(struct device_node *np,             \
  *  parse_prop.prop_name: Name of property holding a phandle value
  *  parse_prop.index: For properties holding a list of phandles, this is the
  *                   index into the list
+ * @get_con_dev: If the consumer node containing the property is never converted
+ *              to a struct device, implement this ops so fw_devlink can use it
+ *              to find the true consumer.
  * @optional: Describes whether a supplier is mandatory or not
- * @node_not_dev: The consumer node containing the property is never converted
- *               to a struct device. Instead, parse ancestor nodes for the
- *               compatible property to find a node corresponding to a device.
  *
  * Returns:
  * parse_prop() return values are
@@ -1236,15 +1208,15 @@ static struct device_node *parse_##fname(struct device_node *np,             \
 struct supplier_bindings {
        struct device_node *(*parse_prop)(struct device_node *np,
                                          const char *prop_name, int index);
+       struct device_node *(*get_con_dev)(struct device_node *np);
        bool optional;
-       bool node_not_dev;
 };
 
 DEFINE_SIMPLE_PROP(clocks, "clocks", "#clock-cells")
 DEFINE_SIMPLE_PROP(interconnects, "interconnects", "#interconnect-cells")
 DEFINE_SIMPLE_PROP(iommus, "iommus", "#iommu-cells")
 DEFINE_SIMPLE_PROP(mboxes, "mboxes", "#mbox-cells")
-DEFINE_SIMPLE_PROP(io_channels, "io-channel", "#io-channel-cells")
+DEFINE_SIMPLE_PROP(io_channels, "io-channels", "#io-channel-cells")
 DEFINE_SIMPLE_PROP(interrupt_parent, "interrupt-parent", NULL)
 DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells")
 DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells")
@@ -1262,7 +1234,6 @@ DEFINE_SIMPLE_PROP(pinctrl5, "pinctrl-5", NULL)
 DEFINE_SIMPLE_PROP(pinctrl6, "pinctrl-6", NULL)
 DEFINE_SIMPLE_PROP(pinctrl7, "pinctrl-7", NULL)
 DEFINE_SIMPLE_PROP(pinctrl8, "pinctrl-8", NULL)
-DEFINE_SIMPLE_PROP(remote_endpoint, "remote-endpoint", NULL)
 DEFINE_SIMPLE_PROP(pwms, "pwms", "#pwm-cells")
 DEFINE_SIMPLE_PROP(resets, "resets", "#reset-cells")
 DEFINE_SIMPLE_PROP(leds, "leds", NULL)
@@ -1328,6 +1299,17 @@ static struct device_node *parse_interrupts(struct device_node *np,
        return of_irq_parse_one(np, index, &sup_args) ? NULL : sup_args.np;
 }
 
+static struct device_node *parse_remote_endpoint(struct device_node *np,
+                                                const char *prop_name,
+                                                int index)
+{
+       /* Return NULL for index > 0 to signify end of remote-endpoints. */
+       if (index > 0 || strcmp(prop_name, "remote-endpoint"))
+               return NULL;
+
+       return of_graph_get_remote_port_parent(np);
+}
+
 static const struct supplier_bindings of_supplier_bindings[] = {
        { .parse_prop = parse_clocks, },
        { .parse_prop = parse_interconnects, },
@@ -1352,7 +1334,10 @@ static const struct supplier_bindings of_supplier_bindings[] = {
        { .parse_prop = parse_pinctrl6, },
        { .parse_prop = parse_pinctrl7, },
        { .parse_prop = parse_pinctrl8, },
-       { .parse_prop = parse_remote_endpoint, .node_not_dev = true, },
+       {
+               .parse_prop = parse_remote_endpoint,
+               .get_con_dev = of_graph_get_port_parent,
+       },
        { .parse_prop = parse_pwms, },
        { .parse_prop = parse_resets, },
        { .parse_prop = parse_leds, },
@@ -1403,8 +1388,8 @@ static int of_link_property(struct device_node *con_np, const char *prop_name)
                while ((phandle = s->parse_prop(con_np, prop_name, i))) {
                        struct device_node *con_dev_np;
 
-                       con_dev_np = s->node_not_dev
-                                       ? of_get_compat_node_parent(con_np)
+                       con_dev_np = s->get_con_dev
+                                       ? s->get_con_dev(con_np)
                                        : of_node_get(con_np);
                        matched = true;
                        i++;
index cfd60e35a8992d7d1bf7ee1ea42c10b6f43a7a2e..d7593bde2d02f39c2532ae4d0be41cccaec38526 100644 (file)
@@ -50,6 +50,12 @@ static struct unittest_results {
        failed; \
 })
 
+#ifdef CONFIG_OF_KOBJ
+#define OF_KREF_READ(NODE) kref_read(&(NODE)->kobj.kref)
+#else
+#define OF_KREF_READ(NODE) 1
+#endif
+
 /*
  * Expected message may have a message level other than KERN_INFO.
  * Print the expected message only if the current loglevel will allow
@@ -570,7 +576,7 @@ static void __init of_unittest_parse_phandle_with_args_map(void)
                        pr_err("missing testcase data\n");
                        return;
                }
-               prefs[i] = kref_read(&p[i]->kobj.kref);
+               prefs[i] = OF_KREF_READ(p[i]);
        }
 
        rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells");
@@ -693,9 +699,9 @@ static void __init of_unittest_parse_phandle_with_args_map(void)
        unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 
        for (i = 0; i < ARRAY_SIZE(p); ++i) {
-               unittest(prefs[i] == kref_read(&p[i]->kobj.kref),
+               unittest(prefs[i] == OF_KREF_READ(p[i]),
                         "provider%d: expected:%d got:%d\n",
-                        i, prefs[i], kref_read(&p[i]->kobj.kref));
+                        i, prefs[i], OF_KREF_READ(p[i]));
                of_node_put(p[i]);
        }
 }
index a89b7de72dcfa02e9b4e3909c4320b67a6114471..7333b305f2a578789893fdbdbdeb82510c8f61c5 100644 (file)
@@ -26,58 +26,79 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
                                             hotplug_slot);
        int rc;
 
-       if (zdev->state != ZPCI_FN_STATE_STANDBY)
-               return -EIO;
+       mutex_lock(&zdev->state_lock);
+       if (zdev->state != ZPCI_FN_STATE_STANDBY) {
+               rc = -EIO;
+               goto out;
+       }
 
        rc = sclp_pci_configure(zdev->fid);
        zpci_dbg(3, "conf fid:%x, rc:%d\n", zdev->fid, rc);
        if (rc)
-               return rc;
+               goto out;
        zdev->state = ZPCI_FN_STATE_CONFIGURED;
 
-       return zpci_scan_configured_device(zdev, zdev->fh);
+       rc = zpci_scan_configured_device(zdev, zdev->fh);
+out:
+       mutex_unlock(&zdev->state_lock);
+       return rc;
 }
 
 static int disable_slot(struct hotplug_slot *hotplug_slot)
 {
        struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev,
                                             hotplug_slot);
-       struct pci_dev *pdev;
+       struct pci_dev *pdev = NULL;
+       int rc;
 
-       if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
-               return -EIO;
+       mutex_lock(&zdev->state_lock);
+       if (zdev->state != ZPCI_FN_STATE_CONFIGURED) {
+               rc = -EIO;
+               goto out;
+       }
 
        pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
        if (pdev && pci_num_vf(pdev)) {
                pci_dev_put(pdev);
-               return -EBUSY;
+               rc = -EBUSY;
+               goto out;
        }
-       pci_dev_put(pdev);
 
-       return zpci_deconfigure_device(zdev);
+       rc = zpci_deconfigure_device(zdev);
+out:
+       mutex_unlock(&zdev->state_lock);
+       if (pdev)
+               pci_dev_put(pdev);
+       return rc;
 }
 
 static int reset_slot(struct hotplug_slot *hotplug_slot, bool probe)
 {
        struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev,
                                             hotplug_slot);
+       int rc = -EIO;
 
-       if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
-               return -EIO;
        /*
-        * We can't take the zdev->lock as reset_slot may be called during
-        * probing and/or device removal which already happens under the
-        * zdev->lock. Instead the user should use the higher level
-        * pci_reset_function() or pci_bus_reset() which hold the PCI device
-        * lock preventing concurrent removal. If not using these functions
-        * holding the PCI device lock is required.
+        * If we can't get the zdev->state_lock the device state is
+        * currently undergoing a transition and we bail out - just
+        * the same as if the device's state is not configured at all.
         */
+       if (!mutex_trylock(&zdev->state_lock))
+               return rc;
 
-       /* As long as the function is configured we can reset */
-       if (probe)
-               return 0;
+       /* We can reset only if the function is configured */
+       if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
+               goto out;
+
+       if (probe) {
+               rc = 0;
+               goto out;
+       }
 
-       return zpci_hot_reset_device(zdev);
+       rc = zpci_hot_reset_device(zdev);
+out:
+       mutex_unlock(&zdev->state_lock);
+       return rc;
 }
 
 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
index c8be056c248ded75cae622f1d8cd82bcc81e5500..cfd84a899c82d881f9ed5c446aed0c204bfd3cd4 100644 (file)
@@ -61,7 +61,7 @@ static irq_hw_number_t pci_msi_domain_calc_hwirq(struct msi_desc *desc)
 
        return (irq_hw_number_t)desc->msi_index |
                pci_dev_id(dev) << 11 |
-               (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
+               ((irq_hw_number_t)(pci_domain_nr(dev->bus) & 0xFFFFFFFF)) << 27;
 }
 
 static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
index 9ab9b1008d8b9de897f1a1372f128e849b8a73a2..c3585229c12a2145401d675ff84c20288b8f158e 100644 (file)
@@ -2522,29 +2522,36 @@ static void pci_pme_list_scan(struct work_struct *work)
                if (pdev->pme_poll) {
                        struct pci_dev *bridge = pdev->bus->self;
                        struct device *dev = &pdev->dev;
-                       int pm_status;
+                       struct device *bdev = bridge ? &bridge->dev : NULL;
+                       int bref = 0;
 
                        /*
-                        * If bridge is in low power state, the
-                        * configuration space of subordinate devices
-                        * may be not accessible
+                        * If we have a bridge, it should be in an active/D0
+                        * state or the configuration space of subordinate
+                        * devices may not be accessible or stable over the
+                        * course of the call.
                         */
-                       if (bridge && bridge->current_state != PCI_D0)
-                               continue;
+                       if (bdev) {
+                               bref = pm_runtime_get_if_active(bdev, true);
+                               if (!bref)
+                                       continue;
+
+                               if (bridge->current_state != PCI_D0)
+                                       goto put_bridge;
+                       }
 
                        /*
-                        * If the device is in a low power state it
-                        * should not be polled either.
+                        * The device itself should be suspended but config
+                        * space must be accessible, therefore it cannot be in
+                        * D3cold.
                         */
-                       pm_status = pm_runtime_get_if_active(dev, true);
-                       if (!pm_status)
-                               continue;
-
-                       if (pdev->current_state != PCI_D3cold)
+                       if (pm_runtime_suspended(dev) &&
+                           pdev->current_state != PCI_D3cold)
                                pci_pme_wakeup(pdev, NULL);
 
-                       if (pm_status > 0)
-                               pm_runtime_put(dev);
+put_bridge:
+                       if (bref > 0)
+                               pm_runtime_put(bdev);
                } else {
                        list_del(&pme_dev->list);
                        kfree(pme_dev);
index c584165b13babd946eb7fcd84300bdf68abe31af..7e3aa7e2345fa3a9d7d3b1cb9c5dd40cc15498ff 100644 (file)
@@ -2305,6 +2305,17 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
                                dev_dbg(cmn->dev, "ignoring external node %llx\n", reg);
                                continue;
                        }
+                       /*
+                        * AmpereOneX erratum AC04_MESH_1 makes some XPs report a bogus
+                        * child count larger than the number of valid child pointers.
+                        * A child offset of 0 can only occur on CMN-600; otherwise it
+                        * would imply the root node being its own grandchild, which
+                        * we can safely dismiss in general.
+                        */
+                       if (reg == 0 && cmn->part != PART_CMN600) {
+                               dev_dbg(cmn->dev, "bogus child pointer?\n");
+                               continue;
+                       }
 
                        arm_cmn_init_node_info(cmn, reg & CMN_CHILD_NODE_ADDR, dn);
 
index 6303b82566f9811261447ec8035e0e453301da37..9e5d7fa647b6d376e69620eae387383c101cb452 100644 (file)
@@ -716,7 +716,7 @@ static void smmu_pmu_free_msis(void *data)
 {
        struct device *dev = data;
 
-       platform_msi_domain_free_irqs(dev);
+       platform_device_msi_free_irqs_all(dev);
 }
 
 static void smmu_pmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
@@ -746,7 +746,7 @@ static void smmu_pmu_setup_msi(struct smmu_pmu *pmu)
        if (!(readl(pmu->reg_base + SMMU_PMCG_CFGR) & SMMU_PMCG_CFGR_MSI))
                return;
 
-       ret = platform_msi_domain_alloc_irqs(dev, 1, smmu_pmu_write_msi_msg);
+       ret = platform_device_msi_init_and_alloc_irqs(dev, 1, smmu_pmu_write_msi_msg);
        if (ret) {
                dev_warn(dev, "failed to allocate MSIs\n");
                return;
index 365d964b0f6a6d7382455f3b07035fafe1de1fa2..308c9969642e1f149cdebd9f8aed7812adbc5f1f 100644 (file)
@@ -59,7 +59,7 @@
 #define   CXL_PMU_COUNTER_CFG_EVENT_GRP_ID_IDX_MSK     GENMASK_ULL(63, 59)
 
 #define CXL_PMU_FILTER_CFG_REG(n, f)   (0x400 + 4 * ((f) + (n) * 8))
-#define   CXL_PMU_FILTER_CFG_VALUE_MSK                 GENMASK(15, 0)
+#define   CXL_PMU_FILTER_CFG_VALUE_MSK                 GENMASK(31, 0)
 
 #define CXL_PMU_COUNTER_REG(n)         (0xc00 + 8 * (n))
 
@@ -314,9 +314,9 @@ static bool cxl_pmu_config1_get_edge(struct perf_event *event)
 }
 
 /*
- * CPMU specification allows for 8 filters, each with a 16 bit value...
- * So we need to find 8x16bits to store it in.
- * As the value used for disable is 0xffff, a separate enable switch
+ * CPMU specification allows for 8 filters, each with a 32 bit value...
+ * So we need to find 8x32bits to store it in.
+ * As the value used for disable is 0xffff_ffff, a separate enable switch
  * is needed.
  */
 
@@ -419,7 +419,7 @@ static struct attribute *cxl_pmu_event_attrs[] = {
        CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmp,                     CXL_PMU_GID_S2M_NDR, BIT(0)),
        CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmps,                    CXL_PMU_GID_S2M_NDR, BIT(1)),
        CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmpe,                    CXL_PMU_GID_S2M_NDR, BIT(2)),
-       CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_biconflictack,           CXL_PMU_GID_S2M_NDR, BIT(3)),
+       CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_biconflictack,           CXL_PMU_GID_S2M_NDR, BIT(4)),
        /* CXL rev 3.0 Table 3-46 S2M DRS opcodes */
        CXL_PMU_EVENT_CXL_ATTR(s2m_drs_memdata,                 CXL_PMU_GID_S2M_DRS, BIT(0)),
        CXL_PMU_EVENT_CXL_ATTR(s2m_drs_memdatanxm,              CXL_PMU_GID_S2M_DRS, BIT(1)),
@@ -642,7 +642,7 @@ static void cxl_pmu_event_start(struct perf_event *event, int flags)
                if (cxl_pmu_config1_hdm_filter_en(event))
                        cfg = cxl_pmu_config2_get_hdm_decoder(event);
                else
-                       cfg = GENMASK(15, 0); /* No filtering if 0xFFFF_FFFF */
+                       cfg = GENMASK(31, 0); /* No filtering if 0xFFFF_FFFF */
                writeq(cfg, base + CXL_PMU_FILTER_CFG_REG(hwc->idx, 0));
        }
 
index 0dda70e1ef90a19017c902689f970dea684b4f4c..c78a6fd6c57f612221749d44673d47845911231f 100644 (file)
@@ -150,19 +150,11 @@ u64 riscv_pmu_ctr_get_width_mask(struct perf_event *event)
        struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
        struct hw_perf_event *hwc = &event->hw;
 
-       if (!rvpmu->ctr_get_width)
-       /**
-        * If the pmu driver doesn't support counter width, set it to default
-        * maximum allowed by the specification.
-        */
-               cwidth = 63;
-       else {
-               if (hwc->idx == -1)
-                       /* Handle init case where idx is not initialized yet */
-                       cwidth = rvpmu->ctr_get_width(0);
-               else
-                       cwidth = rvpmu->ctr_get_width(hwc->idx);
-       }
+       if (hwc->idx == -1)
+               /* Handle init case where idx is not initialized yet */
+               cwidth = rvpmu->ctr_get_width(0);
+       else
+               cwidth = rvpmu->ctr_get_width(hwc->idx);
 
        return GENMASK_ULL(cwidth, 0);
 }
index 79fdd667922e812612aae1f597714bbefa0d4899..fa0bccf4edf2ea6172c7ee72d577cb0904073ea7 100644 (file)
@@ -37,6 +37,12 @@ static int pmu_legacy_event_map(struct perf_event *event, u64 *config)
        return pmu_legacy_ctr_get_idx(event);
 }
 
+/* cycle & instret are always 64 bit, one bit less according to SBI spec */
+static int pmu_legacy_ctr_get_width(int idx)
+{
+       return 63;
+}
+
 static u64 pmu_legacy_read_ctr(struct perf_event *event)
 {
        struct hw_perf_event *hwc = &event->hw;
@@ -111,12 +117,14 @@ static void pmu_legacy_init(struct riscv_pmu *pmu)
        pmu->ctr_stop = NULL;
        pmu->event_map = pmu_legacy_event_map;
        pmu->ctr_get_idx = pmu_legacy_ctr_get_idx;
-       pmu->ctr_get_width = NULL;
+       pmu->ctr_get_width = pmu_legacy_ctr_get_width;
        pmu->ctr_clear_idx = NULL;
        pmu->ctr_read = pmu_legacy_read_ctr;
        pmu->event_mapped = pmu_legacy_event_mapped;
        pmu->event_unmapped = pmu_legacy_event_unmapped;
        pmu->csr_index = pmu_legacy_csr_index;
+       pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
+       pmu->pmu.capabilities |= PERF_PMU_CAP_NO_EXCLUDE;
 
        perf_pmu_register(&pmu->pmu, "cpu", PERF_TYPE_RAW);
 }
index 16acd4dcdb96c75e07b45a3745a71842f2d7d2b8..452aab49db1e8ccc35a6bb0b76661ca7cb6fb71f 100644 (file)
@@ -512,7 +512,7 @@ static void pmu_sbi_set_scounteren(void *arg)
 
        if (event->hw.idx != -1)
                csr_write(CSR_SCOUNTEREN,
-                         csr_read(CSR_SCOUNTEREN) | (1 << pmu_sbi_csr_index(event)));
+                         csr_read(CSR_SCOUNTEREN) | BIT(pmu_sbi_csr_index(event)));
 }
 
 static void pmu_sbi_reset_scounteren(void *arg)
@@ -521,7 +521,7 @@ static void pmu_sbi_reset_scounteren(void *arg)
 
        if (event->hw.idx != -1)
                csr_write(CSR_SCOUNTEREN,
-                         csr_read(CSR_SCOUNTEREN) & ~(1 << pmu_sbi_csr_index(event)));
+                         csr_read(CSR_SCOUNTEREN) & ~BIT(pmu_sbi_csr_index(event)));
 }
 
 static void pmu_sbi_ctr_start(struct perf_event *event, u64 ival)
@@ -731,14 +731,14 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
                /* compute hardware counter index */
                hidx = info->csr - CSR_CYCLE;
                /* check if the corresponding bit is set in sscountovf */
-               if (!(overflow & (1 << hidx)))
+               if (!(overflow & BIT(hidx)))
                        continue;
 
                /*
                 * Keep a track of overflowed counters so that they can be started
                 * with updated initial value.
                 */
-               overflowed_ctrs |= 1 << lidx;
+               overflowed_ctrs |= BIT(lidx);
                hw_evt = &event->hw;
                riscv_pmu_event_update(event);
                perf_sample_data_init(&data, 0, hw_evt->last_period);
index e625b32889bfceaef9846db42e594e971cccb54d..0928a526e2ab3692eaeb1e4abaa45e23eee4cf5b 100644 (file)
@@ -706,7 +706,7 @@ static int mixel_dphy_probe(struct platform_device *pdev)
                        return ret;
                }
 
-               priv->id = of_alias_get_id(np, "mipi_dphy");
+               priv->id = of_alias_get_id(np, "mipi-dphy");
                if (priv->id < 0) {
                        dev_err(dev, "Failed to get phy node alias id: %d\n",
                                priv->id);
index a623f092b11f642bd3d35655e162a94a454bb14f..a43e20abb10d54a2ff2bbe29907f5c4597d6871d 100644 (file)
 #define EUSB2_TUNE_EUSB_EQU            0x5A
 #define EUSB2_TUNE_EUSB_HS_COMP_CUR    0x5B
 
-#define QCOM_EUSB2_REPEATER_INIT_CFG(r, v)     \
-       {                                       \
-               .reg = r,                       \
-               .val = v,                       \
-       }
-
-enum reg_fields {
-       F_TUNE_EUSB_HS_COMP_CUR,
-       F_TUNE_EUSB_EQU,
-       F_TUNE_EUSB_SLEW,
-       F_TUNE_USB2_HS_COMP_CUR,
-       F_TUNE_USB2_PREEM,
-       F_TUNE_USB2_EQU,
-       F_TUNE_USB2_SLEW,
-       F_TUNE_SQUELCH_U,
-       F_TUNE_HSDISC,
-       F_TUNE_RES_FSDIF,
-       F_TUNE_IUSB2,
-       F_TUNE_USB2_CROSSOVER,
-       F_NUM_TUNE_FIELDS,
-
-       F_FORCE_VAL_5 = F_NUM_TUNE_FIELDS,
-       F_FORCE_EN_5,
-
-       F_EN_CTL1,
-
-       F_RPTR_STATUS,
-       F_NUM_FIELDS,
-};
-
-static struct reg_field eusb2_repeater_tune_reg_fields[F_NUM_FIELDS] = {
-       [F_TUNE_EUSB_HS_COMP_CUR] = REG_FIELD(EUSB2_TUNE_EUSB_HS_COMP_CUR, 0, 1),
-       [F_TUNE_EUSB_EQU] = REG_FIELD(EUSB2_TUNE_EUSB_EQU, 0, 1),
-       [F_TUNE_EUSB_SLEW] = REG_FIELD(EUSB2_TUNE_EUSB_SLEW, 0, 1),
-       [F_TUNE_USB2_HS_COMP_CUR] = REG_FIELD(EUSB2_TUNE_USB2_HS_COMP_CUR, 0, 1),
-       [F_TUNE_USB2_PREEM] = REG_FIELD(EUSB2_TUNE_USB2_PREEM, 0, 2),
-       [F_TUNE_USB2_EQU] = REG_FIELD(EUSB2_TUNE_USB2_EQU, 0, 1),
-       [F_TUNE_USB2_SLEW] = REG_FIELD(EUSB2_TUNE_USB2_SLEW, 0, 1),
-       [F_TUNE_SQUELCH_U] = REG_FIELD(EUSB2_TUNE_SQUELCH_U, 0, 2),
-       [F_TUNE_HSDISC] = REG_FIELD(EUSB2_TUNE_HSDISC, 0, 2),
-       [F_TUNE_RES_FSDIF] = REG_FIELD(EUSB2_TUNE_RES_FSDIF, 0, 2),
-       [F_TUNE_IUSB2] = REG_FIELD(EUSB2_TUNE_IUSB2, 0, 3),
-       [F_TUNE_USB2_CROSSOVER] = REG_FIELD(EUSB2_TUNE_USB2_CROSSOVER, 0, 2),
-
-       [F_FORCE_VAL_5] = REG_FIELD(EUSB2_FORCE_VAL_5, 0, 7),
-       [F_FORCE_EN_5] = REG_FIELD(EUSB2_FORCE_EN_5, 0, 7),
-
-       [F_EN_CTL1] = REG_FIELD(EUSB2_EN_CTL1, 0, 7),
-
-       [F_RPTR_STATUS] = REG_FIELD(EUSB2_RPTR_STATUS, 0, 7),
+enum eusb2_reg_layout {
+       TUNE_EUSB_HS_COMP_CUR,
+       TUNE_EUSB_EQU,
+       TUNE_EUSB_SLEW,
+       TUNE_USB2_HS_COMP_CUR,
+       TUNE_USB2_PREEM,
+       TUNE_USB2_EQU,
+       TUNE_USB2_SLEW,
+       TUNE_SQUELCH_U,
+       TUNE_HSDISC,
+       TUNE_RES_FSDIF,
+       TUNE_IUSB2,
+       TUNE_USB2_CROSSOVER,
+       NUM_TUNE_FIELDS,
+
+       FORCE_VAL_5 = NUM_TUNE_FIELDS,
+       FORCE_EN_5,
+
+       EN_CTL1,
+
+       RPTR_STATUS,
+       LAYOUT_SIZE,
 };
 
 struct eusb2_repeater_cfg {
@@ -98,10 +70,11 @@ struct eusb2_repeater_cfg {
 
 struct eusb2_repeater {
        struct device *dev;
-       struct regmap_field *regs[F_NUM_FIELDS];
+       struct regmap *regmap;
        struct phy *phy;
        struct regulator_bulk_data *vregs;
        const struct eusb2_repeater_cfg *cfg;
+       u32 base;
        enum phy_mode mode;
 };
 
@@ -109,10 +82,10 @@ static const char * const pm8550b_vreg_l[] = {
        "vdd18", "vdd3",
 };
 
-static const u32 pm8550b_init_tbl[F_NUM_TUNE_FIELDS] = {
-       [F_TUNE_IUSB2] = 0x8,
-       [F_TUNE_SQUELCH_U] = 0x3,
-       [F_TUNE_USB2_PREEM] = 0x5,
+static const u32 pm8550b_init_tbl[NUM_TUNE_FIELDS] = {
+       [TUNE_IUSB2] = 0x8,
+       [TUNE_SQUELCH_U] = 0x3,
+       [TUNE_USB2_PREEM] = 0x5,
 };
 
 static const struct eusb2_repeater_cfg pm8550b_eusb2_cfg = {
@@ -140,47 +113,42 @@ static int eusb2_repeater_init_vregs(struct eusb2_repeater *rptr)
 
 static int eusb2_repeater_init(struct phy *phy)
 {
-       struct reg_field *regfields = eusb2_repeater_tune_reg_fields;
        struct eusb2_repeater *rptr = phy_get_drvdata(phy);
        struct device_node *np = rptr->dev->of_node;
-       u32 init_tbl[F_NUM_TUNE_FIELDS] = { 0 };
-       u8 override;
+       struct regmap *regmap = rptr->regmap;
+       const u32 *init_tbl = rptr->cfg->init_tbl;
+       u8 tune_usb2_preem = init_tbl[TUNE_USB2_PREEM];
+       u8 tune_hsdisc = init_tbl[TUNE_HSDISC];
+       u8 tune_iusb2 = init_tbl[TUNE_IUSB2];
+       u32 base = rptr->base;
        u32 val;
        int ret;
-       int i;
+
+       of_property_read_u8(np, "qcom,tune-usb2-amplitude", &tune_iusb2);
+       of_property_read_u8(np, "qcom,tune-usb2-disc-thres", &tune_hsdisc);
+       of_property_read_u8(np, "qcom,tune-usb2-preem", &tune_usb2_preem);
 
        ret = regulator_bulk_enable(rptr->cfg->num_vregs, rptr->vregs);
        if (ret)
                return ret;
 
-       regmap_field_update_bits(rptr->regs[F_EN_CTL1], EUSB2_RPTR_EN, EUSB2_RPTR_EN);
+       regmap_write(regmap, base + EUSB2_EN_CTL1, EUSB2_RPTR_EN);
 
-       for (i = 0; i < F_NUM_TUNE_FIELDS; i++) {
-               if (init_tbl[i]) {
-                       regmap_field_update_bits(rptr->regs[i], init_tbl[i], init_tbl[i]);
-               } else {
-                       /* Write 0 if there's no value set */
-                       u32 mask = GENMASK(regfields[i].msb, regfields[i].lsb);
-
-                       regmap_field_update_bits(rptr->regs[i], mask, 0);
-               }
-       }
-       memcpy(init_tbl, rptr->cfg->init_tbl, sizeof(init_tbl));
+       regmap_write(regmap, base + EUSB2_TUNE_EUSB_HS_COMP_CUR, init_tbl[TUNE_EUSB_HS_COMP_CUR]);
+       regmap_write(regmap, base + EUSB2_TUNE_EUSB_EQU, init_tbl[TUNE_EUSB_EQU]);
+       regmap_write(regmap, base + EUSB2_TUNE_EUSB_SLEW, init_tbl[TUNE_EUSB_SLEW]);
+       regmap_write(regmap, base + EUSB2_TUNE_USB2_HS_COMP_CUR, init_tbl[TUNE_USB2_HS_COMP_CUR]);
+       regmap_write(regmap, base + EUSB2_TUNE_USB2_EQU, init_tbl[TUNE_USB2_EQU]);
+       regmap_write(regmap, base + EUSB2_TUNE_USB2_SLEW, init_tbl[TUNE_USB2_SLEW]);
+       regmap_write(regmap, base + EUSB2_TUNE_SQUELCH_U, init_tbl[TUNE_SQUELCH_U]);
+       regmap_write(regmap, base + EUSB2_TUNE_RES_FSDIF, init_tbl[TUNE_RES_FSDIF]);
+       regmap_write(regmap, base + EUSB2_TUNE_USB2_CROSSOVER, init_tbl[TUNE_USB2_CROSSOVER]);
 
-       if (!of_property_read_u8(np, "qcom,tune-usb2-amplitude", &override))
-               init_tbl[F_TUNE_IUSB2] = override;
+       regmap_write(regmap, base + EUSB2_TUNE_USB2_PREEM, tune_usb2_preem);
+       regmap_write(regmap, base + EUSB2_TUNE_HSDISC, tune_hsdisc);
+       regmap_write(regmap, base + EUSB2_TUNE_IUSB2, tune_iusb2);
 
-       if (!of_property_read_u8(np, "qcom,tune-usb2-disc-thres", &override))
-               init_tbl[F_TUNE_HSDISC] = override;
-
-       if (!of_property_read_u8(np, "qcom,tune-usb2-preem", &override))
-               init_tbl[F_TUNE_USB2_PREEM] = override;
-
-       for (i = 0; i < F_NUM_TUNE_FIELDS; i++)
-               regmap_field_update_bits(rptr->regs[i], init_tbl[i], init_tbl[i]);
-
-       ret = regmap_field_read_poll_timeout(rptr->regs[F_RPTR_STATUS],
-                                            val, val & RPTR_OK, 10, 5);
+       ret = regmap_read_poll_timeout(regmap, base + EUSB2_RPTR_STATUS, val, val & RPTR_OK, 10, 5);
        if (ret)
                dev_err(rptr->dev, "initialization timed-out\n");
 
@@ -191,6 +159,8 @@ static int eusb2_repeater_set_mode(struct phy *phy,
                                   enum phy_mode mode, int submode)
 {
        struct eusb2_repeater *rptr = phy_get_drvdata(phy);
+       struct regmap *regmap = rptr->regmap;
+       u32 base = rptr->base;
 
        switch (mode) {
        case PHY_MODE_USB_HOST:
@@ -199,10 +169,8 @@ static int eusb2_repeater_set_mode(struct phy *phy,
                 * per eUSB 1.2 Spec. Below implement software workaround until
                 * PHY and controller is fixing seen observation.
                 */
-               regmap_field_update_bits(rptr->regs[F_FORCE_EN_5],
-                                        F_CLK_19P2M_EN, F_CLK_19P2M_EN);
-               regmap_field_update_bits(rptr->regs[F_FORCE_VAL_5],
-                                        V_CLK_19P2M_EN, V_CLK_19P2M_EN);
+               regmap_write(regmap, base + EUSB2_FORCE_EN_5, F_CLK_19P2M_EN);
+               regmap_write(regmap, base + EUSB2_FORCE_VAL_5, V_CLK_19P2M_EN);
                break;
        case PHY_MODE_USB_DEVICE:
                /*
@@ -211,10 +179,8 @@ static int eusb2_repeater_set_mode(struct phy *phy,
                 * repeater doesn't clear previous value due to shared
                 * regulators (say host <-> device mode switch).
                 */
-               regmap_field_update_bits(rptr->regs[F_FORCE_EN_5],
-                                        F_CLK_19P2M_EN, 0);
-               regmap_field_update_bits(rptr->regs[F_FORCE_VAL_5],
-                                        V_CLK_19P2M_EN, 0);
+               regmap_write(regmap, base + EUSB2_FORCE_EN_5, 0);
+               regmap_write(regmap, base + EUSB2_FORCE_VAL_5, 0);
                break;
        default:
                return -EINVAL;
@@ -243,9 +209,8 @@ static int eusb2_repeater_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct phy_provider *phy_provider;
        struct device_node *np = dev->of_node;
-       struct regmap *regmap;
-       int i, ret;
        u32 res;
+       int ret;
 
        rptr = devm_kzalloc(dev, sizeof(*rptr), GFP_KERNEL);
        if (!rptr)
@@ -258,22 +223,15 @@ static int eusb2_repeater_probe(struct platform_device *pdev)
        if (!rptr->cfg)
                return -EINVAL;
 
-       regmap = dev_get_regmap(dev->parent, NULL);
-       if (!regmap)
+       rptr->regmap = dev_get_regmap(dev->parent, NULL);
+       if (!rptr->regmap)
                return -ENODEV;
 
        ret = of_property_read_u32(np, "reg", &res);
        if (ret < 0)
                return ret;
 
-       for (i = 0; i < F_NUM_FIELDS; i++)
-               eusb2_repeater_tune_reg_fields[i].reg += res;
-
-       ret = devm_regmap_field_bulk_alloc(dev, regmap, rptr->regs,
-                                          eusb2_repeater_tune_reg_fields,
-                                          F_NUM_FIELDS);
-       if (ret)
-               return ret;
+       rptr->base = res;
 
        ret = eusb2_repeater_init_vregs(rptr);
        if (ret < 0) {
index c2590579190a935d76abc9cde99964c9958d3d07..03fb0d4b75d744492e4646af65287f61e7927f1b 100644 (file)
@@ -299,7 +299,7 @@ static int m31usb_phy_probe(struct platform_device *pdev)
 
        qphy->vreg = devm_regulator_get(dev, "vdda-phy");
        if (IS_ERR(qphy->vreg))
-               return dev_err_probe(dev, PTR_ERR(qphy->phy),
+               return dev_err_probe(dev, PTR_ERR(qphy->vreg),
                                     "failed to get vreg\n");
 
        phy_set_drvdata(qphy->phy, qphy);
index 1ad10110dd2544b77ae38a1459497ae6e2905b84..17c4ad7553a5edd0960e8ff7e64e97dd7f22b5f5 100644 (file)
@@ -3562,14 +3562,6 @@ static int qmp_combo_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       ret = qmp_combo_typec_switch_register(qmp);
-       if (ret)
-               return ret;
-
-       ret = drm_aux_bridge_register(dev);
-       if (ret)
-               return ret;
-
        /* Check for legacy binding with child nodes. */
        usb_np = of_get_child_by_name(dev->of_node, "usb3-phy");
        if (usb_np) {
@@ -3589,6 +3581,14 @@ static int qmp_combo_probe(struct platform_device *pdev)
        if (ret)
                goto err_node_put;
 
+       ret = qmp_combo_typec_switch_register(qmp);
+       if (ret)
+               goto err_node_put;
+
+       ret = drm_aux_bridge_register(dev);
+       if (ret)
+               goto err_node_put;
+
        pm_runtime_set_active(dev);
        ret = devm_pm_runtime_enable(dev);
        if (ret)
index 6621246e4ddf0c567f58abdb6fb6799a08ff594e..5c003988c35d38cead7cc6b3e1e2af04a07bdb28 100644 (file)
@@ -1556,7 +1556,7 @@ static const char * const qmp_phy_vreg_l[] = {
        "vdda-phy", "vdda-pll",
 };
 
-static const struct qmp_usb_offsets qmp_usb_offsets_ipq8074 = {
+static const struct qmp_usb_offsets qmp_usb_offsets_v3 = {
        .serdes         = 0,
        .pcs            = 0x800,
        .pcs_misc       = 0x600,
@@ -1572,7 +1572,7 @@ static const struct qmp_usb_offsets qmp_usb_offsets_ipq9574 = {
        .rx             = 0x400,
 };
 
-static const struct qmp_usb_offsets qmp_usb_offsets_v3 = {
+static const struct qmp_usb_offsets qmp_usb_offsets_v3_msm8996 = {
        .serdes         = 0,
        .pcs            = 0x600,
        .tx             = 0x200,
@@ -1624,7 +1624,7 @@ static const struct qmp_usb_offsets qmp_usb_offsets_v7 = {
 static const struct qmp_phy_cfg ipq6018_usb3phy_cfg = {
        .lanes                  = 1,
 
-       .offsets                = &qmp_usb_offsets_ipq8074,
+       .offsets                = &qmp_usb_offsets_v3,
 
        .serdes_tbl             = ipq9574_usb3_serdes_tbl,
        .serdes_tbl_num         = ARRAY_SIZE(ipq9574_usb3_serdes_tbl),
@@ -1642,7 +1642,7 @@ static const struct qmp_phy_cfg ipq6018_usb3phy_cfg = {
 static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = {
        .lanes                  = 1,
 
-       .offsets                = &qmp_usb_offsets_ipq8074,
+       .offsets                = &qmp_usb_offsets_v3,
 
        .serdes_tbl             = ipq8074_usb3_serdes_tbl,
        .serdes_tbl_num         = ARRAY_SIZE(ipq8074_usb3_serdes_tbl),
@@ -1678,7 +1678,7 @@ static const struct qmp_phy_cfg ipq9574_usb3phy_cfg = {
 static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
        .lanes                  = 1,
 
-       .offsets                = &qmp_usb_offsets_v3,
+       .offsets                = &qmp_usb_offsets_v3_msm8996,
 
        .serdes_tbl             = msm8996_usb3_serdes_tbl,
        .serdes_tbl_num         = ARRAY_SIZE(msm8996_usb3_serdes_tbl),
index ee56856cb80c33e4733f2b7f2a43fb681c89fc61..bbcdece83bf422948983a814b7a6221b79cad6a3 100644 (file)
@@ -1644,7 +1644,7 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
        const struct pinctrl_ops *ops = pctldev->desc->pctlops;
        unsigned int i, pin;
 #ifdef CONFIG_GPIOLIB
-       struct gpio_device *gdev __free(gpio_device_put) = NULL;
+       struct gpio_device *gdev = NULL;
        struct pinctrl_gpio_range *range;
        int gpio_num;
 #endif
index 73f091cd827e69edae7e2c0f4743e54c6db14b40..23aebd4695e99fbebffaf308724484f14aeb7984 100644 (file)
@@ -2562,7 +2562,7 @@ static const struct of_device_id stm32mp257_pctrl_match[] = {
 };
 
 static const struct dev_pm_ops stm32_pinctrl_dev_pm_ops = {
-        SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, stm32_pinctrl_resume)
+        SET_LATE_SYSTEM_SLEEP_PM_OPS(stm32_pinctrl_suspend, stm32_pinctrl_resume)
 };
 
 static struct platform_driver stm32mp257_pinctrl_driver = {
index feaa09f5b35a125c9c704a432f82c7672b7bc139..4f734e049f4a46b60b139cf38ec7c7a2e193a4f6 100644 (file)
@@ -296,7 +296,8 @@ static int amd_pmf_suspend_handler(struct device *dev)
 {
        struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
 
-       kfree(pdev->buf);
+       if (pdev->smart_pc_enabled)
+               cancel_delayed_work_sync(&pdev->pb_work);
 
        return 0;
 }
@@ -312,6 +313,9 @@ static int amd_pmf_resume_handler(struct device *dev)
                        return ret;
        }
 
+       if (pdev->smart_pc_enabled)
+               schedule_delayed_work(&pdev->pb_work, msecs_to_jiffies(2000));
+
        return 0;
 }
 
@@ -330,9 +334,14 @@ static void amd_pmf_init_features(struct amd_pmf_dev *dev)
                dev_dbg(dev->dev, "SPS enabled and Platform Profiles registered\n");
        }
 
-       if (!amd_pmf_init_smart_pc(dev)) {
+       amd_pmf_init_smart_pc(dev);
+       if (dev->smart_pc_enabled) {
                dev_dbg(dev->dev, "Smart PC Solution Enabled\n");
-       } else if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
+               /* If Smart PC is enabled, no need to check for other features */
+               return;
+       }
+
+       if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
                amd_pmf_init_auto_mode(dev);
                dev_dbg(dev->dev, "Auto Mode Init done\n");
        } else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) ||
@@ -351,7 +360,7 @@ static void amd_pmf_deinit_features(struct amd_pmf_dev *dev)
                amd_pmf_deinit_sps(dev);
        }
 
-       if (!dev->smart_pc_enabled) {
+       if (dev->smart_pc_enabled) {
                amd_pmf_deinit_smart_pc(dev);
        } else if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
                amd_pmf_deinit_auto_mode(dev);
index 16999c5b334fd44537404c56ab325aff00ede667..66cae1cca73cc16b73210e49af1c836c3da4d260 100644 (file)
@@ -441,11 +441,6 @@ struct apmf_dyn_slider_output {
        struct apmf_cnqf_power_set ps[APMF_CNQF_MAX];
 } __packed;
 
-enum smart_pc_status {
-       PMF_SMART_PC_ENABLED,
-       PMF_SMART_PC_DISABLED,
-};
-
 /* Smart PC - TA internals */
 enum system_state {
        SYSTEM_STATE_S0i3,
index f8c0177afb0dae60d4f67f2876ba98c6100d1ceb..dcbe8f85e122947be014778c14478a7374698b49 100644 (file)
@@ -252,15 +252,17 @@ static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev)
        cookie = readl(dev->policy_buf + POLICY_COOKIE_OFFSET);
        length = readl(dev->policy_buf + POLICY_COOKIE_LEN);
 
-       if (cookie != POLICY_SIGN_COOKIE || !length)
+       if (cookie != POLICY_SIGN_COOKIE || !length) {
+               dev_dbg(dev->dev, "cookie doesn't match\n");
                return -EINVAL;
+       }
 
        /* Update the actual length */
        dev->policy_sz = length + 512;
        res = amd_pmf_invoke_cmd_init(dev);
        if (res == TA_PMF_TYPE_SUCCESS) {
                /* Now its safe to announce that smart pc is enabled */
-               dev->smart_pc_enabled = PMF_SMART_PC_ENABLED;
+               dev->smart_pc_enabled = true;
                /*
                 * Start collecting the data from TA FW after a small delay
                 * or else, we might end up getting stale values.
@@ -268,7 +270,7 @@ static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev)
                schedule_delayed_work(&dev->pb_work, msecs_to_jiffies(pb_actions_ms * 3));
        } else {
                dev_err(dev->dev, "ta invoke cmd init failed err: %x\n", res);
-               dev->smart_pc_enabled = PMF_SMART_PC_DISABLED;
+               dev->smart_pc_enabled = false;
                return res;
        }
 
@@ -336,25 +338,6 @@ static void amd_pmf_remove_pb(struct amd_pmf_dev *dev) {}
 static void amd_pmf_hex_dump_pb(struct amd_pmf_dev *dev) {}
 #endif
 
-static int amd_pmf_get_bios_buffer(struct amd_pmf_dev *dev)
-{
-       dev->policy_buf = kzalloc(dev->policy_sz, GFP_KERNEL);
-       if (!dev->policy_buf)
-               return -ENOMEM;
-
-       dev->policy_base = devm_ioremap(dev->dev, dev->policy_addr, dev->policy_sz);
-       if (!dev->policy_base)
-               return -ENOMEM;
-
-       memcpy(dev->policy_buf, dev->policy_base, dev->policy_sz);
-
-       amd_pmf_hex_dump_pb(dev);
-       if (pb_side_load)
-               amd_pmf_open_pb(dev, dev->dbgfs_dir);
-
-       return amd_pmf_start_policy_engine(dev);
-}
-
 static int amd_pmf_amdtee_ta_match(struct tee_ioctl_version_data *ver, const void *data)
 {
        return ver->impl_id == TEE_IMPL_ID_AMDTEE;
@@ -453,22 +436,59 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
                return ret;
 
        INIT_DELAYED_WORK(&dev->pb_work, amd_pmf_invoke_cmd);
-       amd_pmf_set_dram_addr(dev, true);
-       amd_pmf_get_bios_buffer(dev);
+
+       ret = amd_pmf_set_dram_addr(dev, true);
+       if (ret)
+               goto error;
+
+       dev->policy_base = devm_ioremap(dev->dev, dev->policy_addr, dev->policy_sz);
+       if (!dev->policy_base) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       dev->policy_buf = kzalloc(dev->policy_sz, GFP_KERNEL);
+       if (!dev->policy_buf) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       memcpy(dev->policy_buf, dev->policy_base, dev->policy_sz);
+
+       amd_pmf_hex_dump_pb(dev);
+
        dev->prev_data = kzalloc(sizeof(*dev->prev_data), GFP_KERNEL);
-       if (!dev->prev_data)
-               return -ENOMEM;
+       if (!dev->prev_data) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       ret = amd_pmf_start_policy_engine(dev);
+       if (ret)
+               goto error;
+
+       if (pb_side_load)
+               amd_pmf_open_pb(dev, dev->dbgfs_dir);
+
+       return 0;
 
-       return dev->smart_pc_enabled;
+error:
+       amd_pmf_deinit_smart_pc(dev);
+
+       return ret;
 }
 
 void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev)
 {
-       if (pb_side_load)
+       if (pb_side_load && dev->esbin)
                amd_pmf_remove_pb(dev);
 
+       cancel_delayed_work_sync(&dev->pb_work);
        kfree(dev->prev_data);
+       dev->prev_data = NULL;
        kfree(dev->policy_buf);
-       cancel_delayed_work_sync(&dev->pb_work);
+       dev->policy_buf = NULL;
+       kfree(dev->buf);
+       dev->buf = NULL;
        amd_pmf_tee_deinit(dev);
 }
index b6708bab7c53d5afae8b4cd5d4fb07450a1c92ed..527d8fbc7cc1108da998e86d0d8dd970d9c5b179 100644 (file)
@@ -196,7 +196,7 @@ static int int0002_probe(struct platform_device *pdev)
         * IRQs into gpiolib.
         */
        ret = devm_request_irq(dev, irq, int0002_irq,
-                              IRQF_SHARED, "INT0002", chip);
+                              IRQF_ONESHOT | IRQF_SHARED, "INT0002", chip);
        if (ret) {
                dev_err(dev, "Error requesting IRQ %d: %d\n", irq, ret);
                return ret;
index a5e0f5c22179ff71479ae11bf6d2e5b7b387638b..b89c0dda9e5ddd46d7456e21273be2db93c9eb2e 100644 (file)
@@ -242,7 +242,7 @@ static int __init intel_uncore_init(void)
                return -ENODEV;
 
        uncore_max_entries = topology_max_packages() *
-                                       topology_max_die_per_package();
+                                       topology_max_dies_per_package();
        uncore_instances = kcalloc(uncore_max_entries,
                                   sizeof(*uncore_instances), GFP_KERNEL);
        if (!uncore_instances)
index 210b0a81b7ecbe3ec28499c3c8dbd52cbbf1c3fb..084c355c86f5fa9050ccb881a7efa6682b538773 100644 (file)
@@ -200,9 +200,6 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
        autorelease = val && (!ke_rel || ke_rel->type == KE_IGNORE);
 
        sparse_keymap_report_event(input_dev, event, val, autorelease);
-
-       /* Some devices need this to report further events */
-       acpi_evaluate_object(handle, "VBDL", NULL, NULL);
 }
 
 /*
index 6bd14d0132dbd73b1ea497679d4dd8297671859e..3d66e1d4eb1f52dad69c8b2f94d5089ccd0b0c25 100644 (file)
 #define P2SBC_HIDE             BIT(8)
 
 #define P2SB_DEVFN_DEFAULT     PCI_DEVFN(31, 1)
+#define P2SB_DEVFN_GOLDMONT    PCI_DEVFN(13, 0)
+#define SPI_DEVFN_GOLDMONT     PCI_DEVFN(13, 2)
 
 static const struct x86_cpu_id p2sb_cpu_ids[] = {
-       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT,       PCI_DEVFN(13, 0)),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, P2SB_DEVFN_GOLDMONT),
        {}
 };
 
@@ -98,21 +100,12 @@ static void p2sb_scan_and_cache_devfn(struct pci_bus *bus, unsigned int devfn)
 
 static int p2sb_scan_and_cache(struct pci_bus *bus, unsigned int devfn)
 {
-       unsigned int slot, fn;
-
-       if (PCI_FUNC(devfn) == 0) {
-               /*
-                * When function number of the P2SB device is zero, scan it and
-                * other function numbers, and if devices are available, cache
-                * their BAR0s.
-                */
-               slot = PCI_SLOT(devfn);
-               for (fn = 0; fn < NR_P2SB_RES_CACHE; fn++)
-                       p2sb_scan_and_cache_devfn(bus, PCI_DEVFN(slot, fn));
-       } else {
-               /* Scan the P2SB device and cache its BAR0 */
-               p2sb_scan_and_cache_devfn(bus, devfn);
-       }
+       /* Scan the P2SB device and cache its BAR0 */
+       p2sb_scan_and_cache_devfn(bus, devfn);
+
+       /* On Goldmont p2sb_bar() also gets called for the SPI controller */
+       if (devfn == P2SB_DEVFN_GOLDMONT)
+               p2sb_scan_and_cache_devfn(bus, SPI_DEVFN_GOLDMONT);
 
        if (!p2sb_valid_resource(&p2sb_resources[PCI_FUNC(devfn)].res))
                return -ENOENT;
diff --git a/drivers/platform/x86/serdev_helpers.h b/drivers/platform/x86/serdev_helpers.h
new file mode 100644 (file)
index 0000000..bcf3a0c
--- /dev/null
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * In some cases UART attached devices which require an in kernel driver,
+ * e.g. UART attached Bluetooth HCIs are described in the ACPI tables
+ * by an ACPI device with a broken or missing UartSerialBusV2() resource.
+ *
+ * This causes the kernel to create a /dev/ttyS# char-device for the UART
+ * instead of creating an in kernel serdev-controller + serdev-device pair
+ * for the in kernel driver.
+ *
+ * The quirk handling in acpi_quirk_skip_serdev_enumeration() makes the kernel
+ * create a serdev-controller device for these UARTs instead of a /dev/ttyS#.
+ *
+ * Instantiating the actual serdev-device to bind to is up to pdx86 code,
+ * this header provides a helper for getting the serdev-controller device.
+ */
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/printk.h>
+#include <linux/sprintf.h>
+#include <linux/string.h>
+
+static inline struct device *
+get_serdev_controller(const char *serial_ctrl_hid,
+                     const char *serial_ctrl_uid,
+                     int serial_ctrl_port,
+                     const char *serdev_ctrl_name)
+{
+       struct device *ctrl_dev, *child;
+       struct acpi_device *ctrl_adev;
+       char name[32];
+       int i;
+
+       ctrl_adev = acpi_dev_get_first_match_dev(serial_ctrl_hid, serial_ctrl_uid, -1);
+       if (!ctrl_adev) {
+               pr_err("error could not get %s/%s serial-ctrl adev\n",
+                      serial_ctrl_hid, serial_ctrl_uid);
+               return ERR_PTR(-ENODEV);
+       }
+
+       /* get_first_physical_node() returns a weak ref */
+       ctrl_dev = get_device(acpi_get_first_physical_node(ctrl_adev));
+       if (!ctrl_dev) {
+               pr_err("error could not get %s/%s serial-ctrl physical node\n",
+                      serial_ctrl_hid, serial_ctrl_uid);
+               ctrl_dev = ERR_PTR(-ENODEV);
+               goto put_ctrl_adev;
+       }
+
+       /* Walk host -> uart-ctrl -> port -> serdev-ctrl */
+       for (i = 0; i < 3; i++) {
+               switch (i) {
+               case 0:
+                       snprintf(name, sizeof(name), "%s:0", dev_name(ctrl_dev));
+                       break;
+               case 1:
+                       snprintf(name, sizeof(name), "%s.%d",
+                                dev_name(ctrl_dev), serial_ctrl_port);
+                       break;
+               case 2:
+                       strscpy(name, serdev_ctrl_name, sizeof(name));
+                       break;
+               }
+
+               child = device_find_child_by_name(ctrl_dev, name);
+               put_device(ctrl_dev);
+               if (!child) {
+                       pr_err("error could not find '%s' device\n", name);
+                       ctrl_dev = ERR_PTR(-ENODEV);
+                       goto put_ctrl_adev;
+               }
+
+               ctrl_dev = child;
+       }
+
+put_ctrl_adev:
+       acpi_dev_put(ctrl_adev);
+       return ctrl_dev;
+}
index 3a396b763c4963d1f965e1d635967bd3f3d60f18..ce3e08815a8e647f2bf5578d0383dd4621d8526f 100644 (file)
@@ -1009,7 +1009,16 @@ static ssize_t current_value_store(struct kobject *kobj,
                 * Note - this sets the variable and then the password as separate
                 * WMI calls. Function tlmi_save_bios_settings will error if the
                 * password is incorrect.
+                * Workstation's require the opcode to be set before changing the
+                * attribute.
                 */
+               if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
+                       ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
+                                                 tlmi_priv.pwd_admin->password);
+                       if (ret)
+                               goto out;
+               }
+
                set_str = kasprintf(GFP_KERNEL, "%s,%s;", setting->display_name,
                                    new_setting);
                if (!set_str) {
@@ -1021,17 +1030,10 @@ static ssize_t current_value_store(struct kobject *kobj,
                if (ret)
                        goto out;
 
-               if (tlmi_priv.save_mode == TLMI_SAVE_BULK) {
+               if (tlmi_priv.save_mode == TLMI_SAVE_BULK)
                        tlmi_priv.save_required = true;
-               } else {
-                       if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
-                               ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
-                                                         tlmi_priv.pwd_admin->password);
-                               if (ret)
-                                       goto out;
-                       }
+               else
                        ret = tlmi_save_bios_settings("");
-               }
        } else { /* old non-opcode based authentication method (deprecated) */
                if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
                        auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
index c4895e9bc7148ae991a541508a0672a9ae0345bf..5ecd9d33250d78f3a38c7f99b8b6c5c903cdf25d 100644 (file)
@@ -10308,6 +10308,7 @@ static int convert_dytc_to_profile(int funcmode, int dytcmode,
                return 0;
        default:
                /* Unknown function */
+               pr_debug("unknown function 0x%x\n", funcmode);
                return -EOPNOTSUPP;
        }
        return 0;
@@ -10493,8 +10494,8 @@ static void dytc_profile_refresh(void)
                return;
 
        perfmode = (output >> DYTC_GET_MODE_BIT) & 0xF;
-       convert_dytc_to_profile(funcmode, perfmode, &profile);
-       if (profile != dytc_current_profile) {
+       err = convert_dytc_to_profile(funcmode, perfmode, &profile);
+       if (!err && profile != dytc_current_profile) {
                dytc_current_profile = profile;
                platform_profile_notify();
        }
index 7aee5e9ff2b8dd5810f83cc0317ed329b4361d2e..975cf24ae359a882974f35762894108d4a117fb8 100644 (file)
@@ -81,7 +81,7 @@ static const struct property_entry chuwi_hi8_air_props[] = {
 };
 
 static const struct ts_dmi_data chuwi_hi8_air_data = {
-       .acpi_name      = "MSSL1680:00",
+       .acpi_name      = "MSSL1680",
        .properties     = chuwi_hi8_air_props,
 };
 
@@ -415,18 +415,13 @@ static const struct property_entry gdix1001_upside_down_props[] = {
        { }
 };
 
-static const struct ts_dmi_data gdix1001_00_upside_down_data = {
-       .acpi_name      = "GDIX1001:00",
-       .properties     = gdix1001_upside_down_props,
-};
-
-static const struct ts_dmi_data gdix1001_01_upside_down_data = {
-       .acpi_name      = "GDIX1001:01",
+static const struct ts_dmi_data gdix1001_upside_down_data = {
+       .acpi_name      = "GDIX1001",
        .properties     = gdix1001_upside_down_props,
 };
 
-static const struct ts_dmi_data gdix1002_00_upside_down_data = {
-       .acpi_name      = "GDIX1002:00",
+static const struct ts_dmi_data gdix1002_upside_down_data = {
+       .acpi_name      = "GDIX1002",
        .properties     = gdix1001_upside_down_props,
 };
 
@@ -1412,7 +1407,7 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
        },
        {
                /* Juno Tablet */
-               .driver_data = (void *)&gdix1002_00_upside_down_data,
+               .driver_data = (void *)&gdix1002_upside_down_data,
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Default string"),
                        /* Both product- and board-name being "Default string" is somewhat rare */
@@ -1658,7 +1653,7 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
        },
        {
                /* Teclast X89 (Android version / BIOS) */
-               .driver_data = (void *)&gdix1001_00_upside_down_data,
+               .driver_data = (void *)&gdix1001_upside_down_data,
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "WISKY"),
                        DMI_MATCH(DMI_BOARD_NAME, "3G062i"),
@@ -1666,7 +1661,7 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
        },
        {
                /* Teclast X89 (Windows version / BIOS) */
-               .driver_data = (void *)&gdix1001_01_upside_down_data,
+               .driver_data = (void *)&gdix1001_upside_down_data,
                .matches = {
                        /* tPAD is too generic, also match on bios date */
                        DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
@@ -1684,7 +1679,7 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
        },
        {
                /* Teclast X98 Pro */
-               .driver_data = (void *)&gdix1001_00_upside_down_data,
+               .driver_data = (void *)&gdix1001_upside_down_data,
                .matches = {
                        /*
                         * Only match BIOS date, because the manufacturers
@@ -1788,7 +1783,7 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
        },
        {
                /* "WinBook TW100" */
-               .driver_data = (void *)&gdix1001_00_upside_down_data,
+               .driver_data = (void *)&gdix1001_upside_down_data,
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TW100")
@@ -1796,7 +1791,7 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
        },
        {
                /* WinBook TW700 */
-               .driver_data = (void *)&gdix1001_00_upside_down_data,
+               .driver_data = (void *)&gdix1001_upside_down_data,
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TW700")
@@ -1821,7 +1816,7 @@ static void ts_dmi_add_props(struct i2c_client *client)
        int error;
 
        if (has_acpi_companion(dev) &&
-           !strncmp(ts_data->acpi_name, client->name, I2C_NAME_SIZE)) {
+           strstarts(client->name, ts_data->acpi_name)) {
                error = device_create_managed_software_node(dev, ts_data->properties, NULL);
                if (error)
                        dev_err(dev, "failed to add properties: %d\n", error);
index f8221a15575b327c78df4edb191fdc28c52fe2c1..a3415f1c0b5f82a3f54d4a6eb6fed54d98d5e366 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/string.h>
 
 #include "x86-android-tablets.h"
+#include "../serdev_helpers.h"
 
 static struct platform_device *x86_android_tablet_device;
 
@@ -113,6 +114,9 @@ int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data)
                if (irq_type != IRQ_TYPE_NONE && irq_type != irq_get_trigger_type(irq))
                        irq_set_irq_type(irq, irq_type);
 
+               if (data->free_gpio)
+                       devm_gpiod_put(&x86_android_tablet_device->dev, gpiod);
+
                return irq;
        case X86_ACPI_IRQ_TYPE_PMIC:
                status = acpi_get_handle(NULL, data->chip, &handle);
@@ -229,38 +233,20 @@ static __init int x86_instantiate_spi_dev(const struct x86_dev_info *dev_info, i
 
 static __init int x86_instantiate_serdev(const struct x86_serdev_info *info, int idx)
 {
-       struct acpi_device *ctrl_adev, *serdev_adev;
+       struct acpi_device *serdev_adev;
        struct serdev_device *serdev;
        struct device *ctrl_dev;
        int ret = -ENODEV;
 
-       ctrl_adev = acpi_dev_get_first_match_dev(info->ctrl_hid, info->ctrl_uid, -1);
-       if (!ctrl_adev) {
-               pr_err("error could not get %s/%s ctrl adev\n",
-                      info->ctrl_hid, info->ctrl_uid);
-               return -ENODEV;
-       }
+       ctrl_dev = get_serdev_controller(info->ctrl_hid, info->ctrl_uid, 0,
+                                        info->ctrl_devname);
+       if (IS_ERR(ctrl_dev))
+               return PTR_ERR(ctrl_dev);
 
        serdev_adev = acpi_dev_get_first_match_dev(info->serdev_hid, NULL, -1);
        if (!serdev_adev) {
                pr_err("error could not get %s serdev adev\n", info->serdev_hid);
-               goto put_ctrl_adev;
-       }
-
-       /* get_first_physical_node() returns a weak ref, no need to put() it */
-       ctrl_dev = acpi_get_first_physical_node(ctrl_adev);
-       if (!ctrl_dev)  {
-               pr_err("error could not get %s/%s ctrl physical dev\n",
-                      info->ctrl_hid, info->ctrl_uid);
-               goto put_serdev_adev;
-       }
-
-       /* ctrl_dev now points to the controller's parent, get the controller */
-       ctrl_dev = device_find_child_by_name(ctrl_dev, info->ctrl_devname);
-       if (!ctrl_dev) {
-               pr_err("error could not get %s/%s %s ctrl dev\n",
-                      info->ctrl_hid, info->ctrl_uid, info->ctrl_devname);
-               goto put_serdev_adev;
+               goto put_ctrl_dev;
        }
 
        serdev = serdev_device_alloc(to_serdev_controller(ctrl_dev));
@@ -283,8 +269,8 @@ static __init int x86_instantiate_serdev(const struct x86_serdev_info *info, int
 
 put_serdev_adev:
        acpi_dev_put(serdev_adev);
-put_ctrl_adev:
-       acpi_dev_put(ctrl_adev);
+put_ctrl_dev:
+       put_device(ctrl_dev);
        return ret;
 }
 
index f1c66a61bfc52786f1a6cd49da8ee88c423adbea..c297391955adbcb9a6b076dfb8f009ae4bce2bcb 100644 (file)
@@ -116,6 +116,7 @@ static const struct x86_i2c_client_info lenovo_yb1_x90_i2c_clients[] __initconst
                        .trigger = ACPI_EDGE_SENSITIVE,
                        .polarity = ACPI_ACTIVE_LOW,
                        .con_id = "goodix_ts_irq",
+                       .free_gpio = true,
                },
        }, {
                /* Wacom Digitizer in keyboard half */
index bc6bbf7ec6ea137101394b59d38fb7471675b00c..278402dcb808c5f2b7e25a894c117177867250d0 100644 (file)
@@ -68,7 +68,7 @@ static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst =
        },
 };
 
-static struct gpiod_lookup_table acer_b1_750_goodix_gpios = {
+static struct gpiod_lookup_table acer_b1_750_nvt_ts_gpios = {
        .dev_id = "i2c-NVT-ts",
        .table = {
                GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW),
@@ -77,7 +77,7 @@ static struct gpiod_lookup_table acer_b1_750_goodix_gpios = {
 };
 
 static struct gpiod_lookup_table * const acer_b1_750_gpios[] = {
-       &acer_b1_750_goodix_gpios,
+       &acer_b1_750_nvt_ts_gpios,
        &int3496_reference_gpios,
        NULL
 };
index 49fed9410adbadad39d397a7b541f52b13c03564..468993edfeee25bcb541daedbe6006ccc7fc44bb 100644 (file)
@@ -39,6 +39,7 @@ struct x86_acpi_irq_data {
        int index;
        int trigger;  /* ACPI_EDGE_SENSITIVE / ACPI_LEVEL_SENSITIVE */
        int polarity; /* ACPI_ACTIVE_HIGH / ACPI_ACTIVE_LOW / ACPI_ACTIVE_BOTH */
+       bool free_gpio; /* Release GPIO after getting IRQ (for TYPE_GPIOINT) */
        const char *con_id;
 };
 
index 709bbc448fad431d894479146982664002578584..d7ef46ccd9b8a414f8066f7fe2718f9867c89003 100644 (file)
@@ -159,6 +159,9 @@ static void scmi_perf_domain_remove(struct scmi_device *sdev)
        struct genpd_onecell_data *scmi_pd_data = dev_get_drvdata(dev);
        int i;
 
+       if (!scmi_pd_data)
+               return;
+
        of_genpd_del_provider(dev->of_node);
 
        for (i = 0; i < scmi_pd_data->num_domains; i++)
index 3078896b13008865816edc575fe0d769b44c9453..de9121ef4216b363e8f72ffbc671f5ffcfefd56e 100644 (file)
@@ -217,7 +217,6 @@ static struct rpmhpd *sa8540p_rpmhpds[] = {
        [SC8280XP_CX] = &cx,
        [SC8280XP_CX_AO] = &cx_ao,
        [SC8280XP_EBI] = &ebi,
-       [SC8280XP_GFX] = &gfx,
        [SC8280XP_LCX] = &lcx,
        [SC8280XP_LMX] = &lmx,
        [SC8280XP_MMCX] = &mmcx,
@@ -692,6 +691,7 @@ static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)
        unsigned int active_corner, sleep_corner;
        unsigned int this_active_corner = 0, this_sleep_corner = 0;
        unsigned int peer_active_corner = 0, peer_sleep_corner = 0;
+       unsigned int peer_enabled_corner;
 
        if (pd->state_synced) {
                to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner);
@@ -701,9 +701,11 @@ static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)
                this_sleep_corner = pd->level_count - 1;
        }
 
-       if (peer && peer->enabled)
-               to_active_sleep(peer, peer->corner, &peer_active_corner,
+       if (peer && peer->enabled) {
+               peer_enabled_corner = max(peer->corner, peer->enable_corner);
+               to_active_sleep(peer, peer_enabled_corner, &peer_active_corner,
                                &peer_sleep_corner);
+       }
 
        active_corner = max(this_active_corner, peer_active_corner);
 
index f21cb05815ec6391cc5e11c7edc5190b7163aa94..3e31375491d58055b19f1b61b57dcac3d849b363 100644 (file)
@@ -978,6 +978,7 @@ config CHARGER_QCOM_SMB2
 config FUEL_GAUGE_MM8013
        tristate "Mitsumi MM8013 fuel gauge driver"
        depends on I2C
+       select REGMAP_I2C
        help
          Say Y here to enable the Mitsumi MM8013 fuel gauge driver.
          It enables the monitoring of many battery parameters, including
index 3a1798b0c1a79f3ed3a3fd0be4d84f6df390b3b4..9910c600743ebd9b9e01a1cb393c0378ae837807 100644 (file)
@@ -209,7 +209,9 @@ static void bq27xxx_battery_i2c_remove(struct i2c_client *client)
 {
        struct bq27xxx_device_info *di = i2c_get_clientdata(client);
 
-       free_irq(client->irq, di);
+       if (client->irq)
+               free_irq(client->irq, di);
+
        bq27xxx_battery_teardown(di);
 
        mutex_lock(&battery_mutex);
index 2feed036c1cd415ef98a7ea3437ebd5bc7429b10..00c861899a47ea9860a225befe267a4d629c1ce2 100644 (file)
@@ -1564,7 +1564,7 @@ struct rapl_package *rapl_add_package(int id, struct rapl_if_priv *priv, bool id
        if (id_is_cpu) {
                rp->id = topology_logical_die_id(id);
                rp->lead_cpu = id;
-               if (topology_max_die_per_package() > 1)
+               if (topology_max_dies_per_package() > 1)
                        snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH, "package-%d-die-%d",
                                 topology_physical_package_id(id), topology_die_id(id));
                else
index 2418977989beb420a9587d9c013e61b950d09b85..15ccb7dd2ed0d551c5255f0ebbfbbd9c5d9ceccb 100644 (file)
@@ -28,15 +28,15 @@ static int ptp_kvm_get_time_fn(ktime_t *device_time,
                               struct system_counterval_t *system_counter,
                               void *ctx)
 {
-       long ret;
-       u64 cycle;
+       enum clocksource_ids cs_id;
        struct timespec64 tspec;
-       struct clocksource *cs;
+       u64 cycle;
+       int ret;
 
        spin_lock(&kvm_ptp_lock);
 
        preempt_disable_notrace();
-       ret = kvm_arch_ptp_get_crosststamp(&cycle, &tspec, &cs);
+       ret = kvm_arch_ptp_get_crosststamp(&cycle, &tspec, &cs_id);
        if (ret) {
                spin_unlock(&kvm_ptp_lock);
                preempt_enable_notrace();
@@ -46,7 +46,7 @@ static int ptp_kvm_get_time_fn(ktime_t *device_time,
        preempt_enable_notrace();
 
        system_counter->cycles = cycle;
-       system_counter->cs = cs;
+       system_counter->cs_id = cs_id;
 
        *device_time = timespec64_to_ktime(tspec);
 
index 902844cc1a17d5bd46461702ea149c852454db46..617c8d6706d3d00f7167fbf7e5b624ced29a206d 100644 (file)
@@ -93,7 +93,7 @@ int kvm_arch_ptp_get_clock(struct timespec64 *ts)
 }
 
 int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *tspec,
-                             struct clocksource **cs)
+                             enum clocksource_ids *cs_id)
 {
        struct pvclock_vcpu_time_info *src;
        unsigned int version;
@@ -123,7 +123,7 @@ int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *tspec,
                *cycle = __pvclock_read_cycles(src, clock_pair->tsc);
        } while (pvclock_read_retry(src, version));
 
-       *cs = &kvm_clock;
+       *cs_id = CSID_X86_KVM_CLK;
 
        return 0;
 }
index c2a236f2e84608b73ab42f80cec52c62a1fe33e9..fc4f4bb94a4c659c391a24c6a3119ab7b24e7c7f 100644 (file)
@@ -32,5 +32,18 @@ menuconfig RAS
 if RAS
 
 source "arch/x86/ras/Kconfig"
+source "drivers/ras/amd/atl/Kconfig"
+
+config RAS_FMPM
+       tristate "FRU Memory Poison Manager"
+       default m
+       depends on AMD_ATL && ACPI_APEI
+       help
+         Support saving and restoring memory error information across reboot
+         using ACPI ERST as persistent storage. Error information is saved with
+         the UEFI CPER "FRU Memory Poison" section format.
+
+         Memory will be retired during boot time and run time depending on
+         platform-specific policies.
 
 endif
index 6f0404f501071b37200119fe7d4f90d3c73cf49a..11f95d59d3972d756e4c916bb3ee632d9bd7245a 100644 (file)
@@ -2,3 +2,6 @@
 obj-$(CONFIG_RAS)      += ras.o
 obj-$(CONFIG_DEBUG_FS) += debugfs.o
 obj-$(CONFIG_RAS_CEC)  += cec.o
+
+obj-$(CONFIG_RAS_FMPM) += amd/fmpm.o
+obj-y                  += amd/atl/
diff --git a/drivers/ras/amd/atl/Kconfig b/drivers/ras/amd/atl/Kconfig
new file mode 100644 (file)
index 0000000..df49c23
--- /dev/null
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# AMD Address Translation Library Kconfig
+#
+# Copyright (c) 2023, Advanced Micro Devices, Inc.
+# All Rights Reserved.
+#
+# Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
+
+config AMD_ATL
+       tristate "AMD Address Translation Library"
+       depends on AMD_NB && X86_64 && RAS
+       depends on MEMORY_FAILURE
+       default N
+       help
+         This library includes support for implementation-specific
+         address translation procedures needed for various error
+         handling cases.
+
+         Enable this option if using DRAM ECC on Zen-based systems
+         and OS-based error handling.
diff --git a/drivers/ras/amd/atl/Makefile b/drivers/ras/amd/atl/Makefile
new file mode 100644 (file)
index 0000000..4acd5f0
--- /dev/null
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# AMD Address Translation Library Makefile
+#
+# Copyright (c) 2023, Advanced Micro Devices, Inc.
+# All Rights Reserved.
+#
+# Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
+
+amd_atl-y              := access.o
+amd_atl-y              += core.o
+amd_atl-y              += dehash.o
+amd_atl-y              += denormalize.o
+amd_atl-y              += map.o
+amd_atl-y              += system.o
+amd_atl-y              += umc.o
+
+obj-$(CONFIG_AMD_ATL)  += amd_atl.o
diff --git a/drivers/ras/amd/atl/access.c b/drivers/ras/amd/atl/access.c
new file mode 100644 (file)
index 0000000..ee4661e
--- /dev/null
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD Address Translation Library
+ *
+ * access.c : DF Indirect Access functions
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
+ */
+
+#include "internal.h"
+
+/* Protect the PCI config register pairs used for DF indirect access. */
+static DEFINE_MUTEX(df_indirect_mutex);
+
+/*
+ * Data Fabric Indirect Access uses FICAA/FICAD.
+ *
+ * Fabric Indirect Configuration Access Address (FICAA): constructed based
+ * on the device's Instance Id and the PCI function and register offset of
+ * the desired register.
+ *
+ * Fabric Indirect Configuration Access Data (FICAD): there are FICAD
+ * low and high registers but so far only the low register is needed.
+ *
+ * Use Instance Id 0xFF to indicate a broadcast read.
+ */
+#define DF_BROADCAST           0xFF
+
+#define DF_FICAA_INST_EN       BIT(0)
+#define DF_FICAA_REG_NUM       GENMASK(10, 1)
+#define DF_FICAA_FUNC_NUM      GENMASK(13, 11)
+#define DF_FICAA_INST_ID       GENMASK(23, 16)
+
+#define DF_FICAA_REG_NUM_LEGACY        GENMASK(10, 2)
+
+static u16 get_accessible_node(u16 node)
+{
+       /*
+        * On heterogeneous systems, not all AMD Nodes are accessible
+        * through software-visible registers. The Node ID needs to be
+        * adjusted for register accesses. But its value should not be
+        * changed for the translation methods.
+        */
+       if (df_cfg.flags.heterogeneous) {
+               /* Only Node 0 is accessible on DF3.5 systems. */
+               if (df_cfg.rev == DF3p5)
+                       node = 0;
+
+               /*
+                * Only the first Node in each Socket is accessible on
+                * DF4.5 systems, and this is visible to software as one
+                * Fabric per Socket.  The Socket ID can be derived from
+                * the Node ID and global shift values.
+                */
+               if (df_cfg.rev == DF4p5)
+                       node >>= df_cfg.socket_id_shift - df_cfg.node_id_shift;
+       }
+
+       return node;
+}
+
+static int __df_indirect_read(u16 node, u8 func, u16 reg, u8 instance_id, u32 *lo)
+{
+       u32 ficaa_addr = 0x8C, ficad_addr = 0xB8;
+       struct pci_dev *F4;
+       int err = -ENODEV;
+       u32 ficaa = 0;
+
+       node = get_accessible_node(node);
+       if (node >= amd_nb_num())
+               goto out;
+
+       F4 = node_to_amd_nb(node)->link;
+       if (!F4)
+               goto out;
+
+       /* Enable instance-specific access. */
+       if (instance_id != DF_BROADCAST) {
+               ficaa |= FIELD_PREP(DF_FICAA_INST_EN, 1);
+               ficaa |= FIELD_PREP(DF_FICAA_INST_ID, instance_id);
+       }
+
+       /*
+        * The two least-significant bits are masked when inputing the
+        * register offset to FICAA.
+        */
+       reg >>= 2;
+
+       if (df_cfg.flags.legacy_ficaa) {
+               ficaa_addr = 0x5C;
+               ficad_addr = 0x98;
+
+               ficaa |= FIELD_PREP(DF_FICAA_REG_NUM_LEGACY, reg);
+       } else {
+               ficaa |= FIELD_PREP(DF_FICAA_REG_NUM, reg);
+       }
+
+       ficaa |= FIELD_PREP(DF_FICAA_FUNC_NUM, func);
+
+       mutex_lock(&df_indirect_mutex);
+
+       err = pci_write_config_dword(F4, ficaa_addr, ficaa);
+       if (err) {
+               pr_warn("Error writing DF Indirect FICAA, FICAA=0x%x\n", ficaa);
+               goto out_unlock;
+       }
+
+       err = pci_read_config_dword(F4, ficad_addr, lo);
+       if (err)
+               pr_warn("Error reading DF Indirect FICAD LO, FICAA=0x%x.\n", ficaa);
+
+       pr_debug("node=%u inst=0x%x func=0x%x reg=0x%x val=0x%x",
+                node, instance_id, func, reg << 2, *lo);
+
+out_unlock:
+       mutex_unlock(&df_indirect_mutex);
+
+out:
+       return err;
+}
+
+int df_indirect_read_instance(u16 node, u8 func, u16 reg, u8 instance_id, u32 *lo)
+{
+       return __df_indirect_read(node, func, reg, instance_id, lo);
+}
+
+int df_indirect_read_broadcast(u16 node, u8 func, u16 reg, u32 *lo)
+{
+       return __df_indirect_read(node, func, reg, DF_BROADCAST, lo);
+}
diff --git a/drivers/ras/amd/atl/core.c b/drivers/ras/amd/atl/core.c
new file mode 100644 (file)
index 0000000..6dc4e06
--- /dev/null
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD Address Translation Library
+ *
+ * core.c : Module init and base translation functions
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
+ */
+
+#include <linux/module.h>
+#include <asm/cpu_device_id.h>
+
+#include "internal.h"
+
+struct df_config df_cfg __read_mostly;
+
+static int addr_over_limit(struct addr_ctx *ctx)
+{
+       u64 dram_limit_addr;
+
+       if (df_cfg.rev >= DF4)
+               dram_limit_addr = FIELD_GET(DF4_DRAM_LIMIT_ADDR, ctx->map.limit);
+       else
+               dram_limit_addr = FIELD_GET(DF2_DRAM_LIMIT_ADDR, ctx->map.limit);
+
+       dram_limit_addr <<= DF_DRAM_BASE_LIMIT_LSB;
+       dram_limit_addr |= GENMASK(DF_DRAM_BASE_LIMIT_LSB - 1, 0);
+
+       /* Is calculated system address above DRAM limit address? */
+       if (ctx->ret_addr > dram_limit_addr) {
+               atl_debug(ctx, "Calculated address (0x%016llx) > DRAM limit (0x%016llx)",
+                         ctx->ret_addr, dram_limit_addr);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static bool legacy_hole_en(struct addr_ctx *ctx)
+{
+       u32 reg = ctx->map.base;
+
+       if (df_cfg.rev >= DF4)
+               reg = ctx->map.ctl;
+
+       return FIELD_GET(DF_LEGACY_MMIO_HOLE_EN, reg);
+}
+
+static int add_legacy_hole(struct addr_ctx *ctx)
+{
+       u32 dram_hole_base;
+       u8 func = 0;
+
+       if (!legacy_hole_en(ctx))
+               return 0;
+
+       if (df_cfg.rev >= DF4)
+               func = 7;
+
+       if (df_indirect_read_broadcast(ctx->node_id, func, 0x104, &dram_hole_base))
+               return -EINVAL;
+
+       dram_hole_base &= DF_DRAM_HOLE_BASE_MASK;
+
+       if (ctx->ret_addr >= dram_hole_base)
+               ctx->ret_addr += (BIT_ULL(32) - dram_hole_base);
+
+       return 0;
+}
+
+static u64 get_base_addr(struct addr_ctx *ctx)
+{
+       u64 base_addr;
+
+       if (df_cfg.rev >= DF4)
+               base_addr = FIELD_GET(DF4_BASE_ADDR, ctx->map.base);
+       else
+               base_addr = FIELD_GET(DF2_BASE_ADDR, ctx->map.base);
+
+       return base_addr << DF_DRAM_BASE_LIMIT_LSB;
+}
+
+static int add_base_and_hole(struct addr_ctx *ctx)
+{
+       ctx->ret_addr += get_base_addr(ctx);
+
+       if (add_legacy_hole(ctx))
+               return -EINVAL;
+
+       return 0;
+}
+
+static bool late_hole_remove(struct addr_ctx *ctx)
+{
+       if (df_cfg.rev == DF3p5)
+               return true;
+
+       if (df_cfg.rev == DF4)
+               return true;
+
+       if (ctx->map.intlv_mode == DF3_6CHAN)
+               return true;
+
+       return false;
+}
+
+unsigned long norm_to_sys_addr(u8 socket_id, u8 die_id, u8 coh_st_inst_id, unsigned long addr)
+{
+       struct addr_ctx ctx;
+
+       if (df_cfg.rev == UNKNOWN)
+               return -EINVAL;
+
+       memset(&ctx, 0, sizeof(ctx));
+
+       /* Start from the normalized address */
+       ctx.ret_addr = addr;
+       ctx.inst_id = coh_st_inst_id;
+
+       ctx.inputs.norm_addr = addr;
+       ctx.inputs.socket_id = socket_id;
+       ctx.inputs.die_id = die_id;
+       ctx.inputs.coh_st_inst_id = coh_st_inst_id;
+
+       if (determine_node_id(&ctx, socket_id, die_id))
+               return -EINVAL;
+
+       if (get_address_map(&ctx))
+               return -EINVAL;
+
+       if (denormalize_address(&ctx))
+               return -EINVAL;
+
+       if (!late_hole_remove(&ctx) && add_base_and_hole(&ctx))
+               return -EINVAL;
+
+       if (dehash_address(&ctx))
+               return -EINVAL;
+
+       if (late_hole_remove(&ctx) && add_base_and_hole(&ctx))
+               return -EINVAL;
+
+       if (addr_over_limit(&ctx))
+               return -EINVAL;
+
+       return ctx.ret_addr;
+}
+
+static void check_for_legacy_df_access(void)
+{
+       /*
+        * All Zen-based systems before Family 19h use the legacy
+        * DF Indirect Access (FICAA/FICAD) offsets.
+        */
+       if (boot_cpu_data.x86 < 0x19) {
+               df_cfg.flags.legacy_ficaa = true;
+               return;
+       }
+
+       /* All systems after Family 19h use the current offsets. */
+       if (boot_cpu_data.x86 > 0x19)
+               return;
+
+       /* Some Family 19h systems use the legacy offsets. */
+       switch (boot_cpu_data.x86_model) {
+       case 0x00 ... 0x0f:
+       case 0x20 ... 0x5f:
+              df_cfg.flags.legacy_ficaa = true;
+       }
+}
+
+/*
+ * This library provides functionality for AMD-based systems with a Data Fabric.
+ * The set of systems with a Data Fabric is equivalent to the set of Zen-based systems
+ * and the set of systems with the Scalable MCA feature at this time. However, these
+ * are technically independent things.
+ *
+ * It's possible to match on the PCI IDs of the Data Fabric devices, but this will be
+ * an ever expanding list. Instead, match on the SMCA and Zen features to cover all
+ * relevant systems.
+ */
+static const struct x86_cpu_id amd_atl_cpuids[] = {
+       X86_MATCH_FEATURE(X86_FEATURE_SMCA, NULL),
+       X86_MATCH_FEATURE(X86_FEATURE_ZEN, NULL),
+       { }
+};
+MODULE_DEVICE_TABLE(x86cpu, amd_atl_cpuids);
+
+static int __init amd_atl_init(void)
+{
+       if (!x86_match_cpu(amd_atl_cpuids))
+               return -ENODEV;
+
+       if (!amd_nb_num())
+               return -ENODEV;
+
+       check_for_legacy_df_access();
+
+       if (get_df_system_info())
+               return -ENODEV;
+
+       /* Increment this module's recount so that it can't be easily unloaded. */
+       __module_get(THIS_MODULE);
+       amd_atl_register_decoder(convert_umc_mca_addr_to_sys_addr);
+
+       pr_info("AMD Address Translation Library initialized");
+       return 0;
+}
+
+/*
+ * Exit function is only needed for testing and debug. Module unload must be
+ * forced to override refcount check.
+ */
+static void __exit amd_atl_exit(void)
+{
+       amd_atl_unregister_decoder();
+}
+
+module_init(amd_atl_init);
+module_exit(amd_atl_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ras/amd/atl/dehash.c b/drivers/ras/amd/atl/dehash.c
new file mode 100644 (file)
index 0000000..4ea4626
--- /dev/null
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD Address Translation Library
+ *
+ * dehash.c : Functions to account for hashing bits
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
+ */
+
+#include "internal.h"
+
+/*
+ * Verify the interleave bits are correct in the different interleaving
+ * settings.
+ *
+ * If @num_intlv_dies and/or @num_intlv_sockets are 1, it means the
+ * respective interleaving is disabled.
+ */
+static inline bool map_bits_valid(struct addr_ctx *ctx, u8 bit1, u8 bit2,
+                                 u8 num_intlv_dies, u8 num_intlv_sockets)
+{
+       if (!(ctx->map.intlv_bit_pos == bit1 || ctx->map.intlv_bit_pos == bit2)) {
+               pr_debug("Invalid interleave bit: %u", ctx->map.intlv_bit_pos);
+               return false;
+       }
+
+       if (ctx->map.num_intlv_dies > num_intlv_dies) {
+               pr_debug("Invalid number of interleave dies: %u", ctx->map.num_intlv_dies);
+               return false;
+       }
+
+       if (ctx->map.num_intlv_sockets > num_intlv_sockets) {
+               pr_debug("Invalid number of interleave sockets: %u", ctx->map.num_intlv_sockets);
+               return false;
+       }
+
+       return true;
+}
+
+static int df2_dehash_addr(struct addr_ctx *ctx)
+{
+       u8 hashed_bit, intlv_bit, intlv_bit_pos;
+
+       if (!map_bits_valid(ctx, 8, 9, 1, 1))
+               return -EINVAL;
+
+       intlv_bit_pos = ctx->map.intlv_bit_pos;
+       intlv_bit = !!(BIT_ULL(intlv_bit_pos) & ctx->ret_addr);
+
+       hashed_bit = intlv_bit;
+       hashed_bit ^= FIELD_GET(BIT_ULL(12), ctx->ret_addr);
+       hashed_bit ^= FIELD_GET(BIT_ULL(18), ctx->ret_addr);
+       hashed_bit ^= FIELD_GET(BIT_ULL(21), ctx->ret_addr);
+       hashed_bit ^= FIELD_GET(BIT_ULL(30), ctx->ret_addr);
+
+       if (hashed_bit != intlv_bit)
+               ctx->ret_addr ^= BIT_ULL(intlv_bit_pos);
+
+       return 0;
+}
+
+static int df3_dehash_addr(struct addr_ctx *ctx)
+{
+       bool hash_ctl_64k, hash_ctl_2M, hash_ctl_1G;
+       u8 hashed_bit, intlv_bit, intlv_bit_pos;
+
+       if (!map_bits_valid(ctx, 8, 9, 1, 1))
+               return -EINVAL;
+
+       hash_ctl_64k = FIELD_GET(DF3_HASH_CTL_64K, ctx->map.ctl);
+       hash_ctl_2M  = FIELD_GET(DF3_HASH_CTL_2M, ctx->map.ctl);
+       hash_ctl_1G  = FIELD_GET(DF3_HASH_CTL_1G, ctx->map.ctl);
+
+       intlv_bit_pos = ctx->map.intlv_bit_pos;
+       intlv_bit = !!(BIT_ULL(intlv_bit_pos) & ctx->ret_addr);
+
+       hashed_bit = intlv_bit;
+       hashed_bit ^= FIELD_GET(BIT_ULL(14), ctx->ret_addr);
+       hashed_bit ^= FIELD_GET(BIT_ULL(18), ctx->ret_addr) & hash_ctl_64k;
+       hashed_bit ^= FIELD_GET(BIT_ULL(23), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(32), ctx->ret_addr) & hash_ctl_1G;
+
+       if (hashed_bit != intlv_bit)
+               ctx->ret_addr ^= BIT_ULL(intlv_bit_pos);
+
+       /* Calculation complete for 2 channels. Continue for 4 and 8 channels. */
+       if (ctx->map.intlv_mode == DF3_COD4_2CHAN_HASH)
+               return 0;
+
+       intlv_bit = FIELD_GET(BIT_ULL(12), ctx->ret_addr);
+
+       hashed_bit = intlv_bit;
+       hashed_bit ^= FIELD_GET(BIT_ULL(16), ctx->ret_addr) & hash_ctl_64k;
+       hashed_bit ^= FIELD_GET(BIT_ULL(21), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(30), ctx->ret_addr) & hash_ctl_1G;
+
+       if (hashed_bit != intlv_bit)
+               ctx->ret_addr ^= BIT_ULL(12);
+
+       /* Calculation complete for 4 channels. Continue for 8 channels. */
+       if (ctx->map.intlv_mode == DF3_COD2_4CHAN_HASH)
+               return 0;
+
+       intlv_bit = FIELD_GET(BIT_ULL(13), ctx->ret_addr);
+
+       hashed_bit = intlv_bit;
+       hashed_bit ^= FIELD_GET(BIT_ULL(17), ctx->ret_addr) & hash_ctl_64k;
+       hashed_bit ^= FIELD_GET(BIT_ULL(22), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(31), ctx->ret_addr) & hash_ctl_1G;
+
+       if (hashed_bit != intlv_bit)
+               ctx->ret_addr ^= BIT_ULL(13);
+
+       return 0;
+}
+
+static int df3_6chan_dehash_addr(struct addr_ctx *ctx)
+{
+       u8 intlv_bit_pos = ctx->map.intlv_bit_pos;
+       u8 hashed_bit, intlv_bit, num_intlv_bits;
+       bool hash_ctl_2M, hash_ctl_1G;
+
+       if (ctx->map.intlv_mode != DF3_6CHAN) {
+               atl_debug_on_bad_intlv_mode(ctx);
+               return -EINVAL;
+       }
+
+       num_intlv_bits = ilog2(ctx->map.num_intlv_chan) + 1;
+
+       hash_ctl_2M = FIELD_GET(DF3_HASH_CTL_2M, ctx->map.ctl);
+       hash_ctl_1G = FIELD_GET(DF3_HASH_CTL_1G, ctx->map.ctl);
+
+       intlv_bit = !!(BIT_ULL(intlv_bit_pos) & ctx->ret_addr);
+
+       hashed_bit = intlv_bit;
+       hashed_bit ^= !!(BIT_ULL(intlv_bit_pos + num_intlv_bits) & ctx->ret_addr);
+       hashed_bit ^= FIELD_GET(BIT_ULL(23), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(32), ctx->ret_addr) & hash_ctl_1G;
+
+       if (hashed_bit != intlv_bit)
+               ctx->ret_addr ^= BIT_ULL(intlv_bit_pos);
+
+       intlv_bit_pos++;
+       intlv_bit = !!(BIT_ULL(intlv_bit_pos) & ctx->ret_addr);
+
+       hashed_bit = intlv_bit;
+       hashed_bit ^= FIELD_GET(BIT_ULL(21), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(30), ctx->ret_addr) & hash_ctl_1G;
+
+       if (hashed_bit != intlv_bit)
+               ctx->ret_addr ^= BIT_ULL(intlv_bit_pos);
+
+       intlv_bit_pos++;
+       intlv_bit = !!(BIT_ULL(intlv_bit_pos) & ctx->ret_addr);
+
+       hashed_bit = intlv_bit;
+       hashed_bit ^= FIELD_GET(BIT_ULL(22), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(31), ctx->ret_addr) & hash_ctl_1G;
+
+       if (hashed_bit != intlv_bit)
+               ctx->ret_addr ^= BIT_ULL(intlv_bit_pos);
+
+       return 0;
+}
+
+static int df4_dehash_addr(struct addr_ctx *ctx)
+{
+       bool hash_ctl_64k, hash_ctl_2M, hash_ctl_1G;
+       u8 hashed_bit, intlv_bit;
+
+       if (!map_bits_valid(ctx, 8, 8, 1, 2))
+               return -EINVAL;
+
+       hash_ctl_64k = FIELD_GET(DF4_HASH_CTL_64K, ctx->map.ctl);
+       hash_ctl_2M  = FIELD_GET(DF4_HASH_CTL_2M, ctx->map.ctl);
+       hash_ctl_1G  = FIELD_GET(DF4_HASH_CTL_1G, ctx->map.ctl);
+
+       intlv_bit = FIELD_GET(BIT_ULL(8), ctx->ret_addr);
+
+       hashed_bit = intlv_bit;
+       hashed_bit ^= FIELD_GET(BIT_ULL(16), ctx->ret_addr) & hash_ctl_64k;
+       hashed_bit ^= FIELD_GET(BIT_ULL(21), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(30), ctx->ret_addr) & hash_ctl_1G;
+
+       if (ctx->map.num_intlv_sockets == 1)
+               hashed_bit ^= FIELD_GET(BIT_ULL(14), ctx->ret_addr);
+
+       if (hashed_bit != intlv_bit)
+               ctx->ret_addr ^= BIT_ULL(8);
+
+       /*
+        * Hashing is possible with socket interleaving, so check the total number
+        * of channels in the system rather than DRAM map interleaving mode.
+        *
+        * Calculation complete for 2 channels. Continue for 4, 8, and 16 channels.
+        */
+       if (ctx->map.total_intlv_chan <= 2)
+               return 0;
+
+       intlv_bit = FIELD_GET(BIT_ULL(12), ctx->ret_addr);
+
+       hashed_bit = intlv_bit;
+       hashed_bit ^= FIELD_GET(BIT_ULL(17), ctx->ret_addr) & hash_ctl_64k;
+       hashed_bit ^= FIELD_GET(BIT_ULL(22), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(31), ctx->ret_addr) & hash_ctl_1G;
+
+       if (hashed_bit != intlv_bit)
+               ctx->ret_addr ^= BIT_ULL(12);
+
+       /* Calculation complete for 4 channels. Continue for 8 and 16 channels. */
+       if (ctx->map.total_intlv_chan <= 4)
+               return 0;
+
+       intlv_bit = FIELD_GET(BIT_ULL(13), ctx->ret_addr);
+
+       hashed_bit = intlv_bit;
+       hashed_bit ^= FIELD_GET(BIT_ULL(18), ctx->ret_addr) & hash_ctl_64k;
+       hashed_bit ^= FIELD_GET(BIT_ULL(23), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(32), ctx->ret_addr) & hash_ctl_1G;
+
+       if (hashed_bit != intlv_bit)
+               ctx->ret_addr ^= BIT_ULL(13);
+
+       /* Calculation complete for 8 channels. Continue for 16 channels. */
+       if (ctx->map.total_intlv_chan <= 8)
+               return 0;
+
+       intlv_bit = FIELD_GET(BIT_ULL(14), ctx->ret_addr);
+
+       hashed_bit = intlv_bit;
+       hashed_bit ^= FIELD_GET(BIT_ULL(19), ctx->ret_addr) & hash_ctl_64k;
+       hashed_bit ^= FIELD_GET(BIT_ULL(24), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(33), ctx->ret_addr) & hash_ctl_1G;
+
+       if (hashed_bit != intlv_bit)
+               ctx->ret_addr ^= BIT_ULL(14);
+
+       return 0;
+}
+
+static int df4p5_dehash_addr(struct addr_ctx *ctx)
+{
+       bool hash_ctl_64k, hash_ctl_2M, hash_ctl_1G, hash_ctl_1T;
+       u8 hashed_bit, intlv_bit;
+       u64 rehash_vector;
+
+       if (!map_bits_valid(ctx, 8, 8, 1, 2))
+               return -EINVAL;
+
+       hash_ctl_64k = FIELD_GET(DF4_HASH_CTL_64K, ctx->map.ctl);
+       hash_ctl_2M  = FIELD_GET(DF4_HASH_CTL_2M, ctx->map.ctl);
+       hash_ctl_1G  = FIELD_GET(DF4_HASH_CTL_1G, ctx->map.ctl);
+       hash_ctl_1T  = FIELD_GET(DF4p5_HASH_CTL_1T, ctx->map.ctl);
+
+       /*
+        * Generate a unique address to determine which bits
+        * need to be dehashed.
+        *
+        * Start with a contiguous bitmask for the total
+        * number of channels starting at bit 8.
+        *
+        * Then make a gap in the proper place based on
+        * interleave mode.
+        */
+       rehash_vector = ctx->map.total_intlv_chan - 1;
+       rehash_vector <<= 8;
+
+       if (ctx->map.intlv_mode == DF4p5_NPS2_4CHAN_1K_HASH ||
+           ctx->map.intlv_mode == DF4p5_NPS1_8CHAN_1K_HASH ||
+           ctx->map.intlv_mode == DF4p5_NPS1_16CHAN_1K_HASH)
+               rehash_vector = expand_bits(10, 2, rehash_vector);
+       else
+               rehash_vector = expand_bits(9, 3, rehash_vector);
+
+       if (rehash_vector & BIT_ULL(8)) {
+               intlv_bit = FIELD_GET(BIT_ULL(8), ctx->ret_addr);
+
+               hashed_bit = intlv_bit;
+               hashed_bit ^= FIELD_GET(BIT_ULL(16), ctx->ret_addr) & hash_ctl_64k;
+               hashed_bit ^= FIELD_GET(BIT_ULL(21), ctx->ret_addr) & hash_ctl_2M;
+               hashed_bit ^= FIELD_GET(BIT_ULL(30), ctx->ret_addr) & hash_ctl_1G;
+               hashed_bit ^= FIELD_GET(BIT_ULL(40), ctx->ret_addr) & hash_ctl_1T;
+
+               if (hashed_bit != intlv_bit)
+                       ctx->ret_addr ^= BIT_ULL(8);
+       }
+
+       if (rehash_vector & BIT_ULL(9)) {
+               intlv_bit = FIELD_GET(BIT_ULL(9), ctx->ret_addr);
+
+               hashed_bit = intlv_bit;
+               hashed_bit ^= FIELD_GET(BIT_ULL(17), ctx->ret_addr) & hash_ctl_64k;
+               hashed_bit ^= FIELD_GET(BIT_ULL(22), ctx->ret_addr) & hash_ctl_2M;
+               hashed_bit ^= FIELD_GET(BIT_ULL(31), ctx->ret_addr) & hash_ctl_1G;
+               hashed_bit ^= FIELD_GET(BIT_ULL(41), ctx->ret_addr) & hash_ctl_1T;
+
+               if (hashed_bit != intlv_bit)
+                       ctx->ret_addr ^= BIT_ULL(9);
+       }
+
+       if (rehash_vector & BIT_ULL(12)) {
+               intlv_bit = FIELD_GET(BIT_ULL(12), ctx->ret_addr);
+
+               hashed_bit = intlv_bit;
+               hashed_bit ^= FIELD_GET(BIT_ULL(18), ctx->ret_addr) & hash_ctl_64k;
+               hashed_bit ^= FIELD_GET(BIT_ULL(23), ctx->ret_addr) & hash_ctl_2M;
+               hashed_bit ^= FIELD_GET(BIT_ULL(32), ctx->ret_addr) & hash_ctl_1G;
+               hashed_bit ^= FIELD_GET(BIT_ULL(42), ctx->ret_addr) & hash_ctl_1T;
+
+               if (hashed_bit != intlv_bit)
+                       ctx->ret_addr ^= BIT_ULL(12);
+       }
+
+       if (rehash_vector & BIT_ULL(13)) {
+               intlv_bit = FIELD_GET(BIT_ULL(13), ctx->ret_addr);
+
+               hashed_bit = intlv_bit;
+               hashed_bit ^= FIELD_GET(BIT_ULL(19), ctx->ret_addr) & hash_ctl_64k;
+               hashed_bit ^= FIELD_GET(BIT_ULL(24), ctx->ret_addr) & hash_ctl_2M;
+               hashed_bit ^= FIELD_GET(BIT_ULL(33), ctx->ret_addr) & hash_ctl_1G;
+               hashed_bit ^= FIELD_GET(BIT_ULL(43), ctx->ret_addr) & hash_ctl_1T;
+
+               if (hashed_bit != intlv_bit)
+                       ctx->ret_addr ^= BIT_ULL(13);
+       }
+
+       if (rehash_vector & BIT_ULL(14)) {
+               intlv_bit = FIELD_GET(BIT_ULL(14), ctx->ret_addr);
+
+               hashed_bit = intlv_bit;
+               hashed_bit ^= FIELD_GET(BIT_ULL(20), ctx->ret_addr) & hash_ctl_64k;
+               hashed_bit ^= FIELD_GET(BIT_ULL(25), ctx->ret_addr) & hash_ctl_2M;
+               hashed_bit ^= FIELD_GET(BIT_ULL(34), ctx->ret_addr) & hash_ctl_1G;
+               hashed_bit ^= FIELD_GET(BIT_ULL(44), ctx->ret_addr) & hash_ctl_1T;
+
+               if (hashed_bit != intlv_bit)
+                       ctx->ret_addr ^= BIT_ULL(14);
+       }
+
+       return 0;
+}
+
+/*
+ * MI300 hash bits
+ *                                       4K 64K  2M  1G  1T  1T
+ * COH_ST_Select[0]    = XOR of addr{8,  12, 15, 22, 29, 36, 43}
+ * COH_ST_Select[1]    = XOR of addr{9,  13, 16, 23, 30, 37, 44}
+ * COH_ST_Select[2]    = XOR of addr{10, 14, 17, 24, 31, 38, 45}
+ * COH_ST_Select[3]    = XOR of addr{11,     18, 25, 32, 39, 46}
+ * COH_ST_Select[4]    = XOR of addr{14,     19, 26, 33, 40, 47} aka Stack
+ * DieID[0]            = XOR of addr{12,     20, 27, 34, 41    }
+ * DieID[1]            = XOR of addr{13,     21, 28, 35, 42    }
+ */
+static int mi300_dehash_addr(struct addr_ctx *ctx)
+{
+       bool hash_ctl_4k, hash_ctl_64k, hash_ctl_2M, hash_ctl_1G, hash_ctl_1T;
+       bool hashed_bit, intlv_bit, test_bit;
+       u8 num_intlv_bits, base_bit, i;
+
+       if (!map_bits_valid(ctx, 8, 8, 4, 1))
+               return -EINVAL;
+
+       hash_ctl_4k  = FIELD_GET(DF4p5_HASH_CTL_4K, ctx->map.ctl);
+       hash_ctl_64k = FIELD_GET(DF4_HASH_CTL_64K,  ctx->map.ctl);
+       hash_ctl_2M  = FIELD_GET(DF4_HASH_CTL_2M,   ctx->map.ctl);
+       hash_ctl_1G  = FIELD_GET(DF4_HASH_CTL_1G,   ctx->map.ctl);
+       hash_ctl_1T  = FIELD_GET(DF4p5_HASH_CTL_1T, ctx->map.ctl);
+
+       /* Channel bits */
+       num_intlv_bits = ilog2(ctx->map.num_intlv_chan);
+
+       for (i = 0; i < num_intlv_bits; i++) {
+               base_bit = 8 + i;
+
+               /* COH_ST_Select[4] jumps to a base bit of 14. */
+               if (i == 4)
+                       base_bit = 14;
+
+               intlv_bit = BIT_ULL(base_bit) & ctx->ret_addr;
+
+               hashed_bit = intlv_bit;
+
+               /* 4k hash bit only applies to the first 3 bits. */
+               if (i <= 2) {
+                       test_bit    = BIT_ULL(12 + i) & ctx->ret_addr;
+                       hashed_bit ^= test_bit & hash_ctl_4k;
+               }
+
+               /* Use temporary 'test_bit' value to avoid Sparse warnings. */
+               test_bit    = BIT_ULL(15 + i) & ctx->ret_addr;
+               hashed_bit ^= test_bit & hash_ctl_64k;
+               test_bit    = BIT_ULL(22 + i) & ctx->ret_addr;
+               hashed_bit ^= test_bit & hash_ctl_2M;
+               test_bit    = BIT_ULL(29 + i) & ctx->ret_addr;
+               hashed_bit ^= test_bit & hash_ctl_1G;
+               test_bit    = BIT_ULL(36 + i) & ctx->ret_addr;
+               hashed_bit ^= test_bit & hash_ctl_1T;
+               test_bit    = BIT_ULL(43 + i) & ctx->ret_addr;
+               hashed_bit ^= test_bit & hash_ctl_1T;
+
+               if (hashed_bit != intlv_bit)
+                       ctx->ret_addr ^= BIT_ULL(base_bit);
+       }
+
+       /* Die bits */
+       num_intlv_bits = ilog2(ctx->map.num_intlv_dies);
+
+       for (i = 0; i < num_intlv_bits; i++) {
+               base_bit = 12 + i;
+
+               intlv_bit = BIT_ULL(base_bit) & ctx->ret_addr;
+
+               hashed_bit = intlv_bit;
+
+               test_bit    = BIT_ULL(20 + i) & ctx->ret_addr;
+               hashed_bit ^= test_bit & hash_ctl_64k;
+               test_bit    = BIT_ULL(27 + i) & ctx->ret_addr;
+               hashed_bit ^= test_bit & hash_ctl_2M;
+               test_bit    = BIT_ULL(34 + i) & ctx->ret_addr;
+               hashed_bit ^= test_bit & hash_ctl_1G;
+               test_bit    = BIT_ULL(41 + i) & ctx->ret_addr;
+               hashed_bit ^= test_bit & hash_ctl_1T;
+
+               if (hashed_bit != intlv_bit)
+                       ctx->ret_addr ^= BIT_ULL(base_bit);
+       }
+
+       return 0;
+}
+
+int dehash_address(struct addr_ctx *ctx)
+{
+       switch (ctx->map.intlv_mode) {
+       /* No hashing cases. */
+       case NONE:
+       case NOHASH_2CHAN:
+       case NOHASH_4CHAN:
+       case NOHASH_8CHAN:
+       case NOHASH_16CHAN:
+       case NOHASH_32CHAN:
+       /* Hashing bits handled earlier during CS ID calculation. */
+       case DF4_NPS4_3CHAN_HASH:
+       case DF4_NPS2_5CHAN_HASH:
+       case DF4_NPS2_6CHAN_HASH:
+       case DF4_NPS1_10CHAN_HASH:
+       case DF4_NPS1_12CHAN_HASH:
+       case DF4p5_NPS2_6CHAN_1K_HASH:
+       case DF4p5_NPS2_6CHAN_2K_HASH:
+       case DF4p5_NPS1_10CHAN_1K_HASH:
+       case DF4p5_NPS1_10CHAN_2K_HASH:
+       case DF4p5_NPS1_12CHAN_1K_HASH:
+       case DF4p5_NPS1_12CHAN_2K_HASH:
+       case DF4p5_NPS0_24CHAN_1K_HASH:
+       case DF4p5_NPS0_24CHAN_2K_HASH:
+       /* No hash physical address bits, so nothing to do. */
+       case DF4p5_NPS4_3CHAN_1K_HASH:
+       case DF4p5_NPS4_3CHAN_2K_HASH:
+       case DF4p5_NPS2_5CHAN_1K_HASH:
+       case DF4p5_NPS2_5CHAN_2K_HASH:
+               return 0;
+
+       case DF2_2CHAN_HASH:
+               return df2_dehash_addr(ctx);
+
+       case DF3_COD4_2CHAN_HASH:
+       case DF3_COD2_4CHAN_HASH:
+       case DF3_COD1_8CHAN_HASH:
+               return df3_dehash_addr(ctx);
+
+       case DF3_6CHAN:
+               return df3_6chan_dehash_addr(ctx);
+
+       case DF4_NPS4_2CHAN_HASH:
+       case DF4_NPS2_4CHAN_HASH:
+       case DF4_NPS1_8CHAN_HASH:
+               return df4_dehash_addr(ctx);
+
+       case DF4p5_NPS4_2CHAN_1K_HASH:
+       case DF4p5_NPS4_2CHAN_2K_HASH:
+       case DF4p5_NPS2_4CHAN_2K_HASH:
+       case DF4p5_NPS2_4CHAN_1K_HASH:
+       case DF4p5_NPS1_8CHAN_1K_HASH:
+       case DF4p5_NPS1_8CHAN_2K_HASH:
+       case DF4p5_NPS1_16CHAN_1K_HASH:
+       case DF4p5_NPS1_16CHAN_2K_HASH:
+               return df4p5_dehash_addr(ctx);
+
+       case MI3_HASH_8CHAN:
+       case MI3_HASH_16CHAN:
+       case MI3_HASH_32CHAN:
+               return mi300_dehash_addr(ctx);
+
+       default:
+               atl_debug_on_bad_intlv_mode(ctx);
+               return -EINVAL;
+       }
+}
diff --git a/drivers/ras/amd/atl/denormalize.c b/drivers/ras/amd/atl/denormalize.c
new file mode 100644 (file)
index 0000000..e279224
--- /dev/null
@@ -0,0 +1,718 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD Address Translation Library
+ *
+ * denormalize.c : Functions to account for interleaving bits
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
+ */
+
+#include "internal.h"
+
+/*
+ * Returns the Destination Fabric ID. This is the first (lowest)
+ * COH_ST Fabric ID used within a DRAM Address map.
+ */
+static u16 get_dst_fabric_id(struct addr_ctx *ctx)
+{
+       switch (df_cfg.rev) {
+       case DF2:       return FIELD_GET(DF2_DST_FABRIC_ID,     ctx->map.limit);
+       case DF3:       return FIELD_GET(DF3_DST_FABRIC_ID,     ctx->map.limit);
+       case DF3p5:     return FIELD_GET(DF3p5_DST_FABRIC_ID,   ctx->map.limit);
+       case DF4:       return FIELD_GET(DF4_DST_FABRIC_ID,     ctx->map.ctl);
+       case DF4p5:     return FIELD_GET(DF4p5_DST_FABRIC_ID,   ctx->map.ctl);
+       default:
+                       atl_debug_on_bad_df_rev();
+                       return 0;
+       }
+}
+
+/*
+ * Make a contiguous gap in address for N bits starting at bit P.
+ *
+ * Example:
+ * address bits:               [20:0]
+ * # of interleave bits    (n):        3
+ * starting interleave bit (p):        8
+ *
+ * expanded address bits:      [20+n : n+p][n+p-1 : p][p-1 : 0]
+ *                             [23   :  11][10    : 8][7   : 0]
+ */
+static u64 make_space_for_coh_st_id_at_intlv_bit(struct addr_ctx *ctx)
+{
+       return expand_bits(ctx->map.intlv_bit_pos,
+                          ctx->map.total_intlv_bits,
+                          ctx->ret_addr);
+}
+
+/*
+ * Make two gaps in address for N bits.
+ * First gap is a single bit at bit P.
+ * Second gap is the remaining N-1 bits at bit 12.
+ *
+ * Example:
+ * address bits:               [20:0]
+ * # of interleave bits    (n):        3
+ * starting interleave bit (p):        8
+ *
+ * First gap
+ * expanded address bits:      [20+1 : p+1][p][p-1 : 0]
+ *                             [21   :   9][8][7   : 0]
+ *
+ * Second gap uses result from first.
+ *                             r = n - 1; remaining interleave bits
+ * expanded address bits:      [21+r : 12+r][12+r-1: 12][11 : 0]
+ *                             [23   :   14][13    : 12][11 : 0]
+ */
+static u64 make_space_for_coh_st_id_split_2_1(struct addr_ctx *ctx)
+{
+       /* Make a single space at the interleave bit. */
+       u64 denorm_addr = expand_bits(ctx->map.intlv_bit_pos, 1, ctx->ret_addr);
+
+       /* Done if there's only a single interleave bit. */
+       if (ctx->map.total_intlv_bits <= 1)
+               return denorm_addr;
+
+       /* Make spaces for the remaining interleave bits starting at bit 12. */
+       return expand_bits(12, ctx->map.total_intlv_bits - 1, denorm_addr);
+}
+
+/*
+ * Make space for CS ID at bits [14:8] as follows:
+ *
+ * 8 channels  -> bits [10:8]
+ * 16 channels -> bits [11:8]
+ * 32 channels -> bits [14,11:8]
+ *
+ * 1 die       -> N/A
+ * 2 dies      -> bit  [12]
+ * 4 dies      -> bits [13:12]
+ */
+static u64 make_space_for_coh_st_id_mi300(struct addr_ctx *ctx)
+{
+       u8 num_intlv_bits = ilog2(ctx->map.num_intlv_chan);
+       u64 denorm_addr;
+
+       if (ctx->map.intlv_bit_pos != 8) {
+               pr_debug("Invalid interleave bit: %u", ctx->map.intlv_bit_pos);
+               return ~0ULL;
+       }
+
+       /* Channel bits. Covers up to 4 bits at [11:8]. */
+       denorm_addr = expand_bits(8, min(num_intlv_bits, 4), ctx->ret_addr);
+
+       /* Die bits. Always starts at [12]. */
+       denorm_addr = expand_bits(12, ilog2(ctx->map.num_intlv_dies), denorm_addr);
+
+       /* Additional channel bit at [14]. */
+       if (num_intlv_bits > 4)
+               denorm_addr = expand_bits(14, 1, denorm_addr);
+
+       return denorm_addr;
+}
+
+/*
+ * Take the current calculated address and shift enough bits in the middle
+ * to make a gap where the interleave bits will be inserted.
+ */
+static u64 make_space_for_coh_st_id(struct addr_ctx *ctx)
+{
+       switch (ctx->map.intlv_mode) {
+       case NOHASH_2CHAN:
+       case NOHASH_4CHAN:
+       case NOHASH_8CHAN:
+       case NOHASH_16CHAN:
+       case NOHASH_32CHAN:
+       case DF2_2CHAN_HASH:
+               return make_space_for_coh_st_id_at_intlv_bit(ctx);
+
+       case DF3_COD4_2CHAN_HASH:
+       case DF3_COD2_4CHAN_HASH:
+       case DF3_COD1_8CHAN_HASH:
+       case DF4_NPS4_2CHAN_HASH:
+       case DF4_NPS2_4CHAN_HASH:
+       case DF4_NPS1_8CHAN_HASH:
+       case DF4p5_NPS4_2CHAN_1K_HASH:
+       case DF4p5_NPS4_2CHAN_2K_HASH:
+       case DF4p5_NPS2_4CHAN_2K_HASH:
+       case DF4p5_NPS1_8CHAN_2K_HASH:
+       case DF4p5_NPS1_16CHAN_2K_HASH:
+               return make_space_for_coh_st_id_split_2_1(ctx);
+
+       case MI3_HASH_8CHAN:
+       case MI3_HASH_16CHAN:
+       case MI3_HASH_32CHAN:
+               return make_space_for_coh_st_id_mi300(ctx);
+
+       default:
+               atl_debug_on_bad_intlv_mode(ctx);
+               return ~0ULL;
+       }
+}
+
+static u16 get_coh_st_id_df2(struct addr_ctx *ctx)
+{
+       u8 num_socket_intlv_bits = ilog2(ctx->map.num_intlv_sockets);
+       u8 num_die_intlv_bits = ilog2(ctx->map.num_intlv_dies);
+       u8 num_intlv_bits;
+       u16 coh_st_id, mask;
+
+       coh_st_id = ctx->coh_st_fabric_id - get_dst_fabric_id(ctx);
+
+       /* Channel interleave bits */
+       num_intlv_bits = order_base_2(ctx->map.num_intlv_chan);
+       mask = GENMASK(num_intlv_bits - 1, 0);
+       coh_st_id &= mask;
+
+       /* Die interleave bits */
+       if (num_die_intlv_bits) {
+               u16 die_bits;
+
+               mask = GENMASK(num_die_intlv_bits - 1, 0);
+               die_bits = ctx->coh_st_fabric_id & df_cfg.die_id_mask;
+               die_bits >>= df_cfg.die_id_shift;
+
+               coh_st_id |= (die_bits & mask) << num_intlv_bits;
+               num_intlv_bits += num_die_intlv_bits;
+       }
+
+       /* Socket interleave bits */
+       if (num_socket_intlv_bits) {
+               u16 socket_bits;
+
+               mask = GENMASK(num_socket_intlv_bits - 1, 0);
+               socket_bits = ctx->coh_st_fabric_id & df_cfg.socket_id_mask;
+               socket_bits >>= df_cfg.socket_id_shift;
+
+               coh_st_id |= (socket_bits & mask) << num_intlv_bits;
+       }
+
+       return coh_st_id;
+}
+
+static u16 get_coh_st_id_df4(struct addr_ctx *ctx)
+{
+       /*
+        * Start with the original component mask and the number of interleave
+        * bits for the channels in this map.
+        */
+       u8 num_intlv_bits = ilog2(ctx->map.num_intlv_chan);
+       u16 mask = df_cfg.component_id_mask;
+
+       u16 socket_bits;
+
+       /* Set the derived Coherent Station ID to the input Coherent Station Fabric ID. */
+       u16 coh_st_id = ctx->coh_st_fabric_id & mask;
+
+       /*
+        * Subtract the "base" Destination Fabric ID.
+        * This accounts for systems with disabled Coherent Stations.
+        */
+       coh_st_id -= get_dst_fabric_id(ctx) & mask;
+
+       /*
+        * Generate and use a new mask based on the number of bits
+        * needed for channel interleaving in this map.
+        */
+       mask = GENMASK(num_intlv_bits - 1, 0);
+       coh_st_id &= mask;
+
+       /* Done if socket interleaving is not enabled. */
+       if (ctx->map.num_intlv_sockets <= 1)
+               return coh_st_id;
+
+       /*
+        * Figure out how many bits are needed for the number of
+        * interleaved sockets. And shift the derived Coherent Station ID to account
+        * for these.
+        */
+       num_intlv_bits = ilog2(ctx->map.num_intlv_sockets);
+       coh_st_id <<= num_intlv_bits;
+
+       /* Generate a new mask for the socket interleaving bits. */
+       mask = GENMASK(num_intlv_bits - 1, 0);
+
+       /* Get the socket interleave bits from the original Coherent Station Fabric ID. */
+       socket_bits = (ctx->coh_st_fabric_id & df_cfg.socket_id_mask) >> df_cfg.socket_id_shift;
+
+       /* Apply the appropriate socket bits to the derived Coherent Station ID. */
+       coh_st_id |= socket_bits & mask;
+
+       return coh_st_id;
+}
+
+/*
+ * MI300 hash has:
+ * (C)hannel[3:0]      = coh_st_id[3:0]
+ * (S)tack[0]          = coh_st_id[4]
+ * (D)ie[1:0]          = coh_st_id[6:5]
+ *
+ * Hashed coh_st_id is swizzled so that Stack bit is at the end.
+ * coh_st_id = SDDCCCC
+ */
+static u16 get_coh_st_id_mi300(struct addr_ctx *ctx)
+{
+       u8 channel_bits, die_bits, stack_bit;
+       u16 die_id;
+
+       /* Subtract the "base" Destination Fabric ID. */
+       ctx->coh_st_fabric_id -= get_dst_fabric_id(ctx);
+
+       die_id = (ctx->coh_st_fabric_id & df_cfg.die_id_mask) >> df_cfg.die_id_shift;
+
+       channel_bits    = FIELD_GET(GENMASK(3, 0), ctx->coh_st_fabric_id);
+       stack_bit       = FIELD_GET(BIT(4), ctx->coh_st_fabric_id) << 6;
+       die_bits        = die_id << 4;
+
+       return stack_bit | die_bits | channel_bits;
+}
+
+/*
+ * Derive the correct Coherent Station ID that represents the interleave bits
+ * used within the system physical address. This accounts for the
+ * interleave mode, number of interleaved channels/dies/sockets, and
+ * other system/mode-specific bit swizzling.
+ *
+ * Returns:    Coherent Station ID on success.
+ *             All bits set on error.
+ */
+static u16 calculate_coh_st_id(struct addr_ctx *ctx)
+{
+       switch (ctx->map.intlv_mode) {
+       case NOHASH_2CHAN:
+       case NOHASH_4CHAN:
+       case NOHASH_8CHAN:
+       case NOHASH_16CHAN:
+       case NOHASH_32CHAN:
+       case DF3_COD4_2CHAN_HASH:
+       case DF3_COD2_4CHAN_HASH:
+       case DF3_COD1_8CHAN_HASH:
+       case DF2_2CHAN_HASH:
+               return get_coh_st_id_df2(ctx);
+
+       case DF4_NPS4_2CHAN_HASH:
+       case DF4_NPS2_4CHAN_HASH:
+       case DF4_NPS1_8CHAN_HASH:
+       case DF4p5_NPS4_2CHAN_1K_HASH:
+       case DF4p5_NPS4_2CHAN_2K_HASH:
+       case DF4p5_NPS2_4CHAN_2K_HASH:
+       case DF4p5_NPS1_8CHAN_2K_HASH:
+       case DF4p5_NPS1_16CHAN_2K_HASH:
+               return get_coh_st_id_df4(ctx);
+
+       case MI3_HASH_8CHAN:
+       case MI3_HASH_16CHAN:
+       case MI3_HASH_32CHAN:
+               return get_coh_st_id_mi300(ctx);
+
+       /* COH_ST ID is simply the COH_ST Fabric ID adjusted by the Destination Fabric ID. */
+       case DF4p5_NPS2_4CHAN_1K_HASH:
+       case DF4p5_NPS1_8CHAN_1K_HASH:
+       case DF4p5_NPS1_16CHAN_1K_HASH:
+               return ctx->coh_st_fabric_id - get_dst_fabric_id(ctx);
+
+       default:
+               atl_debug_on_bad_intlv_mode(ctx);
+               return ~0;
+       }
+}
+
+static u64 insert_coh_st_id_at_intlv_bit(struct addr_ctx *ctx, u64 denorm_addr, u16 coh_st_id)
+{
+       return denorm_addr | (coh_st_id << ctx->map.intlv_bit_pos);
+}
+
+static u64 insert_coh_st_id_split_2_1(struct addr_ctx *ctx, u64 denorm_addr, u16 coh_st_id)
+{
+       /* Insert coh_st_id[0] at the interleave bit. */
+       denorm_addr |= (coh_st_id & BIT(0)) << ctx->map.intlv_bit_pos;
+
+       /* Insert coh_st_id[2:1] at bit 12. */
+       denorm_addr |= (coh_st_id & GENMASK(2, 1)) << 11;
+
+       return denorm_addr;
+}
+
+static u64 insert_coh_st_id_split_2_2(struct addr_ctx *ctx, u64 denorm_addr, u16 coh_st_id)
+{
+       /* Insert coh_st_id[1:0] at bit 8. */
+       denorm_addr |= (coh_st_id & GENMASK(1, 0)) << 8;
+
+       /*
+        * Insert coh_st_id[n:2] at bit 12. 'n' could be 2 or 3.
+        * Grab both because bit 3 will be clear if unused.
+        */
+       denorm_addr |= (coh_st_id & GENMASK(3, 2)) << 10;
+
+       return denorm_addr;
+}
+
+static u64 insert_coh_st_id(struct addr_ctx *ctx, u64 denorm_addr, u16 coh_st_id)
+{
+       switch (ctx->map.intlv_mode) {
+       case NOHASH_2CHAN:
+       case NOHASH_4CHAN:
+       case NOHASH_8CHAN:
+       case NOHASH_16CHAN:
+       case NOHASH_32CHAN:
+       case MI3_HASH_8CHAN:
+       case MI3_HASH_16CHAN:
+       case MI3_HASH_32CHAN:
+       case DF2_2CHAN_HASH:
+               return insert_coh_st_id_at_intlv_bit(ctx, denorm_addr, coh_st_id);
+
+       case DF3_COD4_2CHAN_HASH:
+       case DF3_COD2_4CHAN_HASH:
+       case DF3_COD1_8CHAN_HASH:
+       case DF4_NPS4_2CHAN_HASH:
+       case DF4_NPS2_4CHAN_HASH:
+       case DF4_NPS1_8CHAN_HASH:
+       case DF4p5_NPS4_2CHAN_1K_HASH:
+       case DF4p5_NPS4_2CHAN_2K_HASH:
+       case DF4p5_NPS2_4CHAN_2K_HASH:
+       case DF4p5_NPS1_8CHAN_2K_HASH:
+       case DF4p5_NPS1_16CHAN_2K_HASH:
+               return insert_coh_st_id_split_2_1(ctx, denorm_addr, coh_st_id);
+
+       case DF4p5_NPS2_4CHAN_1K_HASH:
+       case DF4p5_NPS1_8CHAN_1K_HASH:
+       case DF4p5_NPS1_16CHAN_1K_HASH:
+               return insert_coh_st_id_split_2_2(ctx, denorm_addr, coh_st_id);
+
+       default:
+               atl_debug_on_bad_intlv_mode(ctx);
+               return ~0ULL;
+       }
+}
+
+/*
+ * MI300 systems have a fixed, hardware-defined physical-to-logical
+ * Coherent Station mapping. The Remap registers are not used.
+ */
+static const u16 phy_to_log_coh_st_map_mi300[] = {
+       12, 13, 14, 15,
+        8,  9, 10, 11,
+        4,  5,  6,  7,
+        0,  1,  2,  3,
+       28, 29, 30, 31,
+       24, 25, 26, 27,
+       20, 21, 22, 23,
+       16, 17, 18, 19,
+};
+
+static u16 get_logical_coh_st_fabric_id_mi300(struct addr_ctx *ctx)
+{
+       if (ctx->inst_id >= ARRAY_SIZE(phy_to_log_coh_st_map_mi300)) {
+               atl_debug(ctx, "Instance ID out of range");
+               return ~0;
+       }
+
+       return phy_to_log_coh_st_map_mi300[ctx->inst_id] | (ctx->node_id << df_cfg.node_id_shift);
+}
+
+static u16 get_logical_coh_st_fabric_id(struct addr_ctx *ctx)
+{
+       u16 component_id, log_fabric_id;
+
+       /* Start with the physical COH_ST Fabric ID. */
+       u16 phys_fabric_id = ctx->coh_st_fabric_id;
+
+       if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous)
+               return get_logical_coh_st_fabric_id_mi300(ctx);
+
+       /* Skip logical ID lookup if remapping is disabled. */
+       if (!FIELD_GET(DF4_REMAP_EN, ctx->map.ctl) &&
+           ctx->map.intlv_mode != DF3_6CHAN)
+               return phys_fabric_id;
+
+       /* Mask off the Node ID bits to get the "local" Component ID. */
+       component_id = phys_fabric_id & df_cfg.component_id_mask;
+
+       /*
+        * Search the list of logical Component IDs for the one that
+        * matches this physical Component ID.
+        */
+       for (log_fabric_id = 0; log_fabric_id < MAX_COH_ST_CHANNELS; log_fabric_id++) {
+               if (ctx->map.remap_array[log_fabric_id] == component_id)
+                       break;
+       }
+
+       if (log_fabric_id == MAX_COH_ST_CHANNELS)
+               atl_debug(ctx, "COH_ST remap entry not found for 0x%x",
+                         log_fabric_id);
+
+       /* Get the Node ID bits from the physical and apply to the logical. */
+       return (phys_fabric_id & df_cfg.node_id_mask) | log_fabric_id;
+}
+
+static int denorm_addr_common(struct addr_ctx *ctx)
+{
+       u64 denorm_addr;
+       u16 coh_st_id;
+
+       /*
+        * Convert the original physical COH_ST Fabric ID to a logical value.
+        * This is required for non-power-of-two and other interleaving modes.
+        */
+       ctx->coh_st_fabric_id = get_logical_coh_st_fabric_id(ctx);
+
+       denorm_addr = make_space_for_coh_st_id(ctx);
+       coh_st_id = calculate_coh_st_id(ctx);
+       ctx->ret_addr = insert_coh_st_id(ctx, denorm_addr, coh_st_id);
+       return 0;
+}
+
+static int denorm_addr_df3_6chan(struct addr_ctx *ctx)
+{
+       u16 coh_st_id = ctx->coh_st_fabric_id & df_cfg.component_id_mask;
+       u8 total_intlv_bits = ctx->map.total_intlv_bits;
+       u8 low_bit, intlv_bit = ctx->map.intlv_bit_pos;
+       u64 msb_intlv_bits, temp_addr_a, temp_addr_b;
+       u8 np2_bits = ctx->map.np2_bits;
+
+       if (ctx->map.intlv_mode != DF3_6CHAN)
+               return -EINVAL;
+
+       /*
+        * 'np2_bits' holds the number of bits needed to cover the
+        * amount of memory (rounded up) in this map using 64K chunks.
+        *
+        * Example:
+        * Total memory in map:                 6GB
+        * Rounded up to next power-of-2:       8GB
+        * Number of 64K chunks:                0x20000
+        * np2_bits = log2(# of chunks):        17
+        *
+        * Get the two most-significant interleave bits from the
+        * input address based on the following:
+        *
+        * [15 + np2_bits - total_intlv_bits : 14 + np2_bits - total_intlv_bits]
+        */
+       low_bit = 14 + np2_bits - total_intlv_bits;
+       msb_intlv_bits = ctx->ret_addr >> low_bit;
+       msb_intlv_bits &= 0x3;
+
+       /*
+        * If MSB are 11b, then logical COH_ST ID is 6 or 7.
+        * Need to adjust based on the mod3 result.
+        */
+       if (msb_intlv_bits == 3) {
+               u8 addr_mod, phys_addr_msb, msb_coh_st_id;
+
+               /* Get the remaining interleave bits from the input address. */
+               temp_addr_b = GENMASK_ULL(low_bit - 1, intlv_bit) & ctx->ret_addr;
+               temp_addr_b >>= intlv_bit;
+
+               /* Calculate the logical COH_ST offset based on mod3. */
+               addr_mod = temp_addr_b % 3;
+
+               /* Get COH_ST ID bits [2:1]. */
+               msb_coh_st_id = (coh_st_id >> 1) & 0x3;
+
+               /* Get the bit that starts the physical address bits. */
+               phys_addr_msb = (intlv_bit + np2_bits + 1);
+               phys_addr_msb &= BIT(0);
+               phys_addr_msb++;
+               phys_addr_msb *= 3 - addr_mod + msb_coh_st_id;
+               phys_addr_msb %= 3;
+
+               /* Move the physical address MSB to the correct place. */
+               temp_addr_b |= phys_addr_msb << (low_bit - total_intlv_bits - intlv_bit);
+
+               /* Generate a new COH_ST ID as follows: coh_st_id = [1, 1, coh_st_id[0]] */
+               coh_st_id &= BIT(0);
+               coh_st_id |= GENMASK(2, 1);
+       } else {
+               temp_addr_b = GENMASK_ULL(63, intlv_bit) & ctx->ret_addr;
+               temp_addr_b >>= intlv_bit;
+       }
+
+       temp_addr_a = GENMASK_ULL(intlv_bit - 1, 0) & ctx->ret_addr;
+       temp_addr_b <<= intlv_bit + total_intlv_bits;
+
+       ctx->ret_addr = temp_addr_a | temp_addr_b;
+       ctx->ret_addr |= coh_st_id << intlv_bit;
+       return 0;
+}
+
+static int denorm_addr_df4_np2(struct addr_ctx *ctx)
+{
+       bool hash_ctl_64k, hash_ctl_2M, hash_ctl_1G;
+       u16 group, group_offset, log_coh_st_offset;
+       unsigned int mod_value, shift_value;
+       u16 mask = df_cfg.component_id_mask;
+       u64 temp_addr_a, temp_addr_b;
+       bool hash_pa8, hashed_bit;
+
+       switch (ctx->map.intlv_mode) {
+       case DF4_NPS4_3CHAN_HASH:
+               mod_value       = 3;
+               shift_value     = 13;
+               break;
+       case DF4_NPS2_6CHAN_HASH:
+               mod_value       = 3;
+               shift_value     = 12;
+               break;
+       case DF4_NPS1_12CHAN_HASH:
+               mod_value       = 3;
+               shift_value     = 11;
+               break;
+       case DF4_NPS2_5CHAN_HASH:
+               mod_value       = 5;
+               shift_value     = 13;
+               break;
+       case DF4_NPS1_10CHAN_HASH:
+               mod_value       = 5;
+               shift_value     = 12;
+               break;
+       default:
+               atl_debug_on_bad_intlv_mode(ctx);
+               return -EINVAL;
+       };
+
+       if (ctx->map.num_intlv_sockets == 1) {
+               hash_pa8        = BIT_ULL(shift_value) & ctx->ret_addr;
+               temp_addr_a     = remove_bits(shift_value, shift_value, ctx->ret_addr);
+       } else {
+               hash_pa8        = ctx->coh_st_fabric_id & df_cfg.socket_id_mask;
+               temp_addr_a     = ctx->ret_addr;
+       }
+
+       /* Make a gap for the real bit [8]. */
+       temp_addr_a = expand_bits(8, 1, temp_addr_a);
+
+       /* Make an additional gap for bits [13:12], as appropriate.*/
+       if (ctx->map.intlv_mode == DF4_NPS2_6CHAN_HASH ||
+           ctx->map.intlv_mode == DF4_NPS1_10CHAN_HASH) {
+               temp_addr_a = expand_bits(13, 1, temp_addr_a);
+       } else if (ctx->map.intlv_mode == DF4_NPS1_12CHAN_HASH) {
+               temp_addr_a = expand_bits(12, 2, temp_addr_a);
+       }
+
+       /* Keep bits [13:0]. */
+       temp_addr_a &= GENMASK_ULL(13, 0);
+
+       /* Get the appropriate high bits. */
+       shift_value += 1 - ilog2(ctx->map.num_intlv_sockets);
+       temp_addr_b = GENMASK_ULL(63, shift_value) & ctx->ret_addr;
+       temp_addr_b >>= shift_value;
+       temp_addr_b *= mod_value;
+
+       /*
+        * Coherent Stations are divided into groups.
+        *
+        * Multiples of 3 (mod3) are divided into quadrants.
+        * e.g. NP4_3CHAN ->    [0, 1, 2] [6, 7, 8]
+        *                      [3, 4, 5] [9, 10, 11]
+        *
+        * Multiples of 5 (mod5) are divided into sides.
+        * e.g. NP2_5CHAN ->    [0, 1, 2, 3, 4] [5, 6, 7, 8, 9]
+        */
+
+        /*
+         * Calculate the logical offset for the COH_ST within its DRAM Address map.
+         * e.g. if map includes [5, 6, 7, 8, 9] and target instance is '8', then
+         *      log_coh_st_offset = 8 - 5 = 3
+         */
+       log_coh_st_offset = (ctx->coh_st_fabric_id & mask) - (get_dst_fabric_id(ctx) & mask);
+
+       /*
+        * Figure out the group number.
+        *
+        * Following above example,
+        * log_coh_st_offset = 3
+        * mod_value = 5
+        * group = 3 / 5 = 0
+        */
+       group = log_coh_st_offset / mod_value;
+
+       /*
+        * Figure out the offset within the group.
+        *
+        * Following above example,
+        * log_coh_st_offset = 3
+        * mod_value = 5
+        * group_offset = 3 % 5 = 3
+        */
+       group_offset = log_coh_st_offset % mod_value;
+
+       /* Adjust group_offset if the hashed bit [8] is set. */
+       if (hash_pa8) {
+               if (!group_offset)
+                       group_offset = mod_value - 1;
+               else
+                       group_offset--;
+       }
+
+       /* Add in the group offset to the high bits. */
+       temp_addr_b += group_offset;
+
+       /* Shift the high bits to the proper starting position. */
+       temp_addr_b <<= 14;
+
+       /* Combine the high and low bits together. */
+       ctx->ret_addr = temp_addr_a | temp_addr_b;
+
+       /* Account for hashing here instead of in dehash_address(). */
+       hash_ctl_64k    = FIELD_GET(DF4_HASH_CTL_64K, ctx->map.ctl);
+       hash_ctl_2M     = FIELD_GET(DF4_HASH_CTL_2M, ctx->map.ctl);
+       hash_ctl_1G     = FIELD_GET(DF4_HASH_CTL_1G, ctx->map.ctl);
+
+       hashed_bit = !!hash_pa8;
+       hashed_bit ^= FIELD_GET(BIT_ULL(14), ctx->ret_addr);
+       hashed_bit ^= FIELD_GET(BIT_ULL(16), ctx->ret_addr) & hash_ctl_64k;
+       hashed_bit ^= FIELD_GET(BIT_ULL(21), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(30), ctx->ret_addr) & hash_ctl_1G;
+
+       ctx->ret_addr |= hashed_bit << 8;
+
+       /* Done for 3 and 5 channel. */
+       if (ctx->map.intlv_mode == DF4_NPS4_3CHAN_HASH ||
+           ctx->map.intlv_mode == DF4_NPS2_5CHAN_HASH)
+               return 0;
+
+       /* Select the proper 'group' bit to use for Bit 13. */
+       if (ctx->map.intlv_mode == DF4_NPS1_12CHAN_HASH)
+               hashed_bit = !!(group & BIT(1));
+       else
+               hashed_bit = group & BIT(0);
+
+       hashed_bit ^= FIELD_GET(BIT_ULL(18), ctx->ret_addr) & hash_ctl_64k;
+       hashed_bit ^= FIELD_GET(BIT_ULL(23), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(32), ctx->ret_addr) & hash_ctl_1G;
+
+       ctx->ret_addr |= hashed_bit << 13;
+
+       /* Done for 6 and 10 channel. */
+       if (ctx->map.intlv_mode != DF4_NPS1_12CHAN_HASH)
+               return 0;
+
+       hashed_bit = group & BIT(0);
+       hashed_bit ^= FIELD_GET(BIT_ULL(17), ctx->ret_addr) & hash_ctl_64k;
+       hashed_bit ^= FIELD_GET(BIT_ULL(22), ctx->ret_addr) & hash_ctl_2M;
+       hashed_bit ^= FIELD_GET(BIT_ULL(31), ctx->ret_addr) & hash_ctl_1G;
+
+       ctx->ret_addr |= hashed_bit << 12;
+       return 0;
+}
+
+int denormalize_address(struct addr_ctx *ctx)
+{
+       switch (ctx->map.intlv_mode) {
+       case NONE:
+               return 0;
+       case DF4_NPS4_3CHAN_HASH:
+       case DF4_NPS2_6CHAN_HASH:
+       case DF4_NPS1_12CHAN_HASH:
+       case DF4_NPS2_5CHAN_HASH:
+       case DF4_NPS1_10CHAN_HASH:
+               return denorm_addr_df4_np2(ctx);
+       case DF3_6CHAN:
+               return denorm_addr_df3_6chan(ctx);
+       default:
+               return denorm_addr_common(ctx);
+       }
+}
diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h
new file mode 100644 (file)
index 0000000..5de69e0
--- /dev/null
@@ -0,0 +1,306 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AMD Address Translation Library
+ *
+ * internal.h : Helper functions and common defines
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
+ */
+
+#ifndef __AMD_ATL_INTERNAL_H__
+#define __AMD_ATL_INTERNAL_H__
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/ras.h>
+
+#include <asm/amd_nb.h>
+
+#include "reg_fields.h"
+
+/* Maximum possible number of Coherent Stations within a single Data Fabric. */
+#define MAX_COH_ST_CHANNELS            32
+
+/* PCI ID for Zen4 Server DF Function 0. */
+#define DF_FUNC0_ID_ZEN4_SERVER                0x14AD1022
+
+/* PCI IDs for MI300 DF Function 0. */
+#define DF_FUNC0_ID_MI300              0x15281022
+
+/* Shift needed for adjusting register values to true values. */
+#define DF_DRAM_BASE_LIMIT_LSB         28
+#define MI300_DRAM_LIMIT_LSB           20
+
+enum df_revisions {
+       UNKNOWN,
+       DF2,
+       DF3,
+       DF3p5,
+       DF4,
+       DF4p5,
+};
+
+/* These are mapped 1:1 to the hardware values. Special cases are set at > 0x20. */
+enum intlv_modes {
+       NONE                            = 0x00,
+       NOHASH_2CHAN                    = 0x01,
+       NOHASH_4CHAN                    = 0x03,
+       NOHASH_8CHAN                    = 0x05,
+       DF3_6CHAN                       = 0x06,
+       NOHASH_16CHAN                   = 0x07,
+       NOHASH_32CHAN                   = 0x08,
+       DF3_COD4_2CHAN_HASH             = 0x0C,
+       DF3_COD2_4CHAN_HASH             = 0x0D,
+       DF3_COD1_8CHAN_HASH             = 0x0E,
+       DF4_NPS4_2CHAN_HASH             = 0x10,
+       DF4_NPS2_4CHAN_HASH             = 0x11,
+       DF4_NPS1_8CHAN_HASH             = 0x12,
+       DF4_NPS4_3CHAN_HASH             = 0x13,
+       DF4_NPS2_6CHAN_HASH             = 0x14,
+       DF4_NPS1_12CHAN_HASH            = 0x15,
+       DF4_NPS2_5CHAN_HASH             = 0x16,
+       DF4_NPS1_10CHAN_HASH            = 0x17,
+       MI3_HASH_8CHAN                  = 0x18,
+       MI3_HASH_16CHAN                 = 0x19,
+       MI3_HASH_32CHAN                 = 0x1A,
+       DF2_2CHAN_HASH                  = 0x21,
+       /* DF4.5 modes are all IntLvNumChan + 0x20 */
+       DF4p5_NPS1_16CHAN_1K_HASH       = 0x2C,
+       DF4p5_NPS0_24CHAN_1K_HASH       = 0x2E,
+       DF4p5_NPS4_2CHAN_1K_HASH        = 0x30,
+       DF4p5_NPS2_4CHAN_1K_HASH        = 0x31,
+       DF4p5_NPS1_8CHAN_1K_HASH        = 0x32,
+       DF4p5_NPS4_3CHAN_1K_HASH        = 0x33,
+       DF4p5_NPS2_6CHAN_1K_HASH        = 0x34,
+       DF4p5_NPS1_12CHAN_1K_HASH       = 0x35,
+       DF4p5_NPS2_5CHAN_1K_HASH        = 0x36,
+       DF4p5_NPS1_10CHAN_1K_HASH       = 0x37,
+       DF4p5_NPS4_2CHAN_2K_HASH        = 0x40,
+       DF4p5_NPS2_4CHAN_2K_HASH        = 0x41,
+       DF4p5_NPS1_8CHAN_2K_HASH        = 0x42,
+       DF4p5_NPS1_16CHAN_2K_HASH       = 0x43,
+       DF4p5_NPS4_3CHAN_2K_HASH        = 0x44,
+       DF4p5_NPS2_6CHAN_2K_HASH        = 0x45,
+       DF4p5_NPS1_12CHAN_2K_HASH       = 0x46,
+       DF4p5_NPS0_24CHAN_2K_HASH       = 0x47,
+       DF4p5_NPS2_5CHAN_2K_HASH        = 0x48,
+       DF4p5_NPS1_10CHAN_2K_HASH       = 0x49,
+};
+
+struct df_flags {
+       __u8    legacy_ficaa            : 1,
+               socket_id_shift_quirk   : 1,
+               heterogeneous           : 1,
+               __reserved_0            : 5;
+};
+
+struct df_config {
+       enum df_revisions rev;
+
+       /*
+        * These masks operate on the 16-bit Coherent Station IDs,
+        * e.g. Instance, Fabric, Destination, etc.
+        */
+       u16 component_id_mask;
+       u16 die_id_mask;
+       u16 node_id_mask;
+       u16 socket_id_mask;
+
+       /*
+        * Least-significant bit of Node ID portion of the
+        * system-wide Coherent Station Fabric ID.
+        */
+       u8 node_id_shift;
+
+       /*
+        * Least-significant bit of Die portion of the Node ID.
+        * Adjusted to include the Node ID shift in order to apply
+        * to the Coherent Station Fabric ID.
+        */
+       u8 die_id_shift;
+
+       /*
+        * Least-significant bit of Socket portion of the Node ID.
+        * Adjusted to include the Node ID shift in order to apply
+        * to the Coherent Station Fabric ID.
+        */
+       u8 socket_id_shift;
+
+       /* Number of DRAM Address maps visible in a Coherent Station. */
+       u8 num_coh_st_maps;
+
+       /* Global flags to handle special cases. */
+       struct df_flags flags;
+};
+
+extern struct df_config df_cfg;
+
+struct dram_addr_map {
+       /*
+        * Each DRAM Address Map can operate independently
+        * in different interleaving modes.
+        */
+       enum intlv_modes intlv_mode;
+
+       /* System-wide number for this address map. */
+       u8 num;
+
+       /* Raw register values */
+       u32 base;
+       u32 limit;
+       u32 ctl;
+       u32 intlv;
+
+       /*
+        * Logical to Physical Coherent Station Remapping array
+        *
+        * Index: Logical Coherent Station Instance ID
+        * Value: Physical Coherent Station Instance ID
+        *
+        * phys_coh_st_inst_id = remap_array[log_coh_st_inst_id]
+        */
+       u8 remap_array[MAX_COH_ST_CHANNELS];
+
+       /*
+        * Number of bits covering DRAM Address map 0
+        * when interleaving is non-power-of-2.
+        *
+        * Used only for DF3_6CHAN.
+        */
+       u8 np2_bits;
+
+       /* Position of the 'interleave bit'. */
+       u8 intlv_bit_pos;
+       /* Number of channels interleaved in this map. */
+       u8 num_intlv_chan;
+       /* Number of dies interleaved in this map. */
+       u8 num_intlv_dies;
+       /* Number of sockets interleaved in this map. */
+       u8 num_intlv_sockets;
+       /*
+        * Total number of channels interleaved accounting
+        * for die and socket interleaving.
+        */
+       u8 total_intlv_chan;
+       /* Total bits needed to cover 'total_intlv_chan'. */
+       u8 total_intlv_bits;
+};
+
+/* Original input values cached for debug printing. */
+struct addr_ctx_inputs {
+       u64 norm_addr;
+       u8 socket_id;
+       u8 die_id;
+       u8 coh_st_inst_id;
+};
+
+struct addr_ctx {
+       u64 ret_addr;
+
+       struct addr_ctx_inputs inputs;
+       struct dram_addr_map map;
+
+       /* AMD Node ID calculated from Socket and Die IDs. */
+       u8 node_id;
+
+       /*
+        * Coherent Station Instance ID
+        * Local ID used within a 'node'.
+        */
+       u16 inst_id;
+
+       /*
+        * Coherent Station Fabric ID
+        * System-wide ID that includes 'node' bits.
+        */
+       u16 coh_st_fabric_id;
+};
+
+int df_indirect_read_instance(u16 node, u8 func, u16 reg, u8 instance_id, u32 *lo);
+int df_indirect_read_broadcast(u16 node, u8 func, u16 reg, u32 *lo);
+
+int get_df_system_info(void);
+int determine_node_id(struct addr_ctx *ctx, u8 socket_num, u8 die_num);
+int get_addr_hash_mi300(void);
+
+int get_address_map(struct addr_ctx *ctx);
+
+int denormalize_address(struct addr_ctx *ctx);
+int dehash_address(struct addr_ctx *ctx);
+
+unsigned long norm_to_sys_addr(u8 socket_id, u8 die_id, u8 coh_st_inst_id, unsigned long addr);
+unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
+
+/*
+ * Make a gap in @data that is @num_bits long starting at @bit_num.
+ * e.g. data           = 11111111'b
+ *     bit_num         = 3
+ *     num_bits        = 2
+ *     result          = 1111100111'b
+ */
+static inline u64 expand_bits(u8 bit_num, u8 num_bits, u64 data)
+{
+       u64 temp1, temp2;
+
+       if (!num_bits)
+               return data;
+
+       if (!bit_num) {
+               WARN_ON_ONCE(num_bits >= BITS_PER_LONG);
+               return data << num_bits;
+       }
+
+       WARN_ON_ONCE(bit_num >= BITS_PER_LONG);
+
+       temp1 = data & GENMASK_ULL(bit_num - 1, 0);
+
+       temp2 = data & GENMASK_ULL(63, bit_num);
+       temp2 <<= num_bits;
+
+       return temp1 | temp2;
+}
+
+/*
+ * Remove bits in @data between @low_bit and @high_bit inclusive.
+ * e.g. data           = XXXYYZZZ'b
+ *     low_bit         = 3
+ *     high_bit        = 4
+ *     result          = XXXZZZ'b
+ */
+static inline u64 remove_bits(u8 low_bit, u8 high_bit, u64 data)
+{
+       u64 temp1, temp2;
+
+       WARN_ON_ONCE(high_bit >= BITS_PER_LONG);
+       WARN_ON_ONCE(low_bit  >= BITS_PER_LONG);
+       WARN_ON_ONCE(low_bit  >  high_bit);
+
+       if (!low_bit)
+               return data >> (high_bit++);
+
+       temp1 = GENMASK_ULL(low_bit - 1, 0) & data;
+       temp2 = GENMASK_ULL(63, high_bit + 1) & data;
+       temp2 >>= high_bit - low_bit + 1;
+
+       return temp1 | temp2;
+}
+
+#define atl_debug(ctx, fmt, arg...) \
+       pr_debug("socket_id=%u die_id=%u coh_st_inst_id=%u norm_addr=0x%016llx: " fmt,\
+                (ctx)->inputs.socket_id, (ctx)->inputs.die_id,\
+                (ctx)->inputs.coh_st_inst_id, (ctx)->inputs.norm_addr, ##arg)
+
+static inline void atl_debug_on_bad_df_rev(void)
+{
+       pr_debug("Unrecognized DF rev: %u", df_cfg.rev);
+}
+
+static inline void atl_debug_on_bad_intlv_mode(struct addr_ctx *ctx)
+{
+       atl_debug(ctx, "Unrecognized interleave mode: %u", ctx->map.intlv_mode);
+}
+
+#endif /* __AMD_ATL_INTERNAL_H__ */
diff --git a/drivers/ras/amd/atl/map.c b/drivers/ras/amd/atl/map.c
new file mode 100644 (file)
index 0000000..8b908e8
--- /dev/null
@@ -0,0 +1,682 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD Address Translation Library
+ *
+ * map.c : Functions to read and decode DRAM address maps
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
+ */
+
+#include "internal.h"
+
+static int df2_get_intlv_mode(struct addr_ctx *ctx)
+{
+       ctx->map.intlv_mode = FIELD_GET(DF2_INTLV_NUM_CHAN, ctx->map.base);
+
+       if (ctx->map.intlv_mode == 8)
+               ctx->map.intlv_mode = DF2_2CHAN_HASH;
+
+       if (ctx->map.intlv_mode != NONE &&
+           ctx->map.intlv_mode != NOHASH_2CHAN &&
+           ctx->map.intlv_mode != DF2_2CHAN_HASH)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int df3_get_intlv_mode(struct addr_ctx *ctx)
+{
+       ctx->map.intlv_mode = FIELD_GET(DF3_INTLV_NUM_CHAN, ctx->map.base);
+       return 0;
+}
+
+static int df3p5_get_intlv_mode(struct addr_ctx *ctx)
+{
+       ctx->map.intlv_mode = FIELD_GET(DF3p5_INTLV_NUM_CHAN, ctx->map.base);
+
+       if (ctx->map.intlv_mode == DF3_6CHAN)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int df4_get_intlv_mode(struct addr_ctx *ctx)
+{
+       ctx->map.intlv_mode = FIELD_GET(DF4_INTLV_NUM_CHAN, ctx->map.intlv);
+
+       if (ctx->map.intlv_mode == DF3_COD4_2CHAN_HASH ||
+           ctx->map.intlv_mode == DF3_COD2_4CHAN_HASH ||
+           ctx->map.intlv_mode == DF3_COD1_8CHAN_HASH ||
+           ctx->map.intlv_mode == DF3_6CHAN)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int df4p5_get_intlv_mode(struct addr_ctx *ctx)
+{
+       ctx->map.intlv_mode = FIELD_GET(DF4p5_INTLV_NUM_CHAN, ctx->map.intlv);
+
+       if (ctx->map.intlv_mode <= NOHASH_32CHAN)
+               return 0;
+
+       if (ctx->map.intlv_mode >= MI3_HASH_8CHAN &&
+           ctx->map.intlv_mode <= MI3_HASH_32CHAN)
+               return 0;
+
+       /*
+        * Modes matching the ranges above are returned as-is.
+        *
+        * All other modes are "fixed up" by adding 20h to make a unique value.
+        */
+       ctx->map.intlv_mode += 0x20;
+
+       return 0;
+}
+
+static int get_intlv_mode(struct addr_ctx *ctx)
+{
+       int ret;
+
+       switch (df_cfg.rev) {
+       case DF2:
+               ret = df2_get_intlv_mode(ctx);
+               break;
+       case DF3:
+               ret = df3_get_intlv_mode(ctx);
+               break;
+       case DF3p5:
+               ret = df3p5_get_intlv_mode(ctx);
+               break;
+       case DF4:
+               ret = df4_get_intlv_mode(ctx);
+               break;
+       case DF4p5:
+               ret = df4p5_get_intlv_mode(ctx);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       if (ret)
+               atl_debug_on_bad_df_rev();
+
+       return ret;
+}
+
+static u64 get_hi_addr_offset(u32 reg_dram_offset)
+{
+       u8 shift = DF_DRAM_BASE_LIMIT_LSB;
+       u64 hi_addr_offset;
+
+       switch (df_cfg.rev) {
+       case DF2:
+               hi_addr_offset = FIELD_GET(DF2_HI_ADDR_OFFSET, reg_dram_offset);
+               break;
+       case DF3:
+       case DF3p5:
+               hi_addr_offset = FIELD_GET(DF3_HI_ADDR_OFFSET, reg_dram_offset);
+               break;
+       case DF4:
+       case DF4p5:
+               hi_addr_offset = FIELD_GET(DF4_HI_ADDR_OFFSET, reg_dram_offset);
+               break;
+       default:
+               hi_addr_offset = 0;
+               atl_debug_on_bad_df_rev();
+       }
+
+       if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous)
+               shift = MI300_DRAM_LIMIT_LSB;
+
+       return hi_addr_offset << shift;
+}
+
+/*
+ * Returns:    0 if offset is disabled.
+ *             1 if offset is enabled.
+ *             -EINVAL on error.
+ */
+static int get_dram_offset(struct addr_ctx *ctx, u64 *norm_offset)
+{
+       u32 reg_dram_offset;
+       u8 map_num;
+
+       /* Should not be called for map 0. */
+       if (!ctx->map.num) {
+               atl_debug(ctx, "Trying to find DRAM offset for map 0");
+               return -EINVAL;
+       }
+
+       /*
+        * DramOffset registers don't exist for map 0, so the base register
+        * actually refers to map 1.
+        * Adjust the map_num for the register offsets.
+        */
+       map_num = ctx->map.num - 1;
+
+       if (df_cfg.rev >= DF4) {
+               /* Read D18F7x140 (DramOffset) */
+               if (df_indirect_read_instance(ctx->node_id, 7, 0x140 + (4 * map_num),
+                                             ctx->inst_id, &reg_dram_offset))
+                       return -EINVAL;
+
+       } else {
+               /* Read D18F0x1B4 (DramOffset) */
+               if (df_indirect_read_instance(ctx->node_id, 0, 0x1B4 + (4 * map_num),
+                                             ctx->inst_id, &reg_dram_offset))
+                       return -EINVAL;
+       }
+
+       if (!FIELD_GET(DF_HI_ADDR_OFFSET_EN, reg_dram_offset))
+               return 0;
+
+       *norm_offset = get_hi_addr_offset(reg_dram_offset);
+
+       return 1;
+}
+
+static int df3_6ch_get_dram_addr_map(struct addr_ctx *ctx)
+{
+       u16 dst_fabric_id = FIELD_GET(DF3_DST_FABRIC_ID, ctx->map.limit);
+       u8 i, j, shift = 4, mask = 0xF;
+       u32 reg, offset = 0x60;
+       u16 dst_node_id;
+
+       /* Get Socket 1 register. */
+       if (dst_fabric_id & df_cfg.socket_id_mask)
+               offset = 0x68;
+
+       /* Read D18F0x06{0,8} (DF::Skt0CsTargetRemap0)/(DF::Skt0CsTargetRemap1) */
+       if (df_indirect_read_broadcast(ctx->node_id, 0, offset, &reg))
+               return -EINVAL;
+
+       /* Save 8 remap entries. */
+       for (i = 0, j = 0; i < 8; i++, j++)
+               ctx->map.remap_array[i] = (reg >> (j * shift)) & mask;
+
+       dst_node_id = dst_fabric_id & df_cfg.node_id_mask;
+       dst_node_id >>= df_cfg.node_id_shift;
+
+       /* Read D18F2x090 (DF::Np2ChannelConfig) */
+       if (df_indirect_read_broadcast(dst_node_id, 2, 0x90, &reg))
+               return -EINVAL;
+
+       ctx->map.np2_bits = FIELD_GET(DF_LOG2_ADDR_64K_SPACE0, reg);
+       return 0;
+}
+
+static int df2_get_dram_addr_map(struct addr_ctx *ctx)
+{
+       /* Read D18F0x110 (DramBaseAddress). */
+       if (df_indirect_read_instance(ctx->node_id, 0, 0x110 + (8 * ctx->map.num),
+                                     ctx->inst_id, &ctx->map.base))
+               return -EINVAL;
+
+       /* Read D18F0x114 (DramLimitAddress). */
+       if (df_indirect_read_instance(ctx->node_id, 0, 0x114 + (8 * ctx->map.num),
+                                     ctx->inst_id, &ctx->map.limit))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int df3_get_dram_addr_map(struct addr_ctx *ctx)
+{
+       if (df2_get_dram_addr_map(ctx))
+               return -EINVAL;
+
+       /* Read D18F0x3F8 (DfGlobalCtl). */
+       if (df_indirect_read_instance(ctx->node_id, 0, 0x3F8,
+                                     ctx->inst_id, &ctx->map.ctl))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int df4_get_dram_addr_map(struct addr_ctx *ctx)
+{
+       u8 remap_sel, i, j, shift = 4, mask = 0xF;
+       u32 remap_reg;
+
+       /* Read D18F7xE00 (DramBaseAddress). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0xE00 + (16 * ctx->map.num),
+                                     ctx->inst_id, &ctx->map.base))
+               return -EINVAL;
+
+       /* Read D18F7xE04 (DramLimitAddress). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0xE04 + (16 * ctx->map.num),
+                                     ctx->inst_id, &ctx->map.limit))
+               return -EINVAL;
+
+       /* Read D18F7xE08 (DramAddressCtl). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0xE08 + (16 * ctx->map.num),
+                                     ctx->inst_id, &ctx->map.ctl))
+               return -EINVAL;
+
+       /* Read D18F7xE0C (DramAddressIntlv). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0xE0C + (16 * ctx->map.num),
+                                     ctx->inst_id, &ctx->map.intlv))
+               return -EINVAL;
+
+       /* Check if Remap Enable bit is valid. */
+       if (!FIELD_GET(DF4_REMAP_EN, ctx->map.ctl))
+               return 0;
+
+       /* Fill with bogus values, because '0' is a valid value. */
+       memset(&ctx->map.remap_array, 0xFF, sizeof(ctx->map.remap_array));
+
+       /* Get Remap registers. */
+       remap_sel = FIELD_GET(DF4_REMAP_SEL, ctx->map.ctl);
+
+       /* Read D18F7x180 (CsTargetRemap0A). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0x180 + (8 * remap_sel),
+                                     ctx->inst_id, &remap_reg))
+               return -EINVAL;
+
+       /* Save first 8 remap entries. */
+       for (i = 0, j = 0; i < 8; i++, j++)
+               ctx->map.remap_array[i] = (remap_reg >> (j * shift)) & mask;
+
+       /* Read D18F7x184 (CsTargetRemap0B). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0x184 + (8 * remap_sel),
+                                     ctx->inst_id, &remap_reg))
+               return -EINVAL;
+
+       /* Save next 8 remap entries. */
+       for (i = 8, j = 0; i < 16; i++, j++)
+               ctx->map.remap_array[i] = (remap_reg >> (j * shift)) & mask;
+
+       return 0;
+}
+
+static int df4p5_get_dram_addr_map(struct addr_ctx *ctx)
+{
+       u8 remap_sel, i, j, shift = 5, mask = 0x1F;
+       u32 remap_reg;
+
+       /* Read D18F7x200 (DramBaseAddress). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0x200 + (16 * ctx->map.num),
+                                     ctx->inst_id, &ctx->map.base))
+               return -EINVAL;
+
+       /* Read D18F7x204 (DramLimitAddress). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0x204 + (16 * ctx->map.num),
+                                     ctx->inst_id, &ctx->map.limit))
+               return -EINVAL;
+
+       /* Read D18F7x208 (DramAddressCtl). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0x208 + (16 * ctx->map.num),
+                                     ctx->inst_id, &ctx->map.ctl))
+               return -EINVAL;
+
+       /* Read D18F7x20C (DramAddressIntlv). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0x20C + (16 * ctx->map.num),
+                                     ctx->inst_id, &ctx->map.intlv))
+               return -EINVAL;
+
+       /* Check if Remap Enable bit is valid. */
+       if (!FIELD_GET(DF4_REMAP_EN, ctx->map.ctl))
+               return 0;
+
+       /* Fill with bogus values, because '0' is a valid value. */
+       memset(&ctx->map.remap_array, 0xFF, sizeof(ctx->map.remap_array));
+
+       /* Get Remap registers. */
+       remap_sel = FIELD_GET(DF4p5_REMAP_SEL, ctx->map.ctl);
+
+       /* Read D18F7x180 (CsTargetRemap0A). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0x180 + (24 * remap_sel),
+                                     ctx->inst_id, &remap_reg))
+               return -EINVAL;
+
+       /* Save first 6 remap entries. */
+       for (i = 0, j = 0; i < 6; i++, j++)
+               ctx->map.remap_array[i] = (remap_reg >> (j * shift)) & mask;
+
+       /* Read D18F7x184 (CsTargetRemap0B). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0x184 + (24 * remap_sel),
+                                     ctx->inst_id, &remap_reg))
+               return -EINVAL;
+
+       /* Save next 6 remap entries. */
+       for (i = 6, j = 0; i < 12; i++, j++)
+               ctx->map.remap_array[i] = (remap_reg >> (j * shift)) & mask;
+
+       /* Read D18F7x188 (CsTargetRemap0C). */
+       if (df_indirect_read_instance(ctx->node_id, 7, 0x188 + (24 * remap_sel),
+                                     ctx->inst_id, &remap_reg))
+               return -EINVAL;
+
+       /* Save next 6 remap entries. */
+       for (i = 12, j = 0; i < 18; i++, j++)
+               ctx->map.remap_array[i] = (remap_reg >> (j * shift)) & mask;
+
+       return 0;
+}
+
+static int get_dram_addr_map(struct addr_ctx *ctx)
+{
+       switch (df_cfg.rev) {
+       case DF2:       return df2_get_dram_addr_map(ctx);
+       case DF3:
+       case DF3p5:     return df3_get_dram_addr_map(ctx);
+       case DF4:       return df4_get_dram_addr_map(ctx);
+       case DF4p5:     return df4p5_get_dram_addr_map(ctx);
+       default:
+                       atl_debug_on_bad_df_rev();
+                       return -EINVAL;
+       }
+}
+
+static int get_coh_st_fabric_id(struct addr_ctx *ctx)
+{
+       u32 reg;
+
+       /*
+        * On MI300 systems, the Coherent Station Fabric ID is derived
+        * later. And it does not depend on the register value.
+        */
+       if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous)
+               return 0;
+
+       /* Read D18F0x50 (FabricBlockInstanceInformation3). */
+       if (df_indirect_read_instance(ctx->node_id, 0, 0x50, ctx->inst_id, &reg))
+               return -EINVAL;
+
+       if (df_cfg.rev < DF4p5)
+               ctx->coh_st_fabric_id = FIELD_GET(DF2_COH_ST_FABRIC_ID, reg);
+       else
+               ctx->coh_st_fabric_id = FIELD_GET(DF4p5_COH_ST_FABRIC_ID, reg);
+
+       return 0;
+}
+
+static int find_normalized_offset(struct addr_ctx *ctx, u64 *norm_offset)
+{
+       u64 last_offset = 0;
+       int ret;
+
+       for (ctx->map.num = 1; ctx->map.num < df_cfg.num_coh_st_maps; ctx->map.num++) {
+               ret = get_dram_offset(ctx, norm_offset);
+               if (ret < 0)
+                       return ret;
+
+               /* Continue search if this map's offset is not enabled. */
+               if (!ret)
+                       continue;
+
+               /* Enabled offsets should never be 0. */
+               if (*norm_offset == 0) {
+                       atl_debug(ctx, "Enabled map %u offset is 0", ctx->map.num);
+                       return -EINVAL;
+               }
+
+               /* Offsets should always increase from one map to the next. */
+               if (*norm_offset <= last_offset) {
+                       atl_debug(ctx, "Map %u offset (0x%016llx) <= previous (0x%016llx)",
+                                 ctx->map.num, *norm_offset, last_offset);
+                       return -EINVAL;
+               }
+
+               /* Match if this map's offset is less than the current calculated address. */
+               if (ctx->ret_addr >= *norm_offset)
+                       break;
+
+               last_offset = *norm_offset;
+       }
+
+       /*
+        * Finished search without finding a match.
+        * Reset to map 0 and no offset.
+        */
+       if (ctx->map.num >= df_cfg.num_coh_st_maps) {
+               ctx->map.num = 0;
+               *norm_offset = 0;
+       }
+
+       return 0;
+}
+
+static bool valid_map(struct addr_ctx *ctx)
+{
+       if (df_cfg.rev >= DF4)
+               return FIELD_GET(DF_ADDR_RANGE_VAL, ctx->map.ctl);
+       else
+               return FIELD_GET(DF_ADDR_RANGE_VAL, ctx->map.base);
+}
+
+static int get_address_map_common(struct addr_ctx *ctx)
+{
+       u64 norm_offset = 0;
+
+       if (get_coh_st_fabric_id(ctx))
+               return -EINVAL;
+
+       if (find_normalized_offset(ctx, &norm_offset))
+               return -EINVAL;
+
+       if (get_dram_addr_map(ctx))
+               return -EINVAL;
+
+       if (!valid_map(ctx))
+               return -EINVAL;
+
+       ctx->ret_addr -= norm_offset;
+
+       return 0;
+}
+
+static u8 get_num_intlv_chan(struct addr_ctx *ctx)
+{
+       switch (ctx->map.intlv_mode) {
+       case NONE:
+               return 1;
+       case NOHASH_2CHAN:
+       case DF2_2CHAN_HASH:
+       case DF3_COD4_2CHAN_HASH:
+       case DF4_NPS4_2CHAN_HASH:
+       case DF4p5_NPS4_2CHAN_1K_HASH:
+       case DF4p5_NPS4_2CHAN_2K_HASH:
+               return 2;
+       case DF4_NPS4_3CHAN_HASH:
+       case DF4p5_NPS4_3CHAN_1K_HASH:
+       case DF4p5_NPS4_3CHAN_2K_HASH:
+               return 3;
+       case NOHASH_4CHAN:
+       case DF3_COD2_4CHAN_HASH:
+       case DF4_NPS2_4CHAN_HASH:
+       case DF4p5_NPS2_4CHAN_1K_HASH:
+       case DF4p5_NPS2_4CHAN_2K_HASH:
+               return 4;
+       case DF4_NPS2_5CHAN_HASH:
+       case DF4p5_NPS2_5CHAN_1K_HASH:
+       case DF4p5_NPS2_5CHAN_2K_HASH:
+               return 5;
+       case DF3_6CHAN:
+       case DF4_NPS2_6CHAN_HASH:
+       case DF4p5_NPS2_6CHAN_1K_HASH:
+       case DF4p5_NPS2_6CHAN_2K_HASH:
+               return 6;
+       case NOHASH_8CHAN:
+       case DF3_COD1_8CHAN_HASH:
+       case DF4_NPS1_8CHAN_HASH:
+       case MI3_HASH_8CHAN:
+       case DF4p5_NPS1_8CHAN_1K_HASH:
+       case DF4p5_NPS1_8CHAN_2K_HASH:
+               return 8;
+       case DF4_NPS1_10CHAN_HASH:
+       case DF4p5_NPS1_10CHAN_1K_HASH:
+       case DF4p5_NPS1_10CHAN_2K_HASH:
+               return 10;
+       case DF4_NPS1_12CHAN_HASH:
+       case DF4p5_NPS1_12CHAN_1K_HASH:
+       case DF4p5_NPS1_12CHAN_2K_HASH:
+               return 12;
+       case NOHASH_16CHAN:
+       case MI3_HASH_16CHAN:
+       case DF4p5_NPS1_16CHAN_1K_HASH:
+       case DF4p5_NPS1_16CHAN_2K_HASH:
+               return 16;
+       case DF4p5_NPS0_24CHAN_1K_HASH:
+       case DF4p5_NPS0_24CHAN_2K_HASH:
+               return 24;
+       case NOHASH_32CHAN:
+       case MI3_HASH_32CHAN:
+               return 32;
+       default:
+               atl_debug_on_bad_intlv_mode(ctx);
+               return 0;
+       }
+}
+
+static void calculate_intlv_bits(struct addr_ctx *ctx)
+{
+       ctx->map.num_intlv_chan = get_num_intlv_chan(ctx);
+
+       ctx->map.total_intlv_chan = ctx->map.num_intlv_chan;
+       ctx->map.total_intlv_chan *= ctx->map.num_intlv_dies;
+       ctx->map.total_intlv_chan *= ctx->map.num_intlv_sockets;
+
+       /*
+        * Get the number of bits needed to cover this many channels.
+        * order_base_2() rounds up automatically.
+        */
+       ctx->map.total_intlv_bits = order_base_2(ctx->map.total_intlv_chan);
+}
+
+static u8 get_intlv_bit_pos(struct addr_ctx *ctx)
+{
+       u8 addr_sel = 0;
+
+       switch (df_cfg.rev) {
+       case DF2:
+               addr_sel = FIELD_GET(DF2_INTLV_ADDR_SEL, ctx->map.base);
+               break;
+       case DF3:
+       case DF3p5:
+               addr_sel = FIELD_GET(DF3_INTLV_ADDR_SEL, ctx->map.base);
+               break;
+       case DF4:
+       case DF4p5:
+               addr_sel = FIELD_GET(DF4_INTLV_ADDR_SEL, ctx->map.intlv);
+               break;
+       default:
+               atl_debug_on_bad_df_rev();
+               break;
+       }
+
+       /* Add '8' to get the 'interleave bit position'. */
+       return addr_sel + 8;
+}
+
+static u8 get_num_intlv_dies(struct addr_ctx *ctx)
+{
+       u8 dies = 0;
+
+       switch (df_cfg.rev) {
+       case DF2:
+               dies = FIELD_GET(DF2_INTLV_NUM_DIES, ctx->map.limit);
+               break;
+       case DF3:
+               dies = FIELD_GET(DF3_INTLV_NUM_DIES, ctx->map.base);
+               break;
+       case DF3p5:
+               dies = FIELD_GET(DF3p5_INTLV_NUM_DIES, ctx->map.base);
+               break;
+       case DF4:
+       case DF4p5:
+               dies = FIELD_GET(DF4_INTLV_NUM_DIES, ctx->map.intlv);
+               break;
+       default:
+               atl_debug_on_bad_df_rev();
+               break;
+       }
+
+       /* Register value is log2, e.g. 0 -> 1 die, 1 -> 2 dies, etc. */
+       return 1 << dies;
+}
+
+static u8 get_num_intlv_sockets(struct addr_ctx *ctx)
+{
+       u8 sockets = 0;
+
+       switch (df_cfg.rev) {
+       case DF2:
+               sockets = FIELD_GET(DF2_INTLV_NUM_SOCKETS, ctx->map.limit);
+               break;
+       case DF3:
+       case DF3p5:
+               sockets = FIELD_GET(DF2_INTLV_NUM_SOCKETS, ctx->map.base);
+               break;
+       case DF4:
+       case DF4p5:
+               sockets = FIELD_GET(DF4_INTLV_NUM_SOCKETS, ctx->map.intlv);
+               break;
+       default:
+               atl_debug_on_bad_df_rev();
+               break;
+       }
+
+       /* Register value is log2, e.g. 0 -> 1 sockets, 1 -> 2 sockets, etc. */
+       return 1 << sockets;
+}
+
+static int get_global_map_data(struct addr_ctx *ctx)
+{
+       if (get_intlv_mode(ctx))
+               return -EINVAL;
+
+       if (ctx->map.intlv_mode == DF3_6CHAN &&
+           df3_6ch_get_dram_addr_map(ctx))
+               return -EINVAL;
+
+       ctx->map.intlv_bit_pos          = get_intlv_bit_pos(ctx);
+       ctx->map.num_intlv_dies         = get_num_intlv_dies(ctx);
+       ctx->map.num_intlv_sockets      = get_num_intlv_sockets(ctx);
+       calculate_intlv_bits(ctx);
+
+       return 0;
+}
+
+static void dump_address_map(struct dram_addr_map *map)
+{
+       u8 i;
+
+       pr_debug("intlv_mode=0x%x",             map->intlv_mode);
+       pr_debug("num=0x%x",                    map->num);
+       pr_debug("base=0x%x",                   map->base);
+       pr_debug("limit=0x%x",                  map->limit);
+       pr_debug("ctl=0x%x",                    map->ctl);
+       pr_debug("intlv=0x%x",                  map->intlv);
+
+       for (i = 0; i < MAX_COH_ST_CHANNELS; i++)
+               pr_debug("remap_array[%u]=0x%x", i, map->remap_array[i]);
+
+       pr_debug("intlv_bit_pos=%u",            map->intlv_bit_pos);
+       pr_debug("num_intlv_chan=%u",           map->num_intlv_chan);
+       pr_debug("num_intlv_dies=%u",           map->num_intlv_dies);
+       pr_debug("num_intlv_sockets=%u",        map->num_intlv_sockets);
+       pr_debug("total_intlv_chan=%u",         map->total_intlv_chan);
+       pr_debug("total_intlv_bits=%u",         map->total_intlv_bits);
+}
+
+int get_address_map(struct addr_ctx *ctx)
+{
+       int ret;
+
+       ret = get_address_map_common(ctx);
+       if (ret)
+               return ret;
+
+       ret = get_global_map_data(ctx);
+       if (ret)
+               return ret;
+
+       dump_address_map(&ctx->map);
+
+       return ret;
+}
diff --git a/drivers/ras/amd/atl/reg_fields.h b/drivers/ras/amd/atl/reg_fields.h
new file mode 100644 (file)
index 0000000..9dcdf6e
--- /dev/null
@@ -0,0 +1,606 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AMD Address Translation Library
+ *
+ * reg_fields.h : Register field definitions
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
+ */
+
+/*
+ * Notes on naming:
+ * 1) Use "DF_" prefix for fields that are the same for all revisions.
+ * 2) Use "DFx_" prefix for fields that differ between revisions.
+ *     a) "x" is the first major revision where the new field appears.
+ *     b) E.g., if DF2 and DF3 have the same field, then call it DF2.
+ *     c) E.g., if DF3p5 and DF4 have the same field, then call it DF4.
+ */
+
+/*
+ * Coherent Station Fabric ID
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x50 [Fabric Block Instance Information 3]
+ *     DF2     BlockFabricId   [19:8]
+ *     DF3     BlockFabricId   [19:8]
+ *     DF3p5   BlockFabricId   [19:8]
+ *     DF4     BlockFabricId   [19:8]
+ *     DF4p5   BlockFabricId   [15:8]
+ */
+#define DF2_COH_ST_FABRIC_ID   GENMASK(19, 8)
+#define DF4p5_COH_ST_FABRIC_ID GENMASK(15, 8)
+
+/*
+ * Component ID Mask
+ *
+ * Access type: Broadcast
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     DF2     N/A
+ *
+ *     D18F1x208 [System Fabric ID Mask 0]
+ *     DF3     ComponentIdMask [9:0]
+ *
+ *     D18F1x150 [System Fabric ID Mask 0]
+ *     DF3p5   ComponentIdMask [15:0]
+ *
+ *     D18F4x1B0 [System Fabric ID Mask 0]
+ *     DF4     ComponentIdMask [15:0]
+ *     DF4p5   ComponentIdMask [15:0]
+ */
+#define DF3_COMPONENT_ID_MASK  GENMASK(9, 0)
+#define DF4_COMPONENT_ID_MASK  GENMASK(15, 0)
+
+/*
+ * Destination Fabric ID
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x114 [DRAM Limit Address]
+ *     DF2     DstFabricID     [7:0]
+ *     DF3     DstFabricID     [9:0]
+ *     DF3     DstFabricID     [11:0]
+ *
+ *     D18F7xE08 [DRAM Address Control]
+ *     DF4     DstFabricID     [27:16]
+ *
+ *     D18F7x208 [DRAM Address Control]
+ *     DF4p5   DstFabricID     [23:16]
+ */
+#define DF2_DST_FABRIC_ID      GENMASK(7, 0)
+#define DF3_DST_FABRIC_ID      GENMASK(9, 0)
+#define DF3p5_DST_FABRIC_ID    GENMASK(11, 0)
+#define DF4_DST_FABRIC_ID      GENMASK(27, 16)
+#define DF4p5_DST_FABRIC_ID    GENMASK(23, 16)
+
+/*
+ * Die ID Mask
+ *
+ * Access type: Broadcast
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F1x208 [System Fabric ID Mask]
+ *     DF2     DieIdMask       [15:8]
+ *
+ *     D18F1x20C [System Fabric ID Mask 1]
+ *     DF3     DieIdMask       [18:16]
+ *
+ *     D18F1x158 [System Fabric ID Mask 2]
+ *     DF3p5   DieIdMask       [15:0]
+ *
+ *     D18F4x1B8 [System Fabric ID Mask 2]
+ *     DF4     DieIdMask       [15:0]
+ *     DF4p5   DieIdMask       [15:0]
+ */
+#define DF2_DIE_ID_MASK                GENMASK(15, 8)
+#define DF3_DIE_ID_MASK                GENMASK(18, 16)
+#define DF4_DIE_ID_MASK                GENMASK(15, 0)
+
+/*
+ * Die ID Shift
+ *
+ * Access type: Broadcast
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F1x208 [System Fabric ID Mask]
+ *     DF2     DieIdShift      [27:24]
+ *
+ *     DF3     N/A
+ *     DF3p5   N/A
+ *     DF4     N/A
+ *     DF4p5   N/A
+ */
+#define DF2_DIE_ID_SHIFT       GENMASK(27, 24)
+
+/*
+ * DRAM Address Range Valid
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x110 [DRAM Base Address]
+ *     DF2     AddrRngVal      [0]
+ *     DF3     AddrRngVal      [0]
+ *     DF3p5   AddrRngVal      [0]
+ *
+ *     D18F7xE08 [DRAM Address Control]
+ *     DF4     AddrRngVal      [0]
+ *
+ *     D18F7x208 [DRAM Address Control]
+ *     DF4p5   AddrRngVal      [0]
+ */
+#define DF_ADDR_RANGE_VAL      BIT(0)
+
+/*
+ * DRAM Base Address
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x110 [DRAM Base Address]
+ *     DF2     DramBaseAddr    [31:12]
+ *     DF3     DramBaseAddr    [31:12]
+ *     DF3p5   DramBaseAddr    [31:12]
+ *
+ *     D18F7xE00 [DRAM Base Address]
+ *     DF4     DramBaseAddr    [27:0]
+ *
+ *     D18F7x200 [DRAM Base Address]
+ *     DF4p5   DramBaseAddr    [27:0]
+ */
+#define DF2_BASE_ADDR          GENMASK(31, 12)
+#define DF4_BASE_ADDR          GENMASK(27, 0)
+
+/*
+ * DRAM Hole Base
+ *
+ * Access type: Broadcast
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x104 [DRAM Hole Control]
+ *     DF2     DramHoleBase    [31:24]
+ *     DF3     DramHoleBase    [31:24]
+ *     DF3p5   DramHoleBase    [31:24]
+ *
+ *     D18F7x104 [DRAM Hole Control]
+ *     DF4     DramHoleBase    [31:24]
+ *     DF4p5   DramHoleBase    [31:24]
+ */
+#define DF_DRAM_HOLE_BASE_MASK GENMASK(31, 24)
+
+/*
+ * DRAM Limit Address
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x114 [DRAM Limit Address]
+ *     DF2     DramLimitAddr   [31:12]
+ *     DF3     DramLimitAddr   [31:12]
+ *     DF3p5   DramLimitAddr   [31:12]
+ *
+ *     D18F7xE04 [DRAM Limit Address]
+ *     DF4     DramLimitAddr   [27:0]
+ *
+ *     D18F7x204 [DRAM Limit Address]
+ *     DF4p5   DramLimitAddr   [27:0]
+ */
+#define DF2_DRAM_LIMIT_ADDR    GENMASK(31, 12)
+#define DF4_DRAM_LIMIT_ADDR    GENMASK(27, 0)
+
+/*
+ * Hash Interleave Controls
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     DF2     N/A
+ *
+ *     D18F0x3F8 [DF Global Control]
+ *     DF3     GlbHashIntlvCtl64K      [20]
+ *             GlbHashIntlvCtl2M       [21]
+ *             GlbHashIntlvCtl1G       [22]
+ *
+ *     DF3p5   GlbHashIntlvCtl64K      [20]
+ *             GlbHashIntlvCtl2M       [21]
+ *             GlbHashIntlvCtl1G       [22]
+ *
+ *     D18F7xE08 [DRAM Address Control]
+ *     DF4     HashIntlvCtl64K         [8]
+ *             HashIntlvCtl2M          [9]
+ *             HashIntlvCtl1G          [10]
+ *
+ *     D18F7x208 [DRAM Address Control]
+ *     DF4p5   HashIntlvCtl4K          [7]
+ *             HashIntlvCtl64K         [8]
+ *             HashIntlvCtl2M          [9]
+ *             HashIntlvCtl1G          [10]
+ *             HashIntlvCtl1T          [15]
+ */
+#define DF3_HASH_CTL_64K               BIT(20)
+#define DF3_HASH_CTL_2M                        BIT(21)
+#define DF3_HASH_CTL_1G                        BIT(22)
+#define DF4_HASH_CTL_64K               BIT(8)
+#define DF4_HASH_CTL_2M                        BIT(9)
+#define DF4_HASH_CTL_1G                        BIT(10)
+#define DF4p5_HASH_CTL_4K              BIT(7)
+#define DF4p5_HASH_CTL_1T              BIT(15)
+
+/*
+ * High Address Offset
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x1B4 [DRAM Offset]
+ *     DF2     HiAddrOffset    [31:20]
+ *     DF3     HiAddrOffset    [31:12]
+ *     DF3p5   HiAddrOffset    [31:12]
+ *
+ *     D18F7x140 [DRAM Offset]
+ *     DF4     HiAddrOffset    [24:1]
+ *     DF4p5   HiAddrOffset    [24:1]
+ *     MI300   HiAddrOffset    [31:1]
+ */
+#define DF2_HI_ADDR_OFFSET     GENMASK(31, 20)
+#define DF3_HI_ADDR_OFFSET     GENMASK(31, 12)
+
+/* Follow reference code by including reserved bits for simplicity. */
+#define DF4_HI_ADDR_OFFSET     GENMASK(31, 1)
+
+/*
+ * High Address Offset Enable
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x1B4 [DRAM Offset]
+ *     DF2     HiAddrOffsetEn  [0]
+ *     DF3     HiAddrOffsetEn  [0]
+ *     DF3p5   HiAddrOffsetEn  [0]
+ *
+ *     D18F7x140 [DRAM Offset]
+ *     DF4     HiAddrOffsetEn  [0]
+ *     DF4p5   HiAddrOffsetEn  [0]
+ */
+#define DF_HI_ADDR_OFFSET_EN   BIT(0)
+
+/*
+ * Interleave Address Select
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x110 [DRAM Base Address]
+ *     DF2     IntLvAddrSel    [10:8]
+ *     DF3     IntLvAddrSel    [11:9]
+ *     DF3p5   IntLvAddrSel    [11:9]
+ *
+ *     D18F7xE0C [DRAM Address Interleave]
+ *     DF4     IntLvAddrSel    [2:0]
+ *
+ *     D18F7x20C [DRAM Address Interleave]
+ *     DF4p5   IntLvAddrSel    [2:0]
+ */
+#define DF2_INTLV_ADDR_SEL     GENMASK(10, 8)
+#define DF3_INTLV_ADDR_SEL     GENMASK(11, 9)
+#define DF4_INTLV_ADDR_SEL     GENMASK(2, 0)
+
+/*
+ * Interleave Number of Channels
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x110 [DRAM Base Address]
+ *     DF2     IntLvNumChan    [7:4]
+ *     DF3     IntLvNumChan    [5:2]
+ *     DF3p5   IntLvNumChan    [6:2]
+ *
+ *     D18F7xE0C [DRAM Address Interleave]
+ *     DF4     IntLvNumChan    [8:4]
+ *
+ *     D18F7x20C [DRAM Address Interleave]
+ *     DF4p5   IntLvNumChan    [9:4]
+ */
+#define DF2_INTLV_NUM_CHAN     GENMASK(7, 4)
+#define DF3_INTLV_NUM_CHAN     GENMASK(5, 2)
+#define DF3p5_INTLV_NUM_CHAN   GENMASK(6, 2)
+#define DF4_INTLV_NUM_CHAN     GENMASK(8, 4)
+#define DF4p5_INTLV_NUM_CHAN   GENMASK(9, 4)
+
+/*
+ * Interleave Number of Dies
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x114 [DRAM Limit Address]
+ *     DF2     IntLvNumDies    [11:10]
+ *
+ *     D18F0x110 [DRAM Base Address]
+ *     DF3     IntLvNumDies    [7:6]
+ *     DF3p5   IntLvNumDies    [7]
+ *
+ *     D18F7xE0C [DRAM Address Interleave]
+ *     DF4     IntLvNumDies    [13:12]
+ *
+ *     D18F7x20C [DRAM Address Interleave]
+ *     DF4p5   IntLvNumDies    [13:12]
+ */
+#define DF2_INTLV_NUM_DIES     GENMASK(11, 10)
+#define DF3_INTLV_NUM_DIES     GENMASK(7, 6)
+#define DF3p5_INTLV_NUM_DIES   BIT(7)
+#define DF4_INTLV_NUM_DIES     GENMASK(13, 12)
+
+/*
+ * Interleave Number of Sockets
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x114 [DRAM Limit Address]
+ *     DF2     IntLvNumSockets [8]
+ *
+ *     D18F0x110 [DRAM Base Address]
+ *     DF3     IntLvNumSockets [8]
+ *     DF3p5   IntLvNumSockets [8]
+ *
+ *     D18F7xE0C [DRAM Address Interleave]
+ *     DF4     IntLvNumSockets [18]
+ *
+ *     D18F7x20C [DRAM Address Interleave]
+ *     DF4p5   IntLvNumSockets [18]
+ */
+#define DF2_INTLV_NUM_SOCKETS  BIT(8)
+#define DF4_INTLV_NUM_SOCKETS  BIT(18)
+
+/*
+ * Legacy MMIO Hole Enable
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     D18F0x110 [DRAM Base Address]
+ *     DF2     LgcyMmioHoleEn  [1]
+ *     DF3     LgcyMmioHoleEn  [1]
+ *     DF3p5   LgcyMmioHoleEn  [1]
+ *
+ *     D18F7xE08 [DRAM Address Control]
+ *     DF4     LgcyMmioHoleEn  [1]
+ *
+ *     D18F7x208 [DRAM Address Control]
+ *     DF4p5   LgcyMmioHoleEn  [1]
+ */
+#define DF_LEGACY_MMIO_HOLE_EN BIT(1)
+
+/*
+ * Log2 Address 64K Space 0
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname               Bits
+ *
+ *     DF2     N/A
+ *
+ *     D18F2x90 [Non-power-of-2 channel Configuration Register for COH_ST DRAM Address Maps]
+ *     DF3     Log2Addr64KSpace0       [5:0]
+ *
+ *     DF3p5   N/A
+ *     DF4     N/A
+ *     DF4p5   N/A
+ */
+#define DF_LOG2_ADDR_64K_SPACE0                GENMASK(5, 0)
+
+/*
+ * Major Revision
+ *
+ * Access type: Broadcast
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     DF2     N/A
+ *     DF3     N/A
+ *     DF3p5   N/A
+ *
+ *     D18F0x040 [Fabric Block Instance Count]
+ *     DF4     MajorRevision   [27:24]
+ *     DF4p5   MajorRevision   [27:24]
+ */
+#define DF_MAJOR_REVISION      GENMASK(27, 24)
+
+/*
+ * Minor Revision
+ *
+ * Access type: Broadcast
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     DF2     N/A
+ *     DF3     N/A
+ *     DF3p5   N/A
+ *
+ *     D18F0x040 [Fabric Block Instance Count]
+ *     DF4     MinorRevision   [23:16]
+ *     DF4p5   MinorRevision   [23:16]
+ */
+#define DF_MINOR_REVISION      GENMASK(23, 16)
+
+/*
+ * Node ID Mask
+ *
+ * Access type: Broadcast
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     DF2     N/A
+ *
+ *     D18F1x208 [System Fabric ID Mask 0]
+ *     DF3     NodeIdMask      [25:16]
+ *
+ *     D18F1x150 [System Fabric ID Mask 0]
+ *     DF3p5   NodeIdMask      [31:16]
+ *
+ *     D18F4x1B0 [System Fabric ID Mask 0]
+ *     DF4     NodeIdMask      [31:16]
+ *     DF4p5   NodeIdMask      [31:16]
+ */
+#define DF3_NODE_ID_MASK       GENMASK(25, 16)
+#define DF4_NODE_ID_MASK       GENMASK(31, 16)
+
+/*
+ * Node ID Shift
+ *
+ * Access type: Broadcast
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     DF2     N/A
+ *
+ *     D18F1x20C [System Fabric ID Mask 1]
+ *     DF3     NodeIdShift     [3:0]
+ *
+ *     D18F1x154 [System Fabric ID Mask 1]
+ *     DF3p5   NodeIdShift     [3:0]
+ *
+ *     D18F4x1B4 [System Fabric ID Mask 1]
+ *     DF4     NodeIdShift     [3:0]
+ *     DF4p5   NodeIdShift     [3:0]
+ */
+#define DF3_NODE_ID_SHIFT      GENMASK(3, 0)
+
+/*
+ * Remap Enable
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     DF2     N/A
+ *     DF3     N/A
+ *     DF3p5   N/A
+ *
+ *     D18F7xE08 [DRAM Address Control]
+ *     DF4     RemapEn         [4]
+ *
+ *     D18F7x208 [DRAM Address Control]
+ *     DF4p5   RemapEn         [4]
+ */
+#define DF4_REMAP_EN           BIT(4)
+
+/*
+ * Remap Select
+ *
+ * Access type: Instance
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ *     DF2     N/A
+ *     DF3     N/A
+ *     DF3p5   N/A
+ *
+ *     D18F7xE08 [DRAM Address Control]
+ *     DF4     RemapSel        [7:5]
+ *
+ *     D18F7x208 [DRAM Address Control]
+ *     DF4p5   RemapSel        [6:5]
+ */
+#define DF4_REMAP_SEL          GENMASK(7, 5)
+#define DF4p5_REMAP_SEL                GENMASK(6, 5)
+
+/*
+ * Socket ID Mask
+ *
+ * Access type: Broadcast
+ *
+ * Register
+ *     Rev     Fieldname       Bits
+ *
+ * D18F1x208 [System Fabric ID Mask]
+ *     DF2     SocketIdMask    [23:16]
+ *
+ * D18F1x20C [System Fabric ID Mask 1]
+ *     DF3     SocketIdMask    [26:24]
+ *
+ * D18F1x158 [System Fabric ID Mask 2]
+ *     DF3p5   SocketIdMask    [31:16]
+ *
+ * D18F4x1B8 [System Fabric ID Mask 2]
+ *     DF4     SocketIdMask    [31:16]
+ *     DF4p5   SocketIdMask    [31:16]
+ */
+#define DF2_SOCKET_ID_MASK     GENMASK(23, 16)
+#define DF3_SOCKET_ID_MASK     GENMASK(26, 24)
+#define DF4_SOCKET_ID_MASK     GENMASK(31, 16)
+
+/*
+ * Socket ID Shift
+ *
+ * Access type: Broadcast
+ *
+ * Register
+ *             Rev     Fieldname       Bits
+ *
+ * D18F1x208 [System Fabric ID Mask]
+ *     DF2     SocketIdShift   [31:28]
+ *
+ * D18F1x20C [System Fabric ID Mask 1]
+ *     DF3     SocketIdShift   [9:8]
+ *
+ * D18F1x158 [System Fabric ID Mask 2]
+ *     DF3p5   SocketIdShift   [11:8]
+ *
+ * D18F4x1B4 [System Fabric ID Mask 1]
+ *     DF4     SocketIdShift   [11:8]
+ *     DF4p5   SocketIdShift   [11:8]
+ */
+#define DF2_SOCKET_ID_SHIFT    GENMASK(31, 28)
+#define DF3_SOCKET_ID_SHIFT    GENMASK(9, 8)
+#define DF4_SOCKET_ID_SHIFT    GENMASK(11, 8)
diff --git a/drivers/ras/amd/atl/system.c b/drivers/ras/amd/atl/system.c
new file mode 100644 (file)
index 0000000..701349e
--- /dev/null
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD Address Translation Library
+ *
+ * system.c : Functions to read and save system-wide data
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
+ */
+
+#include "internal.h"
+
+int determine_node_id(struct addr_ctx *ctx, u8 socket_id, u8 die_id)
+{
+       u16 socket_id_bits, die_id_bits;
+
+       if (socket_id > 0 && df_cfg.socket_id_mask == 0) {
+               atl_debug(ctx, "Invalid socket inputs: socket_id=%u socket_id_mask=0x%x",
+                         socket_id, df_cfg.socket_id_mask);
+               return -EINVAL;
+       }
+
+       /* Do each step independently to avoid shift out-of-bounds issues. */
+       socket_id_bits =        socket_id;
+       socket_id_bits <<=      df_cfg.socket_id_shift;
+       socket_id_bits &=       df_cfg.socket_id_mask;
+
+       if (die_id > 0 && df_cfg.die_id_mask == 0) {
+               atl_debug(ctx, "Invalid die inputs: die_id=%u die_id_mask=0x%x",
+                         die_id, df_cfg.die_id_mask);
+               return -EINVAL;
+       }
+
+       /* Do each step independently to avoid shift out-of-bounds issues. */
+       die_id_bits =           die_id;
+       die_id_bits <<=         df_cfg.die_id_shift;
+       die_id_bits &=          df_cfg.die_id_mask;
+
+       ctx->node_id = (socket_id_bits | die_id_bits) >> df_cfg.node_id_shift;
+       return 0;
+}
+
+static void df2_get_masks_shifts(u32 mask0)
+{
+       df_cfg.socket_id_shift          = FIELD_GET(DF2_SOCKET_ID_SHIFT, mask0);
+       df_cfg.socket_id_mask           = FIELD_GET(DF2_SOCKET_ID_MASK, mask0);
+       df_cfg.die_id_shift             = FIELD_GET(DF2_DIE_ID_SHIFT, mask0);
+       df_cfg.die_id_mask              = FIELD_GET(DF2_DIE_ID_MASK, mask0);
+       df_cfg.node_id_shift            = df_cfg.die_id_shift;
+       df_cfg.node_id_mask             = df_cfg.socket_id_mask | df_cfg.die_id_mask;
+       df_cfg.component_id_mask        = ~df_cfg.node_id_mask;
+}
+
+static void df3_get_masks_shifts(u32 mask0, u32 mask1)
+{
+       df_cfg.component_id_mask        = FIELD_GET(DF3_COMPONENT_ID_MASK, mask0);
+       df_cfg.node_id_mask             = FIELD_GET(DF3_NODE_ID_MASK, mask0);
+
+       df_cfg.node_id_shift            = FIELD_GET(DF3_NODE_ID_SHIFT, mask1);
+       df_cfg.socket_id_shift          = FIELD_GET(DF3_SOCKET_ID_SHIFT, mask1);
+       df_cfg.socket_id_mask           = FIELD_GET(DF3_SOCKET_ID_MASK, mask1);
+       df_cfg.die_id_mask              = FIELD_GET(DF3_DIE_ID_MASK, mask1);
+}
+
+static void df3p5_get_masks_shifts(u32 mask0, u32 mask1, u32 mask2)
+{
+       df_cfg.component_id_mask        = FIELD_GET(DF4_COMPONENT_ID_MASK, mask0);
+       df_cfg.node_id_mask             = FIELD_GET(DF4_NODE_ID_MASK, mask0);
+
+       df_cfg.node_id_shift            = FIELD_GET(DF3_NODE_ID_SHIFT, mask1);
+       df_cfg.socket_id_shift          = FIELD_GET(DF4_SOCKET_ID_SHIFT, mask1);
+
+       df_cfg.socket_id_mask           = FIELD_GET(DF4_SOCKET_ID_MASK, mask2);
+       df_cfg.die_id_mask              = FIELD_GET(DF4_DIE_ID_MASK, mask2);
+}
+
+static void df4_get_masks_shifts(u32 mask0, u32 mask1, u32 mask2)
+{
+       df3p5_get_masks_shifts(mask0, mask1, mask2);
+
+       if (!(df_cfg.flags.socket_id_shift_quirk && df_cfg.socket_id_shift == 1))
+               return;
+
+       df_cfg.socket_id_shift  = 0;
+       df_cfg.socket_id_mask   = 1;
+       df_cfg.die_id_shift     = 0;
+       df_cfg.die_id_mask      = 0;
+       df_cfg.node_id_shift    = 8;
+       df_cfg.node_id_mask     = 0x100;
+}
+
+static int df4_get_fabric_id_mask_registers(void)
+{
+       u32 mask0, mask1, mask2;
+
+       /* Read D18F4x1B0 (SystemFabricIdMask0) */
+       if (df_indirect_read_broadcast(0, 4, 0x1B0, &mask0))
+               return -EINVAL;
+
+       /* Read D18F4x1B4 (SystemFabricIdMask1) */
+       if (df_indirect_read_broadcast(0, 4, 0x1B4, &mask1))
+               return -EINVAL;
+
+       /* Read D18F4x1B8 (SystemFabricIdMask2) */
+       if (df_indirect_read_broadcast(0, 4, 0x1B8, &mask2))
+               return -EINVAL;
+
+       df4_get_masks_shifts(mask0, mask1, mask2);
+       return 0;
+}
+
+static int df4_determine_df_rev(u32 reg)
+{
+       df_cfg.rev = FIELD_GET(DF_MINOR_REVISION, reg) < 5 ? DF4 : DF4p5;
+
+       /* Check for special cases or quirks based on Device/Vendor IDs.*/
+
+       /* Read D18F0x000 (DeviceVendorId0) */
+       if (df_indirect_read_broadcast(0, 0, 0, &reg))
+               return -EINVAL;
+
+       if (reg == DF_FUNC0_ID_ZEN4_SERVER)
+               df_cfg.flags.socket_id_shift_quirk = 1;
+
+       if (reg == DF_FUNC0_ID_MI300) {
+               df_cfg.flags.heterogeneous = 1;
+
+               if (get_addr_hash_mi300())
+                       return -EINVAL;
+       }
+
+       return df4_get_fabric_id_mask_registers();
+}
+
+static int determine_df_rev_legacy(void)
+{
+       u32 fabric_id_mask0, fabric_id_mask1, fabric_id_mask2;
+
+       /*
+        * Check for DF3.5.
+        *
+        * Component ID Mask must be non-zero. Register D18F1x150 is
+        * reserved pre-DF3.5, so value will be Read-as-Zero.
+        */
+
+       /* Read D18F1x150 (SystemFabricIdMask0). */
+       if (df_indirect_read_broadcast(0, 1, 0x150, &fabric_id_mask0))
+               return -EINVAL;
+
+       if (FIELD_GET(DF4_COMPONENT_ID_MASK, fabric_id_mask0)) {
+               df_cfg.rev = DF3p5;
+
+               /* Read D18F1x154 (SystemFabricIdMask1) */
+               if (df_indirect_read_broadcast(0, 1, 0x154, &fabric_id_mask1))
+                       return -EINVAL;
+
+               /* Read D18F1x158 (SystemFabricIdMask2) */
+               if (df_indirect_read_broadcast(0, 1, 0x158, &fabric_id_mask2))
+                       return -EINVAL;
+
+               df3p5_get_masks_shifts(fabric_id_mask0, fabric_id_mask1, fabric_id_mask2);
+               return 0;
+       }
+
+       /*
+        * Check for DF3.
+        *
+        * Component ID Mask must be non-zero. Field is Read-as-Zero on DF2.
+        */
+
+       /* Read D18F1x208 (SystemFabricIdMask). */
+       if (df_indirect_read_broadcast(0, 1, 0x208, &fabric_id_mask0))
+               return -EINVAL;
+
+       if (FIELD_GET(DF3_COMPONENT_ID_MASK, fabric_id_mask0)) {
+               df_cfg.rev = DF3;
+
+               /* Read D18F1x20C (SystemFabricIdMask1) */
+               if (df_indirect_read_broadcast(0, 1, 0x20C, &fabric_id_mask1))
+                       return -EINVAL;
+
+               df3_get_masks_shifts(fabric_id_mask0, fabric_id_mask1);
+               return 0;
+       }
+
+       /* Default to DF2. */
+       df_cfg.rev = DF2;
+       df2_get_masks_shifts(fabric_id_mask0);
+       return 0;
+}
+
+static int determine_df_rev(void)
+{
+       u32 reg;
+       u8 rev;
+
+       if (df_cfg.rev != UNKNOWN)
+               return 0;
+
+       /* Read D18F0x40 (FabricBlockInstanceCount). */
+       if (df_indirect_read_broadcast(0, 0, 0x40, &reg))
+               return -EINVAL;
+
+       /*
+        * Revision fields added for DF4 and later.
+        *
+        * Major revision of '0' is found pre-DF4. Field is Read-as-Zero.
+        */
+       rev = FIELD_GET(DF_MAJOR_REVISION, reg);
+       if (!rev)
+               return determine_df_rev_legacy();
+
+       /*
+        * Fail out for major revisions other than '4'.
+        *
+        * Explicit support should be added for newer systems to avoid issues.
+        */
+       if (rev == 4)
+               return df4_determine_df_rev(reg);
+
+       return -EINVAL;
+}
+
+static void get_num_maps(void)
+{
+       switch (df_cfg.rev) {
+       case DF2:
+       case DF3:
+       case DF3p5:
+               df_cfg.num_coh_st_maps  = 2;
+               break;
+       case DF4:
+       case DF4p5:
+               df_cfg.num_coh_st_maps  = 4;
+               break;
+       default:
+               atl_debug_on_bad_df_rev();
+       }
+}
+
+static void apply_node_id_shift(void)
+{
+       if (df_cfg.rev == DF2)
+               return;
+
+       df_cfg.die_id_shift             = df_cfg.node_id_shift;
+       df_cfg.die_id_mask              <<= df_cfg.node_id_shift;
+       df_cfg.socket_id_mask           <<= df_cfg.node_id_shift;
+       df_cfg.socket_id_shift          += df_cfg.node_id_shift;
+}
+
+static void dump_df_cfg(void)
+{
+       pr_debug("rev=0x%x",                            df_cfg.rev);
+
+       pr_debug("component_id_mask=0x%x",              df_cfg.component_id_mask);
+       pr_debug("die_id_mask=0x%x",                    df_cfg.die_id_mask);
+       pr_debug("node_id_mask=0x%x",                   df_cfg.node_id_mask);
+       pr_debug("socket_id_mask=0x%x",                 df_cfg.socket_id_mask);
+
+       pr_debug("die_id_shift=0x%x",                   df_cfg.die_id_shift);
+       pr_debug("node_id_shift=0x%x",                  df_cfg.node_id_shift);
+       pr_debug("socket_id_shift=0x%x",                df_cfg.socket_id_shift);
+
+       pr_debug("num_coh_st_maps=%u",                  df_cfg.num_coh_st_maps);
+
+       pr_debug("flags.legacy_ficaa=%u",               df_cfg.flags.legacy_ficaa);
+       pr_debug("flags.socket_id_shift_quirk=%u",      df_cfg.flags.socket_id_shift_quirk);
+}
+
+int get_df_system_info(void)
+{
+       if (determine_df_rev()) {
+               pr_warn("amd_atl: Failed to determine DF Revision");
+               df_cfg.rev = UNKNOWN;
+               return -EINVAL;
+       }
+
+       apply_node_id_shift();
+
+       get_num_maps();
+
+       dump_df_cfg();
+
+       return 0;
+}
diff --git a/drivers/ras/amd/atl/umc.c b/drivers/ras/amd/atl/umc.c
new file mode 100644 (file)
index 0000000..59b6169
--- /dev/null
@@ -0,0 +1,341 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD Address Translation Library
+ *
+ * umc.c : Unified Memory Controller (UMC) topology helpers
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
+ */
+
+#include "internal.h"
+
+/*
+ * MI300 has a fixed, model-specific mapping between a UMC instance and
+ * its related Data Fabric Coherent Station instance.
+ *
+ * The MCA_IPID_UMC[InstanceId] field holds a unique identifier for the
+ * UMC instance within a Node. Use this to find the appropriate Coherent
+ * Station ID.
+ *
+ * Redundant bits were removed from the map below.
+ */
+static const u16 umc_coh_st_map[32] = {
+       0x393, 0x293, 0x193, 0x093,
+       0x392, 0x292, 0x192, 0x092,
+       0x391, 0x291, 0x191, 0x091,
+       0x390, 0x290, 0x190, 0x090,
+       0x793, 0x693, 0x593, 0x493,
+       0x792, 0x692, 0x592, 0x492,
+       0x791, 0x691, 0x591, 0x491,
+       0x790, 0x690, 0x590, 0x490,
+};
+
+#define UMC_ID_MI300 GENMASK(23, 12)
+static u8 get_coh_st_inst_id_mi300(struct atl_err *err)
+{
+       u16 umc_id = FIELD_GET(UMC_ID_MI300, err->ipid);
+       u8 i;
+
+       for (i = 0; i < ARRAY_SIZE(umc_coh_st_map); i++) {
+               if (umc_id == umc_coh_st_map[i])
+                       break;
+       }
+
+       WARN_ON_ONCE(i >= ARRAY_SIZE(umc_coh_st_map));
+
+       return i;
+}
+
+/* XOR the bits in @val. */
+static u16 bitwise_xor_bits(u16 val)
+{
+       u16 tmp = 0;
+       u8 i;
+
+       for (i = 0; i < 16; i++)
+               tmp ^= (val >> i) & 0x1;
+
+       return tmp;
+}
+
+struct xor_bits {
+       bool    xor_enable;
+       u16     col_xor;
+       u32     row_xor;
+};
+
+#define NUM_BANK_BITS  4
+
+static struct {
+       /* UMC::CH::AddrHashBank */
+       struct xor_bits bank[NUM_BANK_BITS];
+
+       /* UMC::CH::AddrHashPC */
+       struct xor_bits pc;
+
+       /* UMC::CH::AddrHashPC2 */
+       u8              bank_xor;
+} addr_hash;
+
+#define MI300_UMC_CH_BASE      0x90000
+#define MI300_ADDR_HASH_BANK0  (MI300_UMC_CH_BASE + 0xC8)
+#define MI300_ADDR_HASH_PC     (MI300_UMC_CH_BASE + 0xE0)
+#define MI300_ADDR_HASH_PC2    (MI300_UMC_CH_BASE + 0xE4)
+
+#define ADDR_HASH_XOR_EN       BIT(0)
+#define ADDR_HASH_COL_XOR      GENMASK(13, 1)
+#define ADDR_HASH_ROW_XOR      GENMASK(31, 14)
+#define ADDR_HASH_BANK_XOR     GENMASK(5, 0)
+
+/*
+ * Read UMC::CH::AddrHash{Bank,PC,PC2} registers to get XOR bits used
+ * for hashing. Do this during module init, since the values will not
+ * change during run time.
+ *
+ * These registers are instantiated for each UMC across each AMD Node.
+ * However, they should be identically programmed due to the fixed hardware
+ * design of MI300 systems. So read the values from Node 0 UMC 0 and keep a
+ * single global structure for simplicity.
+ */
+int get_addr_hash_mi300(void)
+{
+       u32 temp;
+       int ret;
+       u8 i;
+
+       for (i = 0; i < NUM_BANK_BITS; i++) {
+               ret = amd_smn_read(0, MI300_ADDR_HASH_BANK0 + (i * 4), &temp);
+               if (ret)
+                       return ret;
+
+               addr_hash.bank[i].xor_enable = FIELD_GET(ADDR_HASH_XOR_EN,  temp);
+               addr_hash.bank[i].col_xor    = FIELD_GET(ADDR_HASH_COL_XOR, temp);
+               addr_hash.bank[i].row_xor    = FIELD_GET(ADDR_HASH_ROW_XOR, temp);
+       }
+
+       ret = amd_smn_read(0, MI300_ADDR_HASH_PC, &temp);
+       if (ret)
+               return ret;
+
+       addr_hash.pc.xor_enable = FIELD_GET(ADDR_HASH_XOR_EN,  temp);
+       addr_hash.pc.col_xor    = FIELD_GET(ADDR_HASH_COL_XOR, temp);
+       addr_hash.pc.row_xor    = FIELD_GET(ADDR_HASH_ROW_XOR, temp);
+
+       ret = amd_smn_read(0, MI300_ADDR_HASH_PC2, &temp);
+       if (ret)
+               return ret;
+
+       addr_hash.bank_xor = FIELD_GET(ADDR_HASH_BANK_XOR, temp);
+
+       return 0;
+}
+
+/*
+ * MI300 systems report a DRAM address in MCA_ADDR for DRAM ECC errors. This must
+ * be converted to the intermediate normalized address (NA) before translating to a
+ * system physical address.
+ *
+ * The DRAM address includes bank, row, and column. Also included are bits for
+ * pseudochannel (PC) and stack ID (SID).
+ *
+ * Abbreviations: (S)tack ID, (P)seudochannel, (R)ow, (B)ank, (C)olumn, (Z)ero
+ *
+ * The MCA address format is as follows:
+ *     MCA_ADDR[27:0] = {S[1:0], P[0], R[14:0], B[3:0], C[4:0], Z[0]}
+ *
+ * The normalized address format is fixed in hardware and is as follows:
+ *     NA[30:0] = {S[1:0], R[13:0], C4, B[1:0], B[3:2], C[3:2], P, C[1:0], Z[4:0]}
+ *
+ * Additionally, the PC and Bank bits may be hashed. This must be accounted for before
+ * reconstructing the normalized address.
+ */
+#define MI300_UMC_MCA_COL      GENMASK(5, 1)
+#define MI300_UMC_MCA_BANK     GENMASK(9, 6)
+#define MI300_UMC_MCA_ROW      GENMASK(24, 10)
+#define MI300_UMC_MCA_PC       BIT(25)
+#define MI300_UMC_MCA_SID      GENMASK(27, 26)
+
+#define MI300_NA_COL_1_0       GENMASK(6, 5)
+#define MI300_NA_PC            BIT(7)
+#define MI300_NA_COL_3_2       GENMASK(9, 8)
+#define MI300_NA_BANK_3_2      GENMASK(11, 10)
+#define MI300_NA_BANK_1_0      GENMASK(13, 12)
+#define MI300_NA_COL_4         BIT(14)
+#define MI300_NA_ROW           GENMASK(28, 15)
+#define MI300_NA_SID           GENMASK(30, 29)
+
+static unsigned long convert_dram_to_norm_addr_mi300(unsigned long addr)
+{
+       u16 i, col, row, bank, pc, sid, temp;
+
+       col  = FIELD_GET(MI300_UMC_MCA_COL,  addr);
+       bank = FIELD_GET(MI300_UMC_MCA_BANK, addr);
+       row  = FIELD_GET(MI300_UMC_MCA_ROW,  addr);
+       pc   = FIELD_GET(MI300_UMC_MCA_PC,   addr);
+       sid  = FIELD_GET(MI300_UMC_MCA_SID,  addr);
+
+       /* Calculate hash for each Bank bit. */
+       for (i = 0; i < NUM_BANK_BITS; i++) {
+               if (!addr_hash.bank[i].xor_enable)
+                       continue;
+
+               temp  = bitwise_xor_bits(col & addr_hash.bank[i].col_xor);
+               temp ^= bitwise_xor_bits(row & addr_hash.bank[i].row_xor);
+               bank ^= temp << i;
+       }
+
+       /* Calculate hash for PC bit. */
+       if (addr_hash.pc.xor_enable) {
+               /* Bits SID[1:0] act as Bank[6:5] for PC hash, so apply them here. */
+               bank |= sid << 5;
+
+               temp  = bitwise_xor_bits(col  & addr_hash.pc.col_xor);
+               temp ^= bitwise_xor_bits(row  & addr_hash.pc.row_xor);
+               temp ^= bitwise_xor_bits(bank & addr_hash.bank_xor);
+               pc   ^= temp;
+
+               /* Drop SID bits for the sake of debug printing later. */
+               bank &= 0x1F;
+       }
+
+       /* Reconstruct the normalized address starting with NA[4:0] = 0 */
+       addr  = 0;
+
+       /* NA[6:5] = Column[1:0] */
+       temp  = col & 0x3;
+       addr |= FIELD_PREP(MI300_NA_COL_1_0, temp);
+
+       /* NA[7] = PC */
+       addr |= FIELD_PREP(MI300_NA_PC, pc);
+
+       /* NA[9:8] = Column[3:2] */
+       temp  = (col >> 2) & 0x3;
+       addr |= FIELD_PREP(MI300_NA_COL_3_2, temp);
+
+       /* NA[11:10] = Bank[3:2] */
+       temp  = (bank >> 2) & 0x3;
+       addr |= FIELD_PREP(MI300_NA_BANK_3_2, temp);
+
+       /* NA[13:12] = Bank[1:0] */
+       temp  = bank & 0x3;
+       addr |= FIELD_PREP(MI300_NA_BANK_1_0, temp);
+
+       /* NA[14] = Column[4] */
+       temp  = (col >> 4) & 0x1;
+       addr |= FIELD_PREP(MI300_NA_COL_4, temp);
+
+       /* NA[28:15] = Row[13:0] */
+       addr |= FIELD_PREP(MI300_NA_ROW, row);
+
+       /* NA[30:29] = SID[1:0] */
+       addr |= FIELD_PREP(MI300_NA_SID, sid);
+
+       pr_debug("Addr=0x%016lx", addr);
+       pr_debug("Bank=%u Row=%u Column=%u PC=%u SID=%u", bank, row, col, pc, sid);
+
+       return addr;
+}
+
+/*
+ * When a DRAM ECC error occurs on MI300 systems, it is recommended to retire
+ * all memory within that DRAM row. This applies to the memory with a DRAM
+ * bank.
+ *
+ * To find the memory addresses, loop through permutations of the DRAM column
+ * bits and find the System Physical address of each. The column bits are used
+ * to calculate the intermediate Normalized address, so all permutations should
+ * be checked.
+ *
+ * See amd_atl::convert_dram_to_norm_addr_mi300() for MI300 address formats.
+ */
+#define MI300_NUM_COL          BIT(HWEIGHT(MI300_UMC_MCA_COL))
+static void retire_row_mi300(struct atl_err *a_err)
+{
+       unsigned long addr;
+       struct page *p;
+       u8 col;
+
+       for (col = 0; col < MI300_NUM_COL; col++) {
+               a_err->addr &= ~MI300_UMC_MCA_COL;
+               a_err->addr |= FIELD_PREP(MI300_UMC_MCA_COL, col);
+
+               addr = amd_convert_umc_mca_addr_to_sys_addr(a_err);
+               if (IS_ERR_VALUE(addr))
+                       continue;
+
+               addr = PHYS_PFN(addr);
+
+               /*
+                * Skip invalid or already poisoned pages to avoid unnecessary
+                * error messages from memory_failure().
+                */
+               p = pfn_to_online_page(addr);
+               if (!p)
+                       continue;
+
+               if (PageHWPoison(p))
+                       continue;
+
+               memory_failure(addr, 0);
+       }
+}
+
+void amd_retire_dram_row(struct atl_err *a_err)
+{
+       if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous)
+               return retire_row_mi300(a_err);
+}
+EXPORT_SYMBOL_GPL(amd_retire_dram_row);
+
+static unsigned long get_addr(unsigned long addr)
+{
+       if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous)
+               return convert_dram_to_norm_addr_mi300(addr);
+
+       return addr;
+}
+
+#define MCA_IPID_INST_ID_HI    GENMASK_ULL(47, 44)
+static u8 get_die_id(struct atl_err *err)
+{
+       /*
+        * AMD Node ID is provided in MCA_IPID[InstanceIdHi], and this
+        * needs to be divided by 4 to get the internal Die ID.
+        */
+       if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous) {
+               u8 node_id = FIELD_GET(MCA_IPID_INST_ID_HI, err->ipid);
+
+               return node_id >> 2;
+       }
+
+       /*
+        * For CPUs, this is the AMD Node ID modulo the number
+        * of AMD Nodes per socket.
+        */
+       return topology_amd_node_id(err->cpu) % topology_amd_nodes_per_pkg();
+}
+
+#define UMC_CHANNEL_NUM        GENMASK(31, 20)
+static u8 get_coh_st_inst_id(struct atl_err *err)
+{
+       if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous)
+               return get_coh_st_inst_id_mi300(err);
+
+       return FIELD_GET(UMC_CHANNEL_NUM, err->ipid);
+}
+
+unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
+{
+       u8 socket_id = topology_physical_package_id(err->cpu);
+       u8 coh_st_inst_id = get_coh_st_inst_id(err);
+       unsigned long addr = get_addr(err->addr);
+       u8 die_id = get_die_id(err);
+
+       pr_debug("socket_id=0x%x die_id=0x%x coh_st_inst_id=0x%x addr=0x%016lx",
+                socket_id, die_id, coh_st_inst_id, addr);
+
+       return norm_to_sys_addr(socket_id, die_id, coh_st_inst_id, addr);
+}
diff --git a/drivers/ras/amd/fmpm.c b/drivers/ras/amd/fmpm.c
new file mode 100644 (file)
index 0000000..2f4ac95
--- /dev/null
@@ -0,0 +1,1013 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * FRU (Field-Replaceable Unit) Memory Poison Manager
+ *
+ * Copyright (c) 2024, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Authors:
+ *     Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>
+ *     Muralidhara M K <muralidhara.mk@amd.com>
+ *     Yazen Ghannam <Yazen.Ghannam@amd.com>
+ *
+ * Implementation notes, assumptions, and limitations:
+ *
+ * - FRU memory poison section and memory poison descriptor definitions are not yet
+ *   included in the UEFI specification. So they are defined here. Afterwards, they
+ *   may be moved to linux/cper.h, if appropriate.
+ *
+ * - Platforms based on AMD MI300 systems will be the first to use these structures.
+ *   There are a number of assumptions made here that will need to be generalized
+ *   to support other platforms.
+ *
+ *   AMD MI300-based platform(s) assumptions:
+ *   - Memory errors are reported through x86 MCA.
+ *   - The entire DRAM row containing a memory error should be retired.
+ *   - There will be (1) FRU memory poison section per CPER.
+ *   - The FRU will be the CPU package (processor socket).
+ *   - The default number of memory poison descriptor entries should be (8).
+ *   - The platform will use ACPI ERST for persistent storage.
+ *   - All FRU records should be saved to persistent storage. Module init will
+ *     fail if any FRU record is not successfully written.
+ *
+ * - Boot time memory retirement may occur later than ideal due to dependencies
+ *   on other libraries and drivers. This leaves a gap where bad memory may be
+ *   accessed during early boot stages.
+ *
+ * - Enough memory should be pre-allocated for each FRU record to be able to hold
+ *   the expected number of descriptor entries. This, mostly empty, record is
+ *   written to storage during init time. Subsequent writes to the same record
+ *   should allow the Platform to update the stored record in-place. Otherwise,
+ *   if the record is extended, then the Platform may need to perform costly memory
+ *   management operations on the storage. For example, the Platform may spend time
+ *   in Firmware copying and invalidating memory on a relatively slow SPI ROM.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/cper.h>
+#include <linux/ras.h>
+#include <linux/cpu.h>
+
+#include <acpi/apei.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/mce.h>
+
+#include "../debugfs.h"
+
+#define INVALID_CPU                    UINT_MAX
+
+/* Validation Bits */
+#define FMP_VALID_ARCH_TYPE            BIT_ULL(0)
+#define FMP_VALID_ARCH                 BIT_ULL(1)
+#define FMP_VALID_ID_TYPE              BIT_ULL(2)
+#define FMP_VALID_ID                   BIT_ULL(3)
+#define FMP_VALID_LIST_ENTRIES         BIT_ULL(4)
+#define FMP_VALID_LIST                 BIT_ULL(5)
+
+/* FRU Architecture Types */
+#define FMP_ARCH_TYPE_X86_CPUID_1_EAX  0
+
+/* FRU ID Types */
+#define FMP_ID_TYPE_X86_PPIN           0
+
+/* FRU Memory Poison Section */
+struct cper_sec_fru_mem_poison {
+       u32 checksum;
+       u64 validation_bits;
+       u32 fru_arch_type;
+       u64 fru_arch;
+       u32 fru_id_type;
+       u64 fru_id;
+       u32 nr_entries;
+} __packed;
+
+/* FRU Descriptor ID Types */
+#define FPD_HW_ID_TYPE_MCA_IPID                0
+
+/* FRU Descriptor Address Types */
+#define FPD_ADDR_TYPE_MCA_ADDR         0
+
+/* Memory Poison Descriptor */
+struct cper_fru_poison_desc {
+       u64 timestamp;
+       u32 hw_id_type;
+       u64 hw_id;
+       u32 addr_type;
+       u64 addr;
+} __packed;
+
+/* Collection of headers and sections for easy pointer use. */
+struct fru_rec {
+       struct cper_record_header       hdr;
+       struct cper_section_descriptor  sec_desc;
+       struct cper_sec_fru_mem_poison  fmp;
+       struct cper_fru_poison_desc     entries[];
+} __packed;
+
+/*
+ * Pointers to the complete CPER record of each FRU.
+ *
+ * Memory allocation will include padded space for descriptor entries.
+ */
+static struct fru_rec **fru_records;
+
+/* system physical addresses array */
+static u64 *spa_entries;
+
+#define INVALID_SPA    ~0ULL
+
+static struct dentry *fmpm_dfs_dir;
+static struct dentry *fmpm_dfs_entries;
+
+#define CPER_CREATOR_FMP                                               \
+       GUID_INIT(0xcd5c2993, 0xf4b2, 0x41b2, 0xb5, 0xd4, 0xf9, 0xc3,   \
+                 0xa0, 0x33, 0x08, 0x75)
+
+#define CPER_SECTION_TYPE_FMP                                          \
+       GUID_INIT(0x5e4706c1, 0x5356, 0x48c6, 0x93, 0x0b, 0x52, 0xf2,   \
+                 0x12, 0x0a, 0x44, 0x58)
+
+/**
+ * DOC: max_nr_entries (byte)
+ * Maximum number of descriptor entries possible for each FRU.
+ *
+ * Values between '1' and '255' are valid.
+ * No input or '0' will default to FMPM_DEFAULT_MAX_NR_ENTRIES.
+ */
+static u8 max_nr_entries;
+module_param(max_nr_entries, byte, 0644);
+MODULE_PARM_DESC(max_nr_entries,
+                "Maximum number of memory poison descriptor entries per FRU");
+
+#define FMPM_DEFAULT_MAX_NR_ENTRIES    8
+
+/* Maximum number of FRUs in the system. */
+#define FMPM_MAX_NR_FRU                        256
+static unsigned int max_nr_fru;
+
+/* Total length of record including headers and list of descriptor entries. */
+static size_t max_rec_len;
+
+/* Total number of SPA entries across all FRUs. */
+static unsigned int spa_nr_entries;
+
+/*
+ * Protect the local records cache in fru_records and prevent concurrent
+ * writes to storage. This is only needed after init once notifier block
+ * registration is done.
+ *
+ * The majority of a record is fixed at module init and will not change
+ * during run time. The entries within a record will be updated as new
+ * errors are reported. The mutex should be held whenever the entries are
+ * accessed during run time.
+ */
+static DEFINE_MUTEX(fmpm_update_mutex);
+
+#define for_each_fru(i, rec) \
+       for (i = 0; rec = fru_records[i], i < max_nr_fru; i++)
+
+static inline u32 get_fmp_len(struct fru_rec *rec)
+{
+       return rec->sec_desc.section_length - sizeof(struct cper_section_descriptor);
+}
+
+static struct fru_rec *get_fru_record(u64 fru_id)
+{
+       struct fru_rec *rec;
+       unsigned int i;
+
+       for_each_fru(i, rec) {
+               if (rec->fmp.fru_id == fru_id)
+                       return rec;
+       }
+
+       pr_debug("Record not found for FRU 0x%016llx\n", fru_id);
+
+       return NULL;
+}
+
+/*
+ * Sum up all bytes within the FRU Memory Poison Section including the Memory
+ * Poison Descriptor entries.
+ *
+ * Don't include the old checksum here. It's a u32 value, so summing each of its
+ * bytes will give the wrong total.
+ */
+static u32 do_fmp_checksum(struct cper_sec_fru_mem_poison *fmp, u32 len)
+{
+       u32 checksum = 0;
+       u8 *buf, *end;
+
+       /* Skip old checksum. */
+       buf = (u8 *)fmp + sizeof(u32);
+       end = buf + len;
+
+       while (buf < end)
+               checksum += (u8)(*(buf++));
+
+       return checksum;
+}
+
+static int update_record_on_storage(struct fru_rec *rec)
+{
+       u32 len, checksum;
+       int ret;
+
+       /* Calculate a new checksum. */
+       len = get_fmp_len(rec);
+
+       /* Get the current total. */
+       checksum = do_fmp_checksum(&rec->fmp, len);
+
+       /* Use the complement value. */
+       rec->fmp.checksum = -checksum;
+
+       pr_debug("Writing to storage\n");
+
+       ret = erst_write(&rec->hdr);
+       if (ret) {
+               pr_warn("Storage update failed for FRU 0x%016llx\n", rec->fmp.fru_id);
+
+               if (ret == -ENOSPC)
+                       pr_warn("Not enough space on storage\n");
+       }
+
+       return ret;
+}
+
+static bool rec_has_valid_entries(struct fru_rec *rec)
+{
+       if (!(rec->fmp.validation_bits & FMP_VALID_LIST_ENTRIES))
+               return false;
+
+       if (!(rec->fmp.validation_bits & FMP_VALID_LIST))
+               return false;
+
+       return true;
+}
+
+static bool fpds_equal(struct cper_fru_poison_desc *old, struct cper_fru_poison_desc *new)
+{
+       /*
+        * Ignore timestamp field.
+        * The same physical error may be reported multiple times due to stuck bits, etc.
+        *
+        * Also, order the checks from most->least likely to fail to shortcut the code.
+        */
+       if (old->addr != new->addr)
+               return false;
+
+       if (old->hw_id != new->hw_id)
+               return false;
+
+       if (old->addr_type != new->addr_type)
+               return false;
+
+       if (old->hw_id_type != new->hw_id_type)
+               return false;
+
+       return true;
+}
+
+static bool rec_has_fpd(struct fru_rec *rec, struct cper_fru_poison_desc *fpd)
+{
+       unsigned int i;
+
+       for (i = 0; i < rec->fmp.nr_entries; i++) {
+               struct cper_fru_poison_desc *fpd_i = &rec->entries[i];
+
+               if (fpds_equal(fpd_i, fpd)) {
+                       pr_debug("Found duplicate record\n");
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static void save_spa(struct fru_rec *rec, unsigned int entry,
+                    u64 addr, u64 id, unsigned int cpu)
+{
+       unsigned int i, fru_idx, spa_entry;
+       struct atl_err a_err;
+       unsigned long spa;
+
+       if (entry >= max_nr_entries) {
+               pr_warn_once("FRU descriptor entry %d out-of-bounds (max: %d)\n",
+                            entry, max_nr_entries);
+               return;
+       }
+
+       /* spa_nr_entries is always multiple of max_nr_entries */
+       for (i = 0; i < spa_nr_entries; i += max_nr_entries) {
+               fru_idx = i / max_nr_entries;
+               if (fru_records[fru_idx] == rec)
+                       break;
+       }
+
+       if (i >= spa_nr_entries) {
+               pr_warn_once("FRU record %d not found\n", i);
+               return;
+       }
+
+       spa_entry = i + entry;
+       if (spa_entry >= spa_nr_entries) {
+               pr_warn_once("spa_entries[] index out-of-bounds\n");
+               return;
+       }
+
+       memset(&a_err, 0, sizeof(struct atl_err));
+
+       a_err.addr = addr;
+       a_err.ipid = id;
+       a_err.cpu  = cpu;
+
+       spa = amd_convert_umc_mca_addr_to_sys_addr(&a_err);
+       if (IS_ERR_VALUE(spa)) {
+               pr_debug("Failed to get system address\n");
+               return;
+       }
+
+       spa_entries[spa_entry] = spa;
+       pr_debug("fru_idx: %u, entry: %u, spa_entry: %u, spa: 0x%016llx\n",
+                fru_idx, entry, spa_entry, spa_entries[spa_entry]);
+}
+
+static void update_fru_record(struct fru_rec *rec, struct mce *m)
+{
+       struct cper_sec_fru_mem_poison *fmp = &rec->fmp;
+       struct cper_fru_poison_desc fpd, *fpd_dest;
+       u32 entry = 0;
+
+       mutex_lock(&fmpm_update_mutex);
+
+       memset(&fpd, 0, sizeof(struct cper_fru_poison_desc));
+
+       fpd.timestamp   = m->time;
+       fpd.hw_id_type = FPD_HW_ID_TYPE_MCA_IPID;
+       fpd.hw_id       = m->ipid;
+       fpd.addr_type   = FPD_ADDR_TYPE_MCA_ADDR;
+       fpd.addr        = m->addr;
+
+       /* This is the first entry, so just save it. */
+       if (!rec_has_valid_entries(rec))
+               goto save_fpd;
+
+       /* Ignore already recorded errors. */
+       if (rec_has_fpd(rec, &fpd))
+               goto out_unlock;
+
+       if (rec->fmp.nr_entries >= max_nr_entries) {
+               pr_warn("Exceeded number of entries for FRU 0x%016llx\n", rec->fmp.fru_id);
+               goto out_unlock;
+       }
+
+       entry  = fmp->nr_entries;
+
+save_fpd:
+       save_spa(rec, entry, m->addr, m->ipid, m->extcpu);
+       fpd_dest  = &rec->entries[entry];
+       memcpy(fpd_dest, &fpd, sizeof(struct cper_fru_poison_desc));
+
+       fmp->nr_entries          = entry + 1;
+       fmp->validation_bits    |= FMP_VALID_LIST_ENTRIES;
+       fmp->validation_bits    |= FMP_VALID_LIST;
+
+       pr_debug("Updated FRU 0x%016llx entry #%u\n", fmp->fru_id, entry);
+
+       update_record_on_storage(rec);
+
+out_unlock:
+       mutex_unlock(&fmpm_update_mutex);
+}
+
+static void retire_dram_row(u64 addr, u64 id, u32 cpu)
+{
+       struct atl_err a_err;
+
+       memset(&a_err, 0, sizeof(struct atl_err));
+
+       a_err.addr = addr;
+       a_err.ipid = id;
+       a_err.cpu  = cpu;
+
+       amd_retire_dram_row(&a_err);
+}
+
+static int fru_handle_mem_poison(struct notifier_block *nb, unsigned long val, void *data)
+{
+       struct mce *m = (struct mce *)data;
+       struct fru_rec *rec;
+
+       if (!mce_is_memory_error(m))
+               return NOTIFY_DONE;
+
+       retire_dram_row(m->addr, m->ipid, m->extcpu);
+
+       /*
+        * An invalid FRU ID should not happen on real errors. But it
+        * could happen from software error injection, etc.
+        */
+       rec = get_fru_record(m->ppin);
+       if (!rec)
+               return NOTIFY_DONE;
+
+       update_fru_record(rec, m);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block fru_mem_poison_nb = {
+       .notifier_call  = fru_handle_mem_poison,
+       .priority       = MCE_PRIO_LOWEST,
+};
+
+static void retire_mem_fmp(struct fru_rec *rec)
+{
+       struct cper_sec_fru_mem_poison *fmp = &rec->fmp;
+       unsigned int i, cpu;
+
+       for (i = 0; i < fmp->nr_entries; i++) {
+               struct cper_fru_poison_desc *fpd = &rec->entries[i];
+               unsigned int err_cpu = INVALID_CPU;
+
+               if (fpd->hw_id_type != FPD_HW_ID_TYPE_MCA_IPID)
+                       continue;
+
+               if (fpd->addr_type != FPD_ADDR_TYPE_MCA_ADDR)
+                       continue;
+
+               cpus_read_lock();
+               for_each_online_cpu(cpu) {
+                       if (topology_ppin(cpu) == fmp->fru_id) {
+                               err_cpu = cpu;
+                               break;
+                       }
+               }
+               cpus_read_unlock();
+
+               if (err_cpu == INVALID_CPU)
+                       continue;
+
+               retire_dram_row(fpd->addr, fpd->hw_id, err_cpu);
+               save_spa(rec, i, fpd->addr, fpd->hw_id, err_cpu);
+       }
+}
+
+static void retire_mem_records(void)
+{
+       struct fru_rec *rec;
+       unsigned int i;
+
+       for_each_fru(i, rec) {
+               if (!rec_has_valid_entries(rec))
+                       continue;
+
+               retire_mem_fmp(rec);
+       }
+}
+
+/* Set the CPER Record Header and CPER Section Descriptor fields. */
+static void set_rec_fields(struct fru_rec *rec)
+{
+       struct cper_section_descriptor  *sec_desc = &rec->sec_desc;
+       struct cper_record_header       *hdr      = &rec->hdr;
+
+       memcpy(hdr->signature, CPER_SIG_RECORD, CPER_SIG_SIZE);
+       hdr->revision                   = CPER_RECORD_REV;
+       hdr->signature_end              = CPER_SIG_END;
+
+       /*
+        * Currently, it is assumed that there is one FRU Memory Poison
+        * section per CPER. But this may change for other implementations.
+        */
+       hdr->section_count              = 1;
+
+       /* The logged errors are recoverable. Otherwise, they'd never make it here. */
+       hdr->error_severity             = CPER_SEV_RECOVERABLE;
+
+       hdr->validation_bits            = 0;
+       hdr->record_length              = max_rec_len;
+       hdr->creator_id                 = CPER_CREATOR_FMP;
+       hdr->notification_type          = CPER_NOTIFY_MCE;
+       hdr->record_id                  = cper_next_record_id();
+       hdr->flags                      = CPER_HW_ERROR_FLAGS_PREVERR;
+
+       sec_desc->section_offset        = sizeof(struct cper_record_header);
+       sec_desc->section_length        = max_rec_len - sizeof(struct cper_record_header);
+       sec_desc->revision              = CPER_SEC_REV;
+       sec_desc->validation_bits       = 0;
+       sec_desc->flags                 = CPER_SEC_PRIMARY;
+       sec_desc->section_type          = CPER_SECTION_TYPE_FMP;
+       sec_desc->section_severity      = CPER_SEV_RECOVERABLE;
+}
+
+static int save_new_records(void)
+{
+       DECLARE_BITMAP(new_records, FMPM_MAX_NR_FRU);
+       struct fru_rec *rec;
+       unsigned int i;
+       int ret = 0;
+
+       for_each_fru(i, rec) {
+               if (rec->hdr.record_length)
+                       continue;
+
+               set_rec_fields(rec);
+
+               ret = update_record_on_storage(rec);
+               if (ret)
+                       goto out_clear;
+
+               set_bit(i, new_records);
+       }
+
+       return ret;
+
+out_clear:
+       for_each_fru(i, rec) {
+               if (!test_bit(i, new_records))
+                       continue;
+
+               erst_clear(rec->hdr.record_id);
+       }
+
+       return ret;
+}
+
+/* Check that the record matches expected types for the current system.*/
+static bool fmp_is_usable(struct fru_rec *rec)
+{
+       struct cper_sec_fru_mem_poison *fmp = &rec->fmp;
+       u64 cpuid;
+
+       pr_debug("Validation bits: 0x%016llx\n", fmp->validation_bits);
+
+       if (!(fmp->validation_bits & FMP_VALID_ARCH_TYPE)) {
+               pr_debug("Arch type unknown\n");
+               return false;
+       }
+
+       if (fmp->fru_arch_type != FMP_ARCH_TYPE_X86_CPUID_1_EAX) {
+               pr_debug("Arch type not 'x86 Family/Model/Stepping'\n");
+               return false;
+       }
+
+       if (!(fmp->validation_bits & FMP_VALID_ARCH)) {
+               pr_debug("Arch value unknown\n");
+               return false;
+       }
+
+       cpuid = cpuid_eax(1);
+       if (fmp->fru_arch != cpuid) {
+               pr_debug("Arch value mismatch: record = 0x%016llx, system = 0x%016llx\n",
+                        fmp->fru_arch, cpuid);
+               return false;
+       }
+
+       if (!(fmp->validation_bits & FMP_VALID_ID_TYPE)) {
+               pr_debug("FRU ID type unknown\n");
+               return false;
+       }
+
+       if (fmp->fru_id_type != FMP_ID_TYPE_X86_PPIN) {
+               pr_debug("FRU ID type is not 'x86 PPIN'\n");
+               return false;
+       }
+
+       if (!(fmp->validation_bits & FMP_VALID_ID)) {
+               pr_debug("FRU ID value unknown\n");
+               return false;
+       }
+
+       return true;
+}
+
+static bool fmp_is_valid(struct fru_rec *rec)
+{
+       struct cper_sec_fru_mem_poison *fmp = &rec->fmp;
+       u32 checksum, len;
+
+       len = get_fmp_len(rec);
+       if (len < sizeof(struct cper_sec_fru_mem_poison)) {
+               pr_debug("fmp length is too small\n");
+               return false;
+       }
+
+       /* Checksum must sum to zero for the entire section. */
+       checksum = do_fmp_checksum(fmp, len) + fmp->checksum;
+       if (checksum) {
+               pr_debug("fmp checksum failed: sum = 0x%x\n", checksum);
+               print_hex_dump_debug("fmp record: ", DUMP_PREFIX_NONE, 16, 1, fmp, len, false);
+               return false;
+       }
+
+       if (!fmp_is_usable(rec))
+               return false;
+
+       return true;
+}
+
+static struct fru_rec *get_valid_record(struct fru_rec *old)
+{
+       struct fru_rec *new;
+
+       if (!fmp_is_valid(old)) {
+               pr_debug("Ignoring invalid record\n");
+               return NULL;
+       }
+
+       new = get_fru_record(old->fmp.fru_id);
+       if (!new)
+               pr_debug("Ignoring record for absent FRU\n");
+
+       return new;
+}
+
+/*
+ * Fetch saved records from persistent storage.
+ *
+ * For each found record:
+ * - If it was not created by this module, then ignore it.
+ * - If it is valid, then copy its data to the local cache.
+ * - If it is not valid, then erase it.
+ */
+static int get_saved_records(void)
+{
+       struct fru_rec *old, *new;
+       u64 record_id;
+       int ret, pos;
+       ssize_t len;
+
+       /*
+        * Assume saved records match current max size.
+        *
+        * However, this may not be true depending on module parameters.
+        */
+       old = kmalloc(max_rec_len, GFP_KERNEL);
+       if (!old) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = erst_get_record_id_begin(&pos);
+       if (ret < 0)
+               goto out_end;
+
+       while (!erst_get_record_id_next(&pos, &record_id)) {
+               if (record_id == APEI_ERST_INVALID_RECORD_ID)
+                       goto out_end;
+               /*
+                * Make sure to clear temporary buffer between reads to avoid
+                * leftover data from records of various sizes.
+                */
+               memset(old, 0, max_rec_len);
+
+               len = erst_read_record(record_id, &old->hdr, max_rec_len,
+                                      sizeof(struct fru_rec), &CPER_CREATOR_FMP);
+               if (len < 0)
+                       continue;
+
+               if (len > max_rec_len) {
+                       pr_debug("Found record larger than max_rec_len\n");
+                       continue;
+               }
+
+               new = get_valid_record(old);
+               if (!new)
+                       erst_clear(record_id);
+
+               /* Restore the record */
+               memcpy(new, old, len);
+       }
+
+out_end:
+       erst_get_record_id_end();
+       kfree(old);
+out:
+       return ret;
+}
+
+static void set_fmp_fields(struct fru_rec *rec, unsigned int cpu)
+{
+       struct cper_sec_fru_mem_poison *fmp = &rec->fmp;
+
+       fmp->fru_arch_type    = FMP_ARCH_TYPE_X86_CPUID_1_EAX;
+       fmp->validation_bits |= FMP_VALID_ARCH_TYPE;
+
+       /* Assume all CPUs in the system have the same value for now. */
+       fmp->fru_arch         = cpuid_eax(1);
+       fmp->validation_bits |= FMP_VALID_ARCH;
+
+       fmp->fru_id_type      = FMP_ID_TYPE_X86_PPIN;
+       fmp->validation_bits |= FMP_VALID_ID_TYPE;
+
+       fmp->fru_id           = topology_ppin(cpu);
+       fmp->validation_bits |= FMP_VALID_ID;
+}
+
+static int init_fmps(void)
+{
+       struct fru_rec *rec;
+       unsigned int i, cpu;
+       int ret = 0;
+
+       for_each_fru(i, rec) {
+               unsigned int fru_cpu = INVALID_CPU;
+
+               cpus_read_lock();
+               for_each_online_cpu(cpu) {
+                       if (topology_physical_package_id(cpu) == i) {
+                               fru_cpu = cpu;
+                               break;
+                       }
+               }
+               cpus_read_unlock();
+
+               if (fru_cpu == INVALID_CPU) {
+                       pr_debug("Failed to find matching CPU for FRU #%u\n", i);
+                       ret = -ENODEV;
+                       break;
+               }
+
+               set_fmp_fields(rec, fru_cpu);
+       }
+
+       return ret;
+}
+
+static int get_system_info(void)
+{
+       /* Only load on MI300A systems for now. */
+       if (!(boot_cpu_data.x86_model >= 0x90 &&
+             boot_cpu_data.x86_model <= 0x9f))
+               return -ENODEV;
+
+       if (!cpu_feature_enabled(X86_FEATURE_AMD_PPIN)) {
+               pr_debug("PPIN feature not available\n");
+               return -ENODEV;
+       }
+
+       /* Use CPU socket as FRU for MI300 systems. */
+       max_nr_fru = topology_max_packages();
+       if (!max_nr_fru)
+               return -ENODEV;
+
+       if (max_nr_fru > FMPM_MAX_NR_FRU) {
+               pr_warn("Too many FRUs to manage: found: %u, max: %u\n",
+                       max_nr_fru, FMPM_MAX_NR_FRU);
+               return -ENODEV;
+       }
+
+       if (!max_nr_entries)
+               max_nr_entries = FMPM_DEFAULT_MAX_NR_ENTRIES;
+
+       spa_nr_entries = max_nr_fru * max_nr_entries;
+
+       max_rec_len  = sizeof(struct fru_rec);
+       max_rec_len += sizeof(struct cper_fru_poison_desc) * max_nr_entries;
+
+       pr_info("max FRUs: %u, max entries: %u, max record length: %lu\n",
+                max_nr_fru, max_nr_entries, max_rec_len);
+
+       return 0;
+}
+
+static void free_records(void)
+{
+       struct fru_rec *rec;
+       int i;
+
+       for_each_fru(i, rec)
+               kfree(rec);
+
+       kfree(fru_records);
+       kfree(spa_entries);
+}
+
+static int allocate_records(void)
+{
+       int i, ret = 0;
+
+       fru_records = kcalloc(max_nr_fru, sizeof(struct fru_rec *), GFP_KERNEL);
+       if (!fru_records) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < max_nr_fru; i++) {
+               fru_records[i] = kzalloc(max_rec_len, GFP_KERNEL);
+               if (!fru_records[i]) {
+                       ret = -ENOMEM;
+                       goto out_free;
+               }
+       }
+
+       spa_entries = kcalloc(spa_nr_entries, sizeof(u64), GFP_KERNEL);
+       if (!spa_entries) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
+       for (i = 0; i < spa_nr_entries; i++)
+               spa_entries[i] = INVALID_SPA;
+
+       return ret;
+
+out_free:
+       while (--i >= 0)
+               kfree(fru_records[i]);
+
+       kfree(fru_records);
+out:
+       return ret;
+}
+
+static void *fmpm_start(struct seq_file *f, loff_t *pos)
+{
+       if (*pos >= (spa_nr_entries + 1))
+               return NULL;
+       return pos;
+}
+
+static void *fmpm_next(struct seq_file *f, void *data, loff_t *pos)
+{
+       if (++(*pos) >= (spa_nr_entries + 1))
+               return NULL;
+       return pos;
+}
+
+static void fmpm_stop(struct seq_file *f, void *data)
+{
+}
+
+#define SHORT_WIDTH    8
+#define U64_WIDTH      18
+#define TIMESTAMP_WIDTH        19
+#define LONG_WIDTH     24
+#define U64_PAD                (LONG_WIDTH - U64_WIDTH)
+#define TS_PAD         (LONG_WIDTH - TIMESTAMP_WIDTH)
+static int fmpm_show(struct seq_file *f, void *data)
+{
+       unsigned int fru_idx, entry, spa_entry, line;
+       struct cper_fru_poison_desc *fpd;
+       struct fru_rec *rec;
+
+       line = *(loff_t *)data;
+       if (line == 0) {
+               seq_printf(f, "%-*s", SHORT_WIDTH, "fru_idx");
+               seq_printf(f, "%-*s", LONG_WIDTH,  "fru_id");
+               seq_printf(f, "%-*s", SHORT_WIDTH, "entry");
+               seq_printf(f, "%-*s", LONG_WIDTH,  "timestamp");
+               seq_printf(f, "%-*s", LONG_WIDTH,  "hw_id");
+               seq_printf(f, "%-*s", LONG_WIDTH,  "addr");
+               seq_printf(f, "%-*s", LONG_WIDTH,  "spa");
+               goto out_newline;
+       }
+
+       spa_entry = line - 1;
+       fru_idx   = spa_entry / max_nr_entries;
+       entry     = spa_entry % max_nr_entries;
+
+       rec = fru_records[fru_idx];
+       if (!rec)
+               goto out;
+
+       seq_printf(f, "%-*u",           SHORT_WIDTH, fru_idx);
+       seq_printf(f, "0x%016llx%-*s",  rec->fmp.fru_id, U64_PAD, "");
+       seq_printf(f, "%-*u",           SHORT_WIDTH, entry);
+
+       mutex_lock(&fmpm_update_mutex);
+
+       if (entry >= rec->fmp.nr_entries) {
+               seq_printf(f, "%-*s", LONG_WIDTH, "*");
+               seq_printf(f, "%-*s", LONG_WIDTH, "*");
+               seq_printf(f, "%-*s", LONG_WIDTH, "*");
+               seq_printf(f, "%-*s", LONG_WIDTH, "*");
+               goto out_unlock;
+       }
+
+       fpd = &rec->entries[entry];
+
+       seq_printf(f, "%ptT%-*s",       &fpd->timestamp, TS_PAD,  "");
+       seq_printf(f, "0x%016llx%-*s",  fpd->hw_id,      U64_PAD, "");
+       seq_printf(f, "0x%016llx%-*s",  fpd->addr,       U64_PAD, "");
+
+       if (spa_entries[spa_entry] == INVALID_SPA)
+               seq_printf(f, "%-*s", LONG_WIDTH, "*");
+       else
+               seq_printf(f, "0x%016llx%-*s", spa_entries[spa_entry], U64_PAD, "");
+
+out_unlock:
+       mutex_unlock(&fmpm_update_mutex);
+out_newline:
+       seq_putc(f, '\n');
+out:
+       return 0;
+}
+
+static const struct seq_operations fmpm_seq_ops = {
+       .start  = fmpm_start,
+       .next   = fmpm_next,
+       .stop   = fmpm_stop,
+       .show   = fmpm_show,
+};
+
+static int fmpm_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &fmpm_seq_ops);
+}
+
+static const struct file_operations fmpm_fops = {
+       .open           = fmpm_open,
+       .release        = seq_release,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+};
+
+static void setup_debugfs(void)
+{
+       struct dentry *dfs = ras_get_debugfs_root();
+
+       if (!dfs)
+               return;
+
+       fmpm_dfs_dir = debugfs_create_dir("fmpm", dfs);
+       if (!fmpm_dfs_dir)
+               return;
+
+       fmpm_dfs_entries = debugfs_create_file("entries", 0400, fmpm_dfs_dir, NULL, &fmpm_fops);
+       if (!fmpm_dfs_entries)
+               debugfs_remove(fmpm_dfs_dir);
+}
+
+static const struct x86_cpu_id fmpm_cpuids[] = {
+       X86_MATCH_VENDOR_FAM(AMD, 0x19, NULL),
+       { }
+};
+MODULE_DEVICE_TABLE(x86cpu, fmpm_cpuids);
+
+static int __init fru_mem_poison_init(void)
+{
+       int ret;
+
+       if (!x86_match_cpu(fmpm_cpuids)) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       if (erst_disable) {
+               pr_debug("ERST not available\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       ret = get_system_info();
+       if (ret)
+               goto out;
+
+       ret = allocate_records();
+       if (ret)
+               goto out;
+
+       ret = init_fmps();
+       if (ret)
+               goto out_free;
+
+       ret = get_saved_records();
+       if (ret)
+               goto out_free;
+
+       ret = save_new_records();
+       if (ret)
+               goto out_free;
+
+       setup_debugfs();
+
+       retire_mem_records();
+
+       mce_register_decode_chain(&fru_mem_poison_nb);
+
+       pr_info("FRU Memory Poison Manager initialized\n");
+       return 0;
+
+out_free:
+       free_records();
+out:
+       return ret;
+}
+
+static void __exit fru_mem_poison_exit(void)
+{
+       mce_unregister_decode_chain(&fru_mem_poison_nb);
+       debugfs_remove(fmpm_dfs_dir);
+       free_records();
+}
+
+module_init(fru_mem_poison_init);
+module_exit(fru_mem_poison_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FRU Memory Poison Manager");
index 321af498ee119d62610b308901932848124b1230..e440b15fbabccbb9ccd53de6f7f36307db28497b 100644 (file)
@@ -480,9 +480,15 @@ DEFINE_SHOW_ATTRIBUTE(array);
 
 static int __init create_debugfs_nodes(void)
 {
-       struct dentry *d, *pfn, *decay, *count, *array;
+       struct dentry *d, *pfn, *decay, *count, *array, *dfs;
 
-       d = debugfs_create_dir("cec", ras_debugfs_dir);
+       dfs = ras_get_debugfs_root();
+       if (!dfs) {
+               pr_warn("Error getting RAS debugfs root!\n");
+               return -1;
+       }
+
+       d = debugfs_create_dir("cec", dfs);
        if (!d) {
                pr_warn("Error creating cec debugfs node!\n");
                return -1;
index ffb973c328e36003c6dd729a1d9140a2b18feb8c..42afd3de68b22edcf52af72177040b2048c498c4 100644 (file)
@@ -3,10 +3,16 @@
 #include <linux/ras.h>
 #include "debugfs.h"
 
-struct dentry *ras_debugfs_dir;
+static struct dentry *ras_debugfs_dir;
 
 static atomic_t trace_count = ATOMIC_INIT(0);
 
+struct dentry *ras_get_debugfs_root(void)
+{
+       return ras_debugfs_dir;
+}
+EXPORT_SYMBOL_GPL(ras_get_debugfs_root);
+
 int ras_userspace_consumers(void)
 {
        return atomic_read(&trace_count);
index c07443b462ad5ebdf06c9e0967baca4890c0e19e..4749ccdeeba12236aff3f8178dbed8582764272a 100644 (file)
@@ -4,6 +4,6 @@
 
 #include <linux/debugfs.h>
 
-extern struct dentry *ras_debugfs_dir;
+struct dentry *ras_get_debugfs_root(void);
 
 #endif /* __RAS_DEBUGFS_H__ */
index 95540ea8dd9db905fa76019e9a0ce618c053a84c..a6e4792a1b2e9239f44f29102a7cc058d64b93ef 100644 (file)
 #include <linux/ras.h>
 #include <linux/uuid.h>
 
+#if IS_ENABLED(CONFIG_AMD_ATL)
+/*
+ * Once set, this function pointer should never be unset.
+ *
+ * The library module will set this pointer if it successfully loads. The module
+ * should not be unloaded except for testing and debug purposes.
+ */
+static unsigned long (*amd_atl_umc_na_to_spa)(struct atl_err *err);
+
+void amd_atl_register_decoder(unsigned long (*f)(struct atl_err *))
+{
+       amd_atl_umc_na_to_spa = f;
+}
+EXPORT_SYMBOL_GPL(amd_atl_register_decoder);
+
+void amd_atl_unregister_decoder(void)
+{
+       amd_atl_umc_na_to_spa = NULL;
+}
+EXPORT_SYMBOL_GPL(amd_atl_unregister_decoder);
+
+unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
+{
+       if (!amd_atl_umc_na_to_spa)
+               return -EINVAL;
+
+       return amd_atl_umc_na_to_spa(err);
+}
+EXPORT_SYMBOL_GPL(amd_convert_umc_mca_addr_to_sys_addr);
+#endif /* CONFIG_AMD_ATL */
+
 #define CREATE_TRACE_POINTS
 #define TRACE_INCLUDE_PATH ../../include/ras
 #include <ras/ras_event.h>
index 830a1c4cd705784687fb424f3bfd23fdc7743fcf..8bbcd983a74aa8d8e5db6ae9e9cb7480a9220575 100644 (file)
@@ -29,8 +29,8 @@ struct max5970_regulator {
 };
 
 enum max597x_regulator_id {
-       MAX597X_SW0,
-       MAX597X_SW1,
+       MAX597X_sw0,
+       MAX597X_sw1,
 };
 
 static int max5970_read_adc(struct regmap *regmap, int reg, long *val)
@@ -378,8 +378,8 @@ static int max597x_dt_parse(struct device_node *np,
 }
 
 static const struct regulator_desc regulators[] = {
-       MAX597X_SWITCH(SW0, MAX5970_REG_CHXEN, 0, "vss1"),
-       MAX597X_SWITCH(SW1, MAX5970_REG_CHXEN, 1, "vss2"),
+       MAX597X_SWITCH(sw0, MAX5970_REG_CHXEN, 0, "vss1"),
+       MAX597X_SWITCH(sw1, MAX5970_REG_CHXEN, 1, "vss2"),
 };
 
 static int max597x_regmap_read_clear(struct regmap *map, unsigned int reg,
index e374fa6e5f2841e4a96fc2ad03907f020284cfc6..d89ae7f16d7a0e1f8d8c0ec19e7ad7565e816858 100644 (file)
@@ -1017,14 +1017,14 @@ static const struct regulator_desc rk805_reg[] = {
 };
 
 static const struct linear_range rk806_buck_voltage_ranges[] = {
-       REGULATOR_LINEAR_RANGE(500000, 0, 160, 6250), /* 500mV ~ 1500mV */
-       REGULATOR_LINEAR_RANGE(1500000, 161, 237, 25000), /* 1500mV ~ 3400mV */
-       REGULATOR_LINEAR_RANGE(3400000, 238, 255, 0),
+       REGULATOR_LINEAR_RANGE(500000, 0, 159, 6250), /* 500mV ~ 1500mV */
+       REGULATOR_LINEAR_RANGE(1500000, 160, 235, 25000), /* 1500mV ~ 3400mV */
+       REGULATOR_LINEAR_RANGE(3400000, 236, 255, 0),
 };
 
 static const struct linear_range rk806_ldo_voltage_ranges[] = {
-       REGULATOR_LINEAR_RANGE(500000, 0, 232, 12500), /* 500mV ~ 3400mV */
-       REGULATOR_LINEAR_RANGE(3400000, 233, 255, 0), /* 500mV ~ 3400mV */
+       REGULATOR_LINEAR_RANGE(500000, 0, 231, 12500), /* 500mV ~ 3400mV */
+       REGULATOR_LINEAR_RANGE(3400000, 232, 255, 0),
 };
 
 static const struct regulator_desc rk806_reg[] = {
index d5caf36c56cdcfdfdc22537de70cd5ab44b1644c..225c859d6da550a8cb44c3d2446f3d433c9716e3 100644 (file)
@@ -54,7 +54,7 @@ static void rtc_time64_to_tm_test_date_range(struct kunit *test)
 
                days = div_s64(secs, 86400);
 
-               #define FAIL_MSG "%d/%02d/%02d (%2d) : %ld", \
+               #define FAIL_MSG "%d/%02d/%02d (%2d) : %lld", \
                        year, month, mday, yday, days
 
                KUNIT_ASSERT_EQ_MSG(test, year - 1900, result.tm_year, FAIL_MSG);
index 7327e81352e9c7c74248adbd95b7c1c62aa05643..cead018c3f06a5917396561321ef354b8db6acc3 100644 (file)
@@ -8,9 +8,6 @@
  * Copyright IBM Corp. 1999, 2009
  */
 
-#define KMSG_COMPONENT "dasd"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-
 #include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -30,9 +27,6 @@
 #include <asm/itcw.h>
 #include <asm/diag.h>
 
-/* This is ugly... */
-#define PRINTK_HEADER "dasd:"
-
 #include "dasd_int.h"
 /*
  * SECTION: Constant definitions to be used within this file
@@ -313,39 +307,57 @@ static int dasd_state_basic_to_known(struct dasd_device *device)
  */
 static int dasd_state_basic_to_ready(struct dasd_device *device)
 {
-       int rc;
-       struct dasd_block *block;
-       struct gendisk *disk;
+       struct dasd_block *block = device->block;
+       struct queue_limits lim;
+       int rc = 0;
 
-       rc = 0;
-       block = device->block;
        /* make disk known with correct capacity */
-       if (block) {
-               if (block->base->discipline->do_analysis != NULL)
-                       rc = block->base->discipline->do_analysis(block);
-               if (rc) {
-                       if (rc != -EAGAIN) {
-                               device->state = DASD_STATE_UNFMT;
-                               disk = device->block->gdp;
-                               kobject_uevent(&disk_to_dev(disk)->kobj,
-                                              KOBJ_CHANGE);
-                               goto out;
-                       }
-                       return rc;
-               }
-               if (device->discipline->setup_blk_queue)
-                       device->discipline->setup_blk_queue(block);
-               set_capacity(block->gdp,
-                            block->blocks << block->s2b_shift);
+       if (!block) {
                device->state = DASD_STATE_READY;
-               rc = dasd_scan_partitions(block);
-               if (rc) {
-                       device->state = DASD_STATE_BASIC;
+               goto out;
+       }
+
+       if (block->base->discipline->do_analysis != NULL)
+               rc = block->base->discipline->do_analysis(block);
+       if (rc) {
+               if (rc == -EAGAIN)
                        return rc;
-               }
-       } else {
-               device->state = DASD_STATE_READY;
+               device->state = DASD_STATE_UNFMT;
+               kobject_uevent(&disk_to_dev(device->block->gdp)->kobj,
+                              KOBJ_CHANGE);
+               goto out;
+       }
+
+       lim = queue_limits_start_update(block->gdp->queue);
+       lim.max_dev_sectors = device->discipline->max_sectors(block);
+       lim.max_hw_sectors = lim.max_dev_sectors;
+       lim.logical_block_size = block->bp_block;
+
+       if (device->discipline->has_discard) {
+               unsigned int max_bytes;
+
+               lim.discard_granularity = block->bp_block;
+
+               /* Calculate max_discard_sectors and make it PAGE aligned */
+               max_bytes = USHRT_MAX * block->bp_block;
+               max_bytes = ALIGN_DOWN(max_bytes, PAGE_SIZE);
+
+               lim.max_hw_discard_sectors = max_bytes / block->bp_block;
+               lim.max_write_zeroes_sectors = lim.max_hw_discard_sectors;
        }
+       rc = queue_limits_commit_update(block->gdp->queue, &lim);
+       if (rc)
+               return rc;
+
+       set_capacity(block->gdp, block->blocks << block->s2b_shift);
+       device->state = DASD_STATE_READY;
+
+       rc = dasd_scan_partitions(block);
+       if (rc) {
+               device->state = DASD_STATE_BASIC;
+               return rc;
+       }
+
 out:
        if (device->discipline->basic_to_ready)
                rc = device->discipline->basic_to_ready(device);
@@ -412,7 +424,7 @@ dasd_state_ready_to_online(struct dasd_device * device)
                                        KOBJ_CHANGE);
                        return 0;
                }
-               disk_uevent(device->block->bdev_handle->bdev->bd_disk,
+               disk_uevent(file_bdev(device->block->bdev_file)->bd_disk,
                            KOBJ_CHANGE);
        }
        return 0;
@@ -433,7 +445,7 @@ static int dasd_state_online_to_ready(struct dasd_device *device)
 
        device->state = DASD_STATE_READY;
        if (device->block && !(device->features & DASD_FEATURE_USERAW))
-               disk_uevent(device->block->bdev_handle->bdev->bd_disk,
+               disk_uevent(file_bdev(device->block->bdev_file)->bd_disk,
                            KOBJ_CHANGE);
        return 0;
 }
@@ -1301,7 +1313,6 @@ int dasd_term_IO(struct dasd_ccw_req *cqr)
 {
        struct dasd_device *device;
        int retries, rc;
-       char errorstring[ERRORLENGTH];
 
        /* Check the cqr */
        rc = dasd_check_cqr(cqr);
@@ -1340,10 +1351,8 @@ int dasd_term_IO(struct dasd_ccw_req *cqr)
                        rc = 0;
                        break;
                default:
-                       /* internal error 10 - unknown rc*/
-                       snprintf(errorstring, ERRORLENGTH, "10 %d", rc);
-                       dev_err(&device->cdev->dev, "An error occurred in the "
-                               "DASD device driver, reason=%s\n", errorstring);
+                       dev_err(&device->cdev->dev,
+                               "Unexpected error during request termination %d\n", rc);
                        BUG();
                        break;
                }
@@ -1362,7 +1371,6 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
 {
        struct dasd_device *device;
        int rc;
-       char errorstring[ERRORLENGTH];
 
        /* Check the cqr */
        rc = dasd_check_cqr(cqr);
@@ -1382,10 +1390,8 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
                return -EPERM;
        }
        if (cqr->retries < 0) {
-               /* internal error 14 - start_IO run out of retries */
-               sprintf(errorstring, "14 %p", cqr);
-               dev_err(&device->cdev->dev, "An error occurred in the DASD "
-                       "device driver, reason=%s\n", errorstring);
+               dev_err(&device->cdev->dev,
+                       "Start I/O ran out of retries\n");
                cqr->status = DASD_CQR_ERROR;
                return -EIO;
        }
@@ -1463,11 +1469,8 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
                              "not accessible");
                break;
        default:
-               /* internal error 11 - unknown rc */
-               snprintf(errorstring, ERRORLENGTH, "11 %d", rc);
                dev_err(&device->cdev->dev,
-                       "An error occurred in the DASD device driver, "
-                       "reason=%s\n", errorstring);
+                       "Unexpected error during request start %d", rc);
                BUG();
                break;
        }
@@ -1904,8 +1907,6 @@ static void __dasd_device_process_ccw_queue(struct dasd_device *device,
 static void __dasd_process_cqr(struct dasd_device *device,
                               struct dasd_ccw_req *cqr)
 {
-       char errorstring[ERRORLENGTH];
-
        switch (cqr->status) {
        case DASD_CQR_SUCCESS:
                cqr->status = DASD_CQR_DONE;
@@ -1917,11 +1918,8 @@ static void __dasd_process_cqr(struct dasd_device *device,
                cqr->status = DASD_CQR_TERMINATED;
                break;
        default:
-               /* internal error 12 - wrong cqr status*/
-               snprintf(errorstring, ERRORLENGTH, "12 %p %x02", cqr, cqr->status);
                dev_err(&device->cdev->dev,
-                       "An error occurred in the DASD device driver, "
-                       "reason=%s\n", errorstring);
+                       "Unexpected CQR status %02x", cqr->status);
                BUG();
        }
        if (cqr->callback)
@@ -1986,16 +1984,14 @@ static void __dasd_device_check_expire(struct dasd_device *device)
                if (device->discipline->term_IO(cqr) != 0) {
                        /* Hmpf, try again in 5 sec */
                        dev_err(&device->cdev->dev,
-                               "cqr %p timed out (%lus) but cannot be "
-                               "ended, retrying in 5 s\n",
-                               cqr, (cqr->expires/HZ));
+                               "CQR timed out (%lus) but cannot be ended, retrying in 5s\n",
+                               (cqr->expires / HZ));
                        cqr->expires += 5*HZ;
                        dasd_device_set_timer(device, 5*HZ);
                } else {
                        dev_err(&device->cdev->dev,
-                               "cqr %p timed out (%lus), %i retries "
-                               "remaining\n", cqr, (cqr->expires/HZ),
-                               cqr->retries);
+                               "CQR timed out (%lus), %i retries remaining\n",
+                               (cqr->expires / HZ), cqr->retries);
                }
                __dasd_device_check_autoquiesce_timeout(device, cqr);
        }
@@ -2116,8 +2112,7 @@ int dasd_flush_device_queue(struct dasd_device *device)
                        if (rc) {
                                /* unable to terminate requeust */
                                dev_err(&device->cdev->dev,
-                                       "Flushing the DASD request queue "
-                                       "failed for request %p\n", cqr);
+                                       "Flushing the DASD request queue failed\n");
                                /* stop flush processing */
                                goto finished;
                        }
@@ -2633,8 +2628,7 @@ static int __dasd_cancel_req(struct dasd_ccw_req *cqr)
                rc = device->discipline->term_IO(cqr);
                if (rc) {
                        dev_err(&device->cdev->dev,
-                               "Cancelling request %p failed with rc=%d\n",
-                               cqr, rc);
+                               "Cancelling request failed with rc=%d\n", rc);
                } else {
                        cqr->stopclk = get_tod_clock();
                }
@@ -3402,8 +3396,7 @@ static void dasd_generic_auto_online(void *data, async_cookie_t cookie)
 
        ret = ccw_device_set_online(cdev);
        if (ret)
-               pr_warn("%s: Setting the DASD online failed with rc=%d\n",
-                       dev_name(&cdev->dev), ret);
+               dev_warn(&cdev->dev, "Setting the DASD online failed with rc=%d\n", ret);
 }
 
 /*
@@ -3490,8 +3483,11 @@ int dasd_generic_set_online(struct ccw_device *cdev,
 {
        struct dasd_discipline *discipline;
        struct dasd_device *device;
+       struct device *dev;
        int rc;
 
+       dev = &cdev->dev;
+
        /* first online clears initial online feature flag */
        dasd_set_feature(cdev, DASD_FEATURE_INITIAL_ONLINE, 0);
        device = dasd_create_device(cdev);
@@ -3504,11 +3500,10 @@ int dasd_generic_set_online(struct ccw_device *cdev,
                        /* Try to load the required module. */
                        rc = request_module(DASD_DIAG_MOD);
                        if (rc) {
-                               pr_warn("%s Setting the DASD online failed "
-                                       "because the required module %s "
-                                       "could not be loaded (rc=%d)\n",
-                                       dev_name(&cdev->dev), DASD_DIAG_MOD,
-                                       rc);
+                               dev_warn(dev, "Setting the DASD online failed "
+                                        "because the required module %s "
+                                        "could not be loaded (rc=%d)\n",
+                                        DASD_DIAG_MOD, rc);
                                dasd_delete_device(device);
                                return -ENODEV;
                        }
@@ -3516,8 +3511,7 @@ int dasd_generic_set_online(struct ccw_device *cdev,
                /* Module init could have failed, so check again here after
                 * request_module(). */
                if (!dasd_diag_discipline_pointer) {
-                       pr_warn("%s Setting the DASD online failed because of missing DIAG discipline\n",
-                               dev_name(&cdev->dev));
+                       dev_warn(dev, "Setting the DASD online failed because of missing DIAG discipline\n");
                        dasd_delete_device(device);
                        return -ENODEV;
                }
@@ -3527,37 +3521,33 @@ int dasd_generic_set_online(struct ccw_device *cdev,
                dasd_delete_device(device);
                return -EINVAL;
        }
+       device->base_discipline = base_discipline;
        if (!try_module_get(discipline->owner)) {
-               module_put(base_discipline->owner);
                dasd_delete_device(device);
                return -EINVAL;
        }
-       device->base_discipline = base_discipline;
        device->discipline = discipline;
 
        /* check_device will allocate block device if necessary */
        rc = discipline->check_device(device);
        if (rc) {
-               pr_warn("%s Setting the DASD online with discipline %s failed with rc=%i\n",
-                       dev_name(&cdev->dev), discipline->name, rc);
-               module_put(discipline->owner);
-               module_put(base_discipline->owner);
+               dev_warn(dev, "Setting the DASD online with discipline %s failed with rc=%i\n",
+                        discipline->name, rc);
                dasd_delete_device(device);
                return rc;
        }
 
        dasd_set_target_state(device, DASD_STATE_ONLINE);
        if (device->state <= DASD_STATE_KNOWN) {
-               pr_warn("%s Setting the DASD online failed because of a missing discipline\n",
-                       dev_name(&cdev->dev));
+               dev_warn(dev, "Setting the DASD online failed because of a missing discipline\n");
                rc = -ENODEV;
                dasd_set_target_state(device, DASD_STATE_NEW);
                if (device->block)
                        dasd_free_block(device->block);
                dasd_delete_device(device);
-       } else
-               pr_debug("dasd_generic device %s found\n",
-                               dev_name(&cdev->dev));
+       } else {
+               dev_dbg(dev, "dasd_generic device found\n");
+       }
 
        wait_event(dasd_init_waitq, _wait_for_device(device));
 
@@ -3568,10 +3558,13 @@ EXPORT_SYMBOL_GPL(dasd_generic_set_online);
 
 int dasd_generic_set_offline(struct ccw_device *cdev)
 {
+       int max_count, open_count, rc;
        struct dasd_device *device;
        struct dasd_block *block;
-       int max_count, open_count, rc;
        unsigned long flags;
+       struct device *dev;
+
+       dev = &cdev->dev;
 
        rc = 0;
        spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
@@ -3588,15 +3581,14 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
         * in the other openers.
         */
        if (device->block) {
-               max_count = device->block->bdev_handle ? 0 : -1;
+               max_count = device->block->bdev_file ? 0 : -1;
                open_count = atomic_read(&device->block->open_count);
                if (open_count > max_count) {
                        if (open_count > 0)
-                               pr_warn("%s: The DASD cannot be set offline with open count %i\n",
-                                       dev_name(&cdev->dev), open_count);
+                               dev_warn(dev, "The DASD cannot be set offline with open count %i\n",
+                                        open_count);
                        else
-                               pr_warn("%s: The DASD cannot be set offline while it is in use\n",
-                                       dev_name(&cdev->dev));
+                               dev_warn(dev, "The DASD cannot be set offline while it is in use\n");
                        rc = -EBUSY;
                        goto out_err;
                }
@@ -3634,8 +3626,8 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
                 * so sync bdev first and then wait for our queues to become
                 * empty
                 */
-               if (device->block && device->block->bdev_handle)
-                       bdev_mark_dead(device->block->bdev_handle->bdev, false);
+               if (device->block && device->block->bdev_file)
+                       bdev_mark_dead(file_bdev(device->block->bdev_file), false);
                dasd_schedule_device_bh(device);
                rc = wait_event_interruptible(shutdown_waitq,
                                              _wait_for_empty_queues(device));
@@ -3956,8 +3948,8 @@ static int dasd_handle_autoquiesce(struct dasd_device *device,
        if (dasd_eer_enabled(device))
                dasd_eer_write(device, NULL, DASD_EER_AUTOQUIESCE);
 
-       pr_info("%s: The DASD has been put in the quiesce state\n",
-               dev_name(&device->cdev->dev));
+       dev_info(&device->cdev->dev,
+                "The DASD has been put in the quiesce state\n");
        dasd_device_set_stop_bits(device, DASD_STOPPED_QUIESCE);
 
        if (device->features & DASD_FEATURE_REQUEUEQUIESCE)
@@ -3977,10 +3969,8 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
                                   NULL);
 
        if (IS_ERR(cqr)) {
-               /* internal error 13 - Allocating the RDC request failed*/
-               dev_err(&device->cdev->dev,
-                        "An error occurred in the DASD device driver, "
-                        "reason=%s\n", "13");
+               DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+                               "Could not allocate RDC request");
                return cqr;
        }
 
index 89957bb7244d2655b5a932bfb9fbd845a7e3d48c..459b7f8ac8837283fc07e6257bd871f407008d08 100644 (file)
@@ -7,13 +7,9 @@
  *
  */
 
-#define KMSG_COMPONENT "dasd-eckd"
-
 #include <linux/timer.h>
 #include <asm/idals.h>
 
-#define PRINTK_HEADER "dasd_erp(3990): "
-
 #include "dasd_int.h"
 #include "dasd_eckd.h"
 
@@ -398,7 +394,6 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
        struct dasd_device *device = erp->startdev;
        char msg_format = (sense[7] & 0xF0);
        char msg_no = (sense[7] & 0x0F);
-       char errorstring[ERRORLENGTH];
 
        switch (msg_format) {
        case 0x00:              /* Format 0 - Program or System Checks */
@@ -1004,12 +999,9 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
                }
                break;
 
-       default:        /* unknown message format - should not happen
-                          internal error 03 - unknown message format */
-               snprintf(errorstring, ERRORLENGTH, "03 %x02", msg_format);
+       default:
                dev_err(&device->cdev->dev,
-                        "An error occurred in the DASD device driver, "
-                        "reason=%s\n", errorstring);
+                       "Unknown message format %02x", msg_format);
                break;
        }                       /* end switch message format */
 
@@ -1056,11 +1048,9 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
                set_bit(DASD_CQR_SUPPRESS_CR, &erp->refers->flags);
                erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
        } else {
-               /* fatal error -  set status to FAILED
-                  internal error 09 - Command Reject */
                if (!test_bit(DASD_CQR_SUPPRESS_CR, &erp->flags))
                        dev_err(&device->cdev->dev,
-                               "An error occurred in the DASD device driver, reason=09\n");
+                               "An I/O command request was rejected\n");
 
                erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
        }
@@ -1128,13 +1118,7 @@ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)
        erp->function = dasd_3990_erp_equip_check;
 
        if (sense[1] & SNS1_WRITE_INHIBITED) {
-               dev_info(&device->cdev->dev,
-                           "Write inhibited path encountered\n");
-
-               /* vary path offline
-                  internal error 04 - Path should be varied off-line.*/
-               dev_err(&device->cdev->dev, "An error occurred in the DASD "
-                       "device driver, reason=%s\n", "04");
+               dev_err(&device->cdev->dev, "Write inhibited path encountered\n");
 
                erp = dasd_3990_erp_action_1(erp);
 
@@ -1285,11 +1269,7 @@ dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)
                erp = dasd_3990_erp_action_4(erp, sense);
 
        } else {
-               /* internal error 06 - The track format is not valid*/
-               dev_err(&device->cdev->dev,
-                       "An error occurred in the DASD device driver, "
-                       "reason=%s\n", "06");
-
+               dev_err(&device->cdev->dev, "Track format is not valid\n");
                erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
        }
 
@@ -1663,9 +1643,8 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
                                     sizeof(struct LO_eckd_data), device);
 
        if (IS_ERR(erp)) {
-               /* internal error 01 - Unable to allocate ERP */
-               dev_err(&device->cdev->dev, "An error occurred in the DASD "
-                       "device driver, reason=%s\n", "01");
+               DBF_DEV_EVENT(DBF_ERR, device, "%s",
+                             "Unable to allocate ERP request (1B 32)");
                return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
        }
 
@@ -1807,10 +1786,8 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
        cpa = previous_erp->irb.scsw.cmd.cpa;
 
        if (cpa == 0) {
-               /* internal error 02 -
-                  Unable to determine address of the CCW to be restarted */
-               dev_err(&device->cdev->dev, "An error occurred in the DASD "
-                       "device driver, reason=%s\n", "02");
+               dev_err(&device->cdev->dev,
+                       "Unable to determine address of to be restarted CCW\n");
 
                previous_erp->status = DASD_CQR_FAILED;
 
@@ -2009,15 +1986,9 @@ dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense)
 {
 
        if ((sense[25] & DASD_SENSE_BIT_1) && (sense[26] & DASD_SENSE_BIT_2)) {
-
-               /* set to suspended duplex state then restart
-                  internal error 05 - Set device to suspended duplex state
-                  should be done */
                struct dasd_device *device = erp->startdev;
                dev_err(&device->cdev->dev,
-                       "An error occurred in the DASD device driver, "
-                       "reason=%s\n", "05");
-
+                       "Compound configuration error occurred\n");
        }
 
        erp->function = dasd_3990_erp_compound_config;
@@ -2153,10 +2124,9 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
                        erp = dasd_3990_erp_int_req(erp);
                        break;
 
-               case 0x0F:  /* length mismatch during update write command
-                              internal error 08 - update write command error*/
-                       dev_err(&device->cdev->dev, "An error occurred in the "
-                               "DASD device driver, reason=%s\n", "08");
+               case 0x0F:
+                       dev_err(&device->cdev->dev,
+                               "Update write command error occurred\n");
 
                        erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
                        break;
@@ -2165,12 +2135,9 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
                        erp = dasd_3990_erp_action_10_32(erp, sense);
                        break;
 
-               case 0x15:      /* next track outside defined extend
-                                  internal error 07 - The next track is not
-                                  within the defined storage extent */
+               case 0x15:
                        dev_err(&device->cdev->dev,
-                               "An error occurred in the DASD device driver, "
-                               "reason=%s\n", "07");
+                               "Track outside defined extent error occurred\n");
 
                        erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
                        break;
@@ -2663,7 +2630,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
                 * necessary
                 */
                dev_err(&device->cdev->dev,
-                       "ERP %p has run out of retries and failed\n", erp);
+                       "ERP %px has run out of retries and failed\n", erp);
 
                erp->status = DASD_CQR_FAILED;
        }
@@ -2704,8 +2671,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
        while (erp_done != erp) {
 
                if (erp_done == NULL)   /* end of chain reached */
-                       panic(PRINTK_HEADER "Programming error in ERP! The "
-                             "original request was lost\n");
+                       panic("Programming error in ERP! The original request was lost\n");
 
                /* remove the request from the device queue */
                list_del(&erp_done->blocklist);
@@ -2786,11 +2752,9 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
                            "ERP chain at BEGINNING of ERP-ACTION\n");
                for (temp_erp = cqr;
                     temp_erp != NULL; temp_erp = temp_erp->refers) {
-
                        dev_err(&device->cdev->dev,
-                                   "ERP %p (%02x) refers to %p\n",
-                                   temp_erp, temp_erp->status,
-                                   temp_erp->refers);
+                               "ERP %px (%02x) refers to %px\n",
+                               temp_erp, temp_erp->status, temp_erp->refers);
                }
        }
 
@@ -2837,11 +2801,9 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
                            "ERP chain at END of ERP-ACTION\n");
                for (temp_erp = erp;
                     temp_erp != NULL; temp_erp = temp_erp->refers) {
-
                        dev_err(&device->cdev->dev,
-                                   "ERP %p (%02x) refers to %p\n",
-                                   temp_erp, temp_erp->status,
-                                   temp_erp->refers);
+                               "ERP %px (%02x) refers to %px\n",
+                               temp_erp, temp_erp->status, temp_erp->refers);
                }
        }
 
index c9740ae88d1a633c92e246912a0f57959f5a0f9a..e84cd5436556392de9c63d78470cc3c48f578d16 100644 (file)
@@ -6,20 +6,12 @@
  * Author(s): Stefan Weinhuber <wein@de.ibm.com>
  */
 
-#define KMSG_COMPONENT "dasd-eckd"
-
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <asm/ebcdic.h>
 #include "dasd_int.h"
 #include "dasd_eckd.h"
 
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif                         /* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd(eckd):"
-
-
 /*
  * General concept of alias management:
  * - PAV and DASD alias management is specific to the eckd discipline.
index c4e36650c42649ff28150ca2d24f93c659758794..0316c20823eecf0024b54f1ae7d54e443a5aaf7f 100644 (file)
@@ -13,8 +13,6 @@
  *
  */
 
-#define KMSG_COMPONENT "dasd"
-
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -24,8 +22,6 @@
 #include <linux/uaccess.h>
 #include <asm/ipl.h>
 
-/* This is ugly... */
-#define PRINTK_HEADER "dasd_devmap:"
 #define DASD_MAX_PARAMS 256
 
 #include "dasd_int.h"
@@ -1114,7 +1110,7 @@ dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
                use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0;
        else
                use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0;
-       return sprintf(buf, use_diag ? "1\n" : "0\n");
+       return sysfs_emit(buf, use_diag ? "1\n" : "0\n");
 }
 
 static ssize_t
@@ -1163,7 +1159,7 @@ dasd_use_raw_show(struct device *dev, struct device_attribute *attr, char *buf)
                use_raw = (devmap->features & DASD_FEATURE_USERAW) != 0;
        else
                use_raw = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USERAW) != 0;
-       return sprintf(buf, use_raw ? "1\n" : "0\n");
+       return sysfs_emit(buf, use_raw ? "1\n" : "0\n");
 }
 
 static ssize_t
@@ -1259,7 +1255,7 @@ dasd_access_show(struct device *dev, struct device_attribute *attr,
        if (count < 0)
                return count;
 
-       return sprintf(buf, "%d\n", count);
+       return sysfs_emit(buf, "%d\n", count);
 }
 
 static DEVICE_ATTR(host_access_count, 0444, dasd_access_show, NULL);
@@ -1338,19 +1334,19 @@ static ssize_t dasd_alias_show(struct device *dev,
 
        device = dasd_device_from_cdev(to_ccwdev(dev));
        if (IS_ERR(device))
-               return sprintf(buf, "0\n");
+               return sysfs_emit(buf, "0\n");
 
        if (device->discipline && device->discipline->get_uid &&
            !device->discipline->get_uid(device, &uid)) {
                if (uid.type == UA_BASE_PAV_ALIAS ||
                    uid.type == UA_HYPER_PAV_ALIAS) {
                        dasd_put_device(device);
-                       return sprintf(buf, "1\n");
+                       return sysfs_emit(buf, "1\n");
                }
        }
        dasd_put_device(device);
 
-       return sprintf(buf, "0\n");
+       return sysfs_emit(buf, "0\n");
 }
 
 static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL);
@@ -1412,15 +1408,9 @@ dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
                        break;
                }
 
-               if (strlen(uid.vduit) > 0)
-                       snprintf(uid_string, sizeof(uid_string),
-                                "%s.%s.%04x.%s.%s",
-                                uid.vendor, uid.serial, uid.ssid, ua_string,
-                                uid.vduit);
-               else
-                       snprintf(uid_string, sizeof(uid_string),
-                                "%s.%s.%04x.%s",
-                                uid.vendor, uid.serial, uid.ssid, ua_string);
+               snprintf(uid_string, sizeof(uid_string), "%s.%s.%04x.%s%s%s",
+                        uid.vendor, uid.serial, uid.ssid, ua_string,
+                        uid.vduit[0] ? "." : "", uid.vduit);
        }
        dasd_put_device(device);
 
@@ -1862,7 +1852,7 @@ static ssize_t dasd_pm_show(struct device *dev,
 
        device = dasd_device_from_cdev(to_ccwdev(dev));
        if (IS_ERR(device))
-               return sprintf(buf, "0\n");
+               return sysfs_emit(buf, "0\n");
 
        opm = dasd_path_get_opm(device);
        nppm = dasd_path_get_nppm(device);
@@ -1872,8 +1862,8 @@ static ssize_t dasd_pm_show(struct device *dev,
        ifccpm = dasd_path_get_ifccpm(device);
        dasd_put_device(device);
 
-       return sprintf(buf, "%02x %02x %02x %02x %02x %02x\n", opm, nppm,
-                      cablepm, cuirpm, hpfpm, ifccpm);
+       return sysfs_emit(buf, "%02x %02x %02x %02x %02x %02x\n", opm, nppm,
+                         cablepm, cuirpm, hpfpm, ifccpm);
 }
 
 static DEVICE_ATTR(path_masks, 0444, dasd_pm_show, NULL);
index 2e4e555b37c33293c7b4dde87d29500748cbd2c3..ea4b1d01bb767ec712e8e3696d91eccbcefa4e8a 100644 (file)
@@ -8,8 +8,6 @@
  *
  */
 
-#define KMSG_COMPONENT "dasd"
-
 #include <linux/kernel_stat.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
@@ -31,8 +29,6 @@
 #include "dasd_int.h"
 #include "dasd_diag.h"
 
-#define PRINTK_HEADER "dasd(diag):"
-
 MODULE_LICENSE("GPL");
 
 /* The maximum number of blocks per request (max_blocks) is dependent on the
@@ -621,25 +617,9 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                    "dump sense not available for DIAG data");
 }
 
-/*
- * Initialize block layer request queue.
- */
-static void dasd_diag_setup_blk_queue(struct dasd_block *block)
+static unsigned int dasd_diag_max_sectors(struct dasd_block *block)
 {
-       unsigned int logical_block_size = block->bp_block;
-       struct request_queue *q = block->gdp->queue;
-       int max;
-
-       max = DIAG_MAX_BLOCKS << block->s2b_shift;
-       blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
-       q->limits.max_dev_sectors = max;
-       blk_queue_logical_block_size(q, logical_block_size);
-       blk_queue_max_hw_sectors(q, max);
-       blk_queue_max_segments(q, USHRT_MAX);
-       /* With page sized segments each segment can be translated into one idaw/tidaw */
-       blk_queue_max_segment_size(q, PAGE_SIZE);
-       blk_queue_segment_boundary(q, PAGE_SIZE - 1);
-       blk_queue_dma_alignment(q, PAGE_SIZE - 1);
+       return DIAG_MAX_BLOCKS << block->s2b_shift;
 }
 
 static int dasd_diag_pe_handler(struct dasd_device *device,
@@ -652,10 +632,10 @@ static struct dasd_discipline dasd_diag_discipline = {
        .owner = THIS_MODULE,
        .name = "DIAG",
        .ebcname = "DIAG",
+       .max_sectors = dasd_diag_max_sectors,
        .check_device = dasd_diag_check_device,
        .pe_handler = dasd_diag_pe_handler,
        .fill_geometry = dasd_diag_fill_geometry,
-       .setup_blk_queue = dasd_diag_setup_blk_queue,
        .start_IO = dasd_start_diag,
        .term_IO = dasd_diag_term_IO,
        .handle_terminated_request = dasd_diag_handle_terminated_request,
index bd89b032968a4b747c64f5e1e9c95b799fab8d22..373c1a86c33ed5d7b760087a6669315bfa35182d 100644 (file)
@@ -10,8 +10,6 @@
  * Author.........: Nigel Hislop <hislop_nigel@emc.com>
  */
 
-#define KMSG_COMPONENT "dasd-eckd"
-
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include "dasd_int.h"
 #include "dasd_eckd.h"
 
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif                         /* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd(eckd):"
-
 /*
  * raw track access always map to 64k in memory
  * so it maps to 16 blocks of 4k per track
@@ -1072,22 +1065,14 @@ static void dasd_eckd_read_fc_security(struct dasd_device *device)
        }
 }
 
-static void dasd_eckd_get_uid_string(struct dasd_conf *conf,
-                                    char *print_uid)
+static void dasd_eckd_get_uid_string(struct dasd_conf *conf, char *print_uid)
 {
        struct dasd_uid uid;
 
        create_uid(conf, &uid);
-       if (strlen(uid.vduit) > 0)
-               snprintf(print_uid, DASD_UID_STRLEN,
-                        "%s.%s.%04x.%02x.%s",
-                        uid.vendor, uid.serial, uid.ssid,
-                        uid.real_unit_addr, uid.vduit);
-       else
-               snprintf(print_uid, DASD_UID_STRLEN,
-                        "%s.%s.%04x.%02x",
-                        uid.vendor, uid.serial, uid.ssid,
-                        uid.real_unit_addr);
+       snprintf(print_uid, DASD_UID_STRLEN, "%s.%s.%04x.%02x%s%s",
+                uid.vendor, uid.serial, uid.ssid, uid.real_unit_addr,
+                uid.vduit[0] ? "." : "", uid.vduit);
 }
 
 static int dasd_eckd_check_cabling(struct dasd_device *device,
@@ -5529,15 +5514,15 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
  * and return number of printed chars.
  */
 static void
-dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
+dasd_eckd_dump_ccw_range(struct dasd_device *device, struct ccw1 *from,
+                        struct ccw1 *to, char *page)
 {
        int len, count;
        char *datap;
 
        len = 0;
        while (from <= to) {
-               len += sprintf(page + len, PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
+               len += sprintf(page + len, "CCW %px: %08X %08X DAT:",
                               from, ((int *) from)[0], ((int *) from)[1]);
 
                /* get pointer to data (consider IDALs) */
@@ -5560,7 +5545,7 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
                from++;
        }
        if (len > 0)
-               printk(KERN_ERR "%s", page);
+               dev_err(&device->cdev->dev, "%s", page);
 }
 
 static void
@@ -5591,9 +5576,12 @@ dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct irb *irb,
 static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
                                 struct dasd_ccw_req *req, struct irb *irb)
 {
-       char *page;
        struct ccw1 *first, *last, *fail, *from, *to;
+       struct device *dev;
        int len, sl, sct;
+       char *page;
+
+       dev = &device->cdev->dev;
 
        page = (char *) get_zeroed_page(GFP_ATOMIC);
        if (page == NULL) {
@@ -5602,24 +5590,18 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
                return;
        }
        /* dump the sense data */
-       len = sprintf(page, PRINTK_HEADER
-                     " I/O status report for device %s:\n",
-                     dev_name(&device->cdev->dev));
-       len += sprintf(page + len, PRINTK_HEADER
-                      " in req: %p CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X "
-                      "CS:%02X RC:%d\n",
+       len = sprintf(page, "I/O status report:\n");
+       len += sprintf(page + len,
+                      "in req: %px CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X CS:%02X RC:%d\n",
                       req, scsw_cc(&irb->scsw), scsw_fctl(&irb->scsw),
                       scsw_actl(&irb->scsw), scsw_stctl(&irb->scsw),
                       scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw),
                       req ? req->intrc : 0);
-       len += sprintf(page + len, PRINTK_HEADER
-                      " device %s: Failing CCW: %p\n",
-                      dev_name(&device->cdev->dev),
+       len += sprintf(page + len, "Failing CCW: %px\n",
                       phys_to_virt(irb->scsw.cmd.cpa));
        if (irb->esw.esw0.erw.cons) {
                for (sl = 0; sl < 4; sl++) {
-                       len += sprintf(page + len, PRINTK_HEADER
-                                      " Sense(hex) %2d-%2d:",
+                       len += sprintf(page + len, "Sense(hex) %2d-%2d:",
                                       (8 * sl), ((8 * sl) + 7));
 
                        for (sct = 0; sct < 8; sct++) {
@@ -5631,23 +5613,20 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
 
                if (irb->ecw[27] & DASD_SENSE_BIT_0) {
                        /* 24 Byte Sense Data */
-                       sprintf(page + len, PRINTK_HEADER
-                               " 24 Byte: %x MSG %x, "
-                               "%s MSGb to SYSOP\n",
+                       sprintf(page + len,
+                               "24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
                                irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
                                irb->ecw[1] & 0x10 ? "" : "no");
                } else {
                        /* 32 Byte Sense Data */
-                       sprintf(page + len, PRINTK_HEADER
-                               " 32 Byte: Format: %x "
-                               "Exception class %x\n",
+                       sprintf(page + len,
+                               "32 Byte: Format: %x Exception class %x\n",
                                irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
                }
        } else {
-               sprintf(page + len, PRINTK_HEADER
-                       " SORRY - NO VALID SENSE AVAILABLE\n");
+               sprintf(page + len, "SORRY - NO VALID SENSE AVAILABLE\n");
        }
-       printk(KERN_ERR "%s", page);
+       dev_err(dev, "%s", page);
 
        if (req) {
                /* req == NULL for unsolicited interrupts */
@@ -5656,8 +5635,8 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
                first = req->cpaddr;
                for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
                to = min(first + 6, last);
-               printk(KERN_ERR PRINTK_HEADER " Related CP in req: %p\n", req);
-               dasd_eckd_dump_ccw_range(first, to, page);
+               dev_err(dev, "Related CP in req: %px\n", req);
+               dasd_eckd_dump_ccw_range(device, first, to, page);
 
                /* print failing CCW area (maximum 4) */
                /* scsw->cda is either valid or zero  */
@@ -5665,19 +5644,19 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
                fail = phys_to_virt(irb->scsw.cmd.cpa); /* failing CCW */
                if (from <  fail - 2) {
                        from = fail - 2;     /* there is a gap - print header */
-                       printk(KERN_ERR PRINTK_HEADER "......\n");
+                       dev_err(dev, "......\n");
                }
                to = min(fail + 1, last);
-               dasd_eckd_dump_ccw_range(from, to, page + len);
+               dasd_eckd_dump_ccw_range(device, from, to, page + len);
 
                /* print last CCWs (maximum 2) */
                len = 0;
                from = max(from, ++to);
                if (from < last - 1) {
                        from = last - 1;     /* there is a gap - print header */
-                       printk(KERN_ERR PRINTK_HEADER "......\n");
+                       dev_err(dev, "......\n");
                }
-               dasd_eckd_dump_ccw_range(from, last, page + len);
+               dasd_eckd_dump_ccw_range(device, from, last, page + len);
        }
        free_page((unsigned long) page);
 }
@@ -5701,11 +5680,9 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
                return;
        }
        /* dump the sense data */
-       len = sprintf(page, PRINTK_HEADER
-                     " I/O status report for device %s:\n",
-                     dev_name(&device->cdev->dev));
-       len += sprintf(page + len, PRINTK_HEADER
-                      " in req: %p CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X "
+       len = sprintf(page, "I/O status report:\n");
+       len += sprintf(page + len,
+                      "in req: %px CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X "
                       "CS:%02X fcxs:%02X schxs:%02X RC:%d\n",
                       req, scsw_cc(&irb->scsw), scsw_fctl(&irb->scsw),
                       scsw_actl(&irb->scsw), scsw_stctl(&irb->scsw),
@@ -5713,9 +5690,7 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
                       irb->scsw.tm.fcxs,
                       (irb->scsw.tm.ifob << 7) | irb->scsw.tm.sesq,
                       req ? req->intrc : 0);
-       len += sprintf(page + len, PRINTK_HEADER
-                      " device %s: Failing TCW: %p\n",
-                      dev_name(&device->cdev->dev),
+       len += sprintf(page + len, "Failing TCW: %px\n",
                       phys_to_virt(irb->scsw.tm.tcw));
 
        tsb = NULL;
@@ -5724,47 +5699,37 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
                tsb = tcw_get_tsb(phys_to_virt(irb->scsw.tm.tcw));
 
        if (tsb) {
-               len += sprintf(page + len, PRINTK_HEADER
-                              " tsb->length %d\n", tsb->length);
-               len += sprintf(page + len, PRINTK_HEADER
-                              " tsb->flags %x\n", tsb->flags);
-               len += sprintf(page + len, PRINTK_HEADER
-                              " tsb->dcw_offset %d\n", tsb->dcw_offset);
-               len += sprintf(page + len, PRINTK_HEADER
-                              " tsb->count %d\n", tsb->count);
+               len += sprintf(page + len, "tsb->length %d\n", tsb->length);
+               len += sprintf(page + len, "tsb->flags %x\n", tsb->flags);
+               len += sprintf(page + len, "tsb->dcw_offset %d\n", tsb->dcw_offset);
+               len += sprintf(page + len, "tsb->count %d\n", tsb->count);
                residual = tsb->count - 28;
-               len += sprintf(page + len, PRINTK_HEADER
-                              " residual %d\n", residual);
+               len += sprintf(page + len, "residual %d\n", residual);
 
                switch (tsb->flags & 0x07) {
                case 1: /* tsa_iostat */
-                       len += sprintf(page + len, PRINTK_HEADER
-                              " tsb->tsa.iostat.dev_time %d\n",
+                       len += sprintf(page + len, "tsb->tsa.iostat.dev_time %d\n",
                                       tsb->tsa.iostat.dev_time);
-                       len += sprintf(page + len, PRINTK_HEADER
-                              " tsb->tsa.iostat.def_time %d\n",
+                       len += sprintf(page + len, "tsb->tsa.iostat.def_time %d\n",
                                       tsb->tsa.iostat.def_time);
-                       len += sprintf(page + len, PRINTK_HEADER
-                              " tsb->tsa.iostat.queue_time %d\n",
+                       len += sprintf(page + len, "tsb->tsa.iostat.queue_time %d\n",
                                       tsb->tsa.iostat.queue_time);
-                       len += sprintf(page + len, PRINTK_HEADER
-                              " tsb->tsa.iostat.dev_busy_time %d\n",
+                       len += sprintf(page + len, "tsb->tsa.iostat.dev_busy_time %d\n",
                                       tsb->tsa.iostat.dev_busy_time);
-                       len += sprintf(page + len, PRINTK_HEADER
-                              " tsb->tsa.iostat.dev_act_time %d\n",
+                       len += sprintf(page + len, "tsb->tsa.iostat.dev_act_time %d\n",
                                       tsb->tsa.iostat.dev_act_time);
                        sense = tsb->tsa.iostat.sense;
                        break;
                case 2: /* ts_ddpc */
-                       len += sprintf(page + len, PRINTK_HEADER
-                              " tsb->tsa.ddpc.rc %d\n", tsb->tsa.ddpc.rc);
+                       len += sprintf(page + len, "tsb->tsa.ddpc.rc %d\n",
+                                      tsb->tsa.ddpc.rc);
                        for (sl = 0; sl < 2; sl++) {
-                               len += sprintf(page + len, PRINTK_HEADER
-                                              " tsb->tsa.ddpc.rcq %2d-%2d: ",
+                               len += sprintf(page + len,
+                                              "tsb->tsa.ddpc.rcq %2d-%2d: ",
                                               (8 * sl), ((8 * sl) + 7));
                                rcq = tsb->tsa.ddpc.rcq;
                                for (sct = 0; sct < 8; sct++) {
-                                       len += sprintf(page + len, " %02x",
+                                       len += sprintf(page + len, "%02x",
                                                       rcq[8 * sl + sct]);
                                }
                                len += sprintf(page + len, "\n");
@@ -5772,15 +5737,15 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
                        sense = tsb->tsa.ddpc.sense;
                        break;
                case 3: /* tsa_intrg */
-                       len += sprintf(page + len, PRINTK_HEADER
-                                     " tsb->tsa.intrg.: not supported yet\n");
+                       len += sprintf(page + len,
+                                     "tsb->tsa.intrg.: not supported yet\n");
                        break;
                }
 
                if (sense) {
                        for (sl = 0; sl < 4; sl++) {
-                               len += sprintf(page + len, PRINTK_HEADER
-                                              " Sense(hex) %2d-%2d:",
+                               len += sprintf(page + len,
+                                              "Sense(hex) %2d-%2d:",
                                               (8 * sl), ((8 * sl) + 7));
                                for (sct = 0; sct < 8; sct++) {
                                        len += sprintf(page + len, " %02x",
@@ -5791,27 +5756,23 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
 
                        if (sense[27] & DASD_SENSE_BIT_0) {
                                /* 24 Byte Sense Data */
-                               sprintf(page + len, PRINTK_HEADER
-                                       " 24 Byte: %x MSG %x, "
-                                       "%s MSGb to SYSOP\n",
+                               sprintf(page + len,
+                                       "24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
                                        sense[7] >> 4, sense[7] & 0x0f,
                                        sense[1] & 0x10 ? "" : "no");
                        } else {
                                /* 32 Byte Sense Data */
-                               sprintf(page + len, PRINTK_HEADER
-                                       " 32 Byte: Format: %x "
-                                       "Exception class %x\n",
+                               sprintf(page + len,
+                                       "32 Byte: Format: %x Exception class %x\n",
                                        sense[6] & 0x0f, sense[22] >> 4);
                        }
                } else {
-                       sprintf(page + len, PRINTK_HEADER
-                               " SORRY - NO VALID SENSE AVAILABLE\n");
+                       sprintf(page + len, "SORRY - NO VALID SENSE AVAILABLE\n");
                }
        } else {
-               sprintf(page + len, PRINTK_HEADER
-                       " SORRY - NO TSB DATA AVAILABLE\n");
+               sprintf(page + len, "SORRY - NO TSB DATA AVAILABLE\n");
        }
-       printk(KERN_ERR "%s", page);
+       dev_err(&device->cdev->dev, "%s", page);
        free_page((unsigned long) page);
 }
 
@@ -6865,17 +6826,9 @@ static void dasd_eckd_handle_hpf_error(struct dasd_device *device,
        dasd_schedule_requeue(device);
 }
 
-/*
- * Initialize block layer request queue.
- */
-static void dasd_eckd_setup_blk_queue(struct dasd_block *block)
+static unsigned int dasd_eckd_max_sectors(struct dasd_block *block)
 {
-       unsigned int logical_block_size = block->bp_block;
-       struct request_queue *q = block->gdp->queue;
-       struct dasd_device *device = block->base;
-       int max;
-
-       if (device->features & DASD_FEATURE_USERAW) {
+       if (block->base->features & DASD_FEATURE_USERAW) {
                /*
                 * the max_blocks value for raw_track access is 256
                 * it is higher than the native ECKD value because we
@@ -6883,19 +6836,10 @@ static void dasd_eckd_setup_blk_queue(struct dasd_block *block)
                 * so the max_hw_sectors are
                 * 2048 x 512B = 1024kB = 16 tracks
                 */
-               max = DASD_ECKD_MAX_BLOCKS_RAW << block->s2b_shift;
-       } else {
-               max = DASD_ECKD_MAX_BLOCKS << block->s2b_shift;
+               return DASD_ECKD_MAX_BLOCKS_RAW << block->s2b_shift;
        }
-       blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
-       q->limits.max_dev_sectors = max;
-       blk_queue_logical_block_size(q, logical_block_size);
-       blk_queue_max_hw_sectors(q, max);
-       blk_queue_max_segments(q, USHRT_MAX);
-       /* With page sized segments each segment can be translated into one idaw/tidaw */
-       blk_queue_max_segment_size(q, PAGE_SIZE);
-       blk_queue_segment_boundary(q, PAGE_SIZE - 1);
-       blk_queue_dma_alignment(q, PAGE_SIZE - 1);
+
+       return DASD_ECKD_MAX_BLOCKS << block->s2b_shift;
 }
 
 static struct ccw_driver dasd_eckd_driver = {
@@ -6927,7 +6871,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
        .basic_to_ready = dasd_eckd_basic_to_ready,
        .online_to_ready = dasd_eckd_online_to_ready,
        .basic_to_known = dasd_eckd_basic_to_known,
-       .setup_blk_queue = dasd_eckd_setup_blk_queue,
+       .max_sectors = dasd_eckd_max_sectors,
        .fill_geometry = dasd_eckd_fill_geometry,
        .start_IO = dasd_start_IO,
        .term_IO = dasd_term_IO,
index c956de711cf78cb15d4e218b224244ae4b793147..5064a616e041a310c1db35c0cbeacdd7980f0b86 100644 (file)
@@ -7,8 +7,6 @@
  *  Author(s): Stefan Weinhuber <wein@de.ibm.com>
  */
 
-#define KMSG_COMPONENT "dasd-eckd"
-
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include "dasd_int.h"
 #include "dasd_eckd.h"
 
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif                         /* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd(eer):"
-
 /*
  * SECTION: the internal buffer
  */
index c07e6e71351835eaf298cd30ba9281a1ef01004d..4c0d3a704513cc9f602317ed899e961d2a842701 100644 (file)
@@ -9,8 +9,6 @@
  *
  */
 
-#define KMSG_COMPONENT "dasd"
-
 #include <linux/ctype.h>
 #include <linux/init.h>
 
@@ -18,9 +16,6 @@
 #include <asm/ebcdic.h>
 #include <linux/uaccess.h>
 
-/* This is ugly... */
-#define PRINTK_HEADER "dasd_erp:"
-
 #include "dasd_int.h"
 
 struct dasd_ccw_req *
@@ -170,12 +165,12 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
        device = cqr->startdev;
        if (cqr->intrc == -ETIMEDOUT) {
                dev_err(&device->cdev->dev,
-                       "A timeout error occurred for cqr %p\n", cqr);
+                       "A timeout error occurred for cqr %px\n", cqr);
                return;
        }
        if (cqr->intrc == -ENOLINK) {
                dev_err(&device->cdev->dev,
-                       "A transport error occurred for cqr %p\n", cqr);
+                       "A transport error occurred for cqr %px\n", cqr);
                return;
        }
        /* dump sense data */
index c06fa2b27120572bca1695c10690ed8fa8f4a9b3..bcbb2f8e91feb6ca1a674742188083d5a0cdb49d 100644 (file)
 #include "dasd_int.h"
 #include "dasd_fba.h"
 
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif                         /* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd(fba):"
-
 #define FBA_DEFAULT_RETRIES 32
 
 #define DASD_FBA_CCW_WRITE 0x41
@@ -660,30 +655,27 @@ static void
 dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                    struct irb *irb)
 {
-       char *page;
        struct ccw1 *act, *end, *last;
        int len, sl, sct, count;
+       struct device *dev;
+       char *page;
+
+       dev = &device->cdev->dev;
 
        page = (char *) get_zeroed_page(GFP_ATOMIC);
        if (page == NULL) {
                DBF_DEV_EVENT(DBF_WARNING, device, "%s",
-                           "No memory to dump sense data");
+                             "No memory to dump sense data");
                return;
        }
-       len = sprintf(page, PRINTK_HEADER
-                     " I/O status report for device %s:\n",
-                     dev_name(&device->cdev->dev));
-       len += sprintf(page + len, PRINTK_HEADER
-                      " in req: %p CS: 0x%02X DS: 0x%02X\n", req,
-                      irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
-       len += sprintf(page + len, PRINTK_HEADER
-                      " device %s: Failing CCW: %p\n",
-                      dev_name(&device->cdev->dev),
+       len = sprintf(page, "I/O status report:\n");
+       len += sprintf(page + len, "in req: %px CS: 0x%02X DS: 0x%02X\n",
+                      req, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
+       len += sprintf(page + len, "Failing CCW: %px\n",
                       (void *) (addr_t) irb->scsw.cmd.cpa);
        if (irb->esw.esw0.erw.cons) {
                for (sl = 0; sl < 4; sl++) {
-                       len += sprintf(page + len, PRINTK_HEADER
-                                      " Sense(hex) %2d-%2d:",
+                       len += sprintf(page + len, "Sense(hex) %2d-%2d:",
                                       (8 * sl), ((8 * sl) + 7));
 
                        for (sct = 0; sct < 8; sct++) {
@@ -693,20 +685,18 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                        len += sprintf(page + len, "\n");
                }
        } else {
-               len += sprintf(page + len, PRINTK_HEADER
-                              " SORRY - NO VALID SENSE AVAILABLE\n");
+               len += sprintf(page + len, "SORRY - NO VALID SENSE AVAILABLE\n");
        }
-       printk(KERN_ERR "%s", page);
+       dev_err(dev, "%s", page);
 
        /* dump the Channel Program */
        /* print first CCWs (maximum 8) */
        act = req->cpaddr;
-        for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
+       for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
        end = min(act + 8, last);
-       len = sprintf(page, PRINTK_HEADER " Related CP in req: %p\n", req);
+       len = sprintf(page, "Related CP in req: %px\n", req);
        while (act <= end) {
-               len += sprintf(page + len, PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
+               len += sprintf(page + len, "CCW %px: %08X %08X DAT:",
                               act, ((int *) act)[0], ((int *) act)[1]);
                for (count = 0; count < 32 && count < act->count;
                     count += sizeof(int))
@@ -716,19 +706,17 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                len += sprintf(page + len, "\n");
                act++;
        }
-       printk(KERN_ERR "%s", page);
-
+       dev_err(dev, "%s", page);
 
        /* print failing CCW area */
        len = 0;
        if (act <  ((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa) - 2) {
                act = ((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa) - 2;
-               len += sprintf(page + len, PRINTK_HEADER "......\n");
+               len += sprintf(page + len, "......\n");
        }
        end = min((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa + 2, last);
        while (act <= end) {
-               len += sprintf(page + len, PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
+               len += sprintf(page + len, "CCW %px: %08X %08X DAT:",
                               act, ((int *) act)[0], ((int *) act)[1]);
                for (count = 0; count < 32 && count < act->count;
                     count += sizeof(int))
@@ -742,11 +730,10 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
        /* print last CCWs */
        if (act <  last - 2) {
                act = last - 2;
-               len += sprintf(page + len, PRINTK_HEADER "......\n");
+               len += sprintf(page + len, "......\n");
        }
        while (act <= last) {
-               len += sprintf(page + len, PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
+               len += sprintf(page + len, "CCW %px: %08X %08X DAT:",
                               act, ((int *) act)[0], ((int *) act)[1]);
                for (count = 0; count < 32 && count < act->count;
                     count += sizeof(int))
@@ -757,39 +744,13 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                act++;
        }
        if (len > 0)
-               printk(KERN_ERR "%s", page);
+               dev_err(dev, "%s", page);
        free_page((unsigned long) page);
 }
 
-/*
- * Initialize block layer request queue.
- */
-static void dasd_fba_setup_blk_queue(struct dasd_block *block)
+static unsigned int dasd_fba_max_sectors(struct dasd_block *block)
 {
-       unsigned int logical_block_size = block->bp_block;
-       struct request_queue *q = block->gdp->queue;
-       unsigned int max_bytes, max_discard_sectors;
-       int max;
-
-       max = DASD_FBA_MAX_BLOCKS << block->s2b_shift;
-       blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
-       q->limits.max_dev_sectors = max;
-       blk_queue_logical_block_size(q, logical_block_size);
-       blk_queue_max_hw_sectors(q, max);
-       blk_queue_max_segments(q, USHRT_MAX);
-       /* With page sized segments each segment can be translated into one idaw/tidaw */
-       blk_queue_max_segment_size(q, PAGE_SIZE);
-       blk_queue_segment_boundary(q, PAGE_SIZE - 1);
-
-       q->limits.discard_granularity = logical_block_size;
-
-       /* Calculate max_discard_sectors and make it PAGE aligned */
-       max_bytes = USHRT_MAX * logical_block_size;
-       max_bytes = ALIGN_DOWN(max_bytes, PAGE_SIZE);
-       max_discard_sectors = max_bytes / logical_block_size;
-
-       blk_queue_max_discard_sectors(q, max_discard_sectors);
-       blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
+       return DASD_FBA_MAX_BLOCKS << block->s2b_shift;
 }
 
 static int dasd_fba_pe_handler(struct dasd_device *device,
@@ -802,10 +763,11 @@ static struct dasd_discipline dasd_fba_discipline = {
        .owner = THIS_MODULE,
        .name = "FBA ",
        .ebcname = "FBA ",
+       .has_discard = true,
        .check_device = dasd_fba_check_characteristics,
        .do_analysis = dasd_fba_do_analysis,
        .pe_handler = dasd_fba_pe_handler,
-       .setup_blk_queue = dasd_fba_setup_blk_queue,
+       .max_sectors = dasd_fba_max_sectors,
        .fill_geometry = dasd_fba_fill_geometry,
        .start_IO = dasd_start_IO,
        .term_IO = dasd_term_IO,
index 55e3abe94cde2f617f34afc1c5ad4c98234c34f9..4533dd055ca8e31d7fc8bf711cf0ad0dd19653cf 100644 (file)
@@ -11,8 +11,6 @@
  *
  */
 
-#define KMSG_COMPONENT "dasd"
-
 #include <linux/interrupt.h>
 #include <linux/major.h>
 #include <linux/fs.h>
@@ -20,9 +18,6 @@
 
 #include <linux/uaccess.h>
 
-/* This is ugly... */
-#define PRINTK_HEADER "dasd_gendisk:"
-
 #include "dasd_int.h"
 
 static unsigned int queue_depth = 32;
@@ -39,6 +34,16 @@ MODULE_PARM_DESC(nr_hw_queues, "Default number of hardware queues for new DASD d
  */
 int dasd_gendisk_alloc(struct dasd_block *block)
 {
+       struct queue_limits lim = {
+               /*
+                * With page sized segments, each segment can be translated into
+                * one idaw/tidaw.
+                */
+               .max_segment_size = PAGE_SIZE,
+               .seg_boundary_mask = PAGE_SIZE - 1,
+               .dma_alignment = PAGE_SIZE - 1,
+               .max_segments = USHRT_MAX,
+       };
        struct gendisk *gdp;
        struct dasd_device *base;
        int len, rc;
@@ -58,11 +63,12 @@ int dasd_gendisk_alloc(struct dasd_block *block)
        if (rc)
                return rc;
 
-       gdp = blk_mq_alloc_disk(&block->tag_set, block);
+       gdp = blk_mq_alloc_disk(&block->tag_set, &lim, block);
        if (IS_ERR(gdp)) {
                blk_mq_free_tag_set(&block->tag_set);
                return PTR_ERR(gdp);
        }
+       blk_queue_flag_set(QUEUE_FLAG_NONROT, gdp->queue);
 
        /* Initialize gendisk structure. */
        gdp->major = DASD_MAJOR;
@@ -127,15 +133,15 @@ void dasd_gendisk_free(struct dasd_block *block)
  */
 int dasd_scan_partitions(struct dasd_block *block)
 {
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        int rc;
 
-       bdev_handle = bdev_open_by_dev(disk_devt(block->gdp), BLK_OPEN_READ,
+       bdev_file = bdev_file_open_by_dev(disk_devt(block->gdp), BLK_OPEN_READ,
                                       NULL, NULL);
-       if (IS_ERR(bdev_handle)) {
+       if (IS_ERR(bdev_file)) {
                DBF_DEV_EVENT(DBF_ERR, block->base,
                              "scan partitions error, blkdev_get returned %ld",
-                             PTR_ERR(bdev_handle));
+                             PTR_ERR(bdev_file));
                return -ENODEV;
        }
 
@@ -147,15 +153,15 @@ int dasd_scan_partitions(struct dasd_block *block)
                                "scan partitions error, rc %d", rc);
 
        /*
-        * Since the matching bdev_release() call to the
-        * bdev_open_by_path() in this function is not called before
+        * Since the matching fput() call to the
+        * bdev_file_open_by_path() in this function is not called before
         * dasd_destroy_partitions the offline open_count limit needs to be
-        * increased from 0 to 1. This is done by setting device->bdev_handle
+        * increased from 0 to 1. This is done by setting device->bdev_file
         * (see dasd_generic_set_offline). As long as the partition detection
         * is running no offline should be allowed. That is why the assignment
-        * to block->bdev_handle is done AFTER the BLKRRPART ioctl.
+        * to block->bdev_file is done AFTER the BLKRRPART ioctl.
         */
-       block->bdev_handle = bdev_handle;
+       block->bdev_file = bdev_file;
        return 0;
 }
 
@@ -165,21 +171,21 @@ int dasd_scan_partitions(struct dasd_block *block)
  */
 void dasd_destroy_partitions(struct dasd_block *block)
 {
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
 
        /*
-        * Get the bdev_handle pointer from the device structure and clear
-        * device->bdev_handle to lower the offline open_count limit again.
+        * Get the bdev_file pointer from the device structure and clear
+        * device->bdev_file to lower the offline open_count limit again.
         */
-       bdev_handle = block->bdev_handle;
-       block->bdev_handle = NULL;
+       bdev_file = block->bdev_file;
+       block->bdev_file = NULL;
 
-       mutex_lock(&bdev_handle->bdev->bd_disk->open_mutex);
-       bdev_disk_changed(bdev_handle->bdev->bd_disk, true);
-       mutex_unlock(&bdev_handle->bdev->bd_disk->open_mutex);
+       mutex_lock(&file_bdev(bdev_file)->bd_disk->open_mutex);
+       bdev_disk_changed(file_bdev(bdev_file)->bd_disk, true);
+       mutex_unlock(&file_bdev(bdev_file)->bd_disk->open_mutex);
 
        /* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
-       bdev_release(bdev_handle);
+       fput(bdev_file);
 }
 
 int dasd_gendisk_init(void)
index 1b1b8a41c4d42e6145be51537785b609e37c73be..e5f40536b4254027c3c181a6efb29e318fa72f7a 100644 (file)
@@ -113,9 +113,6 @@ do { \
                            __dev_id.ssid, __dev_id.devno, d_data);     \
 } while (0)
 
-/* limit size for an errorstring */
-#define ERRORLENGTH 30
-
 /* definition of dbf debug levels */
 #define        DBF_EMERG       0       /* system is unusable                   */
 #define        DBF_ALERT       1       /* action must be taken immediately     */
@@ -126,32 +123,6 @@ do { \
 #define        DBF_INFO        6       /* informational                        */
 #define        DBF_DEBUG       6       /* debug-level messages                 */
 
-/* messages to be written via klogd and dbf */
-#define DEV_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
-do { \
-       printk(d_loglevel PRINTK_HEADER " %s: " d_string "\n", \
-              dev_name(&d_device->cdev->dev), d_args); \
-       DBF_DEV_EVENT(DBF_ALERT, d_device, d_string, d_args); \
-} while(0)
-
-#define MESSAGE(d_loglevel,d_string,d_args...)\
-do { \
-       printk(d_loglevel PRINTK_HEADER " " d_string "\n", d_args); \
-       DBF_EVENT(DBF_ALERT, d_string, d_args); \
-} while(0)
-
-/* messages to be written via klogd only */
-#define DEV_MESSAGE_LOG(d_loglevel,d_device,d_string,d_args...)\
-do { \
-       printk(d_loglevel PRINTK_HEADER " %s: " d_string "\n", \
-              dev_name(&d_device->cdev->dev), d_args); \
-} while(0)
-
-#define MESSAGE_LOG(d_loglevel,d_string,d_args...)\
-do { \
-       printk(d_loglevel PRINTK_HEADER " " d_string "\n", d_args); \
-} while(0)
-
 /* Macro to calculate number of blocks per page */
 #define BLOCKS_PER_PAGE(blksize) (PAGE_SIZE / blksize)
 
@@ -322,6 +293,7 @@ struct dasd_discipline {
        struct module *owner;
        char ebcname[8];        /* a name used for tagging and printks */
        char name[8];           /* a name used for tagging and printks */
+       bool has_discard;
 
        struct list_head list;  /* used for list of disciplines */
 
@@ -360,10 +332,7 @@ struct dasd_discipline {
        int (*online_to_ready) (struct dasd_device *);
        int (*basic_to_known)(struct dasd_device *);
 
-       /*
-        * Initialize block layer request queue.
-        */
-       void (*setup_blk_queue)(struct dasd_block *);
+       unsigned int (*max_sectors)(struct dasd_block *);
        /* (struct dasd_device *);
         * Device operation functions. build_cp creates a ccw chain for
         * a block device request, start_io starts the request and
@@ -650,7 +619,7 @@ struct dasd_block {
        struct gendisk *gdp;
        spinlock_t request_queue_lock;
        struct blk_mq_tag_set tag_set;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        atomic_t open_count;
 
        unsigned long blocks;      /* size of volume in blocks */
index 61b9675e2a675e9dc1ec69101d8a4bc368d461c8..7e0ed7032f76a80ce3079d21537bbae6f5126455 100644 (file)
@@ -10,8 +10,6 @@
  * i/o controls for the dasd driver.
  */
 
-#define KMSG_COMPONENT "dasd"
-
 #include <linux/interrupt.h>
 #include <linux/compat.h>
 #include <linux/major.h>
 #include <linux/uaccess.h>
 #include <linux/dasd_mod.h>
 
-/* This is ugly... */
-#define PRINTK_HEADER "dasd_ioctl:"
-
 #include "dasd_int.h"
 
-
 static int
 dasd_ioctl_api_version(void __user *argp)
 {
@@ -537,7 +531,7 @@ static int __dasd_ioctl_information(struct dasd_block *block,
         * This must be hidden from user-space.
         */
        dasd_info->open_count = atomic_read(&block->open_count);
-       if (!block->bdev_handle)
+       if (!block->bdev_file)
                dasd_info->open_count++;
 
        /*
index 62a859ea67f8936f5b170cbc590b8b7e37a0fb37..0faaa437d9be8535a2cfe8c4aefa9b42463d4fc0 100644 (file)
@@ -11,8 +11,6 @@
  *
  */
 
-#define KMSG_COMPONENT "dasd"
-
 #include <linux/ctype.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -23,9 +21,6 @@
 #include <asm/debug.h>
 #include <linux/uaccess.h>
 
-/* This is ugly... */
-#define PRINTK_HEADER "dasd_proc:"
-
 #include "dasd_int.h"
 
 static struct proc_dir_entry *dasd_proc_root_entry = NULL;
index 4b7ecd4fd4319c000d2a4f1101022eafae0f2291..9c8f529b827cb3556e07bb0c3ed7ce51e5873cff 100644 (file)
@@ -546,6 +546,9 @@ static const struct attribute_group *dcssblk_dev_attr_groups[] = {
 static ssize_t
 dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
+       struct queue_limits lim = {
+               .logical_block_size     = 4096,
+       };
        int rc, i, j, num_of_segments;
        struct dcssblk_dev_info *dev_info;
        struct segment_info *seg_info, *temp;
@@ -629,9 +632,9 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
        dev_info->dev.release = dcssblk_release_segment;
        dev_info->dev.groups = dcssblk_dev_attr_groups;
        INIT_LIST_HEAD(&dev_info->lh);
-       dev_info->gd = blk_alloc_disk(NUMA_NO_NODE);
-       if (dev_info->gd == NULL) {
-               rc = -ENOMEM;
+       dev_info->gd = blk_alloc_disk(&lim, NUMA_NO_NODE);
+       if (IS_ERR(dev_info->gd)) {
+               rc = PTR_ERR(dev_info->gd);
                goto seg_list_del;
        }
        dev_info->gd->major = dcssblk_major;
@@ -639,7 +642,6 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
        dev_info->gd->fops = &dcssblk_devops;
        dev_info->gd->private_data = dev_info;
        dev_info->gd->flags |= GENHD_FL_NO_PART;
-       blk_queue_logical_block_size(dev_info->gd->queue, 4096);
        blk_queue_flag_set(QUEUE_FLAG_DAX, dev_info->gd->queue);
 
        seg_byte_size = (dev_info->end - dev_info->start + 1);
index ade95e91b3c8db6f657fdcb7bcec2c8589175e43..9f6fdd0daa74eb33bbf4fd7f570df7ce192d8b4b 100644 (file)
@@ -435,10 +435,17 @@ static const struct blk_mq_ops scm_mq_ops = {
 
 int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
 {
-       unsigned int devindex, nr_max_blk;
+       struct queue_limits lim = {
+               .logical_block_size     = 1 << 12,
+       };
+       unsigned int devindex;
        struct request_queue *rq;
        int len, ret;
 
+       lim.max_segments = min(scmdev->nr_max_block,
+               (unsigned int) (PAGE_SIZE / sizeof(struct aidaw)));
+       lim.max_hw_sectors = lim.max_segments << 3; /* 8 * 512 = blk_size */
+
        devindex = atomic_inc_return(&nr_devices) - 1;
        /* scma..scmz + scmaa..scmzz */
        if (devindex > 701) {
@@ -462,18 +469,12 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
        if (ret)
                goto out;
 
-       bdev->gendisk = blk_mq_alloc_disk(&bdev->tag_set, scmdev);
+       bdev->gendisk = blk_mq_alloc_disk(&bdev->tag_set, &lim, scmdev);
        if (IS_ERR(bdev->gendisk)) {
                ret = PTR_ERR(bdev->gendisk);
                goto out_tag;
        }
        rq = bdev->rq = bdev->gendisk->queue;
-       nr_max_blk = min(scmdev->nr_max_block,
-                        (unsigned int) (PAGE_SIZE / sizeof(struct aidaw)));
-
-       blk_queue_logical_block_size(rq, 1 << 12);
-       blk_queue_max_hw_sectors(rq, nr_max_blk << 3); /* 8 * 512 = blk_size */
-       blk_queue_max_segments(rq, nr_max_blk);
        blk_queue_flag_set(QUEUE_FLAG_NONROT, rq);
        blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, rq);
 
index 82efdd20ad01edebfc554e98b7af64c9e33a2b46..1d17a83569ce436ca37718dad31150cbd41df47a 100644 (file)
@@ -195,7 +195,7 @@ static void free_chan_prog(struct ccw1 *cpa)
        struct ccw1 *ptr = cpa;
 
        while (ptr->cda) {
-               kfree((void *)(addr_t) ptr->cda);
+               kfree(phys_to_virt(ptr->cda));
                ptr++;
        }
        kfree(cpa);
@@ -237,7 +237,7 @@ static struct ccw1 *alloc_chan_prog(const char __user *ubuf, int rec_count,
                        free_chan_prog(cpa);
                        return ERR_PTR(-ENOMEM);
                }
-               cpa[i].cda = (u32)(addr_t) kbuf;
+               cpa[i].cda = (u32)virt_to_phys(kbuf);
                if (copy_from_user(kbuf, ubuf, reclen)) {
                        free_chan_prog(cpa);
                        return ERR_PTR(-EFAULT);
index bc3be0330f1db97e04048c02cdec9ceb717a3f52..0969fa01df58b0bddff85696afe27d8e33b2dd12 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/irqflags.h>
 #include <asm/checksum.h>
 #include <asm/os_info.h>
-#include <asm/switch_to.h>
 #include <asm/maccess.h>
 #include "sclp.h"
 
index aa3292e57e3838c0e30d2c1302fa4b7dcb36b7e7..6eb8bcd948dc45db60c0c4d22bb2c3de2805172d 100644 (file)
@@ -31,7 +31,7 @@
  * to devices that use multiple subchannels.
  */
 
-static struct bus_type ccwgroup_bus_type;
+static const struct bus_type ccwgroup_bus_type;
 
 static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
 {
@@ -465,7 +465,7 @@ static void ccwgroup_shutdown(struct device *dev)
                gdrv->shutdown(gdev);
 }
 
-static struct bus_type ccwgroup_bus_type = {
+static const struct bus_type ccwgroup_bus_type = {
        .name   = "ccwgroup",
        .dev_groups = ccwgroup_dev_groups,
        .remove = ccwgroup_remove,
index 64ed55c3aed6ce7c8eed64eb03b133a83bff8887..3d88899dff7cfcf4da1d68c939fc73bd3937ba1f 100644 (file)
@@ -1091,8 +1091,8 @@ int __init chsc_init(void)
 {
        int ret;
 
-       sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
-       chsc_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       sei_page = (void *)get_zeroed_page(GFP_KERNEL);
+       chsc_page = (void *)get_zeroed_page(GFP_KERNEL);
        if (!sei_page || !chsc_page) {
                ret = -ENOMEM;
                goto out_err;
index 902237d0baefea37cf2f04f199a272abdcd1b76b..e6c800653f9880a03c1dbe562f20fd5d127bd0bc 100644 (file)
@@ -293,7 +293,7 @@ static int chsc_ioctl_start(void __user *user_area)
        if (!css_general_characteristics.dynio)
                /* It makes no sense to try. */
                return -EOPNOTSUPP;
-       chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL);
+       chsc_area = (void *)get_zeroed_page(GFP_KERNEL);
        if (!chsc_area)
                return -ENOMEM;
        request = kzalloc(sizeof(*request), GFP_KERNEL);
@@ -341,7 +341,7 @@ static int chsc_ioctl_on_close_set(void __user *user_area)
                ret = -ENOMEM;
                goto out_unlock;
        }
-       on_close_chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL);
+       on_close_chsc_area = (void *)get_zeroed_page(GFP_KERNEL);
        if (!on_close_chsc_area) {
                ret = -ENOMEM;
                goto out_free_request;
@@ -393,7 +393,7 @@ static int chsc_ioctl_start_sync(void __user *user_area)
        struct chsc_sync_area *chsc_area;
        int ret, ccode;
 
-       chsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       chsc_area = (void *)get_zeroed_page(GFP_KERNEL);
        if (!chsc_area)
                return -ENOMEM;
        if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) {
@@ -439,7 +439,7 @@ static int chsc_ioctl_info_channel_path(void __user *user_cd)
                u8 data[PAGE_SIZE - 20];
        } __attribute__ ((packed)) *scpcd_area;
 
-       scpcd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       scpcd_area = (void *)get_zeroed_page(GFP_KERNEL);
        if (!scpcd_area)
                return -ENOMEM;
        cd = kzalloc(sizeof(*cd), GFP_KERNEL);
@@ -501,7 +501,7 @@ static int chsc_ioctl_info_cu(void __user *user_cd)
                u8 data[PAGE_SIZE - 20];
        } __attribute__ ((packed)) *scucd_area;
 
-       scucd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       scucd_area = (void *)get_zeroed_page(GFP_KERNEL);
        if (!scucd_area)
                return -ENOMEM;
        cd = kzalloc(sizeof(*cd), GFP_KERNEL);
@@ -564,7 +564,7 @@ static int chsc_ioctl_info_sch_cu(void __user *user_cud)
                u8 data[PAGE_SIZE - 20];
        } __attribute__ ((packed)) *sscud_area;
 
-       sscud_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       sscud_area = (void *)get_zeroed_page(GFP_KERNEL);
        if (!sscud_area)
                return -ENOMEM;
        cud = kzalloc(sizeof(*cud), GFP_KERNEL);
@@ -626,7 +626,7 @@ static int chsc_ioctl_conf_info(void __user *user_ci)
                u8 data[PAGE_SIZE - 20];
        } __attribute__ ((packed)) *sci_area;
 
-       sci_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       sci_area = (void *)get_zeroed_page(GFP_KERNEL);
        if (!sci_area)
                return -ENOMEM;
        ci = kzalloc(sizeof(*ci), GFP_KERNEL);
@@ -697,7 +697,7 @@ static int chsc_ioctl_conf_comp_list(void __user *user_ccl)
                u32 res;
        } __attribute__ ((packed)) *cssids_parm;
 
-       sccl_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       sccl_area = (void *)get_zeroed_page(GFP_KERNEL);
        if (!sccl_area)
                return -ENOMEM;
        ccl = kzalloc(sizeof(*ccl), GFP_KERNEL);
@@ -757,7 +757,7 @@ static int chsc_ioctl_chpd(void __user *user_chpd)
        int ret;
 
        chpd = kzalloc(sizeof(*chpd), GFP_KERNEL);
-       scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       scpd_area = (void *)get_zeroed_page(GFP_KERNEL);
        if (!scpd_area || !chpd) {
                ret = -ENOMEM;
                goto out_free;
@@ -797,7 +797,7 @@ static int chsc_ioctl_dcal(void __user *user_dcal)
                u8 data[PAGE_SIZE - 36];
        } __attribute__ ((packed)) *sdcal_area;
 
-       sdcal_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       sdcal_area = (void *)get_zeroed_page(GFP_KERNEL);
        if (!sdcal_area)
                return -ENOMEM;
        dcal = kzalloc(sizeof(*dcal), GFP_KERNEL);
index 5584aa46c94e159dd5368b061c38b196199e5a71..f80dc18e2a761662dcd491faad85296ea951d252 100644 (file)
@@ -169,7 +169,8 @@ static inline void cmf_activate(void *area, unsigned int onoff)
                "       lgr     2,%[mbo]\n"
                "       schm\n"
                :
-               : [r1] "d" ((unsigned long)onoff), [mbo] "d" (area)
+               : [r1] "d" ((unsigned long)onoff),
+                 [mbo] "d" (virt_to_phys(area))
                : "1", "2");
 }
 
@@ -501,8 +502,7 @@ static int alloc_cmb(struct ccw_device *cdev)
                WARN_ON(!list_empty(&cmb_area.list));
 
                spin_unlock(&cmb_area.lock);
-               mem = (void*)__get_free_pages(GFP_KERNEL | GFP_DMA,
-                                get_order(size));
+               mem = (void *)__get_free_pages(GFP_KERNEL, get_order(size));
                spin_lock(&cmb_area.lock);
 
                if (cmb_area.mem) {
index 28a88ed2c3aada1d0092e98abda63824febcf5d6..094431a62ad542beff160eca325a6b75b5778f15 100644 (file)
@@ -39,7 +39,7 @@ int max_ssid;
 
 #define MAX_CSS_IDX 0
 struct channel_subsystem *channel_subsystems[MAX_CSS_IDX + 1];
-static struct bus_type css_bus_type;
+static const struct bus_type css_bus_type;
 
 int
 for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
@@ -1409,7 +1409,7 @@ static int css_uevent(const struct device *dev, struct kobj_uevent_env *env)
        return ret;
 }
 
-static struct bus_type css_bus_type = {
+static const struct bus_type css_bus_type = {
        .name     = "css",
        .match    = css_bus_match,
        .probe    = css_probe,
index 0cfb179e1bcb61d59be433b7a0e47c7bf7cabd9d..f95d12345d98a6dbfd1efa850829586852d409ab 100644 (file)
@@ -49,7 +49,7 @@ static const unsigned long recovery_delay[] = { 3, 30, 300 };
 
 static atomic_t ccw_device_init_count = ATOMIC_INIT(0);
 static DECLARE_WAIT_QUEUE_HEAD(ccw_device_init_wq);
-static struct bus_type ccw_bus_type;
+static const struct bus_type ccw_bus_type;
 
 /******************* bus type handling ***********************/
 
@@ -1776,7 +1776,7 @@ static void ccw_device_shutdown(struct device *dev)
        __disable_cmf(cdev);
 }
 
-static struct bus_type ccw_bus_type = {
+static const struct bus_type ccw_bus_type = {
        .name   = "ccw",
        .match  = ccw_bus_match,
        .uevent = ccw_uevent,
index c533d1dadc6bbb0f3f388ac62b01049ac99a72c5..a5dba3829769c7954ed2d3ba38800bc768fb0019 100644 (file)
@@ -202,7 +202,8 @@ int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
                return -EINVAL;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
-       if (cdev->private->state == DEV_STATE_VERIFY) {
+       if (cdev->private->state == DEV_STATE_VERIFY ||
+           cdev->private->flags.doverify) {
                /* Remember to fake irb when finished. */
                if (!cdev->private->flags.fake_irb) {
                        cdev->private->flags.fake_irb = FAKE_CMD_IRB;
@@ -214,8 +215,7 @@ int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
        }
        if (cdev->private->state != DEV_STATE_ONLINE ||
            ((sch->schib.scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) &&
-            !(sch->schib.scsw.cmd.stctl & SCSW_STCTL_SEC_STATUS)) ||
-           cdev->private->flags.doverify)
+            !(sch->schib.scsw.cmd.stctl & SCSW_STCTL_SEC_STATUS)))
                return -EBUSY;
        ret = cio_set_options (sch, flags);
        if (ret)
index 6b21ba68c1fe62b3e24080dce36b8642cb94406b..c7894d61306d741350b75384e12541accf112186 100644 (file)
@@ -42,7 +42,7 @@ static int scmdev_uevent(const struct device *dev, struct kobj_uevent_env *env)
        return add_uevent_var(env, "MODALIAS=scm:scmdev");
 }
 
-static struct bus_type scm_bus_type = {
+static const struct bus_type scm_bus_type = {
        .name  = "scm",
        .probe = scmdev_probe,
        .remove = scmdev_remove,
@@ -228,7 +228,7 @@ int scm_update_information(void)
        size_t num;
        int ret;
 
-       scm_info = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+       scm_info = (void *)__get_free_page(GFP_KERNEL);
        if (!scm_info)
                return -ENOMEM;
 
index f46dd6abacd709b2395d15d25151eb266ecacbf1..cce0bafd4c926a2bd53693545b505295dd9d425c 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/debugfs.h>
 #include <linux/ctype.h>
 #include <linux/module.h>
+#include <asm/uv.h>
 
 #include "ap_bus.h"
 #include "ap_debug.h"
@@ -83,14 +84,11 @@ EXPORT_SYMBOL(ap_perms);
 DEFINE_MUTEX(ap_perms_mutex);
 EXPORT_SYMBOL(ap_perms_mutex);
 
-/* # of bus scans since init */
-static atomic64_t ap_scan_bus_count;
-
 /* # of bindings complete since init */
 static atomic64_t ap_bindings_complete_count = ATOMIC64_INIT(0);
 
-/* completion for initial APQN bindings complete */
-static DECLARE_COMPLETION(ap_init_apqn_bindings_complete);
+/* completion for APQN bindings complete */
+static DECLARE_COMPLETION(ap_apqn_bindings_complete);
 
 static struct ap_config_info *ap_qci_info;
 static struct ap_config_info *ap_qci_info_old;
@@ -101,12 +99,16 @@ static struct ap_config_info *ap_qci_info_old;
 debug_info_t *ap_dbf_info;
 
 /*
- * Workqueue timer for bus rescan.
+ * AP bus rescan related things.
  */
-static struct timer_list ap_config_timer;
-static int ap_config_time = AP_CONFIG_TIME;
-static void ap_scan_bus(struct work_struct *);
-static DECLARE_WORK(ap_scan_work, ap_scan_bus);
+static bool ap_scan_bus(void);
+static bool ap_scan_bus_result; /* result of last ap_scan_bus() */
+static DEFINE_MUTEX(ap_scan_bus_mutex); /* mutex ap_scan_bus() invocations */
+static atomic64_t ap_scan_bus_count; /* counter ap_scan_bus() invocations */
+static int ap_scan_bus_time = AP_CONFIG_TIME;
+static struct timer_list ap_scan_bus_timer;
+static void ap_scan_bus_wq_callback(struct work_struct *);
+static DECLARE_WORK(ap_scan_bus_work, ap_scan_bus_wq_callback);
 
 /*
  * Tasklet & timer for AP request polling and interrupts
@@ -135,7 +137,7 @@ static int ap_max_domain_id = 15;
 /* Maximum adapter id, if not given via qci */
 static int ap_max_adapter_id = 63;
 
-static struct bus_type ap_bus_type;
+static const struct bus_type ap_bus_type;
 
 /* Adapter interrupt definitions */
 static void ap_interrupt_handler(struct airq_struct *airq,
@@ -753,7 +755,7 @@ static void ap_calc_bound_apqns(unsigned int *apqns, unsigned int *bound)
 }
 
 /*
- * After initial ap bus scan do check if all existing APQNs are
+ * After ap bus scan do check if all existing APQNs are
  * bound to device drivers.
  */
 static void ap_check_bindings_complete(void)
@@ -763,9 +765,9 @@ static void ap_check_bindings_complete(void)
        if (atomic64_read(&ap_scan_bus_count) >= 1) {
                ap_calc_bound_apqns(&apqns, &bound);
                if (bound == apqns) {
-                       if (!completion_done(&ap_init_apqn_bindings_complete)) {
-                               complete_all(&ap_init_apqn_bindings_complete);
-                               AP_DBF_INFO("%s complete\n", __func__);
+                       if (!completion_done(&ap_apqn_bindings_complete)) {
+                               complete_all(&ap_apqn_bindings_complete);
+                               pr_debug("%s all apqn bindings complete\n", __func__);
                        }
                        ap_send_bindings_complete_uevent();
                }
@@ -782,27 +784,29 @@ static void ap_check_bindings_complete(void)
  * -ETIME is returned. On failures negative return values are
  * returned to the caller.
  */
-int ap_wait_init_apqn_bindings_complete(unsigned long timeout)
+int ap_wait_apqn_bindings_complete(unsigned long timeout)
 {
+       int rc = 0;
        long l;
 
-       if (completion_done(&ap_init_apqn_bindings_complete))
+       if (completion_done(&ap_apqn_bindings_complete))
                return 0;
 
        if (timeout)
                l = wait_for_completion_interruptible_timeout(
-                       &ap_init_apqn_bindings_complete, timeout);
+                       &ap_apqn_bindings_complete, timeout);
        else
                l = wait_for_completion_interruptible(
-                       &ap_init_apqn_bindings_complete);
+                       &ap_apqn_bindings_complete);
        if (l < 0)
-               return l == -ERESTARTSYS ? -EINTR : l;
+               rc = l == -ERESTARTSYS ? -EINTR : l;
        else if (l == 0 && timeout)
-               return -ETIME;
+               rc = -ETIME;
 
-       return 0;
+       pr_debug("%s rc=%d\n", __func__, rc);
+       return rc;
 }
-EXPORT_SYMBOL(ap_wait_init_apqn_bindings_complete);
+EXPORT_SYMBOL(ap_wait_apqn_bindings_complete);
 
 static int __ap_queue_devices_with_id_unregister(struct device *dev, void *data)
 {
@@ -826,8 +830,8 @@ static int __ap_revise_reserved(struct device *dev, void *dummy)
                drvres = to_ap_drv(dev->driver)->flags
                        & AP_DRIVER_FLAG_DEFAULT;
                if (!!devres != !!drvres) {
-                       AP_DBF_DBG("%s reprobing queue=%02x.%04x\n",
-                                  __func__, card, queue);
+                       pr_debug("%s reprobing queue=%02x.%04x\n",
+                                __func__, card, queue);
                        rc = device_reprobe(dev);
                        if (rc)
                                AP_DBF_WARN("%s reprobing queue=%02x.%04x failed\n",
@@ -939,8 +943,6 @@ static int ap_device_probe(struct device *dev)
                if (is_queue_dev(dev))
                        hash_del(&to_ap_queue(dev)->hnode);
                spin_unlock_bh(&ap_queues_lock);
-       } else {
-               ap_check_bindings_complete();
        }
 
 out:
@@ -1012,16 +1014,47 @@ void ap_driver_unregister(struct ap_driver *ap_drv)
 }
 EXPORT_SYMBOL(ap_driver_unregister);
 
-void ap_bus_force_rescan(void)
+/*
+ * Enforce a synchronous AP bus rescan.
+ * Returns true if the bus scan finds a change in the AP configuration
+ * and AP devices have been added or deleted when this function returns.
+ */
+bool ap_bus_force_rescan(void)
 {
+       unsigned long scan_counter = atomic64_read(&ap_scan_bus_count);
+       bool rc = false;
+
+       pr_debug(">%s scan counter=%lu\n", __func__, scan_counter);
+
        /* Only trigger AP bus scans after the initial scan is done */
-       if (atomic64_read(&ap_scan_bus_count) <= 0)
-               return;
+       if (scan_counter <= 0)
+               goto out;
+
+       /* Try to acquire the AP scan bus mutex */
+       if (mutex_trylock(&ap_scan_bus_mutex)) {
+               /* mutex acquired, run the AP bus scan */
+               ap_scan_bus_result = ap_scan_bus();
+               rc = ap_scan_bus_result;
+               mutex_unlock(&ap_scan_bus_mutex);
+               goto out;
+       }
+
+       /*
+        * Mutex acquire failed. So there is currently another task
+        * already running the AP bus scan. Then let's simple wait
+        * for the lock which means the other task has finished and
+        * stored the result in ap_scan_bus_result.
+        */
+       if (mutex_lock_interruptible(&ap_scan_bus_mutex)) {
+               /* some error occurred, ignore and go out */
+               goto out;
+       }
+       rc = ap_scan_bus_result;
+       mutex_unlock(&ap_scan_bus_mutex);
 
-       /* processing a asynchronous bus rescan */
-       del_timer(&ap_config_timer);
-       queue_work(system_long_wq, &ap_scan_work);
-       flush_work(&ap_scan_work);
+out:
+       pr_debug("%s rc=%d\n", __func__, rc);
+       return rc;
 }
 EXPORT_SYMBOL(ap_bus_force_rescan);
 
@@ -1030,7 +1063,7 @@ EXPORT_SYMBOL(ap_bus_force_rescan);
  */
 void ap_bus_cfg_chg(void)
 {
-       AP_DBF_DBG("%s config change, forcing bus rescan\n", __func__);
+       pr_debug("%s config change, forcing bus rescan\n", __func__);
 
        ap_bus_force_rescan();
 }
@@ -1250,7 +1283,7 @@ static BUS_ATTR_RO(ap_interrupts);
 
 static ssize_t config_time_show(const struct bus_type *bus, char *buf)
 {
-       return sysfs_emit(buf, "%d\n", ap_config_time);
+       return sysfs_emit(buf, "%d\n", ap_scan_bus_time);
 }
 
 static ssize_t config_time_store(const struct bus_type *bus,
@@ -1260,8 +1293,8 @@ static ssize_t config_time_store(const struct bus_type *bus,
 
        if (sscanf(buf, "%d\n", &time) != 1 || time < 5 || time > 120)
                return -EINVAL;
-       ap_config_time = time;
-       mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ);
+       ap_scan_bus_time = time;
+       mod_timer(&ap_scan_bus_timer, jiffies + ap_scan_bus_time * HZ);
        return count;
 }
 
@@ -1603,7 +1636,7 @@ static struct attribute *ap_bus_attrs[] = {
 };
 ATTRIBUTE_GROUPS(ap_bus);
 
-static struct bus_type ap_bus_type = {
+static const struct bus_type ap_bus_type = {
        .name = "ap",
        .bus_groups = ap_bus_groups,
        .match = &ap_bus_match,
@@ -1888,8 +1921,8 @@ static inline void ap_scan_domains(struct ap_card *ac)
                                aq->last_err_rc = AP_RESPONSE_CHECKSTOPPED;
                        }
                        spin_unlock_bh(&aq->lock);
-                       AP_DBF_DBG("%s(%d,%d) queue dev checkstop on\n",
-                                  __func__, ac->id, dom);
+                       pr_debug("%s(%d,%d) queue dev checkstop on\n",
+                                __func__, ac->id, dom);
                        /* 'receive' pending messages with -EAGAIN */
                        ap_flush_queue(aq);
                        goto put_dev_and_continue;
@@ -1899,8 +1932,8 @@ static inline void ap_scan_domains(struct ap_card *ac)
                        if (aq->dev_state > AP_DEV_STATE_UNINITIATED)
                                _ap_queue_init_state(aq);
                        spin_unlock_bh(&aq->lock);
-                       AP_DBF_DBG("%s(%d,%d) queue dev checkstop off\n",
-                                  __func__, ac->id, dom);
+                       pr_debug("%s(%d,%d) queue dev checkstop off\n",
+                                __func__, ac->id, dom);
                        goto put_dev_and_continue;
                }
                /* config state change */
@@ -1912,8 +1945,8 @@ static inline void ap_scan_domains(struct ap_card *ac)
                                aq->last_err_rc = AP_RESPONSE_DECONFIGURED;
                        }
                        spin_unlock_bh(&aq->lock);
-                       AP_DBF_DBG("%s(%d,%d) queue dev config off\n",
-                                  __func__, ac->id, dom);
+                       pr_debug("%s(%d,%d) queue dev config off\n",
+                                __func__, ac->id, dom);
                        ap_send_config_uevent(&aq->ap_dev, aq->config);
                        /* 'receive' pending messages with -EAGAIN */
                        ap_flush_queue(aq);
@@ -1924,8 +1957,8 @@ static inline void ap_scan_domains(struct ap_card *ac)
                        if (aq->dev_state > AP_DEV_STATE_UNINITIATED)
                                _ap_queue_init_state(aq);
                        spin_unlock_bh(&aq->lock);
-                       AP_DBF_DBG("%s(%d,%d) queue dev config on\n",
-                                  __func__, ac->id, dom);
+                       pr_debug("%s(%d,%d) queue dev config on\n",
+                                __func__, ac->id, dom);
                        ap_send_config_uevent(&aq->ap_dev, aq->config);
                        goto put_dev_and_continue;
                }
@@ -1997,8 +2030,8 @@ static inline void ap_scan_adapter(int ap)
                        ap_scan_rm_card_dev_and_queue_devs(ac);
                        put_device(dev);
                } else {
-                       AP_DBF_DBG("%s(%d) no type info (no APQN found), ignored\n",
-                                  __func__, ap);
+                       pr_debug("%s(%d) no type info (no APQN found), ignored\n",
+                                __func__, ap);
                }
                return;
        }
@@ -2010,8 +2043,8 @@ static inline void ap_scan_adapter(int ap)
                        ap_scan_rm_card_dev_and_queue_devs(ac);
                        put_device(dev);
                } else {
-                       AP_DBF_DBG("%s(%d) no valid type (0) info, ignored\n",
-                                  __func__, ap);
+                       pr_debug("%s(%d) no valid type (0) info, ignored\n",
+                                __func__, ap);
                }
                return;
        }
@@ -2135,23 +2168,80 @@ static bool ap_get_configuration(void)
                      sizeof(struct ap_config_info)) != 0;
 }
 
+/*
+ * ap_config_has_new_aps - Check current against old qci info if
+ * new adapters have appeared. Returns true if at least one new
+ * adapter in the apm mask is showing up. Existing adapters or
+ * receding adapters are not counted.
+ */
+static bool ap_config_has_new_aps(void)
+{
+
+       unsigned long m[BITS_TO_LONGS(AP_DEVICES)];
+
+       if (!ap_qci_info)
+               return false;
+
+       bitmap_andnot(m, (unsigned long *)ap_qci_info->apm,
+                     (unsigned long *)ap_qci_info_old->apm, AP_DEVICES);
+       if (!bitmap_empty(m, AP_DEVICES))
+               return true;
+
+       return false;
+}
+
+/*
+ * ap_config_has_new_doms - Check current against old qci info if
+ * new (usage) domains have appeared. Returns true if at least one
+ * new domain in the aqm mask is showing up. Existing domains or
+ * receding domains are not counted.
+ */
+static bool ap_config_has_new_doms(void)
+{
+       unsigned long m[BITS_TO_LONGS(AP_DOMAINS)];
+
+       if (!ap_qci_info)
+               return false;
+
+       bitmap_andnot(m, (unsigned long *)ap_qci_info->aqm,
+                     (unsigned long *)ap_qci_info_old->aqm, AP_DOMAINS);
+       if (!bitmap_empty(m, AP_DOMAINS))
+               return true;
+
+       return false;
+}
+
 /**
  * ap_scan_bus(): Scan the AP bus for new devices
- * Runs periodically, workqueue timer (ap_config_time)
- * @unused: Unused pointer.
+ * Always run under mutex ap_scan_bus_mutex protection
+ * which needs to get locked/unlocked by the caller!
+ * Returns true if any config change has been detected
+ * during the scan, otherwise false.
  */
-static void ap_scan_bus(struct work_struct *unused)
+static bool ap_scan_bus(void)
 {
-       int ap, config_changed = 0;
+       bool config_changed;
+       int ap;
+
+       pr_debug(">%s\n", __func__);
 
-       /* config change notify */
+       /* (re-)fetch configuration via QCI */
        config_changed = ap_get_configuration();
-       if (config_changed)
+       if (config_changed) {
+               if (ap_config_has_new_aps() || ap_config_has_new_doms()) {
+                       /*
+                        * Appearance of new adapters and/or domains need to
+                        * build new ap devices which need to get bound to an
+                        * device driver. Thus reset the APQN bindings complete
+                        * completion.
+                        */
+                       reinit_completion(&ap_apqn_bindings_complete);
+               }
+               /* post a config change notify */
                notify_config_changed();
+       }
        ap_select_domain();
 
-       AP_DBF_DBG("%s running\n", __func__);
-
        /* loop over all possible adapters */
        for (ap = 0; ap <= ap_max_adapter_id; ap++)
                ap_scan_adapter(ap);
@@ -2174,23 +2264,56 @@ static void ap_scan_bus(struct work_struct *unused)
        }
 
        if (atomic64_inc_return(&ap_scan_bus_count) == 1) {
-               AP_DBF_DBG("%s init scan complete\n", __func__);
+               pr_debug("%s init scan complete\n", __func__);
                ap_send_init_scan_done_uevent();
-               ap_check_bindings_complete();
        }
 
-       mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ);
+       ap_check_bindings_complete();
+
+       mod_timer(&ap_scan_bus_timer, jiffies + ap_scan_bus_time * HZ);
+
+       pr_debug("<%s config_changed=%d\n", __func__, config_changed);
+
+       return config_changed;
 }
 
-static void ap_config_timeout(struct timer_list *unused)
+/*
+ * Callback for the ap_scan_bus_timer
+ * Runs periodically, workqueue timer (ap_scan_bus_time)
+ */
+static void ap_scan_bus_timer_callback(struct timer_list *unused)
 {
-       queue_work(system_long_wq, &ap_scan_work);
+       /*
+        * schedule work into the system long wq which when
+        * the work is finally executed, calls the AP bus scan.
+        */
+       queue_work(system_long_wq, &ap_scan_bus_work);
+}
+
+/*
+ * Callback for the ap_scan_bus_work
+ */
+static void ap_scan_bus_wq_callback(struct work_struct *unused)
+{
+       /*
+        * Try to invoke an ap_scan_bus(). If the mutex acquisition
+        * fails there is currently another task already running the
+        * AP scan bus and there is no need to wait and re-trigger the
+        * scan again. Please note at the end of the scan bus function
+        * the AP scan bus timer is re-armed which triggers then the
+        * ap_scan_bus_timer_callback which enqueues a work into the
+        * system_long_wq which invokes this function here again.
+        */
+       if (mutex_trylock(&ap_scan_bus_mutex)) {
+               ap_scan_bus_result = ap_scan_bus();
+               mutex_unlock(&ap_scan_bus_mutex);
+       }
 }
 
 static int __init ap_debug_init(void)
 {
        ap_dbf_info = debug_register("ap", 2, 1,
-                                    DBF_MAX_SPRINTF_ARGS * sizeof(long));
+                                    AP_DBF_MAX_SPRINTF_ARGS * sizeof(long));
        debug_register_view(ap_dbf_info, &debug_sprintf_view);
        debug_set_level(ap_dbf_info, DBF_ERR);
 
@@ -2274,7 +2397,7 @@ static int __init ap_module_init(void)
        ap_root_device->bus = &ap_bus_type;
 
        /* Setup the AP bus rescan timer. */
-       timer_setup(&ap_config_timer, ap_config_timeout, 0);
+       timer_setup(&ap_scan_bus_timer, ap_scan_bus_timer_callback, 0);
 
        /*
         * Setup the high resolution poll timer.
@@ -2292,7 +2415,7 @@ static int __init ap_module_init(void)
                        goto out_work;
        }
 
-       queue_work(system_long_wq, &ap_scan_work);
+       queue_work(system_long_wq, &ap_scan_bus_work);
 
        return 0;
 
index 98814839ef301ed796f0700ea11acbcbd7262742..59c7ed49aa02489593ee052b543be348f7df3027 100644 (file)
@@ -266,7 +266,7 @@ int ap_sb_available(void);
 bool ap_is_se_guest(void);
 void ap_wait(enum ap_sm_wait wait);
 void ap_request_timeout(struct timer_list *t);
-void ap_bus_force_rescan(void);
+bool ap_bus_force_rescan(void);
 
 int ap_test_config_usage_domain(unsigned int domain);
 int ap_test_config_ctrl_domain(unsigned int domain);
@@ -352,8 +352,12 @@ int ap_parse_mask_str(const char *str,
  * the return value is 0. If the timeout (in jiffies) hits instead
  * -ETIME is returned. On failures negative return values are
  * returned to the caller.
+ * It may be that the AP bus scan finds new devices. Then the
+ * condition that all APQNs are bound to their device drivers
+ * is reset to false and this call again blocks until either all
+ * APQNs are bound to a device driver or the timeout hits again.
  */
-int ap_wait_init_apqn_bindings_complete(unsigned long timeout);
+int ap_wait_apqn_bindings_complete(unsigned long timeout);
 
 void ap_send_config_uevent(struct ap_device *ap_dev, bool cfg);
 void ap_send_online_uevent(struct ap_device *ap_dev, int online);
index c083ce88a9a61f1b24022827420900e6d521f166..2f66271b8564708cb8724508c189841cb96b5ea6 100644 (file)
@@ -16,7 +16,7 @@
 #define RC2ERR(rc) ((rc) ? DBF_ERR : DBF_INFO)
 #define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO)
 
-#define DBF_MAX_SPRINTF_ARGS 6
+#define AP_DBF_MAX_SPRINTF_ARGS 6
 
 #define AP_DBF(...)                                    \
        debug_sprintf_event(ap_dbf_info, ##__VA_ARGS__)
@@ -26,8 +26,6 @@
        debug_sprintf_event(ap_dbf_info, DBF_WARN, ##__VA_ARGS__)
 #define AP_DBF_INFO(...)                                       \
        debug_sprintf_event(ap_dbf_info, DBF_INFO, ##__VA_ARGS__)
-#define AP_DBF_DBG(...)                                        \
-       debug_sprintf_event(ap_dbf_info, DBF_DEBUG, ##__VA_ARGS__)
 
 extern debug_info_t *ap_dbf_info;
 
index 682595443145a390c57c082ef08b26aa5b2bcde8..6e4e8d324a6def068638e3418b8e9beef70a098f 100644 (file)
@@ -136,6 +136,8 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
 
        switch (status.response_code) {
        case AP_RESPONSE_NORMAL:
+               print_hex_dump_debug("aprpl: ", DUMP_PREFIX_ADDRESS, 16, 1,
+                                    aq->reply->msg, aq->reply->len, false);
                aq->queue_count = max_t(int, 0, aq->queue_count - 1);
                if (!status.queue_empty && !aq->queue_count)
                        aq->queue_count++;
@@ -169,6 +171,9 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
                aq->queue_count = 0;
                list_splice_init(&aq->pendingq, &aq->requestq);
                aq->requestq_count += aq->pendingq_count;
+               pr_debug("%s queue 0x%02x.%04x rescheduled %d reqs (new req %d)\n",
+                        __func__, AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid),
+                        aq->pendingq_count, aq->requestq_count);
                aq->pendingq_count = 0;
                break;
        default:
@@ -243,6 +248,8 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq)
 
        /* Start the next request on the queue. */
        ap_msg = list_entry(aq->requestq.next, struct ap_message, list);
+       print_hex_dump_debug("apreq: ", DUMP_PREFIX_ADDRESS, 16, 1,
+                            ap_msg->msg, ap_msg->len, false);
        status = __ap_send(qid, ap_msg->psmid,
                           ap_msg->msg, ap_msg->len,
                           ap_msg->flags & AP_MSG_FLAG_SPECIAL);
@@ -446,9 +453,9 @@ static enum ap_sm_wait ap_sm_assoc_wait(struct ap_queue *aq)
        case AP_BS_Q_USABLE:
                /* association is through */
                aq->sm_state = AP_SM_STATE_IDLE;
-               AP_DBF_DBG("%s queue 0x%02x.%04x associated with %u\n",
-                          __func__, AP_QID_CARD(aq->qid),
-                          AP_QID_QUEUE(aq->qid), aq->assoc_idx);
+               pr_debug("%s queue 0x%02x.%04x associated with %u\n",
+                        __func__, AP_QID_CARD(aq->qid),
+                        AP_QID_QUEUE(aq->qid), aq->assoc_idx);
                return AP_SM_WAIT_NONE;
        case AP_BS_Q_USABLE_NO_SECURE_KEY:
                /* association still pending */
@@ -690,9 +697,9 @@ static ssize_t ap_functions_show(struct device *dev,
 
        status = ap_test_queue(aq->qid, 1, &hwinfo);
        if (status.response_code > AP_RESPONSE_BUSY) {
-               AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
-                          __func__, status.response_code,
-                          AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
+               pr_debug("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
+                        __func__, status.response_code,
+                        AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
                return -EIO;
        }
 
@@ -846,9 +853,9 @@ static ssize_t se_bind_show(struct device *dev,
 
        status = ap_test_queue(aq->qid, 1, &hwinfo);
        if (status.response_code > AP_RESPONSE_BUSY) {
-               AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
-                          __func__, status.response_code,
-                          AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
+               pr_debug("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
+                        __func__, status.response_code,
+                        AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
                return -EIO;
        }
 
@@ -974,9 +981,9 @@ static ssize_t se_associate_show(struct device *dev,
 
        status = ap_test_queue(aq->qid, 1, &hwinfo);
        if (status.response_code > AP_RESPONSE_BUSY) {
-               AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
-                          __func__, status.response_code,
-                          AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
+               pr_debug("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
+                        __func__, status.response_code,
+                        AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
                return -EIO;
        }
 
index 6cfb6b2340c997b6989d717a417a60bc4bd7b5ce..dccf664a3d957366b99ee08d1ec613b6dec3a246 100644 (file)
@@ -42,24 +42,23 @@ MODULE_DESCRIPTION("s390 protected key interface");
  * debug feature data and functions
  */
 
-static debug_info_t *debug_info;
+static debug_info_t *pkey_dbf_info;
 
-#define DEBUG_DBG(...) debug_sprintf_event(debug_info, 6, ##__VA_ARGS__)
-#define DEBUG_INFO(...) debug_sprintf_event(debug_info, 5, ##__VA_ARGS__)
-#define DEBUG_WARN(...) debug_sprintf_event(debug_info, 4, ##__VA_ARGS__)
-#define DEBUG_ERR(...) debug_sprintf_event(debug_info, 3, ##__VA_ARGS__)
+#define PKEY_DBF_INFO(...) debug_sprintf_event(pkey_dbf_info, 5, ##__VA_ARGS__)
+#define PKEY_DBF_WARN(...) debug_sprintf_event(pkey_dbf_info, 4, ##__VA_ARGS__)
+#define PKEY_DBF_ERR(...)  debug_sprintf_event(pkey_dbf_info, 3, ##__VA_ARGS__)
 
 static void __init pkey_debug_init(void)
 {
        /* 5 arguments per dbf entry (including the format string ptr) */
-       debug_info = debug_register("pkey", 1, 1, 5 * sizeof(long));
-       debug_register_view(debug_info, &debug_sprintf_view);
-       debug_set_level(debug_info, 3);
+       pkey_dbf_info = debug_register("pkey", 1, 1, 5 * sizeof(long));
+       debug_register_view(pkey_dbf_info, &debug_sprintf_view);
+       debug_set_level(pkey_dbf_info, 3);
 }
 
 static void __exit pkey_debug_exit(void)
 {
-       debug_unregister(debug_info);
+       debug_unregister(pkey_dbf_info);
 }
 
 /* inside view of a protected key token (only type 0x00 version 0x01) */
@@ -163,14 +162,14 @@ static int pkey_clr2protkey(u32 keytype, const u8 *clrkey,
                fc = CPACF_PCKMO_ENC_ECC_ED448_KEY;
                break;
        default:
-               DEBUG_ERR("%s unknown/unsupported keytype %u\n",
-                         __func__, keytype);
+               PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n",
+                            __func__, keytype);
                return -EINVAL;
        }
 
        if (*protkeylen < keysize + AES_WK_VP_SIZE) {
-               DEBUG_ERR("%s prot key buffer size too small: %u < %d\n",
-                         __func__, *protkeylen, keysize + AES_WK_VP_SIZE);
+               PKEY_DBF_ERR("%s prot key buffer size too small: %u < %d\n",
+                            __func__, *protkeylen, keysize + AES_WK_VP_SIZE);
                return -EINVAL;
        }
 
@@ -182,7 +181,7 @@ static int pkey_clr2protkey(u32 keytype, const u8 *clrkey,
        }
        /* check for the pckmo subfunction we need now */
        if (!cpacf_test_func(&pckmo_functions, fc)) {
-               DEBUG_ERR("%s pckmo functions not available\n", __func__);
+               PKEY_DBF_ERR("%s pckmo functions not available\n", __func__);
                return -ENODEV;
        }
 
@@ -244,7 +243,7 @@ static int pkey_skey2pkey(const u8 *key, u8 *protkey,
        }
 
        if (rc)
-               DEBUG_DBG("%s failed rc=%d\n", __func__, rc);
+               pr_debug("%s failed rc=%d\n", __func__, rc);
 
        return rc;
 }
@@ -283,7 +282,7 @@ static int pkey_clr2ep11key(const u8 *clrkey, size_t clrkeylen,
 out:
        kfree(apqns);
        if (rc)
-               DEBUG_DBG("%s failed rc=%d\n", __func__, rc);
+               pr_debug("%s failed rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -294,33 +293,36 @@ static int pkey_ep11key2pkey(const u8 *key, size_t keylen,
                             u8 *protkey, u32 *protkeylen, u32 *protkeytype)
 {
        u32 nr_apqns, *apqns = NULL;
+       int i, j, rc = -ENODEV;
        u16 card, dom;
-       int i, rc;
 
        zcrypt_wait_api_operational();
 
-       /* build a list of apqns suitable for this key */
-       rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
-                           ZCRYPT_CEX7,
-                           ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4,
-                           ep11_kb_wkvp(key, keylen));
-       if (rc)
-               goto out;
+       /* try two times in case of failure */
+       for (i = 0; i < 2 && rc; i++) {
 
-       /* go through the list of apqns and try to derive an pkey */
-       for (rc = -ENODEV, i = 0; i < nr_apqns; i++) {
-               card = apqns[i] >> 16;
-               dom = apqns[i] & 0xFFFF;
-               rc = ep11_kblob2protkey(card, dom, key, keylen,
-                                       protkey, protkeylen, protkeytype);
-               if (rc == 0)
-                       break;
+               /* build a list of apqns suitable for this key */
+               rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
+                                   ZCRYPT_CEX7,
+                                   ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4,
+                                   ep11_kb_wkvp(key, keylen));
+               if (rc)
+                       continue; /* retry findcard on failure */
+
+               /* go through the list of apqns and try to derive an pkey */
+               for (rc = -ENODEV, j = 0; j < nr_apqns && rc; j++) {
+                       card = apqns[j] >> 16;
+                       dom = apqns[j] & 0xFFFF;
+                       rc = ep11_kblob2protkey(card, dom, key, keylen,
+                                               protkey, protkeylen, protkeytype);
+               }
+
+               kfree(apqns);
        }
 
-out:
-       kfree(apqns);
        if (rc)
-               DEBUG_DBG("%s failed rc=%d\n", __func__, rc);
+               pr_debug("%s failed rc=%d\n", __func__, rc);
+
        return rc;
 }
 
@@ -336,7 +338,7 @@ static int pkey_verifykey(const struct pkey_seckey *seckey,
        int rc;
 
        /* check the secure key for valid AES secure key */
-       rc = cca_check_secaeskeytoken(debug_info, 3, (u8 *)seckey, 0);
+       rc = cca_check_secaeskeytoken(pkey_dbf_info, 3, (u8 *)seckey, 0);
        if (rc)
                goto out;
        if (pattributes)
@@ -351,7 +353,7 @@ static int pkey_verifykey(const struct pkey_seckey *seckey,
 
        if (rc > 0) {
                /* key mkvp matches to old master key mkvp */
-               DEBUG_DBG("%s secure key has old mkvp\n", __func__);
+               pr_debug("%s secure key has old mkvp\n", __func__);
                if (pattributes)
                        *pattributes |= PKEY_VERIFY_ATTR_OLD_MKVP;
                rc = 0;
@@ -363,7 +365,7 @@ static int pkey_verifykey(const struct pkey_seckey *seckey,
                *pdomain = domain;
 
 out:
-       DEBUG_DBG("%s rc=%d\n", __func__, rc);
+       pr_debug("%s rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -379,8 +381,8 @@ static int pkey_genprotkey(u32 keytype, u8 *protkey,
 
        keysize = pkey_keytype_aes_to_size(keytype);
        if (!keysize) {
-               DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__,
-                         keytype);
+               PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n", __func__,
+                            keytype);
                return -EINVAL;
        }
 
@@ -428,13 +430,13 @@ static int pkey_verifyprotkey(const u8 *protkey, u32 protkeylen,
                fc = CPACF_KMC_PAES_256;
                break;
        default:
-               DEBUG_ERR("%s unknown/unsupported keytype %u\n", __func__,
-                         protkeytype);
+               PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n", __func__,
+                            protkeytype);
                return -EINVAL;
        }
        if (protkeylen != pkeylen) {
-               DEBUG_ERR("%s invalid protected key size %u for keytype %u\n",
-                         __func__, protkeylen, protkeytype);
+               PKEY_DBF_ERR("%s invalid protected key size %u for keytype %u\n",
+                            __func__, protkeylen, protkeytype);
                return -EINVAL;
        }
 
@@ -446,7 +448,7 @@ static int pkey_verifyprotkey(const u8 *protkey, u32 protkeylen,
        k = cpacf_kmc(fc | CPACF_ENCRYPT, &param, null_msg, dest_buf,
                      sizeof(null_msg));
        if (k != sizeof(null_msg)) {
-               DEBUG_ERR("%s protected key is not valid\n", __func__);
+               PKEY_DBF_ERR("%s protected key is not valid\n", __func__);
                return -EKEYREJECTED;
        }
 
@@ -464,13 +466,13 @@ static int nonccatokaes2pkey(const struct clearkeytoken *t,
 
        keysize = pkey_keytype_aes_to_size(t->keytype);
        if (!keysize) {
-               DEBUG_ERR("%s unknown/unsupported keytype %u\n",
-                         __func__, t->keytype);
+               PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n",
+                            __func__, t->keytype);
                return -EINVAL;
        }
        if (t->len != keysize) {
-               DEBUG_ERR("%s non clear key aes token: invalid key len %u\n",
-                         __func__, t->len);
+               PKEY_DBF_ERR("%s non clear key aes token: invalid key len %u\n",
+                            __func__, t->len);
                return -EINVAL;
        }
 
@@ -505,7 +507,7 @@ try_via_ep11:
                goto out;
 
 failure:
-       DEBUG_ERR("%s unable to build protected key from clear", __func__);
+       PKEY_DBF_ERR("%s unable to build protected key from clear", __func__);
 
 out:
        kfree(tmpbuf);
@@ -536,14 +538,14 @@ static int nonccatokecc2pkey(const struct clearkeytoken *t,
                keylen = 64;
                break;
        default:
-               DEBUG_ERR("%s unknown/unsupported keytype %u\n",
-                         __func__, t->keytype);
+               PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n",
+                            __func__, t->keytype);
                return -EINVAL;
        }
 
        if (t->len != keylen) {
-               DEBUG_ERR("%s non clear key ecc token: invalid key len %u\n",
-                         __func__, t->len);
+               PKEY_DBF_ERR("%s non clear key ecc token: invalid key len %u\n",
+                            __func__, t->len);
                return -EINVAL;
        }
 
@@ -551,8 +553,8 @@ static int nonccatokecc2pkey(const struct clearkeytoken *t,
        rc = pkey_clr2protkey(t->keytype, t->clearkey,
                              protkey, protkeylen, protkeytype);
        if (rc) {
-               DEBUG_ERR("%s unable to build protected key from clear",
-                         __func__);
+               PKEY_DBF_ERR("%s unable to build protected key from clear",
+                            __func__);
        }
 
        return rc;
@@ -604,15 +606,15 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
                                               protkeylen, protkeytype);
                        break;
                default:
-                       DEBUG_ERR("%s unknown/unsupported non cca clear key type %u\n",
-                                 __func__, t->keytype);
+                       PKEY_DBF_ERR("%s unknown/unsupported non cca clear key type %u\n",
+                                    __func__, t->keytype);
                        return -EINVAL;
                }
                break;
        }
        case TOKVER_EP11_AES: {
                /* check ep11 key for exportable as protected key */
-               rc = ep11_check_aes_key(debug_info, 3, key, keylen, 1);
+               rc = ep11_check_aes_key(pkey_dbf_info, 3, key, keylen, 1);
                if (rc)
                        goto out;
                rc = pkey_ep11key2pkey(key, keylen,
@@ -621,15 +623,16 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
        }
        case TOKVER_EP11_AES_WITH_HEADER:
                /* check ep11 key with header for exportable as protected key */
-               rc = ep11_check_aes_key_with_hdr(debug_info, 3, key, keylen, 1);
+               rc = ep11_check_aes_key_with_hdr(pkey_dbf_info,
+                                                3, key, keylen, 1);
                if (rc)
                        goto out;
                rc = pkey_ep11key2pkey(key, keylen,
                                       protkey, protkeylen, protkeytype);
                break;
        default:
-               DEBUG_ERR("%s unknown/unsupported non-CCA token version %d\n",
-                         __func__, hdr->version);
+               PKEY_DBF_ERR("%s unknown/unsupported non-CCA token version %d\n",
+                            __func__, hdr->version);
        }
 
 out:
@@ -654,8 +657,8 @@ static int pkey_ccainttok2pkey(const u8 *key, u32 keylen,
                        return -EINVAL;
                break;
        default:
-               DEBUG_ERR("%s unknown/unsupported CCA internal token version %d\n",
-                         __func__, hdr->version);
+               PKEY_DBF_ERR("%s unknown/unsupported CCA internal token version %d\n",
+                            __func__, hdr->version);
                return -EINVAL;
        }
 
@@ -672,7 +675,7 @@ int pkey_keyblob2pkey(const u8 *key, u32 keylen,
        int rc;
 
        if (keylen < sizeof(struct keytoken_header)) {
-               DEBUG_ERR("%s invalid keylen %d\n", __func__, keylen);
+               PKEY_DBF_ERR("%s invalid keylen %d\n", __func__, keylen);
                return -EINVAL;
        }
 
@@ -686,12 +689,12 @@ int pkey_keyblob2pkey(const u8 *key, u32 keylen,
                                         protkey, protkeylen, protkeytype);
                break;
        default:
-               DEBUG_ERR("%s unknown/unsupported blob type %d\n",
-                         __func__, hdr->type);
+               PKEY_DBF_ERR("%s unknown/unsupported blob type %d\n",
+                            __func__, hdr->type);
                return -EINVAL;
        }
 
-       DEBUG_DBG("%s rc=%d\n", __func__, rc);
+       pr_debug("%s rc=%d\n", __func__, rc);
        return rc;
 }
 EXPORT_SYMBOL(pkey_keyblob2pkey);
@@ -839,7 +842,7 @@ static int pkey_verifykey2(const u8 *key, size_t keylen,
            hdr->version == TOKVER_CCA_AES) {
                struct secaeskeytoken *t = (struct secaeskeytoken *)key;
 
-               rc = cca_check_secaeskeytoken(debug_info, 3, key, 0);
+               rc = cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0);
                if (rc)
                        goto out;
                if (ktype)
@@ -869,7 +872,7 @@ static int pkey_verifykey2(const u8 *key, size_t keylen,
                   hdr->version == TOKVER_CCA_VLSC) {
                struct cipherkeytoken *t = (struct cipherkeytoken *)key;
 
-               rc = cca_check_secaescipherkey(debug_info, 3, key, 0, 1);
+               rc = cca_check_secaescipherkey(pkey_dbf_info, 3, key, 0, 1);
                if (rc)
                        goto out;
                if (ktype)
@@ -907,7 +910,7 @@ static int pkey_verifykey2(const u8 *key, size_t keylen,
                struct ep11keyblob *kb = (struct ep11keyblob *)key;
                int api;
 
-               rc = ep11_check_aes_key(debug_info, 3, key, keylen, 1);
+               rc = ep11_check_aes_key(pkey_dbf_info, 3, key, keylen, 1);
                if (rc)
                        goto out;
                if (ktype)
@@ -933,8 +936,8 @@ static int pkey_verifykey2(const u8 *key, size_t keylen,
                struct ep11kblob_header *kh = (struct ep11kblob_header *)key;
                int api;
 
-               rc = ep11_check_aes_key_with_hdr(debug_info, 3,
-                                                key, keylen, 1);
+               rc = ep11_check_aes_key_with_hdr(pkey_dbf_info,
+                                                3, key, keylen, 1);
                if (rc)
                        goto out;
                if (ktype)
@@ -981,25 +984,27 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns,
                if (hdr->version == TOKVER_CCA_AES) {
                        if (keylen != sizeof(struct secaeskeytoken))
                                return -EINVAL;
-                       if (cca_check_secaeskeytoken(debug_info, 3, key, 0))
+                       if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0))
                                return -EINVAL;
                } else if (hdr->version == TOKVER_CCA_VLSC) {
                        if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE)
                                return -EINVAL;
-                       if (cca_check_secaescipherkey(debug_info, 3, key, 0, 1))
+                       if (cca_check_secaescipherkey(pkey_dbf_info,
+                                                     3, key, 0, 1))
                                return -EINVAL;
                } else {
-                       DEBUG_ERR("%s unknown CCA internal token version %d\n",
-                                 __func__, hdr->version);
+                       PKEY_DBF_ERR("%s unknown CCA internal token version %d\n",
+                                    __func__, hdr->version);
                        return -EINVAL;
                }
        } else if (hdr->type == TOKTYPE_NON_CCA) {
                if (hdr->version == TOKVER_EP11_AES) {
-                       if (ep11_check_aes_key(debug_info, 3, key, keylen, 1))
+                       if (ep11_check_aes_key(pkey_dbf_info,
+                                              3, key, keylen, 1))
                                return -EINVAL;
                } else if (hdr->version == TOKVER_EP11_AES_WITH_HEADER) {
-                       if (ep11_check_aes_key_with_hdr(debug_info, 3,
-                                                       key, keylen, 1))
+                       if (ep11_check_aes_key_with_hdr(pkey_dbf_info,
+                                                       3, key, keylen, 1))
                                return -EINVAL;
                } else {
                        return pkey_nonccatok2pkey(key, keylen,
@@ -1007,8 +1012,8 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns,
                                                   protkeytype);
                }
        } else {
-               DEBUG_ERR("%s unknown/unsupported blob type %d\n",
-                         __func__, hdr->type);
+               PKEY_DBF_ERR("%s unknown/unsupported blob type %d\n",
+                            __func__, hdr->type);
                return -EINVAL;
        }
 
@@ -1234,50 +1239,53 @@ static int pkey_keyblob2pkey3(const struct pkey_apqn *apqns, size_t nr_apqns,
            hdr->version == TOKVER_EP11_AES_WITH_HEADER &&
            is_ep11_keyblob(key + sizeof(struct ep11kblob_header))) {
                /* EP11 AES key blob with header */
-               if (ep11_check_aes_key_with_hdr(debug_info, 3, key, keylen, 1))
+               if (ep11_check_aes_key_with_hdr(pkey_dbf_info,
+                                               3, key, keylen, 1))
                        return -EINVAL;
        } else if (hdr->type == TOKTYPE_NON_CCA &&
                   hdr->version == TOKVER_EP11_ECC_WITH_HEADER &&
                   is_ep11_keyblob(key + sizeof(struct ep11kblob_header))) {
                /* EP11 ECC key blob with header */
-               if (ep11_check_ecc_key_with_hdr(debug_info, 3, key, keylen, 1))
+               if (ep11_check_ecc_key_with_hdr(pkey_dbf_info,
+                                               3, key, keylen, 1))
                        return -EINVAL;
        } else if (hdr->type == TOKTYPE_NON_CCA &&
                   hdr->version == TOKVER_EP11_AES &&
                   is_ep11_keyblob(key)) {
                /* EP11 AES key blob with header in session field */
-               if (ep11_check_aes_key(debug_info, 3, key, keylen, 1))
+               if (ep11_check_aes_key(pkey_dbf_info, 3, key, keylen, 1))
                        return -EINVAL;
        } else  if (hdr->type == TOKTYPE_CCA_INTERNAL) {
                if (hdr->version == TOKVER_CCA_AES) {
                        /* CCA AES data key */
                        if (keylen != sizeof(struct secaeskeytoken))
                                return -EINVAL;
-                       if (cca_check_secaeskeytoken(debug_info, 3, key, 0))
+                       if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0))
                                return -EINVAL;
                } else if (hdr->version == TOKVER_CCA_VLSC) {
                        /* CCA AES cipher key */
                        if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE)
                                return -EINVAL;
-                       if (cca_check_secaescipherkey(debug_info, 3, key, 0, 1))
+                       if (cca_check_secaescipherkey(pkey_dbf_info,
+                                                     3, key, 0, 1))
                                return -EINVAL;
                } else {
-                       DEBUG_ERR("%s unknown CCA internal token version %d\n",
-                                 __func__, hdr->version);
+                       PKEY_DBF_ERR("%s unknown CCA internal token version %d\n",
+                                    __func__, hdr->version);
                        return -EINVAL;
                }
        } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {
                /* CCA ECC (private) key */
                if (keylen < sizeof(struct eccprivkeytoken))
                        return -EINVAL;
-               if (cca_check_sececckeytoken(debug_info, 3, key, keylen, 1))
+               if (cca_check_sececckeytoken(pkey_dbf_info, 3, key, keylen, 1))
                        return -EINVAL;
        } else if (hdr->type == TOKTYPE_NON_CCA) {
                return pkey_nonccatok2pkey(key, keylen,
                                           protkey, protkeylen, protkeytype);
        } else {
-               DEBUG_ERR("%s unknown/unsupported blob type %d\n",
-                         __func__, hdr->type);
+               PKEY_DBF_ERR("%s unknown/unsupported blob type %d\n",
+                            __func__, hdr->type);
                return -EINVAL;
        }
 
@@ -1350,7 +1358,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                        return -EFAULT;
                rc = cca_genseckey(kgs.cardnr, kgs.domain,
                                   kgs.keytype, kgs.seckey.seckey);
-               DEBUG_DBG("%s cca_genseckey()=%d\n", __func__, rc);
+               pr_debug("%s cca_genseckey()=%d\n", __func__, rc);
                if (rc)
                        break;
                if (copy_to_user(ugs, &kgs, sizeof(kgs)))
@@ -1365,7 +1373,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                        return -EFAULT;
                rc = cca_clr2seckey(kcs.cardnr, kcs.domain, kcs.keytype,
                                    kcs.clrkey.clrkey, kcs.seckey.seckey);
-               DEBUG_DBG("%s cca_clr2seckey()=%d\n", __func__, rc);
+               pr_debug("%s cca_clr2seckey()=%d\n", __func__, rc);
                if (rc)
                        break;
                if (copy_to_user(ucs, &kcs, sizeof(kcs)))
@@ -1383,7 +1391,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                rc = cca_sec2protkey(ksp.cardnr, ksp.domain,
                                     ksp.seckey.seckey, ksp.protkey.protkey,
                                     &ksp.protkey.len, &ksp.protkey.type);
-               DEBUG_DBG("%s cca_sec2protkey()=%d\n", __func__, rc);
+               pr_debug("%s cca_sec2protkey()=%d\n", __func__, rc);
                if (rc)
                        break;
                if (copy_to_user(usp, &ksp, sizeof(ksp)))
@@ -1400,7 +1408,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                rc = pkey_clr2protkey(kcp.keytype, kcp.clrkey.clrkey,
                                      kcp.protkey.protkey,
                                      &kcp.protkey.len, &kcp.protkey.type);
-               DEBUG_DBG("%s pkey_clr2protkey()=%d\n", __func__, rc);
+               pr_debug("%s pkey_clr2protkey()=%d\n", __func__, rc);
                if (rc)
                        break;
                if (copy_to_user(ucp, &kcp, sizeof(kcp)))
@@ -1416,7 +1424,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                        return -EFAULT;
                rc = cca_findcard(kfc.seckey.seckey,
                                  &kfc.cardnr, &kfc.domain, 1);
-               DEBUG_DBG("%s cca_findcard()=%d\n", __func__, rc);
+               pr_debug("%s cca_findcard()=%d\n", __func__, rc);
                if (rc < 0)
                        break;
                if (copy_to_user(ufc, &kfc, sizeof(kfc)))
@@ -1432,7 +1440,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                ksp.protkey.len = sizeof(ksp.protkey.protkey);
                rc = pkey_skey2pkey(ksp.seckey.seckey, ksp.protkey.protkey,
                                    &ksp.protkey.len, &ksp.protkey.type);
-               DEBUG_DBG("%s pkey_skey2pkey()=%d\n", __func__, rc);
+               pr_debug("%s pkey_skey2pkey()=%d\n", __func__, rc);
                if (rc)
                        break;
                if (copy_to_user(usp, &ksp, sizeof(ksp)))
@@ -1447,7 +1455,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                        return -EFAULT;
                rc = pkey_verifykey(&kvk.seckey, &kvk.cardnr, &kvk.domain,
                                    &kvk.keysize, &kvk.attributes);
-               DEBUG_DBG("%s pkey_verifykey()=%d\n", __func__, rc);
+               pr_debug("%s pkey_verifykey()=%d\n", __func__, rc);
                if (rc)
                        break;
                if (copy_to_user(uvk, &kvk, sizeof(kvk)))
@@ -1463,7 +1471,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                kgp.protkey.len = sizeof(kgp.protkey.protkey);
                rc = pkey_genprotkey(kgp.keytype, kgp.protkey.protkey,
                                     &kgp.protkey.len, &kgp.protkey.type);
-               DEBUG_DBG("%s pkey_genprotkey()=%d\n", __func__, rc);
+               pr_debug("%s pkey_genprotkey()=%d\n", __func__, rc);
                if (rc)
                        break;
                if (copy_to_user(ugp, &kgp, sizeof(kgp)))
@@ -1478,7 +1486,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                        return -EFAULT;
                rc = pkey_verifyprotkey(kvp.protkey.protkey,
                                        kvp.protkey.len, kvp.protkey.type);
-               DEBUG_DBG("%s pkey_verifyprotkey()=%d\n", __func__, rc);
+               pr_debug("%s pkey_verifyprotkey()=%d\n", __func__, rc);
                break;
        }
        case PKEY_KBLOB2PROTK: {
@@ -1494,7 +1502,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                ktp.protkey.len = sizeof(ktp.protkey.protkey);
                rc = pkey_keyblob2pkey(kkey, ktp.keylen, ktp.protkey.protkey,
                                       &ktp.protkey.len, &ktp.protkey.type);
-               DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc);
+               pr_debug("%s pkey_keyblob2pkey()=%d\n", __func__, rc);
                memzero_explicit(kkey, ktp.keylen);
                kfree(kkey);
                if (rc)
@@ -1523,7 +1531,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                rc = pkey_genseckey2(apqns, kgs.apqn_entries,
                                     kgs.type, kgs.size, kgs.keygenflags,
                                     kkey, &klen);
-               DEBUG_DBG("%s pkey_genseckey2()=%d\n", __func__, rc);
+               pr_debug("%s pkey_genseckey2()=%d\n", __func__, rc);
                kfree(apqns);
                if (rc) {
                        kfree(kkey);
@@ -1565,7 +1573,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                rc = pkey_clr2seckey2(apqns, kcs.apqn_entries,
                                      kcs.type, kcs.size, kcs.keygenflags,
                                      kcs.clrkey.clrkey, kkey, &klen);
-               DEBUG_DBG("%s pkey_clr2seckey2()=%d\n", __func__, rc);
+               pr_debug("%s pkey_clr2seckey2()=%d\n", __func__, rc);
                kfree(apqns);
                if (rc) {
                        kfree(kkey);
@@ -1601,7 +1609,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                rc = pkey_verifykey2(kkey, kvk.keylen,
                                     &kvk.cardnr, &kvk.domain,
                                     &kvk.type, &kvk.size, &kvk.flags);
-               DEBUG_DBG("%s pkey_verifykey2()=%d\n", __func__, rc);
+               pr_debug("%s pkey_verifykey2()=%d\n", __func__, rc);
                kfree(kkey);
                if (rc)
                        break;
@@ -1630,7 +1638,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                                        kkey, ktp.keylen,
                                        ktp.protkey.protkey, &ktp.protkey.len,
                                        &ktp.protkey.type);
-               DEBUG_DBG("%s pkey_keyblob2pkey2()=%d\n", __func__, rc);
+               pr_debug("%s pkey_keyblob2pkey2()=%d\n", __func__, rc);
                kfree(apqns);
                memzero_explicit(kkey, ktp.keylen);
                kfree(kkey);
@@ -1664,7 +1672,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                }
                rc = pkey_apqns4key(kkey, kak.keylen, kak.flags,
                                    apqns, &nr_apqns);
-               DEBUG_DBG("%s pkey_apqns4key()=%d\n", __func__, rc);
+               pr_debug("%s pkey_apqns4key()=%d\n", __func__, rc);
                kfree(kkey);
                if (rc && rc != -ENOSPC) {
                        kfree(apqns);
@@ -1707,7 +1715,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                }
                rc = pkey_apqns4keytype(kat.type, kat.cur_mkvp, kat.alt_mkvp,
                                        kat.flags, apqns, &nr_apqns);
-               DEBUG_DBG("%s pkey_apqns4keytype()=%d\n", __func__, rc);
+               pr_debug("%s pkey_apqns4keytype()=%d\n", __func__, rc);
                if (rc && rc != -ENOSPC) {
                        kfree(apqns);
                        break;
@@ -1757,7 +1765,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                rc = pkey_keyblob2pkey3(apqns, ktp.apqn_entries,
                                        kkey, ktp.keylen,
                                        protkey, &protkeylen, &ktp.pkeytype);
-               DEBUG_DBG("%s pkey_keyblob2pkey3()=%d\n", __func__, rc);
+               pr_debug("%s pkey_keyblob2pkey3()=%d\n", __func__, rc);
                kfree(apqns);
                memzero_explicit(kkey, ktp.keylen);
                kfree(kkey);
index a5ab03e42ff1ccf08428c851abdd552e30bcf57f..4aeb3e1213c773a05b54321e7e348cd54376afad 100644 (file)
@@ -60,7 +60,7 @@ static void vfio_ap_matrix_dev_release(struct device *dev)
        kfree(matrix_dev);
 }
 
-static struct bus_type matrix_bus = {
+static const struct bus_type matrix_bus = {
        .name = "matrix",
 };
 
index 983b3b16196c6b7638e023f121e5c937c83ce150..fc169bc61593955525368f56f5eb1bf3caa414b7 100644 (file)
@@ -659,6 +659,21 @@ static bool vfio_ap_mdev_filter_cdoms(struct ap_matrix_mdev *matrix_mdev)
                             AP_DOMAINS);
 }
 
+static bool _queue_passable(struct vfio_ap_queue *q)
+{
+       if (!q)
+               return false;
+
+       switch (q->reset_status.response_code) {
+       case AP_RESPONSE_NORMAL:
+       case AP_RESPONSE_DECONFIGURED:
+       case AP_RESPONSE_CHECKSTOPPED:
+               return true;
+       default:
+               return false;
+       }
+}
+
 /*
  * vfio_ap_mdev_filter_matrix - filter the APQNs assigned to the matrix mdev
  *                             to ensure no queue devices are passed through to
@@ -687,7 +702,6 @@ static bool vfio_ap_mdev_filter_matrix(struct ap_matrix_mdev *matrix_mdev,
        unsigned long apid, apqi, apqn;
        DECLARE_BITMAP(prev_shadow_apm, AP_DEVICES);
        DECLARE_BITMAP(prev_shadow_aqm, AP_DOMAINS);
-       struct vfio_ap_queue *q;
 
        bitmap_copy(prev_shadow_apm, matrix_mdev->shadow_apcb.apm, AP_DEVICES);
        bitmap_copy(prev_shadow_aqm, matrix_mdev->shadow_apcb.aqm, AP_DOMAINS);
@@ -716,8 +730,7 @@ static bool vfio_ap_mdev_filter_matrix(struct ap_matrix_mdev *matrix_mdev,
                         * hardware device.
                         */
                        apqn = AP_MKQID(apid, apqi);
-                       q = vfio_ap_mdev_get_queue(matrix_mdev, apqn);
-                       if (!q || q->reset_status.response_code) {
+                       if (!_queue_passable(vfio_ap_mdev_get_queue(matrix_mdev, apqn))) {
                                clear_bit_inv(apid, matrix_mdev->shadow_apcb.apm);
 
                                /*
@@ -1691,6 +1704,7 @@ static int apq_status_check(int apqn, struct ap_queue_status *status)
        switch (status->response_code) {
        case AP_RESPONSE_NORMAL:
        case AP_RESPONSE_DECONFIGURED:
+       case AP_RESPONSE_CHECKSTOPPED:
                return 0;
        case AP_RESPONSE_RESET_IN_PROGRESS:
        case AP_RESPONSE_BUSY:
@@ -1747,14 +1761,6 @@ static void apq_reset_check(struct work_struct *reset_work)
                                memcpy(&q->reset_status, &status, sizeof(status));
                                continue;
                        }
-                       /*
-                        * When an AP adapter is deconfigured, the
-                        * associated queues are reset, so let's set the
-                        * status response code to 0 so the queue may be
-                        * passed through (i.e., not filtered)
-                        */
-                       if (status.response_code == AP_RESPONSE_DECONFIGURED)
-                               q->reset_status.response_code = 0;
                        if (q->saved_isc != VFIO_AP_ISC_INVALID)
                                vfio_ap_free_aqic_resources(q);
                        break;
@@ -1781,12 +1787,7 @@ static void vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q)
                queue_work(system_long_wq, &q->reset_work);
                break;
        case AP_RESPONSE_DECONFIGURED:
-               /*
-                * When an AP adapter is deconfigured, the associated
-                * queues are reset, so let's set the status response code to 0
-                * so the queue may be passed through (i.e., not filtered).
-                */
-               q->reset_status.response_code = 0;
+       case AP_RESPONSE_CHECKSTOPPED:
                vfio_ap_free_aqic_resources(q);
                break;
        default:
index 74200f54dfff78b12b60819879ec67a5fec5d194..02c503f16bc2dbd28828910db992fc1f5e6a9cbc 100644 (file)
@@ -12,6 +12,9 @@
  *  Multiple device nodes: Harald Freudenberger <freude@linux.ibm.com>
  */
 
+#define KMSG_COMPONENT "zcrypt"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -57,10 +60,6 @@ DEFINE_SPINLOCK(zcrypt_list_lock);
 LIST_HEAD(zcrypt_card_list);
 
 static atomic_t zcrypt_open_count = ATOMIC_INIT(0);
-static atomic_t zcrypt_rescan_count = ATOMIC_INIT(0);
-
-atomic_t zcrypt_rescan_req = ATOMIC_INIT(0);
-EXPORT_SYMBOL(zcrypt_rescan_req);
 
 static LIST_HEAD(zcrypt_ops_list);
 
@@ -69,20 +68,15 @@ debug_info_t *zcrypt_dbf_info;
 
 /*
  * Process a rescan of the transport layer.
- *
- * Returns 1, if the rescan has been processed, otherwise 0.
+ * Runs a synchronous AP bus rescan.
+ * Returns true if something has changed (for example the
+ * bus scan has found and build up new devices) and it is
+ * worth to do a retry. Otherwise false is returned meaning
+ * no changes on the AP bus level.
  */
-static inline int zcrypt_process_rescan(void)
-{
-       if (atomic_read(&zcrypt_rescan_req)) {
-               atomic_set(&zcrypt_rescan_req, 0);
-               atomic_inc(&zcrypt_rescan_count);
-               ap_bus_force_rescan();
-               ZCRYPT_DBF_INFO("%s rescan count=%07d\n", __func__,
-                               atomic_inc_return(&zcrypt_rescan_count));
-               return 1;
-       }
-       return 0;
+static inline bool zcrypt_process_rescan(void)
+{
+       return ap_bus_force_rescan();
 }
 
 void zcrypt_msgtype_register(struct zcrypt_ops *zops)
@@ -715,8 +709,7 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms,
        spin_unlock(&zcrypt_list_lock);
 
        if (!pref_zq) {
-               ZCRYPT_DBF_DBG("%s no matching queue found => ENODEV\n",
-                              __func__);
+               pr_debug("%s no matching queue found => ENODEV\n", __func__);
                rc = -ENODEV;
                goto out;
        }
@@ -820,8 +813,7 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
        spin_unlock(&zcrypt_list_lock);
 
        if (!pref_zq) {
-               ZCRYPT_DBF_DBG("%s no matching queue found => ENODEV\n",
-                              __func__);
+               pr_debug("%s no matching queue found => ENODEV\n", __func__);
                rc = -ENODEV;
                goto out;
        }
@@ -865,6 +857,8 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
        rc = prep_cca_ap_msg(userspace, xcrb, &ap_msg, &func_code, &domain);
        if (rc)
                goto out;
+       print_hex_dump_debug("ccareq: ", DUMP_PREFIX_ADDRESS, 16, 1,
+                            ap_msg.msg, ap_msg.len, false);
 
        tdom = *domain;
        if (perms != &ap_perms && tdom < AP_DOMAINS) {
@@ -940,8 +934,8 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
        spin_unlock(&zcrypt_list_lock);
 
        if (!pref_zq) {
-               ZCRYPT_DBF_DBG("%s no match for address %02x.%04x => ENODEV\n",
-                              __func__, xcrb->user_defined, *domain);
+               pr_debug("%s no match for address %02x.%04x => ENODEV\n",
+                        __func__, xcrb->user_defined, *domain);
                rc = -ENODEV;
                goto out;
        }
@@ -952,6 +946,10 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
                *domain = AP_QID_QUEUE(qid);
 
        rc = pref_zq->ops->send_cprb(userspace, pref_zq, xcrb, &ap_msg);
+       if (!rc) {
+               print_hex_dump_debug("ccarpl: ", DUMP_PREFIX_ADDRESS, 16, 1,
+                                    ap_msg.msg, ap_msg.len, false);
+       }
 
        spin_lock(&zcrypt_list_lock);
        zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
@@ -970,7 +968,26 @@ out:
 
 long zcrypt_send_cprb(struct ica_xcRB *xcrb)
 {
-       return _zcrypt_send_cprb(false, &ap_perms, NULL, xcrb);
+       struct zcrypt_track tr;
+       int rc;
+
+       memset(&tr, 0, sizeof(tr));
+
+       do {
+               rc = _zcrypt_send_cprb(false, &ap_perms, &tr, xcrb);
+       } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
+
+       /* on ENODEV failure: retry once again after a requested rescan */
+       if (rc == -ENODEV && zcrypt_process_rescan())
+               do {
+                       rc = _zcrypt_send_cprb(false, &ap_perms, &tr, xcrb);
+               } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
+       if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
+               rc = -EIO;
+       if (rc)
+               pr_debug("%s rc=%d\n", __func__, rc);
+
+       return rc;
 }
 EXPORT_SYMBOL(zcrypt_send_cprb);
 
@@ -1045,6 +1062,8 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
        rc = prep_ep11_ap_msg(userspace, xcrb, &ap_msg, &func_code, &domain);
        if (rc)
                goto out_free;
+       print_hex_dump_debug("ep11req: ", DUMP_PREFIX_ADDRESS, 16, 1,
+                            ap_msg.msg, ap_msg.len, false);
 
        if (perms != &ap_perms && domain < AUTOSEL_DOM) {
                if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
@@ -1113,15 +1132,15 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
 
        if (!pref_zq) {
                if (targets && target_num == 1) {
-                       ZCRYPT_DBF_DBG("%s no match for address %02x.%04x => ENODEV\n",
-                                      __func__, (int)targets->ap_id,
-                                      (int)targets->dom_id);
+                       pr_debug("%s no match for address %02x.%04x => ENODEV\n",
+                                __func__, (int)targets->ap_id,
+                                (int)targets->dom_id);
                } else if (targets) {
-                       ZCRYPT_DBF_DBG("%s no match for %d target addrs => ENODEV\n",
-                                      __func__, (int)target_num);
+                       pr_debug("%s no match for %d target addrs => ENODEV\n",
+                                __func__, (int)target_num);
                } else {
-                       ZCRYPT_DBF_DBG("%s no match for address ff.ffff => ENODEV\n",
-                                      __func__);
+                       pr_debug("%s no match for address ff.ffff => ENODEV\n",
+                                __func__);
                }
                rc = -ENODEV;
                goto out_free;
@@ -1129,6 +1148,10 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
 
        qid = pref_zq->queue->qid;
        rc = pref_zq->ops->send_ep11_cprb(userspace, pref_zq, xcrb, &ap_msg);
+       if (!rc) {
+               print_hex_dump_debug("ep11rpl: ", DUMP_PREFIX_ADDRESS, 16, 1,
+                                    ap_msg.msg, ap_msg.len, false);
+       }
 
        spin_lock(&zcrypt_list_lock);
        zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
@@ -1149,7 +1172,26 @@ out:
 
 long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
 {
-       return _zcrypt_send_ep11_cprb(false, &ap_perms, NULL, xcrb);
+       struct zcrypt_track tr;
+       int rc;
+
+       memset(&tr, 0, sizeof(tr));
+
+       do {
+               rc = _zcrypt_send_ep11_cprb(false, &ap_perms, &tr, xcrb);
+       } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
+
+       /* on ENODEV failure: retry once again after a requested rescan */
+       if (rc == -ENODEV && zcrypt_process_rescan())
+               do {
+                       rc = _zcrypt_send_ep11_cprb(false, &ap_perms, &tr, xcrb);
+               } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
+       if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
+               rc = -EIO;
+       if (rc)
+               pr_debug("%s rc=%d\n", __func__, rc);
+
+       return rc;
 }
 EXPORT_SYMBOL(zcrypt_send_ep11_cprb);
 
@@ -1199,8 +1241,7 @@ static long zcrypt_rng(char *buffer)
        spin_unlock(&zcrypt_list_lock);
 
        if (!pref_zq) {
-               ZCRYPT_DBF_DBG("%s no matching queue found => ENODEV\n",
-                              __func__);
+               pr_debug("%s no matching queue found => ENODEV\n", __func__);
                rc = -ENODEV;
                goto out;
        }
@@ -1431,20 +1472,17 @@ static int icarsamodexpo_ioctl(struct ap_perms *perms, unsigned long arg)
 
        do {
                rc = zcrypt_rsa_modexpo(perms, &tr, &mex);
-               if (rc == -EAGAIN)
-                       tr.again_counter++;
-       } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
-       /* on failure: retry once again after a requested rescan */
-       if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+       } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
+
+       /* on ENODEV failure: retry once again after a requested rescan */
+       if (rc == -ENODEV && zcrypt_process_rescan())
                do {
                        rc = zcrypt_rsa_modexpo(perms, &tr, &mex);
-                       if (rc == -EAGAIN)
-                               tr.again_counter++;
-               } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
+               } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
        if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
                rc = -EIO;
        if (rc) {
-               ZCRYPT_DBF_DBG("ioctl ICARSAMODEXPO rc=%d\n", rc);
+               pr_debug("ioctl ICARSAMODEXPO rc=%d\n", rc);
                return rc;
        }
        return put_user(mex.outputdatalength, &umex->outputdatalength);
@@ -1463,20 +1501,17 @@ static int icarsacrt_ioctl(struct ap_perms *perms, unsigned long arg)
 
        do {
                rc = zcrypt_rsa_crt(perms, &tr, &crt);
-               if (rc == -EAGAIN)
-                       tr.again_counter++;
-       } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
-       /* on failure: retry once again after a requested rescan */
-       if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+       } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
+
+       /* on ENODEV failure: retry once again after a requested rescan */
+       if (rc == -ENODEV && zcrypt_process_rescan())
                do {
                        rc = zcrypt_rsa_crt(perms, &tr, &crt);
-                       if (rc == -EAGAIN)
-                               tr.again_counter++;
-               } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
+               } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
        if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
                rc = -EIO;
        if (rc) {
-               ZCRYPT_DBF_DBG("ioctl ICARSACRT rc=%d\n", rc);
+               pr_debug("ioctl ICARSACRT rc=%d\n", rc);
                return rc;
        }
        return put_user(crt.outputdatalength, &ucrt->outputdatalength);
@@ -1495,21 +1530,18 @@ static int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg)
 
        do {
                rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb);
-               if (rc == -EAGAIN)
-                       tr.again_counter++;
-       } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
-       /* on failure: retry once again after a requested rescan */
-       if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+       } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
+
+       /* on ENODEV failure: retry once again after a requested rescan */
+       if (rc == -ENODEV && zcrypt_process_rescan())
                do {
                        rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb);
-                       if (rc == -EAGAIN)
-                               tr.again_counter++;
-               } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
+               } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
        if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
                rc = -EIO;
        if (rc)
-               ZCRYPT_DBF_DBG("ioctl ZSENDCPRB rc=%d status=0x%x\n",
-                              rc, xcrb.status);
+               pr_debug("ioctl ZSENDCPRB rc=%d status=0x%x\n",
+                        rc, xcrb.status);
        if (copy_to_user(uxcrb, &xcrb, sizeof(xcrb)))
                return -EFAULT;
        return rc;
@@ -1528,20 +1560,17 @@ static int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg)
 
        do {
                rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb);
-               if (rc == -EAGAIN)
-                       tr.again_counter++;
-       } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
-       /* on failure: retry once again after a requested rescan */
-       if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+       } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
+
+       /* on ENODEV failure: retry once again after a requested rescan */
+       if (rc == -ENODEV && zcrypt_process_rescan())
                do {
                        rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb);
-                       if (rc == -EAGAIN)
-                               tr.again_counter++;
-               } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
+               } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
        if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
                rc = -EIO;
        if (rc)
-               ZCRYPT_DBF_DBG("ioctl ZSENDEP11CPRB rc=%d\n", rc);
+               pr_debug("ioctl ZSENDEP11CPRB rc=%d\n", rc);
        if (copy_to_user(uxcrb, &xcrb, sizeof(xcrb)))
                return -EFAULT;
        return rc;
@@ -1670,7 +1699,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
        }
        /* unknown ioctl number */
        default:
-               ZCRYPT_DBF_DBG("unknown ioctl 0x%08x\n", cmd);
+               pr_debug("unknown ioctl 0x%08x\n", cmd);
                return -ENOIOCTLCMD;
        }
 }
@@ -1708,16 +1737,13 @@ static long trans_modexpo32(struct ap_perms *perms, struct file *filp,
        mex64.n_modulus = compat_ptr(mex32.n_modulus);
        do {
                rc = zcrypt_rsa_modexpo(perms, &tr, &mex64);
-               if (rc == -EAGAIN)
-                       tr.again_counter++;
-       } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
-       /* on failure: retry once again after a requested rescan */
-       if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+       } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
+
+       /* on ENODEV failure: retry once again after a requested rescan */
+       if (rc == -ENODEV && zcrypt_process_rescan())
                do {
                        rc = zcrypt_rsa_modexpo(perms, &tr, &mex64);
-                       if (rc == -EAGAIN)
-                               tr.again_counter++;
-               } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
+               } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
        if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
                rc = -EIO;
        if (rc)
@@ -1761,16 +1787,13 @@ static long trans_modexpo_crt32(struct ap_perms *perms, struct file *filp,
        crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv);
        do {
                rc = zcrypt_rsa_crt(perms, &tr, &crt64);
-               if (rc == -EAGAIN)
-                       tr.again_counter++;
-       } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
-       /* on failure: retry once again after a requested rescan */
-       if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+       } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
+
+       /* on ENODEV failure: retry once again after a requested rescan */
+       if (rc == -ENODEV && zcrypt_process_rescan())
                do {
                        rc = zcrypt_rsa_crt(perms, &tr, &crt64);
-                       if (rc == -EAGAIN)
-                               tr.again_counter++;
-               } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
+               } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
        if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
                rc = -EIO;
        if (rc)
@@ -1833,16 +1856,13 @@ static long trans_xcrb32(struct ap_perms *perms, struct file *filp,
        xcrb64.status = xcrb32.status;
        do {
                rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb64);
-               if (rc == -EAGAIN)
-                       tr.again_counter++;
-       } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
-       /* on failure: retry once again after a requested rescan */
-       if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+       } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
+
+       /* on ENODEV failure: retry once again after a requested rescan */
+       if (rc == -ENODEV && zcrypt_process_rescan())
                do {
                        rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb64);
-                       if (rc == -EAGAIN)
-                               tr.again_counter++;
-               } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
+               } while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
        if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
                rc = -EIO;
        xcrb32.reply_control_blk_length = xcrb64.reply_control_blk_length;
@@ -1914,8 +1934,8 @@ static int zcrypt_rng_data_read(struct hwrng *rng, u32 *data)
         */
        if (zcrypt_rng_buffer_index == 0) {
                rc = zcrypt_rng((char *)zcrypt_rng_buffer);
-               /* on failure: retry once again after a requested rescan */
-               if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+               /* on ENODEV failure: retry once again after an AP bus rescan */
+               if (rc == -ENODEV && zcrypt_process_rescan())
                        rc = zcrypt_rng((char *)zcrypt_rng_buffer);
                if (rc < 0)
                        return -EIO;
@@ -1977,7 +1997,7 @@ void zcrypt_rng_device_remove(void)
  * an asynchronous job. This function waits until these initial jobs
  * are done and so the zcrypt api should be ready to serve crypto
  * requests - if there are resources available. The function uses an
- * internal timeout of 60s. The very first caller will either wait for
+ * internal timeout of 30s. The very first caller will either wait for
  * ap bus bindings complete or the timeout happens. This state will be
  * remembered for further callers which will only be blocked until a
  * decision is made (timeout or bindings complete).
@@ -1996,8 +2016,8 @@ int zcrypt_wait_api_operational(void)
        switch (zcrypt_wait_api_state) {
        case 0:
                /* initial state, invoke wait for the ap bus complete */
-               rc = ap_wait_init_apqn_bindings_complete(
-                       msecs_to_jiffies(60 * 1000));
+               rc = ap_wait_apqn_bindings_complete(
+                       msecs_to_jiffies(ZCRYPT_WAIT_BINDINGS_COMPLETE_MS));
                switch (rc) {
                case 0:
                        /* ap bus bindings are complete */
@@ -2014,8 +2034,8 @@ int zcrypt_wait_api_operational(void)
                        break;
                default:
                        /* other failure */
-                       ZCRYPT_DBF_DBG("%s ap_wait_init_apqn_bindings_complete()=%d\n",
-                                      __func__, rc);
+                       pr_debug("%s ap_wait_init_apqn_bindings_complete()=%d\n",
+                                __func__, rc);
                        break;
                }
                break;
@@ -2038,7 +2058,7 @@ EXPORT_SYMBOL(zcrypt_wait_api_operational);
 int __init zcrypt_debug_init(void)
 {
        zcrypt_dbf_info = debug_register("zcrypt", 2, 1,
-                                        DBF_MAX_SPRINTF_ARGS * sizeof(long));
+                                        ZCRYPT_DBF_MAX_SPRINTF_ARGS * sizeof(long));
        debug_register_view(zcrypt_dbf_info, &debug_sprintf_view);
        debug_set_level(zcrypt_dbf_info, DBF_ERR);
 
index de659954c8f7d21035213ecd42c4e97f9cac8e34..4ed481df57ca4addaf914204bbeb17f54993c58b 100644 (file)
  */
 #define ZCRYPT_RNG_BUFFER_SIZE 4096
 
+/**
+ * The zcrypt_wait_api_operational() function waits this
+ * amount in milliseconds for ap_wait_aqpn_bindings_complete().
+ * Also on a cprb send failure with ENODEV the send functions
+ * trigger an ap bus rescan and wait this time in milliseconds
+ * for ap_wait_aqpn_bindings_complete() before resending.
+ */
+#define ZCRYPT_WAIT_BINDINGS_COMPLETE_MS 30000
+
 /*
  * Identifier for Crypto Request Performance Index
  */
index 263fe182648b8427ea7c7f89c92bf3ef15918ef2..0a3a678ffc7eedb237f3bc72e21ffe4c076c1444 100644 (file)
 #include "zcrypt_msgtype6.h"
 #include "zcrypt_ccamisc.h"
 
-#define DEBUG_DBG(...) ZCRYPT_DBF(DBF_DEBUG, ##__VA_ARGS__)
-#define DEBUG_INFO(...) ZCRYPT_DBF(DBF_INFO, ##__VA_ARGS__)
-#define DEBUG_WARN(...) ZCRYPT_DBF(DBF_WARN, ##__VA_ARGS__)
-#define DEBUG_ERR(...) ZCRYPT_DBF(DBF_ERR, ##__VA_ARGS__)
-
 /* Size of parameter block used for all cca requests/replies */
 #define PARMBSIZE 512
 
@@ -367,8 +362,8 @@ int cca_genseckey(u16 cardnr, u16 domain,
                memcpy(preqparm->lv1.key_length, "KEYLN32 ", 8);
                break;
        default:
-               DEBUG_ERR("%s unknown/unsupported keybitsize %d\n",
-                         __func__, keybitsize);
+               ZCRYPT_DBF_ERR("%s unknown/unsupported keybitsize %d\n",
+                              __func__, keybitsize);
                rc = -EINVAL;
                goto out;
        }
@@ -386,15 +381,15 @@ int cca_genseckey(u16 cardnr, u16 domain,
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
        rc = zcrypt_send_cprb(&xcrb);
        if (rc) {
-               DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, errno %d\n",
-                         __func__, (int)cardnr, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, errno %d\n",
+                              __func__, (int)cardnr, (int)domain, rc);
                goto out;
        }
 
        /* check response returncode and reasoncode */
        if (prepcblk->ccp_rtcode != 0) {
-               DEBUG_ERR("%s secure key generate failure, card response %d/%d\n",
-                         __func__,
+               ZCRYPT_DBF_ERR("%s secure key generate failure, card response %d/%d\n",
+                              __func__,
                          (int)prepcblk->ccp_rtcode,
                          (int)prepcblk->ccp_rscode);
                rc = -EIO;
@@ -411,8 +406,8 @@ int cca_genseckey(u16 cardnr, u16 domain,
                - sizeof(prepparm->lv3.keyblock.toklen)
                - sizeof(prepparm->lv3.keyblock.tokattr);
        if (seckeysize != SECKEYBLOBSIZE) {
-               DEBUG_ERR("%s secure token size mismatch %d != %d bytes\n",
-                         __func__, seckeysize, SECKEYBLOBSIZE);
+               ZCRYPT_DBF_ERR("%s secure token size mismatch %d != %d bytes\n",
+                              __func__, seckeysize, SECKEYBLOBSIZE);
                rc = -EIO;
                goto out;
        }
@@ -505,8 +500,8 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
                keysize = 32;
                break;
        default:
-               DEBUG_ERR("%s unknown/unsupported keybitsize %d\n",
-                         __func__, keybitsize);
+               ZCRYPT_DBF_ERR("%s unknown/unsupported keybitsize %d\n",
+                              __func__, keybitsize);
                rc = -EINVAL;
                goto out;
        }
@@ -524,17 +519,17 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
        rc = zcrypt_send_cprb(&xcrb);
        if (rc) {
-               DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
-                         __func__, (int)cardnr, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
+                              __func__, (int)cardnr, (int)domain, rc);
                goto out;
        }
 
        /* check response returncode and reasoncode */
        if (prepcblk->ccp_rtcode != 0) {
-               DEBUG_ERR("%s clear key import failure, card response %d/%d\n",
-                         __func__,
-                         (int)prepcblk->ccp_rtcode,
-                         (int)prepcblk->ccp_rscode);
+               ZCRYPT_DBF_ERR("%s clear key import failure, card response %d/%d\n",
+                              __func__,
+                              (int)prepcblk->ccp_rtcode,
+                              (int)prepcblk->ccp_rscode);
                rc = -EIO;
                goto out;
        }
@@ -549,8 +544,8 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
                - sizeof(prepparm->lv3.keyblock.toklen)
                - sizeof(prepparm->lv3.keyblock.tokattr);
        if (seckeysize != SECKEYBLOBSIZE) {
-               DEBUG_ERR("%s secure token size mismatch %d != %d bytes\n",
-                         __func__, seckeysize, SECKEYBLOBSIZE);
+               ZCRYPT_DBF_ERR("%s secure token size mismatch %d != %d bytes\n",
+                              __func__, seckeysize, SECKEYBLOBSIZE);
                rc = -EIO;
                goto out;
        }
@@ -651,17 +646,17 @@ int cca_sec2protkey(u16 cardnr, u16 domain,
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
        rc = zcrypt_send_cprb(&xcrb);
        if (rc) {
-               DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
-                         __func__, (int)cardnr, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
+                              __func__, (int)cardnr, (int)domain, rc);
                goto out;
        }
 
        /* check response returncode and reasoncode */
        if (prepcblk->ccp_rtcode != 0) {
-               DEBUG_ERR("%s unwrap secure key failure, card response %d/%d\n",
-                         __func__,
-                         (int)prepcblk->ccp_rtcode,
-                         (int)prepcblk->ccp_rscode);
+               ZCRYPT_DBF_ERR("%s unwrap secure key failure, card response %d/%d\n",
+                              __func__,
+                              (int)prepcblk->ccp_rtcode,
+                              (int)prepcblk->ccp_rscode);
                if (prepcblk->ccp_rtcode == 8 && prepcblk->ccp_rscode == 2290)
                        rc = -EAGAIN;
                else
@@ -669,10 +664,10 @@ int cca_sec2protkey(u16 cardnr, u16 domain,
                goto out;
        }
        if (prepcblk->ccp_rscode != 0) {
-               DEBUG_WARN("%s unwrap secure key warning, card response %d/%d\n",
-                          __func__,
-                          (int)prepcblk->ccp_rtcode,
-                          (int)prepcblk->ccp_rscode);
+               ZCRYPT_DBF_WARN("%s unwrap secure key warning, card response %d/%d\n",
+                               __func__,
+                               (int)prepcblk->ccp_rtcode,
+                               (int)prepcblk->ccp_rscode);
        }
 
        /* process response cprb param block */
@@ -683,8 +678,8 @@ int cca_sec2protkey(u16 cardnr, u16 domain,
        /* check the returned keyblock */
        if (prepparm->lv3.ckb.version != 0x01 &&
            prepparm->lv3.ckb.version != 0x02) {
-               DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x\n",
-                         __func__, (int)prepparm->lv3.ckb.version);
+               ZCRYPT_DBF_ERR("%s reply param keyblock version mismatch 0x%02x\n",
+                              __func__, (int)prepparm->lv3.ckb.version);
                rc = -EIO;
                goto out;
        }
@@ -707,8 +702,8 @@ int cca_sec2protkey(u16 cardnr, u16 domain,
                        *protkeytype = PKEY_KEYTYPE_AES_256;
                break;
        default:
-               DEBUG_ERR("%s unknown/unsupported keylen %d\n",
-                         __func__, prepparm->lv3.ckb.len);
+               ZCRYPT_DBF_ERR("%s unknown/unsupported keylen %d\n",
+                              __func__, prepparm->lv3.ckb.len);
                rc = -EIO;
                goto out;
        }
@@ -840,9 +835,8 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
        case 256:
                break;
        default:
-               DEBUG_ERR(
-                       "%s unknown/unsupported keybitsize %d\n",
-                       __func__, keybitsize);
+               ZCRYPT_DBF_ERR("%s unknown/unsupported keybitsize %d\n",
+                              __func__, keybitsize);
                rc = -EINVAL;
                goto out;
        }
@@ -880,19 +874,17 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
        rc = zcrypt_send_cprb(&xcrb);
        if (rc) {
-               DEBUG_ERR(
-                       "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
-                       __func__, (int)cardnr, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
+                              __func__, (int)cardnr, (int)domain, rc);
                goto out;
        }
 
        /* check response returncode and reasoncode */
        if (prepcblk->ccp_rtcode != 0) {
-               DEBUG_ERR(
-                       "%s cipher key generate failure, card response %d/%d\n",
-                       __func__,
-                       (int)prepcblk->ccp_rtcode,
-                       (int)prepcblk->ccp_rscode);
+               ZCRYPT_DBF_ERR("%s cipher key generate failure, card response %d/%d\n",
+                              __func__,
+                              (int)prepcblk->ccp_rtcode,
+                              (int)prepcblk->ccp_rscode);
                rc = -EIO;
                goto out;
        }
@@ -905,8 +897,8 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
        /* do some plausibility checks on the key block */
        if (prepparm->kb.len < 120 + 5 * sizeof(uint16_t) ||
            prepparm->kb.len > 136 + 5 * sizeof(uint16_t)) {
-               DEBUG_ERR("%s reply with invalid or unknown key block\n",
-                         __func__);
+               ZCRYPT_DBF_ERR("%s reply with invalid or unknown key block\n",
+                              __func__);
                rc = -EIO;
                goto out;
        }
@@ -1048,19 +1040,17 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
        rc = zcrypt_send_cprb(&xcrb);
        if (rc) {
-               DEBUG_ERR(
-                       "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
-                       __func__, (int)cardnr, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
+                              __func__, (int)cardnr, (int)domain, rc);
                goto out;
        }
 
        /* check response returncode and reasoncode */
        if (prepcblk->ccp_rtcode != 0) {
-               DEBUG_ERR(
-                       "%s CSNBKPI2 failure, card response %d/%d\n",
-                       __func__,
-                       (int)prepcblk->ccp_rtcode,
-                       (int)prepcblk->ccp_rscode);
+               ZCRYPT_DBF_ERR("%s CSNBKPI2 failure, card response %d/%d\n",
+                              __func__,
+                              (int)prepcblk->ccp_rtcode,
+                              (int)prepcblk->ccp_rscode);
                rc = -EIO;
                goto out;
        }
@@ -1073,8 +1063,8 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
        /* do some plausibility checks on the key block */
        if (prepparm->kb.len < 120 + 3 * sizeof(uint16_t) ||
            prepparm->kb.len > 136 + 3 * sizeof(uint16_t)) {
-               DEBUG_ERR("%s reply with invalid or unknown key block\n",
-                         __func__);
+               ZCRYPT_DBF_ERR("%s reply with invalid or unknown key block\n",
+                              __func__);
                rc = -EIO;
                goto out;
        }
@@ -1132,33 +1122,29 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
        rc = _ip_cprb_helper(card, dom, "AES     ", "FIRST   ", "MIN3PART",
                             exorbuf, keybitsize, token, &tokensize);
        if (rc) {
-               DEBUG_ERR(
-                       "%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n",
-                       __func__, rc);
+               ZCRYPT_DBF_ERR("%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n",
+                              __func__, rc);
                goto out;
        }
        rc = _ip_cprb_helper(card, dom, "AES     ", "ADD-PART", NULL,
                             clrkey, keybitsize, token, &tokensize);
        if (rc) {
-               DEBUG_ERR(
-                       "%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n",
-                       __func__, rc);
+               ZCRYPT_DBF_ERR("%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n",
+                              __func__, rc);
                goto out;
        }
        rc = _ip_cprb_helper(card, dom, "AES     ", "ADD-PART", NULL,
                             exorbuf, keybitsize, token, &tokensize);
        if (rc) {
-               DEBUG_ERR(
-                       "%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n",
-                       __func__, rc);
+               ZCRYPT_DBF_ERR("%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n",
+                              __func__, rc);
                goto out;
        }
        rc = _ip_cprb_helper(card, dom, "AES     ", "COMPLETE", NULL,
                             NULL, keybitsize, token, &tokensize);
        if (rc) {
-               DEBUG_ERR(
-                       "%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n",
-                       __func__, rc);
+               ZCRYPT_DBF_ERR("%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n",
+                              __func__, rc);
                goto out;
        }
 
@@ -1265,19 +1251,17 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
        rc = zcrypt_send_cprb(&xcrb);
        if (rc) {
-               DEBUG_ERR(
-                       "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
-                       __func__, (int)cardnr, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
+                              __func__, (int)cardnr, (int)domain, rc);
                goto out;
        }
 
        /* check response returncode and reasoncode */
        if (prepcblk->ccp_rtcode != 0) {
-               DEBUG_ERR(
-                       "%s unwrap secure key failure, card response %d/%d\n",
-                       __func__,
-                       (int)prepcblk->ccp_rtcode,
-                       (int)prepcblk->ccp_rscode);
+               ZCRYPT_DBF_ERR("%s unwrap secure key failure, card response %d/%d\n",
+                              __func__,
+                              (int)prepcblk->ccp_rtcode,
+                              (int)prepcblk->ccp_rscode);
                if (prepcblk->ccp_rtcode == 8 && prepcblk->ccp_rscode == 2290)
                        rc = -EAGAIN;
                else
@@ -1285,11 +1269,10 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
                goto out;
        }
        if (prepcblk->ccp_rscode != 0) {
-               DEBUG_WARN(
-                       "%s unwrap secure key warning, card response %d/%d\n",
-                       __func__,
-                       (int)prepcblk->ccp_rtcode,
-                       (int)prepcblk->ccp_rscode);
+               ZCRYPT_DBF_WARN("%s unwrap secure key warning, card response %d/%d\n",
+                               __func__,
+                               (int)prepcblk->ccp_rtcode,
+                               (int)prepcblk->ccp_rscode);
        }
 
        /* process response cprb param block */
@@ -1300,15 +1283,14 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
        /* check the returned keyblock */
        if (prepparm->vud.ckb.version != 0x01 &&
            prepparm->vud.ckb.version != 0x02) {
-               DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x\n",
-                         __func__, (int)prepparm->vud.ckb.version);
+               ZCRYPT_DBF_ERR("%s reply param keyblock version mismatch 0x%02x\n",
+                              __func__, (int)prepparm->vud.ckb.version);
                rc = -EIO;
                goto out;
        }
        if (prepparm->vud.ckb.algo != 0x02) {
-               DEBUG_ERR(
-                       "%s reply param keyblock algo mismatch 0x%02x != 0x02\n",
-                       __func__, (int)prepparm->vud.ckb.algo);
+               ZCRYPT_DBF_ERR("%s reply param keyblock algo mismatch 0x%02x != 0x02\n",
+                              __func__, (int)prepparm->vud.ckb.algo);
                rc = -EIO;
                goto out;
        }
@@ -1331,8 +1313,8 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
                        *protkeytype = PKEY_KEYTYPE_AES_256;
                break;
        default:
-               DEBUG_ERR("%s unknown/unsupported keylen %d\n",
-                         __func__, prepparm->vud.ckb.keylen);
+               ZCRYPT_DBF_ERR("%s unknown/unsupported keylen %d\n",
+                              __func__, prepparm->vud.ckb.keylen);
                rc = -EIO;
                goto out;
        }
@@ -1432,19 +1414,17 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
        rc = zcrypt_send_cprb(&xcrb);
        if (rc) {
-               DEBUG_ERR(
-                       "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
-                       __func__, (int)cardnr, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
+                              __func__, (int)cardnr, (int)domain, rc);
                goto out;
        }
 
        /* check response returncode and reasoncode */
        if (prepcblk->ccp_rtcode != 0) {
-               DEBUG_ERR(
-                       "%s unwrap secure key failure, card response %d/%d\n",
-                       __func__,
-                       (int)prepcblk->ccp_rtcode,
-                       (int)prepcblk->ccp_rscode);
+               ZCRYPT_DBF_ERR("%s unwrap secure key failure, card response %d/%d\n",
+                              __func__,
+                              (int)prepcblk->ccp_rtcode,
+                              (int)prepcblk->ccp_rscode);
                if (prepcblk->ccp_rtcode == 8 && prepcblk->ccp_rscode == 2290)
                        rc = -EAGAIN;
                else
@@ -1452,11 +1432,10 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
                goto out;
        }
        if (prepcblk->ccp_rscode != 0) {
-               DEBUG_WARN(
-                       "%s unwrap secure key warning, card response %d/%d\n",
-                       __func__,
-                       (int)prepcblk->ccp_rtcode,
-                       (int)prepcblk->ccp_rscode);
+               ZCRYPT_DBF_WARN("%s unwrap secure key warning, card response %d/%d\n",
+                               __func__,
+                               (int)prepcblk->ccp_rtcode,
+                               (int)prepcblk->ccp_rscode);
        }
 
        /* process response cprb param block */
@@ -1466,23 +1445,22 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
 
        /* check the returned keyblock */
        if (prepparm->vud.ckb.version != 0x02) {
-               DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x != 0x02\n",
-                         __func__, (int)prepparm->vud.ckb.version);
+               ZCRYPT_DBF_ERR("%s reply param keyblock version mismatch 0x%02x != 0x02\n",
+                              __func__, (int)prepparm->vud.ckb.version);
                rc = -EIO;
                goto out;
        }
        if (prepparm->vud.ckb.algo != 0x81) {
-               DEBUG_ERR(
-                       "%s reply param keyblock algo mismatch 0x%02x != 0x81\n",
-                       __func__, (int)prepparm->vud.ckb.algo);
+               ZCRYPT_DBF_ERR("%s reply param keyblock algo mismatch 0x%02x != 0x81\n",
+                              __func__, (int)prepparm->vud.ckb.algo);
                rc = -EIO;
                goto out;
        }
 
        /* copy the translated protected key */
        if (prepparm->vud.ckb.keylen > *protkeylen) {
-               DEBUG_ERR("%s prot keylen mismatch %d > buffersize %u\n",
-                         __func__, prepparm->vud.ckb.keylen, *protkeylen);
+               ZCRYPT_DBF_ERR("%s prot keylen mismatch %d > buffersize %u\n",
+                              __func__, prepparm->vud.ckb.keylen, *protkeylen);
                rc = -EIO;
                goto out;
        }
@@ -1550,17 +1528,17 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain,
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
        rc = zcrypt_send_cprb(&xcrb);
        if (rc) {
-               DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
-                         __func__, (int)cardnr, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
+                              __func__, (int)cardnr, (int)domain, rc);
                goto out;
        }
 
        /* check response returncode and reasoncode */
        if (prepcblk->ccp_rtcode != 0) {
-               DEBUG_ERR("%s unwrap secure key failure, card response %d/%d\n",
-                         __func__,
-                         (int)prepcblk->ccp_rtcode,
-                         (int)prepcblk->ccp_rscode);
+               ZCRYPT_DBF_ERR("%s unwrap secure key failure, card response %d/%d\n",
+                              __func__,
+                              (int)prepcblk->ccp_rtcode,
+                              (int)prepcblk->ccp_rscode);
                rc = -EIO;
                goto out;
        }
index 5cf88aabd64b9f9048cc8374b664847f87b286a0..9a208dc4c2005137d4348f2c01d224d6a5a8d5d2 100644 (file)
@@ -17,7 +17,7 @@
 #define RC2ERR(rc) ((rc) ? DBF_ERR : DBF_INFO)
 #define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO)
 
-#define DBF_MAX_SPRINTF_ARGS 6
+#define ZCRYPT_DBF_MAX_SPRINTF_ARGS 6
 
 #define ZCRYPT_DBF(...)                                        \
        debug_sprintf_event(zcrypt_dbf_info, ##__VA_ARGS__)
@@ -27,8 +27,6 @@
        debug_sprintf_event(zcrypt_dbf_info, DBF_WARN, ##__VA_ARGS__)
 #define ZCRYPT_DBF_INFO(...)                                   \
        debug_sprintf_event(zcrypt_dbf_info, DBF_INFO, ##__VA_ARGS__)
-#define ZCRYPT_DBF_DBG(...)                                    \
-       debug_sprintf_event(zcrypt_dbf_info, DBF_DEBUG, ##__VA_ARGS__)
 
 extern debug_info_t *zcrypt_dbf_info;
 
index 0a877f9792c2ae6901aa940660e49b0af13cdadb..eb7f5489ccf95962034a2a135dbc30fa83599973 100644 (file)
 #include "zcrypt_ep11misc.h"
 #include "zcrypt_ccamisc.h"
 
-#define DEBUG_DBG(...) ZCRYPT_DBF(DBF_DEBUG, ##__VA_ARGS__)
-#define DEBUG_INFO(...) ZCRYPT_DBF(DBF_INFO, ##__VA_ARGS__)
-#define DEBUG_WARN(...) ZCRYPT_DBF(DBF_WARN, ##__VA_ARGS__)
-#define DEBUG_ERR(...) ZCRYPT_DBF(DBF_ERR, ##__VA_ARGS__)
-
 #define EP11_PINBLOB_V1_BYTES 56
 
 /* default iv used here */
@@ -510,7 +505,7 @@ static int check_reply_pl(const u8 *pl, const char *func)
 
        /* start tag */
        if (*pl++ != 0x30) {
-               DEBUG_ERR("%s reply start tag mismatch\n", func);
+               ZCRYPT_DBF_ERR("%s reply start tag mismatch\n", func);
                return -EIO;
        }
 
@@ -527,40 +522,41 @@ static int check_reply_pl(const u8 *pl, const char *func)
                len = *((u16 *)pl);
                pl += 2;
        } else {
-               DEBUG_ERR("%s reply start tag lenfmt mismatch 0x%02hhx\n",
-                         func, *pl);
+               ZCRYPT_DBF_ERR("%s reply start tag lenfmt mismatch 0x%02hhx\n",
+                              func, *pl);
                return -EIO;
        }
 
        /* len should cover at least 3 fields with 32 bit value each */
        if (len < 3 * 6) {
-               DEBUG_ERR("%s reply length %d too small\n", func, len);
+               ZCRYPT_DBF_ERR("%s reply length %d too small\n", func, len);
                return -EIO;
        }
 
        /* function tag, length and value */
        if (pl[0] != 0x04 || pl[1] != 0x04) {
-               DEBUG_ERR("%s function tag or length mismatch\n", func);
+               ZCRYPT_DBF_ERR("%s function tag or length mismatch\n", func);
                return -EIO;
        }
        pl += 6;
 
        /* dom tag, length and value */
        if (pl[0] != 0x04 || pl[1] != 0x04) {
-               DEBUG_ERR("%s dom tag or length mismatch\n", func);
+               ZCRYPT_DBF_ERR("%s dom tag or length mismatch\n", func);
                return -EIO;
        }
        pl += 6;
 
        /* return value tag, length and value */
        if (pl[0] != 0x04 || pl[1] != 0x04) {
-               DEBUG_ERR("%s return value tag or length mismatch\n", func);
+               ZCRYPT_DBF_ERR("%s return value tag or length mismatch\n",
+                              func);
                return -EIO;
        }
        pl += 2;
        ret = *((u32 *)pl);
        if (ret != 0) {
-               DEBUG_ERR("%s return value 0x%04x != 0\n", func, ret);
+               ZCRYPT_DBF_ERR("%s return value 0x%04x != 0\n", func, ret);
                return -EIO;
        }
 
@@ -626,9 +622,8 @@ static int ep11_query_info(u16 cardnr, u16 domain, u32 query_type,
 
        rc = zcrypt_send_ep11_cprb(urb);
        if (rc) {
-               DEBUG_ERR(
-                       "%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
-                       __func__, (int)cardnr, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
+                              __func__, (int)cardnr, (int)domain, rc);
                goto out;
        }
 
@@ -636,13 +631,13 @@ static int ep11_query_info(u16 cardnr, u16 domain, u32 query_type,
        if (rc)
                goto out;
        if (rep_pl->data_tag != 0x04 || rep_pl->data_lenfmt != 0x82) {
-               DEBUG_ERR("%s unknown reply data format\n", __func__);
+               ZCRYPT_DBF_ERR("%s unknown reply data format\n", __func__);
                rc = -EIO;
                goto out;
        }
        if (rep_pl->data_len > buflen) {
-               DEBUG_ERR("%s mismatch between reply data len and buffer len\n",
-                         __func__);
+               ZCRYPT_DBF_ERR("%s mismatch between reply data len and buffer len\n",
+                              __func__);
                rc = -ENOSPC;
                goto out;
        }
@@ -816,9 +811,8 @@ static int _ep11_genaeskey(u16 card, u16 domain,
        case 256:
                break;
        default:
-               DEBUG_ERR(
-                       "%s unknown/unsupported keybitsize %d\n",
-                       __func__, keybitsize);
+               ZCRYPT_DBF_ERR("%s unknown/unsupported keybitsize %d\n",
+                              __func__, keybitsize);
                rc = -EINVAL;
                goto out;
        }
@@ -878,9 +872,8 @@ static int _ep11_genaeskey(u16 card, u16 domain,
 
        rc = zcrypt_send_ep11_cprb(urb);
        if (rc) {
-               DEBUG_ERR(
-                       "%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
-                       __func__, (int)card, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
+                              __func__, (int)card, (int)domain, rc);
                goto out;
        }
 
@@ -888,13 +881,13 @@ static int _ep11_genaeskey(u16 card, u16 domain,
        if (rc)
                goto out;
        if (rep_pl->data_tag != 0x04 || rep_pl->data_lenfmt != 0x82) {
-               DEBUG_ERR("%s unknown reply data format\n", __func__);
+               ZCRYPT_DBF_ERR("%s unknown reply data format\n", __func__);
                rc = -EIO;
                goto out;
        }
        if (rep_pl->data_len > *keybufsize) {
-               DEBUG_ERR("%s mismatch reply data len / key buffer len\n",
-                         __func__);
+               ZCRYPT_DBF_ERR("%s mismatch reply data len / key buffer len\n",
+                              __func__);
                rc = -ENOSPC;
                goto out;
        }
@@ -1030,9 +1023,8 @@ static int ep11_cryptsingle(u16 card, u16 domain,
 
        rc = zcrypt_send_ep11_cprb(urb);
        if (rc) {
-               DEBUG_ERR(
-                       "%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
-                       __func__, (int)card, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
+                              __func__, (int)card, (int)domain, rc);
                goto out;
        }
 
@@ -1040,7 +1032,7 @@ static int ep11_cryptsingle(u16 card, u16 domain,
        if (rc)
                goto out;
        if (rep_pl->data_tag != 0x04) {
-               DEBUG_ERR("%s unknown reply data format\n", __func__);
+               ZCRYPT_DBF_ERR("%s unknown reply data format\n", __func__);
                rc = -EIO;
                goto out;
        }
@@ -1053,14 +1045,14 @@ static int ep11_cryptsingle(u16 card, u16 domain,
                n = *((u16 *)p);
                p += 2;
        } else {
-               DEBUG_ERR("%s unknown reply data length format 0x%02hhx\n",
-                         __func__, rep_pl->data_lenfmt);
+               ZCRYPT_DBF_ERR("%s unknown reply data length format 0x%02hhx\n",
+                              __func__, rep_pl->data_lenfmt);
                rc = -EIO;
                goto out;
        }
        if (n > *outbufsize) {
-               DEBUG_ERR("%s mismatch reply data len %d / output buffer %zu\n",
-                         __func__, n, *outbufsize);
+               ZCRYPT_DBF_ERR("%s mismatch reply data len %d / output buffer %zu\n",
+                              __func__, n, *outbufsize);
                rc = -ENOSPC;
                goto out;
        }
@@ -1188,9 +1180,8 @@ static int _ep11_unwrapkey(u16 card, u16 domain,
 
        rc = zcrypt_send_ep11_cprb(urb);
        if (rc) {
-               DEBUG_ERR(
-                       "%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
-                       __func__, (int)card, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
+                              __func__, (int)card, (int)domain, rc);
                goto out;
        }
 
@@ -1198,13 +1189,13 @@ static int _ep11_unwrapkey(u16 card, u16 domain,
        if (rc)
                goto out;
        if (rep_pl->data_tag != 0x04 || rep_pl->data_lenfmt != 0x82) {
-               DEBUG_ERR("%s unknown reply data format\n", __func__);
+               ZCRYPT_DBF_ERR("%s unknown reply data format\n", __func__);
                rc = -EIO;
                goto out;
        }
        if (rep_pl->data_len > *keybufsize) {
-               DEBUG_ERR("%s mismatch reply data len / key buffer len\n",
-                         __func__);
+               ZCRYPT_DBF_ERR("%s mismatch reply data len / key buffer len\n",
+                              __func__);
                rc = -ENOSPC;
                goto out;
        }
@@ -1343,9 +1334,8 @@ static int _ep11_wrapkey(u16 card, u16 domain,
 
        rc = zcrypt_send_ep11_cprb(urb);
        if (rc) {
-               DEBUG_ERR(
-                       "%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
-                       __func__, (int)card, (int)domain, rc);
+               ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
+                              __func__, (int)card, (int)domain, rc);
                goto out;
        }
 
@@ -1353,13 +1343,13 @@ static int _ep11_wrapkey(u16 card, u16 domain,
        if (rc)
                goto out;
        if (rep_pl->data_tag != 0x04 || rep_pl->data_lenfmt != 0x82) {
-               DEBUG_ERR("%s unknown reply data format\n", __func__);
+               ZCRYPT_DBF_ERR("%s unknown reply data format\n", __func__);
                rc = -EIO;
                goto out;
        }
        if (rep_pl->data_len > *datasize) {
-               DEBUG_ERR("%s mismatch reply data len / data buffer len\n",
-                         __func__);
+               ZCRYPT_DBF_ERR("%s mismatch reply data len / data buffer len\n",
+                              __func__);
                rc = -ENOSPC;
                goto out;
        }
@@ -1386,9 +1376,8 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
        if (keybitsize == 128 || keybitsize == 192 || keybitsize == 256) {
                clrkeylen = keybitsize / 8;
        } else {
-               DEBUG_ERR(
-                       "%s unknown/unsupported keybitsize %d\n",
-                       __func__, keybitsize);
+               ZCRYPT_DBF_ERR("%s unknown/unsupported keybitsize %d\n",
+                              __func__, keybitsize);
                return -EINVAL;
        }
 
@@ -1405,9 +1394,8 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
                             0x00006c00, /* EN/DECRYPT, WRAP/UNWRAP */
                             kek, &keklen);
        if (rc) {
-               DEBUG_ERR(
-                       "%s generate kek key failed, rc=%d\n",
-                       __func__, rc);
+               ZCRYPT_DBF_ERR("%s generate kek key failed, rc=%d\n",
+                              __func__, rc);
                goto out;
        }
 
@@ -1415,9 +1403,8 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
        rc = ep11_cryptsingle(card, domain, 0, 0, def_iv, kek, keklen,
                              clrkey, clrkeylen, encbuf, &encbuflen);
        if (rc) {
-               DEBUG_ERR(
-                       "%s encrypting key value with kek key failed, rc=%d\n",
-                       __func__, rc);
+               ZCRYPT_DBF_ERR("%s encrypting key value with kek key failed, rc=%d\n",
+                              __func__, rc);
                goto out;
        }
 
@@ -1426,9 +1413,8 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
                            encbuf, encbuflen, 0, def_iv,
                            keybitsize, 0, keybuf, keybufsize, keytype);
        if (rc) {
-               DEBUG_ERR(
-                       "%s importing key value as new key failed,, rc=%d\n",
-                       __func__, rc);
+               ZCRYPT_DBF_ERR("%s importing key value as new key failed,, rc=%d\n",
+                              __func__, rc);
                goto out;
        }
 
@@ -1476,17 +1462,16 @@ int ep11_kblob2protkey(u16 card, u16 dom,
        rc = _ep11_wrapkey(card, dom, (u8 *)key, keylen,
                           0, def_iv, wkbuf, &wkbuflen);
        if (rc) {
-               DEBUG_ERR(
-                       "%s rewrapping ep11 key to pkey failed, rc=%d\n",
-                       __func__, rc);
+               ZCRYPT_DBF_ERR("%s rewrapping ep11 key to pkey failed, rc=%d\n",
+                              __func__, rc);
                goto out;
        }
        wki = (struct wk_info *)wkbuf;
 
        /* check struct version and pkey type */
        if (wki->version != 1 || wki->pkeytype < 1 || wki->pkeytype > 5) {
-               DEBUG_ERR("%s wk info version %d or pkeytype %d mismatch.\n",
-                         __func__, (int)wki->version, (int)wki->pkeytype);
+               ZCRYPT_DBF_ERR("%s wk info version %d or pkeytype %d mismatch.\n",
+                              __func__, (int)wki->version, (int)wki->pkeytype);
                rc = -EIO;
                goto out;
        }
@@ -1511,8 +1496,8 @@ int ep11_kblob2protkey(u16 card, u16 dom,
                                *protkeytype = PKEY_KEYTYPE_AES_256;
                        break;
                default:
-                       DEBUG_ERR("%s unknown/unsupported AES pkeysize %d\n",
-                                 __func__, (int)wki->pkeysize);
+                       ZCRYPT_DBF_ERR("%s unknown/unsupported AES pkeysize %d\n",
+                                      __func__, (int)wki->pkeysize);
                        rc = -EIO;
                        goto out;
                }
@@ -1525,16 +1510,16 @@ int ep11_kblob2protkey(u16 card, u16 dom,
                break;
        case 2: /* TDES */
        default:
-               DEBUG_ERR("%s unknown/unsupported key type %d\n",
-                         __func__, (int)wki->pkeytype);
+               ZCRYPT_DBF_ERR("%s unknown/unsupported key type %d\n",
+                              __func__, (int)wki->pkeytype);
                rc = -EIO;
                goto out;
        }
 
        /* copy the translated protected key */
        if (wki->pkeysize > *protkeylen) {
-               DEBUG_ERR("%s wk info pkeysize %llu > protkeysize %u\n",
-                         __func__, wki->pkeysize, *protkeylen);
+               ZCRYPT_DBF_ERR("%s wk info pkeysize %llu > protkeysize %u\n",
+                              __func__, wki->pkeysize, *protkeylen);
                rc = -EINVAL;
                goto out;
        }
index a44fcfcec9387820951bdf5eeab0014e5c14c042..46e27b43a8afe7df13dc43af6aaf35e31918f253 100644 (file)
@@ -119,10 +119,9 @@ static inline int convert_error(struct zcrypt_queue *zq,
        case REP82_ERROR_MESSAGE_TYPE:           /* 0x20 */
        case REP82_ERROR_TRANSPORT_FAIL:         /* 0x90 */
                /*
-                * Msg to wrong type or card/infrastructure failure.
-                * Trigger rescan of the ap bus, trigger retry request.
+                * Msg to wrong type or card/infrastructure failure. Return
+                * EAGAIN, the upper layer may do a retry on the request.
                 */
-               atomic_set(&zcrypt_rescan_req, 1);
                /* For type 86 response show the apfs value (failure reason) */
                if (ehdr->reply_code == REP82_ERROR_TRANSPORT_FAIL &&
                    ehdr->type == TYPE86_RSP_CODE) {
index 2e155de8abe5b25e1ab7496953243c5809663d0b..3b39cb8f926dbd3731999ac242636c8715dcd762 100644 (file)
@@ -427,7 +427,7 @@ static void zcrypt_msgtype50_receive(struct ap_queue *aq,
                len = t80h->len;
                if (len > reply->bufsize || len > msg->bufsize ||
                    len != reply->len) {
-                       ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__);
+                       pr_debug("%s len mismatch => EMSGSIZE\n", __func__);
                        msg->rc = -EMSGSIZE;
                        goto out;
                }
@@ -487,9 +487,9 @@ static long zcrypt_msgtype50_modexpo(struct zcrypt_queue *zq,
 out:
        ap_msg->private = NULL;
        if (rc)
-               ZCRYPT_DBF_DBG("%s send me cprb at dev=%02x.%04x rc=%d\n",
-                              __func__, AP_QID_CARD(zq->queue->qid),
-                              AP_QID_QUEUE(zq->queue->qid), rc);
+               pr_debug("%s send me cprb at dev=%02x.%04x rc=%d\n",
+                        __func__, AP_QID_CARD(zq->queue->qid),
+                        AP_QID_QUEUE(zq->queue->qid), rc);
        return rc;
 }
 
@@ -537,9 +537,9 @@ static long zcrypt_msgtype50_modexpo_crt(struct zcrypt_queue *zq,
 out:
        ap_msg->private = NULL;
        if (rc)
-               ZCRYPT_DBF_DBG("%s send crt cprb at dev=%02x.%04x rc=%d\n",
-                              __func__, AP_QID_CARD(zq->queue->qid),
-                              AP_QID_QUEUE(zq->queue->qid), rc);
+               pr_debug("%s send crt cprb at dev=%02x.%04x rc=%d\n",
+                        __func__, AP_QID_CARD(zq->queue->qid),
+                        AP_QID_QUEUE(zq->queue->qid), rc);
        return rc;
 }
 
index 3c53abbdc3420a51378001cc35595a04b3841615..215f257d2360d0021c3e12868da0967a8e6de494 100644 (file)
@@ -437,9 +437,9 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg,
                ap_msg->flags |= AP_MSG_FLAG_ADMIN;
                break;
        default:
-               ZCRYPT_DBF_DBG("%s unknown CPRB minor version '%c%c'\n",
-                              __func__, msg->cprbx.func_id[0],
-                              msg->cprbx.func_id[1]);
+               pr_debug("%s unknown CPRB minor version '%c%c'\n",
+                        __func__, msg->cprbx.func_id[0],
+                        msg->cprbx.func_id[1]);
        }
 
        /* copy data block */
@@ -629,9 +629,9 @@ static int convert_type86_xcrb(bool userspace, struct zcrypt_queue *zq,
 
        /* Copy CPRB to user */
        if (xcrb->reply_control_blk_length < msg->fmt2.count1) {
-               ZCRYPT_DBF_DBG("%s reply_control_blk_length %u < required %u => EMSGSIZE\n",
-                              __func__, xcrb->reply_control_blk_length,
-                              msg->fmt2.count1);
+               pr_debug("%s reply_control_blk_length %u < required %u => EMSGSIZE\n",
+                        __func__, xcrb->reply_control_blk_length,
+                        msg->fmt2.count1);
                return -EMSGSIZE;
        }
        if (z_copy_to_user(userspace, xcrb->reply_control_blk_addr,
@@ -642,9 +642,9 @@ static int convert_type86_xcrb(bool userspace, struct zcrypt_queue *zq,
        /* Copy data buffer to user */
        if (msg->fmt2.count2) {
                if (xcrb->reply_data_length < msg->fmt2.count2) {
-                       ZCRYPT_DBF_DBG("%s reply_data_length %u < required %u => EMSGSIZE\n",
-                                      __func__, xcrb->reply_data_length,
-                                      msg->fmt2.count2);
+                       pr_debug("%s reply_data_length %u < required %u => EMSGSIZE\n",
+                                __func__, xcrb->reply_data_length,
+                                msg->fmt2.count2);
                        return -EMSGSIZE;
                }
                if (z_copy_to_user(userspace, xcrb->reply_data_addr,
@@ -673,9 +673,9 @@ static int convert_type86_ep11_xcrb(bool userspace, struct zcrypt_queue *zq,
        char *data = reply->msg;
 
        if (xcrb->resp_len < msg->fmt2.count1) {
-               ZCRYPT_DBF_DBG("%s resp_len %u < required %u => EMSGSIZE\n",
-                              __func__, (unsigned int)xcrb->resp_len,
-                              msg->fmt2.count1);
+               pr_debug("%s resp_len %u < required %u => EMSGSIZE\n",
+                        __func__, (unsigned int)xcrb->resp_len,
+                        msg->fmt2.count1);
                return -EMSGSIZE;
        }
 
@@ -875,7 +875,8 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq,
                        len = sizeof(struct type86x_reply) + t86r->length;
                        if (len > reply->bufsize || len > msg->bufsize ||
                            len != reply->len) {
-                               ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__);
+                               pr_debug("%s len mismatch => EMSGSIZE\n",
+                                        __func__);
                                msg->rc = -EMSGSIZE;
                                goto out;
                        }
@@ -889,7 +890,8 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq,
                                len = t86r->fmt2.offset1 + t86r->fmt2.count1;
                        if (len > reply->bufsize || len > msg->bufsize ||
                            len != reply->len) {
-                               ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__);
+                               pr_debug("%s len mismatch => EMSGSIZE\n",
+                                        __func__);
                                msg->rc = -EMSGSIZE;
                                goto out;
                        }
@@ -939,7 +941,8 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq,
                        len = t86r->fmt2.offset1 + t86r->fmt2.count1;
                        if (len > reply->bufsize || len > msg->bufsize ||
                            len != reply->len) {
-                               ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__);
+                               pr_debug("%s len mismatch => EMSGSIZE\n",
+                                        __func__);
                                msg->rc = -EMSGSIZE;
                                goto out;
                        }
@@ -1151,9 +1154,9 @@ static long zcrypt_msgtype6_send_cprb(bool userspace, struct zcrypt_queue *zq,
 
 out:
        if (rc)
-               ZCRYPT_DBF_DBG("%s send cprb at dev=%02x.%04x rc=%d\n",
-                              __func__, AP_QID_CARD(zq->queue->qid),
-                              AP_QID_QUEUE(zq->queue->qid), rc);
+               pr_debug("%s send cprb at dev=%02x.%04x rc=%d\n",
+                        __func__, AP_QID_CARD(zq->queue->qid),
+                        AP_QID_QUEUE(zq->queue->qid), rc);
        return rc;
 }
 
@@ -1274,9 +1277,9 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue *
 
 out:
        if (rc)
-               ZCRYPT_DBF_DBG("%s send cprb at dev=%02x.%04x rc=%d\n",
-                              __func__, AP_QID_CARD(zq->queue->qid),
-                              AP_QID_QUEUE(zq->queue->qid), rc);
+               pr_debug("%s send cprb at dev=%02x.%04x rc=%d\n",
+                        __func__, AP_QID_CARD(zq->queue->qid),
+                        AP_QID_QUEUE(zq->queue->qid), rc);
        return rc;
 }
 
index addac7fbe37b9870380cc715acf923344071e6e6..9ce27092729c30a2791b329c117fa9314b268352 100644 (file)
@@ -1270,7 +1270,7 @@ source "drivers/scsi/arm/Kconfig"
 
 config JAZZ_ESP
        bool "MIPS JAZZ FAS216 SCSI support"
-       depends on MACH_JAZZ && SCSI
+       depends on MACH_JAZZ && SCSI=y
        select SCSI_SPI_ATTRS
        help
          This is the driver for the onboard SCSI host adapter of MIPS Magnum
index 19eee108db02145e55d6bebc33a03e4fffba1ef5..5c8d1ba3f8f3c9c2de41e7f111db57f2b4c3e63a 100644 (file)
@@ -319,17 +319,16 @@ static void fcoe_ctlr_announce(struct fcoe_ctlr *fip)
 {
        struct fcoe_fcf *sel;
        struct fcoe_fcf *fcf;
-       unsigned long flags;
 
        mutex_lock(&fip->ctlr_mutex);
-       spin_lock_irqsave(&fip->ctlr_lock, flags);
+       spin_lock_bh(&fip->ctlr_lock);
 
        kfree_skb(fip->flogi_req);
        fip->flogi_req = NULL;
        list_for_each_entry(fcf, &fip->fcfs, list)
                fcf->flogi_sent = 0;
 
-       spin_unlock_irqrestore(&fip->ctlr_lock, flags);
+       spin_unlock_bh(&fip->ctlr_lock);
        sel = fip->sel_fcf;
 
        if (sel && ether_addr_equal(sel->fcf_mac, fip->dest_addr))
@@ -700,7 +699,6 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
 {
        struct fc_frame *fp;
        struct fc_frame_header *fh;
-       unsigned long flags;
        u16 old_xid;
        u8 op;
        u8 mac[ETH_ALEN];
@@ -734,11 +732,11 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
                op = FIP_DT_FLOGI;
                if (fip->mode == FIP_MODE_VN2VN)
                        break;
-               spin_lock_irqsave(&fip->ctlr_lock, flags);
+               spin_lock_bh(&fip->ctlr_lock);
                kfree_skb(fip->flogi_req);
                fip->flogi_req = skb;
                fip->flogi_req_send = 1;
-               spin_unlock_irqrestore(&fip->ctlr_lock, flags);
+               spin_unlock_bh(&fip->ctlr_lock);
                schedule_work(&fip->timer_work);
                return -EINPROGRESS;
        case ELS_FDISC:
@@ -1707,11 +1705,10 @@ static int fcoe_ctlr_flogi_send_locked(struct fcoe_ctlr *fip)
 static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip)
 {
        struct fcoe_fcf *fcf;
-       unsigned long flags;
        int error;
 
        mutex_lock(&fip->ctlr_mutex);
-       spin_lock_irqsave(&fip->ctlr_lock, flags);
+       spin_lock_bh(&fip->ctlr_lock);
        LIBFCOE_FIP_DBG(fip, "re-sending FLOGI - reselect\n");
        fcf = fcoe_ctlr_select(fip);
        if (!fcf || fcf->flogi_sent) {
@@ -1722,7 +1719,7 @@ static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip)
                fcoe_ctlr_solicit(fip, NULL);
                error = fcoe_ctlr_flogi_send_locked(fip);
        }
-       spin_unlock_irqrestore(&fip->ctlr_lock, flags);
+       spin_unlock_bh(&fip->ctlr_lock);
        mutex_unlock(&fip->ctlr_mutex);
        return error;
 }
@@ -1739,9 +1736,8 @@ static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip)
 static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip)
 {
        struct fcoe_fcf *fcf;
-       unsigned long flags;
 
-       spin_lock_irqsave(&fip->ctlr_lock, flags);
+       spin_lock_bh(&fip->ctlr_lock);
        fcf = fip->sel_fcf;
        if (!fcf || !fip->flogi_req_send)
                goto unlock;
@@ -1768,7 +1764,7 @@ static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip)
        } else /* XXX */
                LIBFCOE_FIP_DBG(fip, "No FCF selected - defer send\n");
 unlock:
-       spin_unlock_irqrestore(&fip->ctlr_lock, flags);
+       spin_unlock_bh(&fip->ctlr_lock);
 }
 
 /**
index 2074937c05bc855dea5a580079b84fd677460fb5..ce73f08ee889f1409c43583d959baeae6f0fb895 100644 (file)
@@ -305,6 +305,7 @@ struct fnic {
        unsigned int copy_wq_base;
        struct work_struct link_work;
        struct work_struct frame_work;
+       struct work_struct flush_work;
        struct sk_buff_head frame_queue;
        struct sk_buff_head tx_queue;
 
@@ -363,7 +364,7 @@ void fnic_handle_event(struct work_struct *work);
 int fnic_rq_cmpl_handler(struct fnic *fnic, int);
 int fnic_alloc_rq_frame(struct vnic_rq *rq);
 void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf);
-void fnic_flush_tx(struct fnic *);
+void fnic_flush_tx(struct work_struct *work);
 void fnic_eth_send(struct fcoe_ctlr *, struct sk_buff *skb);
 void fnic_set_port_id(struct fc_lport *, u32, struct fc_frame *);
 void fnic_update_mac(struct fc_lport *, u8 *new);
index 5e312a55cc7da0c73811b0fc26aed17d8c6a034c..a08293b2ad9f59031d5220aba3480a84461a0e8a 100644 (file)
@@ -1182,7 +1182,7 @@ int fnic_send(struct fc_lport *lp, struct fc_frame *fp)
 
 /**
  * fnic_flush_tx() - send queued frames.
- * @fnic: fnic device
+ * @work: pointer to work element
  *
  * Send frames that were waiting to go out in FC or Ethernet mode.
  * Whenever changing modes we purge queued frames, so these frames should
@@ -1190,8 +1190,9 @@ int fnic_send(struct fc_lport *lp, struct fc_frame *fp)
  *
  * Called without fnic_lock held.
  */
-void fnic_flush_tx(struct fnic *fnic)
+void fnic_flush_tx(struct work_struct *work)
 {
+       struct fnic *fnic = container_of(work, struct fnic, flush_work);
        struct sk_buff *skb;
        struct fc_frame *fp;
 
index 5ed1d897311a88c0d1194bff7b36e9677a45166f..29eead383eb9a478bb71643eaac1a4e302418f0f 100644 (file)
@@ -830,6 +830,7 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                spin_lock_init(&fnic->vlans_lock);
                INIT_WORK(&fnic->fip_frame_work, fnic_handle_fip_frame);
                INIT_WORK(&fnic->event_work, fnic_handle_event);
+               INIT_WORK(&fnic->flush_work, fnic_flush_tx);
                skb_queue_head_init(&fnic->fip_frame_queue);
                INIT_LIST_HEAD(&fnic->evlist);
                INIT_LIST_HEAD(&fnic->vlans);
index 8d7fc5284293b5283523b049ba38387857ebb09e..fc4cee91b175c14d0950337ac8928b659cbc8cef 100644 (file)
@@ -680,7 +680,7 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic,
 
        spin_unlock_irqrestore(&fnic->fnic_lock, flags);
 
-       fnic_flush_tx(fnic);
+       queue_work(fnic_event_queue, &fnic->flush_work);
 
  reset_cmpl_handler_end:
        fnic_clear_state_flags(fnic, FNIC_FLAGS_FWRESET);
@@ -736,7 +736,7 @@ static int fnic_fcpio_flogi_reg_cmpl_handler(struct fnic *fnic,
                }
                spin_unlock_irqrestore(&fnic->fnic_lock, flags);
 
-               fnic_flush_tx(fnic);
+               queue_work(fnic_event_queue, &fnic->flush_work);
                queue_work(fnic_event_queue, &fnic->frame_work);
        } else {
                spin_unlock_irqrestore(&fnic->fnic_lock, flags);
index c0c8ab5869572f77fa11f1c2154e85802ff8a4e5..d32ad46318cb09af970085b3ab00fc376a934e4f 100644 (file)
@@ -1671,7 +1671,7 @@ mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port,
 void
 mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc)
 {
-       struct host_port h_port[64];
+       struct host_port *h_port = NULL;
        int i, j, found, host_port_count = 0, port_idx;
        u16 sz, attached_handle, ioc_status;
        struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
@@ -1685,6 +1685,10 @@ mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc)
        sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
        if (!sas_io_unit_pg0)
                return;
+       h_port = kcalloc(64, sizeof(struct host_port), GFP_KERNEL);
+       if (!h_port)
+               goto out;
+
        if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
                ioc_err(mrioc, "failure at %s:%d/%s()!\n",
                    __FILE__, __LINE__, __func__);
@@ -1814,6 +1818,7 @@ mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc)
                }
        }
 out:
+       kfree(h_port);
        kfree(sas_io_unit_pg0);
 }
 
index 8761bc58d965f0f6eb6776a4272ca856e8724463..b8120ca93c79740d7827ebff1652b4b22b296421 100644 (file)
@@ -7378,7 +7378,9 @@ _base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout)
                return -EFAULT;
        }
 
- issue_diag_reset:
+       return 0;
+
+issue_diag_reset:
        rc = _base_diag_reset(ioc);
        return rc;
 }
index 76d369343c7a9c2457e7d7bc16aa518815cbfc8f..8cad9792a56275b38f70595baf7fb095882a6c1f 100644 (file)
@@ -328,21 +328,39 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
        return result + 4;
 }
 
+enum scsi_vpd_parameters {
+       SCSI_VPD_HEADER_SIZE = 4,
+       SCSI_VPD_LIST_SIZE = 36,
+};
+
 static int scsi_get_vpd_size(struct scsi_device *sdev, u8 page)
 {
-       unsigned char vpd_header[SCSI_VPD_HEADER_SIZE] __aligned(4);
+       unsigned char vpd[SCSI_VPD_LIST_SIZE] __aligned(4);
        int result;
 
        if (sdev->no_vpd_size)
                return SCSI_DEFAULT_VPD_LEN;
 
+       /*
+        * Fetch the supported pages VPD and validate that the requested page
+        * number is present.
+        */
+       if (page != 0) {
+               result = scsi_vpd_inquiry(sdev, vpd, 0, sizeof(vpd));
+               if (result < SCSI_VPD_HEADER_SIZE)
+                       return 0;
+
+               result -= SCSI_VPD_HEADER_SIZE;
+               if (!memchr(&vpd[SCSI_VPD_HEADER_SIZE], page, result))
+                       return 0;
+       }
        /*
         * Fetch the VPD page header to find out how big the page
         * is. This is done to prevent problems on legacy devices
         * which can not handle allocation lengths as large as
         * potentially requested by the caller.
         */
-       result = scsi_vpd_inquiry(sdev, vpd_header, page, sizeof(vpd_header));
+       result = scsi_vpd_inquiry(sdev, vpd, page, SCSI_VPD_HEADER_SIZE);
        if (result < 0)
                return 0;
 
index 44680f65ea1455daec91d4c6dd98d2cb2431f4e2..9969f4e2f1c3d9c656076e3e540bd17c8352c2af 100644 (file)
@@ -332,7 +332,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
 
        sdev->sg_reserved_size = INT_MAX;
 
-       q = blk_mq_init_queue(&sdev->host->tag_set);
+       q = blk_mq_alloc_queue(&sdev->host->tag_set, NULL, NULL);
        if (IS_ERR(q)) {
                /* release fn is set up in scsi_sysfs_device_initialise, so
                 * have to free and put manually here */
index 0833b3e6aa6e8f35b791d3f75fe208fb0f888914..bdd0acf7fa3cb130e64fac2aacf684aa5a91da8b 100644 (file)
@@ -3407,6 +3407,24 @@ static bool sd_validate_opt_xfer_size(struct scsi_disk *sdkp,
        return true;
 }
 
+static void sd_read_block_zero(struct scsi_disk *sdkp)
+{
+       unsigned int buf_len = sdkp->device->sector_size;
+       char *buffer, cmd[10] = { };
+
+       buffer = kmalloc(buf_len, GFP_KERNEL);
+       if (!buffer)
+               return;
+
+       cmd[0] = READ_10;
+       put_unaligned_be32(0, &cmd[2]); /* Logical block address 0 */
+       put_unaligned_be16(1, &cmd[7]); /* Transfer 1 logical block */
+
+       scsi_execute_cmd(sdkp->device, cmd, REQ_OP_DRV_IN, buffer, buf_len,
+                        SD_TIMEOUT, sdkp->max_retries, NULL);
+       kfree(buffer);
+}
+
 /**
  *     sd_revalidate_disk - called the first time a new disk is seen,
  *     performs disk spin up, read_capacity, etc.
@@ -3446,7 +3464,13 @@ static int sd_revalidate_disk(struct gendisk *disk)
         */
        if (sdkp->media_present) {
                sd_read_capacity(sdkp, buffer);
-
+               /*
+                * Some USB/UAS devices return generic values for mode pages
+                * until the media has been accessed. Trigger a READ operation
+                * to force the device to populate mode pages.
+                */
+               if (sdp->read_before_ms)
+                       sd_read_block_zero(sdkp);
                /*
                 * set the default to rotational.  All non-rotational devices
                 * support the block characteristics VPD page, which will
index ceff1ec13f9ea9ea056da947d3939c51f4797522..385180c98be496989dbf469926f52c974609a013 100644 (file)
@@ -6533,8 +6533,11 @@ static void pqi_map_queues(struct Scsi_Host *shost)
 {
        struct pqi_ctrl_info *ctrl_info = shost_to_hba(shost);
 
-       blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT],
+       if (!ctrl_info->disable_managed_interrupts)
+               return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT],
                              ctrl_info->pci_dev, 0);
+       else
+               return blk_mq_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT]);
 }
 
 static inline bool pqi_is_tape_changer_device(struct pqi_scsi_dev *device)
index 0810b5b0c6883f5f88215651d6b8fa2f4461a923..50c664b65f4d44ada7892098029ee25b7a3af876 100644 (file)
@@ -68,4 +68,13 @@ config MTK_SVS
          chip process corner, temperatures and other factors. Then DVFS
          driver could apply SVS bank voltage to PMIC/Buck.
 
+config MTK_SOCINFO
+       tristate "MediaTek SoC Information"
+       default y
+       depends on NVMEM_MTK_EFUSE
+       help
+         The MediaTek SoC Information (mtk-socinfo) driver provides
+         information about the SoC to the userspace including the
+         manufacturer name, marketing name and soc name.
+
 endmenu
index 9d3ce7878c5c7db3d708137d5ddbb0fe114c79fc..6830512848fd0feb2d559894ac1b88397b487e91 100644 (file)
@@ -7,3 +7,4 @@ obj-$(CONFIG_MTK_REGULATOR_COUPLER) += mtk-regulator-coupler.o
 obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
 obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
 obj-$(CONFIG_MTK_SVS) += mtk-svs.o
+obj-$(CONFIG_MTK_SOCINFO) += mtk-socinfo.o
diff --git a/drivers/soc/mediatek/mtk-socinfo.c b/drivers/soc/mediatek/mtk-socinfo.c
new file mode 100644 (file)
index 0000000..42572e8
--- /dev/null
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/device.h>
+#include <linux/device/bus.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/sys_soc.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#define MTK_SOCINFO_ENTRY(_soc_name, _segment_name, _marketing_name, _cell_data1, _cell_data2) {\
+       .soc_name = _soc_name,                                                                  \
+       .segment_name = _segment_name,                                                          \
+       .marketing_name = _marketing_name,                                                      \
+       .cell_data = {_cell_data1, _cell_data2}                                                 \
+}
+#define CELL_NOT_USED (0xFFFFFFFF)
+#define MAX_CELLS (2)
+
+struct mtk_socinfo {
+       struct device *dev;
+       struct name_data *name_data;
+       struct socinfo_data *socinfo_data;
+       struct soc_device *soc_dev;
+};
+
+struct socinfo_data {
+       char *soc_name;
+       char *segment_name;
+       char *marketing_name;
+       u32 cell_data[MAX_CELLS];
+};
+
+static const char *cell_names[MAX_CELLS] = {"socinfo-data1", "socinfo-data2"};
+
+static struct socinfo_data socinfo_data_table[] = {
+       MTK_SOCINFO_ENTRY("MT8173", "MT8173V/AC", "MT8173", 0x6CA20004, 0x10000000),
+       MTK_SOCINFO_ENTRY("MT8183", "MT8183V/AZA", "Kompanio 500", 0x00010043, 0x00000840),
+       MTK_SOCINFO_ENTRY("MT8183", "MT8183V/AZA", "Kompanio 500", 0x00010043, 0x00000940),
+       MTK_SOCINFO_ENTRY("MT8186", "MT8186GV/AZA", "Kompanio 520", 0x81861001, CELL_NOT_USED),
+       MTK_SOCINFO_ENTRY("MT8186T", "MT8186TV/AZA", "Kompanio 528", 0x81862001, CELL_NOT_USED),
+       MTK_SOCINFO_ENTRY("MT8188", "MT8188GV/AZA", "Kompanio 830", 0x81880000, 0x00000010),
+       MTK_SOCINFO_ENTRY("MT8188", "MT8188GV/HZA", "Kompanio 830", 0x81880000, 0x00000011),
+       MTK_SOCINFO_ENTRY("MT8192", "MT8192V/AZA", "Kompanio 820", 0x00001100, 0x00040080),
+       MTK_SOCINFO_ENTRY("MT8192T", "MT8192V/ATZA", "Kompanio 828", 0x00000100, 0x000400C0),
+       MTK_SOCINFO_ENTRY("MT8195", "MT8195GV/EZA", "Kompanio 1200", 0x81950300, CELL_NOT_USED),
+       MTK_SOCINFO_ENTRY("MT8195", "MT8195GV/EHZA", "Kompanio 1200", 0x81950304, CELL_NOT_USED),
+       MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EZA", "Kompanio 1380", 0x81950400, CELL_NOT_USED),
+       MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EHZA", "Kompanio 1380", 0x81950404, CELL_NOT_USED),
+};
+
+static int mtk_socinfo_create_socinfo_node(struct mtk_socinfo *mtk_socinfop)
+{
+       struct soc_device_attribute *attrs;
+       static char machine[30] = {0};
+       static const char *soc_manufacturer = "MediaTek";
+
+       attrs = devm_kzalloc(mtk_socinfop->dev, sizeof(*attrs), GFP_KERNEL);
+       if (!attrs)
+               return -ENOMEM;
+
+       snprintf(machine, sizeof(machine), "%s (%s)", mtk_socinfop->socinfo_data->marketing_name,
+               mtk_socinfop->socinfo_data->soc_name);
+       attrs->family = soc_manufacturer;
+       attrs->machine = machine;
+
+       mtk_socinfop->soc_dev = soc_device_register(attrs);
+       if (IS_ERR(mtk_socinfop->soc_dev))
+               return PTR_ERR(mtk_socinfop->soc_dev);
+
+       dev_info(mtk_socinfop->dev, "%s %s SoC detected.\n", soc_manufacturer, attrs->machine);
+       return 0;
+}
+
+static u32 mtk_socinfo_read_cell(struct device *dev, const char *name)
+{
+       struct nvmem_device *nvmemp;
+       struct device_node *np, *nvmem_node = dev->parent->of_node;
+       u32 offset;
+       u32 cell_val = CELL_NOT_USED;
+
+       /* should never fail since the nvmem driver registers this child */
+       nvmemp = nvmem_device_find(nvmem_node, device_match_of_node);
+       if (IS_ERR(nvmemp))
+               goto out;
+
+       np = of_get_child_by_name(nvmem_node, name);
+       if (!np)
+               goto put_device;
+
+       if (of_property_read_u32_index(np, "reg", 0, &offset))
+               goto put_node;
+
+       nvmem_device_read(nvmemp, offset, sizeof(cell_val), &cell_val);
+
+put_node:
+       of_node_put(np);
+put_device:
+       nvmem_device_put(nvmemp);
+out:
+       return cell_val;
+}
+
+static int mtk_socinfo_get_socinfo_data(struct mtk_socinfo *mtk_socinfop)
+{
+       unsigned int i, j;
+       unsigned int num_cell_data = 0;
+       u32 cell_data[MAX_CELLS] = {0};
+       bool match_socinfo;
+       int match_socinfo_index = -1;
+
+       for (i = 0; i < MAX_CELLS; i++) {
+               cell_data[i] = mtk_socinfo_read_cell(mtk_socinfop->dev, cell_names[i]);
+               if (cell_data[i] != CELL_NOT_USED)
+                       num_cell_data++;
+               else
+                       break;
+       }
+
+       if (!num_cell_data)
+               return -ENOENT;
+
+       for (i = 0; i < ARRAY_SIZE(socinfo_data_table); i++) {
+               match_socinfo = true;
+               for (j = 0; j < num_cell_data; j++) {
+                       if (cell_data[j] != socinfo_data_table[i].cell_data[j]) {
+                               match_socinfo = false;
+                               break;
+                       }
+               }
+               if (match_socinfo) {
+                       mtk_socinfop->socinfo_data = &(socinfo_data_table[i]);
+                       match_socinfo_index = i;
+                       break;
+               }
+       }
+
+       return match_socinfo_index >= 0 ? match_socinfo_index : -ENOENT;
+}
+
+static int mtk_socinfo_probe(struct platform_device *pdev)
+{
+       struct mtk_socinfo *mtk_socinfop;
+       int ret;
+
+       mtk_socinfop = devm_kzalloc(&pdev->dev, sizeof(*mtk_socinfop), GFP_KERNEL);
+       if (!mtk_socinfop)
+               return -ENOMEM;
+
+       mtk_socinfop->dev = &pdev->dev;
+
+       ret = mtk_socinfo_get_socinfo_data(mtk_socinfop);
+       if (ret < 0)
+               return dev_err_probe(mtk_socinfop->dev, ret, "Failed to get socinfo data\n");
+
+       ret = mtk_socinfo_create_socinfo_node(mtk_socinfop);
+       if (ret)
+               return dev_err_probe(mtk_socinfop->dev, ret, "Cannot create node\n");
+
+       platform_set_drvdata(pdev, mtk_socinfop);
+       return 0;
+}
+
+static void mtk_socinfo_remove(struct platform_device *pdev)
+{
+       struct mtk_socinfo *mtk_socinfop = platform_get_drvdata(pdev);
+
+       soc_device_unregister(mtk_socinfop->soc_dev);
+}
+
+static struct platform_driver mtk_socinfo = {
+       .probe = mtk_socinfo_probe,
+       .remove_new = mtk_socinfo_remove,
+       .driver = {
+               .name = "mtk-socinfo",
+       },
+};
+module_platform_driver(mtk_socinfo);
+
+MODULE_AUTHOR("William-TW LIN <william-tw.lin@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek socinfo driver");
+MODULE_LICENSE("GPL");
index 9b0fdd95276e4e017d32012d1f2de3107556e242..19f4b576f822b2e57309308f5294914af27df570 100644 (file)
@@ -1,5 +1,5 @@
 config POLARFIRE_SOC_SYS_CTRL
-       tristate "POLARFIRE_SOC_SYS_CTRL"
+       tristate "Microchip PolarFire SoC (MPFS) system controller support"
        depends on POLARFIRE_SOC_MAILBOX
        depends on MTD
        help
index c6ca4de425863dd42c6482104ce13f431027c32d..5af33b0e3470ec4e9d5b3242fb9755e94ecbd2df 100644 (file)
@@ -268,4 +268,13 @@ config QCOM_INLINE_CRYPTO_ENGINE
        tristate
        select QCOM_SCM
 
+config QCOM_PBS
+       tristate "PBS trigger support for Qualcomm Technologies, Inc. PMICS"
+       depends on SPMI
+       help
+         This driver supports configuring software programmable boot sequencer (PBS)
+         trigger event through PBS RAM on Qualcomm Technologies, Inc. PMICs.
+         This module provides the APIs to the client drivers that wants to send the
+         PBS trigger event to the PBS RAM.
+
 endmenu
index 05b3d54e8dc93992d3bbce0e1eca0d7fa964cd69..ca0bece0dfff90dc950eda8740535505d8a32797 100644 (file)
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 CFLAGS_rpmh-rsc.o := -I$(src)
+CFLAGS_qcom_aoss.o := -I$(src)
 obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o
 obj-$(CONFIG_QCOM_GENI_SE) +=  qcom-geni-se.o
 obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
@@ -34,3 +35,4 @@ obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) +=       kryo-l2-accessors.o
 obj-$(CONFIG_QCOM_ICC_BWMON)   += icc-bwmon.o
 qcom_ice-objs                  += ice.o
 obj-$(CONFIG_QCOM_INLINE_CRYPTO_ENGINE)        += qcom_ice.o
+obj-$(CONFIG_QCOM_PBS) +=      qcom-pbs.o
index 1f8b315576a4abc3f697b03fcf9ecf6d438d4df4..50749e870efaf52ff27ff69bd0baee0a19dfdfd1 100644 (file)
@@ -399,7 +399,7 @@ static int apr_uevent(const struct device *dev, struct kobj_uevent_env *env)
        return add_uevent_var(env, "MODALIAS=apr:%s", adev->name);
 }
 
-struct bus_type aprbus = {
+const struct bus_type aprbus = {
        .name           = "aprbus",
        .match          = apr_device_match,
        .probe          = apr_device_probe,
index 4ca88eaebf06a590b780e32c97a69ae16f707227..cbef0dea1d5d7b52b681d6a3b5f9715fede96bec 100644 (file)
@@ -859,6 +859,8 @@ static int llcc_update_act_ctrl(u32 sid,
        ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
                                      slice_status, !(slice_status & status),
                                      0, LLCC_STATUS_READ_DELAY);
+       if (ret)
+               return ret;
 
        if (drv_data->version >= LLCC_VERSION_4_1_0_0)
                ret = regmap_write(drv_data->bcast_regmap, act_clear_reg,
index f4bfd24386f1b5d2defe9aad6ffcd7123035158d..f913e9bd57ed4a7aa6d1b99d27a40552713b2536 100644 (file)
@@ -265,10 +265,17 @@ static int pmic_glink_probe(struct platform_device *pdev)
 
        pg->client_mask = *match_data;
 
+       pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg);
+       if (IS_ERR(pg->pdr)) {
+               ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr),
+                                   "failed to initialize pdr\n");
+               return ret;
+       }
+
        if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) {
                ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi");
                if (ret)
-                       return ret;
+                       goto out_release_pdr_handle;
        }
        if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) {
                ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode");
@@ -281,17 +288,11 @@ static int pmic_glink_probe(struct platform_device *pdev)
                        goto out_release_altmode_aux;
        }
 
-       pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg);
-       if (IS_ERR(pg->pdr)) {
-               ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr), "failed to initialize pdr\n");
-               goto out_release_aux_devices;
-       }
-
        service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd");
        if (IS_ERR(service)) {
                ret = dev_err_probe(&pdev->dev, PTR_ERR(service),
                                    "failed adding pdr lookup for charger_pd\n");
-               goto out_release_pdr_handle;
+               goto out_release_aux_devices;
        }
 
        mutex_lock(&__pmic_glink_lock);
@@ -300,8 +301,6 @@ static int pmic_glink_probe(struct platform_device *pdev)
 
        return 0;
 
-out_release_pdr_handle:
-       pdr_handle_release(pg->pdr);
 out_release_aux_devices:
        if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
                pmic_glink_del_aux_device(pg, &pg->ps_aux);
@@ -311,6 +310,8 @@ out_release_altmode_aux:
 out_release_ucsi_aux:
        if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
                pmic_glink_del_aux_device(pg, &pg->ucsi_aux);
+out_release_pdr_handle:
+       pdr_handle_release(pg->pdr);
 
        return ret;
 }
index 5fcd0fdd2faa2d087fc03e001dffe4f5016c80a9..b3808fc24c695e89fa10f46b93e0fcfabc3b4d61 100644 (file)
@@ -76,7 +76,7 @@ struct pmic_glink_altmode_port {
 
        struct work_struct work;
 
-       struct device *bridge;
+       struct auxiliary_device *bridge;
 
        enum typec_orientation orientation;
        u16 svid;
@@ -230,7 +230,7 @@ static void pmic_glink_altmode_worker(struct work_struct *work)
        else
                pmic_glink_altmode_enable_usb(altmode, alt_port);
 
-       drm_aux_hpd_bridge_notify(alt_port->bridge,
+       drm_aux_hpd_bridge_notify(&alt_port->bridge->dev,
                                  alt_port->hpd_state ?
                                  connector_status_connected :
                                  connector_status_disconnected);
@@ -454,7 +454,7 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
                alt_port->index = port;
                INIT_WORK(&alt_port->work, pmic_glink_altmode_worker);
 
-               alt_port->bridge = drm_dp_hpd_bridge_register(dev, to_of_node(fwnode));
+               alt_port->bridge = devm_drm_dp_hpd_bridge_alloc(dev, to_of_node(fwnode));
                if (IS_ERR(alt_port->bridge)) {
                        fwnode_handle_put(fwnode);
                        return PTR_ERR(alt_port->bridge);
@@ -510,6 +510,16 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
                }
        }
 
+       for (port = 0; port < ARRAY_SIZE(altmode->ports); port++) {
+               alt_port = &altmode->ports[port];
+               if (!alt_port->bridge)
+                       continue;
+
+               ret = devm_drm_dp_hpd_bridge_add(dev, alt_port->bridge);
+               if (ret)
+                       return ret;
+       }
+
        altmode->client = devm_pmic_glink_register_client(dev,
                                                          altmode->owner_id,
                                                          pmic_glink_altmode_callback,
index bdcf44b85b2f2704a0cdfff6c5f370ab9ba32c4a..2e8f24d5da80b6aadbdacfcc0c36d7cf9a4e92a1 100644 (file)
@@ -89,7 +89,6 @@
  * @base:              Base address of this instance of QUP wrapper core
  * @clks:              Handle to the primary & optional secondary AHB clocks
  * @num_clks:          Count of clocks
- * @to_core:           Core ICC path
  */
 struct geni_wrapper {
        struct device *dev;
diff --git a/drivers/soc/qcom/qcom-pbs.c b/drivers/soc/qcom/qcom-pbs.c
new file mode 100644 (file)
index 0000000..6af49b5
--- /dev/null
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/spmi.h>
+#include <linux/soc/qcom/qcom-pbs.h>
+
+#define PBS_CLIENT_TRIG_CTL            0x42
+#define PBS_CLIENT_SW_TRIG_BIT         BIT(7)
+#define PBS_CLIENT_SCRATCH1            0x50
+#define PBS_CLIENT_SCRATCH2            0x51
+#define PBS_CLIENT_SCRATCH2_ERROR      0xFF
+
+#define RETRIES                                2000
+#define DELAY                          1100
+
+struct pbs_dev {
+       struct device           *dev;
+       struct regmap           *regmap;
+       struct mutex            lock;
+       struct device_link      *link;
+
+       u32                     base;
+};
+
+static int qcom_pbs_wait_for_ack(struct pbs_dev *pbs, u8 bit_pos)
+{
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read_poll_timeout(pbs->regmap,  pbs->base + PBS_CLIENT_SCRATCH2,
+                                      val, val & BIT(bit_pos), DELAY, DELAY * RETRIES);
+
+       if (ret < 0) {
+               dev_err(pbs->dev, "Timeout for PBS ACK/NACK for bit %u\n", bit_pos);
+               return -ETIMEDOUT;
+       }
+
+       if (val == PBS_CLIENT_SCRATCH2_ERROR) {
+               ret = regmap_write(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, 0);
+               dev_err(pbs->dev, "NACK from PBS for bit %u\n", bit_pos);
+               return -EINVAL;
+       }
+
+       dev_dbg(pbs->dev, "PBS sequence for bit %u executed!\n", bit_pos);
+       return 0;
+}
+
+/**
+ * qcom_pbs_trigger_event() - Trigger the PBS RAM sequence
+ * @pbs: Pointer to PBS device
+ * @bitmap: bitmap
+ *
+ * This function is used to trigger the PBS RAM sequence to be
+ * executed by the client driver.
+ *
+ * The PBS trigger sequence involves
+ * 1. setting the PBS sequence bit in PBS_CLIENT_SCRATCH1
+ * 2. Initiating the SW PBS trigger
+ * 3. Checking the equivalent bit in PBS_CLIENT_SCRATCH2 for the
+ *    completion of the sequence.
+ * 4. If PBS_CLIENT_SCRATCH2 == 0xFF, the PBS sequence failed to execute
+ *
+ * Return: 0 on success, < 0 on failure
+ */
+int qcom_pbs_trigger_event(struct pbs_dev *pbs, u8 bitmap)
+{
+       unsigned int val;
+       u16 bit_pos;
+       int ret;
+
+       if (WARN_ON(!bitmap))
+               return -EINVAL;
+
+       if (IS_ERR_OR_NULL(pbs))
+               return -EINVAL;
+
+       mutex_lock(&pbs->lock);
+       ret = regmap_read(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, &val);
+       if (ret < 0)
+               goto out;
+
+       if (val == PBS_CLIENT_SCRATCH2_ERROR) {
+               /* PBS error - clear SCRATCH2 register */
+               ret = regmap_write(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, 0);
+               if (ret < 0)
+                       goto out;
+       }
+
+       for (bit_pos = 0; bit_pos < 8; bit_pos++) {
+               if (!(bitmap & BIT(bit_pos)))
+                       continue;
+
+               /* Clear the PBS sequence bit position */
+               ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2,
+                                        BIT(bit_pos), 0);
+               if (ret < 0)
+                       goto out_clear_scratch1;
+
+               /* Set the PBS sequence bit position */
+               ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1,
+                                        BIT(bit_pos), BIT(bit_pos));
+               if (ret < 0)
+                       goto out_clear_scratch1;
+
+               /* Initiate the SW trigger */
+               ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_TRIG_CTL,
+                                        PBS_CLIENT_SW_TRIG_BIT, PBS_CLIENT_SW_TRIG_BIT);
+               if (ret < 0)
+                       goto out_clear_scratch1;
+
+               ret = qcom_pbs_wait_for_ack(pbs, bit_pos);
+               if (ret < 0)
+                       goto out_clear_scratch1;
+
+               /* Clear the PBS sequence bit position */
+               regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1, BIT(bit_pos), 0);
+               regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0);
+       }
+
+out_clear_scratch1:
+       /* Clear all the requested bitmap */
+       ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1, bitmap, 0);
+
+out:
+       mutex_unlock(&pbs->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_pbs_trigger_event);
+
+/**
+ * get_pbs_client_device() - Get the PBS device used by client
+ * @dev: Client device
+ *
+ * This function is used to get the PBS device that is being
+ * used by the client.
+ *
+ * Return: pbs_dev on success, ERR_PTR on failure
+ */
+struct pbs_dev *get_pbs_client_device(struct device *dev)
+{
+       struct device_node *pbs_dev_node;
+       struct platform_device *pdev;
+       struct pbs_dev *pbs;
+
+       pbs_dev_node = of_parse_phandle(dev->of_node, "qcom,pbs", 0);
+       if (!pbs_dev_node) {
+               dev_err(dev, "Missing qcom,pbs property\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       pdev = of_find_device_by_node(pbs_dev_node);
+       if (!pdev) {
+               dev_err(dev, "Unable to find PBS dev_node\n");
+               pbs = ERR_PTR(-EPROBE_DEFER);
+               goto out;
+       }
+
+       pbs = platform_get_drvdata(pdev);
+       if (!pbs) {
+               dev_err(dev, "Cannot get pbs instance from %s\n", dev_name(&pdev->dev));
+               platform_device_put(pdev);
+               pbs = ERR_PTR(-EPROBE_DEFER);
+               goto out;
+       }
+
+       pbs->link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
+       if (!pbs->link) {
+               dev_err(&pdev->dev, "Failed to create device link to consumer %s\n", dev_name(dev));
+               platform_device_put(pdev);
+               pbs = ERR_PTR(-EINVAL);
+               goto out;
+       }
+
+out:
+       of_node_put(pbs_dev_node);
+       return pbs;
+}
+EXPORT_SYMBOL_GPL(get_pbs_client_device);
+
+static int qcom_pbs_probe(struct platform_device *pdev)
+{
+       struct pbs_dev *pbs;
+       u32 val;
+       int ret;
+
+       pbs = devm_kzalloc(&pdev->dev, sizeof(*pbs), GFP_KERNEL);
+       if (!pbs)
+               return -ENOMEM;
+
+       pbs->dev = &pdev->dev;
+       pbs->regmap = dev_get_regmap(pbs->dev->parent, NULL);
+       if (!pbs->regmap) {
+               dev_err(pbs->dev, "Couldn't get parent's regmap\n");
+               return -EINVAL;
+       }
+
+       ret = device_property_read_u32(pbs->dev, "reg", &val);
+       if (ret < 0) {
+               dev_err(pbs->dev, "Couldn't find reg, ret = %d\n", ret);
+               return ret;
+       }
+       pbs->base = val;
+       mutex_init(&pbs->lock);
+
+       platform_set_drvdata(pdev, pbs);
+
+       return 0;
+}
+
+static const struct of_device_id qcom_pbs_match_table[] = {
+       { .compatible = "qcom,pbs" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, qcom_pbs_match_table);
+
+static struct platform_driver qcom_pbs_driver = {
+       .driver = {
+               .name           = "qcom-pbs",
+               .of_match_table = qcom_pbs_match_table,
+       },
+       .probe = qcom_pbs_probe,
+};
+module_platform_driver(qcom_pbs_driver)
+
+MODULE_DESCRIPTION("QCOM PBS DRIVER");
+MODULE_LICENSE("GPL");
index aff0cfb71482026e116a9b70812034da35d520c8..ca2f6b7629ce0388f5263b548c3864a4a3529318 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (c) 2019, Linaro Ltd
  */
 #include <linux/clk-provider.h>
+#include <linux/debugfs.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/mailbox_client.h>
@@ -13,6 +14,9 @@
 #include <linux/slab.h>
 #include <linux/soc/qcom/qcom_aoss.h>
 
+#define CREATE_TRACE_POINTS
+#include "trace-aoss.h"
+
 #define QMP_DESC_MAGIC                 0x0
 #define QMP_DESC_VERSION               0x4
 #define QMP_DESC_FEATURES              0x8
@@ -44,6 +48,8 @@
 
 #define QMP_NUM_COOLING_RESOURCES      2
 
+#define QMP_DEBUGFS_FILES              4
+
 static bool qmp_cdev_max_state = 1;
 
 struct qmp_cooling_device {
@@ -65,6 +71,8 @@ struct qmp_cooling_device {
  * @tx_lock: provides synchronization between multiple callers of qmp_send()
  * @qdss_clk: QDSS clock hw struct
  * @cooling_devs: thermal cooling devices
+ * @debugfs_root: directory for the developer/tester interface
+ * @debugfs_files: array of individual debugfs entries under debugfs_root
  */
 struct qmp {
        void __iomem *msgram;
@@ -82,6 +90,8 @@ struct qmp {
 
        struct clk_hw qdss_clk;
        struct qmp_cooling_device *cooling_devs;
+       struct dentry *debugfs_root;
+       struct dentry *debugfs_files[QMP_DEBUGFS_FILES];
 };
 
 static void qmp_kick(struct qmp *qmp)
@@ -214,7 +224,7 @@ static bool qmp_message_empty(struct qmp *qmp)
  *
  * Return: 0 on success, negative errno on failure
  */
-int qmp_send(struct qmp *qmp, const char *fmt, ...)
+int __printf(2, 3) qmp_send(struct qmp *qmp, const char *fmt, ...)
 {
        char buf[QMP_MSG_LEN];
        long time_left;
@@ -235,6 +245,8 @@ int qmp_send(struct qmp *qmp, const char *fmt, ...)
 
        mutex_lock(&qmp->tx_lock);
 
+       trace_aoss_send(buf);
+
        /* The message RAM only implements 32-bit accesses */
        __iowrite32_copy(qmp->msgram + qmp->offset + sizeof(u32),
                         buf, sizeof(buf) / sizeof(u32));
@@ -256,6 +268,8 @@ int qmp_send(struct qmp *qmp, const char *fmt, ...)
                ret = 0;
        }
 
+       trace_aoss_send_done(buf, ret);
+
        mutex_unlock(&qmp->tx_lock);
 
        return ret;
@@ -475,6 +489,91 @@ void qmp_put(struct qmp *qmp)
 }
 EXPORT_SYMBOL_GPL(qmp_put);
 
+struct qmp_debugfs_entry {
+       const char *name;
+       const char *fmt;
+       bool is_bool;
+       const char *true_val;
+       const char *false_val;
+};
+
+static const struct qmp_debugfs_entry qmp_debugfs_entries[QMP_DEBUGFS_FILES] = {
+       { "ddr_frequency_mhz", "{class: ddr, res: fixed, val: %u}", false },
+       { "prevent_aoss_sleep", "{class: aoss_slp, res: sleep: %s}", true, "enable", "disable" },
+       { "prevent_cx_collapse", "{class: cx_mol, res: cx, val: %s}", true, "mol", "off" },
+       { "prevent_ddr_collapse", "{class: ddr_mol, res: ddr, val: %s}", true, "mol", "off" },
+};
+
+static ssize_t qmp_debugfs_write(struct file *file, const char __user *user_buf,
+                                size_t count, loff_t *pos)
+{
+       const struct qmp_debugfs_entry *entry = NULL;
+       struct qmp *qmp = file->private_data;
+       char buf[QMP_MSG_LEN];
+       unsigned int uint_val;
+       const char *str_val;
+       bool bool_val;
+       int ret;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(qmp->debugfs_files); i++) {
+               if (qmp->debugfs_files[i] == file->f_path.dentry) {
+                       entry = &qmp_debugfs_entries[i];
+                       break;
+               }
+       }
+       if (WARN_ON(!entry))
+               return -EFAULT;
+
+       if (entry->is_bool) {
+               ret = kstrtobool_from_user(user_buf, count, &bool_val);
+               if (ret)
+                       return ret;
+
+               str_val = bool_val ? entry->true_val : entry->false_val;
+
+               ret = snprintf(buf, sizeof(buf), entry->fmt, str_val);
+               if (ret >= sizeof(buf))
+                       return -EINVAL;
+       } else {
+               ret = kstrtou32_from_user(user_buf, count, 0, &uint_val);
+               if (ret)
+                       return ret;
+
+               ret = snprintf(buf, sizeof(buf), entry->fmt, uint_val);
+               if (ret >= sizeof(buf))
+                       return -EINVAL;
+       }
+
+       ret = qmp_send(qmp, buf);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static const struct file_operations qmp_debugfs_fops = {
+       .open = simple_open,
+       .write = qmp_debugfs_write,
+};
+
+static void qmp_debugfs_create(struct qmp *qmp)
+{
+       const struct qmp_debugfs_entry *entry;
+       int i;
+
+       qmp->debugfs_root = debugfs_create_dir("qcom_aoss", NULL);
+
+       for (i = 0; i < ARRAY_SIZE(qmp->debugfs_files); i++) {
+               entry = &qmp_debugfs_entries[i];
+
+               qmp->debugfs_files[i] = debugfs_create_file(entry->name, 0200,
+                                                           qmp->debugfs_root,
+                                                           qmp,
+                                                           &qmp_debugfs_fops);
+       }
+}
+
 static int qmp_probe(struct platform_device *pdev)
 {
        struct qmp *qmp;
@@ -523,6 +622,8 @@ static int qmp_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, qmp);
 
+       qmp_debugfs_create(qmp);
+
        return 0;
 
 err_close_qmp:
@@ -537,6 +638,8 @@ static void qmp_remove(struct platform_device *pdev)
 {
        struct qmp *qmp = platform_get_drvdata(pdev);
 
+       debugfs_remove_recursive(qmp->debugfs_root);
+
        qmp_qdss_clk_remove(qmp);
        qmp_cooling_devices_remove(qmp);
 
index 690afc9a12f4ca37fb245cb7e43e8f66d9508f0f..7191fa0c087f2ba278863944f3b9dbe5373fb6af 100644 (file)
@@ -655,8 +655,6 @@ invalid_canary:
 void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
 {
        struct smem_partition *part;
-       unsigned long flags;
-       int ret;
        void *ptr = ERR_PTR(-EPROBE_DEFER);
 
        if (!__smem)
@@ -665,12 +663,6 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
        if (WARN_ON(item >= __smem->item_count))
                return ERR_PTR(-EINVAL);
 
-       ret = hwspin_lock_timeout_irqsave(__smem->hwlock,
-                                         HWSPINLOCK_TIMEOUT,
-                                         &flags);
-       if (ret)
-               return ERR_PTR(ret);
-
        if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
                part = &__smem->partitions[host];
                ptr = qcom_smem_get_private(__smem, part, item, size);
@@ -681,10 +673,7 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
                ptr = qcom_smem_get_global(__smem, item, size);
        }
 
-       hwspin_unlock_irqrestore(__smem->hwlock, &flags);
-
        return ptr;
-
 }
 EXPORT_SYMBOL_GPL(qcom_smem_get);
 
index 914b2246148fcb4c44ec3e267bb41868761e2b9c..a21241cbeec7bab72ab89eec731f7fbf2aaec502 100644 (file)
@@ -58,8 +58,8 @@
  * @valid_entries:     number of allocated entries
  * @flags:
  * @entries:           individual communication entries
- *     @name:          name of the entry
- *     @value:         content of the entry
+ * @entries.name:      name of the entry
+ * @entries.value:     content of the entry
  */
 struct smp2p_smem_item {
        u32 magic;
@@ -275,6 +275,8 @@ static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p)
  *
  * Handle notifications from the remote side to handle newly allocated entries
  * or any changes to the state bits of existing entries.
+ *
+ * Return: %IRQ_HANDLED
  */
 static irqreturn_t qcom_smp2p_intr(int irq, void *data)
 {
index 6349a0debeb576ca82302412b552f7017e28e245..e8ff9819ac47746b1a93b791d48c9599699327de 100644 (file)
@@ -124,7 +124,7 @@ static const char *const pmic_models[] = {
        [50] = "PM8350B",
        [51] = "PMR735A",
        [52] = "PMR735B",
-       [55] = "PM2250",
+       [55] = "PM4125",
        [58] = "PM8450",
        [65] = "PM8010",
        [69] = "PM8550VS",
@@ -424,8 +424,11 @@ static const struct soc_id soc_id[] = {
        { qcom_board_id(IPQ9510) },
        { qcom_board_id(QRB4210) },
        { qcom_board_id(QRB2210) },
+       { qcom_board_id(SM8475) },
+       { qcom_board_id(SM8475P) },
        { qcom_board_id(SA8775P) },
        { qcom_board_id(QRU1000) },
+       { qcom_board_id(SM8475_2) },
        { qcom_board_id(QDU1000) },
        { qcom_board_id(SM8650) },
        { qcom_board_id(SM4450) },
@@ -437,6 +440,8 @@ static const struct soc_id soc_id[] = {
        { qcom_board_id(IPQ5322) },
        { qcom_board_id(IPQ5312) },
        { qcom_board_id(IPQ5302) },
+       { qcom_board_id(QCS8550) },
+       { qcom_board_id(QCM8550) },
        { qcom_board_id(IPQ5300) },
 };
 
index 2f0b1bfe7658876b1337124415085d364a8fac0f..06e2c4c2a4a82a89025f6786b39d0a98116e8512 100644 (file)
@@ -6,20 +6,40 @@
  * SAW power controller driver
  */
 
-#include <linux/kernel.h>
+#include <linux/bitfield.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/linear_range.h>
 #include <linux/module.h>
-#include <linux/slab.h>
 #include <linux/of.h>
-#include <linux/err.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+
+#include <linux/regulator/driver.h>
+
 #include <soc/qcom/spm.h>
 
+#define FIELD_SET(current, mask, val)  \
+       (((current) & ~(mask)) | FIELD_PREP((mask), (val)))
+
 #define SPM_CTL_INDEX          0x7f
 #define SPM_CTL_INDEX_SHIFT    4
 #define SPM_CTL_EN             BIT(0)
 
+/* These registers might be specific to SPM 1.1 */
+#define SPM_VCTL_VLVL                  GENMASK(7, 0)
+#define SPM_PMIC_DATA_0_VLVL           GENMASK(7, 0)
+#define SPM_PMIC_DATA_1_MIN_VSEL       GENMASK(5, 0)
+#define SPM_PMIC_DATA_1_MAX_VSEL       GENMASK(21, 16)
+
+#define SPM_1_1_AVS_CTL_AVS_ENABLED    BIT(27)
+#define SPM_AVS_CTL_MAX_VLVL           GENMASK(22, 17)
+#define SPM_AVS_CTL_MIN_VLVL           GENMASK(15, 10)
+
 enum spm_reg {
        SPM_REG_CFG,
        SPM_REG_SPM_CTL,
@@ -29,13 +49,44 @@ enum spm_reg {
        SPM_REG_PMIC_DATA_1,
        SPM_REG_VCTL,
        SPM_REG_SEQ_ENTRY,
-       SPM_REG_SPM_STS,
+       SPM_REG_STS0,
+       SPM_REG_STS1,
        SPM_REG_PMIC_STS,
        SPM_REG_AVS_CTL,
        SPM_REG_AVS_LIMIT,
+       SPM_REG_RST,
        SPM_REG_NR,
 };
 
+#define MAX_PMIC_DATA          2
+#define MAX_SEQ_DATA           64
+
+struct spm_reg_data {
+       const u16 *reg_offset;
+       u32 spm_cfg;
+       u32 spm_dly;
+       u32 pmic_dly;
+       u32 pmic_data[MAX_PMIC_DATA];
+       u32 avs_ctl;
+       u32 avs_limit;
+       u8 seq[MAX_SEQ_DATA];
+       u8 start_index[PM_SLEEP_MODE_NR];
+
+       smp_call_func_t set_vdd;
+       /* for now we support only a single range */
+       struct linear_range *range;
+       unsigned int ramp_delay;
+       unsigned int init_uV;
+};
+
+struct spm_driver_data {
+       void __iomem *reg_base;
+       const struct spm_reg_data *reg_data;
+       struct device *dev;
+       unsigned int volt_sel;
+       int reg_cpu;
+};
+
 static const u16 spm_reg_offset_v4_1[SPM_REG_NR] = {
        [SPM_REG_AVS_CTL]       = 0x904,
        [SPM_REG_AVS_LIMIT]     = 0x908,
@@ -169,6 +220,10 @@ static const struct spm_reg_data spm_reg_8226_cpu  = {
 
 static const u16 spm_reg_offset_v1_1[SPM_REG_NR] = {
        [SPM_REG_CFG]           = 0x08,
+       [SPM_REG_STS0]          = 0x0c,
+       [SPM_REG_STS1]          = 0x10,
+       [SPM_REG_VCTL]          = 0x14,
+       [SPM_REG_AVS_CTL]       = 0x18,
        [SPM_REG_SPM_CTL]       = 0x20,
        [SPM_REG_PMIC_DLY]      = 0x24,
        [SPM_REG_PMIC_DATA_0]   = 0x28,
@@ -176,7 +231,12 @@ static const u16 spm_reg_offset_v1_1[SPM_REG_NR] = {
        [SPM_REG_SEQ_ENTRY]     = 0x80,
 };
 
+static void smp_set_vdd_v1_1(void *data);
+
 /* SPM register data for 8064 */
+static struct linear_range spm_v1_1_regulator_range =
+       REGULATOR_LINEAR_RANGE(700000, 0, 56, 12500);
+
 static const struct spm_reg_data spm_reg_8064_cpu = {
        .reg_offset = spm_reg_offset_v1_1,
        .spm_cfg = 0x1F,
@@ -187,6 +247,10 @@ static const struct spm_reg_data spm_reg_8064_cpu = {
                0x10, 0x54, 0x30, 0x0C, 0x24, 0x30, 0x0F },
        .start_index[PM_SLEEP_MODE_STBY] = 0,
        .start_index[PM_SLEEP_MODE_SPC] = 2,
+       .set_vdd = smp_set_vdd_v1_1,
+       .range = &spm_v1_1_regulator_range,
+       .init_uV = 1300000,
+       .ramp_delay = 1250,
 };
 
 static inline void spm_register_write(struct spm_driver_data *drv,
@@ -238,6 +302,178 @@ void spm_set_low_power_mode(struct spm_driver_data *drv,
        spm_register_write_sync(drv, SPM_REG_SPM_CTL, ctl_val);
 }
 
+static int spm_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
+{
+       struct spm_driver_data *drv = rdev_get_drvdata(rdev);
+
+       drv->volt_sel = selector;
+
+       /* Always do the SAW register writes on the corresponding CPU */
+       return smp_call_function_single(drv->reg_cpu, drv->reg_data->set_vdd, drv, true);
+}
+
+static int spm_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct spm_driver_data *drv = rdev_get_drvdata(rdev);
+
+       return drv->volt_sel;
+}
+
+static const struct regulator_ops spm_reg_ops = {
+       .set_voltage_sel        = spm_set_voltage_sel,
+       .get_voltage_sel        = spm_get_voltage_sel,
+       .list_voltage           = regulator_list_voltage_linear_range,
+       .set_voltage_time_sel   = regulator_set_voltage_time_sel,
+};
+
+static void smp_set_vdd_v1_1(void *data)
+{
+       struct spm_driver_data *drv = data;
+       unsigned int vctl, data0, data1, avs_ctl, sts;
+       unsigned int vlevel, volt_sel;
+       bool avs_enabled;
+
+       volt_sel = drv->volt_sel;
+       vlevel = volt_sel | 0x80; /* band */
+
+       avs_ctl = spm_register_read(drv, SPM_REG_AVS_CTL);
+       vctl = spm_register_read(drv, SPM_REG_VCTL);
+       data0 = spm_register_read(drv, SPM_REG_PMIC_DATA_0);
+       data1 = spm_register_read(drv, SPM_REG_PMIC_DATA_1);
+
+       avs_enabled = avs_ctl & SPM_1_1_AVS_CTL_AVS_ENABLED;
+
+       /* If AVS is enabled, switch it off during the voltage change */
+       if (avs_enabled) {
+               avs_ctl &= ~SPM_1_1_AVS_CTL_AVS_ENABLED;
+               spm_register_write(drv, SPM_REG_AVS_CTL, avs_ctl);
+       }
+
+       /* Kick the state machine back to idle */
+       spm_register_write(drv, SPM_REG_RST, 1);
+
+       vctl = FIELD_SET(vctl, SPM_VCTL_VLVL, vlevel);
+       data0 = FIELD_SET(data0, SPM_PMIC_DATA_0_VLVL, vlevel);
+       data1 = FIELD_SET(data1, SPM_PMIC_DATA_1_MIN_VSEL, volt_sel);
+       data1 = FIELD_SET(data1, SPM_PMIC_DATA_1_MAX_VSEL, volt_sel);
+
+       spm_register_write(drv, SPM_REG_VCTL, vctl);
+       spm_register_write(drv, SPM_REG_PMIC_DATA_0, data0);
+       spm_register_write(drv, SPM_REG_PMIC_DATA_1, data1);
+
+       if (read_poll_timeout_atomic(spm_register_read,
+                                    sts, sts == vlevel,
+                                    1, 200, false,
+                                    drv, SPM_REG_STS1)) {
+               dev_err_ratelimited(drv->dev, "timeout setting the voltage (%x %x)!\n", sts, vlevel);
+               goto enable_avs;
+       }
+
+       if (avs_enabled) {
+               unsigned int max_avs = volt_sel;
+               unsigned int min_avs = max(max_avs, 4U) - 4;
+
+               avs_ctl = FIELD_SET(avs_ctl, SPM_AVS_CTL_MIN_VLVL, min_avs);
+               avs_ctl = FIELD_SET(avs_ctl, SPM_AVS_CTL_MAX_VLVL, max_avs);
+               spm_register_write(drv, SPM_REG_AVS_CTL, avs_ctl);
+       }
+
+enable_avs:
+       if (avs_enabled) {
+               avs_ctl |= SPM_1_1_AVS_CTL_AVS_ENABLED;
+               spm_register_write(drv, SPM_REG_AVS_CTL, avs_ctl);
+       }
+}
+
+static int spm_get_cpu(struct device *dev)
+{
+       int cpu;
+       bool found;
+
+       for_each_possible_cpu(cpu) {
+               struct device_node *cpu_node, *saw_node;
+
+               cpu_node = of_cpu_device_node_get(cpu);
+               if (!cpu_node)
+                       continue;
+
+               saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
+               found = (saw_node == dev->of_node);
+               of_node_put(saw_node);
+               of_node_put(cpu_node);
+
+               if (found)
+                       return cpu;
+       }
+
+       /* L2 SPM is not bound to any CPU, voltage setting is not supported */
+
+       return -EOPNOTSUPP;
+}
+
+static int spm_register_regulator(struct device *dev, struct spm_driver_data *drv)
+{
+       struct regulator_config config = {
+               .dev = dev,
+               .driver_data = drv,
+       };
+       struct regulator_desc *rdesc;
+       struct regulator_dev *rdev;
+       int ret;
+       bool found;
+
+       if (!drv->reg_data->set_vdd)
+               return 0;
+
+       rdesc = devm_kzalloc(dev, sizeof(*rdesc), GFP_KERNEL);
+       if (!rdesc)
+               return -ENOMEM;
+
+       rdesc->name = "spm";
+       rdesc->of_match = of_match_ptr("regulator");
+       rdesc->type = REGULATOR_VOLTAGE;
+       rdesc->owner = THIS_MODULE;
+       rdesc->ops = &spm_reg_ops;
+
+       rdesc->linear_ranges = drv->reg_data->range;
+       rdesc->n_linear_ranges = 1;
+       rdesc->n_voltages = rdesc->linear_ranges[rdesc->n_linear_ranges - 1].max_sel + 1;
+       rdesc->ramp_delay = drv->reg_data->ramp_delay;
+
+       ret = spm_get_cpu(dev);
+       if (ret < 0)
+               return ret;
+
+       drv->reg_cpu = ret;
+       dev_dbg(dev, "SAW2 bound to CPU %d\n", drv->reg_cpu);
+
+       /*
+        * Program initial voltage, otherwise registration will also try
+        * setting the voltage, which might result in undervolting the CPU.
+        */
+       drv->volt_sel = DIV_ROUND_UP(drv->reg_data->init_uV - rdesc->min_uV,
+                                    rdesc->uV_step);
+       ret = linear_range_get_selector_high(drv->reg_data->range,
+                                            drv->reg_data->init_uV,
+                                            &drv->volt_sel,
+                                            &found);
+       if (ret) {
+               dev_err(dev, "Initial uV value out of bounds\n");
+               return ret;
+       }
+
+       /* Always do the SAW register writes on the corresponding CPU */
+       smp_call_function_single(drv->reg_cpu, drv->reg_data->set_vdd, drv, true);
+
+       rdev = devm_regulator_register(dev, rdesc, &config);
+       if (IS_ERR(rdev)) {
+               dev_err(dev, "failed to register regulator\n");
+               return PTR_ERR(rdev);
+       }
+
+       return 0;
+}
+
 static const struct of_device_id spm_match_table[] = {
        { .compatible = "qcom,sdm660-gold-saw2-v4.1-l2",
          .data = &spm_reg_660_gold_l2 },
@@ -288,6 +524,7 @@ static int spm_dev_probe(struct platform_device *pdev)
                return -ENODEV;
 
        drv->reg_data = match_id->data;
+       drv->dev = &pdev->dev;
        platform_set_drvdata(pdev, drv);
 
        /* Write the SPM sequences first.. */
@@ -315,6 +552,9 @@ static int spm_dev_probe(struct platform_device *pdev)
        if (drv->reg_data->reg_offset[SPM_REG_SPM_CTL])
                spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY);
 
+       if (IS_ENABLED(CONFIG_REGULATOR))
+               return spm_register_regulator(&pdev->dev, drv);
+
        return 0;
 }
 
diff --git a/drivers/soc/qcom/trace-aoss.h b/drivers/soc/qcom/trace-aoss.h
new file mode 100644 (file)
index 0000000..554029b
--- /dev/null
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM qcom_aoss
+
+#if !defined(_TRACE_QCOM_AOSS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_QCOM_AOSS_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(aoss_send,
+       TP_PROTO(const char *msg),
+       TP_ARGS(msg),
+       TP_STRUCT__entry(
+               __string(msg, msg)
+       ),
+       TP_fast_assign(
+               __assign_str(msg, msg);
+       ),
+       TP_printk("%s", __get_str(msg))
+);
+
+TRACE_EVENT(aoss_send_done,
+       TP_PROTO(const char *msg, int ret),
+       TP_ARGS(msg, ret),
+       TP_STRUCT__entry(
+               __string(msg, msg)
+               __field(int, ret)
+       ),
+       TP_fast_assign(
+               __assign_str(msg, msg);
+               __entry->ret = ret;
+       ),
+       TP_printk("%s: %d", __get_str(msg), __entry->ret)
+);
+
+#endif /* _TRACE_QCOM_AOSS_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace-aoss
+
+#include <trace/define_trace.h>
index 0986672f63757663e2e4401bc96a81406b6c13f7..5deca747fb7717448107d0b3e7a9102c23760c69 100644 (file)
@@ -34,6 +34,10 @@ config ARCH_RCAR_GEN3
        select SYS_SUPPORTS_SH_CMT
        select SYS_SUPPORTS_SH_TMU
 
+config ARCH_RCAR_GEN4
+       bool
+       select ARCH_RCAR_GEN3
+
 config ARCH_RMOBILE
        bool
        select PM
@@ -240,7 +244,7 @@ config ARCH_R8A77961
 
 config ARCH_R8A779F0
        bool "ARM64 Platform support for R-Car S4-8"
-       select ARCH_RCAR_GEN3
+       select ARCH_RCAR_GEN4
        select SYSC_R8A779F0
        help
          This enables support for the Renesas R-Car S4-8 SoC.
@@ -261,18 +265,25 @@ config ARCH_R8A77970
 
 config ARCH_R8A779A0
        bool "ARM64 Platform support for R-Car V3U"
-       select ARCH_RCAR_GEN3
+       select ARCH_RCAR_GEN4
        select SYSC_R8A779A0
        help
          This enables support for the Renesas R-Car V3U SoC.
 
 config ARCH_R8A779G0
        bool "ARM64 Platform support for R-Car V4H"
-       select ARCH_RCAR_GEN3
+       select ARCH_RCAR_GEN4
        select SYSC_R8A779G0
        help
          This enables support for the Renesas R-Car V4H SoC.
 
+config ARCH_R8A779H0
+       bool "ARM64 Platform support for R-Car V4M"
+       select ARCH_RCAR_GEN4
+       select SYSC_R8A779H0
+       help
+         This enables support for the Renesas R-Car V4M SoC.
+
 config ARCH_R8A774C0
        bool "ARM64 Platform support for RZ/G2E"
        select ARCH_RCAR_GEN3
index 98fd97da6cd4330dcd1673a2f7d775937e80e174..7ba02f3a4a4fbb9fc41f7c08d5a438de7f16569e 100644 (file)
@@ -117,6 +117,7 @@ static const struct of_device_id rcar_rst_matches[] __initconst = {
        { .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_v3u },
        { .compatible = "renesas,r8a779f0-rst", .data = &rcar_rst_gen4 },
        { .compatible = "renesas,r8a779g0-rst", .data = &rcar_rst_gen4 },
+       { .compatible = "renesas,r8a779h0-rst", .data = &rcar_rst_gen4 },
        { /* sentinel */ }
 };
 
index 27eae1a354ab23296fea4a873d72b038c323b290..8f9b8d3736dcdb47b5f06f03dd8ea4217ae13ed8 100644 (file)
@@ -270,6 +270,11 @@ static const struct renesas_soc soc_rcar_v4h __initconst __maybe_unused = {
        .id     = 0x5c,
 };
 
+static const struct renesas_soc soc_rcar_v4m __initconst __maybe_unused = {
+       .family = &fam_rcar_gen4,
+       .id     = 0x5d,
+};
+
 static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = {
        .family = &fam_shmobile,
        .id     = 0x37,
@@ -380,6 +385,9 @@ static const struct of_device_id renesas_socs[] __initconst __maybe_unused = {
 #ifdef CONFIG_ARCH_R8A779G0
        { .compatible = "renesas,r8a779g0",     .data = &soc_rcar_v4h },
 #endif
+#ifdef CONFIG_ARCH_R8A779H0
+       { .compatible = "renesas,r8a779h0",     .data = &soc_rcar_v4m },
+#endif
 #ifdef CONFIG_ARCH_R9A07G043
 #ifdef CONFIG_RISCV
        { .compatible = "renesas,r9a07g043",    .data = &soc_rz_five },
index 27ec99af77e33adecd883cd9949f38415945153d..1a5dfdc978dc4069eb71c4e8eada7ff1913b86b3 100644 (file)
@@ -42,6 +42,7 @@ config EXYNOS_PMU
        depends on ARCH_EXYNOS || ((ARM || ARM64) && COMPILE_TEST)
        select EXYNOS_PMU_ARM_DRIVERS if ARM && ARCH_EXYNOS
        select MFD_CORE
+       select REGMAP_MMIO
 
 # There is no need to enable these drivers for ARMv8
 config EXYNOS_PMU_ARM_DRIVERS
index 250537d7cfd64555de47cc5369776c3ebd0d715e..fd8b6ac066562ff1415f561e17e893e607fff497 100644 (file)
@@ -5,6 +5,7 @@
 //
 // Exynos - CPU PMU(Power Management Unit) support
 
+#include <linux/arm-smccc.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/mfd/core.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
+#include <linux/regmap.h>
 
 #include <linux/soc/samsung/exynos-regs-pmu.h>
 #include <linux/soc/samsung/exynos-pmu.h>
 
 #include "exynos-pmu.h"
 
+#define PMUALIVE_MASK                  GENMASK(13, 0)
+#define TENSOR_SET_BITS                        (BIT(15) | BIT(14))
+#define TENSOR_CLR_BITS                        BIT(15)
+#define TENSOR_SMC_PMU_SEC_REG         0x82000504
+#define TENSOR_PMUREG_READ             0
+#define TENSOR_PMUREG_WRITE            1
+#define TENSOR_PMUREG_RMW              2
+
 struct exynos_pmu_context {
        struct device *dev;
        const struct exynos_pmu_data *pmu_data;
+       struct regmap *pmureg;
 };
 
 void __iomem *pmu_base_addr;
 static struct exynos_pmu_context *pmu_context;
+/* forward declaration */
+static struct platform_driver exynos_pmu_driver;
+
+/*
+ * Tensor SoCs are configured so that PMU_ALIVE registers can only be written
+ * from EL3, but are still read accessible. As Linux needs to write some of
+ * these registers, the following functions are provided and exposed via
+ * regmap.
+ *
+ * Note: This SMC interface is known to be implemented on gs101 and derivative
+ * SoCs.
+ */
+
+/* Write to a protected PMU register. */
+static int tensor_sec_reg_write(void *context, unsigned int reg,
+                               unsigned int val)
+{
+       struct arm_smccc_res res;
+       unsigned long pmu_base = (unsigned long)context;
+
+       arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg,
+                     TENSOR_PMUREG_WRITE, val, 0, 0, 0, 0, &res);
+
+       /* returns -EINVAL if access isn't allowed or 0 */
+       if (res.a0)
+               pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0);
+
+       return (int)res.a0;
+}
+
+/* Read/Modify/Write a protected PMU register. */
+static int tensor_sec_reg_rmw(void *context, unsigned int reg,
+                             unsigned int mask, unsigned int val)
+{
+       struct arm_smccc_res res;
+       unsigned long pmu_base = (unsigned long)context;
+
+       arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg,
+                     TENSOR_PMUREG_RMW, mask, val, 0, 0, 0, &res);
+
+       /* returns -EINVAL if access isn't allowed or 0 */
+       if (res.a0)
+               pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0);
+
+       return (int)res.a0;
+}
+
+/*
+ * Read a protected PMU register. All PMU registers can be read by Linux.
+ * Note: The SMC read register is not used, as only registers that can be
+ * written are readable via SMC.
+ */
+static int tensor_sec_reg_read(void *context, unsigned int reg,
+                              unsigned int *val)
+{
+       *val = pmu_raw_readl(reg);
+       return 0;
+}
+
+/*
+ * For SoCs that have set/clear bit hardware this function can be used when
+ * the PMU register will be accessed by multiple masters.
+ *
+ * For example, to set bits 13:8 in PMU reg offset 0x3e80
+ * tensor_set_bits_atomic(ctx, 0x3e80, 0x3f00, 0x3f00);
+ *
+ * Set bit 8, and clear bits 13:9 PMU reg offset 0x3e80
+ * tensor_set_bits_atomic(0x3e80, 0x100, 0x3f00);
+ */
+static int tensor_set_bits_atomic(void *ctx, unsigned int offset, u32 val,
+                                 u32 mask)
+{
+       int ret;
+       unsigned int i;
+
+       for (i = 0; i < 32; i++) {
+               if (!(mask & BIT(i)))
+                       continue;
+
+               offset &= ~TENSOR_SET_BITS;
+
+               if (val & BIT(i))
+                       offset |= TENSOR_SET_BITS;
+               else
+                       offset |= TENSOR_CLR_BITS;
+
+               ret = tensor_sec_reg_write(ctx, offset, i);
+               if (ret)
+                       return ret;
+       }
+       return ret;
+}
+
+static int tensor_sec_update_bits(void *ctx, unsigned int reg,
+                                 unsigned int mask, unsigned int val)
+{
+       /*
+        * Use atomic operations for PMU_ALIVE registers (offset 0~0x3FFF)
+        * as the target registers can be accessed by multiple masters.
+        */
+       if (reg > PMUALIVE_MASK)
+               return tensor_sec_reg_rmw(ctx, reg, mask, val);
+
+       return tensor_set_bits_atomic(ctx, reg, val, mask);
+}
 
 void pmu_raw_writel(u32 val, u32 offset)
 {
@@ -75,11 +191,41 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode)
 #define exynos_pmu_data_arm_ptr(data)  NULL
 #endif
 
+static const struct regmap_config regmap_smccfg = {
+       .name = "pmu_regs",
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .fast_io = true,
+       .use_single_read = true,
+       .use_single_write = true,
+       .reg_read = tensor_sec_reg_read,
+       .reg_write = tensor_sec_reg_write,
+       .reg_update_bits = tensor_sec_update_bits,
+};
+
+static const struct regmap_config regmap_mmiocfg = {
+       .name = "pmu_regs",
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .fast_io = true,
+       .use_single_read = true,
+       .use_single_write = true,
+};
+
+static const struct exynos_pmu_data gs101_pmu_data = {
+       .pmu_secure = true
+};
+
 /*
  * PMU platform driver and devicetree bindings.
  */
 static const struct of_device_id exynos_pmu_of_device_ids[] = {
        {
+               .compatible = "google,gs101-pmu",
+               .data = &gs101_pmu_data,
+       }, {
                .compatible = "samsung,exynos3250-pmu",
                .data = exynos_pmu_data_arm_ptr(exynos3250_pmu_data),
        }, {
@@ -113,19 +259,75 @@ static const struct mfd_cell exynos_pmu_devs[] = {
        { .name = "exynos-clkout", },
 };
 
+/**
+ * exynos_get_pmu_regmap() - Obtain pmureg regmap
+ *
+ * Find the pmureg regmap previously configured in probe() and return regmap
+ * pointer.
+ *
+ * Return: A pointer to regmap if found or ERR_PTR error value.
+ */
 struct regmap *exynos_get_pmu_regmap(void)
 {
        struct device_node *np = of_find_matching_node(NULL,
                                                      exynos_pmu_of_device_ids);
        if (np)
-               return syscon_node_to_regmap(np);
+               return exynos_get_pmu_regmap_by_phandle(np, NULL);
        return ERR_PTR(-ENODEV);
 }
 EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap);
 
+/**
+ * exynos_get_pmu_regmap_by_phandle() - Obtain pmureg regmap via phandle
+ * @np: Device node holding PMU phandle property
+ * @propname: Name of property holding phandle value
+ *
+ * Find the pmureg regmap previously configured in probe() and return regmap
+ * pointer.
+ *
+ * Return: A pointer to regmap if found or ERR_PTR error value.
+ */
+struct regmap *exynos_get_pmu_regmap_by_phandle(struct device_node *np,
+                                               const char *propname)
+{
+       struct exynos_pmu_context *ctx;
+       struct device_node *pmu_np;
+       struct device *dev;
+
+       if (propname)
+               pmu_np = of_parse_phandle(np, propname, 0);
+       else
+               pmu_np = np;
+
+       if (!pmu_np)
+               return ERR_PTR(-ENODEV);
+
+       /*
+        * Determine if exynos-pmu device has probed and therefore regmap
+        * has been created and can be returned to the caller. Otherwise we
+        * return -EPROBE_DEFER.
+        */
+       dev = driver_find_device_by_of_node(&exynos_pmu_driver.driver,
+                                           (void *)pmu_np);
+
+       if (propname)
+               of_node_put(pmu_np);
+
+       if (!dev)
+               return ERR_PTR(-EPROBE_DEFER);
+
+       ctx = dev_get_drvdata(dev);
+
+       return ctx->pmureg;
+}
+EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap_by_phandle);
+
 static int exynos_pmu_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       struct regmap_config pmu_regmcfg;
+       struct regmap *regmap;
+       struct resource *res;
        int ret;
 
        pmu_base_addr = devm_platform_ioremap_resource(pdev, 0);
@@ -137,9 +339,38 @@ static int exynos_pmu_probe(struct platform_device *pdev)
                        GFP_KERNEL);
        if (!pmu_context)
                return -ENOMEM;
-       pmu_context->dev = dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
        pmu_context->pmu_data = of_device_get_match_data(dev);
 
+       /* For SoCs that secure PMU register writes use custom regmap */
+       if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_secure) {
+               pmu_regmcfg = regmap_smccfg;
+               pmu_regmcfg.max_register = resource_size(res) -
+                                          pmu_regmcfg.reg_stride;
+               /* Need physical address for SMC call */
+               regmap = devm_regmap_init(dev, NULL,
+                                         (void *)(uintptr_t)res->start,
+                                         &pmu_regmcfg);
+       } else {
+               /* All other SoCs use a MMIO regmap */
+               pmu_regmcfg = regmap_mmiocfg;
+               pmu_regmcfg.max_register = resource_size(res) -
+                                          pmu_regmcfg.reg_stride;
+               regmap = devm_regmap_init_mmio(dev, pmu_base_addr,
+                                              &pmu_regmcfg);
+       }
+
+       if (IS_ERR(regmap))
+               return dev_err_probe(&pdev->dev, PTR_ERR(regmap),
+                                    "regmap init failed\n");
+
+       pmu_context->pmureg = regmap;
+       pmu_context->dev = dev;
+
        if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_init)
                pmu_context->pmu_data->pmu_init();
 
index 1c652ffd79b415520a793d57a2813c6300a8dc4f..0a49a2c9a08ef5bc75670551bdbf6d0a2d3e8ae9 100644 (file)
@@ -21,6 +21,7 @@ struct exynos_pmu_conf {
 struct exynos_pmu_data {
        const struct exynos_pmu_conf *pmu_config;
        const struct exynos_pmu_conf *pmu_config_extra;
+       bool pmu_secure;
 
        void (*pmu_init)(void);
        void (*powerdown_conf)(enum sys_powerdown);
index f16beeabaa92bb890a3174227364bb84d2885b15..33512558af9f7f017a2aa286a3eacb142472f7e5 100644 (file)
@@ -133,6 +133,11 @@ config ARCH_TEGRA_234_SOC
        help
          Enable support for the NVIDIA Tegra234 SoC.
 
+config ARCH_TEGRA_241_SOC
+       bool "NVIDIA Tegra241 SoC"
+       help
+         Enable support for the NVIDIA Tegra241 SoC.
+
 endif
 endif
 
index a2c28f493a75e52a0e620dd5fa35c2636d40d4ae..b6bfd6729df3904adbe5affd1208e59f9a5608dc 100644 (file)
@@ -3,11 +3,13 @@
  * Copyright (c) 2013-2023, NVIDIA CORPORATION.  All rights reserved.
  */
 
+#include <linux/acpi.h>
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/kobject.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/mod_devicetable.h>
 #include <linux/nvmem-consumer.h>
 #include <linux/nvmem-provider.h>
 #include <linux/of.h>
@@ -113,6 +115,28 @@ static void tegra_fuse_restore(void *base)
        fuse->clk = NULL;
 }
 
+static void tegra_fuse_print_sku_info(struct tegra_sku_info *tegra_sku_info)
+{
+       pr_info("Tegra Revision: %s SKU: %d CPU Process: %d SoC Process: %d\n",
+               tegra_revision_name[tegra_sku_info->revision],
+               tegra_sku_info->sku_id, tegra_sku_info->cpu_process_id,
+               tegra_sku_info->soc_process_id);
+       pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n",
+               tegra_sku_info->cpu_speedo_id, tegra_sku_info->soc_speedo_id);
+}
+
+static int tegra_fuse_add_lookups(struct tegra_fuse *fuse)
+{
+       fuse->lookups = kmemdup_array(fuse->soc->lookups, sizeof(*fuse->lookups),
+                                     fuse->soc->num_lookups, GFP_KERNEL);
+       if (!fuse->lookups)
+               return -ENOMEM;
+
+       nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
+
+       return 0;
+}
+
 static int tegra_fuse_probe(struct platform_device *pdev)
 {
        void __iomem *base = fuse->base;
@@ -130,15 +154,46 @@ static int tegra_fuse_probe(struct platform_device *pdev)
                return PTR_ERR(fuse->base);
        fuse->phys = res->start;
 
-       fuse->clk = devm_clk_get(&pdev->dev, "fuse");
-       if (IS_ERR(fuse->clk)) {
-               if (PTR_ERR(fuse->clk) != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
-                               PTR_ERR(fuse->clk));
+       /* Initialize the soc data and lookups if using ACPI boot. */
+       if (is_acpi_node(dev_fwnode(&pdev->dev)) && !fuse->soc) {
+               u8 chip;
 
-               return PTR_ERR(fuse->clk);
+               tegra_acpi_init_apbmisc();
+
+               chip = tegra_get_chip_id();
+               switch (chip) {
+#if defined(CONFIG_ARCH_TEGRA_194_SOC)
+               case TEGRA194:
+                       fuse->soc = &tegra194_fuse_soc;
+                       break;
+#endif
+#if defined(CONFIG_ARCH_TEGRA_234_SOC)
+               case TEGRA234:
+                       fuse->soc = &tegra234_fuse_soc;
+                       break;
+#endif
+#if defined(CONFIG_ARCH_TEGRA_241_SOC)
+               case TEGRA241:
+                       fuse->soc = &tegra241_fuse_soc;
+                       break;
+#endif
+               default:
+                       return dev_err_probe(&pdev->dev, -EINVAL, "Unsupported SoC: %02x\n", chip);
+               }
+
+               fuse->soc->init(fuse);
+               tegra_fuse_print_sku_info(&tegra_sku_info);
+               tegra_soc_device_register();
+
+               err = tegra_fuse_add_lookups(fuse);
+               if (err)
+                       return dev_err_probe(&pdev->dev, err, "failed to add FUSE lookups\n");
        }
 
+       fuse->clk = devm_clk_get_optional(&pdev->dev, "fuse");
+       if (IS_ERR(fuse->clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(fuse->clk), "failed to get FUSE clock\n");
+
        platform_set_drvdata(pdev, fuse);
        fuse->dev = &pdev->dev;
 
@@ -179,12 +234,8 @@ static int tegra_fuse_probe(struct platform_device *pdev)
        }
 
        fuse->rst = devm_reset_control_get_optional(&pdev->dev, "fuse");
-       if (IS_ERR(fuse->rst)) {
-               err = PTR_ERR(fuse->rst);
-               dev_err(&pdev->dev, "failed to get FUSE reset: %pe\n",
-                       fuse->rst);
-               return err;
-       }
+       if (IS_ERR(fuse->rst))
+               return dev_err_probe(&pdev->dev, PTR_ERR(fuse->rst), "failed to get FUSE reset\n");
 
        /*
         * FUSE clock is enabled at a boot time, hence this resume/suspend
@@ -262,10 +313,17 @@ static const struct dev_pm_ops tegra_fuse_pm = {
        SET_SYSTEM_SLEEP_PM_OPS(tegra_fuse_suspend, tegra_fuse_resume)
 };
 
+static const struct acpi_device_id tegra_fuse_acpi_match[] = {
+       { "NVDA200F" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, tegra_fuse_acpi_match);
+
 static struct platform_driver tegra_fuse_driver = {
        .driver = {
                .name = "tegra-fuse",
                .of_match_table = tegra_fuse_match,
+               .acpi_match_table = tegra_fuse_acpi_match,
                .pm = &tegra_fuse_pm,
                .suppress_bind_attrs = true,
        },
@@ -287,7 +345,16 @@ u32 __init tegra_fuse_read_early(unsigned int offset)
 
 int tegra_fuse_readl(unsigned long offset, u32 *value)
 {
-       if (!fuse->read || !fuse->clk)
+       if (!fuse->dev)
+               return -EPROBE_DEFER;
+
+       /*
+        * Wait for fuse->clk to be initialized if device-tree boot is used.
+        */
+       if (is_of_node(dev_fwnode(fuse->dev)) && !fuse->clk)
+               return -EPROBE_DEFER;
+
+       if (!fuse->read)
                return -EPROBE_DEFER;
 
        if (IS_ERR(fuse->clk))
@@ -343,7 +410,8 @@ const struct attribute_group tegra_soc_attr_group = {
 };
 
 #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
-    IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
+    IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) || \
+    IS_ENABLED(CONFIG_ARCH_TEGRA_241_SOC)
 static ssize_t platform_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
@@ -370,7 +438,7 @@ const struct attribute_group tegra194_soc_attr_group = {
 };
 #endif
 
-struct device * __init tegra_soc_device_register(void)
+struct device *tegra_soc_device_register(void)
 {
        struct soc_device_attribute *attr;
        struct soc_device *dev;
@@ -407,6 +475,7 @@ static int __init tegra_init_fuse(void)
        const struct of_device_id *match;
        struct device_node *np;
        struct resource regs;
+       int err;
 
        tegra_init_apbmisc();
 
@@ -497,22 +566,13 @@ static int __init tegra_init_fuse(void)
 
        fuse->soc->init(fuse);
 
-       pr_info("Tegra Revision: %s SKU: %d CPU Process: %d SoC Process: %d\n",
-               tegra_revision_name[tegra_sku_info.revision],
-               tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id,
-               tegra_sku_info.soc_process_id);
-       pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n",
-                tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id);
+       tegra_fuse_print_sku_info(&tegra_sku_info);
 
-       if (fuse->soc->lookups) {
-               size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups;
-
-               fuse->lookups = kmemdup(fuse->soc->lookups, size, GFP_KERNEL);
-               if (fuse->lookups)
-                       nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
-       }
+       err = tegra_fuse_add_lookups(fuse);
+       if (err)
+               pr_err("failed to add FUSE lookups\n");
 
-       return 0;
+       return err;
 }
 early_initcall(tegra_init_fuse);
 
index e94d46372a6396d14ee5dab31f0aa378a18bc9e1..eb14e5ff5a0aa8b5023b742b14e99320b47b7084 100644 (file)
@@ -38,7 +38,8 @@
     defined(CONFIG_ARCH_TEGRA_210_SOC) || \
     defined(CONFIG_ARCH_TEGRA_186_SOC) || \
     defined(CONFIG_ARCH_TEGRA_194_SOC) || \
-    defined(CONFIG_ARCH_TEGRA_234_SOC)
+    defined(CONFIG_ARCH_TEGRA_234_SOC) || \
+    defined(CONFIG_ARCH_TEGRA_241_SOC)
 static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset)
 {
        if (WARN_ON(!fuse->base))
@@ -678,3 +679,23 @@ const struct tegra_fuse_soc tegra234_fuse_soc = {
        .clk_suspend_on = false,
 };
 #endif
+
+#if defined(CONFIG_ARCH_TEGRA_241_SOC)
+static const struct tegra_fuse_info tegra241_fuse_info = {
+       .read = tegra30_fuse_read,
+       .size = 0x16008,
+       .spare = 0xcf0,
+};
+
+static const struct nvmem_keepout tegra241_fuse_keepouts[] = {
+       { .start = 0xc, .end = 0x1600c }
+};
+
+const struct tegra_fuse_soc tegra241_fuse_soc = {
+       .init = tegra30_fuse_init,
+       .info = &tegra241_fuse_info,
+       .keepouts = tegra241_fuse_keepouts,
+       .num_keepouts = ARRAY_SIZE(tegra241_fuse_keepouts),
+       .soc_attr_group = &tegra194_soc_attr_group,
+};
+#endif
index 90f23be738947a5b5ebd7e8dc03e01bdd5d6b434..9fee6ad6ad9e98852c9d47079cdf49433e55fdb7 100644 (file)
@@ -69,6 +69,7 @@ struct tegra_fuse {
 
 void tegra_init_revision(void);
 void tegra_init_apbmisc(void);
+void tegra_acpi_init_apbmisc(void);
 
 u32 __init tegra_fuse_read_spare(unsigned int spare);
 u32 __init tegra_fuse_read_early(unsigned int offset);
@@ -123,7 +124,8 @@ extern const struct tegra_fuse_soc tegra186_fuse_soc;
 #endif
 
 #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
-    IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
+    IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) || \
+    IS_ENABLED(CONFIG_ARCH_TEGRA_241_SOC)
 extern const struct attribute_group tegra194_soc_attr_group;
 #endif
 
@@ -135,4 +137,8 @@ extern const struct tegra_fuse_soc tegra194_fuse_soc;
 extern const struct tegra_fuse_soc tegra234_fuse_soc;
 #endif
 
+#ifdef CONFIG_ARCH_TEGRA_241_SOC
+extern const struct tegra_fuse_soc tegra241_fuse_soc;
+#endif
+
 #endif
index da970f3dbf35620ac64f3d6255301ee4807a8f57..e2ca5d55fd31259452f444e7d846d9cc145f5e8c 100644 (file)
@@ -3,9 +3,11 @@
  * Copyright (c) 2014-2023, NVIDIA CORPORATION.  All rights reserved.
  */
 
+#include <linux/acpi.h>
 #include <linux/export.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 
@@ -62,6 +64,7 @@ bool tegra_is_silicon(void)
        switch (tegra_get_chip_id()) {
        case TEGRA194:
        case TEGRA234:
+       case TEGRA241:
        case TEGRA264:
                if (tegra_get_platform() == 0)
                        return true;
@@ -160,9 +163,34 @@ void __init tegra_init_revision(void)
        tegra_sku_info.platform = tegra_get_platform();
 }
 
-void __init tegra_init_apbmisc(void)
+static void tegra_init_apbmisc_resources(struct resource *apbmisc,
+                                        struct resource *straps)
 {
        void __iomem *strapping_base;
+
+       apbmisc_base = ioremap(apbmisc->start, resource_size(apbmisc));
+       if (apbmisc_base)
+               chipid = readl_relaxed(apbmisc_base + 4);
+       else
+               pr_err("failed to map APBMISC registers\n");
+
+       strapping_base = ioremap(straps->start, resource_size(straps));
+       if (strapping_base) {
+               strapping = readl_relaxed(strapping_base);
+               iounmap(strapping_base);
+       } else {
+               pr_err("failed to map strapping options registers\n");
+       }
+}
+
+/**
+ * tegra_init_apbmisc - Initializes Tegra APBMISC and Strapping registers.
+ *
+ * This is called during early init as some of the old 32-bit ARM code needs
+ * information from the APBMISC registers very early during boot.
+ */
+void __init tegra_init_apbmisc(void)
+{
        struct resource apbmisc, straps;
        struct device_node *np;
 
@@ -219,23 +247,73 @@ void __init tegra_init_apbmisc(void)
                }
        }
 
-       apbmisc_base = ioremap(apbmisc.start, resource_size(&apbmisc));
-       if (!apbmisc_base) {
-               pr_err("failed to map APBMISC registers\n");
-       } else {
-               chipid = readl_relaxed(apbmisc_base + 4);
+       tegra_init_apbmisc_resources(&apbmisc, &straps);
+       long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code");
+
+put:
+       of_node_put(np);
+}
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id apbmisc_acpi_match[] = {
+       { "NVDA2010" },
+       { /* sentinel */ }
+};
+
+void tegra_acpi_init_apbmisc(void)
+{
+       struct resource *resources[2] = { NULL };
+       struct resource_entry *rentry;
+       struct acpi_device *adev = NULL;
+       struct list_head resource_list;
+       int rcount = 0;
+       int ret;
+
+       adev = acpi_dev_get_first_match_dev(apbmisc_acpi_match[0].id, NULL, -1);
+       if (!adev)
+               return;
+
+       INIT_LIST_HEAD(&resource_list);
+
+       ret = acpi_dev_get_memory_resources(adev, &resource_list);
+       if (ret < 0) {
+               pr_err("failed to get APBMISC memory resources");
+               goto out_put_acpi_dev;
        }
 
-       strapping_base = ioremap(straps.start, resource_size(&straps));
-       if (!strapping_base) {
-               pr_err("failed to map strapping options registers\n");
-       } else {
-               strapping = readl_relaxed(strapping_base);
-               iounmap(strapping_base);
+       /*
+        * Get required memory resources.
+        *
+        * resources[0]: apbmisc.
+        * resources[1]: straps.
+        */
+       resource_list_for_each_entry(rentry, &resource_list) {
+               if (rcount >= ARRAY_SIZE(resources))
+                       break;
+
+               resources[rcount++] = rentry->res;
        }
 
-       long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code");
+       if (!resources[0]) {
+               pr_err("failed to get APBMISC registers\n");
+               goto out_free_resource_list;
+       }
 
-put:
-       of_node_put(np);
+       if (!resources[1]) {
+               pr_err("failed to get strapping options registers\n");
+               goto out_free_resource_list;
+       }
+
+       tegra_init_apbmisc_resources(resources[0], resources[1]);
+
+out_free_resource_list:
+       acpi_dev_free_resource_list(&resource_list);
+
+out_put_acpi_dev:
+       acpi_dev_put(adev);
+}
+#else
+void tegra_acpi_init_apbmisc(void)
+{
 }
+#endif
index f432aa022ace0685e70329cb7d8cca947f666b5a..d6bfcea5ee653f84dc805fa6c4f4041765ad01ec 100644 (file)
@@ -3,7 +3,7 @@
  * drivers/soc/tegra/pmc.c
  *
  * Copyright (c) 2010 Google, Inc
- * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
  *
  * Author:
  *     Colin Cross <ccross@google.com>
@@ -384,6 +384,7 @@ struct tegra_pmc_soc {
        bool has_blink_output;
        bool has_usb_sleepwalk;
        bool supports_core_domain;
+       bool has_single_mmio_aperture;
 };
 
 /**
@@ -1777,30 +1778,6 @@ static int tegra_io_pad_get_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id)
        return TEGRA_IO_PAD_VOLTAGE_3V3;
 }
 
-/**
- * tegra_io_rail_power_on() - enable power to I/O rail
- * @id: Tegra I/O pad ID for which to enable power
- *
- * See also: tegra_io_pad_power_enable()
- */
-int tegra_io_rail_power_on(unsigned int id)
-{
-       return tegra_io_pad_power_enable(id);
-}
-EXPORT_SYMBOL(tegra_io_rail_power_on);
-
-/**
- * tegra_io_rail_power_off() - disable power to I/O rail
- * @id: Tegra I/O pad ID for which to disable power
- *
- * See also: tegra_io_pad_power_disable()
- */
-int tegra_io_rail_power_off(unsigned int id)
-{
-       return tegra_io_pad_power_disable(id);
-}
-EXPORT_SYMBOL(tegra_io_rail_power_off);
-
 #ifdef CONFIG_PM_SLEEP
 enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
 {
@@ -2909,31 +2886,33 @@ static int tegra_pmc_probe(struct platform_device *pdev)
        if (IS_ERR(base))
                return PTR_ERR(base);
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake");
-       if (res) {
+       if (pmc->soc->has_single_mmio_aperture) {
+               pmc->wake = base;
+               pmc->aotag = base;
+               pmc->scratch = base;
+       } else {
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "wake");
                pmc->wake = devm_ioremap_resource(&pdev->dev, res);
                if (IS_ERR(pmc->wake))
                        return PTR_ERR(pmc->wake);
-       } else {
-               pmc->wake = base;
-       }
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag");
-       if (res) {
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "aotag");
                pmc->aotag = devm_ioremap_resource(&pdev->dev, res);
                if (IS_ERR(pmc->aotag))
                        return PTR_ERR(pmc->aotag);
-       } else {
-               pmc->aotag = base;
-       }
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch");
-       if (res) {
-               pmc->scratch = devm_ioremap_resource(&pdev->dev, res);
-               if (IS_ERR(pmc->scratch))
-                       return PTR_ERR(pmc->scratch);
-       } else {
-               pmc->scratch = base;
+               /* "scratch" is an optional aperture */
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "scratch");
+               if (res) {
+                       pmc->scratch = devm_ioremap_resource(&pdev->dev, res);
+                       if (IS_ERR(pmc->scratch))
+                               return PTR_ERR(pmc->scratch);
+               } else {
+                       pmc->scratch = NULL;
+               }
        }
 
        pmc->clk = devm_clk_get_optional(&pdev->dev, "pclk");
@@ -2945,12 +2924,15 @@ static int tegra_pmc_probe(struct platform_device *pdev)
         * PMC should be last resort for restarting since it soft-resets
         * CPU without resetting everything else.
         */
-       err = devm_register_reboot_notifier(&pdev->dev,
-                                           &tegra_pmc_reboot_notifier);
-       if (err) {
-               dev_err(&pdev->dev, "unable to register reboot notifier, %d\n",
-                       err);
-               return err;
+       if (pmc->scratch) {
+               err = devm_register_reboot_notifier(&pdev->dev,
+                                                   &tegra_pmc_reboot_notifier);
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "unable to register reboot notifier, %d\n",
+                               err);
+                       return err;
+               }
        }
 
        err = devm_register_sys_off_handler(&pdev->dev,
@@ -3324,6 +3306,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
        .num_pmc_clks = 0,
        .has_blink_output = true,
        .has_usb_sleepwalk = true,
+       .has_single_mmio_aperture = true,
 };
 
 static const char * const tegra30_powergates[] = {
@@ -3385,6 +3368,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
        .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
        .has_blink_output = true,
        .has_usb_sleepwalk = true,
+       .has_single_mmio_aperture = true,
 };
 
 static const char * const tegra114_powergates[] = {
@@ -3442,6 +3426,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
        .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
        .has_blink_output = true,
        .has_usb_sleepwalk = true,
+       .has_single_mmio_aperture = true,
 };
 
 static const char * const tegra124_powergates[] = {
@@ -3586,6 +3571,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
        .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
        .has_blink_output = true,
        .has_usb_sleepwalk = true,
+       .has_single_mmio_aperture = true,
 };
 
 static const char * const tegra210_powergates[] = {
@@ -3749,6 +3735,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
        .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
        .has_blink_output = true,
        .has_usb_sleepwalk = true,
+       .has_single_mmio_aperture = true,
 };
 
 static const struct tegra_io_pad_soc tegra186_io_pads[] = {
@@ -3946,6 +3933,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
        .num_pmc_clks = 0,
        .has_blink_output = false,
        .has_usb_sleepwalk = false,
+       .has_single_mmio_aperture = false,
 };
 
 static const struct tegra_io_pad_soc tegra194_io_pads[] = {
@@ -4131,6 +4119,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
        .num_pmc_clks = 0,
        .has_blink_output = false,
        .has_usb_sleepwalk = false,
+       .has_single_mmio_aperture = false,
 };
 
 static const struct tegra_io_pad_soc tegra234_io_pads[] = {
@@ -4220,6 +4209,7 @@ static const char * const tegra234_reset_sources[] = {
 };
 
 static const struct tegra_wake_event tegra234_wake_events[] = {
+       TEGRA_WAKE_GPIO("sd-wake", 8, 0, TEGRA234_MAIN_GPIO(G, 7)),
        TEGRA_WAKE_IRQ("pmu", 24, 209),
        TEGRA_WAKE_GPIO("power", 29, 1, TEGRA234_AON_GPIO(EE, 4)),
        TEGRA_WAKE_GPIO("mgbe", 56, 0, TEGRA234_MAIN_GPIO(Y, 3)),
@@ -4259,6 +4249,7 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = {
        .pmc_clks_data = NULL,
        .num_pmc_clks = 0,
        .has_blink_output = false,
+       .has_single_mmio_aperture = false,
 };
 
 static const struct of_device_id tegra_pmc_match[] = {
index f94e0d370d466e9742261a84a567593b8073f169..1a8d03958dffbfb77a4cd183d8a18fbd3ed53d63 100644 (file)
@@ -1927,24 +1927,18 @@ static void cqspi_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
 }
 
-static int cqspi_suspend(struct device *dev)
+static int cqspi_runtime_suspend(struct device *dev)
 {
        struct cqspi_st *cqspi = dev_get_drvdata(dev);
-       struct spi_controller *host = dev_get_drvdata(dev);
-       int ret;
 
-       ret = spi_controller_suspend(host);
        cqspi_controller_enable(cqspi, 0);
-
        clk_disable_unprepare(cqspi->clk);
-
-       return ret;
+       return 0;
 }
 
-static int cqspi_resume(struct device *dev)
+static int cqspi_runtime_resume(struct device *dev)
 {
        struct cqspi_st *cqspi = dev_get_drvdata(dev);
-       struct spi_controller *host = dev_get_drvdata(dev);
 
        clk_prepare_enable(cqspi->clk);
        cqspi_wait_idle(cqspi);
@@ -1952,12 +1946,27 @@ static int cqspi_resume(struct device *dev)
 
        cqspi->current_cs = -1;
        cqspi->sclk = 0;
+       return 0;
+}
+
+static int cqspi_suspend(struct device *dev)
+{
+       struct cqspi_st *cqspi = dev_get_drvdata(dev);
+
+       return spi_controller_suspend(cqspi->host);
+}
 
-       return spi_controller_resume(host);
+static int cqspi_resume(struct device *dev)
+{
+       struct cqspi_st *cqspi = dev_get_drvdata(dev);
+
+       return spi_controller_resume(cqspi->host);
 }
 
-static DEFINE_RUNTIME_DEV_PM_OPS(cqspi_dev_pm_ops, cqspi_suspend,
-                                cqspi_resume, NULL);
+static const struct dev_pm_ops cqspi_dev_pm_ops = {
+       RUNTIME_PM_OPS(cqspi_runtime_suspend, cqspi_runtime_resume, NULL)
+       SYSTEM_SLEEP_PM_OPS(cqspi_suspend, cqspi_resume)
+};
 
 static const struct cqspi_driver_platdata cdns_qspi = {
        .quirks = CQSPI_DISABLE_DAC_MODE,
index b24190526ce96420fe885e585b00fb820502bacd..adf19e8c4c8a0d1ef9ede14374e8ab6638073a82 100644 (file)
@@ -148,8 +148,7 @@ static void cs42l43_set_cs(struct spi_device *spi, bool is_high)
 {
        struct cs42l43_spi *priv = spi_controller_get_devdata(spi->controller);
 
-       if (spi_get_chipselect(spi, 0) == 0)
-               regmap_write(priv->regmap, CS42L43_SPI_CONFIG2, !is_high);
+       regmap_write(priv->regmap, CS42L43_SPI_CONFIG2, !is_high);
 }
 
 static int cs42l43_prepare_message(struct spi_controller *ctlr, struct spi_message *msg)
index 546cdce525fc5b1b49b305b872e81d2b0aed0cb5..833a1bb7a91438e02c2d5a176e1afdaba4159552 100644 (file)
@@ -2,6 +2,7 @@
 // Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
 // Copyright (C) 2008 Juergen Beisert
 
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
@@ -660,15 +661,15 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
                        << MX51_ECSPI_CTRL_BL_OFFSET;
        else {
                if (spi_imx->usedma) {
-                       ctrl |= (spi_imx->bits_per_word *
-                               spi_imx_bytes_per_word(spi_imx->bits_per_word) - 1)
+                       ctrl |= (spi_imx->bits_per_word - 1)
                                << MX51_ECSPI_CTRL_BL_OFFSET;
                } else {
                        if (spi_imx->count >= MX51_ECSPI_CTRL_MAX_BURST)
-                               ctrl |= (MX51_ECSPI_CTRL_MAX_BURST - 1)
+                               ctrl |= (MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1)
                                                << MX51_ECSPI_CTRL_BL_OFFSET;
                        else
-                               ctrl |= (spi_imx->count * spi_imx->bits_per_word - 1)
+                               ctrl |= spi_imx->count / DIV_ROUND_UP(spi_imx->bits_per_word,
+                                               BITS_PER_BYTE) * spi_imx->bits_per_word
                                                << MX51_ECSPI_CTRL_BL_OFFSET;
                }
        }
index 07d20ca1164c357813e075b7a1a6763da735ab0a..4337ca51d7aa21555684f62295a39a52772cce3d 100644 (file)
@@ -85,6 +85,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0xa2a4), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&cnl_info },
+       { PCI_VDEVICE(INTEL, 0xa823), (unsigned long)&cnl_info },
        { },
 };
 MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids);
index 1bf080339b5a722b8ec6abb356f8bad231d19d9f..88cbe4f00cc3b11e5fef822a60114a90a88149f8 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/mxs-spi.h>
 #include <trace/events/spi.h>
+#include <linux/dma/mxs-dma.h>
 
 #define DRIVER_NAME            "mxs-spi"
 
@@ -252,7 +253,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi,
                desc = dmaengine_prep_slave_sg(ssp->dmach,
                                &dma_xfer[sg_count].sg, 1,
                                (flags & TXRX_WRITE) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
-                               DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+                               DMA_PREP_INTERRUPT | MXS_DMA_CTRL_WAIT4END);
 
                if (!desc) {
                        dev_err(ssp->dev,
index a0c9fea908f553e0bf007a7a78a35746f60a25f4..ddf1c684bcc7d863ede340aa196506a3a3505654 100644 (file)
@@ -53,8 +53,6 @@
 
 /* per-register bitmasks: */
 #define OMAP2_MCSPI_IRQSTATUS_EOW      BIT(17)
-#define OMAP2_MCSPI_IRQSTATUS_TX0_EMPTY    BIT(0)
-#define OMAP2_MCSPI_IRQSTATUS_RX0_FULL    BIT(2)
 
 #define OMAP2_MCSPI_MODULCTRL_SINGLE   BIT(0)
 #define OMAP2_MCSPI_MODULCTRL_MS       BIT(2)
@@ -293,7 +291,7 @@ static void omap2_mcspi_set_mode(struct spi_controller *ctlr)
 }
 
 static void omap2_mcspi_set_fifo(const struct spi_device *spi,
-                               struct spi_transfer *t, int enable, int dma_enabled)
+                               struct spi_transfer *t, int enable)
 {
        struct spi_controller *ctlr = spi->controller;
        struct omap2_mcspi_cs *cs = spi->controller_state;
@@ -314,28 +312,20 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
                        max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH / 2;
                else
                        max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH;
-               if (dma_enabled)
-                       wcnt = t->len / bytes_per_word;
-               else
-                       wcnt = 0;
+
+               wcnt = t->len / bytes_per_word;
                if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT)
                        goto disable_fifo;
 
                xferlevel = wcnt << 16;
                if (t->rx_buf != NULL) {
                        chconf |= OMAP2_MCSPI_CHCONF_FFER;
-                       if (dma_enabled)
-                               xferlevel |= (bytes_per_word - 1) << 8;
-                       else
-                               xferlevel |= (max_fifo_depth - 1) << 8;
+                       xferlevel |= (bytes_per_word - 1) << 8;
                }
 
                if (t->tx_buf != NULL) {
                        chconf |= OMAP2_MCSPI_CHCONF_FFET;
-                       if (dma_enabled)
-                               xferlevel |= bytes_per_word - 1;
-                       else
-                               xferlevel |= (max_fifo_depth - 1);
+                       xferlevel |= bytes_per_word - 1;
                }
 
                mcspi_write_reg(ctlr, OMAP2_MCSPI_XFERLEVEL, xferlevel);
@@ -892,113 +882,6 @@ out:
        return count - c;
 }
 
-static unsigned
-omap2_mcspi_txrx_piofifo(struct spi_device *spi, struct spi_transfer *xfer)
-{
-       struct omap2_mcspi_cs   *cs = spi->controller_state;
-       struct omap2_mcspi    *mcspi;
-       unsigned int            count, c;
-       unsigned int            iter, cwc;
-       int last_request;
-       void __iomem            *base = cs->base;
-       void __iomem            *tx_reg;
-       void __iomem            *rx_reg;
-       void __iomem            *chstat_reg;
-       void __iomem        *irqstat_reg;
-       int                     word_len, bytes_per_word;
-       u8              *rx;
-       const u8        *tx;
-
-       mcspi = spi_controller_get_devdata(spi->controller);
-       count = xfer->len;
-       c = count;
-       word_len = cs->word_len;
-       bytes_per_word = mcspi_bytes_per_word(word_len);
-
-       /*
-        * We store the pre-calculated register addresses on stack to speed
-        * up the transfer loop.
-        */
-       tx_reg          = base + OMAP2_MCSPI_TX0;
-       rx_reg          = base + OMAP2_MCSPI_RX0;
-       chstat_reg      = base + OMAP2_MCSPI_CHSTAT0;
-       irqstat_reg    = base + OMAP2_MCSPI_IRQSTATUS;
-
-       if (c < (word_len >> 3))
-               return 0;
-
-       rx = xfer->rx_buf;
-       tx = xfer->tx_buf;
-
-       do {
-               /* calculate number of words in current iteration */
-               cwc = min((unsigned int)mcspi->fifo_depth / bytes_per_word,
-                         c / bytes_per_word);
-               last_request = cwc != (mcspi->fifo_depth / bytes_per_word);
-               if (tx) {
-                       if (mcspi_wait_for_reg_bit(irqstat_reg,
-                                                  OMAP2_MCSPI_IRQSTATUS_TX0_EMPTY) < 0) {
-                               dev_err(&spi->dev, "TX Empty timed out\n");
-                               goto out;
-                       }
-                       writel_relaxed(OMAP2_MCSPI_IRQSTATUS_TX0_EMPTY, irqstat_reg);
-
-                       for (iter = 0; iter < cwc; iter++, tx += bytes_per_word) {
-                               if (bytes_per_word == 1)
-                                       writel_relaxed(*tx, tx_reg);
-                               else if (bytes_per_word == 2)
-                                       writel_relaxed(*((u16 *)tx), tx_reg);
-                               else if (bytes_per_word == 4)
-                                       writel_relaxed(*((u32 *)tx), tx_reg);
-                       }
-               }
-
-               if (rx) {
-                       if (!last_request &&
-                           mcspi_wait_for_reg_bit(irqstat_reg,
-                                                  OMAP2_MCSPI_IRQSTATUS_RX0_FULL) < 0) {
-                               dev_err(&spi->dev, "RX_FULL timed out\n");
-                               goto out;
-                       }
-                       writel_relaxed(OMAP2_MCSPI_IRQSTATUS_RX0_FULL, irqstat_reg);
-
-                       for (iter = 0; iter < cwc; iter++, rx += bytes_per_word) {
-                               if (last_request &&
-                                   mcspi_wait_for_reg_bit(chstat_reg,
-                                                          OMAP2_MCSPI_CHSTAT_RXS) < 0) {
-                                       dev_err(&spi->dev, "RXS timed out\n");
-                                       goto out;
-                               }
-                               if (bytes_per_word == 1)
-                                       *rx = readl_relaxed(rx_reg);
-                               else if (bytes_per_word == 2)
-                                       *((u16 *)rx) = readl_relaxed(rx_reg);
-                               else if (bytes_per_word == 4)
-                                       *((u32 *)rx) = readl_relaxed(rx_reg);
-                       }
-               }
-
-               if (last_request) {
-                       if (mcspi_wait_for_reg_bit(chstat_reg,
-                                                  OMAP2_MCSPI_CHSTAT_EOT) < 0) {
-                               dev_err(&spi->dev, "EOT timed out\n");
-                               goto out;
-                       }
-                       if (mcspi_wait_for_reg_bit(chstat_reg,
-                                                  OMAP2_MCSPI_CHSTAT_TXFFE) < 0) {
-                               dev_err(&spi->dev, "TXFFE timed out\n");
-                               goto out;
-                       }
-                       omap2_mcspi_set_enable(spi, 0);
-               }
-               c -= cwc * bytes_per_word;
-       } while (c >= bytes_per_word);
-
-out:
-       omap2_mcspi_set_enable(spi, 1);
-       return count - c;
-}
-
 static u32 omap2_mcspi_calc_divisor(u32 speed_hz, u32 ref_clk_hz)
 {
        u32 div;
@@ -1323,9 +1206,7 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr,
                if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
                    ctlr->cur_msg_mapped &&
                    ctlr->can_dma(ctlr, spi, t))
-                       omap2_mcspi_set_fifo(spi, t, 1, 1);
-               else if (t->len > OMAP2_MCSPI_MAX_FIFODEPTH)
-                       omap2_mcspi_set_fifo(spi, t, 1, 0);
+                       omap2_mcspi_set_fifo(spi, t, 1);
 
                omap2_mcspi_set_enable(spi, 1);
 
@@ -1338,8 +1219,6 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr,
                    ctlr->cur_msg_mapped &&
                    ctlr->can_dma(ctlr, spi, t))
                        count = omap2_mcspi_txrx_dma(spi, t);
-               else if (mcspi->fifo_depth > 0)
-                       count = omap2_mcspi_txrx_piofifo(spi, t);
                else
                        count = omap2_mcspi_txrx_pio(spi, t);
 
@@ -1352,7 +1231,7 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr,
        omap2_mcspi_set_enable(spi, 0);
 
        if (mcspi->fifo_depth > 0)
-               omap2_mcspi_set_fifo(spi, t, 0, 0);
+               omap2_mcspi_set_fifo(spi, t, 0);
 
 out:
        /* Restore defaults if they were overriden */
@@ -1375,7 +1254,7 @@ out:
                omap2_mcspi_set_cs(spi, !(spi->mode & SPI_CS_HIGH));
 
        if (mcspi->fifo_depth > 0 && t)
-               omap2_mcspi_set_fifo(spi, t, 0, 0);
+               omap2_mcspi_set_fifo(spi, t, 0);
 
        return status;
 }
index 03aab661be9d33af1ff6ad93052171f206402b83..82d6264841fc7f090a5541235569e40023330483 100644 (file)
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
+#include <linux/platform_device.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/platform_device.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
@@ -166,10 +168,8 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
        int scr;
        u8 cdm = 0;
        u32 speed;
-       u8 bits_per_word;
 
        /* Start with the generic configuration for this device. */
-       bits_per_word = spi->bits_per_word;
        speed = spi->max_speed_hz;
 
        /*
@@ -177,9 +177,6 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
         * the transfer to overwrite the generic configuration with zeros.
         */
        if (t) {
-               if (t->bits_per_word)
-                       bits_per_word = t->bits_per_word;
-
                if (t->speed_hz)
                        speed = min(t->speed_hz, spi->max_speed_hz);
        }
index b1f9474f36d51a6235cd29b815248f8e7dbb5b84..f34a95611645bd5d889384dfa547a4a47bd1b36d 100644 (file)
@@ -48,7 +48,7 @@ Example of usage:
 -----------------
 
 This example places the bridge on top of the i.MX WEIM parallel bus, see:
-Documentation/devicetree/bindings/bus/imx-weim.txt
+Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim.yaml
 
 &weim {
        controller@0,0 {
index e748a5d04e970598c4bee3b52c19a57fcbbd1c12..9149d41fe65b7ed48785f80bc712902278eccec3 100644 (file)
@@ -608,7 +608,7 @@ static void ad5933_work(struct work_struct *work)
                struct ad5933_state, work.work);
        struct iio_dev *indio_dev = i2c_get_clientdata(st->client);
        __be16 buf[2];
-       int val[2];
+       u16 val[2];
        unsigned char status;
        int ret;
 
index f44e6412f4e31a4ee3ab22cc650eee5a49ee31a1..d0db2efe004525e9d88531e0115c8edd2fa9c4df 100644 (file)
@@ -3723,12 +3723,10 @@ apply_min_padding:
 
 static int atomisp_set_crop(struct atomisp_device *isp,
                            const struct v4l2_mbus_framefmt *format,
+                           struct v4l2_subdev_state *sd_state,
                            int which)
 {
        struct atomisp_input_subdev *input = &isp->inputs[isp->asd.input_curr];
-       struct v4l2_subdev_state pad_state = {
-               .pads = &input->pad_cfg,
-       };
        struct v4l2_subdev_selection sel = {
                .which = which,
                .target = V4L2_SEL_TGT_CROP,
@@ -3754,7 +3752,7 @@ static int atomisp_set_crop(struct atomisp_device *isp,
        sel.r.left = ((input->native_rect.width - sel.r.width) / 2) & ~1;
        sel.r.top = ((input->native_rect.height - sel.r.height) / 2) & ~1;
 
-       ret = v4l2_subdev_call(input->camera, pad, set_selection, &pad_state, &sel);
+       ret = v4l2_subdev_call(input->camera, pad, set_selection, sd_state, &sel);
        if (ret)
                dev_err(isp->dev, "Error setting crop to %ux%u @%ux%u: %d\n",
                        sel.r.width, sel.r.height, sel.r.left, sel.r.top, ret);
@@ -3770,9 +3768,6 @@ int atomisp_try_fmt(struct atomisp_device *isp, struct v4l2_pix_format *f,
        const struct atomisp_format_bridge *fmt, *snr_fmt;
        struct atomisp_sub_device *asd = &isp->asd;
        struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr];
-       struct v4l2_subdev_state pad_state = {
-               .pads = &input->pad_cfg,
-       };
        struct v4l2_subdev_format format = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
@@ -3809,11 +3804,16 @@ int atomisp_try_fmt(struct atomisp_device *isp, struct v4l2_pix_format *f,
        dev_dbg(isp->dev, "try_mbus_fmt: asking for %ux%u\n",
                format.format.width, format.format.height);
 
-       ret = atomisp_set_crop(isp, &format.format, V4L2_SUBDEV_FORMAT_TRY);
-       if (ret)
-               return ret;
+       v4l2_subdev_lock_state(input->try_sd_state);
+
+       ret = atomisp_set_crop(isp, &format.format, input->try_sd_state,
+                              V4L2_SUBDEV_FORMAT_TRY);
+       if (ret == 0)
+               ret = v4l2_subdev_call(input->camera, pad, set_fmt,
+                                      input->try_sd_state, &format);
+
+       v4l2_subdev_unlock_state(input->try_sd_state);
 
-       ret = v4l2_subdev_call(input->camera, pad, set_fmt, &pad_state, &format);
        if (ret)
                return ret;
 
@@ -4238,9 +4238,7 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, const struct v4l2_p
        struct atomisp_device *isp = asd->isp;
        struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr];
        const struct atomisp_format_bridge *format;
-       struct v4l2_subdev_state pad_state = {
-               .pads = &input->pad_cfg,
-       };
+       struct v4l2_subdev_state *act_sd_state;
        struct v4l2_subdev_format vformat = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
@@ -4268,12 +4266,18 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, const struct v4l2_p
 
        /* Disable dvs if resolution can't be supported by sensor */
        if (asd->params.video_dis_en && asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
-               ret = atomisp_set_crop(isp, &vformat.format, V4L2_SUBDEV_FORMAT_TRY);
-               if (ret)
-                       return ret;
+               v4l2_subdev_lock_state(input->try_sd_state);
+
+               ret = atomisp_set_crop(isp, &vformat.format, input->try_sd_state,
+                                      V4L2_SUBDEV_FORMAT_TRY);
+               if (ret == 0) {
+                       vformat.which = V4L2_SUBDEV_FORMAT_TRY;
+                       ret = v4l2_subdev_call(input->camera, pad, set_fmt,
+                                              input->try_sd_state, &vformat);
+               }
+
+               v4l2_subdev_unlock_state(input->try_sd_state);
 
-               vformat.which = V4L2_SUBDEV_FORMAT_TRY;
-               ret = v4l2_subdev_call(input->camera, pad, set_fmt, &pad_state, &vformat);
                if (ret)
                        return ret;
 
@@ -4291,12 +4295,18 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, const struct v4l2_p
                }
        }
 
-       ret = atomisp_set_crop(isp, &vformat.format, V4L2_SUBDEV_FORMAT_ACTIVE);
-       if (ret)
-               return ret;
+       act_sd_state = v4l2_subdev_lock_and_get_active_state(input->camera);
+
+       ret = atomisp_set_crop(isp, &vformat.format, act_sd_state,
+                              V4L2_SUBDEV_FORMAT_ACTIVE);
+       if (ret == 0) {
+               vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+               ret = v4l2_subdev_call(input->camera, pad, set_fmt, act_sd_state, &vformat);
+       }
+
+       if (act_sd_state)
+               v4l2_subdev_unlock_state(act_sd_state);
 
-       vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-       ret = v4l2_subdev_call(input->camera, pad, set_fmt, NULL, &vformat);
        if (ret)
                return ret;
 
index f7b4bee9574bdb8ea330bec4e04074515e71f5a5..d5b077e602caec6ac2863780f660f7aac751ff02 100644 (file)
@@ -132,8 +132,8 @@ struct atomisp_input_subdev {
        /* Sensor rects for sensors which support crop */
        struct v4l2_rect native_rect;
        struct v4l2_rect active_rect;
-       /* Sensor pad_cfg for which == V4L2_SUBDEV_FORMAT_TRY calls */
-       struct v4l2_subdev_pad_config pad_cfg;
+       /* Sensor state for which == V4L2_SUBDEV_FORMAT_TRY calls */
+       struct v4l2_subdev_state *try_sd_state;
 
        struct v4l2_subdev *motor;
 
index 01b7fa9b56a21378459f3aa4101eab6195558546..5b2d88c02d36a083376ee21660923635e9ff70c4 100644 (file)
@@ -781,12 +781,20 @@ static int atomisp_enum_framesizes(struct file *file, void *priv,
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
                .code = input->code,
        };
+       struct v4l2_subdev_state *act_sd_state;
        int ret;
 
+       if (!input->camera)
+               return -EINVAL;
+
        if (input->crop_support)
                return atomisp_enum_framesizes_crop(isp, fsize);
 
-       ret = v4l2_subdev_call(input->camera, pad, enum_frame_size, NULL, &fse);
+       act_sd_state = v4l2_subdev_lock_and_get_active_state(input->camera);
+       ret = v4l2_subdev_call(input->camera, pad, enum_frame_size,
+                              act_sd_state, &fse);
+       if (act_sd_state)
+               v4l2_subdev_unlock_state(act_sd_state);
        if (ret)
                return ret;
 
@@ -803,18 +811,25 @@ static int atomisp_enum_frameintervals(struct file *file, void *priv,
        struct video_device *vdev = video_devdata(file);
        struct atomisp_device *isp = video_get_drvdata(vdev);
        struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
+       struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr];
        struct v4l2_subdev_frame_interval_enum fie = {
-               .code   = atomisp_in_fmt_conv[0].code,
+               .code = atomisp_in_fmt_conv[0].code,
                .index = fival->index,
                .width = fival->width,
                .height = fival->height,
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
        };
+       struct v4l2_subdev_state *act_sd_state;
        int ret;
 
-       ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
-                              pad, enum_frame_interval, NULL,
-                              &fie);
+       if (!input->camera)
+               return -EINVAL;
+
+       act_sd_state = v4l2_subdev_lock_and_get_active_state(input->camera);
+       ret = v4l2_subdev_call(input->camera, pad, enum_frame_interval,
+                              act_sd_state, &fie);
+       if (act_sd_state)
+               v4l2_subdev_unlock_state(act_sd_state);
        if (ret)
                return ret;
 
@@ -830,30 +845,25 @@ static int atomisp_enum_fmt_cap(struct file *file, void *fh,
        struct video_device *vdev = video_devdata(file);
        struct atomisp_device *isp = video_get_drvdata(vdev);
        struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
+       struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr];
        struct v4l2_subdev_mbus_code_enum code = {
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
        };
        const struct atomisp_format_bridge *format;
-       struct v4l2_subdev *camera;
+       struct v4l2_subdev_state *act_sd_state;
        unsigned int i, fi = 0;
-       int rval;
+       int ret;
 
-       camera = isp->inputs[asd->input_curr].camera;
-       if(!camera) {
-               dev_err(isp->dev, "%s(): camera is NULL, device is %s\n",
-                       __func__, vdev->name);
+       if (!input->camera)
                return -EINVAL;
-       }
 
-       rval = v4l2_subdev_call(camera, pad, enum_mbus_code, NULL, &code);
-       if (rval == -ENOIOCTLCMD) {
-               dev_warn(isp->dev,
-                        "enum_mbus_code pad op not supported by %s. Please fix your sensor driver!\n",
-                        camera->name);
-       }
-
-       if (rval)
-               return rval;
+       act_sd_state = v4l2_subdev_lock_and_get_active_state(input->camera);
+       ret = v4l2_subdev_call(input->camera, pad, enum_mbus_code,
+                              act_sd_state, &code);
+       if (act_sd_state)
+               v4l2_subdev_unlock_state(act_sd_state);
+       if (ret)
+               return ret;
 
        for (i = 0; i < ARRAY_SIZE(atomisp_output_fmts); i++) {
                format = &atomisp_output_fmts[i];
index c1c8501ec61f57046af5027c8f9a4170597210d5..547e1444ad9733569816c1e43c74e542089f82fa 100644 (file)
@@ -862,6 +862,9 @@ static void atomisp_unregister_entities(struct atomisp_device *isp)
        v4l2_device_unregister(&isp->v4l2_dev);
        media_device_unregister(&isp->media_dev);
        media_device_cleanup(&isp->media_dev);
+
+       for (i = 0; i < isp->input_cnt; i++)
+               __v4l2_subdev_state_free(isp->inputs[i].try_sd_state);
 }
 
 static int atomisp_register_entities(struct atomisp_device *isp)
@@ -933,32 +936,49 @@ v4l2_device_failed:
 
 static void atomisp_init_sensor(struct atomisp_input_subdev *input)
 {
+       static struct lock_class_key try_sd_state_key;
        struct v4l2_subdev_mbus_code_enum mbus_code_enum = { };
        struct v4l2_subdev_frame_size_enum fse = { };
-       struct v4l2_subdev_state sd_state = {
-               .pads = &input->pad_cfg,
-       };
        struct v4l2_subdev_selection sel = { };
+       struct v4l2_subdev_state *try_sd_state, *act_sd_state;
        int i, err;
 
+       /*
+        * FIXME: Drivers are not supposed to use __v4l2_subdev_state_alloc()
+        * but atomisp needs this for try_fmt on its /dev/video# node since
+        * it emulates a normal v4l2 device there, passing through try_fmt /
+        * set_fmt to the sensor.
+        */
+       try_sd_state = __v4l2_subdev_state_alloc(input->camera,
+                               "atomisp:try_sd_state->lock", &try_sd_state_key);
+       if (IS_ERR(try_sd_state))
+               return;
+
+       input->try_sd_state = try_sd_state;
+
+       act_sd_state = v4l2_subdev_lock_and_get_active_state(input->camera);
+
        mbus_code_enum.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-       err = v4l2_subdev_call(input->camera, pad, enum_mbus_code, NULL, &mbus_code_enum);
+       err = v4l2_subdev_call(input->camera, pad, enum_mbus_code,
+                              act_sd_state, &mbus_code_enum);
        if (!err)
                input->code = mbus_code_enum.code;
 
        sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
        sel.target = V4L2_SEL_TGT_NATIVE_SIZE;
-       err = v4l2_subdev_call(input->camera, pad, get_selection, NULL, &sel);
+       err = v4l2_subdev_call(input->camera, pad, get_selection,
+                              act_sd_state, &sel);
        if (err)
-               return;
+               goto unlock_act_sd_state;
 
        input->native_rect = sel.r;
 
        sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
        sel.target = V4L2_SEL_TGT_CROP_DEFAULT;
-       err = v4l2_subdev_call(input->camera, pad, get_selection, NULL, &sel);
+       err = v4l2_subdev_call(input->camera, pad, get_selection,
+                              act_sd_state, &sel);
        if (err)
-               return;
+               goto unlock_act_sd_state;
 
        input->active_rect = sel.r;
 
@@ -973,7 +993,8 @@ static void atomisp_init_sensor(struct atomisp_input_subdev *input)
                fse.code = input->code;
                fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 
-               err = v4l2_subdev_call(input->camera, pad, enum_frame_size, NULL, &fse);
+               err = v4l2_subdev_call(input->camera, pad, enum_frame_size,
+                                      act_sd_state, &fse);
                if (err)
                        break;
 
@@ -989,22 +1010,26 @@ static void atomisp_init_sensor(struct atomisp_input_subdev *input)
         * for padding, set the crop rect to cover the entire sensor instead
         * of only the default active area.
         *
-        * Do this for both try and active formats since the try_crop rect in
-        * pad_cfg may influence (clamp) future try_fmt calls with which == try.
+        * Do this for both try and active formats since the crop rect in
+        * try_sd_state may influence (clamp size) in calls with which == try.
         */
        sel.which = V4L2_SUBDEV_FORMAT_TRY;
        sel.target = V4L2_SEL_TGT_CROP;
        sel.r = input->native_rect;
-       err = v4l2_subdev_call(input->camera, pad, set_selection, &sd_state, &sel);
+       v4l2_subdev_lock_state(input->try_sd_state);
+       err = v4l2_subdev_call(input->camera, pad, set_selection,
+                              input->try_sd_state, &sel);
+       v4l2_subdev_unlock_state(input->try_sd_state);
        if (err)
-               return;
+               goto unlock_act_sd_state;
 
        sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
        sel.target = V4L2_SEL_TGT_CROP;
        sel.r = input->native_rect;
-       err = v4l2_subdev_call(input->camera, pad, set_selection, NULL, &sel);
+       err = v4l2_subdev_call(input->camera, pad, set_selection,
+                              act_sd_state, &sel);
        if (err)
-               return;
+               goto unlock_act_sd_state;
 
        dev_info(input->camera->dev, "Supports crop native %dx%d active %dx%d binning %d\n",
                 input->native_rect.width, input->native_rect.height,
@@ -1012,6 +1037,10 @@ static void atomisp_init_sensor(struct atomisp_input_subdev *input)
                 input->binning_support);
 
        input->crop_support = true;
+
+unlock_act_sd_state:
+       if (act_sd_state)
+               v4l2_subdev_unlock_state(act_sd_state);
 }
 
 int atomisp_register_device_nodes(struct atomisp_device *isp)
index a5f58988130a15c921e45570298edfbe212273ba..c1fbcdd1618264f0cd09f5e4078ac600ad6dc22a 100644 (file)
@@ -759,6 +759,29 @@ static ssize_t emulate_tas_store(struct config_item *item,
        return count;
 }
 
+static int target_try_configure_unmap(struct se_device *dev,
+                                     const char *config_opt)
+{
+       if (!dev->transport->configure_unmap) {
+               pr_err("Generic Block Discard not supported\n");
+               return -ENOSYS;
+       }
+
+       if (!target_dev_configured(dev)) {
+               pr_err("Generic Block Discard setup for %s requires device to be configured\n",
+                      config_opt);
+               return -ENODEV;
+       }
+
+       if (!dev->transport->configure_unmap(dev)) {
+               pr_err("Generic Block Discard setup for %s failed\n",
+                      config_opt);
+               return -ENOSYS;
+       }
+
+       return 0;
+}
+
 static ssize_t emulate_tpu_store(struct config_item *item,
                const char *page, size_t count)
 {
@@ -776,11 +799,9 @@ static ssize_t emulate_tpu_store(struct config_item *item,
         * Discard supported is detected iblock_create_virtdevice().
         */
        if (flag && !da->max_unmap_block_desc_count) {
-               if (!dev->transport->configure_unmap ||
-                   !dev->transport->configure_unmap(dev)) {
-                       pr_err("Generic Block Discard not supported\n");
-                       return -ENOSYS;
-               }
+               ret = target_try_configure_unmap(dev, "emulate_tpu");
+               if (ret)
+                       return ret;
        }
 
        da->emulate_tpu = flag;
@@ -806,11 +827,9 @@ static ssize_t emulate_tpws_store(struct config_item *item,
         * Discard supported is detected iblock_create_virtdevice().
         */
        if (flag && !da->max_unmap_block_desc_count) {
-               if (!dev->transport->configure_unmap ||
-                   !dev->transport->configure_unmap(dev)) {
-                       pr_err("Generic Block Discard not supported\n");
-                       return -ENOSYS;
-               }
+               ret = target_try_configure_unmap(dev, "emulate_tpws");
+               if (ret)
+                       return ret;
        }
 
        da->emulate_tpws = flag;
@@ -1022,12 +1041,9 @@ static ssize_t unmap_zeroes_data_store(struct config_item *item,
         * Discard supported is detected iblock_configure_device().
         */
        if (flag && !da->max_unmap_block_desc_count) {
-               if (!dev->transport->configure_unmap ||
-                   !dev->transport->configure_unmap(dev)) {
-                       pr_err("dev[%p]: Thin Provisioning LBPRZ will not be set because max_unmap_block_desc_count is zero\n",
-                              da->da_dev);
-                       return -ENOSYS;
-               }
+               ret = target_try_configure_unmap(dev, "unmap_zeroes_data");
+               if (ret)
+                       return ret;
        }
        da->unmap_zeroes_data = flag;
        pr_debug("dev[%p]: SE Device Thin Provisioning LBPRZ bit: %d\n",
index 8eb9eb7ce5df522b9ba734ef602f5ff22c4716e0..7f6ca81778453b0817f0d9f4c32e6b2b44ea6069 100644 (file)
@@ -91,7 +91,7 @@ static int iblock_configure_device(struct se_device *dev)
 {
        struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
        struct request_queue *q;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct block_device *bd;
        struct blk_integrity *bi;
        blk_mode_t mode = BLK_OPEN_READ;
@@ -117,14 +117,14 @@ static int iblock_configure_device(struct se_device *dev)
        else
                dev->dev_flags |= DF_READ_ONLY;
 
-       bdev_handle = bdev_open_by_path(ib_dev->ibd_udev_path, mode, ib_dev,
+       bdev_file = bdev_file_open_by_path(ib_dev->ibd_udev_path, mode, ib_dev,
                                        NULL);
-       if (IS_ERR(bdev_handle)) {
-               ret = PTR_ERR(bdev_handle);
+       if (IS_ERR(bdev_file)) {
+               ret = PTR_ERR(bdev_file);
                goto out_free_bioset;
        }
-       ib_dev->ibd_bdev_handle = bdev_handle;
-       ib_dev->ibd_bd = bd = bdev_handle->bdev;
+       ib_dev->ibd_bdev_file = bdev_file;
+       ib_dev->ibd_bd = bd = file_bdev(bdev_file);
 
        q = bdev_get_queue(bd);
 
@@ -180,7 +180,7 @@ static int iblock_configure_device(struct se_device *dev)
        return 0;
 
 out_blkdev_put:
-       bdev_release(ib_dev->ibd_bdev_handle);
+       fput(ib_dev->ibd_bdev_file);
 out_free_bioset:
        bioset_exit(&ib_dev->ibd_bio_set);
 out:
@@ -205,8 +205,8 @@ static void iblock_destroy_device(struct se_device *dev)
 {
        struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
 
-       if (ib_dev->ibd_bdev_handle)
-               bdev_release(ib_dev->ibd_bdev_handle);
+       if (ib_dev->ibd_bdev_file)
+               fput(ib_dev->ibd_bdev_file);
        bioset_exit(&ib_dev->ibd_bio_set);
 }
 
index 683f9a55945bb2676c992707bbeb7edaae806e36..91f6f4280666cb08d694d458bb53fb96c8719eae 100644 (file)
@@ -32,7 +32,7 @@ struct iblock_dev {
        u32     ibd_flags;
        struct bio_set  ibd_bio_set;
        struct block_device *ibd_bd;
-       struct bdev_handle *ibd_bdev_handle;
+       struct file *ibd_bdev_file;
        bool ibd_readonly;
        struct iblock_dev_plug *ibd_plug;
 } ____cacheline_aligned;
index 41b7489d37ce95e059ec4849ae7039949c6e6ff1..f98ebb18666bf09354daa36a97c04a8755f3233b 100644 (file)
@@ -352,7 +352,7 @@ static int pscsi_create_type_disk(struct se_device *dev, struct scsi_device *sd)
        struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr;
        struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);
        struct Scsi_Host *sh = sd->host;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        int ret;
 
        if (scsi_device_get(sd)) {
@@ -366,18 +366,18 @@ static int pscsi_create_type_disk(struct se_device *dev, struct scsi_device *sd)
         * Claim exclusive struct block_device access to struct scsi_device
         * for TYPE_DISK and TYPE_ZBC using supplied udev_path
         */
-       bdev_handle = bdev_open_by_path(dev->udev_path,
+       bdev_file = bdev_file_open_by_path(dev->udev_path,
                                BLK_OPEN_WRITE | BLK_OPEN_READ, pdv, NULL);
-       if (IS_ERR(bdev_handle)) {
+       if (IS_ERR(bdev_file)) {
                pr_err("pSCSI: bdev_open_by_path() failed\n");
                scsi_device_put(sd);
-               return PTR_ERR(bdev_handle);
+               return PTR_ERR(bdev_file);
        }
-       pdv->pdv_bdev_handle = bdev_handle;
+       pdv->pdv_bdev_file = bdev_file;
 
        ret = pscsi_add_device_to_list(dev, sd);
        if (ret) {
-               bdev_release(bdev_handle);
+               fput(bdev_file);
                scsi_device_put(sd);
                return ret;
        }
@@ -564,9 +564,9 @@ static void pscsi_destroy_device(struct se_device *dev)
                 * from pscsi_create_type_disk()
                 */
                if ((sd->type == TYPE_DISK || sd->type == TYPE_ZBC) &&
-                   pdv->pdv_bdev_handle) {
-                       bdev_release(pdv->pdv_bdev_handle);
-                       pdv->pdv_bdev_handle = NULL;
+                   pdv->pdv_bdev_file) {
+                       fput(pdv->pdv_bdev_file);
+                       pdv->pdv_bdev_file = NULL;
                }
                /*
                 * For HBA mode PHV_LLD_SCSI_HOST_NO, release the reference
@@ -907,12 +907,15 @@ new_bio:
 
        return 0;
 fail:
-       if (bio)
-               bio_put(bio);
+       if (bio) {
+               bio_uninit(bio);
+               kfree(bio);
+       }
        while (req->bio) {
                bio = req->bio;
                req->bio = bio->bi_next;
-               bio_put(bio);
+               bio_uninit(bio);
+               kfree(bio);
        }
        req->biotail = NULL;
        return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -994,8 +997,8 @@ static sector_t pscsi_get_blocks(struct se_device *dev)
 {
        struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);
 
-       if (pdv->pdv_bdev_handle)
-               return bdev_nr_sectors(pdv->pdv_bdev_handle->bdev);
+       if (pdv->pdv_bdev_file)
+               return bdev_nr_sectors(file_bdev(pdv->pdv_bdev_file));
        return 0;
 }
 
index b0a3ef136592a9b00653a14a525f1568af976cd1..9acaa21e4c78a431a4f165b27faeb5198fea706c 100644 (file)
@@ -37,7 +37,7 @@ struct pscsi_dev_virt {
        int     pdv_channel_id;
        int     pdv_target_id;
        int     pdv_lun_id;
-       struct bdev_handle *pdv_bdev_handle;
+       struct file *pdv_bdev_file;
        struct scsi_device *pdv_sd;
        struct Scsi_Host *pdv_lld_host;
 } ____cacheline_aligned;
index 4b10921276942ed13a43e531b723e746b76dd6fa..1892e49a8e6a68b5c0f8e719042b34b4d2856b42 100644 (file)
@@ -90,13 +90,14 @@ static int optee_register_device(const uuid_t *device_uuid, u32 func)
        if (rc) {
                pr_err("device registration failed, err: %d\n", rc);
                put_device(&optee_device->dev);
+               return rc;
        }
 
        if (func == PTA_CMD_GET_DEVICES_SUPP)
                device_create_file(&optee_device->dev,
                                   &dev_attr_need_supplicant);
 
-       return rc;
+       return 0;
 }
 
 static int __optee_enumerate_devices(u32 func)
index 792d6fae4354d5a389dbf953e02bb065b1b5fa47..e59c20d74b36ae08db5d372f46ef03b9c4694cb6 100644 (file)
@@ -1226,7 +1226,7 @@ static int tee_client_device_uevent(const struct device *dev,
        return add_uevent_var(env, "MODALIAS=tee:%pUb", dev_id);
 }
 
-struct bus_type tee_bus_type = {
+const struct bus_type tee_bus_type = {
        .name           = "tee",
        .match          = tee_client_device_match,
        .uevent         = tee_client_device_uevent,
index 3b04c6ec4fca0762c9508e7450fad4af989e71d6..40d664a66cdcb33f65736b4bfc933382ba01e7ca 100644 (file)
@@ -607,7 +607,7 @@ void __init intel_hfi_init(void)
 
        /* There is one HFI instance per die/package. */
        max_hfi_instances = topology_max_packages() *
-                           topology_max_die_per_package();
+                           topology_max_dies_per_package();
 
        /*
         * This allocation may fail. CPU hotplug callbacks must check
index bc6eb0dd66a495f04ae5d0c398611895351c9b2f..4ba649370aa1a7f8a687c476c4470178541b8baf 100644 (file)
@@ -587,7 +587,7 @@ static int powerclamp_idle_injection_register(void)
        poll_pkg_cstate_enable = false;
        if (cpumask_equal(cpu_present_mask, idle_injection_cpu_mask)) {
                ii_dev = idle_inject_register_full(idle_injection_cpu_mask, idle_inject_update);
-               if (topology_max_packages() == 1 && topology_max_die_per_package() == 1)
+               if (topology_max_packages() == 1 && topology_max_dies_per_package() == 1)
                        poll_pkg_cstate_enable = true;
        } else {
                ii_dev = idle_inject_register(idle_injection_cpu_mask);
index 11a7f8108bbbfeb5a92e054f203b242c340ebaf4..f6c2e5964b8f2e7ec0823097749013853b3e8016 100644 (file)
@@ -494,7 +494,7 @@ static int __init pkg_temp_thermal_init(void)
        if (!x86_match_cpu(pkg_temp_thermal_ids))
                return -ENODEV;
 
-       max_id = topology_max_packages() * topology_max_die_per_package();
+       max_id = topology_max_packages() * topology_max_dies_per_package();
        zones = kcalloc(max_id, sizeof(struct zone_device *),
                           GFP_KERNEL);
        if (!zones)
index 900114ba4371b10fd941e0add6ade8210c74268f..fad40c4bc710341f27b7f98f6d4317aef6627ae0 100644 (file)
@@ -1249,6 +1249,9 @@ int tb_port_update_credits(struct tb_port *port)
        ret = tb_port_do_update_credits(port);
        if (ret)
                return ret;
+
+       if (!port->dual_link_port)
+               return 0;
        return tb_port_do_update_credits(port->dual_link_port);
 }
 
index 87e4795275fe6772e0497e8c50650d4a1835b1af..6f798f6a2b8488ca5011fe813733ffc8b5942f48 100644 (file)
@@ -203,7 +203,7 @@ struct tb_regs_switch_header {
 #define ROUTER_CS_5_WOP                                BIT(1)
 #define ROUTER_CS_5_WOU                                BIT(2)
 #define ROUTER_CS_5_WOD                                BIT(3)
-#define ROUTER_CS_5_C3S                                BIT(23)
+#define ROUTER_CS_5_CNS                                BIT(23)
 #define ROUTER_CS_5_PTO                                BIT(24)
 #define ROUTER_CS_5_UTO                                BIT(25)
 #define ROUTER_CS_5_HCO                                BIT(26)
index f8f0d24ff6e4629856ea8a59b3941b79633d1781..1515eff8cc3e23434202fead2a9aa038080111d6 100644 (file)
@@ -290,7 +290,7 @@ int usb4_switch_setup(struct tb_switch *sw)
        }
 
        /* TBT3 supported by the CM */
-       val |= ROUTER_CS_5_C3S;
+       val &= ~ROUTER_CS_5_CNS;
 
        return tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1);
 }
index 6e05c5c7bca1ad258502eaf158b94534c1cdd23d..c2a4e88b328f35888cb44c0fe1ca5f57f2040e66 100644 (file)
@@ -108,13 +108,15 @@ config HVC_DCC_SERIALIZE_SMP
 
 config HVC_RISCV_SBI
        bool "RISC-V SBI console support"
-       depends on RISCV_SBI
+       depends on RISCV_SBI && NONPORTABLE
        select HVC_DRIVER
        help
          This enables support for console output via RISC-V SBI calls, which
-         is normally used only during boot to output printk.
+         is normally used only during boot to output printk.  This driver
+         conflicts with real console drivers and should not be enabled on
+         systems that directly access the console.
 
-         If you don't know what do to here, say Y.
+         If you don't know what do to here, say N.
 
 config HVCS
        tristate "IBM Hypervisor Virtual Console Server support"
index 2d1f350a4bea2a86103d707cc322ded0f5941abb..c1d43f040c43abc517c4ef6b48a5423e936e97f2 100644 (file)
@@ -357,9 +357,9 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
        long rate;
        int ret;
 
-       clk_disable_unprepare(d->clk);
        rate = clk_round_rate(d->clk, newrate);
-       if (rate > 0) {
+       if (rate > 0 && p->uartclk != rate) {
+               clk_disable_unprepare(d->clk);
                /*
                 * Note that any clock-notifer worker will block in
                 * serial8250_update_uartclk() until we are done.
@@ -367,8 +367,8 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
                ret = clk_set_rate(d->clk, newrate);
                if (!ret)
                        p->uartclk = rate;
+               clk_prepare_enable(d->clk);
        }
-       clk_prepare_enable(d->clk);
 
        dw8250_do_set_termios(p, termios, old);
 }
index cd258922bd780019609fee227f55d84ed3a04246..2dda737b1660bd7bd6f576d2146440d97e945047 100644 (file)
@@ -302,7 +302,7 @@ static void pci1xxxx_process_read_data(struct uart_port *port,
         * to read, the data is received one byte at a time.
         */
        while (valid_burst_count--) {
-               if (*buff_index >= (RX_BUF_SIZE - UART_BURST_SIZE))
+               if (*buff_index > (RX_BUF_SIZE - UART_BURST_SIZE))
                        break;
                burst_buf = (u32 *)&rx_buff[*buff_index];
                *burst_buf = readl(port->membase + UART_RX_BURST_FIFO);
index fccec1698a54104c1487ea65536dce7729123c61..cf2c890a560f05204e249b931668deca04b3cb27 100644 (file)
@@ -1339,11 +1339,41 @@ static void pl011_start_tx_pio(struct uart_amba_port *uap)
        }
 }
 
+static void pl011_rs485_tx_start(struct uart_amba_port *uap)
+{
+       struct uart_port *port = &uap->port;
+       u32 cr;
+
+       /* Enable transmitter */
+       cr = pl011_read(uap, REG_CR);
+       cr |= UART011_CR_TXE;
+
+       /* Disable receiver if half-duplex */
+       if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
+               cr &= ~UART011_CR_RXE;
+
+       if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
+               cr &= ~UART011_CR_RTS;
+       else
+               cr |= UART011_CR_RTS;
+
+       pl011_write(cr, uap, REG_CR);
+
+       if (port->rs485.delay_rts_before_send)
+               mdelay(port->rs485.delay_rts_before_send);
+
+       uap->rs485_tx_started = true;
+}
+
 static void pl011_start_tx(struct uart_port *port)
 {
        struct uart_amba_port *uap =
            container_of(port, struct uart_amba_port, port);
 
+       if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
+           !uap->rs485_tx_started)
+               pl011_rs485_tx_start(uap);
+
        if (!pl011_dma_tx_start(uap))
                pl011_start_tx_pio(uap);
 }
@@ -1424,42 +1454,12 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
        return true;
 }
 
-static void pl011_rs485_tx_start(struct uart_amba_port *uap)
-{
-       struct uart_port *port = &uap->port;
-       u32 cr;
-
-       /* Enable transmitter */
-       cr = pl011_read(uap, REG_CR);
-       cr |= UART011_CR_TXE;
-
-       /* Disable receiver if half-duplex */
-       if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
-               cr &= ~UART011_CR_RXE;
-
-       if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
-               cr &= ~UART011_CR_RTS;
-       else
-               cr |= UART011_CR_RTS;
-
-       pl011_write(cr, uap, REG_CR);
-
-       if (port->rs485.delay_rts_before_send)
-               mdelay(port->rs485.delay_rts_before_send);
-
-       uap->rs485_tx_started = true;
-}
-
 /* Returns true if tx interrupts have to be (kept) enabled  */
 static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
 {
        struct circ_buf *xmit = &uap->port.state->xmit;
        int count = uap->fifosize >> 1;
 
-       if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
-           !uap->rs485_tx_started)
-               pl011_rs485_tx_start(uap);
-
        if (uap->port.x_char) {
                if (!pl011_tx_char(uap, uap->port.x_char, from_irq))
                        return true;
index 5ddf110aedbe513b522d10e691cada5563fec4df..bbcbc91482af0bbd04db16242b4d955d21a9753a 100644 (file)
@@ -2345,9 +2345,12 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
 
        lpuart32_write(&sport->port, bd, UARTBAUD);
        lpuart32_serial_setbrg(sport, baud);
-       lpuart32_write(&sport->port, modem, UARTMODIR);
-       lpuart32_write(&sport->port, ctrl, UARTCTRL);
+       /* disable CTS before enabling UARTCTRL_TE to avoid pending idle preamble */
+       lpuart32_write(&sport->port, modem & ~UARTMODIR_TXCTSE, UARTMODIR);
        /* restore control register */
+       lpuart32_write(&sport->port, ctrl, UARTCTRL);
+       /* re-enable the CTS if needed */
+       lpuart32_write(&sport->port, modem, UARTMODIR);
 
        if ((ctrl & (UARTCTRL_PE | UARTCTRL_M)) == UARTCTRL_PE)
                sport->is_cs7 = true;
index 4aa72d5aeafbf081ac37241853c49cdb18e46ae5..e14813250616118e5ecfcfdafc1a4c1033f2bf79 100644 (file)
@@ -462,8 +462,7 @@ static void imx_uart_stop_tx(struct uart_port *port)
        }
 }
 
-/* called with port.lock taken and irqs off */
-static void imx_uart_stop_rx(struct uart_port *port)
+static void imx_uart_stop_rx_with_loopback_ctrl(struct uart_port *port, bool loopback)
 {
        struct imx_port *sport = (struct imx_port *)port;
        u32 ucr1, ucr2, ucr4, uts;
@@ -485,7 +484,7 @@ static void imx_uart_stop_rx(struct uart_port *port)
        /* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */
        if (port->rs485.flags & SER_RS485_ENABLED &&
            port->rs485.flags & SER_RS485_RTS_ON_SEND &&
-           sport->have_rtscts && !sport->have_rtsgpio) {
+           sport->have_rtscts && !sport->have_rtsgpio && loopback) {
                uts = imx_uart_readl(sport, imx_uart_uts_reg(sport));
                uts |= UTS_LOOP;
                imx_uart_writel(sport, uts, imx_uart_uts_reg(sport));
@@ -497,6 +496,16 @@ static void imx_uart_stop_rx(struct uart_port *port)
        imx_uart_writel(sport, ucr2, UCR2);
 }
 
+/* called with port.lock taken and irqs off */
+static void imx_uart_stop_rx(struct uart_port *port)
+{
+       /*
+        * Stop RX and enable loopback in order to make sure RS485 bus
+        * is not blocked. Se comment in imx_uart_probe().
+        */
+       imx_uart_stop_rx_with_loopback_ctrl(port, true);
+}
+
 /* called with port.lock taken and irqs off */
 static void imx_uart_enable_ms(struct uart_port *port)
 {
@@ -682,9 +691,14 @@ static void imx_uart_start_tx(struct uart_port *port)
                                imx_uart_rts_inactive(sport, &ucr2);
                        imx_uart_writel(sport, ucr2, UCR2);
 
+                       /*
+                        * Since we are about to transmit we can not stop RX
+                        * with loopback enabled because that will make our
+                        * transmitted data being just looped to RX.
+                        */
                        if (!(port->rs485.flags & SER_RS485_RX_DURING_TX) &&
                            !port->rs485_rx_during_tx_gpio)
-                               imx_uart_stop_rx(port);
+                               imx_uart_stop_rx_with_loopback_ctrl(port, false);
 
                        sport->tx_state = WAIT_AFTER_RTS;
 
index 3ec725555bcc1e6eb2843a186a5c49cba1ab0b42..4749331fe618cad7c0af98630f90021b8244bd07 100644 (file)
@@ -605,13 +605,16 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s)
                return;
        }
 
-       pending = uart_port_tx(&s->port, ch,
+       pending = uart_port_tx_flags(&s->port, ch, UART_TX_NOSTOP,
                !(mxs_read(s, REG_STAT) & AUART_STAT_TXFF),
                mxs_write(ch, s, REG_DATA));
        if (pending)
                mxs_set(AUART_INTR_TXIEN, s, REG_INTR);
        else
                mxs_clr(AUART_INTR_TXIEN, s, REG_INTR);
+
+       if (uart_tx_stopped(&s->port))
+               mxs_auart_stop_tx(&s->port);
 }
 
 static void mxs_auart_rx_char(struct mxs_auart_port *s)
index e63a8fbe63bdb22b70fd9362fae5d557c4c59b75..99e08737f293c6868e56d2de80f31bf0e3345ca3 100644 (file)
@@ -851,19 +851,21 @@ static void qcom_geni_serial_stop_tx(struct uart_port *uport)
 }
 
 static void qcom_geni_serial_send_chunk_fifo(struct uart_port *uport,
-                                            unsigned int remaining)
+                                            unsigned int chunk)
 {
        struct qcom_geni_serial_port *port = to_dev_port(uport);
        struct circ_buf *xmit = &uport->state->xmit;
-       unsigned int tx_bytes;
+       unsigned int tx_bytes, c, remaining = chunk;
        u8 buf[BYTES_PER_FIFO_WORD];
 
        while (remaining) {
                memset(buf, 0, sizeof(buf));
                tx_bytes = min(remaining, BYTES_PER_FIFO_WORD);
 
-               memcpy(buf, &xmit->buf[xmit->tail], tx_bytes);
-               uart_xmit_advance(uport, tx_bytes);
+               for (c = 0; c < tx_bytes ; c++) {
+                       buf[c] = xmit->buf[xmit->tail];
+                       uart_xmit_advance(uport, 1);
+               }
 
                iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);
 
index 88975a4df3060599b233abb49fe07ca53ba15b3a..72b6f4f326e2b04953875062f8ebc6e56f324e45 100644 (file)
@@ -46,8 +46,31 @@ out:
        return 0;
 }
 
+static int serial_port_runtime_suspend(struct device *dev)
+{
+       struct serial_port_device *port_dev = to_serial_base_port_device(dev);
+       struct uart_port *port = port_dev->port;
+       unsigned long flags;
+       bool busy;
+
+       if (port->flags & UPF_DEAD)
+               return 0;
+
+       uart_port_lock_irqsave(port, &flags);
+       busy = __serial_port_busy(port);
+       if (busy)
+               port->ops->start_tx(port);
+       uart_port_unlock_irqrestore(port, flags);
+
+       if (busy)
+               pm_runtime_mark_last_busy(dev);
+
+       return busy ? -EBUSY : 0;
+}
+
 static DEFINE_RUNTIME_DEV_PM_OPS(serial_port_pm,
-                                NULL, serial_port_runtime_resume, NULL);
+                                serial_port_runtime_suspend,
+                                serial_port_runtime_resume, NULL);
 
 static int serial_port_probe(struct device *dev)
 {
index 794b7751274034848c65a7e3374b694bcf61c42d..693e932d6feb5842467d1408e04c8d574342cb1f 100644 (file)
@@ -251,7 +251,9 @@ static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *ter
                writel_relaxed(cr3, port->membase + ofs->cr3);
                writel_relaxed(cr1, port->membase + ofs->cr1);
 
-               rs485conf->flags |= SER_RS485_RX_DURING_TX;
+               if (!port->rs485_rx_during_tx_gpio)
+                       rs485conf->flags |= SER_RS485_RX_DURING_TX;
+
        } else {
                stm32_usart_clr_bits(port, ofs->cr3,
                                     USART_CR3_DEM | USART_CR3_DEP);
index 156efda7c80d64b3c512d8cc84f228521aefec11..38a765eadbe2bc81494f1fbd7a63b50b87101f08 100644 (file)
@@ -381,7 +381,7 @@ static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr)
                u32 *ln = vc->vc_uni_lines[vc->state.y];
                unsigned int x = vc->state.x, cols = vc->vc_cols;
 
-               memcpy(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln));
+               memmove(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln));
                memset32(&ln[cols - nr], ' ', nr);
        }
 }
index d77b25b79ae3ec5c949912eb88b2433472180be0..eac7fff6992d0a863ec674c4c3c33f50b0d1f51e 100644 (file)
@@ -1469,7 +1469,7 @@ static int ufshcd_devfreq_target(struct device *dev,
        int ret = 0;
        struct ufs_hba *hba = dev_get_drvdata(dev);
        ktime_t start;
-       bool scale_up, sched_clk_scaling_suspend_work = false;
+       bool scale_up = false, sched_clk_scaling_suspend_work = false;
        struct list_head *clk_list = &hba->clk_list_head;
        struct ufs_clk_info *clki;
        unsigned long irq_flags;
@@ -10593,7 +10593,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
        err = blk_mq_alloc_tag_set(&hba->tmf_tag_set);
        if (err < 0)
                goto out_remove_scsi_host;
-       hba->tmf_queue = blk_mq_init_queue(&hba->tmf_tag_set);
+       hba->tmf_queue = blk_mq_alloc_queue(&hba->tmf_tag_set, NULL, NULL);
        if (IS_ERR(hba->tmf_queue)) {
                err = PTR_ERR(hba->tmf_queue);
                goto free_tmf_tag_set;
index 39eef470f8fa5b88b41450aeec8833a619899e34..8fde5204e88b06d1d83a055316064d55126c5de5 100644 (file)
@@ -1712,8 +1712,8 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba)
         * 2. Poll queues do not need ESI.
         */
        nr_irqs = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL];
-       ret = platform_msi_domain_alloc_irqs(hba->dev, nr_irqs,
-                                            ufs_qcom_write_msi_msg);
+       ret = platform_device_msi_init_and_alloc_irqs(hba->dev, nr_irqs,
+                                                     ufs_qcom_write_msi_msg);
        if (ret) {
                dev_err(hba->dev, "Failed to request Platform MSI %d\n", ret);
                return ret;
@@ -1742,7 +1742,7 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba)
                        devm_free_irq(hba->dev, desc->irq, hba);
                }
                msi_unlock_descs(hba->dev);
-               platform_msi_domain_free_irqs(hba->dev);
+               platform_device_msi_free_irqs_all(hba->dev);
        } else {
                if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 &&
                    host->hw_ver.step == 0)
@@ -1818,7 +1818,7 @@ static void ufs_qcom_remove(struct platform_device *pdev)
 
        pm_runtime_get_sync(&(pdev)->dev);
        ufshcd_remove(hba);
-       platform_msi_domain_free_irqs(hba->dev);
+       platform_device_msi_free_irqs_all(hba->dev);
 }
 
 static const struct of_device_id ufs_qcom_of_match[] __maybe_unused = {
index aeca902ab6cc427b0946cf13ea9b8c725eb3f287..fd1beb10bba726cef258e7438d642f31d6567dfe 100644 (file)
@@ -828,7 +828,11 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep,
                        return;
        }
 
-       if (request->complete) {
+       /*
+        * zlp request is appended by driver, needn't call usb_gadget_giveback_request() to notify
+        * gadget composite driver.
+        */
+       if (request->complete && request->buf != priv_dev->zlp_buf) {
                spin_unlock(&priv_dev->lock);
                usb_gadget_giveback_request(&priv_ep->endpoint,
                                            request);
@@ -2540,11 +2544,11 @@ static int cdns3_gadget_ep_disable(struct usb_ep *ep)
 
        while (!list_empty(&priv_ep->wa2_descmiss_req_list)) {
                priv_req = cdns3_next_priv_request(&priv_ep->wa2_descmiss_req_list);
+               list_del_init(&priv_req->list);
 
                kfree(priv_req->request.buf);
                cdns3_gadget_ep_free_request(&priv_ep->endpoint,
                                             &priv_req->request);
-               list_del_init(&priv_req->list);
                --priv_ep->wa2_counter;
        }
 
index 33548771a0d3a7212781ff39814fedb7d01f0ab4..465e9267b49c12768ac72ecb818f731fc8787641 100644 (file)
@@ -395,7 +395,6 @@ pm_put:
        return ret;
 }
 
-
 /**
  * cdns_wakeup_irq - interrupt handler for wakeup events
  * @irq: irq number for cdns3/cdnsp core device
index 04b6d12f2b9a39b9bfad76fe1909b22f7c010990..ee917f1b091c893ebccad19bd5a62aea9e65c721 100644 (file)
@@ -156,7 +156,8 @@ bool cdns_is_device(struct cdns *cdns)
  */
 static void cdns_otg_disable_irq(struct cdns *cdns)
 {
-       writel(0, &cdns->otg_irq_regs->ien);
+       if (cdns->version)
+               writel(0, &cdns->otg_irq_regs->ien);
 }
 
 /**
@@ -422,15 +423,20 @@ int cdns_drd_init(struct cdns *cdns)
 
                cdns->otg_regs = (void __iomem *)&cdns->otg_v1_regs->cmd;
 
-               if (readl(&cdns->otg_cdnsp_regs->did) == OTG_CDNSP_DID) {
+               state = readl(&cdns->otg_cdnsp_regs->did);
+
+               if (OTG_CDNSP_CHECK_DID(state)) {
                        cdns->otg_irq_regs = (struct cdns_otg_irq_regs __iomem *)
                                              &cdns->otg_cdnsp_regs->ien;
                        cdns->version  = CDNSP_CONTROLLER_V2;
-               } else {
+               } else if (OTG_CDNS3_CHECK_DID(state)) {
                        cdns->otg_irq_regs = (struct cdns_otg_irq_regs __iomem *)
                                              &cdns->otg_v1_regs->ien;
                        writel(1, &cdns->otg_v1_regs->simulate);
                        cdns->version  = CDNS3_CONTROLLER_V1;
+               } else {
+                       dev_err(cdns->dev, "not supporte DID=0x%08x\n", state);
+                       return -EINVAL;
                }
 
                dev_dbg(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n",
@@ -483,7 +489,6 @@ int cdns_drd_exit(struct cdns *cdns)
        return 0;
 }
 
-
 /* Indicate the cdns3 core was power lost before */
 bool cdns_power_is_lost(struct cdns *cdns)
 {
index cbdf94f73ed917bb14baf23a9087b10aca2f7015..d72370c321d3929fc477854585d9e46be6848fef 100644 (file)
@@ -79,7 +79,11 @@ struct cdnsp_otg_regs {
        __le32 susp_timing_ctrl;
 };
 
-#define OTG_CDNSP_DID  0x0004034E
+/* CDNSP driver supports 0x000403xx Cadence USB controller family. */
+#define OTG_CDNSP_CHECK_DID(did) (((did) & GENMASK(31, 8)) == 0x00040300)
+
+/* CDNS3 driver supports 0x000402xx Cadence USB controller family. */
+#define OTG_CDNS3_CHECK_DID(did) (((did) & GENMASK(31, 8)) == 0x00040200)
 
 /*
  * Common registers interface for both CDNS3 and CDNSP version of DRD.
index 6164fc4c96a49b60b73f772bdc92b8acf383269c..ceca4d839dfd42b87167f4de3019ab63776fa6c2 100644 (file)
 #include "../host/xhci.h"
 #include "../host/xhci-plat.h"
 
+/*
+ * The XECP_PORT_CAP_REG and XECP_AUX_CTRL_REG1 exist only
+ * in Cadence USB3 dual-role controller, so it can't be used
+ * with Cadence CDNSP dual-role controller.
+ */
 #define XECP_PORT_CAP_REG      0x8000
 #define XECP_AUX_CTRL_REG1     0x8120
 
@@ -57,6 +62,8 @@ static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
        .resume_quirk = xhci_cdns3_resume_quirk,
 };
 
+static const struct xhci_plat_priv xhci_plat_cdnsp_xhci;
+
 static int __cdns_host_init(struct cdns *cdns)
 {
        struct platform_device *xhci;
@@ -81,8 +88,13 @@ static int __cdns_host_init(struct cdns *cdns)
                goto err1;
        }
 
-       cdns->xhci_plat_data = kmemdup(&xhci_plat_cdns3_xhci,
-                       sizeof(struct xhci_plat_priv), GFP_KERNEL);
+       if (cdns->version < CDNSP_CONTROLLER_V2)
+               cdns->xhci_plat_data = kmemdup(&xhci_plat_cdns3_xhci,
+                               sizeof(struct xhci_plat_priv), GFP_KERNEL);
+       else
+               cdns->xhci_plat_data = kmemdup(&xhci_plat_cdnsp_xhci,
+                               sizeof(struct xhci_plat_priv), GFP_KERNEL);
+
        if (!cdns->xhci_plat_data) {
                ret = -ENOMEM;
                goto err1;
index 12b6dfeaf658c909aeef88699c42a40a7d15c38e..edf74458474a1e7065d3d6c3bd651e9cbba172b8 100644 (file)
@@ -1664,9 +1664,10 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
        usb_put_urb(urb);
 }
 
-static void usb_giveback_urb_bh(struct tasklet_struct *t)
+static void usb_giveback_urb_bh(struct work_struct *work)
 {
-       struct giveback_urb_bh *bh = from_tasklet(bh, t, bh);
+       struct giveback_urb_bh *bh =
+               container_of(work, struct giveback_urb_bh, bh);
        struct list_head local_list;
 
        spin_lock_irq(&bh->lock);
@@ -1691,9 +1692,9 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t)
        spin_lock_irq(&bh->lock);
        if (!list_empty(&bh->head)) {
                if (bh->high_prio)
-                       tasklet_hi_schedule(&bh->bh);
+                       queue_work(system_bh_highpri_wq, &bh->bh);
                else
-                       tasklet_schedule(&bh->bh);
+                       queue_work(system_bh_wq, &bh->bh);
        }
        bh->running = false;
        spin_unlock_irq(&bh->lock);
@@ -1706,7 +1707,7 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t)
  * @status: completion status code for the URB.
  *
  * Context: atomic. The completion callback is invoked in caller's context.
- * For HCDs with HCD_BH flag set, the completion callback is invoked in tasklet
+ * For HCDs with HCD_BH flag set, the completion callback is invoked in BH
  * context (except for URBs submitted to the root hub which always complete in
  * caller's context).
  *
@@ -1725,7 +1726,7 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
        struct giveback_urb_bh *bh;
        bool running;
 
-       /* pass status to tasklet via unlinked */
+       /* pass status to BH via unlinked */
        if (likely(!urb->unlinked))
                urb->unlinked = status;
 
@@ -1747,9 +1748,9 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
        if (running)
                ;
        else if (bh->high_prio)
-               tasklet_hi_schedule(&bh->bh);
+               queue_work(system_bh_highpri_wq, &bh->bh);
        else
-               tasklet_schedule(&bh->bh);
+               queue_work(system_bh_wq, &bh->bh);
 }
 EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb);
 
@@ -2540,7 +2541,7 @@ static void init_giveback_urb_bh(struct giveback_urb_bh *bh)
 
        spin_lock_init(&bh->lock);
        INIT_LIST_HEAD(&bh->head);
-       tasklet_setup(&bh->bh, usb_giveback_urb_bh);
+       INIT_WORK(&bh->bh, usb_giveback_urb_bh);
 }
 
 struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver,
@@ -2926,7 +2927,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
                        && device_can_wakeup(&hcd->self.root_hub->dev))
                dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
 
-       /* initialize tasklets */
+       /* initialize BHs */
        init_giveback_urb_bh(&hcd->high_prio_bh);
        hcd->high_prio_bh.high_prio = true;
        init_giveback_urb_bh(&hcd->low_prio_bh);
@@ -3036,7 +3037,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
        mutex_unlock(&usb_bus_idr_lock);
 
        /*
-        * tasklet_kill() isn't needed here because:
+        * flush_work() isn't needed here because:
         * - driver's disconnect() called from usb_disconnect() should
         *   make sure its URBs are completed during the disconnect()
         *   callback
index c628c1abc90711cb9b8e652a0d903a6359c968bc..4d63496f98b6c45074eee270db26c53b4019dac6 100644 (file)
@@ -573,7 +573,7 @@ static int match_location(struct usb_device *peer_hdev, void *p)
        struct usb_hub *peer_hub = usb_hub_to_struct_hub(peer_hdev);
        struct usb_device *hdev = to_usb_device(port_dev->dev.parent->parent);
 
-       if (!peer_hub)
+       if (!peer_hub || port_dev->connect_type == USB_PORT_NOT_USED)
                return 0;
 
        hcd = bus_to_hcd(hdev->bus);
@@ -584,7 +584,8 @@ static int match_location(struct usb_device *peer_hdev, void *p)
 
        for (port1 = 1; port1 <= peer_hdev->maxchild; port1++) {
                peer = peer_hub->ports[port1 - 1];
-               if (peer && peer->location == port_dev->location) {
+               if (peer && peer->connect_type != USB_PORT_NOT_USED &&
+                   peer->location == port_dev->location) {
                        link_peers_report(port_dev, peer);
                        return 1; /* done */
                }
index e3eea965e57bfd3d32fa6b1cb52fd4072734a30d..e120611a5174f7589ac124641a7b279654babff6 100644 (file)
 /* Global HWPARAMS4 Register */
 #define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n)   (((n) & (0x0f << 13)) >> 13)
 #define DWC3_MAX_HIBER_SCRATCHBUFS             15
-#define DWC3_EXT_BUFF_CONTROL          BIT(21)
 
 /* Global HWPARAMS6 Register */
 #define DWC3_GHWPARAMS6_BCSUPPORT              BIT(14)
index 564976b3e2b911e6709758cc8bdbe0c85df86562..28f49400f3e8b178e23c881120577da461178c35 100644 (file)
@@ -673,12 +673,6 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action)
                params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(bInterval_m1);
        }
 
-       if (dep->endpoint.fifo_mode) {
-               if (!(dwc->hwparams.hwparams4 & DWC3_EXT_BUFF_CONTROL))
-                       return -EINVAL;
-               params.param1 |= DWC3_DEPCFG_EBC_HWO_NOWB | DWC3_DEPCFG_USE_EBC;
-       }
-
        return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETEPCONFIG, &params);
 }
 
@@ -2656,6 +2650,11 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
        int ret;
 
        spin_lock_irqsave(&dwc->lock, flags);
+       if (!dwc->pullups_connected) {
+               spin_unlock_irqrestore(&dwc->lock, flags);
+               return 0;
+       }
+
        dwc->connected = false;
 
        /*
index fd7a4e94397e64ccc74e362e5d73319918fdbae6..55a56cf67d7364998f9f4a42fd95e5d856cd105c 100644 (file)
@@ -26,8 +26,6 @@ struct dwc3;
 #define DWC3_DEPCFG_XFER_NOT_READY_EN  BIT(10)
 #define DWC3_DEPCFG_FIFO_ERROR_EN      BIT(11)
 #define DWC3_DEPCFG_STREAM_EVENT_EN    BIT(13)
-#define DWC3_DEPCFG_EBC_HWO_NOWB       BIT(14)
-#define DWC3_DEPCFG_USE_EBC            BIT(15)
 #define DWC3_DEPCFG_BINTERVAL_M1(n)    (((n) & 0xff) << 16)
 #define DWC3_DEPCFG_STREAM_CAPABLE     BIT(24)
 #define DWC3_DEPCFG_EP_NUMBER(n)       (((n) & 0x1f) << 25)
index ca5d5f5649982a6752b03053421cbf31c7589276..28f4e6552e84592566d261ec3174773650c5d444 100644 (file)
@@ -1338,7 +1338,15 @@ parse_ntb:
             "Parsed NTB with %d frames\n", dgram_counter);
 
        to_process -= block_len;
-       if (to_process != 0) {
+
+       /*
+        * Windows NCM driver avoids USB ZLPs by adding a 1-byte
+        * zero pad as needed.
+        */
+       if (to_process == 1 &&
+           (*(unsigned char *)(ntb_ptr + block_len) == 0x00)) {
+               to_process--;
+       } else if ((to_process > 0) && (block_len != 0)) {
                ntb_ptr = (unsigned char *)(ntb_ptr + block_len);
                goto parse_ntb;
        }
index 10c5d7f726a1fdd967d058bcc60302db8d839009..f90eeecf27de110ee4abc9d4cebef8cf73306193 100644 (file)
@@ -2036,7 +2036,8 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
 
 static inline int machine_without_vbus_sense(void)
 {
-       return  machine_is_omap_osk() || machine_is_sx1();
+       return  machine_is_omap_osk() || machine_is_omap_palmte() ||
+               machine_is_sx1();
 }
 
 static int omap_udc_start(struct usb_gadget *g,
index ac3fc597031573199a141e60e2b54432d2a2782e..cfebb833668e4b014633d0919be1aa1777c25140 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
+#include <linux/platform_device.h>
 
 static int uhci_grlib_init(struct usb_hcd *hcd)
 {
index f0d8a607ff214f86ba33b2e9126ccb186e6c1853..4f64b814d4aa20fdd08e349e5c07324b3e105c5e 100644 (file)
@@ -326,7 +326,13 @@ static unsigned int xhci_ring_expansion_needed(struct xhci_hcd *xhci, struct xhc
        /* how many trbs will be queued past the enqueue segment? */
        trbs_past_seg = enq_used + num_trbs - (TRBS_PER_SEGMENT - 1);
 
-       if (trbs_past_seg <= 0)
+       /*
+        * Consider expanding the ring already if num_trbs fills the current
+        * segment (i.e. trbs_past_seg == 0), not only when num_trbs goes into
+        * the next segment. Avoids confusing full ring with special empty ring
+        * case below
+        */
+       if (trbs_past_seg < 0)
                return 0;
 
        /* Empty ring special case, enqueue stuck on link trb while dequeue advanced */
index ae41578bd0149900b0a867f71a0cf6080e238566..70165dd86b5de958ab4f5fe0d1573988977be425 100644 (file)
@@ -21,7 +21,9 @@ static const struct class role_class = {
 struct usb_role_switch {
        struct device dev;
        struct mutex lock; /* device lock*/
+       struct module *module; /* the module this device depends on */
        enum usb_role role;
+       bool registered;
 
        /* From descriptor */
        struct device *usb2_port;
@@ -48,6 +50,9 @@ int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role)
        if (IS_ERR_OR_NULL(sw))
                return 0;
 
+       if (!sw->registered)
+               return -EOPNOTSUPP;
+
        mutex_lock(&sw->lock);
 
        ret = sw->set(sw, role);
@@ -73,7 +78,7 @@ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw)
 {
        enum usb_role role;
 
-       if (IS_ERR_OR_NULL(sw))
+       if (IS_ERR_OR_NULL(sw) || !sw->registered)
                return USB_ROLE_NONE;
 
        mutex_lock(&sw->lock);
@@ -135,7 +140,7 @@ struct usb_role_switch *usb_role_switch_get(struct device *dev)
                                                  usb_role_switch_match);
 
        if (!IS_ERR_OR_NULL(sw))
-               WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
+               WARN_ON(!try_module_get(sw->module));
 
        return sw;
 }
@@ -157,7 +162,7 @@ struct usb_role_switch *fwnode_usb_role_switch_get(struct fwnode_handle *fwnode)
                sw = fwnode_connection_find_match(fwnode, "usb-role-switch",
                                                  NULL, usb_role_switch_match);
        if (!IS_ERR_OR_NULL(sw))
-               WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
+               WARN_ON(!try_module_get(sw->module));
 
        return sw;
 }
@@ -172,7 +177,7 @@ EXPORT_SYMBOL_GPL(fwnode_usb_role_switch_get);
 void usb_role_switch_put(struct usb_role_switch *sw)
 {
        if (!IS_ERR_OR_NULL(sw)) {
-               module_put(sw->dev.parent->driver->owner);
+               module_put(sw->module);
                put_device(&sw->dev);
        }
 }
@@ -189,15 +194,18 @@ struct usb_role_switch *
 usb_role_switch_find_by_fwnode(const struct fwnode_handle *fwnode)
 {
        struct device *dev;
+       struct usb_role_switch *sw = NULL;
 
        if (!fwnode)
                return NULL;
 
        dev = class_find_device_by_fwnode(&role_class, fwnode);
-       if (dev)
-               WARN_ON(!try_module_get(dev->parent->driver->owner));
+       if (dev) {
+               sw = to_role_switch(dev);
+               WARN_ON(!try_module_get(sw->module));
+       }
 
-       return dev ? to_role_switch(dev) : NULL;
+       return sw;
 }
 EXPORT_SYMBOL_GPL(usb_role_switch_find_by_fwnode);
 
@@ -338,6 +346,7 @@ usb_role_switch_register(struct device *parent,
        sw->set = desc->set;
        sw->get = desc->get;
 
+       sw->module = parent->driver->owner;
        sw->dev.parent = parent;
        sw->dev.fwnode = desc->fwnode;
        sw->dev.class = &role_class;
@@ -352,6 +361,8 @@ usb_role_switch_register(struct device *parent,
                return ERR_PTR(ret);
        }
 
+       sw->registered = true;
+
        /* TODO: Symlinks for the host port and the device controller. */
 
        return sw;
@@ -366,8 +377,10 @@ EXPORT_SYMBOL_GPL(usb_role_switch_register);
  */
 void usb_role_switch_unregister(struct usb_role_switch *sw)
 {
-       if (!IS_ERR_OR_NULL(sw))
+       if (!IS_ERR_OR_NULL(sw)) {
+               sw->registered = false;
                device_unregister(&sw->dev);
+       }
 }
 EXPORT_SYMBOL_GPL(usb_role_switch_unregister);
 
index 4e0eef1440b7fd7407cf2158adad796b516aeda5..300aeef160e75c9d84fbd4b69b3c3ad35a774f5b 100644 (file)
@@ -1105,7 +1105,7 @@ static void isd200_dump_driveid(struct us_data *us, u16 *id)
 static int isd200_get_inquiry_data( struct us_data *us )
 {
        struct isd200_info *info = (struct isd200_info *)us->extra;
-       int retStatus = ISD200_GOOD;
+       int retStatus;
        u16 *id = info->id;
 
        usb_stor_dbg(us, "Entering isd200_get_inquiry_data\n");
@@ -1137,6 +1137,13 @@ static int isd200_get_inquiry_data( struct us_data *us )
                                isd200_fix_driveid(id);
                                isd200_dump_driveid(us, id);
 
+                               /* Prevent division by 0 in isd200_scsi_to_ata() */
+                               if (id[ATA_ID_HEADS] == 0 || id[ATA_ID_SECTORS] == 0) {
+                                       usb_stor_dbg(us, "   Invalid ATA Identify data\n");
+                                       retStatus = ISD200_ERROR;
+                                       goto Done;
+                               }
+
                                memset(&info->InquiryData, 0, sizeof(info->InquiryData));
 
                                /* Standard IDE interface only supports disks */
@@ -1202,6 +1209,7 @@ static int isd200_get_inquiry_data( struct us_data *us )
                }
        }
 
+ Done:
        usb_stor_dbg(us, "Leaving isd200_get_inquiry_data %08X\n", retStatus);
 
        return(retStatus);
@@ -1481,22 +1489,27 @@ static int isd200_init_info(struct us_data *us)
 
 static int isd200_Initialization(struct us_data *us)
 {
+       int rc = 0;
+
        usb_stor_dbg(us, "ISD200 Initialization...\n");
 
        /* Initialize ISD200 info struct */
 
-       if (isd200_init_info(us) == ISD200_ERROR) {
+       if (isd200_init_info(us) < 0) {
                usb_stor_dbg(us, "ERROR Initializing ISD200 Info struct\n");
+               rc = -ENOMEM;
        } else {
                /* Get device specific data */
 
-               if (isd200_get_inquiry_data(us) != ISD200_GOOD)
+               if (isd200_get_inquiry_data(us) != ISD200_GOOD) {
                        usb_stor_dbg(us, "ISD200 Initialization Failure\n");
-               else
+                       rc = -EINVAL;
+               } else {
                        usb_stor_dbg(us, "ISD200 Initialization complete\n");
+               }
        }
 
-       return 0;
+       return rc;
 }
 
 
index c54e9805da536a0ec139ad789017b79131c88561..12cf9940e5b6759167f9ae7450df8af92a85c63a 100644 (file)
@@ -179,6 +179,13 @@ static int slave_configure(struct scsi_device *sdev)
                 */
                sdev->use_192_bytes_for_3f = 1;
 
+               /*
+                * Some devices report generic values until the media has been
+                * accessed. Force a READ(10) prior to querying device
+                * characteristics.
+                */
+               sdev->read_before_ms = 1;
+
                /*
                 * Some devices don't like MODE SENSE with page=0x3f,
                 * which is the command used for checking if a device
index 9707f53cfda9c08507082ac33b69b5d146c6927f..71ace274761f182f0cbb942676e74d7e2c26d7a1 100644 (file)
@@ -878,6 +878,13 @@ static int uas_slave_configure(struct scsi_device *sdev)
        if (devinfo->flags & US_FL_CAPACITY_HEURISTICS)
                sdev->guess_capacity = 1;
 
+       /*
+        * Some devices report generic values until the media has been
+        * accessed. Force a READ(10) prior to querying device
+        * characteristics.
+        */
+       sdev->read_before_ms = 1;
+
        /*
         * Some devices don't like MODE SENSE with page=0x3f,
         * which is the command used for checking if a device
index f81bec0c7b864dc605143078ec9f1cd3e2706379..f8ea3054be54245c4233b48facaabe91f52868ed 100644 (file)
@@ -559,16 +559,21 @@ static ssize_t hpd_show(struct device *dev, struct device_attribute *attr, char
 }
 static DEVICE_ATTR_RO(hpd);
 
-static struct attribute *dp_altmode_attrs[] = {
+static struct attribute *displayport_attrs[] = {
        &dev_attr_configuration.attr,
        &dev_attr_pin_assignment.attr,
        &dev_attr_hpd.attr,
        NULL
 };
 
-static const struct attribute_group dp_altmode_group = {
+static const struct attribute_group displayport_group = {
        .name = "displayport",
-       .attrs = dp_altmode_attrs,
+       .attrs = displayport_attrs,
+};
+
+static const struct attribute_group *displayport_groups[] = {
+       &displayport_group,
+       NULL,
 };
 
 int dp_altmode_probe(struct typec_altmode *alt)
@@ -576,7 +581,6 @@ int dp_altmode_probe(struct typec_altmode *alt)
        const struct typec_altmode *port = typec_altmode_get_partner(alt);
        struct fwnode_handle *fwnode;
        struct dp_altmode *dp;
-       int ret;
 
        /* FIXME: Port can only be DFP_U. */
 
@@ -587,10 +591,6 @@ int dp_altmode_probe(struct typec_altmode *alt)
              DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo)))
                return -ENODEV;
 
-       ret = sysfs_create_group(&alt->dev.kobj, &dp_altmode_group);
-       if (ret)
-               return ret;
-
        dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL);
        if (!dp)
                return -ENOMEM;
@@ -624,7 +624,6 @@ void dp_altmode_remove(struct typec_altmode *alt)
 {
        struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
 
-       sysfs_remove_group(&alt->dev.kobj, &dp_altmode_group);
        cancel_work_sync(&dp->work);
 
        if (dp->connector_fwnode) {
@@ -649,6 +648,7 @@ static struct typec_altmode_driver dp_altmode_driver = {
        .driver = {
                .name = "typec_displayport",
                .owner = THIS_MODULE,
+               .dev_groups = displayport_groups,
        },
 };
 module_typec_altmode_driver(dp_altmode_driver);
index f7d7daa60c8dc98b04d29f10b2e1377b02124d61..0965972310275e1c4d82be94051573648175a4fe 100644 (file)
@@ -3743,9 +3743,6 @@ static void tcpm_detach(struct tcpm_port *port)
        if (tcpm_port_is_disconnected(port))
                port->hard_reset_count = 0;
 
-       port->try_src_count = 0;
-       port->try_snk_count = 0;
-
        if (!port->attached)
                return;
 
@@ -4876,7 +4873,11 @@ static void run_state_machine(struct tcpm_port *port)
                break;
        case PORT_RESET:
                tcpm_reset_port(port);
-               tcpm_set_cc(port, TYPEC_CC_OPEN);
+               if (port->self_powered)
+                       tcpm_set_cc(port, TYPEC_CC_OPEN);
+               else
+                       tcpm_set_cc(port, tcpm_default_state(port) == SNK_UNATTACHED ?
+                                   TYPEC_CC_RD : tcpm_rp_cc(port));
                tcpm_set_state(port, PORT_RESET_WAIT_OFF,
                               PD_T_ERROR_RECOVERY);
                break;
index 53a7ede8556df5688abb2631ce78a7c13dbc8308..faccc942b381be43700f0de95401bef80af500ec 100644 (file)
@@ -301,6 +301,7 @@ static const struct of_device_id pmic_glink_ucsi_of_quirks[] = {
        { .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, },
        { .compatible = "qcom,sc8280xp-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, },
        { .compatible = "qcom,sm8350-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, },
+       { .compatible = "qcom,sm8550-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, },
        {}
 };
 
index 1183e7a871f8b270a9ff2106cef15e44720184a4..46823c2e2ba1207e327607fa0ca0c757bc0968aa 100644 (file)
@@ -2399,11 +2399,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
        struct fbcon_ops *ops = info->fbcon_par;
        struct fbcon_display *p = &fb_display[vc->vc_num];
        int resize, ret, old_userfont, old_width, old_height, old_charcount;
-       char *old_data = NULL;
+       u8 *old_data = vc->vc_font.data;
 
        resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
-       if (p->userfont)
-               old_data = vc->vc_font.data;
        vc->vc_font.data = (void *)(p->fontdata = data);
        old_userfont = p->userfont;
        if ((p->userfont = userfont))
@@ -2437,13 +2435,13 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
                update_screen(vc);
        }
 
-       if (old_data && (--REFCOUNT(old_data) == 0))
+       if (old_userfont && (--REFCOUNT(old_data) == 0))
                kfree(old_data - FONT_EXTRA_WORDS * sizeof(int));
        return 0;
 
 err_out:
        p->fontdata = old_data;
-       vc->vc_font.data = (void *)old_data;
+       vc->vc_font.data = old_data;
 
        if (userfont) {
                p->userfont = old_userfont;
index c26ee6fd73c9bb0cff77793e2af4ca5407c59aa1..8fdccf033b2d9bf9a05e967fb166bbabe82bfe19 100644 (file)
@@ -1010,8 +1010,6 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
                        goto getmem_done;
                }
                pr_info("Unable to allocate enough contiguous physical memory on Gen 1 VM. Using MMIO instead.\n");
-       } else {
-               goto err1;
        }
 
        /*
index 7d22051b15a29946f47ffb0d3c0beb6ecf20e766..d78fe7137799ac28ec24fb784859eaeac019fd16 100644 (file)
@@ -512,7 +512,6 @@ config S3C2410_WATCHDOG
        tristate "S3C6410/S5Pv210/Exynos Watchdog"
        depends on ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
        select WATCHDOG_CORE
-       select MFD_SYSCON if ARCH_EXYNOS
        help
          Watchdog timer block in the Samsung S3C64xx, S5Pv210 and Exynos
          SoCs. This will reboot the system when the timer expires with
index 349d30462c8c0c7c6a5e0f6fae071b2a052ca97f..686cf544d0ae7a607f087a09c0ff6a64b3803158 100644 (file)
@@ -24,9 +24,9 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/of.h>
-#include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
 #include <linux/delay.h>
+#include <linux/soc/samsung/exynos-pmu.h>
 
 #define S3C2410_WTCON          0x00
 #define S3C2410_WTDAT          0x04
@@ -699,11 +699,11 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
                return ret;
 
        if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) {
-               wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
-                                               "samsung,syscon-phandle");
+               wdt->pmureg = exynos_get_pmu_regmap_by_phandle(dev->of_node,
+                                                "samsung,syscon-phandle");
                if (IS_ERR(wdt->pmureg))
                        return dev_err_probe(dev, PTR_ERR(wdt->pmureg),
-                                            "syscon regmap lookup failed.\n");
+                                            "PMU regmap lookup failed.\n");
        }
 
        wdt_irq = platform_get_irq(pdev, 0);
index b8cfea7812d6b61110cc5e42fe4249d4578dc721..2faa4bf78c7a9d87a0cbfe76358c2ad7538f6b48 100644 (file)
@@ -923,8 +923,8 @@ static void shutdown_pirq(struct irq_data *data)
                return;
 
        do_mask(info, EVT_MASK_REASON_EXPLICIT);
-       xen_evtchn_close(evtchn);
        xen_irq_info_cleanup(info);
+       xen_evtchn_close(evtchn);
 }
 
 static void enable_pirq(struct irq_data *data)
@@ -956,6 +956,7 @@ EXPORT_SYMBOL_GPL(xen_irq_from_gsi);
 static void __unbind_from_irq(struct irq_info *info, unsigned int irq)
 {
        evtchn_port_t evtchn;
+       bool close_evtchn = false;
 
        if (!info) {
                xen_irq_free_desc(irq);
@@ -975,7 +976,7 @@ static void __unbind_from_irq(struct irq_info *info, unsigned int irq)
                struct xenbus_device *dev;
 
                if (!info->is_static)
-                       xen_evtchn_close(evtchn);
+                       close_evtchn = true;
 
                switch (info->type) {
                case IRQT_VIRQ:
@@ -995,6 +996,9 @@ static void __unbind_from_irq(struct irq_info *info, unsigned int irq)
                }
 
                xen_irq_info_cleanup(info);
+
+               if (close_evtchn)
+                       xen_evtchn_close(evtchn);
        }
 
        xen_free_irq(info);
@@ -2216,7 +2220,7 @@ static __init void xen_alloc_callback_vector(void)
                return;
 
        pr_info("Xen HVM callback vector for event delivery is enabled\n");
-       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, asm_sysvec_xen_hvm_callback);
+       sysvec_install(HYPERVISOR_CALLBACK_VECTOR, sysvec_xen_hvm_callback);
 }
 #else
 void xen_setup_callback_vector(void) {}
index 26ffb8755ffb5da27bd1eb38ceeb59ca06c473ed..f93f73ecefeee4b2b052a3ac758a8fbf9fdc11ae 100644 (file)
@@ -317,7 +317,7 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
                rc = -EFAULT;
                goto out_free;
        }
-       if (copy_to_user(arg->gref_ids, gref_ids,
+       if (copy_to_user(arg->gref_ids_flex, gref_ids,
                        sizeof(gref_ids[0]) * op.count)) {
                rc = -EFAULT;
                goto out_free;
index 50865527314538a8bedbde0f2590fbbb4afce3ce..c63f317e3df3de111b63a6f1b58feefca7de998b 100644 (file)
@@ -65,7 +65,7 @@ struct pcpu {
        uint32_t flags;
 };
 
-static struct bus_type xen_pcpu_subsys = {
+static const struct bus_type xen_pcpu_subsys = {
        .name = "xen_cpu",
        .dev_name = "xen_cpu",
 };
index 35b6e306026a4bfa1829f39f9b63ee8568f332d3..67dfa47788649328f6ad5783902f7dbcee9efa48 100644 (file)
@@ -1223,18 +1223,13 @@ struct privcmd_kernel_ioreq *alloc_ioreq(struct privcmd_ioeventfd *ioeventfd)
        kioreq->ioreq = (struct ioreq *)(page_to_virt(pages[0]));
        mmap_write_unlock(mm);
 
-       size = sizeof(*ports) * kioreq->vcpus;
-       ports = kzalloc(size, GFP_KERNEL);
-       if (!ports) {
-               ret = -ENOMEM;
+       ports = memdup_array_user(u64_to_user_ptr(ioeventfd->ports),
+                                 kioreq->vcpus, sizeof(*ports));
+       if (IS_ERR(ports)) {
+               ret = PTR_ERR(ports);
                goto error_kfree;
        }
 
-       if (copy_from_user(ports, u64_to_user_ptr(ioeventfd->ports), size)) {
-               ret = -EFAULT;
-               goto error_kfree_ports;
-       }
-
        for (i = 0; i < kioreq->vcpus; i++) {
                kioreq->ports[i].vcpu = i;
                kioreq->ports[i].port = ports[i];
@@ -1256,7 +1251,7 @@ struct privcmd_kernel_ioreq *alloc_ioreq(struct privcmd_ioeventfd *ioeventfd)
 error_unbind:
        while (--i >= 0)
                unbind_from_irqhandler(irq_from_evtchn(ports[i]), &kioreq->ports[i]);
-error_kfree_ports:
+
        kfree(ports);
 error_kfree:
        kfree(kioreq);
index 8cd583db20b1737144dbfb562f83a505d72c1f3d..b293d7652f15593532b9483422bcc56cbaae8cd9 100644 (file)
@@ -237,7 +237,7 @@ static const struct attribute_group *balloon_groups[] = {
        NULL
 };
 
-static struct bus_type balloon_subsys = {
+static const struct bus_type balloon_subsys = {
        .name = BALLOON_CLASS_NAME,
        .dev_name = BALLOON_CLASS_NAME,
 };
index 32835b4b9bc5030ad3e81ae411d56635f8d6a696..51b3124b0d56c98c316c58fa73d92c07e59b726a 100644 (file)
@@ -116,14 +116,15 @@ EXPORT_SYMBOL_GPL(xenbus_strstate);
  * @dev: xenbus device
  * @path: path to watch
  * @watch: watch to register
+ * @will_handle: events queuing determine callback
  * @callback: callback to register
  *
  * Register a @watch on the given path, using the given xenbus_watch structure
- * for storage, and the given @callback function as the callback.  On success,
- * the given @path will be saved as @watch->node, and remains the
- * caller's to free.  On error, @watch->node will
- * be NULL, the device will switch to %XenbusStateClosing, and the error will
- * be saved in the store.
+ * for storage, @will_handle function as the callback to determine if each
+ * event need to be queued, and the given @callback function as the callback.
+ * On success, the given @path will be saved as @watch->node, and remains the
+ * caller's to free.  On error, @watch->node will be NULL, the device will
+ * switch to %XenbusStateClosing, and the error will be saved in the store.
  *
  * Returns: %0 on success or -errno on error
  */
@@ -158,11 +159,13 @@ EXPORT_SYMBOL_GPL(xenbus_watch_path);
  * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path
  * @dev: xenbus device
  * @watch: watch to register
+ * @will_handle: events queuing determine callback
  * @callback: callback to register
  * @pathfmt: format of path to watch
  *
  * Register a watch on the given @path, using the given xenbus_watch
- * structure for storage, and the given @callback function as the
+ * structure for storage, @will_handle function as the callback to determine if
+ * each event need to be queued, and the given @callback function as the
  * callback.  On success, the watched path (@path/@path2) will be saved
  * as @watch->node, and becomes the caller's to kfree().
  * On error, watch->node will be NULL, so the caller has nothing to
index 025edfccedcf71e443363000644de6e38056d24b..f49d19977e82a71808912acf7119abdfa47dc0f7 100644 (file)
@@ -150,7 +150,7 @@ static int zorro_uevent(const struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
-struct bus_type zorro_bus_type = {
+const struct bus_type zorro_bus_type = {
        .name           = "zorro",
        .dev_name       = "zorro",
        .dev_groups     = zorro_device_attribute_groups,
index f84df9fb4c200ec3d8c87924fd7e2b96ac003d25..df44e35203fd9e90db6d3e89d52efcfd69b5369d 100644 (file)
@@ -4,7 +4,7 @@
      *  Zorro bus
      */
 
-extern struct bus_type zorro_bus_type;
+extern const struct bus_type zorro_bus_type;
 
 
 #ifdef CONFIG_ZORRO_NAMES
index bae330c2f0cf07d207af8c193dad15a78703793a..abdbbaee51846218d807033a30c98394a0c213b6 100644 (file)
@@ -107,7 +107,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
 
        p9_debug(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
 
-       if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
+       if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->c.flc_type != F_UNLCK) {
                filemap_write_and_wait(inode->i_mapping);
                invalidate_mapping_pages(&inode->i_data, 0, -1);
        }
@@ -121,13 +121,12 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
        struct p9_fid *fid;
        uint8_t status = P9_LOCK_ERROR;
        int res = 0;
-       unsigned char fl_type;
        struct v9fs_session_info *v9ses;
 
        fid = filp->private_data;
        BUG_ON(fid == NULL);
 
-       BUG_ON((fl->fl_flags & FL_POSIX) != FL_POSIX);
+       BUG_ON((fl->c.flc_flags & FL_POSIX) != FL_POSIX);
 
        res = locks_lock_file_wait(filp, fl);
        if (res < 0)
@@ -136,7 +135,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
        /* convert posix lock to p9 tlock args */
        memset(&flock, 0, sizeof(flock));
        /* map the lock type */
-       switch (fl->fl_type) {
+       switch (fl->c.flc_type) {
        case F_RDLCK:
                flock.type = P9_LOCK_TYPE_RDLCK;
                break;
@@ -152,7 +151,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
                flock.length = 0;
        else
                flock.length = fl->fl_end - fl->fl_start + 1;
-       flock.proc_id = fl->fl_pid;
+       flock.proc_id = fl->c.flc_pid;
        flock.client_id = fid->clnt->name;
        if (IS_SETLKW(cmd))
                flock.flags = P9_LOCK_FLAGS_BLOCK;
@@ -207,12 +206,13 @@ out_unlock:
         * incase server returned error for lock request, revert
         * it locally
         */
-       if (res < 0 && fl->fl_type != F_UNLCK) {
-               fl_type = fl->fl_type;
-               fl->fl_type = F_UNLCK;
+       if (res < 0 && fl->c.flc_type != F_UNLCK) {
+               unsigned char type = fl->c.flc_type;
+
+               fl->c.flc_type = F_UNLCK;
                /* Even if this fails we want to return the remote error */
                locks_lock_file_wait(filp, fl);
-               fl->fl_type = fl_type;
+               fl->c.flc_type = type;
        }
        if (flock.client_id != fid->clnt->name)
                kfree(flock.client_id);
@@ -234,7 +234,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
         * if we have a conflicting lock locally, no need to validate
         * with server
         */
-       if (fl->fl_type != F_UNLCK)
+       if (fl->c.flc_type != F_UNLCK)
                return res;
 
        /* convert posix lock to p9 tgetlock args */
@@ -245,7 +245,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
                glock.length = 0;
        else
                glock.length = fl->fl_end - fl->fl_start + 1;
-       glock.proc_id = fl->fl_pid;
+       glock.proc_id = fl->c.flc_pid;
        glock.client_id = fid->clnt->name;
 
        res = p9_client_getlock_dotl(fid, &glock);
@@ -254,13 +254,13 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
        /* map 9p lock type to os lock type */
        switch (glock.type) {
        case P9_LOCK_TYPE_RDLCK:
-               fl->fl_type = F_RDLCK;
+               fl->c.flc_type = F_RDLCK;
                break;
        case P9_LOCK_TYPE_WRLCK:
-               fl->fl_type = F_WRLCK;
+               fl->c.flc_type = F_WRLCK;
                break;
        case P9_LOCK_TYPE_UNLCK:
-               fl->fl_type = F_UNLCK;
+               fl->c.flc_type = F_UNLCK;
                break;
        }
        if (glock.type != P9_LOCK_TYPE_UNLCK) {
@@ -269,7 +269,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
                        fl->fl_end = OFFSET_MAX;
                else
                        fl->fl_end = glock.start + glock.length - 1;
-               fl->fl_pid = -glock.proc_id;
+               fl->c.flc_pid = -glock.proc_id;
        }
 out:
        if (glock.client_id != fid->clnt->name)
@@ -293,7 +293,7 @@ static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
        p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %pD\n",
                 filp, cmd, fl, filp);
 
-       if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
+       if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->c.flc_type != F_UNLCK) {
                filemap_write_and_wait(inode->i_mapping);
                invalidate_mapping_pages(&inode->i_data, 0, -1);
        }
@@ -324,16 +324,16 @@ static int v9fs_file_flock_dotl(struct file *filp, int cmd,
        p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %pD\n",
                 filp, cmd, fl, filp);
 
-       if (!(fl->fl_flags & FL_FLOCK))
+       if (!(fl->c.flc_flags & FL_FLOCK))
                goto out_err;
 
-       if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
+       if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->c.flc_type != F_UNLCK) {
                filemap_write_and_wait(inode->i_mapping);
                invalidate_mapping_pages(&inode->i_data, 0, -1);
        }
        /* Convert flock to posix lock */
-       fl->fl_flags |= FL_POSIX;
-       fl->fl_flags ^= FL_FLOCK;
+       fl->c.flc_flags |= FL_POSIX;
+       fl->c.flc_flags ^= FL_FLOCK;
 
        if (IS_SETLK(cmd) | IS_SETLKW(cmd))
                ret = v9fs_file_do_lock(filp, cmd, fl);
index 89fdbefd1075f8f5a071987bca3b4a50f687a887..4bc7dd420874aa979d325d5bc620d4425f0e04db 100644 (file)
@@ -162,7 +162,6 @@ menu "DOS/FAT/EXFAT/NT Filesystems"
 
 source "fs/fat/Kconfig"
 source "fs/exfat/Kconfig"
-source "fs/ntfs/Kconfig"
 source "fs/ntfs3/Kconfig"
 
 endmenu
@@ -174,6 +173,13 @@ source "fs/proc/Kconfig"
 source "fs/kernfs/Kconfig"
 source "fs/sysfs/Kconfig"
 
+config FS_PID
+       bool "Pseudo filesystem for process file descriptors"
+       depends on 64BIT
+       default y
+       help
+         Pidfs implements advanced features for process file descriptors.
+
 config TMPFS
        bool "Tmpfs virtual memory file system support (former shm fs)"
        depends on SHMEM
index c09016257f05e82a772da50ab18e2d708ea5a768..6ecc9b0a53f2b0478385fe131c325d377d794c64 100644 (file)
@@ -15,7 +15,7 @@ obj-y :=      open.o read_write.o file_table.o super.o \
                pnode.o splice.o sync.o utimes.o d_path.o \
                stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \
                fs_types.o fs_context.o fs_parser.o fsopen.o init.o \
-               kernel_read_file.o mnt_idmapping.o remap_range.o
+               kernel_read_file.o mnt_idmapping.o remap_range.o pidfs.o
 
 obj-$(CONFIG_BUFFER_HEAD)      += buffer.o mpage.o
 obj-$(CONFIG_PROC_FS)          += proc_namespace.o
@@ -91,7 +91,6 @@ obj-y                         += unicode/
 obj-$(CONFIG_SYSV_FS)          += sysv/
 obj-$(CONFIG_SMBFS)            += smb/
 obj-$(CONFIG_HPFS_FS)          += hpfs/
-obj-$(CONFIG_NTFS_FS)          += ntfs/
 obj-$(CONFIG_NTFS3_FS)         += ntfs3/
 obj-$(CONFIG_UFS_FS)           += ufs/
 obj-$(CONFIG_EFS_FS)           += efs/
index 60685ec76d983523f15da7c7e97b38634b750c07..2e612834329ac127ae6e63d802a7b31b89558b0c 100644 (file)
@@ -105,6 +105,7 @@ struct affs_sb_info {
        int work_queued;                /* non-zero delayed work is queued */
        struct delayed_work sb_work;    /* superblock flush delayed work */
        spinlock_t work_lock;           /* protects sb_work and work_queued */
+       struct rcu_head rcu;
 };
 
 #define AFFS_MOUNT_SF_INTL             0x0001 /* International filesystem. */
index 58b391446ae1fd97e48891c82ec8d88f32314303..b56a95cf414a44277783e7242c33cba5cb818707 100644 (file)
@@ -640,7 +640,7 @@ static void affs_kill_sb(struct super_block *sb)
                affs_brelse(sbi->s_root_bh);
                kfree(sbi->s_prefix);
                mutex_destroy(&sbi->s_bmlock);
-               kfree(sbi);
+               kfree_rcu(sbi, rcu);
        }
 }
 
index b5b8de521f99b26ba6c9b2fd707fb794a62612ae..8a67fc427e748a0840d9e92c1c0e8e4a3d7c4fdc 100644 (file)
@@ -479,8 +479,10 @@ static int afs_dir_iterate_block(struct afs_vnode *dvnode,
                    dire->u.name[0] == '.' &&
                    ctx->actor != afs_lookup_filldir &&
                    ctx->actor != afs_lookup_one_filldir &&
-                   memcmp(dire->u.name, ".__afs", 6) == 0)
+                   memcmp(dire->u.name, ".__afs", 6) == 0) {
+                       ctx->pos = blkoff + next * sizeof(union afs_xdr_dirent);
                        continue;
+               }
 
                /* found the next entry */
                if (!dir_emit(ctx, dire->u.name, nlen,
index 3d33b221d9ca256a3b3d978a835d2db9fff2e284..ef2cc8f565d25b15e086d2fc64c6f565bac7a16b 100644 (file)
@@ -417,13 +417,17 @@ static void afs_add_open_mmap(struct afs_vnode *vnode)
 
 static void afs_drop_open_mmap(struct afs_vnode *vnode)
 {
-       if (!atomic_dec_and_test(&vnode->cb_nr_mmap))
+       if (atomic_add_unless(&vnode->cb_nr_mmap, -1, 1))
                return;
 
        down_write(&vnode->volume->open_mmaps_lock);
 
-       if (atomic_read(&vnode->cb_nr_mmap) == 0)
+       read_seqlock_excl(&vnode->cb_lock);
+       // the only place where ->cb_nr_mmap may hit 0
+       // see __afs_break_callback() for the other side...
+       if (atomic_dec_and_test(&vnode->cb_nr_mmap))
                list_del_init(&vnode->cb_mmap_link);
+       read_sequnlock_excl(&vnode->cb_lock);
 
        up_write(&vnode->volume->open_mmaps_lock);
        flush_work(&vnode->cb_work);
index 9c6dea3139f5a88497fc387190ca9050b182431a..f0e96a35093fa44871985d2edabd3e910a7b7a7d 100644 (file)
@@ -93,13 +93,13 @@ static void afs_grant_locks(struct afs_vnode *vnode)
        bool exclusive = (vnode->lock_type == AFS_LOCK_WRITE);
 
        list_for_each_entry_safe(p, _p, &vnode->pending_locks, fl_u.afs.link) {
-               if (!exclusive && p->fl_type == F_WRLCK)
+               if (!exclusive && lock_is_write(p))
                        continue;
 
                list_move_tail(&p->fl_u.afs.link, &vnode->granted_locks);
                p->fl_u.afs.state = AFS_LOCK_GRANTED;
                trace_afs_flock_op(vnode, p, afs_flock_op_grant);
-               wake_up(&p->fl_wait);
+               locks_wake_up(p);
        }
 }
 
@@ -112,25 +112,24 @@ static void afs_next_locker(struct afs_vnode *vnode, int error)
 {
        struct file_lock *p, *_p, *next = NULL;
        struct key *key = vnode->lock_key;
-       unsigned int fl_type = F_RDLCK;
+       unsigned int type = F_RDLCK;
 
        _enter("");
 
        if (vnode->lock_type == AFS_LOCK_WRITE)
-               fl_type = F_WRLCK;
+               type = F_WRLCK;
 
        list_for_each_entry_safe(p, _p, &vnode->pending_locks, fl_u.afs.link) {
                if (error &&
-                   p->fl_type == fl_type &&
-                   afs_file_key(p->fl_file) == key) {
+                   p->c.flc_type == type &&
+                   afs_file_key(p->c.flc_file) == key) {
                        list_del_init(&p->fl_u.afs.link);
                        p->fl_u.afs.state = error;
-                       wake_up(&p->fl_wait);
+                       locks_wake_up(p);
                }
 
                /* Select the next locker to hand off to. */
-               if (next &&
-                   (next->fl_type == F_WRLCK || p->fl_type == F_RDLCK))
+               if (next && (lock_is_write(next) || lock_is_read(p)))
                        continue;
                next = p;
        }
@@ -142,7 +141,7 @@ static void afs_next_locker(struct afs_vnode *vnode, int error)
                afs_set_lock_state(vnode, AFS_VNODE_LOCK_SETTING);
                next->fl_u.afs.state = AFS_LOCK_YOUR_TRY;
                trace_afs_flock_op(vnode, next, afs_flock_op_wake);
-               wake_up(&next->fl_wait);
+               locks_wake_up(next);
        } else {
                afs_set_lock_state(vnode, AFS_VNODE_LOCK_NONE);
                trace_afs_flock_ev(vnode, NULL, afs_flock_no_lockers, 0);
@@ -166,7 +165,7 @@ static void afs_kill_lockers_enoent(struct afs_vnode *vnode)
                               struct file_lock, fl_u.afs.link);
                list_del_init(&p->fl_u.afs.link);
                p->fl_u.afs.state = -ENOENT;
-               wake_up(&p->fl_wait);
+               locks_wake_up(p);
        }
 
        key_put(vnode->lock_key);
@@ -464,14 +463,14 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
 
        _enter("{%llx:%llu},%llu-%llu,%u,%u",
               vnode->fid.vid, vnode->fid.vnode,
-              fl->fl_start, fl->fl_end, fl->fl_type, mode);
+              fl->fl_start, fl->fl_end, fl->c.flc_type, mode);
 
        fl->fl_ops = &afs_lock_ops;
        INIT_LIST_HEAD(&fl->fl_u.afs.link);
        fl->fl_u.afs.state = AFS_LOCK_PENDING;
 
        partial = (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX);
-       type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
+       type = lock_is_read(fl) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
        if (mode == afs_flock_mode_write && partial)
                type = AFS_LOCK_WRITE;
 
@@ -524,7 +523,7 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
        }
 
        if (vnode->lock_state == AFS_VNODE_LOCK_NONE &&
-           !(fl->fl_flags & FL_SLEEP)) {
+           !(fl->c.flc_flags & FL_SLEEP)) {
                ret = -EAGAIN;
                if (type == AFS_LOCK_READ) {
                        if (vnode->status.lock_count == -1)
@@ -621,7 +620,7 @@ skip_server_lock:
        return 0;
 
 lock_is_contended:
-       if (!(fl->fl_flags & FL_SLEEP)) {
+       if (!(fl->c.flc_flags & FL_SLEEP)) {
                list_del_init(&fl->fl_u.afs.link);
                afs_next_locker(vnode, 0);
                ret = -EAGAIN;
@@ -641,7 +640,7 @@ need_to_wait:
        spin_unlock(&vnode->lock);
 
        trace_afs_flock_ev(vnode, fl, afs_flock_waiting, 0);
-       ret = wait_event_interruptible(fl->fl_wait,
+       ret = wait_event_interruptible(fl->c.flc_wait,
                                       fl->fl_u.afs.state != AFS_LOCK_PENDING);
        trace_afs_flock_ev(vnode, fl, afs_flock_waited, ret);
 
@@ -704,7 +703,8 @@ static int afs_do_unlk(struct file *file, struct file_lock *fl)
        struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
        int ret;
 
-       _enter("{%llx:%llu},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type);
+       _enter("{%llx:%llu},%u", vnode->fid.vid, vnode->fid.vnode,
+              fl->c.flc_type);
 
        trace_afs_flock_op(vnode, fl, afs_flock_op_unlock);
 
@@ -730,11 +730,11 @@ static int afs_do_getlk(struct file *file, struct file_lock *fl)
        if (vnode->lock_state == AFS_VNODE_LOCK_DELETED)
                return -ENOENT;
 
-       fl->fl_type = F_UNLCK;
+       fl->c.flc_type = F_UNLCK;
 
        /* check local lock records first */
        posix_test_lock(file, fl);
-       if (fl->fl_type == F_UNLCK) {
+       if (lock_is_unlock(fl)) {
                /* no local locks; consult the server */
                ret = afs_fetch_status(vnode, key, false, NULL);
                if (ret < 0)
@@ -743,18 +743,18 @@ static int afs_do_getlk(struct file *file, struct file_lock *fl)
                lock_count = READ_ONCE(vnode->status.lock_count);
                if (lock_count != 0) {
                        if (lock_count > 0)
-                               fl->fl_type = F_RDLCK;
+                               fl->c.flc_type = F_RDLCK;
                        else
-                               fl->fl_type = F_WRLCK;
+                               fl->c.flc_type = F_WRLCK;
                        fl->fl_start = 0;
                        fl->fl_end = OFFSET_MAX;
-                       fl->fl_pid = 0;
+                       fl->c.flc_pid = 0;
                }
        }
 
        ret = 0;
 error:
-       _leave(" = %d [%hd]", ret, fl->fl_type);
+       _leave(" = %d [%hd]", ret, fl->c.flc_type);
        return ret;
 }
 
@@ -769,7 +769,7 @@ int afs_lock(struct file *file, int cmd, struct file_lock *fl)
 
        _enter("{%llx:%llu},%d,{t=%x,fl=%x,r=%Ld:%Ld}",
               vnode->fid.vid, vnode->fid.vnode, cmd,
-              fl->fl_type, fl->fl_flags,
+              fl->c.flc_type, fl->c.flc_flags,
               (long long) fl->fl_start, (long long) fl->fl_end);
 
        if (IS_GETLK(cmd))
@@ -778,7 +778,7 @@ int afs_lock(struct file *file, int cmd, struct file_lock *fl)
        fl->fl_u.afs.debug_id = atomic_inc_return(&afs_file_lock_debug_id);
        trace_afs_flock_op(vnode, fl, afs_flock_op_lock);
 
-       if (fl->fl_type == F_UNLCK)
+       if (lock_is_unlock(fl))
                ret = afs_do_unlk(file, fl);
        else
                ret = afs_do_setlk(file, fl);
@@ -804,7 +804,7 @@ int afs_flock(struct file *file, int cmd, struct file_lock *fl)
 
        _enter("{%llx:%llu},%d,{t=%x,fl=%x}",
               vnode->fid.vid, vnode->fid.vnode, cmd,
-              fl->fl_type, fl->fl_flags);
+              fl->c.flc_type, fl->c.flc_flags);
 
        /*
         * No BSD flocks over NFS allowed.
@@ -813,14 +813,14 @@ int afs_flock(struct file *file, int cmd, struct file_lock *fl)
         * Not sure whether that would be unique, though, or whether
         * that would break in other places.
         */
-       if (!(fl->fl_flags & FL_FLOCK))
+       if (!(fl->c.flc_flags & FL_FLOCK))
                return -ENOLCK;
 
        fl->fl_u.afs.debug_id = atomic_inc_return(&afs_file_lock_debug_id);
        trace_afs_flock_op(vnode, fl, afs_flock_op_flock);
 
        /* we're simulating flock() locks using posix locks on the server */
-       if (fl->fl_type == F_UNLCK)
+       if (lock_is_unlock(fl))
                ret = afs_do_unlk(file, fl);
        else
                ret = afs_do_setlk(file, fl);
@@ -843,7 +843,7 @@ int afs_flock(struct file *file, int cmd, struct file_lock *fl)
  */
 static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl)
 {
-       struct afs_vnode *vnode = AFS_FS_I(file_inode(fl->fl_file));
+       struct afs_vnode *vnode = AFS_FS_I(file_inode(fl->c.flc_file));
 
        _enter("");
 
@@ -861,7 +861,7 @@ static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl)
  */
 static void afs_fl_release_private(struct file_lock *fl)
 {
-       struct afs_vnode *vnode = AFS_FS_I(file_inode(fl->fl_file));
+       struct afs_vnode *vnode = AFS_FS_I(file_inode(fl->c.flc_file));
 
        _enter("");
 
index 9c03fcf7ffaa84e9f7604444209bd934b64db466..6ce5a612937c61e2021b32cad1f68a22b7c501ca 100644 (file)
@@ -321,8 +321,7 @@ struct afs_net {
        struct list_head        fs_probe_slow;  /* List of afs_server to probe at 5m intervals */
        struct hlist_head       fs_proc;        /* procfs servers list */
 
-       struct hlist_head       fs_addresses4;  /* afs_server (by lowest IPv4 addr) */
-       struct hlist_head       fs_addresses6;  /* afs_server (by lowest IPv6 addr) */
+       struct hlist_head       fs_addresses;   /* afs_server (by lowest IPv6 addr) */
        seqlock_t               fs_addr_lock;   /* For fs_addresses[46] */
 
        struct work_struct      fs_manager;
@@ -561,8 +560,7 @@ struct afs_server {
        struct afs_server __rcu *uuid_next;     /* Next server with same UUID */
        struct afs_server       *uuid_prev;     /* Previous server with same UUID */
        struct list_head        probe_link;     /* Link in net->fs_probe_list */
-       struct hlist_node       addr4_link;     /* Link in net->fs_addresses4 */
-       struct hlist_node       addr6_link;     /* Link in net->fs_addresses6 */
+       struct hlist_node       addr_link;      /* Link in net->fs_addresses6 */
        struct hlist_node       proc_link;      /* Link in net->fs_proc */
        struct list_head        volumes;        /* RCU list of afs_server_entry objects */
        struct afs_server       *gc_next;       /* Next server in manager's list */
index 1b3bd21c168acc223bfaf39fa454d2cb49ae3fbb..a14f6013e316d964bfa6eef3e09befe62d591411 100644 (file)
@@ -90,8 +90,7 @@ static int __net_init afs_net_init(struct net *net_ns)
        INIT_LIST_HEAD(&net->fs_probe_slow);
        INIT_HLIST_HEAD(&net->fs_proc);
 
-       INIT_HLIST_HEAD(&net->fs_addresses4);
-       INIT_HLIST_HEAD(&net->fs_addresses6);
+       INIT_HLIST_HEAD(&net->fs_addresses);
        seqlock_init(&net->fs_addr_lock);
 
        INIT_WORK(&net->fs_manager, afs_manage_servers);
index e169121f603e28d5679a895d0ca0f136270a6f56..038f9d0ae3af8ee1df24dc163c972e826c5d62fb 100644 (file)
@@ -38,7 +38,7 @@ struct afs_server *afs_find_server(struct afs_net *net, const struct rxrpc_peer
                seq++; /* 2 on the 1st/lockless path, otherwise odd */
                read_seqbegin_or_lock(&net->fs_addr_lock, &seq);
 
-               hlist_for_each_entry_rcu(server, &net->fs_addresses6, addr6_link) {
+               hlist_for_each_entry_rcu(server, &net->fs_addresses, addr_link) {
                        estate = rcu_dereference(server->endpoint_state);
                        alist = estate->addresses;
                        for (i = 0; i < alist->nr_addrs; i++)
@@ -177,10 +177,8 @@ added_dup:
         * bit, but anything we might want to do gets messy and memory
         * intensive.
         */
-       if (alist->nr_ipv4 > 0)
-               hlist_add_head_rcu(&server->addr4_link, &net->fs_addresses4);
-       if (alist->nr_addrs > alist->nr_ipv4)
-               hlist_add_head_rcu(&server->addr6_link, &net->fs_addresses6);
+       if (alist->nr_addrs > 0)
+               hlist_add_head_rcu(&server->addr_link, &net->fs_addresses);
 
        write_sequnlock(&net->fs_addr_lock);
 
@@ -511,10 +509,8 @@ static void afs_gc_servers(struct afs_net *net, struct afs_server *gc_list)
 
                        list_del(&server->probe_link);
                        hlist_del_rcu(&server->proc_link);
-                       if (!hlist_unhashed(&server->addr4_link))
-                               hlist_del_rcu(&server->addr4_link);
-                       if (!hlist_unhashed(&server->addr6_link))
-                               hlist_del_rcu(&server->addr6_link);
+                       if (!hlist_unhashed(&server->addr_link))
+                               hlist_del_rcu(&server->addr_link);
                }
                write_sequnlock(&net->fs_lock);
 
index 020ecd45e476214f08b9867412ec4b379889344d..af3a3f57c1b3f9512bcaa08ce37a0f8173e809d0 100644 (file)
@@ -353,7 +353,7 @@ static int afs_update_volume_status(struct afs_volume *volume, struct key *key)
 {
        struct afs_server_list *new, *old, *discard;
        struct afs_vldb_entry *vldb;
-       char idbuf[16];
+       char idbuf[24];
        int ret, idsz;
 
        _enter("");
@@ -361,7 +361,7 @@ static int afs_update_volume_status(struct afs_volume *volume, struct key *key)
        /* We look up an ID by passing it as a decimal string in the
         * operation's name parameter.
         */
-       idsz = sprintf(idbuf, "%llu", volume->vid);
+       idsz = snprintf(idbuf, sizeof(idbuf), "%llu", volume->vid);
 
        vldb = afs_vl_lookup_vldb(volume->cell, key, idbuf, idsz);
        if (IS_ERR(vldb)) {
index bb2ff48991f35ed59479a004641e1452c7bad3ea..9cdaa2faa5363333627e0cba54a4efe75b45b144 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -589,13 +589,24 @@ static int aio_setup_ring(struct kioctx *ctx, unsigned int nr_events)
 
 void kiocb_set_cancel_fn(struct kiocb *iocb, kiocb_cancel_fn *cancel)
 {
-       struct aio_kiocb *req = container_of(iocb, struct aio_kiocb, rw);
-       struct kioctx *ctx = req->ki_ctx;
+       struct aio_kiocb *req;
+       struct kioctx *ctx;
        unsigned long flags;
 
+       /*
+        * kiocb didn't come from aio or is neither a read nor a write, hence
+        * ignore it.
+        */
+       if (!(iocb->ki_flags & IOCB_AIO_RW))
+               return;
+
+       req = container_of(iocb, struct aio_kiocb, rw);
+
        if (WARN_ON_ONCE(!list_empty(&req->ki_list)))
                return;
 
+       ctx = req->ki_ctx;
+
        spin_lock_irqsave(&ctx->ctx_lock, flags);
        list_add_tail(&req->ki_list, &ctx->active_reqs);
        req->ki_cancel = cancel;
@@ -1509,7 +1520,7 @@ static int aio_prep_rw(struct kiocb *req, const struct iocb *iocb)
        req->ki_complete = aio_complete_rw;
        req->private = NULL;
        req->ki_pos = iocb->aio_offset;
-       req->ki_flags = req->ki_filp->f_iocb_flags;
+       req->ki_flags = req->ki_filp->f_iocb_flags | IOCB_AIO_RW;
        if (iocb->aio_flags & IOCB_FLAG_RESFD)
                req->ki_flags |= IOCB_EVENTFD;
        if (iocb->aio_flags & IOCB_FLAG_IOPRIO) {
index 5a13f0c8495fde67df096d4501d32c47e86f056e..49d23b5dbab4b971bb8756c3fca360c5618cc2c3 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -352,7 +352,7 @@ int may_setattr(struct mnt_idmap *idmap, struct inode *inode,
 EXPORT_SYMBOL(may_setattr);
 
 /**
- * notify_change - modify attributes of a filesytem object
+ * notify_change - modify attributes of a filesystem object
  * @idmap:     idmap of the mount the inode was found from
  * @dentry:    object affected
  * @attr:      new attributes
index a681f38d84d8e170bcca715c6045811c7c7f163b..740185198db3473163bb141719e6e03514314c72 100644 (file)
@@ -325,9 +325,7 @@ EXPORT_SYMBOL_GPL(backing_file_mmap);
 
 static int __init backing_aio_init(void)
 {
-       backing_aio_cachep = kmem_cache_create("backing_aio",
-                                              sizeof(struct backing_aio),
-                                              0, SLAB_HWCACHE_ALIGN, NULL);
+       backing_aio_cachep = KMEM_CACHE(backing_aio, SLAB_HWCACHE_ALIGN);
        if (!backing_aio_cachep)
                return -ENOMEM;
 
index b4dc319bcb2bc0a5363e74f6d2096d3b5652599d..569b97904da42eec8975e8662dd78895d41d62fe 100644 (file)
@@ -68,9 +68,11 @@ void bch2_backpointer_to_text(struct printbuf *out, const struct bch_backpointer
 
 void bch2_backpointer_k_to_text(struct printbuf *out, struct bch_fs *c, struct bkey_s_c k)
 {
-       prt_str(out, "bucket=");
-       bch2_bpos_to_text(out, bp_pos_to_bucket(c, k.k->p));
-       prt_str(out, " ");
+       if (bch2_dev_exists2(c, k.k->p.inode)) {
+               prt_str(out, "bucket=");
+               bch2_bpos_to_text(out, bp_pos_to_bucket(c, k.k->p));
+               prt_str(out, " ");
+       }
 
        bch2_backpointer_to_text(out, bkey_s_c_to_backpointer(k).v);
 }
index b80c6c9efd8cef95b46b5b45b21f639e18373755..69d0d60d50e366edf9e56ba101dda047536f5338 100644 (file)
@@ -1249,6 +1249,18 @@ static inline struct stdio_redirect *bch2_fs_stdio_redirect(struct bch_fs *c)
        return stdio;
 }
 
+static inline unsigned metadata_replicas_required(struct bch_fs *c)
+{
+       return min(c->opts.metadata_replicas,
+                  c->opts.metadata_replicas_required);
+}
+
+static inline unsigned data_replicas_required(struct bch_fs *c)
+{
+       return min(c->opts.data_replicas,
+                  c->opts.data_replicas_required);
+}
+
 #define BKEY_PADDED_ONSTACK(key, pad)                          \
        struct { struct bkey_i key; __u64 key ## _pad[pad]; }
 
index 5467a8635be113102c56bb6f02986209533c35ac..3ef338df82f5e46228f583a85a7cacdba233a64b 100644 (file)
@@ -2156,7 +2156,9 @@ struct bkey_s_c bch2_btree_iter_peek_upto(struct btree_iter *iter, struct bpos e
                 * isn't monotonically increasing before FILTER_SNAPSHOTS, and
                 * that's what we check against in extents mode:
                 */
-               if (k.k->p.inode > end.inode)
+               if (unlikely(!(iter->flags & BTREE_ITER_IS_EXTENTS)
+                            ? bkey_gt(k.k->p, end)
+                            : k.k->p.inode > end.inode))
                        goto end;
 
                if (iter->update_path &&
index 17a5938aa71a6b43b45c12383e4690df146ee2a3..4530b14ff2c3717ec15e92615385c04e185e28e1 100644 (file)
@@ -280,7 +280,8 @@ retry:
                                      writepoint_ptr(&c->btree_write_point),
                                      &devs_have,
                                      res->nr_replicas,
-                                     c->opts.metadata_replicas_required,
+                                     min(res->nr_replicas,
+                                         c->opts.metadata_replicas_required),
                                      watermark, 0, cl, &wp);
        if (unlikely(ret))
                return ERR_PTR(ret);
index 73c12e565af50a465260856baaa831eb2a542caa..27710cdd5710ec5bba9ff9a11cad92f7cf14bc09 100644 (file)
@@ -303,18 +303,6 @@ void bch2_readahead(struct readahead_control *ractl)
        darray_exit(&readpages_iter.folios);
 }
 
-static void __bchfs_readfolio(struct bch_fs *c, struct bch_read_bio *rbio,
-                            subvol_inum inum, struct folio *folio)
-{
-       bch2_folio_create(folio, __GFP_NOFAIL);
-
-       rbio->bio.bi_opf = REQ_OP_READ|REQ_SYNC;
-       rbio->bio.bi_iter.bi_sector = folio_sector(folio);
-       BUG_ON(!bio_add_folio(&rbio->bio, folio, folio_size(folio), 0));
-
-       bch2_trans_run(c, (bchfs_read(trans, rbio, inum, NULL), 0));
-}
-
 static void bch2_read_single_folio_end_io(struct bio *bio)
 {
        complete(bio->bi_private);
@@ -329,6 +317,9 @@ int bch2_read_single_folio(struct folio *folio, struct address_space *mapping)
        int ret;
        DECLARE_COMPLETION_ONSTACK(done);
 
+       if (!bch2_folio_create(folio, GFP_KERNEL))
+               return -ENOMEM;
+
        bch2_inode_opts_get(&opts, c, &inode->ei_inode);
 
        rbio = rbio_init(bio_alloc_bioset(NULL, 1, REQ_OP_READ, GFP_KERNEL, &c->bio_read),
@@ -336,7 +327,11 @@ int bch2_read_single_folio(struct folio *folio, struct address_space *mapping)
        rbio->bio.bi_private = &done;
        rbio->bio.bi_end_io = bch2_read_single_folio_end_io;
 
-       __bchfs_readfolio(c, rbio, inode_inum(inode), folio);
+       rbio->bio.bi_opf = REQ_OP_READ|REQ_SYNC;
+       rbio->bio.bi_iter.bi_sector = folio_sector(folio);
+       BUG_ON(!bio_add_folio(&rbio->bio, folio, folio_size(folio), 0));
+
+       bch2_trans_run(c, (bchfs_read(trans, rbio, inode_inum(inode), NULL), 0));
        wait_for_completion(&done);
 
        ret = blk_status_to_errno(rbio->bio.bi_status);
index e3b219e19e1008ccfe1ff61e966115795f9c1831..33cb6da3a5ad28f2c014c2ef12408937933d49c3 100644 (file)
@@ -88,6 +88,8 @@ static int bch2_direct_IO_read(struct kiocb *req, struct iov_iter *iter)
                return ret;
 
        shorten = iov_iter_count(iter) - round_up(ret, block_bytes(c));
+       if (shorten >= iter->count)
+               shorten = 0;
        iter->count -= shorten;
 
        bio = bio_alloc_bioset(NULL,
index ec419b8e2c43123b42e0d84c837611fc5f6e2314..77ae65542db9166a4168a78a55064295bb1d9ebf 100644 (file)
@@ -435,7 +435,7 @@ static int bch2_link(struct dentry *old_dentry, struct inode *vdir,
                bch2_subvol_is_ro(c, inode->ei_subvol) ?:
                __bch2_link(c, inode, dir, dentry);
        if (unlikely(ret))
-               return ret;
+               return bch2_err_class(ret);
 
        ihold(&inode->v);
        d_instantiate(dentry, &inode->v);
@@ -487,8 +487,9 @@ static int bch2_unlink(struct inode *vdir, struct dentry *dentry)
        struct bch_inode_info *dir= to_bch_ei(vdir);
        struct bch_fs *c = dir->v.i_sb->s_fs_info;
 
-       return bch2_subvol_is_ro(c, dir->ei_subvol) ?:
+       int ret = bch2_subvol_is_ro(c, dir->ei_subvol) ?:
                __bch2_unlink(vdir, dentry, false);
+       return bch2_err_class(ret);
 }
 
 static int bch2_symlink(struct mnt_idmap *idmap,
@@ -523,7 +524,7 @@ static int bch2_symlink(struct mnt_idmap *idmap,
        return 0;
 err:
        iput(&inode->v);
-       return ret;
+       return bch2_err_class(ret);
 }
 
 static int bch2_mkdir(struct mnt_idmap *idmap,
@@ -641,7 +642,7 @@ err:
                           src_inode,
                           dst_inode);
 
-       return ret;
+       return bch2_err_class(ret);
 }
 
 static void bch2_setattr_copy(struct mnt_idmap *idmap,
index ef3a53f9045af2591ab1f9e272dd9d6151250444..2c098ac017b30b6a4b5d016e9f5dde93ee258f2f 100644 (file)
@@ -1564,6 +1564,7 @@ CLOSURE_CALLBACK(bch2_write)
        BUG_ON(!op->write_point.v);
        BUG_ON(bkey_eq(op->pos, POS_MAX));
 
+       op->nr_replicas_required = min_t(unsigned, op->nr_replicas_required, op->nr_replicas);
        op->start_time = local_clock();
        bch2_keylist_init(&op->insert_keys, op->inline_keys);
        wbio_init(bio)->put_bio = false;
index bfd6585e746da45880da9b5ad8fb502586cbf933..47805193f18cc72c941f72f5b82cfb461eb8982c 100644 (file)
@@ -1478,6 +1478,8 @@ static int journal_write_alloc(struct journal *j, struct journal_buf *w)
                c->opts.foreground_target;
        unsigned i, replicas = 0, replicas_want =
                READ_ONCE(c->opts.metadata_replicas);
+       unsigned replicas_need = min_t(unsigned, replicas_want,
+                                      READ_ONCE(c->opts.metadata_replicas_required));
 
        rcu_read_lock();
 retry:
@@ -1526,7 +1528,7 @@ done:
 
        BUG_ON(bkey_val_u64s(&w->key.k) > BCH_REPLICAS_MAX);
 
-       return replicas >= c->opts.metadata_replicas_required ? 0 : -EROFS;
+       return replicas >= replicas_need ? 0 : -EROFS;
 }
 
 static void journal_buf_realloc(struct journal *j, struct journal_buf *buf)
index 820d25e19e5fe3ee6a45e70f23eb74fc1d558e88..c33dca641575dffc58b6db8354e71c879ed5cf26 100644 (file)
@@ -205,7 +205,7 @@ void bch2_journal_space_available(struct journal *j)
 
        j->can_discard = can_discard;
 
-       if (nr_online < c->opts.metadata_replicas_required) {
+       if (nr_online < metadata_replicas_required(c)) {
                ret = JOURNAL_ERR_insufficient_devices;
                goto out;
        }
@@ -892,9 +892,11 @@ int bch2_journal_flush_device_pins(struct journal *j, int dev_idx)
                                         journal_seq_pin(j, seq)->devs);
                seq++;
 
-               spin_unlock(&j->lock);
-               ret = bch2_mark_replicas(c, &replicas.e);
-               spin_lock(&j->lock);
+               if (replicas.e.nr_devs) {
+                       spin_unlock(&j->lock);
+                       ret = bch2_mark_replicas(c, &replicas.e);
+                       spin_lock(&j->lock);
+               }
        }
        spin_unlock(&j->lock);
 err:
index accf246c32330919869bccff32a1ecfcc6d97856..b27d22925929a6554079fb8731f82dfb3dd0421c 100644 (file)
@@ -56,6 +56,7 @@ void bch2_prt_vprintf(struct printbuf *out, const char *fmt, va_list args)
 
                va_copy(args2, args);
                len = vsnprintf(out->buf + out->pos, printbuf_remaining(out), fmt, args2);
+               va_end(args2);
        } while (len + 1 >= printbuf_remaining(out) &&
                 !bch2_printbuf_make_room(out, len + 1));
 
index 9127d0e3ca2f6a3fd44e076b42f01ee6f7736427..21e13bb4335be3b6d48005282000c2f0a7c4e2bd 100644 (file)
@@ -577,8 +577,9 @@ u64 bch2_recovery_passes_from_stable(u64 v)
 
 static bool check_version_upgrade(struct bch_fs *c)
 {
-       unsigned latest_compatible = bch2_latest_compatible_version(c->sb.version);
        unsigned latest_version = bcachefs_metadata_version_current;
+       unsigned latest_compatible = min(latest_version,
+                                        bch2_latest_compatible_version(c->sb.version));
        unsigned old_version = c->sb.version_upgrade_complete ?: c->sb.version;
        unsigned new_version = 0;
 
@@ -597,7 +598,7 @@ static bool check_version_upgrade(struct bch_fs *c)
                        new_version = latest_version;
                        break;
                case BCH_VERSION_UPGRADE_none:
-                       new_version = old_version;
+                       new_version = min(old_version, latest_version);
                        break;
                }
        }
@@ -774,7 +775,7 @@ int bch2_fs_recovery(struct bch_fs *c)
                goto err;
        }
 
-       if (!(c->opts.nochanges && c->opts.norecovery)) {
+       if (!c->opts.nochanges) {
                mutex_lock(&c->sb_lock);
                bool write_sb = false;
 
@@ -804,7 +805,7 @@ int bch2_fs_recovery(struct bch_fs *c)
                if (bch2_check_version_downgrade(c)) {
                        struct printbuf buf = PRINTBUF;
 
-                       prt_str(&buf, "Version downgrade required:\n");
+                       prt_str(&buf, "Version downgrade required:");
 
                        __le64 passes = ext->recovery_passes_required[0];
                        bch2_sb_set_downgrade(c,
@@ -812,7 +813,7 @@ int bch2_fs_recovery(struct bch_fs *c)
                                        BCH_VERSION_MINOR(c->sb.version));
                        passes = ext->recovery_passes_required[0] & ~passes;
                        if (passes) {
-                               prt_str(&buf, "  running recovery passes: ");
+                               prt_str(&buf, "\n  running recovery passes: ");
                                prt_bitflags(&buf, bch2_recovery_passes,
                                             bch2_recovery_passes_from_stable(le64_to_cpu(passes)));
                        }
index a45354d2acde9f3ad0b149247c8ff4c7c869fb15..eff5ce18c69c0600047c1fef688a5980af33c678 100644 (file)
@@ -421,7 +421,7 @@ void bch2_dev_errors_reset(struct bch_dev *ca)
        m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
        for (unsigned i = 0; i < ARRAY_SIZE(m->errors_at_reset); i++)
                m->errors_at_reset[i] = cpu_to_le64(atomic64_read(&ca->errors[i]));
-       m->errors_reset_time = ktime_get_real_seconds();
+       m->errors_reset_time = cpu_to_le64(ktime_get_real_seconds());
 
        bch2_write_super(c);
        mutex_unlock(&c->sb_lock);
index 45f67e8b29eb67f188e5cfb32aa39e0b1ad1d625..ac6ba04d5521714ece2e2cb00400fff60ec05eb6 100644 (file)
@@ -728,7 +728,7 @@ static int check_snapshot(struct btree_trans *trans,
                return 0;
 
        memset(&s, 0, sizeof(s));
-       memcpy(&s, k.v, bkey_val_bytes(k.k));
+       memcpy(&s, k.v, min(sizeof(s), bkey_val_bytes(k.k)));
 
        id = le32_to_cpu(s.parent);
        if (id) {
index d60c7d27a0477cb0de116675671d5c888d8f1c86..bd64eb68e84af4c6b7afed028a6bd7d9ae2cc5d6 100644 (file)
@@ -142,8 +142,8 @@ void bch2_sb_field_delete(struct bch_sb_handle *sb,
 void bch2_free_super(struct bch_sb_handle *sb)
 {
        kfree(sb->bio);
-       if (!IS_ERR_OR_NULL(sb->bdev_handle))
-               bdev_release(sb->bdev_handle);
+       if (!IS_ERR_OR_NULL(sb->s_bdev_file))
+               fput(sb->s_bdev_file);
        kfree(sb->holder);
        kfree(sb->sb_name);
 
@@ -704,22 +704,22 @@ retry:
        if (!opt_get(*opts, nochanges))
                sb->mode |= BLK_OPEN_WRITE;
 
-       sb->bdev_handle = bdev_open_by_path(path, sb->mode, sb->holder, &bch2_sb_handle_bdev_ops);
-       if (IS_ERR(sb->bdev_handle) &&
-           PTR_ERR(sb->bdev_handle) == -EACCES &&
+       sb->s_bdev_file = bdev_file_open_by_path(path, sb->mode, sb->holder, &bch2_sb_handle_bdev_ops);
+       if (IS_ERR(sb->s_bdev_file) &&
+           PTR_ERR(sb->s_bdev_file) == -EACCES &&
            opt_get(*opts, read_only)) {
                sb->mode &= ~BLK_OPEN_WRITE;
 
-               sb->bdev_handle = bdev_open_by_path(path, sb->mode, sb->holder, &bch2_sb_handle_bdev_ops);
-               if (!IS_ERR(sb->bdev_handle))
+               sb->s_bdev_file = bdev_file_open_by_path(path, sb->mode, sb->holder, &bch2_sb_handle_bdev_ops);
+               if (!IS_ERR(sb->s_bdev_file))
                        opt_set(*opts, nochanges, true);
        }
 
-       if (IS_ERR(sb->bdev_handle)) {
-               ret = PTR_ERR(sb->bdev_handle);
-               goto out;
+       if (IS_ERR(sb->s_bdev_file)) {
+               ret = PTR_ERR(sb->s_bdev_file);
+               goto err;
        }
-       sb->bdev = sb->bdev_handle->bdev;
+       sb->bdev = file_bdev(sb->s_bdev_file);
 
        ret = bch2_sb_realloc(sb, 0);
        if (ret) {
index b9911402b1753baa986a1673339c4454eba87431..6b23e11825e6d47ef46c7f294add46fa455e6a8f 100644 (file)
@@ -1428,10 +1428,10 @@ bool bch2_dev_state_allowed(struct bch_fs *c, struct bch_dev *ca,
 
                required = max(!(flags & BCH_FORCE_IF_METADATA_DEGRADED)
                               ? c->opts.metadata_replicas
-                              : c->opts.metadata_replicas_required,
+                              : metadata_replicas_required(c),
                               !(flags & BCH_FORCE_IF_DATA_DEGRADED)
                               ? c->opts.data_replicas
-                              : c->opts.data_replicas_required);
+                              : data_replicas_required(c));
 
                return nr_rw >= required;
        case BCH_MEMBER_STATE_failed:
index 0e5a14fc8e7fbfde622ec68dfae45f69ad83bd87..ec784d975f6655a378207692644975e53271ddca 100644 (file)
@@ -4,7 +4,7 @@
 
 struct bch_sb_handle {
        struct bch_sb           *sb;
-       struct bdev_handle      *bdev_handle;
+       struct file             *s_bdev_file;
        struct block_device     *bdev;
        char                    *sb_name;
        struct bio              *bio;
index 231003b405efc304a4cefa61a6e4e2f30b4b9466..3a32faa86b5c4a2eee98de32951c18dc73052041 100644 (file)
@@ -289,7 +289,7 @@ int bch2_save_backtrace(bch_stacktrace *stack, struct task_struct *task, unsigne
        do {
                nr_entries = stack_trace_save_tsk(task, stack->data, stack->size, skipnr + 1);
        } while (nr_entries == stack->size &&
-                !(ret = darray_make_room(stack, stack->size * 2)));
+                !(ret = darray_make_room_gfp(stack, stack->size * 2, gfp)));
 
        stack->nr = nr_entries;
        up_read(&task->signal->exec_update_lock);
index a9be9ac9922225bb32801aec5834c9e9d87ffc97..378d9103a2072b1628e66d850a42b9254be72b36 100644 (file)
@@ -1455,6 +1455,7 @@ out:
  */
 void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
 {
+       LIST_HEAD(retry_list);
        struct btrfs_block_group *block_group;
        struct btrfs_space_info *space_info;
        struct btrfs_trans_handle *trans;
@@ -1476,6 +1477,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
 
        spin_lock(&fs_info->unused_bgs_lock);
        while (!list_empty(&fs_info->unused_bgs)) {
+               u64 used;
                int trimming;
 
                block_group = list_first_entry(&fs_info->unused_bgs,
@@ -1511,9 +1513,9 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
                        goto next;
                }
 
+               spin_lock(&space_info->lock);
                spin_lock(&block_group->lock);
-               if (block_group->reserved || block_group->pinned ||
-                   block_group->used || block_group->ro ||
+               if (btrfs_is_block_group_used(block_group) || block_group->ro ||
                    list_is_singular(&block_group->list)) {
                        /*
                         * We want to bail if we made new allocations or have
@@ -1523,10 +1525,49 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
                         */
                        trace_btrfs_skip_unused_block_group(block_group);
                        spin_unlock(&block_group->lock);
+                       spin_unlock(&space_info->lock);
                        up_write(&space_info->groups_sem);
                        goto next;
                }
+
+               /*
+                * The block group may be unused but there may be space reserved
+                * accounting with the existence of that block group, that is,
+                * space_info->bytes_may_use was incremented by a task but no
+                * space was yet allocated from the block group by the task.
+                * That space may or may not be allocated, as we are generally
+                * pessimistic about space reservation for metadata as well as
+                * for data when using compression (as we reserve space based on
+                * the worst case, when data can't be compressed, and before
+                * actually attempting compression, before starting writeback).
+                *
+                * So check if the total space of the space_info minus the size
+                * of this block group is less than the used space of the
+                * space_info - if that's the case, then it means we have tasks
+                * that might be relying on the block group in order to allocate
+                * extents, and add back the block group to the unused list when
+                * we finish, so that we retry later in case no tasks ended up
+                * needing to allocate extents from the block group.
+                */
+               used = btrfs_space_info_used(space_info, true);
+               if (space_info->total_bytes - block_group->length < used) {
+                       /*
+                        * Add a reference for the list, compensate for the ref
+                        * drop under the "next" label for the
+                        * fs_info->unused_bgs list.
+                        */
+                       btrfs_get_block_group(block_group);
+                       list_add_tail(&block_group->bg_list, &retry_list);
+
+                       trace_btrfs_skip_unused_block_group(block_group);
+                       spin_unlock(&block_group->lock);
+                       spin_unlock(&space_info->lock);
+                       up_write(&space_info->groups_sem);
+                       goto next;
+               }
+
                spin_unlock(&block_group->lock);
+               spin_unlock(&space_info->lock);
 
                /* We don't want to force the issue, only flip if it's ok. */
                ret = inc_block_group_ro(block_group, 0);
@@ -1650,12 +1691,16 @@ next:
                btrfs_put_block_group(block_group);
                spin_lock(&fs_info->unused_bgs_lock);
        }
+       list_splice_tail(&retry_list, &fs_info->unused_bgs);
        spin_unlock(&fs_info->unused_bgs_lock);
        mutex_unlock(&fs_info->reclaim_bgs_lock);
        return;
 
 flip_async:
        btrfs_end_transaction(trans);
+       spin_lock(&fs_info->unused_bgs_lock);
+       list_splice_tail(&retry_list, &fs_info->unused_bgs);
+       spin_unlock(&fs_info->unused_bgs_lock);
        mutex_unlock(&fs_info->reclaim_bgs_lock);
        btrfs_put_block_group(block_group);
        btrfs_discard_punt_unused_bgs_list(fs_info);
@@ -2684,6 +2729,37 @@ next:
                btrfs_dec_delayed_refs_rsv_bg_inserts(fs_info);
                list_del_init(&block_group->bg_list);
                clear_bit(BLOCK_GROUP_FLAG_NEW, &block_group->runtime_flags);
+
+               /*
+                * If the block group is still unused, add it to the list of
+                * unused block groups. The block group may have been created in
+                * order to satisfy a space reservation, in which case the
+                * extent allocation only happens later. But often we don't
+                * actually need to allocate space that we previously reserved,
+                * so the block group may become unused for a long time. For
+                * example for metadata we generally reserve space for a worst
+                * possible scenario, but then don't end up allocating all that
+                * space or none at all (due to no need to COW, extent buffers
+                * were already COWed in the current transaction and still
+                * unwritten, tree heights lower than the maximum possible
+                * height, etc). For data we generally reserve the axact amount
+                * of space we are going to allocate later, the exception is
+                * when using compression, as we must reserve space based on the
+                * uncompressed data size, because the compression is only done
+                * when writeback triggered and we don't know how much space we
+                * are actually going to need, so we reserve the uncompressed
+                * size because the data may be uncompressible in the worst case.
+                */
+               if (ret == 0) {
+                       bool used;
+
+                       spin_lock(&block_group->lock);
+                       used = btrfs_is_block_group_used(block_group);
+                       spin_unlock(&block_group->lock);
+
+                       if (!used)
+                               btrfs_mark_bg_unused(block_group);
+               }
        }
        btrfs_trans_release_chunk_metadata(trans);
 }
index c4a1f01cc1c240d108702fc8899de9efe00da613..962b11983901a86ae16add7962c5ea5a26796b6f 100644 (file)
@@ -257,6 +257,13 @@ static inline u64 btrfs_block_group_end(struct btrfs_block_group *block_group)
        return (block_group->start + block_group->length);
 }
 
+static inline bool btrfs_is_block_group_used(const struct btrfs_block_group *bg)
+{
+       lockdep_assert_held(&bg->lock);
+
+       return (bg->used > 0 || bg->reserved > 0 || bg->pinned > 0);
+}
+
 static inline bool btrfs_is_block_group_data_only(
                                        struct btrfs_block_group *block_group)
 {
index ceb5f586a2d55571d53db2de227f4ef0f5ec1c27..1043a8142351b2692587f4a5e6d11147ee7fde99 100644 (file)
@@ -494,7 +494,7 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans,
 
        block_rsv = get_block_rsv(trans, root);
 
-       if (unlikely(block_rsv->size == 0))
+       if (unlikely(btrfs_block_rsv_size(block_rsv) == 0))
                goto try_reserve;
 again:
        ret = btrfs_block_rsv_use_bytes(block_rsv, blocksize);
index b0bd12b8652f4f51e467a95b4bfa36ec8d894837..43a9a6b5a79f4622607529393eaced15cb1409ac 100644 (file)
@@ -101,4 +101,36 @@ static inline bool btrfs_block_rsv_full(const struct btrfs_block_rsv *rsv)
        return data_race(rsv->full);
 }
 
+/*
+ * Get the reserved mount of a block reserve in a context where getting a stale
+ * value is acceptable, instead of accessing it directly and trigger data race
+ * warning from KCSAN.
+ */
+static inline u64 btrfs_block_rsv_reserved(struct btrfs_block_rsv *rsv)
+{
+       u64 ret;
+
+       spin_lock(&rsv->lock);
+       ret = rsv->reserved;
+       spin_unlock(&rsv->lock);
+
+       return ret;
+}
+
+/*
+ * Get the size of a block reserve in a context where getting a stale value is
+ * acceptable, instead of accessing it directly and trigger data race warning
+ * from KCSAN.
+ */
+static inline u64 btrfs_block_rsv_size(struct btrfs_block_rsv *rsv)
+{
+       u64 ret;
+
+       spin_lock(&rsv->lock);
+       ret = rsv->size;
+       spin_unlock(&rsv->lock);
+
+       return ret;
+}
+
 #endif /* BTRFS_BLOCK_RSV_H */
index c276b136ab63a16d5278a654ab26a670098806c0..5b0b645714183a7adcbe093d48964ee7380c4b24 100644 (file)
@@ -1046,7 +1046,7 @@ static int defrag_collect_targets(struct btrfs_inode *inode,
                        goto add;
 
                /* Skip too large extent */
-               if (range_len >= extent_thresh)
+               if (em->len >= extent_thresh)
                        goto next;
 
                /*
index 2833e8ef4c098f680a4883d41a1e925dc477bc2f..acf9f4b6c044025fe2ef288e99716d0373d01f31 100644 (file)
@@ -245,7 +245,6 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
        struct btrfs_block_rsv *block_rsv = &inode->block_rsv;
        u64 reserve_size = 0;
        u64 qgroup_rsv_size = 0;
-       u64 csum_leaves;
        unsigned outstanding_extents;
 
        lockdep_assert_held(&inode->lock);
@@ -260,10 +259,12 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
                                                outstanding_extents);
                reserve_size += btrfs_calc_metadata_size(fs_info, 1);
        }
-       csum_leaves = btrfs_csum_bytes_to_leaves(fs_info,
-                                                inode->csum_bytes);
-       reserve_size += btrfs_calc_insert_metadata_size(fs_info,
-                                                       csum_leaves);
+       if (!(inode->flags & BTRFS_INODE_NODATASUM)) {
+               u64 csum_leaves;
+
+               csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, inode->csum_bytes);
+               reserve_size += btrfs_calc_insert_metadata_size(fs_info, csum_leaves);
+       }
        /*
         * For qgroup rsv, the calculation is very simple:
         * account one nodesize for each outstanding extent
@@ -278,14 +279,20 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
        spin_unlock(&block_rsv->lock);
 }
 
-static void calc_inode_reservations(struct btrfs_fs_info *fs_info,
+static void calc_inode_reservations(struct btrfs_inode *inode,
                                    u64 num_bytes, u64 disk_num_bytes,
                                    u64 *meta_reserve, u64 *qgroup_reserve)
 {
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
        u64 nr_extents = count_max_extents(fs_info, num_bytes);
-       u64 csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, disk_num_bytes);
+       u64 csum_leaves;
        u64 inode_update = btrfs_calc_metadata_size(fs_info, 1);
 
+       if (inode->flags & BTRFS_INODE_NODATASUM)
+               csum_leaves = 0;
+       else
+               csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, disk_num_bytes);
+
        *meta_reserve = btrfs_calc_insert_metadata_size(fs_info,
                                                nr_extents + csum_leaves);
 
@@ -337,7 +344,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes,
         * everything out and try again, which is bad.  This way we just
         * over-reserve slightly, and clean up the mess when we are done.
         */
-       calc_inode_reservations(fs_info, num_bytes, disk_num_bytes,
+       calc_inode_reservations(inode, num_bytes, disk_num_bytes,
                                &meta_reserve, &qgroup_reserve);
        ret = btrfs_qgroup_reserve_meta_prealloc(root, qgroup_reserve, true,
                                                 noflush);
@@ -359,7 +366,8 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes,
        nr_extents = count_max_extents(fs_info, num_bytes);
        spin_lock(&inode->lock);
        btrfs_mod_outstanding_extents(inode, nr_extents);
-       inode->csum_bytes += disk_num_bytes;
+       if (!(inode->flags & BTRFS_INODE_NODATASUM))
+               inode->csum_bytes += disk_num_bytes;
        btrfs_calculate_inode_block_rsv_size(fs_info, inode);
        spin_unlock(&inode->lock);
 
@@ -393,7 +401,8 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
 
        num_bytes = ALIGN(num_bytes, fs_info->sectorsize);
        spin_lock(&inode->lock);
-       inode->csum_bytes -= num_bytes;
+       if (!(inode->flags & BTRFS_INODE_NODATASUM))
+               inode->csum_bytes -= num_bytes;
        btrfs_calculate_inode_block_rsv_size(fs_info, inode);
        spin_unlock(&inode->lock);
 
index 1502d664c89273eb54ba3516528b74eab094f3b3..fb33027e5a4cd05b89c74ef97b25f9de9249cbf3 100644 (file)
@@ -246,7 +246,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
 {
        struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
        struct btrfs_device *device;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct block_device *bdev;
        u64 devid = BTRFS_DEV_REPLACE_DEVID;
        int ret = 0;
@@ -257,13 +257,13 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
                return -EINVAL;
        }
 
-       bdev_handle = bdev_open_by_path(device_path, BLK_OPEN_WRITE,
+       bdev_file = bdev_file_open_by_path(device_path, BLK_OPEN_WRITE,
                                        fs_info->bdev_holder, NULL);
-       if (IS_ERR(bdev_handle)) {
+       if (IS_ERR(bdev_file)) {
                btrfs_err(fs_info, "target device %s is invalid!", device_path);
-               return PTR_ERR(bdev_handle);
+               return PTR_ERR(bdev_file);
        }
-       bdev = bdev_handle->bdev;
+       bdev = file_bdev(bdev_file);
 
        if (!btrfs_check_device_zone_type(fs_info, bdev)) {
                btrfs_err(fs_info,
@@ -314,7 +314,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
        device->commit_bytes_used = device->bytes_used;
        device->fs_info = fs_info;
        device->bdev = bdev;
-       device->bdev_handle = bdev_handle;
+       device->bdev_file = bdev_file;
        set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
        set_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state);
        device->dev_stats_valid = 1;
@@ -335,7 +335,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
        return 0;
 
 error:
-       bdev_release(bdev_handle);
+       fput(bdev_file);
        return ret;
 }
 
@@ -725,6 +725,23 @@ leave:
        return ret;
 }
 
+static int btrfs_check_replace_dev_names(struct btrfs_ioctl_dev_replace_args *args)
+{
+       if (args->start.srcdevid == 0) {
+               if (memchr(args->start.srcdev_name, 0,
+                          sizeof(args->start.srcdev_name)) == NULL)
+                       return -ENAMETOOLONG;
+       } else {
+               args->start.srcdev_name[0] = 0;
+       }
+
+       if (memchr(args->start.tgtdev_name, 0,
+                  sizeof(args->start.tgtdev_name)) == NULL)
+           return -ENAMETOOLONG;
+
+       return 0;
+}
+
 int btrfs_dev_replace_by_ioctl(struct btrfs_fs_info *fs_info,
                            struct btrfs_ioctl_dev_replace_args *args)
 {
@@ -737,10 +754,9 @@ int btrfs_dev_replace_by_ioctl(struct btrfs_fs_info *fs_info,
        default:
                return -EINVAL;
        }
-
-       if ((args->start.srcdevid == 0 && args->start.srcdev_name[0] == '\0') ||
-           args->start.tgtdev_name[0] == '\0')
-               return -EINVAL;
+       ret = btrfs_check_replace_dev_names(args);
+       if (ret < 0)
+               return ret;
 
        ret = btrfs_dev_replace_start(fs_info, args->start.tgtdev_name,
                                        args->start.srcdevid,
index e71ef97d0a7cabb236e8cbd073667b2e3d143dca..c843563914cad08e2dd84ef1741e19d933f092ee 100644 (file)
@@ -1307,12 +1307,12 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info)
  *
  * @objectid:  root id
  * @anon_dev:  preallocated anonymous block device number for new roots,
- *             pass 0 for new allocation.
+ *             pass NULL for a new allocation.
  * @check_ref: whether to check root item references, If true, return -ENOENT
  *             for orphan roots
  */
 static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info,
-                                            u64 objectid, dev_t anon_dev,
+                                            u64 objectid, dev_t *anon_dev,
                                             bool check_ref)
 {
        struct btrfs_root *root;
@@ -1342,9 +1342,9 @@ again:
                 * that common but still possible.  In that case, we just need
                 * to free the anon_dev.
                 */
-               if (unlikely(anon_dev)) {
-                       free_anon_bdev(anon_dev);
-                       anon_dev = 0;
+               if (unlikely(anon_dev && *anon_dev)) {
+                       free_anon_bdev(*anon_dev);
+                       *anon_dev = 0;
                }
 
                if (check_ref && btrfs_root_refs(&root->root_item) == 0) {
@@ -1366,7 +1366,7 @@ again:
                goto fail;
        }
 
-       ret = btrfs_init_fs_root(root, anon_dev);
+       ret = btrfs_init_fs_root(root, anon_dev ? *anon_dev : 0);
        if (ret)
                goto fail;
 
@@ -1402,7 +1402,7 @@ fail:
         * root's anon_dev to 0 to avoid a double free, once by btrfs_put_root()
         * and once again by our caller.
         */
-       if (anon_dev)
+       if (anon_dev && *anon_dev)
                root->anon_dev = 0;
        btrfs_put_root(root);
        return ERR_PTR(ret);
@@ -1418,7 +1418,7 @@ fail:
 struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
                                     u64 objectid, bool check_ref)
 {
-       return btrfs_get_root_ref(fs_info, objectid, 0, check_ref);
+       return btrfs_get_root_ref(fs_info, objectid, NULL, check_ref);
 }
 
 /*
@@ -1426,11 +1426,11 @@ struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
  * the anonymous block device id
  *
  * @objectid:  tree objectid
- * @anon_dev:  if zero, allocate a new anonymous block device or use the
- *             parameter value
+ * @anon_dev:  if NULL, allocate a new anonymous block device or use the
+ *             parameter value if not NULL
  */
 struct btrfs_root *btrfs_get_new_fs_root(struct btrfs_fs_info *fs_info,
-                                        u64 objectid, dev_t anon_dev)
+                                        u64 objectid, dev_t *anon_dev)
 {
        return btrfs_get_root_ref(fs_info, objectid, anon_dev, true);
 }
index 9413726b329bb123202a66cf341320ca2d99e410..eb3473d1c1ac1b239092a594cf0f788f961b4943 100644 (file)
@@ -61,7 +61,7 @@ void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info);
 struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
                                     u64 objectid, bool check_ref);
 struct btrfs_root *btrfs_get_new_fs_root(struct btrfs_fs_info *fs_info,
-                                        u64 objectid, dev_t anon_dev);
+                                        u64 objectid, dev_t *anon_dev);
 struct btrfs_root *btrfs_get_fs_root_commit_root(struct btrfs_fs_info *fs_info,
                                                 struct btrfs_path *path,
                                                 u64 objectid);
index cfd2967f04a293cf3d38956e9e21ce9e6656b498..8b4bef05e22217cfe43af497060889e0e5b02d0a 100644 (file)
@@ -2480,6 +2480,7 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
                                struct fiemap_cache *cache,
                                u64 offset, u64 phys, u64 len, u32 flags)
 {
+       u64 cache_end;
        int ret = 0;
 
        /* Set at the end of extent_fiemap(). */
@@ -2489,15 +2490,102 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
                goto assign;
 
        /*
-        * Sanity check, extent_fiemap() should have ensured that new
-        * fiemap extent won't overlap with cached one.
-        * Not recoverable.
+        * When iterating the extents of the inode, at extent_fiemap(), we may
+        * find an extent that starts at an offset behind the end offset of the
+        * previous extent we processed. This happens if fiemap is called
+        * without FIEMAP_FLAG_SYNC and there are ordered extents completing
+        * while we call btrfs_next_leaf() (through fiemap_next_leaf_item()).
         *
-        * NOTE: Physical address can overlap, due to compression
+        * For example we are in leaf X processing its last item, which is the
+        * file extent item for file range [512K, 1M[, and after
+        * btrfs_next_leaf() releases the path, there's an ordered extent that
+        * completes for the file range [768K, 2M[, and that results in trimming
+        * the file extent item so that it now corresponds to the file range
+        * [512K, 768K[ and a new file extent item is inserted for the file
+        * range [768K, 2M[, which may end up as the last item of leaf X or as
+        * the first item of the next leaf - in either case btrfs_next_leaf()
+        * will leave us with a path pointing to the new extent item, for the
+        * file range [768K, 2M[, since that's the first key that follows the
+        * last one we processed. So in order not to report overlapping extents
+        * to user space, we trim the length of the previously cached extent and
+        * emit it.
+        *
+        * Upon calling btrfs_next_leaf() we may also find an extent with an
+        * offset smaller than or equals to cache->offset, and this happens
+        * when we had a hole or prealloc extent with several delalloc ranges in
+        * it, but after btrfs_next_leaf() released the path, delalloc was
+        * flushed and the resulting ordered extents were completed, so we can
+        * now have found a file extent item for an offset that is smaller than
+        * or equals to what we have in cache->offset. We deal with this as
+        * described below.
         */
-       if (cache->offset + cache->len > offset) {
-               WARN_ON(1);
-               return -EINVAL;
+       cache_end = cache->offset + cache->len;
+       if (cache_end > offset) {
+               if (offset == cache->offset) {
+                       /*
+                        * We cached a dealloc range (found in the io tree) for
+                        * a hole or prealloc extent and we have now found a
+                        * file extent item for the same offset. What we have
+                        * now is more recent and up to date, so discard what
+                        * we had in the cache and use what we have just found.
+                        */
+                       goto assign;
+               } else if (offset > cache->offset) {
+                       /*
+                        * The extent range we previously found ends after the
+                        * offset of the file extent item we found and that
+                        * offset falls somewhere in the middle of that previous
+                        * extent range. So adjust the range we previously found
+                        * to end at the offset of the file extent item we have
+                        * just found, since this extent is more up to date.
+                        * Emit that adjusted range and cache the file extent
+                        * item we have just found. This corresponds to the case
+                        * where a previously found file extent item was split
+                        * due to an ordered extent completing.
+                        */
+                       cache->len = offset - cache->offset;
+                       goto emit;
+               } else {
+                       const u64 range_end = offset + len;
+
+                       /*
+                        * The offset of the file extent item we have just found
+                        * is behind the cached offset. This means we were
+                        * processing a hole or prealloc extent for which we
+                        * have found delalloc ranges (in the io tree), so what
+                        * we have in the cache is the last delalloc range we
+                        * found while the file extent item we found can be
+                        * either for a whole delalloc range we previously
+                        * emmitted or only a part of that range.
+                        *
+                        * We have two cases here:
+                        *
+                        * 1) The file extent item's range ends at or behind the
+                        *    cached extent's end. In this case just ignore the
+                        *    current file extent item because we don't want to
+                        *    overlap with previous ranges that may have been
+                        *    emmitted already;
+                        *
+                        * 2) The file extent item starts behind the currently
+                        *    cached extent but its end offset goes beyond the
+                        *    end offset of the cached extent. We don't want to
+                        *    overlap with a previous range that may have been
+                        *    emmitted already, so we emit the currently cached
+                        *    extent and then partially store the current file
+                        *    extent item's range in the cache, for the subrange
+                        *    going the cached extent's end to the end of the
+                        *    file extent item.
+                        */
+                       if (range_end <= cache_end)
+                               return 0;
+
+                       if (!(flags & (FIEMAP_EXTENT_ENCODED | FIEMAP_EXTENT_DELALLOC)))
+                               phys += cache_end - offset;
+
+                       offset = cache_end;
+                       len = range_end - cache_end;
+                       goto emit;
+               }
        }
 
        /*
@@ -2517,6 +2605,7 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
                return 0;
        }
 
+emit:
        /* Not mergeable, need to submit cached one */
        ret = fiemap_fill_next_extent(fieinfo, cache->offset, cache->phys,
                                      cache->len, cache->flags);
@@ -2689,16 +2778,34 @@ static int fiemap_process_hole(struct btrfs_inode *inode,
         * it beyond i_size.
         */
        while (cur_offset < end && cur_offset < i_size) {
+               struct extent_state *cached_state = NULL;
                u64 delalloc_start;
                u64 delalloc_end;
                u64 prealloc_start;
+               u64 lockstart;
+               u64 lockend;
                u64 prealloc_len = 0;
                bool delalloc;
 
+               lockstart = round_down(cur_offset, inode->root->fs_info->sectorsize);
+               lockend = round_up(end, inode->root->fs_info->sectorsize);
+
+               /*
+                * We are only locking for the delalloc range because that's the
+                * only thing that can change here.  With fiemap we have a lock
+                * on the inode, so no buffered or direct writes can happen.
+                *
+                * However mmaps and normal page writeback will cause this to
+                * change arbitrarily.  We have to lock the extent lock here to
+                * make sure that nobody messes with the tree while we're doing
+                * btrfs_find_delalloc_in_range.
+                */
+               lock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
                delalloc = btrfs_find_delalloc_in_range(inode, cur_offset, end,
                                                        delalloc_cached_state,
                                                        &delalloc_start,
                                                        &delalloc_end);
+               unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
                if (!delalloc)
                        break;
 
@@ -2866,15 +2973,15 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
                  u64 start, u64 len)
 {
        const u64 ino = btrfs_ino(inode);
-       struct extent_state *cached_state = NULL;
        struct extent_state *delalloc_cached_state = NULL;
        struct btrfs_path *path;
        struct fiemap_cache cache = { 0 };
        struct btrfs_backref_share_check_ctx *backref_ctx;
        u64 last_extent_end;
        u64 prev_extent_end;
-       u64 lockstart;
-       u64 lockend;
+       u64 range_start;
+       u64 range_end;
+       const u64 sectorsize = inode->root->fs_info->sectorsize;
        bool stopped = false;
        int ret;
 
@@ -2885,22 +2992,19 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
                goto out;
        }
 
-       lockstart = round_down(start, inode->root->fs_info->sectorsize);
-       lockend = round_up(start + len, inode->root->fs_info->sectorsize);
-       prev_extent_end = lockstart;
-
-       btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED);
-       lock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
+       range_start = round_down(start, sectorsize);
+       range_end = round_up(start + len, sectorsize);
+       prev_extent_end = range_start;
 
        ret = fiemap_find_last_extent_offset(inode, path, &last_extent_end);
        if (ret < 0)
-               goto out_unlock;
+               goto out;
        btrfs_release_path(path);
 
        path->reada = READA_FORWARD;
-       ret = fiemap_search_slot(inode, path, lockstart);
+       ret = fiemap_search_slot(inode, path, range_start);
        if (ret < 0) {
-               goto out_unlock;
+               goto out;
        } else if (ret > 0) {
                /*
                 * No file extent item found, but we may have delalloc between
@@ -2910,7 +3014,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
                goto check_eof_delalloc;
        }
 
-       while (prev_extent_end < lockend) {
+       while (prev_extent_end < range_end) {
                struct extent_buffer *leaf = path->nodes[0];
                struct btrfs_file_extent_item *ei;
                struct btrfs_key key;
@@ -2933,21 +3037,21 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
                 * The first iteration can leave us at an extent item that ends
                 * before our range's start. Move to the next item.
                 */
-               if (extent_end <= lockstart)
+               if (extent_end <= range_start)
                        goto next_item;
 
                backref_ctx->curr_leaf_bytenr = leaf->start;
 
                /* We have in implicit hole (NO_HOLES feature enabled). */
                if (prev_extent_end < key.offset) {
-                       const u64 range_end = min(key.offset, lockend) - 1;
+                       const u64 hole_end = min(key.offset, range_end) - 1;
 
                        ret = fiemap_process_hole(inode, fieinfo, &cache,
                                                  &delalloc_cached_state,
                                                  backref_ctx, 0, 0, 0,
-                                                 prev_extent_end, range_end);
+                                                 prev_extent_end, hole_end);
                        if (ret < 0) {
-                               goto out_unlock;
+                               goto out;
                        } else if (ret > 0) {
                                /* fiemap_fill_next_extent() told us to stop. */
                                stopped = true;
@@ -2955,7 +3059,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
                        }
 
                        /* We've reached the end of the fiemap range, stop. */
-                       if (key.offset >= lockend) {
+                       if (key.offset >= range_end) {
                                stopped = true;
                                break;
                        }
@@ -3003,7 +3107,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
                                                                  extent_gen,
                                                                  backref_ctx);
                                if (ret < 0)
-                                       goto out_unlock;
+                                       goto out;
                                else if (ret > 0)
                                        flags |= FIEMAP_EXTENT_SHARED;
                        }
@@ -3014,7 +3118,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
                }
 
                if (ret < 0) {
-                       goto out_unlock;
+                       goto out;
                } else if (ret > 0) {
                        /* fiemap_fill_next_extent() told us to stop. */
                        stopped = true;
@@ -3025,12 +3129,12 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
 next_item:
                if (fatal_signal_pending(current)) {
                        ret = -EINTR;
-                       goto out_unlock;
+                       goto out;
                }
 
                ret = fiemap_next_leaf_item(inode, path);
                if (ret < 0) {
-                       goto out_unlock;
+                       goto out;
                } else if (ret > 0) {
                        /* No more file extent items for this inode. */
                        break;
@@ -3049,29 +3153,41 @@ check_eof_delalloc:
        btrfs_free_path(path);
        path = NULL;
 
-       if (!stopped && prev_extent_end < lockend) {
+       if (!stopped && prev_extent_end < range_end) {
                ret = fiemap_process_hole(inode, fieinfo, &cache,
                                          &delalloc_cached_state, backref_ctx,
-                                         0, 0, 0, prev_extent_end, lockend - 1);
+                                         0, 0, 0, prev_extent_end, range_end - 1);
                if (ret < 0)
-                       goto out_unlock;
-               prev_extent_end = lockend;
+                       goto out;
+               prev_extent_end = range_end;
        }
 
        if (cache.cached && cache.offset + cache.len >= last_extent_end) {
                const u64 i_size = i_size_read(&inode->vfs_inode);
 
                if (prev_extent_end < i_size) {
+                       struct extent_state *cached_state = NULL;
                        u64 delalloc_start;
                        u64 delalloc_end;
+                       u64 lockstart;
+                       u64 lockend;
                        bool delalloc;
 
+                       lockstart = round_down(prev_extent_end, sectorsize);
+                       lockend = round_up(i_size, sectorsize);
+
+                       /*
+                        * See the comment in fiemap_process_hole as to why
+                        * we're doing the locking here.
+                        */
+                       lock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
                        delalloc = btrfs_find_delalloc_in_range(inode,
                                                                prev_extent_end,
                                                                i_size - 1,
                                                                &delalloc_cached_state,
                                                                &delalloc_start,
                                                                &delalloc_end);
+                       unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
                        if (!delalloc)
                                cache.flags |= FIEMAP_EXTENT_LAST;
                } else {
@@ -3080,10 +3196,6 @@ check_eof_delalloc:
        }
 
        ret = emit_last_fiemap_cache(fieinfo, &cache);
-
-out_unlock:
-       unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
-       btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
 out:
        free_extent_state(delalloc_cached_state);
        btrfs_free_backref_share_ctx(backref_ctx);
index 1eb93d3962aac4608cda0255ea31d7e53dbc8da2..4795738d5785bce730fad21b68a00ff729b97915 100644 (file)
@@ -3184,8 +3184,23 @@ out:
                        unwritten_start += logical_len;
                clear_extent_uptodate(io_tree, unwritten_start, end, NULL);
 
-               /* Drop extent maps for the part of the extent we didn't write. */
-               btrfs_drop_extent_map_range(inode, unwritten_start, end, false);
+               /*
+                * Drop extent maps for the part of the extent we didn't write.
+                *
+                * We have an exception here for the free_space_inode, this is
+                * because when we do btrfs_get_extent() on the free space inode
+                * we will search the commit root.  If this is a new block group
+                * we won't find anything, and we will trip over the assert in
+                * writepage where we do ASSERT(em->block_start !=
+                * EXTENT_MAP_HOLE).
+                *
+                * Theoretically we could also skip this for any NOCOW extent as
+                * we don't mess with the extent map tree in the NOCOW case, but
+                * for now simply skip this if we are the free space inode.
+                */
+               if (!btrfs_is_free_space_inode(inode))
+                       btrfs_drop_extent_map_range(inode, unwritten_start,
+                                                   end, false);
 
                /*
                 * If the ordered extent had an IOERR or something else went
@@ -7820,6 +7835,7 @@ struct iomap_dio *btrfs_dio_write(struct kiocb *iocb, struct iov_iter *iter,
 static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                        u64 start, u64 len)
 {
+       struct btrfs_inode *btrfs_inode = BTRFS_I(inode);
        int     ret;
 
        ret = fiemap_prep(inode, fieinfo, start, &len, 0);
@@ -7845,7 +7861,26 @@ static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                        return ret;
        }
 
-       return extent_fiemap(BTRFS_I(inode), fieinfo, start, len);
+       btrfs_inode_lock(btrfs_inode, BTRFS_ILOCK_SHARED);
+
+       /*
+        * We did an initial flush to avoid holding the inode's lock while
+        * triggering writeback and waiting for the completion of IO and ordered
+        * extents. Now after we locked the inode we do it again, because it's
+        * possible a new write may have happened in between those two steps.
+        */
+       if (fieinfo->fi_flags & FIEMAP_FLAG_SYNC) {
+               ret = btrfs_wait_ordered_range(inode, 0, LLONG_MAX);
+               if (ret) {
+                       btrfs_inode_unlock(btrfs_inode, BTRFS_ILOCK_SHARED);
+                       return ret;
+               }
+       }
+
+       ret = extent_fiemap(btrfs_inode, fieinfo, start, len);
+       btrfs_inode_unlock(btrfs_inode, BTRFS_ILOCK_SHARED);
+
+       return ret;
 }
 
 static int btrfs_writepages(struct address_space *mapping,
@@ -10273,6 +10308,13 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
        if (encoded->encryption != BTRFS_ENCODED_IO_ENCRYPTION_NONE)
                return -EINVAL;
 
+       /*
+        * Compressed extents should always have checksums, so error out if we
+        * have a NOCOW file or inode was created while mounted with NODATASUM.
+        */
+       if (inode->flags & BTRFS_INODE_NODATASUM)
+               return -EINVAL;
+
        orig_count = iov_iter_count(from);
 
        /* The extent size must be sane. */
index ac3316e0d11c3a42835dc8a2094b00a16019bd64..9876ee27f069e693f47c74170f5c54167b8c0268 100644 (file)
@@ -721,7 +721,7 @@ static noinline int create_subvol(struct mnt_idmap *idmap,
        free_extent_buffer(leaf);
        leaf = NULL;
 
-       new_root = btrfs_get_new_fs_root(fs_info, objectid, anon_dev);
+       new_root = btrfs_get_new_fs_root(fs_info, objectid, &anon_dev);
        if (IS_ERR(new_root)) {
                ret = PTR_ERR(new_root);
                btrfs_abort_transaction(trans, ret);
@@ -2698,7 +2698,7 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
        struct inode *inode = file_inode(file);
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_ioctl_vol_args_v2 *vol_args;
-       struct bdev_handle *bdev_handle = NULL;
+       struct file *bdev_file = NULL;
        int ret;
        bool cancel = false;
 
@@ -2735,7 +2735,7 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
                goto err_drop;
 
        /* Exclusive operation is now claimed */
-       ret = btrfs_rm_device(fs_info, &args, &bdev_handle);
+       ret = btrfs_rm_device(fs_info, &args, &bdev_file);
 
        btrfs_exclop_finish(fs_info);
 
@@ -2749,8 +2749,8 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
        }
 err_drop:
        mnt_drop_write_file(file);
-       if (bdev_handle)
-               bdev_release(bdev_handle);
+       if (bdev_file)
+               fput(bdev_file);
 out:
        btrfs_put_dev_args_from_path(&args);
        kfree(vol_args);
@@ -2763,7 +2763,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
        struct inode *inode = file_inode(file);
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_ioctl_vol_args *vol_args;
-       struct bdev_handle *bdev_handle = NULL;
+       struct file *bdev_file = NULL;
        int ret;
        bool cancel = false;
 
@@ -2790,15 +2790,15 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
        ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_DEV_REMOVE,
                                           cancel);
        if (ret == 0) {
-               ret = btrfs_rm_device(fs_info, &args, &bdev_handle);
+               ret = btrfs_rm_device(fs_info, &args, &bdev_file);
                if (!ret)
                        btrfs_info(fs_info, "disk deleted %s", vol_args->name);
                btrfs_exclop_finish(fs_info);
        }
 
        mnt_drop_write_file(file);
-       if (bdev_handle)
-               bdev_release(bdev_handle);
+       if (bdev_file)
+               fput(bdev_file);
 out:
        btrfs_put_dev_args_from_path(&args);
        kfree(vol_args);
index 7902298c1f25bbee1586a97f2223f3c079e3a8fb..e48a063ef0851f9476fd37a00572c1dd6c6fe379 100644 (file)
@@ -6705,11 +6705,20 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
                                if (ret)
                                        goto out;
                        }
-                       if (sctx->cur_inode_last_extent <
-                           sctx->cur_inode_size) {
-                               ret = send_hole(sctx, sctx->cur_inode_size);
-                               if (ret)
+                       if (sctx->cur_inode_last_extent < sctx->cur_inode_size) {
+                               ret = range_is_hole_in_parent(sctx,
+                                                     sctx->cur_inode_last_extent,
+                                                     sctx->cur_inode_size);
+                               if (ret < 0) {
                                        goto out;
+                               } else if (ret == 0) {
+                                       ret = send_hole(sctx, sctx->cur_inode_size);
+                                       if (ret < 0)
+                                               goto out;
+                               } else {
+                                       /* Range is already a hole, skip. */
+                                       ret = 0;
+                               }
                        }
                }
                if (need_truncate) {
index 571bb13587d5e7aabc1c40feab093af5257a6782..3b54eb5834746be51807d3e13023fba3f2701981 100644 (file)
@@ -856,7 +856,7 @@ btrfs_calc_reclaim_metadata_size(struct btrfs_fs_info *fs_info,
 static bool need_preemptive_reclaim(struct btrfs_fs_info *fs_info,
                                    struct btrfs_space_info *space_info)
 {
-       u64 global_rsv_size = fs_info->global_block_rsv.reserved;
+       const u64 global_rsv_size = btrfs_block_rsv_reserved(&fs_info->global_block_rsv);
        u64 ordered, delalloc;
        u64 thresh;
        u64 used;
@@ -956,8 +956,8 @@ static bool need_preemptive_reclaim(struct btrfs_fs_info *fs_info,
        ordered = percpu_counter_read_positive(&fs_info->ordered_bytes) >> 1;
        delalloc = percpu_counter_read_positive(&fs_info->delalloc_bytes);
        if (ordered >= delalloc)
-               used += fs_info->delayed_refs_rsv.reserved +
-                       fs_info->delayed_block_rsv.reserved;
+               used += btrfs_block_rsv_reserved(&fs_info->delayed_refs_rsv) +
+                       btrfs_block_rsv_reserved(&fs_info->delayed_block_rsv);
        else
                used += space_info->bytes_may_use - global_rsv_size;
 
@@ -1173,7 +1173,7 @@ static void btrfs_preempt_reclaim_metadata_space(struct work_struct *work)
                enum btrfs_flush_state flush;
                u64 delalloc_size = 0;
                u64 to_reclaim, block_rsv_size;
-               u64 global_rsv_size = global_rsv->reserved;
+               const u64 global_rsv_size = btrfs_block_rsv_reserved(global_rsv);
 
                loops++;
 
@@ -1185,9 +1185,9 @@ static void btrfs_preempt_reclaim_metadata_space(struct work_struct *work)
                 * assume it's tied up in delalloc reservations.
                 */
                block_rsv_size = global_rsv_size +
-                       delayed_block_rsv->reserved +
-                       delayed_refs_rsv->reserved +
-                       trans_rsv->reserved;
+                       btrfs_block_rsv_reserved(delayed_block_rsv) +
+                       btrfs_block_rsv_reserved(delayed_refs_rsv) +
+                       btrfs_block_rsv_reserved(trans_rsv);
                if (block_rsv_size < space_info->bytes_may_use)
                        delalloc_size = space_info->bytes_may_use - block_rsv_size;
 
@@ -1207,16 +1207,16 @@ static void btrfs_preempt_reclaim_metadata_space(struct work_struct *work)
                        to_reclaim = delalloc_size;
                        flush = FLUSH_DELALLOC;
                } else if (space_info->bytes_pinned >
-                          (delayed_block_rsv->reserved +
-                           delayed_refs_rsv->reserved)) {
+                          (btrfs_block_rsv_reserved(delayed_block_rsv) +
+                           btrfs_block_rsv_reserved(delayed_refs_rsv))) {
                        to_reclaim = space_info->bytes_pinned;
                        flush = COMMIT_TRANS;
-               } else if (delayed_block_rsv->reserved >
-                          delayed_refs_rsv->reserved) {
-                       to_reclaim = delayed_block_rsv->reserved;
+               } else if (btrfs_block_rsv_reserved(delayed_block_rsv) >
+                          btrfs_block_rsv_reserved(delayed_refs_rsv)) {
+                       to_reclaim = btrfs_block_rsv_reserved(delayed_block_rsv);
                        flush = FLUSH_DELAYED_ITEMS_NR;
                } else {
-                       to_reclaim = delayed_refs_rsv->reserved;
+                       to_reclaim = btrfs_block_rsv_reserved(delayed_refs_rsv);
                        flush = FLUSH_DELAYED_REFS_NR;
                }
 
index 5b3333ceef04818dbf98270da4bb84c99e5c70f8..bf8e64c766b63b4c8b424f4437791eaea12f24a2 100644 (file)
@@ -564,56 +564,22 @@ static int btrfs_reserve_trans_metadata(struct btrfs_fs_info *fs_info,
                                        u64 num_bytes,
                                        u64 *delayed_refs_bytes)
 {
-       struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv;
        struct btrfs_space_info *si = fs_info->trans_block_rsv.space_info;
-       u64 extra_delayed_refs_bytes = 0;
-       u64 bytes;
+       u64 bytes = num_bytes + *delayed_refs_bytes;
        int ret;
 
-       /*
-        * If there's a gap between the size of the delayed refs reserve and
-        * its reserved space, than some tasks have added delayed refs or bumped
-        * its size otherwise (due to block group creation or removal, or block
-        * group item update). Also try to allocate that gap in order to prevent
-        * using (and possibly abusing) the global reserve when committing the
-        * transaction.
-        */
-       if (flush == BTRFS_RESERVE_FLUSH_ALL &&
-           !btrfs_block_rsv_full(delayed_refs_rsv)) {
-               spin_lock(&delayed_refs_rsv->lock);
-               if (delayed_refs_rsv->size > delayed_refs_rsv->reserved)
-                       extra_delayed_refs_bytes = delayed_refs_rsv->size -
-                               delayed_refs_rsv->reserved;
-               spin_unlock(&delayed_refs_rsv->lock);
-       }
-
-       bytes = num_bytes + *delayed_refs_bytes + extra_delayed_refs_bytes;
-
        /*
         * We want to reserve all the bytes we may need all at once, so we only
         * do 1 enospc flushing cycle per transaction start.
         */
        ret = btrfs_reserve_metadata_bytes(fs_info, si, bytes, flush);
-       if (ret == 0) {
-               if (extra_delayed_refs_bytes > 0)
-                       btrfs_migrate_to_delayed_refs_rsv(fs_info,
-                                                         extra_delayed_refs_bytes);
-               return 0;
-       }
-
-       if (extra_delayed_refs_bytes > 0) {
-               bytes -= extra_delayed_refs_bytes;
-               ret = btrfs_reserve_metadata_bytes(fs_info, si, bytes, flush);
-               if (ret == 0)
-                       return 0;
-       }
 
        /*
         * If we are an emergency flush, which can steal from the global block
         * reserve, then attempt to not reserve space for the delayed refs, as
         * we will consume space for them from the global block reserve.
         */
-       if (flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) {
+       if (ret && flush == BTRFS_RESERVE_FLUSH_ALL_STEAL) {
                bytes -= *delayed_refs_bytes;
                *delayed_refs_bytes = 0;
                ret = btrfs_reserve_metadata_bytes(fs_info, si, bytes, flush);
@@ -1868,7 +1834,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        }
 
        key.offset = (u64)-1;
-       pending->snap = btrfs_get_new_fs_root(fs_info, objectid, pending->anon_dev);
+       pending->snap = btrfs_get_new_fs_root(fs_info, objectid, &pending->anon_dev);
        if (IS_ERR(pending->snap)) {
                ret = PTR_ERR(pending->snap);
                pending->snap = NULL;
index d67785be2c778c6611d639dcbdcffffec4c513c2..e180da4cc227317370401651d495c303d5a79782 100644 (file)
@@ -468,39 +468,39 @@ static noinline struct btrfs_fs_devices *find_fsid(
 
 static int
 btrfs_get_bdev_and_sb(const char *device_path, blk_mode_t flags, void *holder,
-                     int flush, struct bdev_handle **bdev_handle,
+                     int flush, struct file **bdev_file,
                      struct btrfs_super_block **disk_super)
 {
        struct block_device *bdev;
        int ret;
 
-       *bdev_handle = bdev_open_by_path(device_path, flags, holder, NULL);
+       *bdev_file = bdev_file_open_by_path(device_path, flags, holder, NULL);
 
-       if (IS_ERR(*bdev_handle)) {
-               ret = PTR_ERR(*bdev_handle);
+       if (IS_ERR(*bdev_file)) {
+               ret = PTR_ERR(*bdev_file);
                goto error;
        }
-       bdev = (*bdev_handle)->bdev;
+       bdev = file_bdev(*bdev_file);
 
        if (flush)
                sync_blockdev(bdev);
        ret = set_blocksize(bdev, BTRFS_BDEV_BLOCKSIZE);
        if (ret) {
-               bdev_release(*bdev_handle);
+               fput(*bdev_file);
                goto error;
        }
        invalidate_bdev(bdev);
        *disk_super = btrfs_read_dev_super(bdev);
        if (IS_ERR(*disk_super)) {
                ret = PTR_ERR(*disk_super);
-               bdev_release(*bdev_handle);
+               fput(*bdev_file);
                goto error;
        }
 
        return 0;
 
 error:
-       *bdev_handle = NULL;
+       *bdev_file = NULL;
        return ret;
 }
 
@@ -643,7 +643,7 @@ static int btrfs_open_one_device(struct btrfs_fs_devices *fs_devices,
                        struct btrfs_device *device, blk_mode_t flags,
                        void *holder)
 {
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct btrfs_super_block *disk_super;
        u64 devid;
        int ret;
@@ -654,7 +654,7 @@ static int btrfs_open_one_device(struct btrfs_fs_devices *fs_devices,
                return -EINVAL;
 
        ret = btrfs_get_bdev_and_sb(device->name->str, flags, holder, 1,
-                                   &bdev_handle, &disk_super);
+                                   &bdev_file, &disk_super);
        if (ret)
                return ret;
 
@@ -678,20 +678,20 @@ static int btrfs_open_one_device(struct btrfs_fs_devices *fs_devices,
                clear_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
                fs_devices->seeding = true;
        } else {
-               if (bdev_read_only(bdev_handle->bdev))
+               if (bdev_read_only(file_bdev(bdev_file)))
                        clear_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
                else
                        set_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
        }
 
-       if (!bdev_nonrot(bdev_handle->bdev))
+       if (!bdev_nonrot(file_bdev(bdev_file)))
                fs_devices->rotating = true;
 
-       if (bdev_max_discard_sectors(bdev_handle->bdev))
+       if (bdev_max_discard_sectors(file_bdev(bdev_file)))
                fs_devices->discardable = true;
 
-       device->bdev_handle = bdev_handle;
-       device->bdev = bdev_handle->bdev;
+       device->bdev_file = bdev_file;
+       device->bdev = file_bdev(bdev_file);
        clear_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
 
        fs_devices->open_devices++;
@@ -706,7 +706,7 @@ static int btrfs_open_one_device(struct btrfs_fs_devices *fs_devices,
 
 error_free_page:
        btrfs_release_disk_super(disk_super);
-       bdev_release(bdev_handle);
+       fput(bdev_file);
 
        return -EINVAL;
 }
@@ -1015,10 +1015,10 @@ static void __btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices,
                if (device->devid == BTRFS_DEV_REPLACE_DEVID)
                        continue;
 
-               if (device->bdev_handle) {
-                       bdev_release(device->bdev_handle);
+               if (device->bdev_file) {
+                       fput(device->bdev_file);
                        device->bdev = NULL;
-                       device->bdev_handle = NULL;
+                       device->bdev_file = NULL;
                        fs_devices->open_devices--;
                }
                if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
@@ -1063,7 +1063,7 @@ static void btrfs_close_bdev(struct btrfs_device *device)
                invalidate_bdev(device->bdev);
        }
 
-       bdev_release(device->bdev_handle);
+       fput(device->bdev_file);
 }
 
 static void btrfs_close_one_device(struct btrfs_device *device)
@@ -1316,7 +1316,7 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
        struct btrfs_super_block *disk_super;
        bool new_device_added = false;
        struct btrfs_device *device = NULL;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        u64 bytenr, bytenr_orig;
        int ret;
 
@@ -1339,18 +1339,18 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
         * values temporarily, as the device paths of the fsid are the only
         * required information for assembling the volume.
         */
-       bdev_handle = bdev_open_by_path(path, flags, NULL, NULL);
-       if (IS_ERR(bdev_handle))
-               return ERR_CAST(bdev_handle);
+       bdev_file = bdev_file_open_by_path(path, flags, NULL, NULL);
+       if (IS_ERR(bdev_file))
+               return ERR_CAST(bdev_file);
 
        bytenr_orig = btrfs_sb_offset(0);
-       ret = btrfs_sb_log_location_bdev(bdev_handle->bdev, 0, READ, &bytenr);
+       ret = btrfs_sb_log_location_bdev(file_bdev(bdev_file), 0, READ, &bytenr);
        if (ret) {
                device = ERR_PTR(ret);
                goto error_bdev_put;
        }
 
-       disk_super = btrfs_read_disk_super(bdev_handle->bdev, bytenr,
+       disk_super = btrfs_read_disk_super(file_bdev(bdev_file), bytenr,
                                           bytenr_orig);
        if (IS_ERR(disk_super)) {
                device = ERR_CAST(disk_super);
@@ -1381,7 +1381,7 @@ free_disk_super:
        btrfs_release_disk_super(disk_super);
 
 error_bdev_put:
-       bdev_release(bdev_handle);
+       fput(bdev_file);
 
        return device;
 }
@@ -2057,7 +2057,7 @@ void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
 
 int btrfs_rm_device(struct btrfs_fs_info *fs_info,
                    struct btrfs_dev_lookup_args *args,
-                   struct bdev_handle **bdev_handle)
+                   struct file **bdev_file)
 {
        struct btrfs_trans_handle *trans;
        struct btrfs_device *device;
@@ -2166,7 +2166,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
 
        btrfs_assign_next_active_device(device, NULL);
 
-       if (device->bdev_handle) {
+       if (device->bdev_file) {
                cur_devices->open_devices--;
                /* remove sysfs entry */
                btrfs_sysfs_remove_device(device);
@@ -2182,9 +2182,9 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
         * free the device.
         *
         * We cannot call btrfs_close_bdev() here because we're holding the sb
-        * write lock, and bdev_release() will pull in the ->open_mutex on
-        * the block device and it's dependencies.  Instead just flush the
-        * device and let the caller do the final bdev_release.
+        * write lock, and fput() on the block device will pull in the
+        * ->open_mutex on the block device and it's dependencies.  Instead
+        *  just flush the device and let the caller do the final bdev_release.
         */
        if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
                btrfs_scratch_superblocks(fs_info, device->bdev,
@@ -2195,7 +2195,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
                }
        }
 
-       *bdev_handle = device->bdev_handle;
+       *bdev_file = device->bdev_file;
        synchronize_rcu();
        btrfs_free_device(device);
 
@@ -2332,7 +2332,7 @@ int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
                                 const char *path)
 {
        struct btrfs_super_block *disk_super;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        int ret;
 
        if (!path || !path[0])
@@ -2350,7 +2350,7 @@ int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
        }
 
        ret = btrfs_get_bdev_and_sb(path, BLK_OPEN_READ, NULL, 0,
-                                   &bdev_handle, &disk_super);
+                                   &bdev_file, &disk_super);
        if (ret) {
                btrfs_put_dev_args_from_path(args);
                return ret;
@@ -2363,7 +2363,7 @@ int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
        else
                memcpy(args->fsid, disk_super->fsid, BTRFS_FSID_SIZE);
        btrfs_release_disk_super(disk_super);
-       bdev_release(bdev_handle);
+       fput(bdev_file);
        return 0;
 }
 
@@ -2583,7 +2583,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        struct btrfs_root *root = fs_info->dev_root;
        struct btrfs_trans_handle *trans;
        struct btrfs_device *device;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct super_block *sb = fs_info->sb;
        struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
        struct btrfs_fs_devices *seed_devices = NULL;
@@ -2596,12 +2596,12 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        if (sb_rdonly(sb) && !fs_devices->seeding)
                return -EROFS;
 
-       bdev_handle = bdev_open_by_path(device_path, BLK_OPEN_WRITE,
+       bdev_file = bdev_file_open_by_path(device_path, BLK_OPEN_WRITE,
                                        fs_info->bdev_holder, NULL);
-       if (IS_ERR(bdev_handle))
-               return PTR_ERR(bdev_handle);
+       if (IS_ERR(bdev_file))
+               return PTR_ERR(bdev_file);
 
-       if (!btrfs_check_device_zone_type(fs_info, bdev_handle->bdev)) {
+       if (!btrfs_check_device_zone_type(fs_info, file_bdev(bdev_file))) {
                ret = -EINVAL;
                goto error;
        }
@@ -2613,11 +2613,11 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
                locked = true;
        }
 
-       sync_blockdev(bdev_handle->bdev);
+       sync_blockdev(file_bdev(bdev_file));
 
        rcu_read_lock();
        list_for_each_entry_rcu(device, &fs_devices->devices, dev_list) {
-               if (device->bdev == bdev_handle->bdev) {
+               if (device->bdev == file_bdev(bdev_file)) {
                        ret = -EEXIST;
                        rcu_read_unlock();
                        goto error;
@@ -2633,8 +2633,8 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        }
 
        device->fs_info = fs_info;
-       device->bdev_handle = bdev_handle;
-       device->bdev = bdev_handle->bdev;
+       device->bdev_file = bdev_file;
+       device->bdev = file_bdev(bdev_file);
        ret = lookup_bdev(device_path, &device->devt);
        if (ret)
                goto error_free_device;
@@ -2817,7 +2817,7 @@ error_free_zone:
 error_free_device:
        btrfs_free_device(device);
 error:
-       bdev_release(bdev_handle);
+       fput(bdev_file);
        if (locked) {
                mutex_unlock(&uuid_mutex);
                up_write(&sb->s_umount);
index 53f87f398da779aba835c5d3cb65a090ac5a5698..a11854912d535fe60325d31b19879ef183392c04 100644 (file)
@@ -90,7 +90,7 @@ struct btrfs_device {
 
        u64 generation;
 
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct block_device *bdev;
 
        struct btrfs_zoned_device_info *zone_info;
@@ -661,7 +661,7 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
 void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args);
 int btrfs_rm_device(struct btrfs_fs_info *fs_info,
                    struct btrfs_dev_lookup_args *args,
-                   struct bdev_handle **bdev_handle);
+                   struct file **bdev_file);
 void __exit btrfs_cleanup_fs_uuids(void);
 int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len);
 int btrfs_grow_device(struct btrfs_trans_handle *trans,
index 168af9d000d168324fcc8355781517ddeedeefd1..aea51fd850cd9de130b30644a831488b5601f9ff 100644 (file)
@@ -824,11 +824,14 @@ static int sb_log_location(struct block_device *bdev, struct blk_zone *zones,
                        reset = &zones[1];
 
                if (reset && reset->cond != BLK_ZONE_COND_EMPTY) {
+                       unsigned int nofs_flags;
+
                        ASSERT(sb_zone_is_full(reset));
 
+                       nofs_flags = memalloc_nofs_save();
                        ret = blkdev_zone_mgmt(bdev, REQ_OP_ZONE_RESET,
-                                              reset->start, reset->len,
-                                              GFP_NOFS);
+                                              reset->start, reset->len);
+                       memalloc_nofs_restore(nofs_flags);
                        if (ret)
                                return ret;
 
@@ -974,11 +977,14 @@ int btrfs_advance_sb_log(struct btrfs_device *device, int mirror)
                         * explicit ZONE_FINISH is not necessary.
                         */
                        if (zone->wp != zone->start + zone->capacity) {
+                               unsigned int nofs_flags;
                                int ret;
 
+                               nofs_flags = memalloc_nofs_save();
                                ret = blkdev_zone_mgmt(device->bdev,
                                                REQ_OP_ZONE_FINISH, zone->start,
-                                               zone->len, GFP_NOFS);
+                                               zone->len);
+                               memalloc_nofs_restore(nofs_flags);
                                if (ret)
                                        return ret;
                        }
@@ -996,11 +1002,13 @@ int btrfs_advance_sb_log(struct btrfs_device *device, int mirror)
 
 int btrfs_reset_sb_log_zones(struct block_device *bdev, int mirror)
 {
+       unsigned int nofs_flags;
        sector_t zone_sectors;
        sector_t nr_sectors;
        u8 zone_sectors_shift;
        u32 sb_zone;
        u32 nr_zones;
+       int ret;
 
        zone_sectors = bdev_zone_sectors(bdev);
        zone_sectors_shift = ilog2(zone_sectors);
@@ -1011,9 +1019,12 @@ int btrfs_reset_sb_log_zones(struct block_device *bdev, int mirror)
        if (sb_zone + 1 >= nr_zones)
                return -ENOENT;
 
-       return blkdev_zone_mgmt(bdev, REQ_OP_ZONE_RESET,
-                               zone_start_sector(sb_zone, bdev),
-                               zone_sectors * BTRFS_NR_SB_LOG_ZONES, GFP_NOFS);
+       nofs_flags = memalloc_nofs_save();
+       ret = blkdev_zone_mgmt(bdev, REQ_OP_ZONE_RESET,
+                              zone_start_sector(sb_zone, bdev),
+                              zone_sectors * BTRFS_NR_SB_LOG_ZONES);
+       memalloc_nofs_restore(nofs_flags);
+       return ret;
 }
 
 /*
@@ -1124,12 +1135,14 @@ static void btrfs_dev_clear_active_zone(struct btrfs_device *device, u64 pos)
 int btrfs_reset_device_zone(struct btrfs_device *device, u64 physical,
                            u64 length, u64 *bytes)
 {
+       unsigned int nofs_flags;
        int ret;
 
        *bytes = 0;
+       nofs_flags = memalloc_nofs_save();
        ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_RESET,
-                              physical >> SECTOR_SHIFT, length >> SECTOR_SHIFT,
-                              GFP_NOFS);
+                              physical >> SECTOR_SHIFT, length >> SECTOR_SHIFT);
+       memalloc_nofs_restore(nofs_flags);
        if (ret)
                return ret;
 
@@ -1639,6 +1652,15 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
        }
 
 out:
+       /* Reject non SINGLE data profiles without RST */
+       if ((map->type & BTRFS_BLOCK_GROUP_DATA) &&
+           (map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) &&
+           !fs_info->stripe_root) {
+               btrfs_err(fs_info, "zoned: data %s needs raid-stripe-tree",
+                         btrfs_bg_type_to_raid_name(map->type));
+               return -EINVAL;
+       }
+
        if (cache->alloc_offset > cache->zone_capacity) {
                btrfs_err(fs_info,
 "zoned: invalid write pointer %llu (larger than zone capacity %llu) in block group %llu",
@@ -1670,6 +1692,7 @@ out:
        }
        bitmap_free(active);
        kfree(zone_info);
+       btrfs_free_chunk_map(map);
 
        return ret;
 }
@@ -2234,14 +2257,16 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
                struct btrfs_device *device = map->stripes[i].dev;
                const u64 physical = map->stripes[i].physical;
                struct btrfs_zoned_device_info *zinfo = device->zone_info;
+               unsigned int nofs_flags;
 
                if (zinfo->max_active_zones == 0)
                        continue;
 
+               nofs_flags = memalloc_nofs_save();
                ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
                                       physical >> SECTOR_SHIFT,
-                                      zinfo->zone_size >> SECTOR_SHIFT,
-                                      GFP_NOFS);
+                                      zinfo->zone_size >> SECTOR_SHIFT);
+               memalloc_nofs_restore(nofs_flags);
 
                if (ret)
                        return ret;
index d3bcf601d3e5a5330419d8e69500c3781f9e8cfc..4f73d23c2c469182a5d873993cdcf0651bfd04f8 100644 (file)
@@ -55,7 +55,7 @@
 
 static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
 static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
-                         struct writeback_control *wbc);
+                         enum rw_hint hint, struct writeback_control *wbc);
 
 #define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers)
 
@@ -464,7 +464,7 @@ EXPORT_SYMBOL(mark_buffer_async_write);
  * a successful fsync().  For example, ext2 indirect blocks need to be
  * written back and waited upon before fsync() returns.
  *
- * The functions mark_buffer_inode_dirty(), fsync_inode_buffers(),
+ * The functions mark_buffer_dirty_inode(), fsync_inode_buffers(),
  * inode_has_buffers() and invalidate_inode_buffers() are provided for the
  * management of a list of dependent buffers at ->i_mapping->i_private_list.
  *
@@ -1889,7 +1889,8 @@ int __block_write_full_folio(struct inode *inode, struct folio *folio,
        do {
                struct buffer_head *next = bh->b_this_page;
                if (buffer_async_write(bh)) {
-                       submit_bh_wbc(REQ_OP_WRITE | write_flags, bh, wbc);
+                       submit_bh_wbc(REQ_OP_WRITE | write_flags, bh,
+                                     inode->i_write_hint, wbc);
                        nr_underway++;
                }
                bh = next;
@@ -1944,7 +1945,8 @@ recover:
                struct buffer_head *next = bh->b_this_page;
                if (buffer_async_write(bh)) {
                        clear_buffer_dirty(bh);
-                       submit_bh_wbc(REQ_OP_WRITE | write_flags, bh, wbc);
+                       submit_bh_wbc(REQ_OP_WRITE | write_flags, bh,
+                                     inode->i_write_hint, wbc);
                        nr_underway++;
                }
                bh = next;
@@ -2756,6 +2758,7 @@ static void end_bio_bh_io_sync(struct bio *bio)
 }
 
 static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
+                         enum rw_hint write_hint,
                          struct writeback_control *wbc)
 {
        const enum req_op op = opf & REQ_OP_MASK;
@@ -2783,6 +2786,7 @@ static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
        fscrypt_set_bio_crypt_ctx_bh(bio, bh, GFP_NOIO);
 
        bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
+       bio->bi_write_hint = write_hint;
 
        __bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh));
 
@@ -2802,7 +2806,7 @@ static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
 
 void submit_bh(blk_opf_t opf, struct buffer_head *bh)
 {
-       submit_bh_wbc(opf, bh, NULL);
+       submit_bh_wbc(opf, bh, WRITE_LIFE_NOT_SET, NULL);
 }
 EXPORT_SYMBOL(submit_bh);
 
@@ -3121,12 +3125,8 @@ void __init buffer_init(void)
        unsigned long nrpages;
        int ret;
 
-       bh_cachep = kmem_cache_create("buffer_head",
-                       sizeof(struct buffer_head), 0,
-                               (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
-                               SLAB_MEM_SPREAD),
-                               NULL);
-
+       bh_cachep = KMEM_CACHE(buffer_head,
+                               SLAB_RECLAIM_ACCOUNT|SLAB_PANIC);
        /*
         * Limit the bh occupancy to 10% of ZONE_NORMAL
         */
index 7077f72e6f4747c2a1f1bd6c898221d4bdaab380..f449f7340aad0811ae2cea3134731e1a2111f5ff 100644 (file)
@@ -168,6 +168,8 @@ error_unsupported:
        dput(root);
 error_open_root:
        cachefiles_end_secure(cache, saved_cred);
+       put_cred(cache->cache_cred);
+       cache->cache_cred = NULL;
 error_getsec:
        fscache_relinquish_cache(cache_cookie);
        cache->cache = NULL;
index 3f24905f40661302936f08122394947d55e3d5f3..6465e257423091d5183a6bf4c7963a2e8e900766 100644 (file)
@@ -816,6 +816,7 @@ static void cachefiles_daemon_unbind(struct cachefiles_cache *cache)
        cachefiles_put_directory(cache->graveyard);
        cachefiles_put_directory(cache->store);
        mntput(cache->mnt);
+       put_cred(cache->cache_cred);
 
        kfree(cache->rootdirname);
        kfree(cache->secctx);
index ad1f46c66fbffbee52ba280ad79e03279e56e1e5..7fb4aae97412464c54b42037f75016085d214bd3 100644 (file)
@@ -2156,6 +2156,30 @@ retry:
                      ceph_cap_string(cap->implemented),
                      ceph_cap_string(revoking));
 
+               /* completed revocation? going down and there are no caps? */
+               if (revoking) {
+                       if ((revoking & cap_used) == 0) {
+                               doutc(cl, "completed revocation of %s\n",
+                                     ceph_cap_string(cap->implemented & ~cap->issued));
+                               goto ack;
+                       }
+
+                       /*
+                        * If the "i_wrbuffer_ref" was increased by mmap or generic
+                        * cache write just before the ceph_check_caps() is called,
+                        * the Fb capability revoking will fail this time. Then we
+                        * must wait for the BDI's delayed work to flush the dirty
+                        * pages and to release the "i_wrbuffer_ref", which will cost
+                        * at most 5 seconds. That means the MDS needs to wait at
+                        * most 5 seconds to finished the Fb capability's revocation.
+                        *
+                        * Let's queue a writeback for it.
+                        */
+                       if (S_ISREG(inode->i_mode) && ci->i_wrbuffer_ref &&
+                           (revoking & CEPH_CAP_FILE_BUFFER))
+                               queue_writeback = true;
+               }
+
                if (cap == ci->i_auth_cap &&
                    (cap->issued & CEPH_CAP_FILE_WR)) {
                        /* request larger max_size from MDS? */
@@ -2183,30 +2207,6 @@ retry:
                        }
                }
 
-               /* completed revocation? going down and there are no caps? */
-               if (revoking) {
-                       if ((revoking & cap_used) == 0) {
-                               doutc(cl, "completed revocation of %s\n",
-                                     ceph_cap_string(cap->implemented & ~cap->issued));
-                               goto ack;
-                       }
-
-                       /*
-                        * If the "i_wrbuffer_ref" was increased by mmap or generic
-                        * cache write just before the ceph_check_caps() is called,
-                        * the Fb capability revoking will fail this time. Then we
-                        * must wait for the BDI's delayed work to flush the dirty
-                        * pages and to release the "i_wrbuffer_ref", which will cost
-                        * at most 5 seconds. That means the MDS needs to wait at
-                        * most 5 seconds to finished the Fb capability's revocation.
-                        *
-                        * Let's queue a writeback for it.
-                        */
-                       if (S_ISREG(inode->i_mode) && ci->i_wrbuffer_ref &&
-                           (revoking & CEPH_CAP_FILE_BUFFER))
-                               queue_writeback = true;
-               }
-
                /* want more caps from mds? */
                if (want & ~cap->mds_wanted) {
                        if (want & ~(cap->mds_wanted | cap->issued))
@@ -4772,7 +4772,22 @@ int ceph_drop_caps_for_unlink(struct inode *inode)
                if (__ceph_caps_dirty(ci)) {
                        struct ceph_mds_client *mdsc =
                                ceph_inode_to_fs_client(inode)->mdsc;
-                       __cap_delay_requeue_front(mdsc, ci);
+
+                       doutc(mdsc->fsc->client, "%p %llx.%llx\n", inode,
+                             ceph_vinop(inode));
+                       spin_lock(&mdsc->cap_unlink_delay_lock);
+                       ci->i_ceph_flags |= CEPH_I_FLUSH;
+                       if (!list_empty(&ci->i_cap_delay_list))
+                               list_del_init(&ci->i_cap_delay_list);
+                       list_add_tail(&ci->i_cap_delay_list,
+                                     &mdsc->cap_unlink_delay_list);
+                       spin_unlock(&mdsc->cap_unlink_delay_lock);
+
+                       /*
+                        * Fire the work immediately, because the MDS maybe
+                        * waiting for caps release.
+                        */
+                       ceph_queue_cap_unlink_work(mdsc);
                }
        }
        spin_unlock(&ci->i_ceph_lock);
index e07ad29ff8b97210ed3d3173412f0b1d1cb7a257..ebf4ac0055ddc59815e4121550b09ebec08f801b 100644 (file)
@@ -33,7 +33,7 @@ void __init ceph_flock_init(void)
 
 static void ceph_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
 {
-       struct inode *inode = file_inode(dst->fl_file);
+       struct inode *inode = file_inode(dst->c.flc_file);
        atomic_inc(&ceph_inode(inode)->i_filelock_ref);
        dst->fl_u.ceph.inode = igrab(inode);
 }
@@ -110,17 +110,18 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct inode *inode,
        else
                length = fl->fl_end - fl->fl_start + 1;
 
-       owner = secure_addr(fl->fl_owner);
+       owner = secure_addr(fl->c.flc_owner);
 
        doutc(cl, "rule: %d, op: %d, owner: %llx, pid: %llu, "
                    "start: %llu, length: %llu, wait: %d, type: %d\n",
-                   (int)lock_type, (int)operation, owner, (u64)fl->fl_pid,
-                   fl->fl_start, length, wait, fl->fl_type);
+                   (int)lock_type, (int)operation, owner,
+                   (u64) fl->c.flc_pid,
+                   fl->fl_start, length, wait, fl->c.flc_type);
 
        req->r_args.filelock_change.rule = lock_type;
        req->r_args.filelock_change.type = cmd;
        req->r_args.filelock_change.owner = cpu_to_le64(owner);
-       req->r_args.filelock_change.pid = cpu_to_le64((u64)fl->fl_pid);
+       req->r_args.filelock_change.pid = cpu_to_le64((u64) fl->c.flc_pid);
        req->r_args.filelock_change.start = cpu_to_le64(fl->fl_start);
        req->r_args.filelock_change.length = cpu_to_le64(length);
        req->r_args.filelock_change.wait = wait;
@@ -130,13 +131,13 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct inode *inode,
                err = ceph_mdsc_wait_request(mdsc, req, wait ?
                                        ceph_lock_wait_for_completion : NULL);
        if (!err && operation == CEPH_MDS_OP_GETFILELOCK) {
-               fl->fl_pid = -le64_to_cpu(req->r_reply_info.filelock_reply->pid);
+               fl->c.flc_pid = -le64_to_cpu(req->r_reply_info.filelock_reply->pid);
                if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type)
-                       fl->fl_type = F_RDLCK;
+                       fl->c.flc_type = F_RDLCK;
                else if (CEPH_LOCK_EXCL == req->r_reply_info.filelock_reply->type)
-                       fl->fl_type = F_WRLCK;
+                       fl->c.flc_type = F_WRLCK;
                else
-                       fl->fl_type = F_UNLCK;
+                       fl->c.flc_type = F_UNLCK;
 
                fl->fl_start = le64_to_cpu(req->r_reply_info.filelock_reply->start);
                length = le64_to_cpu(req->r_reply_info.filelock_reply->start) +
@@ -150,8 +151,8 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct inode *inode,
        ceph_mdsc_put_request(req);
        doutc(cl, "rule: %d, op: %d, pid: %llu, start: %llu, "
              "length: %llu, wait: %d, type: %d, err code %d\n",
-             (int)lock_type, (int)operation, (u64)fl->fl_pid,
-             fl->fl_start, length, wait, fl->fl_type, err);
+             (int)lock_type, (int)operation, (u64) fl->c.flc_pid,
+             fl->fl_start, length, wait, fl->c.flc_type, err);
        return err;
 }
 
@@ -227,10 +228,10 @@ static int ceph_lock_wait_for_completion(struct ceph_mds_client *mdsc,
 static int try_unlock_file(struct file *file, struct file_lock *fl)
 {
        int err;
-       unsigned int orig_flags = fl->fl_flags;
-       fl->fl_flags |= FL_EXISTS;
+       unsigned int orig_flags = fl->c.flc_flags;
+       fl->c.flc_flags |= FL_EXISTS;
        err = locks_lock_file_wait(file, fl);
-       fl->fl_flags = orig_flags;
+       fl->c.flc_flags = orig_flags;
        if (err == -ENOENT) {
                if (!(orig_flags & FL_EXISTS))
                        err = 0;
@@ -253,13 +254,13 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
        u8 wait = 0;
        u8 lock_cmd;
 
-       if (!(fl->fl_flags & FL_POSIX))
+       if (!(fl->c.flc_flags & FL_POSIX))
                return -ENOLCK;
 
        if (ceph_inode_is_shutdown(inode))
                return -ESTALE;
 
-       doutc(cl, "fl_owner: %p\n", fl->fl_owner);
+       doutc(cl, "fl_owner: %p\n", fl->c.flc_owner);
 
        /* set wait bit as appropriate, then make command as Ceph expects it*/
        if (IS_GETLK(cmd))
@@ -273,19 +274,19 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
        }
        spin_unlock(&ci->i_ceph_lock);
        if (err < 0) {
-               if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK == fl->fl_type)
+               if (op == CEPH_MDS_OP_SETFILELOCK && lock_is_unlock(fl))
                        posix_lock_file(file, fl, NULL);
                return err;
        }
 
-       if (F_RDLCK == fl->fl_type)
+       if (lock_is_read(fl))
                lock_cmd = CEPH_LOCK_SHARED;
-       else if (F_WRLCK == fl->fl_type)
+       else if (lock_is_write(fl))
                lock_cmd = CEPH_LOCK_EXCL;
        else
                lock_cmd = CEPH_LOCK_UNLOCK;
 
-       if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK == fl->fl_type) {
+       if (op == CEPH_MDS_OP_SETFILELOCK && lock_is_unlock(fl)) {
                err = try_unlock_file(file, fl);
                if (err <= 0)
                        return err;
@@ -293,7 +294,7 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
 
        err = ceph_lock_message(CEPH_LOCK_FCNTL, op, inode, lock_cmd, wait, fl);
        if (!err) {
-               if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK != fl->fl_type) {
+               if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK != fl->c.flc_type) {
                        doutc(cl, "locking locally\n");
                        err = posix_lock_file(file, fl, NULL);
                        if (err) {
@@ -319,13 +320,13 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
        u8 wait = 0;
        u8 lock_cmd;
 
-       if (!(fl->fl_flags & FL_FLOCK))
+       if (!(fl->c.flc_flags & FL_FLOCK))
                return -ENOLCK;
 
        if (ceph_inode_is_shutdown(inode))
                return -ESTALE;
 
-       doutc(cl, "fl_file: %p\n", fl->fl_file);
+       doutc(cl, "fl_file: %p\n", fl->c.flc_file);
 
        spin_lock(&ci->i_ceph_lock);
        if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) {
@@ -333,7 +334,7 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
        }
        spin_unlock(&ci->i_ceph_lock);
        if (err < 0) {
-               if (F_UNLCK == fl->fl_type)
+               if (lock_is_unlock(fl))
                        locks_lock_file_wait(file, fl);
                return err;
        }
@@ -341,14 +342,14 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
        if (IS_SETLKW(cmd))
                wait = 1;
 
-       if (F_RDLCK == fl->fl_type)
+       if (lock_is_read(fl))
                lock_cmd = CEPH_LOCK_SHARED;
-       else if (F_WRLCK == fl->fl_type)
+       else if (lock_is_write(fl))
                lock_cmd = CEPH_LOCK_EXCL;
        else
                lock_cmd = CEPH_LOCK_UNLOCK;
 
-       if (F_UNLCK == fl->fl_type) {
+       if (lock_is_unlock(fl)) {
                err = try_unlock_file(file, fl);
                if (err <= 0)
                        return err;
@@ -356,7 +357,7 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
 
        err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK,
                                inode, lock_cmd, wait, fl);
-       if (!err && F_UNLCK != fl->fl_type) {
+       if (!err && F_UNLCK != fl->c.flc_type) {
                err = locks_lock_file_wait(file, fl);
                if (err) {
                        ceph_lock_message(CEPH_LOCK_FLOCK,
@@ -385,9 +386,9 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
        ctx = locks_inode_context(inode);
        if (ctx) {
                spin_lock(&ctx->flc_lock);
-               list_for_each_entry(lock, &ctx->flc_posix, fl_list)
+               for_each_file_lock(lock, &ctx->flc_posix)
                        ++(*fcntl_count);
-               list_for_each_entry(lock, &ctx->flc_flock, fl_list)
+               for_each_file_lock(lock, &ctx->flc_flock)
                        ++(*flock_count);
                spin_unlock(&ctx->flc_lock);
        }
@@ -408,10 +409,10 @@ static int lock_to_ceph_filelock(struct inode *inode,
        cephlock->start = cpu_to_le64(lock->fl_start);
        cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1);
        cephlock->client = cpu_to_le64(0);
-       cephlock->pid = cpu_to_le64((u64)lock->fl_pid);
-       cephlock->owner = cpu_to_le64(secure_addr(lock->fl_owner));
+       cephlock->pid = cpu_to_le64((u64) lock->c.flc_pid);
+       cephlock->owner = cpu_to_le64(secure_addr(lock->c.flc_owner));
 
-       switch (lock->fl_type) {
+       switch (lock->c.flc_type) {
        case F_RDLCK:
                cephlock->type = CEPH_LOCK_SHARED;
                break;
@@ -422,7 +423,8 @@ static int lock_to_ceph_filelock(struct inode *inode,
                cephlock->type = CEPH_LOCK_UNLOCK;
                break;
        default:
-               doutc(cl, "Have unknown lock type %d\n", lock->fl_type);
+               doutc(cl, "Have unknown lock type %d\n",
+                     lock->c.flc_type);
                err = -EINVAL;
        }
 
@@ -453,7 +455,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
                return 0;
 
        spin_lock(&ctx->flc_lock);
-       list_for_each_entry(lock, &ctx->flc_posix, fl_list) {
+       for_each_file_lock(lock, &ctx->flc_posix) {
                ++seen_fcntl;
                if (seen_fcntl > num_fcntl_locks) {
                        err = -ENOSPC;
@@ -464,7 +466,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
                        goto fail;
                ++l;
        }
-       list_for_each_entry(lock, &ctx->flc_flock, fl_list) {
+       for_each_file_lock(lock, &ctx->flc_flock) {
                ++seen_flock;
                if (seen_flock > num_flock_locks) {
                        err = -ENOSPC;
index f71bb9c9569fc754f447b50cfb8abc89083fe7fd..3ab9c268a8bb398b779cc93d3da98f3d13df8fe3 100644 (file)
@@ -2484,6 +2484,50 @@ void ceph_reclaim_caps_nr(struct ceph_mds_client *mdsc, int nr)
        }
 }
 
+void ceph_queue_cap_unlink_work(struct ceph_mds_client *mdsc)
+{
+       struct ceph_client *cl = mdsc->fsc->client;
+       if (mdsc->stopping)
+               return;
+
+        if (queue_work(mdsc->fsc->cap_wq, &mdsc->cap_unlink_work)) {
+                doutc(cl, "caps unlink work queued\n");
+        } else {
+                doutc(cl, "failed to queue caps unlink work\n");
+        }
+}
+
+static void ceph_cap_unlink_work(struct work_struct *work)
+{
+       struct ceph_mds_client *mdsc =
+               container_of(work, struct ceph_mds_client, cap_unlink_work);
+       struct ceph_client *cl = mdsc->fsc->client;
+
+       doutc(cl, "begin\n");
+       spin_lock(&mdsc->cap_unlink_delay_lock);
+       while (!list_empty(&mdsc->cap_unlink_delay_list)) {
+               struct ceph_inode_info *ci;
+               struct inode *inode;
+
+               ci = list_first_entry(&mdsc->cap_unlink_delay_list,
+                                     struct ceph_inode_info,
+                                     i_cap_delay_list);
+               list_del_init(&ci->i_cap_delay_list);
+
+               inode = igrab(&ci->netfs.inode);
+               if (inode) {
+                       spin_unlock(&mdsc->cap_unlink_delay_lock);
+                       doutc(cl, "on %p %llx.%llx\n", inode,
+                             ceph_vinop(inode));
+                       ceph_check_caps(ci, CHECK_CAPS_FLUSH);
+                       iput(inode);
+                       spin_lock(&mdsc->cap_unlink_delay_lock);
+               }
+       }
+       spin_unlock(&mdsc->cap_unlink_delay_lock);
+       doutc(cl, "done\n");
+}
+
 /*
  * requests
  */
@@ -5359,6 +5403,8 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        INIT_LIST_HEAD(&mdsc->cap_delay_list);
        INIT_LIST_HEAD(&mdsc->cap_wait_list);
        spin_lock_init(&mdsc->cap_delay_lock);
+       INIT_LIST_HEAD(&mdsc->cap_unlink_delay_list);
+       spin_lock_init(&mdsc->cap_unlink_delay_lock);
        INIT_LIST_HEAD(&mdsc->snap_flush_list);
        spin_lock_init(&mdsc->snap_flush_lock);
        mdsc->last_cap_flush_tid = 1;
@@ -5367,6 +5413,7 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        spin_lock_init(&mdsc->cap_dirty_lock);
        init_waitqueue_head(&mdsc->cap_flushing_wq);
        INIT_WORK(&mdsc->cap_reclaim_work, ceph_cap_reclaim_work);
+       INIT_WORK(&mdsc->cap_unlink_work, ceph_cap_unlink_work);
        err = ceph_metric_init(&mdsc->metric);
        if (err)
                goto err_mdsmap;
@@ -5640,6 +5687,7 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc)
        ceph_cleanup_global_and_empty_realms(mdsc);
 
        cancel_work_sync(&mdsc->cap_reclaim_work);
+       cancel_work_sync(&mdsc->cap_unlink_work);
        cancel_delayed_work_sync(&mdsc->delayed_work); /* cancel timer */
 
        doutc(cl, "done\n");
index 40560af3882720bd4bc90c1f728cd2ebeaaf3de9..03f8ff00874f727adff8b88cc8d538fc989692d8 100644 (file)
@@ -462,6 +462,8 @@ struct ceph_mds_client {
        unsigned long    last_renew_caps;  /* last time we renewed our caps */
        struct list_head cap_delay_list;   /* caps with delayed release */
        spinlock_t       cap_delay_lock;   /* protects cap_delay_list */
+       struct list_head cap_unlink_delay_list;  /* caps with delayed release for unlink */
+       spinlock_t       cap_unlink_delay_lock;  /* protects cap_unlink_delay_list */
        struct list_head snap_flush_list;  /* cap_snaps ready to flush */
        spinlock_t       snap_flush_lock;
 
@@ -475,6 +477,8 @@ struct ceph_mds_client {
        struct work_struct cap_reclaim_work;
        atomic_t           cap_reclaim_pending;
 
+       struct work_struct cap_unlink_work;
+
        /*
         * Cap reservations
         *
@@ -574,6 +578,7 @@ extern void ceph_flush_cap_releases(struct ceph_mds_client *mdsc,
                                    struct ceph_mds_session *session);
 extern void ceph_queue_cap_reclaim_work(struct ceph_mds_client *mdsc);
 extern void ceph_reclaim_caps_nr(struct ceph_mds_client *mdsc, int nr);
+extern void ceph_queue_cap_unlink_work(struct ceph_mds_client *mdsc);
 extern int ceph_iterate_session_caps(struct ceph_mds_session *session,
                                     int (*cb)(struct inode *, int mds, void *),
                                     void *arg);
index fae97c25ce58d5b268b7e3d73c5d4c94def4946d..8109aba66e023eb0d3dd5cdf06f3060c5cbf4b1a 100644 (file)
@@ -380,10 +380,11 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p,
                ceph_decode_skip_8(p, end, bad_ext);
                /* required_client_features */
                ceph_decode_skip_set(p, end, 64, bad_ext);
+               /* bal_rank_mask */
+               ceph_decode_skip_string(p, end, bad_ext);
+       }
+       if (mdsmap_ev >= 18) {
                ceph_decode_64_safe(p, end, m->m_max_xattr_size, bad_ext);
-       } else {
-               /* This forces the usage of the (sync) SETXATTR Op */
-               m->m_max_xattr_size = 0;
        }
 bad_ext:
        doutc(cl, "m_enabled: %d, m_damaged: %d, m_num_laggy: %d\n",
index 89f1931f1ba6c9643a4098b1255c240e00f0c38e..1f2171dd01bfa34a404eef00113646bdcb978980 100644 (file)
@@ -27,7 +27,11 @@ struct ceph_mdsmap {
        u32 m_session_timeout;          /* seconds */
        u32 m_session_autoclose;        /* seconds */
        u64 m_max_file_size;
-       u64 m_max_xattr_size;           /* maximum size for xattrs blob */
+       /*
+        * maximum size for xattrs blob.
+        * Zeroed by default to force the usage of the (sync) SETXATTR Op.
+        */
+       u64 m_max_xattr_size;
        u32 m_max_mds;                  /* expected up:active mds number */
        u32 m_num_active_mds;           /* actual up:active mds number */
        u32 possible_max_rank;          /* possible max rank index */
index 0c7c2528791ebc010acad4754b51fe3e9283901b..a50356c541f6c7bb61769ac7ef3122304226a2de 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/pid_namespace.h>
 #include <linux/uaccess.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
 #include <linux/vmalloc.h>
 
 #include <linux/coda.h>
@@ -87,10 +89,10 @@ void coda_destroy_inodecache(void)
        kmem_cache_destroy(coda_inode_cachep);
 }
 
-static int coda_remount(struct super_block *sb, int *flags, char *data)
+static int coda_reconfigure(struct fs_context *fc)
 {
-       sync_filesystem(sb);
-       *flags |= SB_NOATIME;
+       sync_filesystem(fc->root->d_sb);
+       fc->sb_flags |= SB_NOATIME;
        return 0;
 }
 
@@ -102,78 +104,102 @@ static const struct super_operations coda_super_operations =
        .evict_inode    = coda_evict_inode,
        .put_super      = coda_put_super,
        .statfs         = coda_statfs,
-       .remount_fs     = coda_remount,
 };
 
-static int get_device_index(struct coda_mount_data *data)
+struct coda_fs_context {
+       int     idx;
+};
+
+enum {
+       Opt_fd,
+};
+
+static const struct fs_parameter_spec coda_param_specs[] = {
+       fsparam_fd      ("fd",  Opt_fd),
+       {}
+};
+
+static int coda_parse_fd(struct fs_context *fc, int fd)
 {
+       struct coda_fs_context *ctx = fc->fs_private;
        struct fd f;
        struct inode *inode;
        int idx;
 
-       if (data == NULL) {
-               pr_warn("%s: Bad mount data\n", __func__);
-               return -1;
-       }
-
-       if (data->version != CODA_MOUNT_VERSION) {
-               pr_warn("%s: Bad mount version\n", __func__);
-               return -1;
-       }
-
-       f = fdget(data->fd);
+       f = fdget(fd);
        if (!f.file)
-               goto Ebadf;
+               return -EBADF;
        inode = file_inode(f.file);
        if (!S_ISCHR(inode->i_mode) || imajor(inode) != CODA_PSDEV_MAJOR) {
                fdput(f);
-               goto Ebadf;
+               return invalf(fc, "code: Not coda psdev");
        }
 
        idx = iminor(inode);
        fdput(f);
 
-       if (idx < 0 || idx >= MAX_CODADEVS) {
-               pr_warn("%s: Bad minor number\n", __func__);
-               return -1;
+       if (idx < 0 || idx >= MAX_CODADEVS)
+               return invalf(fc, "coda: Bad minor number");
+       ctx->idx = idx;
+       return 0;
+}
+
+static int coda_parse_param(struct fs_context *fc, struct fs_parameter *param)
+{
+       struct fs_parse_result result;
+       int opt;
+
+       opt = fs_parse(fc, coda_param_specs, param, &result);
+       if (opt < 0)
+               return opt;
+
+       switch (opt) {
+       case Opt_fd:
+               return coda_parse_fd(fc, result.uint_32);
        }
 
-       return idx;
-Ebadf:
-       pr_warn("%s: Bad file\n", __func__);
-       return -1;
+       return 0;
+}
+
+/*
+ * Parse coda's binary mount data form.  We ignore any errors and go with index
+ * 0 if we get one for backward compatibility.
+ */
+static int coda_parse_monolithic(struct fs_context *fc, void *_data)
+{
+       struct coda_mount_data *data = _data;
+
+       if (!data)
+               return invalf(fc, "coda: Bad mount data");
+
+       if (data->version != CODA_MOUNT_VERSION)
+               return invalf(fc, "coda: Bad mount version");
+
+       coda_parse_fd(fc, data->fd);
+       return 0;
 }
 
-static int coda_fill_super(struct super_block *sb, void *data, int silent)
+static int coda_fill_super(struct super_block *sb, struct fs_context *fc)
 {
+       struct coda_fs_context *ctx = fc->fs_private;
        struct inode *root = NULL;
        struct venus_comm *vc;
        struct CodaFid fid;
        int error;
-       int idx;
-
-       if (task_active_pid_ns(current) != &init_pid_ns)
-               return -EINVAL;
-
-       idx = get_device_index((struct coda_mount_data *) data);
 
-       /* Ignore errors in data, for backward compatibility */
-       if(idx == -1)
-               idx = 0;
-       
-       pr_info("%s: device index: %i\n", __func__,  idx);
+       infof(fc, "coda: device index: %i\n", ctx->idx);
 
-       vc = &coda_comms[idx];
+       vc = &coda_comms[ctx->idx];
        mutex_lock(&vc->vc_mutex);
 
        if (!vc->vc_inuse) {
-               pr_warn("%s: No pseudo device\n", __func__);
+               errorf(fc, "coda: No pseudo device");
                error = -EINVAL;
                goto unlock_out;
        }
 
        if (vc->vc_sb) {
-               pr_warn("%s: Device already mounted\n", __func__);
+               errorf(fc, "coda: Device already mounted");
                error = -EBUSY;
                goto unlock_out;
        }
@@ -313,18 +339,45 @@ static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0; 
 }
 
-/* init_coda: used by filesystems.c to register coda */
+static int coda_get_tree(struct fs_context *fc)
+{
+       if (task_active_pid_ns(current) != &init_pid_ns)
+               return -EINVAL;
 
-static struct dentry *coda_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
+       return get_tree_nodev(fc, coda_fill_super);
+}
+
+static void coda_free_fc(struct fs_context *fc)
 {
-       return mount_nodev(fs_type, flags, data, coda_fill_super);
+       kfree(fc->fs_private);
+}
+
+static const struct fs_context_operations coda_context_ops = {
+       .free           = coda_free_fc,
+       .parse_param    = coda_parse_param,
+       .parse_monolithic = coda_parse_monolithic,
+       .get_tree       = coda_get_tree,
+       .reconfigure    = coda_reconfigure,
+};
+
+static int coda_init_fs_context(struct fs_context *fc)
+{
+       struct coda_fs_context *ctx;
+
+       ctx = kzalloc(sizeof(struct coda_fs_context), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       fc->fs_private = ctx;
+       fc->ops = &coda_context_ops;
+       return 0;
 }
 
 struct file_system_type coda_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "coda",
-       .mount          = coda_mount,
+       .init_fs_context = coda_init_fs_context,
+       .parameters     = coda_param_specs,
        .kill_sb        = kill_anon_super,
        .fs_flags       = FS_BINARY_MOUNTDATA,
 };
index f258c17c18411284b9725ed88110de32fadc8993..be6403b4b14b6a26e611398f0903244d1af96343 100644 (file)
@@ -872,6 +872,9 @@ static int dump_emit_page(struct coredump_params *cprm, struct page *page)
        loff_t pos;
        ssize_t n;
 
+       if (!page)
+               return 0;
+
        if (cprm->to_skip) {
                if (!__dump_skip(cprm, cprm->to_skip))
                        return 0;
@@ -884,7 +887,6 @@ static int dump_emit_page(struct coredump_params *cprm, struct page *page)
        pos = file->f_pos;
        bvec_set_page(&bvec, page, PAGE_SIZE, 0);
        iov_iter_bvec(&iter, ITER_SOURCE, &bvec, 1, PAGE_SIZE);
-       iov_iter_set_copy_mc(&iter);
        n = __kernel_write_iter(cprm->file, &iter, &pos);
        if (n != PAGE_SIZE)
                return 0;
@@ -895,10 +897,44 @@ static int dump_emit_page(struct coredump_params *cprm, struct page *page)
        return 1;
 }
 
+/*
+ * If we might get machine checks from kernel accesses during the
+ * core dump, let's get those errors early rather than during the
+ * IO. This is not performance-critical enough to warrant having
+ * all the machine check logic in the iovec paths.
+ */
+#ifdef copy_mc_to_kernel
+
+#define dump_page_alloc() alloc_page(GFP_KERNEL)
+#define dump_page_free(x) __free_page(x)
+static struct page *dump_page_copy(struct page *src, struct page *dst)
+{
+       void *buf = kmap_local_page(src);
+       size_t left = copy_mc_to_kernel(page_address(dst), buf, PAGE_SIZE);
+       kunmap_local(buf);
+       return left ? NULL : dst;
+}
+
+#else
+
+/* We just want to return non-NULL; it's never used. */
+#define dump_page_alloc() ERR_PTR(-EINVAL)
+#define dump_page_free(x) ((void)(x))
+static inline struct page *dump_page_copy(struct page *src, struct page *dst)
+{
+       return src;
+}
+#endif
+
 int dump_user_range(struct coredump_params *cprm, unsigned long start,
                    unsigned long len)
 {
        unsigned long addr;
+       struct page *dump_page;
+
+       dump_page = dump_page_alloc();
+       if (!dump_page)
+               return 0;
 
        for (addr = start; addr < start + len; addr += PAGE_SIZE) {
                struct page *page;
@@ -912,14 +948,17 @@ int dump_user_range(struct coredump_params *cprm, unsigned long start,
                 */
                page = get_dump_page(addr);
                if (page) {
-                       int stop = !dump_emit_page(cprm, page);
+                       int stop = !dump_emit_page(cprm, dump_page_copy(page, dump_page));
                        put_page(page);
-                       if (stop)
+                       if (stop) {
+                               dump_page_free(dump_page);
                                return 0;
+                       }
                } else {
                        dump_skip(cprm, PAGE_SIZE);
                }
        }
+       dump_page_free(dump_page);
        return 1;
 }
 #endif
index 60dbfa0f880514d2bb5ce155a94109db5f34087f..39e75131fd5aa01d732f703cb1f421a3696bffd6 100644 (file)
@@ -495,7 +495,7 @@ static void cramfs_kill_sb(struct super_block *sb)
                sb->s_mtd = NULL;
        } else if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV) && sb->s_bdev) {
                sync_blockdev(sb->s_bdev);
-               bdev_release(sb->s_bdev_handle);
+               fput(sb->s_bdev_file);
        }
        kfree(sbi);
 }
index 7b3fc189593a5ac67d7e68b6cb8be55d57348cdc..0ad52fbe51c944eded295196a4cd27f91301571a 100644 (file)
@@ -74,13 +74,7 @@ struct fscrypt_nokey_name {
 
 static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
 {
-       if (str->len == 1 && str->name[0] == '.')
-               return true;
-
-       if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
-               return true;
-
-       return false;
+       return is_dot_dotdot(str->name, str->len);
 }
 
 /**
index 52504dd478d31b4b1cd2db9780970e867435f91c..104771c3d3f6ad968ef822c464edfbc7f1b52ca2 100644 (file)
@@ -102,11 +102,8 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,
        if (err && err != -ENOENT)
                return err;
 
-       if (fname->is_nokey_name) {
-               spin_lock(&dentry->d_lock);
-               dentry->d_flags |= DCACHE_NOKEY_NAME;
-               spin_unlock(&dentry->d_lock);
-       }
+       fscrypt_prepare_dentry(dentry, fname->is_nokey_name);
+
        return err;
 }
 EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
@@ -131,12 +128,10 @@ EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
 int fscrypt_prepare_lookup_partial(struct inode *dir, struct dentry *dentry)
 {
        int err = fscrypt_get_encryption_info(dir, true);
+       bool is_nokey_name = (!err && !fscrypt_has_encryption_key(dir));
+
+       fscrypt_prepare_dentry(dentry, is_nokey_name);
 
-       if (!err && !fscrypt_has_encryption_key(dir)) {
-               spin_lock(&dentry->d_lock);
-               dentry->d_flags |= DCACHE_NOKEY_NAME;
-               spin_unlock(&dentry->d_lock);
-       }
        return err;
 }
 EXPORT_SYMBOL_GPL(fscrypt_prepare_lookup_partial);
index b813528fb147784c6f308e67d47f3069e3a96e33..71a8e943a0fa506c93fd7f11400de9a5d7e23e01 100644 (file)
@@ -3061,7 +3061,10 @@ static enum d_walk_ret d_genocide_kill(void *data, struct dentry *dentry)
                if (d_unhashed(dentry) || !dentry->d_inode)
                        return D_WALK_SKIP;
 
-               dentry->d_lockref.count--;
+               if (!(dentry->d_flags & DCACHE_GENOCIDE)) {
+                       dentry->d_flags |= DCACHE_GENOCIDE;
+                       dentry->d_lockref.count--;
+               }
        }
        return D_WALK_CONTINUE;
 }
@@ -3136,7 +3139,7 @@ static void __init dcache_init(void)
         * of the dcache.
         */
        dentry_cache = KMEM_CACHE_USERCOPY(dentry,
-               SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD|SLAB_ACCOUNT,
+               SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_ACCOUNT,
                d_iname);
 
        /* Hash may have been set up in dcache_init_early */
index 60456263a338e018e6b4cb0f79ce26e0806ec4c9..62c97ff9e852a15b495b1bdb3790290dddc33515 100644 (file)
@@ -410,6 +410,8 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio,
                bio->bi_end_io = dio_bio_end_io;
        if (dio->is_pinned)
                bio_set_flag(bio, BIO_PAGE_PINNED);
+       bio->bi_write_hint = file_inode(dio->iocb->ki_filp)->i_write_hint;
+
        sdio->bio = bio;
        sdio->logical_offset_in_bio = sdio->cur_page_fs_offset;
 }
index d814c51213670bb8897701e30c01dc5b78ab6af9..9ca83ef70ed1e11ee2bc50920405603d2e047c71 100644 (file)
@@ -138,14 +138,14 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
        }
 
        op->info.optype         = DLM_PLOCK_OP_LOCK;
-       op->info.pid            = fl->fl_pid;
-       op->info.ex             = (fl->fl_type == F_WRLCK);
-       op->info.wait           = !!(fl->fl_flags & FL_SLEEP);
+       op->info.pid            = fl->c.flc_pid;
+       op->info.ex             = lock_is_write(fl);
+       op->info.wait           = !!(fl->c.flc_flags & FL_SLEEP);
        op->info.fsid           = ls->ls_global_id;
        op->info.number         = number;
        op->info.start          = fl->fl_start;
        op->info.end            = fl->fl_end;
-       op->info.owner = (__u64)(long)fl->fl_owner;
+       op->info.owner = (__u64)(long) fl->c.flc_owner;
        /* async handling */
        if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
                op_data = kzalloc(sizeof(*op_data), GFP_NOFS);
@@ -258,7 +258,7 @@ static int dlm_plock_callback(struct plock_op *op)
        }
 
        /* got fs lock; bookkeep locally as well: */
-       flc->fl_flags &= ~FL_SLEEP;
+       flc->c.flc_flags &= ~FL_SLEEP;
        if (posix_lock_file(file, flc, NULL)) {
                /*
                 * This can only happen in the case of kmalloc() failure.
@@ -291,7 +291,7 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
        struct dlm_ls *ls;
        struct plock_op *op;
        int rv;
-       unsigned char fl_flags = fl->fl_flags;
+       unsigned char saved_flags = fl->c.flc_flags;
 
        ls = dlm_find_lockspace_local(lockspace);
        if (!ls)
@@ -304,7 +304,7 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
        }
 
        /* cause the vfs unlock to return ENOENT if lock is not found */
-       fl->fl_flags |= FL_EXISTS;
+       fl->c.flc_flags |= FL_EXISTS;
 
        rv = locks_lock_file_wait(file, fl);
        if (rv == -ENOENT) {
@@ -317,14 +317,14 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
        }
 
        op->info.optype         = DLM_PLOCK_OP_UNLOCK;
-       op->info.pid            = fl->fl_pid;
+       op->info.pid            = fl->c.flc_pid;
        op->info.fsid           = ls->ls_global_id;
        op->info.number         = number;
        op->info.start          = fl->fl_start;
        op->info.end            = fl->fl_end;
-       op->info.owner = (__u64)(long)fl->fl_owner;
+       op->info.owner = (__u64)(long) fl->c.flc_owner;
 
-       if (fl->fl_flags & FL_CLOSE) {
+       if (fl->c.flc_flags & FL_CLOSE) {
                op->info.flags |= DLM_PLOCK_FL_CLOSE;
                send_op(op);
                rv = 0;
@@ -345,7 +345,7 @@ out_free:
        dlm_release_plock_op(op);
 out:
        dlm_put_lockspace(ls);
-       fl->fl_flags = fl_flags;
+       fl->c.flc_flags = saved_flags;
        return rv;
 }
 EXPORT_SYMBOL_GPL(dlm_posix_unlock);
@@ -375,14 +375,14 @@ int dlm_posix_cancel(dlm_lockspace_t *lockspace, u64 number, struct file *file,
                return -EINVAL;
 
        memset(&info, 0, sizeof(info));
-       info.pid = fl->fl_pid;
-       info.ex = (fl->fl_type == F_WRLCK);
+       info.pid = fl->c.flc_pid;
+       info.ex = lock_is_write(fl);
        info.fsid = ls->ls_global_id;
        dlm_put_lockspace(ls);
        info.number = number;
        info.start = fl->fl_start;
        info.end = fl->fl_end;
-       info.owner = (__u64)(long)fl->fl_owner;
+       info.owner = (__u64)(long) fl->c.flc_owner;
 
        rv = do_lock_cancel(&info);
        switch (rv) {
@@ -437,13 +437,13 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
        }
 
        op->info.optype         = DLM_PLOCK_OP_GET;
-       op->info.pid            = fl->fl_pid;
-       op->info.ex             = (fl->fl_type == F_WRLCK);
+       op->info.pid            = fl->c.flc_pid;
+       op->info.ex             = lock_is_write(fl);
        op->info.fsid           = ls->ls_global_id;
        op->info.number         = number;
        op->info.start          = fl->fl_start;
        op->info.end            = fl->fl_end;
-       op->info.owner = (__u64)(long)fl->fl_owner;
+       op->info.owner = (__u64)(long) fl->c.flc_owner;
 
        send_op(op);
        wait_event(recv_wq, (op->done != 0));
@@ -455,16 +455,16 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
 
        rv = op->info.rv;
 
-       fl->fl_type = F_UNLCK;
+       fl->c.flc_type = F_UNLCK;
        if (rv == -ENOENT)
                rv = 0;
        else if (rv > 0) {
                locks_init_lock(fl);
-               fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
-               fl->fl_flags = FL_POSIX;
-               fl->fl_pid = op->info.pid;
+               fl->c.flc_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
+               fl->c.flc_flags = FL_POSIX;
+               fl->c.flc_pid = op->info.pid;
                if (op->info.nodeid != dlm_our_nodeid())
-                       fl->fl_pid = -fl->fl_pid;
+                       fl->c.flc_pid = -fl->c.flc_pid;
                fl->fl_start = op->info.start;
                fl->fl_end = op->info.end;
                rv = 0;
index 03bd55069d8600bb5b838150e1a74da0fc1e4a1d..2fe0f3af1a08ec5831d2609862e0e9a80c9b0475 100644 (file)
@@ -1949,16 +1949,6 @@ out:
        return rc;
 }
 
-static bool is_dot_dotdot(const char *name, size_t name_size)
-{
-       if (name_size == 1 && name[0] == '.')
-               return true;
-       else if (name_size == 2 && name[0] == '.' && name[1] == '.')
-               return true;
-
-       return false;
-}
-
 /**
  * ecryptfs_decode_and_decrypt_filename - converts the encoded cipher text name to decoded plaintext
  * @plaintext_name: The plaintext name
index 169252e6dc4616c7712126adde4a36ce8e2d6922..f7206158ee81385eeaab387fd16b05aea5a7634b 100644 (file)
@@ -38,7 +38,7 @@ struct efivar_entry {
 
 int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *,
                            struct list_head *),
-               void *data, bool duplicates, struct list_head *head);
+               void *data, struct list_head *head);
 
 int efivar_entry_add(struct efivar_entry *entry, struct list_head *head);
 void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head);
index 6038dd39367abe41430c55b04448ced7727dd287..bb14462f6d992a5506f4fda2158952cb410c96f3 100644 (file)
@@ -343,12 +343,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
        if (err)
                return err;
 
-       err = efivar_init(efivarfs_callback, (void *)sb, true,
-                         &sfi->efivarfs_list);
-       if (err)
-               efivar_entry_iter(efivarfs_destroy, &sfi->efivarfs_list, NULL);
-
-       return err;
+       return efivar_init(efivarfs_callback, sb, &sfi->efivarfs_list);
 }
 
 static int efivarfs_get_tree(struct fs_context *fc)
index 114ff0fd4e55732e2ebe0cdc8b20d82436571abf..4d722af1014f2a18198cc3e831d1fea68d46e251 100644 (file)
@@ -361,7 +361,6 @@ static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid,
  * efivar_init - build the initial list of EFI variables
  * @func: callback function to invoke for every variable
  * @data: function-specific data to pass to @func
- * @duplicates: error if we encounter duplicates on @head?
  * @head: initialised head of variable list
  *
  * Get every EFI variable from the firmware and invoke @func. @func
@@ -371,9 +370,9 @@ static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid,
  */
 int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *,
                            struct list_head *),
-               void *data, bool duplicates, struct list_head *head)
+               void *data, struct list_head *head)
 {
-       unsigned long variable_name_size = 1024;
+       unsigned long variable_name_size = 512;
        efi_char16_t *variable_name;
        efi_status_t status;
        efi_guid_t vendor_guid;
@@ -390,12 +389,13 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *,
                goto free;
 
        /*
-        * Per EFI spec, the maximum storage allocated for both
-        * the variable name and variable data is 1024 bytes.
+        * A small set of old UEFI implementations reject sizes
+        * above a certain threshold, the lowest seen in the wild
+        * is 512.
         */
 
        do {
-               variable_name_size = 1024;
+               variable_name_size = 512;
 
                status = efivar_get_next_variable(&variable_name_size,
                                                  variable_name,
@@ -413,8 +413,7 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *,
                         * we'll ever see a different variable name,
                         * and may end up looping here forever.
                         */
-                       if (duplicates &&
-                           variable_is_present(variable_name, &vendor_guid,
+                       if (variable_is_present(variable_name, &vendor_guid,
                                                head)) {
                                dup_variable_bug(variable_name, &vendor_guid,
                                                 variable_name_size);
@@ -432,9 +431,13 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *,
                        break;
                case EFI_NOT_FOUND:
                        break;
+               case EFI_BUFFER_TOO_SMALL:
+                       pr_warn("efivars: Variable name size exceeds maximum (%lu > 512)\n",
+                               variable_name_size);
+                       status = EFI_NOT_FOUND;
+                       break;
                default:
-                       printk(KERN_WARNING "efivars: get_next_variable: status=%lx\n",
-                               status);
+                       pr_warn("efivars: get_next_variable: status=%lx\n", status);
                        status = EFI_NOT_FOUND;
                        break;
                }
index f17fdac76b2eea716631f63bce3ca2c66b14a2fc..e4421c10caebe5a5114cbcbe76c717272f6d14f6 100644 (file)
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
 #include <linux/blkdev.h>
-
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
 #include "efs.h"
 #include <linux/efs_vh.h>
 #include <linux/efs_fs_sb.h>
 
 static int efs_statfs(struct dentry *dentry, struct kstatfs *buf);
-static int efs_fill_super(struct super_block *s, void *d, int silent);
-
-static struct dentry *efs_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
-{
-       return mount_bdev(fs_type, flags, dev_name, data, efs_fill_super);
-}
+static int efs_init_fs_context(struct fs_context *fc);
 
 static void efs_kill_sb(struct super_block *s)
 {
@@ -35,15 +30,6 @@ static void efs_kill_sb(struct super_block *s)
        kfree(sbi);
 }
 
-static struct file_system_type efs_fs_type = {
-       .owner          = THIS_MODULE,
-       .name           = "efs",
-       .mount          = efs_mount,
-       .kill_sb        = efs_kill_sb,
-       .fs_flags       = FS_REQUIRES_DEV,
-};
-MODULE_ALIAS_FS("efs");
-
 static struct pt_types sgi_pt_types[] = {
        {0x00,          "SGI vh"},
        {0x01,          "SGI trkrepl"},
@@ -63,6 +49,27 @@ static struct pt_types sgi_pt_types[] = {
        {0,             NULL}
 };
 
+enum {
+       Opt_explicit_open,
+};
+
+static const struct fs_parameter_spec efs_param_spec[] = {
+       fsparam_flag    ("explicit-open",       Opt_explicit_open),
+       {}
+};
+
+/*
+ * File system definition and registration.
+ */
+static struct file_system_type efs_fs_type = {
+       .owner                  = THIS_MODULE,
+       .name                   = "efs",
+       .kill_sb                = efs_kill_sb,
+       .fs_flags               = FS_REQUIRES_DEV,
+       .init_fs_context        = efs_init_fs_context,
+       .parameters             = efs_param_spec,
+};
+MODULE_ALIAS_FS("efs");
 
 static struct kmem_cache * efs_inode_cachep;
 
@@ -91,8 +98,8 @@ static int __init init_inodecache(void)
 {
        efs_inode_cachep = kmem_cache_create("efs_inode_cache",
                                sizeof(struct efs_inode_info), 0,
-                               SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|
-                               SLAB_ACCOUNT, init_once);
+                               SLAB_RECLAIM_ACCOUNT|SLAB_ACCOUNT,
+                               init_once);
        if (efs_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
@@ -108,18 +115,10 @@ static void destroy_inodecache(void)
        kmem_cache_destroy(efs_inode_cachep);
 }
 
-static int efs_remount(struct super_block *sb, int *flags, char *data)
-{
-       sync_filesystem(sb);
-       *flags |= SB_RDONLY;
-       return 0;
-}
-
 static const struct super_operations efs_superblock_operations = {
        .alloc_inode    = efs_alloc_inode,
        .free_inode     = efs_free_inode,
        .statfs         = efs_statfs,
-       .remount_fs     = efs_remount,
 };
 
 static const struct export_operations efs_export_ops = {
@@ -249,26 +248,26 @@ static int efs_validate_super(struct efs_sb_info *sb, struct efs_super *super) {
        return 0;    
 }
 
-static int efs_fill_super(struct super_block *s, void *d, int silent)
+static int efs_fill_super(struct super_block *s, struct fs_context *fc)
 {
        struct efs_sb_info *sb;
        struct buffer_head *bh;
        struct inode *root;
 
-       sb = kzalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
+       sb = kzalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
        if (!sb)
                return -ENOMEM;
        s->s_fs_info = sb;
        s->s_time_min = 0;
        s->s_time_max = U32_MAX;
+
        s->s_magic              = EFS_SUPER_MAGIC;
        if (!sb_set_blocksize(s, EFS_BLOCKSIZE)) {
                pr_err("device does not support %d byte blocks\n",
                        EFS_BLOCKSIZE);
                return -EINVAL;
        }
-  
+
        /* read the vh (volume header) block */
        bh = sb_bread(s, 0);
 
@@ -294,7 +293,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
                pr_err("cannot read superblock\n");
                return -EIO;
        }
-               
+
        if (efs_validate_super(sb, (struct efs_super *) bh->b_data)) {
 #ifdef DEBUG
                pr_warn("invalid superblock at block %u\n",
@@ -328,6 +327,61 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
        return 0;
 }
 
+static void efs_free_fc(struct fs_context *fc)
+{
+       kfree(fc->fs_private);
+}
+
+static int efs_get_tree(struct fs_context *fc)
+{
+       return get_tree_bdev(fc, efs_fill_super);
+}
+
+static int efs_parse_param(struct fs_context *fc, struct fs_parameter *param)
+{
+       int token;
+       struct fs_parse_result result;
+
+       token = fs_parse(fc, efs_param_spec, param, &result);
+       if (token < 0)
+               return token;
+       return 0;
+}
+
+static int efs_reconfigure(struct fs_context *fc)
+{
+       sync_filesystem(fc->root->d_sb);
+
+       return 0;
+}
+
+struct efs_context {
+       unsigned long s_mount_opts;
+};
+
+static const struct fs_context_operations efs_context_opts = {
+       .parse_param    = efs_parse_param,
+       .get_tree       = efs_get_tree,
+       .reconfigure    = efs_reconfigure,
+       .free           = efs_free_fc,
+};
+
+/*
+ * Set up the filesystem mount context.
+ */
+static int efs_init_fs_context(struct fs_context *fc)
+{
+       struct efs_context *ctx;
+
+       ctx = kzalloc(sizeof(struct efs_context), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+       fc->fs_private = ctx;
+       fc->ops = &efs_context_opts;
+
+       return 0;
+}
+
 static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
        struct super_block *sb = dentry->d_sb;
        struct efs_sb_info *sbi = SUPER_INFO(sb);
index c98aeda8abb215e9be577d1b27dea2713b0b6e87..52524bd9698b43591e767cd0e45fc3c807375c58 100644 (file)
@@ -220,7 +220,7 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)
                        up_read(&devs->rwsem);
                        return 0;
                }
-               map->m_bdev = dif->bdev_handle ? dif->bdev_handle->bdev : NULL;
+               map->m_bdev = dif->bdev_file ? file_bdev(dif->bdev_file) : NULL;
                map->m_daxdev = dif->dax_dev;
                map->m_dax_part_off = dif->dax_part_off;
                map->m_fscache = dif->fscache;
@@ -238,8 +238,8 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)
                        if (map->m_pa >= startoff &&
                            map->m_pa < startoff + length) {
                                map->m_pa -= startoff;
-                               map->m_bdev = dif->bdev_handle ?
-                                             dif->bdev_handle->bdev : NULL;
+                               map->m_bdev = dif->bdev_file ?
+                                             file_bdev(dif->bdev_file) : NULL;
                                map->m_daxdev = dif->dax_dev;
                                map->m_dax_part_off = dif->dax_part_off;
                                map->m_fscache = dif->fscache;
@@ -447,5 +447,6 @@ const struct file_operations erofs_file_fops = {
        .llseek         = generic_file_llseek,
        .read_iter      = erofs_file_read_iter,
        .mmap           = erofs_file_mmap,
+       .get_unmapped_area = thp_get_unmapped_area,
        .splice_read    = filemap_splice_read,
 };
index d4cee95af14c7490e85706589853059b99b7e688..2ec9b2bb628d6b03bdf454c3fc6457b4065aabc8 100644 (file)
@@ -323,7 +323,8 @@ static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
        unsigned int cur = 0, ni = 0, no, pi, po, insz, cnt;
        u8 *kin;
 
-       DBG_BUGON(rq->outputsize > rq->inputsize);
+       if (rq->outputsize > rq->inputsize)
+               return -EOPNOTSUPP;
        if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) {
                cur = bs - (rq->pageofs_out & (bs - 1));
                pi = (rq->pageofs_in + rq->inputsize - cur) & ~PAGE_MASK;
index 5ff90026fd43fe116e3a34178bf00b9f3303b411..89a7c2453aae6f130e679af1459673397d581842 100644 (file)
@@ -381,11 +381,12 @@ static int erofs_fscache_init_domain(struct super_block *sb)
                goto out;
 
        if (!erofs_pseudo_mnt) {
-               erofs_pseudo_mnt = kern_mount(&erofs_fs_type);
-               if (IS_ERR(erofs_pseudo_mnt)) {
-                       err = PTR_ERR(erofs_pseudo_mnt);
+               struct vfsmount *mnt = kern_mount(&erofs_fs_type);
+               if (IS_ERR(mnt)) {
+                       err = PTR_ERR(mnt);
                        goto out;
                }
+               erofs_pseudo_mnt = mnt;
        }
 
        domain->volume = sbi->volume;
index b0409badb0172387f8b96c03f69267da5403b68d..0f0706325b7b4753f93c515ec423f35466e5224d 100644 (file)
@@ -49,7 +49,7 @@ typedef u32 erofs_blk_t;
 struct erofs_device_info {
        char *path;
        struct erofs_fscache *fscache;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct dax_device *dax_dev;
        u64 dax_part_off;
 
index d4f631d39f0fa83141eafcb13951bb3fd36598bd..f0110a78acb2078aa2ce6eae13e39481e46b7ea9 100644 (file)
@@ -130,24 +130,24 @@ static void *erofs_find_target_block(struct erofs_buf *target,
                        /* string comparison without already matched prefix */
                        diff = erofs_dirnamecmp(name, &dname, &matched);
 
-                       if (!diff) {
-                               *_ndirents = 0;
-                               goto out;
-                       } else if (diff > 0) {
-                               head = mid + 1;
-                               startprfx = matched;
-
-                               if (!IS_ERR(candidate))
-                                       erofs_put_metabuf(target);
-                               *target = buf;
-                               candidate = de;
-                               *_ndirents = ndirents;
-                       } else {
+                       if (diff < 0) {
                                erofs_put_metabuf(&buf);
-
                                back = mid - 1;
                                endprfx = matched;
+                               continue;
+                       }
+
+                       if (!IS_ERR(candidate))
+                               erofs_put_metabuf(target);
+                       *target = buf;
+                       if (!diff) {
+                               *_ndirents = 0;
+                               return de;
                        }
+                       head = mid + 1;
+                       startprfx = matched;
+                       candidate = de;
+                       *_ndirents = ndirents;
                        continue;
                }
 out:           /* free if the candidate is valid */
index 5f60f163bd56e272d167399ddac9a95de42b1b34..9b4b66dcdd4f10d5f8338c398e394b6601941818 100644 (file)
@@ -177,7 +177,7 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
        struct erofs_sb_info *sbi = EROFS_SB(sb);
        struct erofs_fscache *fscache;
        struct erofs_deviceslot *dis;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        void *ptr;
 
        ptr = erofs_read_metabuf(buf, sb, erofs_blknr(sb, *pos), EROFS_KMAP);
@@ -201,12 +201,12 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
                        return PTR_ERR(fscache);
                dif->fscache = fscache;
        } else if (!sbi->devs->flatdev) {
-               bdev_handle = bdev_open_by_path(dif->path, BLK_OPEN_READ,
+               bdev_file = bdev_file_open_by_path(dif->path, BLK_OPEN_READ,
                                                sb->s_type, NULL);
-               if (IS_ERR(bdev_handle))
-                       return PTR_ERR(bdev_handle);
-               dif->bdev_handle = bdev_handle;
-               dif->dax_dev = fs_dax_get_by_bdev(bdev_handle->bdev,
+               if (IS_ERR(bdev_file))
+                       return PTR_ERR(bdev_file);
+               dif->bdev_file = bdev_file;
+               dif->dax_dev = fs_dax_get_by_bdev(file_bdev(bdev_file),
                                &dif->dax_part_off, NULL, NULL);
        }
 
@@ -754,8 +754,8 @@ static int erofs_release_device_info(int id, void *ptr, void *data)
        struct erofs_device_info *dif = ptr;
 
        fs_put_dax(dif->dax_dev, NULL);
-       if (dif->bdev_handle)
-               bdev_release(dif->bdev_handle);
+       if (dif->bdev_file)
+               fput(dif->bdev_file);
        erofs_fscache_unregister_cookie(dif->fscache);
        dif->fscache = NULL;
        kfree(dif->path);
index ad8186d47ba76062f1540835c9a5a0a64f560cd5..9afdb722fa9257f4f0dfac12146a229933c11441 100644 (file)
@@ -251,7 +251,7 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c
        ssize_t res;
        __u64 ucnt;
 
-       if (count < sizeof(ucnt))
+       if (count != sizeof(ucnt))
                return -EINVAL;
        if (copy_from_user(&ucnt, buf, sizeof(ucnt)))
                return -EFAULT;
@@ -283,13 +283,18 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c
 static void eventfd_show_fdinfo(struct seq_file *m, struct file *f)
 {
        struct eventfd_ctx *ctx = f->private_data;
+       __u64 cnt;
 
        spin_lock_irq(&ctx->wqh.lock);
-       seq_printf(m, "eventfd-count: %16llx\n",
-                  (unsigned long long)ctx->count);
+       cnt = ctx->count;
        spin_unlock_irq(&ctx->wqh.lock);
-       seq_printf(m, "eventfd-id: %d\n", ctx->id);
-       seq_printf(m, "eventfd-semaphore: %d\n",
+
+       seq_printf(m,
+                  "eventfd-count: %16llx\n"
+                  "eventfd-id: %d\n"
+                  "eventfd-semaphore: %d\n",
+                  cnt,
+                  ctx->id,
                   !!(ctx->flags & EFD_SEMAPHORE));
 }
 #endif
@@ -383,6 +388,7 @@ static int do_eventfd(unsigned int count, int flags)
        /* Check the EFD_* constants for consistency.  */
        BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC);
        BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK);
+       BUILD_BUG_ON(EFD_SEMAPHORE != (1 << 0));
 
        if (flags & ~EFD_FLAGS_SET)
                return -EINVAL;
index 3534d36a147400079bfd618d198e47fe669aee5f..39ac6fdf8bcab38533b3c2f4e5b4bb97ed3432fa 100644 (file)
@@ -206,7 +206,7 @@ struct eventpoll {
         */
        struct epitem *ovflist;
 
-       /* wakeup_source used when ep_scan_ready_list is running */
+       /* wakeup_source used when ep_send_events or __ep_eventpoll_poll is running */
        struct wakeup_source *ws;
 
        /* The user that created the eventpoll descriptor */
@@ -678,12 +678,6 @@ static void ep_done_scan(struct eventpoll *ep,
        write_unlock_irq(&ep->lock);
 }
 
-static void epi_rcu_free(struct rcu_head *head)
-{
-       struct epitem *epi = container_of(head, struct epitem, rcu);
-       kmem_cache_free(epi_cache, epi);
-}
-
 static void ep_get(struct eventpoll *ep)
 {
        refcount_inc(&ep->refcount);
@@ -767,7 +761,7 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
         * ep->mtx. The rcu read side, reverse_path_check_proc(), does not make
         * use of the rbn field.
         */
-       call_rcu(&epi->rcu, epi_rcu_free);
+       kfree_rcu(epi, rcu);
 
        percpu_counter_dec(&ep->user->epoll_watches);
        return ep_refcount_dec_and_test(ep);
@@ -1153,7 +1147,7 @@ static inline bool chain_epi_lockless(struct epitem *epi)
  * This callback takes a read lock in order not to contend with concurrent
  * events from another file descriptor, thus all modifications to ->rdllist
  * or ->ovflist are lockless.  Read lock is paired with the write lock from
- * ep_scan_ready_list(), which stops all list modifications and guarantees
+ * ep_start/done_scan(), which stops all list modifications and guarantees
  * that lists state is seen correctly.
  *
  * Another thing worth to mention is that ep_poll_callback() can be called
@@ -1751,7 +1745,7 @@ static int ep_send_events(struct eventpoll *ep,
                         * availability. At this point, no one can insert
                         * into ep->rdllist besides us. The epoll_ctl()
                         * callers are locked out by
-                        * ep_scan_ready_list() holding "mtx" and the
+                        * ep_send_events() holding "mtx" and the
                         * poll callback will queue them in ep->ovflist.
                         */
                        list_add_tail(&epi->rdllink, &ep->rdllist);
@@ -1904,7 +1898,7 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
                __set_current_state(TASK_INTERRUPTIBLE);
 
                /*
-                * Do the final check under the lock. ep_scan_ready_list()
+                * Do the final check under the lock. ep_start/done_scan()
                 * plays with two lists (->rdllist and ->ovflist) and there
                 * is always a race when both lists are empty for short
                 * period of time although events are pending, so lock is
index af4fbb61cd53e97c788387a0d8277d1ce5495d7d..ece3ab0998e11ee3fb6f0e13d7766ae2c50b2968 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1158,7 +1158,6 @@ static int de_thread(struct task_struct *tsk)
 
                BUG_ON(leader->exit_state != EXIT_ZOMBIE);
                leader->exit_state = EXIT_DEAD;
-
                /*
                 * We are going to release_task()->ptrace_unlink() silently,
                 * the tracer can sleep in do_wait(). EXIT_DEAD guarantees
index 9474cd50da6d4fd8b9fba92f1f3d8717f19245dc..361595433480c46562765ad4d5c886a071005c25 100644 (file)
@@ -275,6 +275,7 @@ struct exfat_sb_info {
 
        spinlock_t inode_hash_lock;
        struct hlist_head inode_hashtable[EXFAT_HASH_SIZE];
+       struct rcu_head rcu;
 };
 
 #define EXFAT_CACHE_VALID      0
index d25a96a148af4cdb966c5d20f720aa944cab10c2..cc00f1a7a1e18082af9e0e8ff28f5995de75f1ba 100644 (file)
@@ -35,13 +35,18 @@ static int exfat_cont_expand(struct inode *inode, loff_t size)
        if (new_num_clusters == num_clusters)
                goto out;
 
-       exfat_chain_set(&clu, ei->start_clu, num_clusters, ei->flags);
-       ret = exfat_find_last_cluster(sb, &clu, &last_clu);
-       if (ret)
-               return ret;
+       if (num_clusters) {
+               exfat_chain_set(&clu, ei->start_clu, num_clusters, ei->flags);
+               ret = exfat_find_last_cluster(sb, &clu, &last_clu);
+               if (ret)
+                       return ret;
+
+               clu.dir = last_clu + 1;
+       } else {
+               last_clu = EXFAT_EOF_CLUSTER;
+               clu.dir = EXFAT_EOF_CLUSTER;
+       }
 
-       clu.dir = (last_clu == EXFAT_EOF_CLUSTER) ?
-                       EXFAT_EOF_CLUSTER : last_clu + 1;
        clu.size = 0;
        clu.flags = ei->flags;
 
@@ -51,17 +56,19 @@ static int exfat_cont_expand(struct inode *inode, loff_t size)
                return ret;
 
        /* Append new clusters to chain */
-       if (clu.flags != ei->flags) {
-               exfat_chain_cont_cluster(sb, ei->start_clu, num_clusters);
-               ei->flags = ALLOC_FAT_CHAIN;
-       }
-       if (clu.flags == ALLOC_FAT_CHAIN)
-               if (exfat_ent_set(sb, last_clu, clu.dir))
-                       goto free_clu;
-
-       if (num_clusters == 0)
+       if (num_clusters) {
+               if (clu.flags != ei->flags)
+                       if (exfat_chain_cont_cluster(sb, ei->start_clu, num_clusters))
+                               goto free_clu;
+
+               if (clu.flags == ALLOC_FAT_CHAIN)
+                       if (exfat_ent_set(sb, last_clu, clu.dir))
+                               goto free_clu;
+       } else
                ei->start_clu = clu.dir;
 
+       ei->flags = clu.flags;
+
 out:
        inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
        /* Expanded range not zeroed, do not update valid_size */
index 705710f93e2ddd3c911df119b2c8e0ca5a9152cd..afdf13c34ff526fb423f322d3503b571e2d153e8 100644 (file)
@@ -655,7 +655,6 @@ static int exfat_load_upcase_table(struct super_block *sb,
        unsigned int sect_size = sb->s_blocksize;
        unsigned int i, index = 0;
        u32 chksum = 0;
-       int ret;
        unsigned char skip = false;
        unsigned short *upcase_table;
 
@@ -673,8 +672,7 @@ static int exfat_load_upcase_table(struct super_block *sb,
                if (!bh) {
                        exfat_err(sb, "failed to read sector(0x%llx)",
                                  (unsigned long long)sector);
-                       ret = -EIO;
-                       goto free_table;
+                       return -EIO;
                }
                sector++;
                for (i = 0; i < sect_size && index <= 0xFFFF; i += 2) {
@@ -701,15 +699,12 @@ static int exfat_load_upcase_table(struct super_block *sb,
 
        exfat_err(sb, "failed to load upcase table (idx : 0x%08x, chksum : 0x%08x, utbl_chksum : 0x%08x)",
                  index, chksum, utbl_checksum);
-       ret = -EINVAL;
-free_table:
-       exfat_free_upcase_table(sbi);
-       return ret;
+       return -EINVAL;
 }
 
 static int exfat_load_default_upcase_table(struct super_block *sb)
 {
-       int i, ret = -EIO;
+       int i;
        struct exfat_sb_info *sbi = EXFAT_SB(sb);
        unsigned char skip = false;
        unsigned short uni = 0, *upcase_table;
@@ -740,8 +735,7 @@ static int exfat_load_default_upcase_table(struct super_block *sb)
                return 0;
 
        /* FATAL error: default upcase table has error */
-       exfat_free_upcase_table(sbi);
-       return ret;
+       return -EIO;
 }
 
 int exfat_create_upcase_table(struct super_block *sb)
index d9d4fa91010bb1d226b1d00afdbb841e73911d33..fcb6582677650bd1462e501e9c5bb67a032befd4 100644 (file)
@@ -39,9 +39,6 @@ static void exfat_put_super(struct super_block *sb)
        exfat_free_bitmap(sbi);
        brelse(sbi->boot_bh);
        mutex_unlock(&sbi->s_lock);
-
-       unload_nls(sbi->nls_io);
-       exfat_free_upcase_table(sbi);
 }
 
 static int exfat_sync_fs(struct super_block *sb, int wait)
@@ -600,7 +597,7 @@ static int __exfat_fill_super(struct super_block *sb)
        ret = exfat_load_bitmap(sb);
        if (ret) {
                exfat_err(sb, "failed to load alloc-bitmap");
-               goto free_upcase_table;
+               goto free_bh;
        }
 
        ret = exfat_count_used_clusters(sb, &sbi->used_clusters);
@@ -613,8 +610,6 @@ static int __exfat_fill_super(struct super_block *sb)
 
 free_alloc_bitmap:
        exfat_free_bitmap(sbi);
-free_upcase_table:
-       exfat_free_upcase_table(sbi);
 free_bh:
        brelse(sbi->boot_bh);
        return ret;
@@ -701,12 +696,10 @@ put_inode:
        sb->s_root = NULL;
 
 free_table:
-       exfat_free_upcase_table(sbi);
        exfat_free_bitmap(sbi);
        brelse(sbi->boot_bh);
 
 check_nls_io:
-       unload_nls(sbi->nls_io);
        return err;
 }
 
@@ -771,13 +764,22 @@ static int exfat_init_fs_context(struct fs_context *fc)
        return 0;
 }
 
+static void delayed_free(struct rcu_head *p)
+{
+       struct exfat_sb_info *sbi = container_of(p, struct exfat_sb_info, rcu);
+
+       unload_nls(sbi->nls_io);
+       exfat_free_upcase_table(sbi);
+       exfat_free_sbi(sbi);
+}
+
 static void exfat_kill_sb(struct super_block *sb)
 {
        struct exfat_sb_info *sbi = sb->s_fs_info;
 
        kill_block_super(sb);
        if (sbi)
-               exfat_free_sbi(sbi);
+               call_rcu(&sbi->rcu, delayed_free);
 }
 
 static struct file_system_type exfat_fs_type = {
index 3ae0154c5680b2c06771a3819d825a1953aa707f..07ea3d62b2982d308439cd9c4008b0c7113df5fa 100644 (file)
@@ -255,7 +255,7 @@ static bool filldir_one(struct dir_context *ctx, const char *name, int len,
                container_of(ctx, struct getdents_callback, ctx);
 
        buf->sequence++;
-       if (buf->ino == ino && len <= NAME_MAX) {
+       if (buf->ino == ino && len <= NAME_MAX && !is_dot_dotdot(name, len)) {
                memcpy(buf->name, name, len);
                buf->name[len] = '\0';
                buf->found = 1;
index 023571f8dd1b43887b691c4dd61742d07ac1b356..3c0d7d143036abd34867604cd9c89a4a2a3151d4 100644 (file)
@@ -1550,7 +1550,7 @@ struct ext4_sb_info {
        unsigned long s_commit_interval;
        u32 s_max_batch_time;
        u32 s_min_batch_time;
-       struct bdev_handle *s_journal_bdev_handle;
+       struct file *s_journal_bdev_file;
 #ifdef CONFIG_QUOTA
        /* Names of quota files with journalled quota */
        char __rcu *s_qf_names[EXT4_MAXQUOTAS];
index 11e6f33677a2c8566cbb7fc230f42e514a1c726c..df853c4d3a8c91b8ee8e7f07bb5853362067cb25 100644 (file)
@@ -576,9 +576,9 @@ static bool ext4_getfsmap_is_valid_device(struct super_block *sb,
        if (fm->fmr_device == 0 || fm->fmr_device == UINT_MAX ||
            fm->fmr_device == new_encode_dev(sb->s_bdev->bd_dev))
                return true;
-       if (EXT4_SB(sb)->s_journal_bdev_handle &&
+       if (EXT4_SB(sb)->s_journal_bdev_file &&
            fm->fmr_device ==
-           new_encode_dev(EXT4_SB(sb)->s_journal_bdev_handle->bdev->bd_dev))
+           new_encode_dev(file_bdev(EXT4_SB(sb)->s_journal_bdev_file)->bd_dev))
                return true;
        return false;
 }
@@ -648,9 +648,9 @@ int ext4_getfsmap(struct super_block *sb, struct ext4_fsmap_head *head,
        memset(handlers, 0, sizeof(handlers));
        handlers[0].gfd_dev = new_encode_dev(sb->s_bdev->bd_dev);
        handlers[0].gfd_fn = ext4_getfsmap_datadev;
-       if (EXT4_SB(sb)->s_journal_bdev_handle) {
+       if (EXT4_SB(sb)->s_journal_bdev_file) {
                handlers[1].gfd_dev = new_encode_dev(
-                       EXT4_SB(sb)->s_journal_bdev_handle->bdev->bd_dev);
+                       file_bdev(EXT4_SB(sb)->s_journal_bdev_file)->bd_dev);
                handlers[1].gfd_fn = ext4_getfsmap_logdev;
        }
 
index 05b647e6bc19547a117214b17226d97420887ce6..5e4f65c14dfb9e2d508f259fd2bb7013b7da38a8 100644 (file)
@@ -1762,7 +1762,6 @@ static struct buffer_head *ext4_lookup_entry(struct inode *dir,
        struct buffer_head *bh;
 
        err = ext4_fname_prepare_lookup(dir, dentry, &fname);
-       generic_set_encrypted_ci_d_ops(dentry);
        if (err == -ENOENT)
                return NULL;
        if (err)
index 0f931d0c227daa8b00950667d8b8bb42a7a28a48..a8ba84eabab2c28df962174ba2b752c3cd928676 100644 (file)
@@ -1359,14 +1359,14 @@ static void ext4_put_super(struct super_block *sb)
 
        sync_blockdev(sb->s_bdev);
        invalidate_bdev(sb->s_bdev);
-       if (sbi->s_journal_bdev_handle) {
+       if (sbi->s_journal_bdev_file) {
                /*
                 * Invalidate the journal device's buffers.  We don't want them
                 * floating about in memory - the physical journal device may
                 * hotswapped, and it breaks the `ro-after' testing code.
                 */
-               sync_blockdev(sbi->s_journal_bdev_handle->bdev);
-               invalidate_bdev(sbi->s_journal_bdev_handle->bdev);
+               sync_blockdev(file_bdev(sbi->s_journal_bdev_file));
+               invalidate_bdev(file_bdev(sbi->s_journal_bdev_file));
        }
 
        ext4_xattr_destroy_cache(sbi->s_ea_inode_cache);
@@ -4233,7 +4233,7 @@ int ext4_calculate_overhead(struct super_block *sb)
         * Add the internal journal blocks whether the journal has been
         * loaded or not
         */
-       if (sbi->s_journal && !sbi->s_journal_bdev_handle)
+       if (sbi->s_journal && !sbi->s_journal_bdev_file)
                overhead += EXT4_NUM_B2C(sbi, sbi->s_journal->j_total_len);
        else if (ext4_has_feature_journal(sb) && !sbi->s_journal && j_inum) {
                /* j_inum for internal journal is non-zero */
@@ -5346,7 +5346,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
                sb->s_qcop = &ext4_qctl_operations;
        sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
 #endif
-       memcpy(&sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
+       super_set_uuid(sb, es->s_uuid, sizeof(es->s_uuid));
 
        INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
        mutex_init(&sbi->s_orphan_lock);
@@ -5484,6 +5484,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
                goto failed_mount4;
        }
 
+       generic_set_sb_d_ops(sb);
        sb->s_root = d_make_root(root);
        if (!sb->s_root) {
                ext4_msg(sb, KERN_ERR, "get root dentry failed");
@@ -5670,9 +5671,9 @@ failed_mount:
 #endif
        fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
        brelse(sbi->s_sbh);
-       if (sbi->s_journal_bdev_handle) {
-               invalidate_bdev(sbi->s_journal_bdev_handle->bdev);
-               bdev_release(sbi->s_journal_bdev_handle);
+       if (sbi->s_journal_bdev_file) {
+               invalidate_bdev(file_bdev(sbi->s_journal_bdev_file));
+               fput(sbi->s_journal_bdev_file);
        }
 out_fail:
        invalidate_bdev(sb->s_bdev);
@@ -5842,30 +5843,30 @@ static journal_t *ext4_open_inode_journal(struct super_block *sb,
        return journal;
 }
 
-static struct bdev_handle *ext4_get_journal_blkdev(struct super_block *sb,
+static struct file *ext4_get_journal_blkdev(struct super_block *sb,
                                        dev_t j_dev, ext4_fsblk_t *j_start,
                                        ext4_fsblk_t *j_len)
 {
        struct buffer_head *bh;
        struct block_device *bdev;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        int hblock, blocksize;
        ext4_fsblk_t sb_block;
        unsigned long offset;
        struct ext4_super_block *es;
        int errno;
 
-       bdev_handle = bdev_open_by_dev(j_dev,
+       bdev_file = bdev_file_open_by_dev(j_dev,
                BLK_OPEN_READ | BLK_OPEN_WRITE | BLK_OPEN_RESTRICT_WRITES,
                sb, &fs_holder_ops);
-       if (IS_ERR(bdev_handle)) {
+       if (IS_ERR(bdev_file)) {
                ext4_msg(sb, KERN_ERR,
                         "failed to open journal device unknown-block(%u,%u) %ld",
-                        MAJOR(j_dev), MINOR(j_dev), PTR_ERR(bdev_handle));
-               return bdev_handle;
+                        MAJOR(j_dev), MINOR(j_dev), PTR_ERR(bdev_file));
+               return bdev_file;
        }
 
-       bdev = bdev_handle->bdev;
+       bdev = file_bdev(bdev_file);
        blocksize = sb->s_blocksize;
        hblock = bdev_logical_block_size(bdev);
        if (blocksize < hblock) {
@@ -5912,12 +5913,12 @@ static struct bdev_handle *ext4_get_journal_blkdev(struct super_block *sb,
        *j_start = sb_block + 1;
        *j_len = ext4_blocks_count(es);
        brelse(bh);
-       return bdev_handle;
+       return bdev_file;
 
 out_bh:
        brelse(bh);
 out_bdev:
-       bdev_release(bdev_handle);
+       fput(bdev_file);
        return ERR_PTR(errno);
 }
 
@@ -5927,14 +5928,14 @@ static journal_t *ext4_open_dev_journal(struct super_block *sb,
        journal_t *journal;
        ext4_fsblk_t j_start;
        ext4_fsblk_t j_len;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        int errno = 0;
 
-       bdev_handle = ext4_get_journal_blkdev(sb, j_dev, &j_start, &j_len);
-       if (IS_ERR(bdev_handle))
-               return ERR_CAST(bdev_handle);
+       bdev_file = ext4_get_journal_blkdev(sb, j_dev, &j_start, &j_len);
+       if (IS_ERR(bdev_file))
+               return ERR_CAST(bdev_file);
 
-       journal = jbd2_journal_init_dev(bdev_handle->bdev, sb->s_bdev, j_start,
+       journal = jbd2_journal_init_dev(file_bdev(bdev_file), sb->s_bdev, j_start,
                                        j_len, sb->s_blocksize);
        if (IS_ERR(journal)) {
                ext4_msg(sb, KERN_ERR, "failed to create device journal");
@@ -5949,14 +5950,14 @@ static journal_t *ext4_open_dev_journal(struct super_block *sb,
                goto out_journal;
        }
        journal->j_private = sb;
-       EXT4_SB(sb)->s_journal_bdev_handle = bdev_handle;
+       EXT4_SB(sb)->s_journal_bdev_file = bdev_file;
        ext4_init_journal_params(sb, journal);
        return journal;
 
 out_journal:
        jbd2_journal_destroy(journal);
 out_bdev:
-       bdev_release(bdev_handle);
+       fput(bdev_file);
        return ERR_PTR(errno);
 }
 
@@ -7314,12 +7315,12 @@ static inline int ext3_feature_set_ok(struct super_block *sb)
 static void ext4_kill_sb(struct super_block *sb)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct bdev_handle *handle = sbi ? sbi->s_journal_bdev_handle : NULL;
+       struct file *bdev_file = sbi ? sbi->s_journal_bdev_file : NULL;
 
        kill_block_super(sb);
 
-       if (handle)
-               bdev_release(handle);
+       if (bdev_file)
+               fput(bdev_file);
 }
 
 static struct file_system_type ext4_fs_type = {
index 75bf1f88843c4ce96c285423228a70ff77c08517..645240cc0229fe4a2eda4499ae4a834fe3bd3a66 100644 (file)
@@ -92,10 +92,12 @@ static const char *ext4_get_link(struct dentry *dentry, struct inode *inode,
 
        if (!dentry) {
                bh = ext4_getblk(NULL, inode, 0, EXT4_GET_BLOCKS_CACHED_NOWAIT);
-               if (IS_ERR(bh))
-                       return ERR_CAST(bh);
-               if (!bh || !ext4_buffer_uptodate(bh))
+               if (IS_ERR(bh) || !bh)
                        return ERR_PTR(-ECHILD);
+               if (!ext4_buffer_uptodate(bh)) {
+                       brelse(bh);
+                       return ERR_PTR(-ECHILD);
+               }
        } else {
                bh = ext4_bread(NULL, inode, 0, 0);
                if (IS_ERR(bh))
index 65294e3b0bef880a424c480ba4f4997b23c6b59c..4c77e8ce5c7514461831d4c02e9c42a136aec3c1 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/blkdev.h>
 #include <linux/quotaops.h>
 #include <linux/part_stat.h>
+#include <linux/rw_hint.h>
 #include <crypto/hash.h>
 
 #include <linux/fscrypt.h>
@@ -1239,7 +1240,7 @@ struct f2fs_bio_info {
 #define FDEV(i)                                (sbi->devs[i])
 #define RDEV(i)                                (raw_super->devs[i])
 struct f2fs_dev_info {
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct block_device *bdev;
        char path[MAX_PATH_LEN];
        unsigned int total_segments;
@@ -3364,17 +3365,6 @@ static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi)
        return is_set_ckpt_flags(sbi, CP_ERROR_FLAG);
 }
 
-static inline bool is_dot_dotdot(const u8 *name, size_t len)
-{
-       if (len == 1 && name[0] == '.')
-               return true;
-
-       if (len == 2 && name[0] == '.' && name[1] == '.')
-               return true;
-
-       return false;
-}
-
 static inline void *f2fs_kmalloc(struct f2fs_sb_info *sbi,
                                        size_t size, gfp_t flags)
 {
index b3bb815fc6aa45b957b89da9feae04bad9f0a9a8..f7f63a567d869d66e024b0334a06e1cc83c8b6f4 100644 (file)
@@ -531,7 +531,6 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
        }
 
        err = f2fs_prepare_lookup(dir, dentry, &fname);
-       generic_set_encrypted_ci_d_ops(dentry);
        if (err == -ENOENT)
                goto out_splice;
        if (err)
index 4c8836ded90fc253a593a8348fb8ab78cf9eab40..e1065ba702076131067091fe173b19edab41b5d1 100644 (file)
@@ -1971,9 +1971,15 @@ static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi,
                }
 
                if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) {
+                       unsigned int nofs_flags;
+                       int ret;
+
                        trace_f2fs_issue_reset_zone(bdev, blkstart);
-                       return blkdev_zone_mgmt(bdev, REQ_OP_ZONE_RESET,
-                                               sector, nr_sects, GFP_NOFS);
+                       nofs_flags = memalloc_nofs_save();
+                       ret = blkdev_zone_mgmt(bdev, REQ_OP_ZONE_RESET,
+                                               sector, nr_sects);
+                       memalloc_nofs_restore(nofs_flags);
+                       return ret;
                }
 
                __queue_zone_reset_cmd(sbi, bdev, blkstart, lblkstart, blklen);
@@ -4865,6 +4871,7 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi,
        block_t zone_block, valid_block_cnt;
        unsigned int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT;
        int ret;
+       unsigned int nofs_flags;
 
        if (zone->type != BLK_ZONE_TYPE_SEQWRITE_REQ)
                return 0;
@@ -4912,8 +4919,10 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi,
                    "pointer: valid block[0x%x,0x%x] cond[0x%x]",
                    zone_segno, valid_block_cnt, zone->cond);
 
+       nofs_flags = memalloc_nofs_save();
        ret = blkdev_zone_mgmt(fdev->bdev, REQ_OP_ZONE_FINISH,
-                               zone->start, zone->len, GFP_NOFS);
+                               zone->start, zone->len);
+       memalloc_nofs_restore(nofs_flags);
        if (ret == -EOPNOTSUPP) {
                ret = blkdev_issue_zeroout(fdev->bdev, zone->wp,
                                        zone->len - (zone->wp - zone->start),
index d45ab0992ae5947e6f89628e8e8829c548645d26..b880b746f2263f72868f27b7f43247637f068950 100644 (file)
@@ -1605,7 +1605,7 @@ static void destroy_device_list(struct f2fs_sb_info *sbi)
 
        for (i = 0; i < sbi->s_ndevs; i++) {
                if (i > 0)
-                       bdev_release(FDEV(i).bdev_handle);
+                       fput(FDEV(i).bdev_file);
 #ifdef CONFIG_BLK_DEV_ZONED
                kvfree(FDEV(i).blkz_seq);
 #endif
@@ -4247,7 +4247,7 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
 
        for (i = 0; i < max_devices; i++) {
                if (i == 0)
-                       FDEV(0).bdev_handle = sbi->sb->s_bdev_handle;
+                       FDEV(0).bdev_file = sbi->sb->s_bdev_file;
                else if (!RDEV(i).path[0])
                        break;
 
@@ -4267,14 +4267,14 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
                                FDEV(i).end_blk = FDEV(i).start_blk +
                                        (FDEV(i).total_segments <<
                                        sbi->log_blocks_per_seg) - 1;
-                               FDEV(i).bdev_handle = bdev_open_by_path(
+                               FDEV(i).bdev_file = bdev_file_open_by_path(
                                        FDEV(i).path, mode, sbi->sb, NULL);
                        }
                }
-               if (IS_ERR(FDEV(i).bdev_handle))
-                       return PTR_ERR(FDEV(i).bdev_handle);
+               if (IS_ERR(FDEV(i).bdev_file))
+                       return PTR_ERR(FDEV(i).bdev_file);
 
-               FDEV(i).bdev = FDEV(i).bdev_handle->bdev;
+               FDEV(i).bdev = file_bdev(FDEV(i).bdev_file);
                /* to release errored devices */
                sbi->s_ndevs = i + 1;
 
@@ -4496,7 +4496,7 @@ try_onemore:
        sb->s_time_gran = 1;
        sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
                (test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0);
-       memcpy(&sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid));
+       super_set_uuid(sb, (void *) raw_super->uuid, sizeof(raw_super->uuid));
        sb->s_iflags |= SB_I_CGROUPWB;
 
        /* init f2fs-specific super block info */
@@ -4660,6 +4660,7 @@ try_onemore:
                goto free_node_inode;
        }
 
+       generic_set_sb_d_ops(sb);
        sb->s_root = d_make_root(root); /* allocate root dentry */
        if (!sb->s_root) {
                err = -ENOMEM;
index 1fac3dabf13031fdf02e257f363d451190721a9e..5c813696d1ff282220ee5a28b1173d0eb02aaa25 100644 (file)
@@ -1762,6 +1762,9 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
        else /* fat 16 or 12 */
                sbi->vol_id = bpb.fat16_vol_id;
 
+       __le32 vol_id_le = cpu_to_le32(sbi->vol_id);
+       super_set_uuid(sb, (void *) &vol_id_le, sizeof(vol_id_le));
+
        sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry);
        sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
 
index c80a6acad742fb027a4a990f63ef05d0678736d7..54cc85d3338ed5afb12021e02a4fe6877aa675af 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/memfd.h>
 #include <linux/compat.h>
 #include <linux/mount.h>
+#include <linux/rw_hint.h>
 
 #include <linux/poll.h>
 #include <asm/siginfo.h>
@@ -268,8 +269,15 @@ static int f_getowner_uids(struct file *filp, unsigned long arg)
 }
 #endif
 
-static bool rw_hint_valid(enum rw_hint hint)
+static bool rw_hint_valid(u64 hint)
 {
+       BUILD_BUG_ON(WRITE_LIFE_NOT_SET != RWH_WRITE_LIFE_NOT_SET);
+       BUILD_BUG_ON(WRITE_LIFE_NONE != RWH_WRITE_LIFE_NONE);
+       BUILD_BUG_ON(WRITE_LIFE_SHORT != RWH_WRITE_LIFE_SHORT);
+       BUILD_BUG_ON(WRITE_LIFE_MEDIUM != RWH_WRITE_LIFE_MEDIUM);
+       BUILD_BUG_ON(WRITE_LIFE_LONG != RWH_WRITE_LIFE_LONG);
+       BUILD_BUG_ON(WRITE_LIFE_EXTREME != RWH_WRITE_LIFE_EXTREME);
+
        switch (hint) {
        case RWH_WRITE_LIFE_NOT_SET:
        case RWH_WRITE_LIFE_NONE:
@@ -283,34 +291,40 @@ static bool rw_hint_valid(enum rw_hint hint)
        }
 }
 
-static long fcntl_rw_hint(struct file *file, unsigned int cmd,
-                         unsigned long arg)
+static long fcntl_get_rw_hint(struct file *file, unsigned int cmd,
+                             unsigned long arg)
 {
        struct inode *inode = file_inode(file);
        u64 __user *argp = (u64 __user *)arg;
-       enum rw_hint hint;
-       u64 h;
+       u64 hint = READ_ONCE(inode->i_write_hint);
 
-       switch (cmd) {
-       case F_GET_RW_HINT:
-               h = inode->i_write_hint;
-               if (copy_to_user(argp, &h, sizeof(*argp)))
-                       return -EFAULT;
-               return 0;
-       case F_SET_RW_HINT:
-               if (copy_from_user(&h, argp, sizeof(h)))
-                       return -EFAULT;
-               hint = (enum rw_hint) h;
-               if (!rw_hint_valid(hint))
-                       return -EINVAL;
+       if (copy_to_user(argp, &hint, sizeof(*argp)))
+               return -EFAULT;
+       return 0;
+}
 
-               inode_lock(inode);
-               inode->i_write_hint = hint;
-               inode_unlock(inode);
-               return 0;
-       default:
+static long fcntl_set_rw_hint(struct file *file, unsigned int cmd,
+                             unsigned long arg)
+{
+       struct inode *inode = file_inode(file);
+       u64 __user *argp = (u64 __user *)arg;
+       u64 hint;
+
+       if (copy_from_user(&hint, argp, sizeof(hint)))
+               return -EFAULT;
+       if (!rw_hint_valid(hint))
                return -EINVAL;
-       }
+
+       WRITE_ONCE(inode->i_write_hint, hint);
+
+       /*
+        * file->f_mapping->host may differ from inode. As an example,
+        * blkdev_open() modifies file->f_mapping.
+        */
+       if (file->f_mapping->host != inode)
+               WRITE_ONCE(file->f_mapping->host->i_write_hint, hint);
+
+       return 0;
 }
 
 static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
@@ -416,8 +430,10 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
                err = memfd_fcntl(filp, cmd, argi);
                break;
        case F_GET_RW_HINT:
+               err = fcntl_get_rw_hint(filp, cmd, arg);
+               break;
        case F_SET_RW_HINT:
-               err = fcntl_rw_hint(filp, cmd, arg);
+               err = fcntl_set_rw_hint(filp, cmd, arg);
                break;
        default:
                break;
@@ -846,12 +862,6 @@ int send_sigurg(struct fown_struct *fown)
 static DEFINE_SPINLOCK(fasync_lock);
 static struct kmem_cache *fasync_cache __ro_after_init;
 
-static void fasync_free_rcu(struct rcu_head *head)
-{
-       kmem_cache_free(fasync_cache,
-                       container_of(head, struct fasync_struct, fa_rcu));
-}
-
 /*
  * Remove a fasync entry. If successfully removed, return
  * positive and clear the FASYNC flag. If no entry exists,
@@ -877,7 +887,7 @@ int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
                write_unlock_irq(&fa->fa_lock);
 
                *fp = fa->fa_next;
-               call_rcu(&fa->fa_rcu, fasync_free_rcu);
+               kfree_rcu(fa, fa_rcu);
                filp->f_flags &= ~FASYNC;
                result = 1;
                break;
index 18b3ba8dc8ead7c6016a1f76d96275268b0667f0..57a12614addfd434f981a5b8c981a48ae1a71ceb 100644 (file)
@@ -36,7 +36,7 @@ static long do_sys_name_to_handle(const struct path *path,
        if (f_handle.handle_bytes > MAX_HANDLE_SZ)
                return -EINVAL;
 
-       handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
+       handle = kzalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
                         GFP_KERNEL);
        if (!handle)
                return -ENOMEM;
index b991f90571b4d3089a0c00884fea3e38f317b1da..6925522faa0ae53cb9105eaaed56c6a7fcdb305a 100644 (file)
@@ -276,21 +276,15 @@ struct file *alloc_empty_backing_file(int flags, const struct cred *cred)
 }
 
 /**
- * alloc_file - allocate and initialize a 'struct file'
+ * file_init_path - initialize a 'struct file' based on path
  *
+ * @file: the file to set up
  * @path: the (dentry, vfsmount) pair for the new file
- * @flags: O_... flags with which the new file will be opened
  * @fop: the 'struct file_operations' for the new file
  */
-static struct file *alloc_file(const struct path *path, int flags,
-               const struct file_operations *fop)
+static void file_init_path(struct file *file, const struct path *path,
+                          const struct file_operations *fop)
 {
-       struct file *file;
-
-       file = alloc_empty_file(flags, current_cred());
-       if (IS_ERR(file))
-               return file;
-
        file->f_path = *path;
        file->f_inode = path->dentry->d_inode;
        file->f_mapping = path->dentry->d_inode->i_mapping;
@@ -309,22 +303,51 @@ static struct file *alloc_file(const struct path *path, int flags,
        file->f_op = fop;
        if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
                i_readcount_inc(path->dentry->d_inode);
+}
+
+/**
+ * alloc_file - allocate and initialize a 'struct file'
+ *
+ * @path: the (dentry, vfsmount) pair for the new file
+ * @flags: O_... flags with which the new file will be opened
+ * @fop: the 'struct file_operations' for the new file
+ */
+static struct file *alloc_file(const struct path *path, int flags,
+               const struct file_operations *fop)
+{
+       struct file *file;
+
+       file = alloc_empty_file(flags, current_cred());
+       if (!IS_ERR(file))
+               file_init_path(file, path, fop);
        return file;
 }
 
-struct file *alloc_file_pseudo(struct inode *inode, struct vfsmount *mnt,
-                               const char *name, int flags,
-                               const struct file_operations *fops)
+static inline int alloc_path_pseudo(const char *name, struct inode *inode,
+                                   struct vfsmount *mnt, struct path *path)
 {
        struct qstr this = QSTR_INIT(name, strlen(name));
+
+       path->dentry = d_alloc_pseudo(mnt->mnt_sb, &this);
+       if (!path->dentry)
+               return -ENOMEM;
+       path->mnt = mntget(mnt);
+       d_instantiate(path->dentry, inode);
+       return 0;
+}
+
+struct file *alloc_file_pseudo(struct inode *inode, struct vfsmount *mnt,
+                              const char *name, int flags,
+                              const struct file_operations *fops)
+{
+       int ret;
        struct path path;
        struct file *file;
 
-       path.dentry = d_alloc_pseudo(mnt->mnt_sb, &this);
-       if (!path.dentry)
-               return ERR_PTR(-ENOMEM);
-       path.mnt = mntget(mnt);
-       d_instantiate(path.dentry, inode);
+       ret = alloc_path_pseudo(name, inode, mnt, &path);
+       if (ret)
+               return ERR_PTR(ret);
+
        file = alloc_file(&path, flags, fops);
        if (IS_ERR(file)) {
                ihold(inode);
@@ -334,6 +357,30 @@ struct file *alloc_file_pseudo(struct inode *inode, struct vfsmount *mnt,
 }
 EXPORT_SYMBOL(alloc_file_pseudo);
 
+struct file *alloc_file_pseudo_noaccount(struct inode *inode,
+                                        struct vfsmount *mnt, const char *name,
+                                        int flags,
+                                        const struct file_operations *fops)
+{
+       int ret;
+       struct path path;
+       struct file *file;
+
+       ret = alloc_path_pseudo(name, inode, mnt, &path);
+       if (ret)
+               return ERR_PTR(ret);
+
+       file = alloc_empty_file_noaccount(flags, current_cred());
+       if (IS_ERR(file)) {
+               ihold(inode);
+               path_put(&path);
+               return file;
+       }
+       file_init_path(file, &path, fops);
+       return file;
+}
+EXPORT_SYMBOL_GPL(alloc_file_pseudo_noaccount);
+
 struct file *alloc_file_clone(struct file *base, int flags,
                                const struct file_operations *fops)
 {
index 3d84fcc471c6000e38625e2652121282e4bec3c0..e4f17c53ddfcf345bda9961f239be00a98a528f4 100644 (file)
@@ -141,6 +141,31 @@ static void wb_wakeup(struct bdi_writeback *wb)
        spin_unlock_irq(&wb->work_lock);
 }
 
+/*
+ * This function is used when the first inode for this wb is marked dirty. It
+ * wakes-up the corresponding bdi thread which should then take care of the
+ * periodic background write-out of dirty inodes. Since the write-out would
+ * starts only 'dirty_writeback_interval' centisecs from now anyway, we just
+ * set up a timer which wakes the bdi thread up later.
+ *
+ * Note, we wouldn't bother setting up the timer, but this function is on the
+ * fast-path (used by '__mark_inode_dirty()'), so we save few context switches
+ * by delaying the wake-up.
+ *
+ * We have to be careful not to postpone flush work if it is scheduled for
+ * earlier. Thus we use queue_delayed_work().
+ */
+static void wb_wakeup_delayed(struct bdi_writeback *wb)
+{
+       unsigned long timeout;
+
+       timeout = msecs_to_jiffies(dirty_writeback_interval * 10);
+       spin_lock_irq(&wb->work_lock);
+       if (test_bit(WB_registered, &wb->state))
+               queue_delayed_work(bdi_wq, &wb->dwork, timeout);
+       spin_unlock_irq(&wb->work_lock);
+}
+
 static void finish_writeback_work(struct bdi_writeback *wb,
                                  struct wb_writeback_work *work)
 {
index edb3712dcfa5805aa60364bd0c794c257ae04734..a4d6ca0b8971e65b1e3b832d591ac01bad10f8d8 100644 (file)
@@ -83,8 +83,8 @@ static const struct fs_parameter_spec *fs_lookup_key(
 }
 
 /*
- * fs_parse - Parse a filesystem configuration parameter
- * @fc: The filesystem context to log errors through.
+ * __fs_parse - Parse a filesystem configuration parameter
+ * @log: The filesystem context to log errors through.
  * @desc: The parameter description to use.
  * @param: The parameter.
  * @result: Where to place the result of the parse
index 91e89e68177ee4bd686a920b9dfad4978d8d5062..b6cad106c37e44258bd6e4433cd4aaedfbb98f65 100644 (file)
@@ -474,8 +474,7 @@ err:
 
 static void cuse_fc_release(struct fuse_conn *fc)
 {
-       struct cuse_conn *cc = fc_to_cc(fc);
-       kfree_rcu(cc, fc.rcu);
+       kfree(fc_to_cc(fc));
 }
 
 /**
index 148a71b8b4d0e51037b6b59c754dabb9d3273173..c007b0f0c3a7e73bf222eab2928fc86d544aa692 100644 (file)
@@ -2509,14 +2509,14 @@ static int convert_fuse_file_lock(struct fuse_conn *fc,
                 * translate it into the caller's pid namespace.
                 */
                rcu_read_lock();
-               fl->fl_pid = pid_nr_ns(find_pid_ns(ffl->pid, fc->pid_ns), &init_pid_ns);
+               fl->c.flc_pid = pid_nr_ns(find_pid_ns(ffl->pid, fc->pid_ns), &init_pid_ns);
                rcu_read_unlock();
                break;
 
        default:
                return -EIO;
        }
-       fl->fl_type = ffl->type;
+       fl->c.flc_type = ffl->type;
        return 0;
 }
 
@@ -2530,10 +2530,10 @@ static void fuse_lk_fill(struct fuse_args *args, struct file *file,
 
        memset(inarg, 0, sizeof(*inarg));
        inarg->fh = ff->fh;
-       inarg->owner = fuse_lock_owner_id(fc, fl->fl_owner);
+       inarg->owner = fuse_lock_owner_id(fc, fl->c.flc_owner);
        inarg->lk.start = fl->fl_start;
        inarg->lk.end = fl->fl_end;
-       inarg->lk.type = fl->fl_type;
+       inarg->lk.type = fl->c.flc_type;
        inarg->lk.pid = pid;
        if (flock)
                inarg->lk_flags |= FUSE_LK_FLOCK;
@@ -2570,8 +2570,8 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock)
        struct fuse_mount *fm = get_fuse_mount(inode);
        FUSE_ARGS(args);
        struct fuse_lk_in inarg;
-       int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
-       struct pid *pid = fl->fl_type != F_UNLCK ? task_tgid(current) : NULL;
+       int opcode = (fl->c.flc_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
+       struct pid *pid = fl->c.flc_type != F_UNLCK ? task_tgid(current) : NULL;
        pid_t pid_nr = pid_nr_ns(pid, fm->fc->pid_ns);
        int err;
 
@@ -2581,7 +2581,7 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock)
        }
 
        /* Unlock on close is handled by the flush method */
-       if ((fl->fl_flags & FL_CLOSE_POSIX) == FL_CLOSE_POSIX)
+       if ((fl->c.flc_flags & FL_CLOSE_POSIX) == FL_CLOSE_POSIX)
                return 0;
 
        fuse_lk_fill(&args, file, fl, opcode, pid_nr, flock, &inarg);
index 1df83eebda92771d20a42ea2aaefa118effcbc77..bcbe34488862752154ca2284386baacadf972744 100644 (file)
@@ -888,6 +888,7 @@ struct fuse_mount {
 
        /* Entry on fc->mounts */
        struct list_head fc_entry;
+       struct rcu_head rcu;
 };
 
 static inline struct fuse_mount *get_fuse_mount_super(struct super_block *sb)
index 2a6d44f91729bbd7e3bf1c955a952ecdd695bd0f..516ea2979a90ff2d0eff63a71dc6b8edc4c91b98 100644 (file)
@@ -930,6 +930,14 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
 }
 EXPORT_SYMBOL_GPL(fuse_conn_init);
 
+static void delayed_release(struct rcu_head *p)
+{
+       struct fuse_conn *fc = container_of(p, struct fuse_conn, rcu);
+
+       put_user_ns(fc->user_ns);
+       fc->release(fc);
+}
+
 void fuse_conn_put(struct fuse_conn *fc)
 {
        if (refcount_dec_and_test(&fc->count)) {
@@ -941,13 +949,12 @@ void fuse_conn_put(struct fuse_conn *fc)
                if (fiq->ops->release)
                        fiq->ops->release(fiq);
                put_pid_ns(fc->pid_ns);
-               put_user_ns(fc->user_ns);
                bucket = rcu_dereference_protected(fc->curr_bucket, 1);
                if (bucket) {
                        WARN_ON(atomic_read(&bucket->count) != 1);
                        kfree(bucket);
                }
-               fc->release(fc);
+               call_rcu(&fc->rcu, delayed_release);
        }
 }
 EXPORT_SYMBOL_GPL(fuse_conn_put);
@@ -1366,7 +1373,7 @@ EXPORT_SYMBOL_GPL(fuse_send_init);
 void fuse_free_conn(struct fuse_conn *fc)
 {
        WARN_ON(!list_empty(&fc->devices));
-       kfree_rcu(fc, rcu);
+       kfree(fc);
 }
 EXPORT_SYMBOL_GPL(fuse_free_conn);
 
@@ -1902,7 +1909,7 @@ static void fuse_sb_destroy(struct super_block *sb)
 void fuse_mount_destroy(struct fuse_mount *fm)
 {
        fuse_conn_put(fm->fc);
-       kfree(fm);
+       kfree_rcu(fm, rcu);
 }
 EXPORT_SYMBOL(fuse_mount_destroy);
 
index d9ccfd27e4f11fe4ecc7ce36981cbef469942847..789af5c8fade9d86354f86a6a7ffe696a9f5447d 100644 (file)
@@ -2465,7 +2465,7 @@ out:
 }
 
 static int gfs2_map_blocks(struct iomap_writepage_ctx *wpc, struct inode *inode,
-               loff_t offset)
+               loff_t offset, unsigned int len)
 {
        int ret;
 
index 992ca4effb505ec2936a403ea31fac4391cba76e..4c42ada60ae7a4b2fabbfd17ae1508a3f5d82a39 100644 (file)
@@ -1440,10 +1440,10 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
        struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
 
-       if (!(fl->fl_flags & FL_POSIX))
+       if (!(fl->c.flc_flags & FL_POSIX))
                return -ENOLCK;
        if (gfs2_withdrawing_or_withdrawn(sdp)) {
-               if (fl->fl_type == F_UNLCK)
+               if (lock_is_unlock(fl))
                        locks_lock_file_wait(file, fl);
                return -EIO;
        }
@@ -1451,7 +1451,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
                return dlm_posix_cancel(ls->ls_dlm, ip->i_no_addr, file, fl);
        else if (IS_GETLK(cmd))
                return dlm_posix_get(ls->ls_dlm, ip->i_no_addr, file, fl);
-       else if (fl->fl_type == F_UNLCK)
+       else if (lock_is_unlock(fl))
                return dlm_posix_unlock(ls->ls_dlm, ip->i_no_addr, file, fl);
        else
                return dlm_posix_lock(ls->ls_dlm, ip->i_no_addr, file, cmd, fl);
@@ -1483,7 +1483,7 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl)
        int error = 0;
        int sleeptime;
 
-       state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED;
+       state = lock_is_write(fl) ? LM_ST_EXCLUSIVE : LM_ST_SHARED;
        flags = GL_EXACT | GL_NOPID;
        if (!IS_SETLKW(cmd))
                flags |= LM_FLAG_TRY_1CB;
@@ -1495,8 +1495,8 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl)
                if (fl_gh->gh_state == state)
                        goto out;
                locks_init_lock(&request);
-               request.fl_type = F_UNLCK;
-               request.fl_flags = FL_FLOCK;
+               request.c.flc_type = F_UNLCK;
+               request.c.flc_flags = FL_FLOCK;
                locks_lock_file_wait(file, &request);
                gfs2_glock_dq(fl_gh);
                gfs2_holder_reinit(state, flags, fl_gh);
@@ -1557,10 +1557,10 @@ static void do_unflock(struct file *file, struct file_lock *fl)
 
 static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
 {
-       if (!(fl->fl_flags & FL_FLOCK))
+       if (!(fl->c.flc_flags & FL_FLOCK))
                return -ENOLCK;
 
-       if (fl->fl_type == F_UNLCK) {
+       if (lock_is_unlock(fl)) {
                do_unflock(file, fl);
                return 0;
        } else {
index 1281e60be63900764f8c6c97973e057e02897a12..572d58e86296f9117a4e476075eaacdef52394f7 100644 (file)
@@ -214,7 +214,7 @@ static void gfs2_sb_in(struct gfs2_sbd *sdp, const void *buf)
 
        memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN);
        memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN);
-       memcpy(&s->s_uuid, str->sb_uuid, 16);
+       super_set_uuid(s, str->sb_uuid, 16);
 }
 
 /**
index 7ededcb720c121794eb3782dd84ccff74685296b..012a3d003fbe6162db231058a647cb07f78ef0a9 100644 (file)
@@ -190,6 +190,7 @@ struct hfsplus_sb_info {
        int work_queued;               /* non-zero delayed work is queued */
        struct delayed_work sync_work; /* FS sync delayed work */
        spinlock_t work_lock;          /* protects sync_work and work_queued */
+       struct rcu_head rcu;
 };
 
 #define HFSPLUS_SB_WRITEBACKUP 0
index 1986b4f18a9013ee27f056b7c871df215f05f862..97920202790f944f0d03dda35cc1a83f27201470 100644 (file)
@@ -277,6 +277,14 @@ void hfsplus_mark_mdb_dirty(struct super_block *sb)
        spin_unlock(&sbi->work_lock);
 }
 
+static void delayed_free(struct rcu_head *p)
+{
+       struct hfsplus_sb_info *sbi = container_of(p, struct hfsplus_sb_info, rcu);
+
+       unload_nls(sbi->nls);
+       kfree(sbi);
+}
+
 static void hfsplus_put_super(struct super_block *sb)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
@@ -302,9 +310,7 @@ static void hfsplus_put_super(struct super_block *sb)
        hfs_btree_close(sbi->ext_tree);
        kfree(sbi->s_vhdr_buf);
        kfree(sbi->s_backup_vhdr_buf);
-       unload_nls(sbi->nls);
-       kfree(sb->s_fs_info);
-       sb->s_fs_info = NULL;
+       call_rcu(&sbi->rcu, delayed_free);
 }
 
 static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
index b0cb704009963c73d1021acdd70f65b01cab9911..ce9346099c72dc89b15a24d7be67a076923ebfcc 100644 (file)
@@ -30,7 +30,7 @@ struct hfsplus_wd {
  * @sector: block to read or write, for blocks of HFSPLUS_SECTOR_SIZE bytes
  * @buf: buffer for I/O
  * @data: output pointer for location of requested data
- * @opf: request op flags
+ * @opf: I/O operation type and flags
  *
  * The unit of I/O is hfsplus_min_io_size(sb), which may be bigger than
  * HFSPLUS_SECTOR_SIZE, and @buf must be sized accordingly. On reads
index d746866ae3b6ba79a4ed1d8b6600c29cfc28e005..6502c7e776d195e1d004908964f74ce5a76d6db2 100644 (file)
@@ -933,7 +933,7 @@ static int hugetlbfs_setattr(struct mnt_idmap *idmap,
        unsigned int ia_valid = attr->ia_valid;
        struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode);
 
-       error = setattr_prepare(&nop_mnt_idmap, dentry, attr);
+       error = setattr_prepare(idmap, dentry, attr);
        if (error)
                return error;
 
@@ -950,7 +950,7 @@ static int hugetlbfs_setattr(struct mnt_idmap *idmap,
                hugetlb_vmtruncate(inode, newsize);
        }
 
-       setattr_copy(&nop_mnt_idmap, inode, attr);
+       setattr_copy(idmap, inode, attr);
        mark_inode_dirty(inode);
        return 0;
 }
@@ -985,6 +985,7 @@ static struct inode *hugetlbfs_get_root(struct super_block *sb,
 static struct lock_class_key hugetlbfs_i_mmap_rwsem_key;
 
 static struct inode *hugetlbfs_get_inode(struct super_block *sb,
+                                       struct mnt_idmap *idmap,
                                        struct inode *dir,
                                        umode_t mode, dev_t dev)
 {
@@ -1006,7 +1007,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
                struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode);
 
                inode->i_ino = get_next_ino();
-               inode_init_owner(&nop_mnt_idmap, inode, dir, mode);
+               inode_init_owner(idmap, inode, dir, mode);
                lockdep_set_class(&inode->i_mapping->i_mmap_rwsem,
                                &hugetlbfs_i_mmap_rwsem_key);
                inode->i_mapping->a_ops = &hugetlbfs_aops;
@@ -1050,7 +1051,7 @@ static int hugetlbfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
 {
        struct inode *inode;
 
-       inode = hugetlbfs_get_inode(dir->i_sb, dir, mode, dev);
+       inode = hugetlbfs_get_inode(dir->i_sb, idmap, dir, mode, dev);
        if (!inode)
                return -ENOSPC;
        inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
@@ -1062,7 +1063,7 @@ static int hugetlbfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
 static int hugetlbfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
                           struct dentry *dentry, umode_t mode)
 {
-       int retval = hugetlbfs_mknod(&nop_mnt_idmap, dir, dentry,
+       int retval = hugetlbfs_mknod(idmap, dir, dentry,
                                     mode | S_IFDIR, 0);
        if (!retval)
                inc_nlink(dir);
@@ -1073,7 +1074,7 @@ static int hugetlbfs_create(struct mnt_idmap *idmap,
                            struct inode *dir, struct dentry *dentry,
                            umode_t mode, bool excl)
 {
-       return hugetlbfs_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFREG, 0);
+       return hugetlbfs_mknod(idmap, dir, dentry, mode | S_IFREG, 0);
 }
 
 static int hugetlbfs_tmpfile(struct mnt_idmap *idmap,
@@ -1082,7 +1083,7 @@ static int hugetlbfs_tmpfile(struct mnt_idmap *idmap,
 {
        struct inode *inode;
 
-       inode = hugetlbfs_get_inode(dir->i_sb, dir, mode | S_IFREG, 0);
+       inode = hugetlbfs_get_inode(dir->i_sb, idmap, dir, mode | S_IFREG, 0);
        if (!inode)
                return -ENOSPC;
        inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
@@ -1094,10 +1095,11 @@ static int hugetlbfs_symlink(struct mnt_idmap *idmap,
                             struct inode *dir, struct dentry *dentry,
                             const char *symname)
 {
+       const umode_t mode = S_IFLNK|S_IRWXUGO;
        struct inode *inode;
        int error = -ENOSPC;
 
-       inode = hugetlbfs_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0);
+       inode = hugetlbfs_get_inode(dir->i_sb, idmap, dir, mode, 0);
        if (inode) {
                int l = strlen(symname)+1;
                error = page_symlink(inode, symname, l);
@@ -1566,6 +1568,7 @@ static struct file_system_type hugetlbfs_fs_type = {
        .init_fs_context        = hugetlbfs_init_fs_context,
        .parameters             = hugetlb_fs_parameters,
        .kill_sb                = kill_litter_super,
+       .fs_flags               = FS_ALLOW_IDMAP,
 };
 
 static struct vfsmount *hugetlbfs_vfsmount[HUGE_MAX_HSTATE];
@@ -1619,7 +1622,9 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
        }
 
        file = ERR_PTR(-ENOSPC);
-       inode = hugetlbfs_get_inode(mnt->mnt_sb, NULL, S_IFREG | S_IRWXUGO, 0);
+       /* hugetlbfs_vfsmount[] mounts do not use idmapped mounts.  */
+       inode = hugetlbfs_get_inode(mnt->mnt_sb, &nop_mnt_idmap, NULL,
+                                   S_IFREG | S_IRWXUGO, 0);
        if (!inode)
                goto out;
        if (creat_flags == HUGETLB_SHMFS_INODE)
index 91048c4c9c9e7d1079d375afe64383c74f0c3c81..d290f007b3d13132319ea4eec2774ab9622d7ff9 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/ratelimit.h>
 #include <linux/list_lru.h>
 #include <linux/iversion.h>
+#include <linux/rw_hint.h>
 #include <trace/events/writeback.h>
 #include "internal.h"
 
@@ -588,7 +589,8 @@ void dump_mapping(const struct address_space *mapping)
        }
 
        dentry_ptr = container_of(dentry_first, struct dentry, d_u.d_alias);
-       if (get_kernel_nofault(dentry, dentry_ptr)) {
+       if (get_kernel_nofault(dentry, dentry_ptr) ||
+           !dentry.d_parent || !dentry.d_name.name) {
                pr_warn("aops:%ps ino:%lx invalid dentry:%px\n",
                                a_ops, ino, dentry_ptr);
                return;
@@ -2285,7 +2287,7 @@ void __init inode_init(void)
                                         sizeof(struct inode),
                                         0,
                                         (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
-                                        SLAB_MEM_SPREAD|SLAB_ACCOUNT),
+                                        SLAB_ACCOUNT),
                                         init_once);
 
        /* Hash may have been set up in inode_init_early */
@@ -2509,7 +2511,7 @@ struct timespec64 inode_set_ctime_current(struct inode *inode)
 {
        struct timespec64 now = current_time(inode);
 
-       inode_set_ctime(inode, now.tv_sec, now.tv_nsec);
+       inode_set_ctime_to_ts(inode, now);
        return now;
 }
 EXPORT_SYMBOL(inode_set_ctime_current);
index b67406435fc02763299e8732fa4cf6dfe1d51bf6..49c1fcfee4b35a8f8f653ad916ec4a4459f1ed34 100644 (file)
@@ -183,6 +183,7 @@ extern struct open_how build_open_how(int flags, umode_t mode);
 extern int build_open_flags(const struct open_how *how, struct open_flags *op);
 struct file *file_close_fd_locked(struct files_struct *files, unsigned fd);
 
+long do_ftruncate(struct file *file, loff_t length, int small);
 long do_sys_ftruncate(unsigned int fd, loff_t length, int small);
 int chmod_common(const struct path *path, umode_t mode);
 int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
@@ -310,3 +311,10 @@ ssize_t __kernel_write_iter(struct file *file, struct iov_iter *from, loff_t *po
 struct mnt_idmap *alloc_mnt_idmap(struct user_namespace *mnt_userns);
 struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap);
 void mnt_idmap_put(struct mnt_idmap *idmap);
+struct stashed_operations {
+       void (*put_data)(void *data);
+       void (*init_inode)(struct inode *inode, void *data);
+};
+int path_from_stashed(struct dentry **stashed, unsigned long ino,
+                     struct vfsmount *mnt, void *data, struct path *path);
+void stashed_dentry_prune(struct dentry *dentry);
index 76cf22ac97d76256104a6dbc4f819247168ce769..1d5abfdf0f22a626560b9ae6bb95309f8c146be5 100644 (file)
@@ -763,6 +763,33 @@ static int ioctl_fssetxattr(struct file *file, void __user *argp)
        return err;
 }
 
+static int ioctl_getfsuuid(struct file *file, void __user *argp)
+{
+       struct super_block *sb = file_inode(file)->i_sb;
+       struct fsuuid2 u = { .len = sb->s_uuid_len, };
+
+       if (!sb->s_uuid_len)
+               return -ENOIOCTLCMD;
+
+       memcpy(&u.uuid[0], &sb->s_uuid, sb->s_uuid_len);
+
+       return copy_to_user(argp, &u, sizeof(u)) ? -EFAULT : 0;
+}
+
+static int ioctl_get_fs_sysfs_path(struct file *file, void __user *argp)
+{
+       struct super_block *sb = file_inode(file)->i_sb;
+
+       if (!strlen(sb->s_sysfs_name))
+               return -ENOIOCTLCMD;
+
+       struct fs_sysfs_path u = {};
+
+       u.len = scnprintf(u.name, sizeof(u.name), "%s/%s", sb->s_type->name, sb->s_sysfs_name);
+
+       return copy_to_user(argp, &u, sizeof(u)) ? -EFAULT : 0;
+}
+
 /*
  * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d.
  * It's just a simple helper for sys_ioctl and compat_sys_ioctl.
@@ -845,6 +872,12 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd,
        case FS_IOC_FSSETXATTR:
                return ioctl_fssetxattr(filp, argp);
 
+       case FS_IOC_GETFSUUID:
+               return ioctl_getfsuuid(filp, argp);
+
+       case FS_IOC_GETFSSYSFSPATH:
+               return ioctl_get_fs_sysfs_path(filp, argp);
+
        default:
                if (S_ISREG(inode->i_mode))
                        return file_ioctl(filp, cmd, argp);
index 093c4515b22a53b9b9f9b862747269d76448ab09..4e8e41c8b3c0e41c97ed544bfafbef4113f4fbd5 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2010 Red Hat, Inc.
- * Copyright (C) 2016-2019 Christoph Hellwig.
+ * Copyright (C) 2016-2023 Christoph Hellwig.
  */
 #include <linux/module.h>
 #include <linux/compiler.h>
@@ -95,6 +95,44 @@ static inline bool ifs_block_is_dirty(struct folio *folio,
        return test_bit(block + blks_per_folio, ifs->state);
 }
 
+static unsigned ifs_find_dirty_range(struct folio *folio,
+               struct iomap_folio_state *ifs, u64 *range_start, u64 range_end)
+{
+       struct inode *inode = folio->mapping->host;
+       unsigned start_blk =
+               offset_in_folio(folio, *range_start) >> inode->i_blkbits;
+       unsigned end_blk = min_not_zero(
+               offset_in_folio(folio, range_end) >> inode->i_blkbits,
+               i_blocks_per_folio(inode, folio));
+       unsigned nblks = 1;
+
+       while (!ifs_block_is_dirty(folio, ifs, start_blk))
+               if (++start_blk == end_blk)
+                       return 0;
+
+       while (start_blk + nblks < end_blk) {
+               if (!ifs_block_is_dirty(folio, ifs, start_blk + nblks))
+                       break;
+               nblks++;
+       }
+
+       *range_start = folio_pos(folio) + (start_blk << inode->i_blkbits);
+       return nblks << inode->i_blkbits;
+}
+
+static unsigned iomap_find_dirty_range(struct folio *folio, u64 *range_start,
+               u64 range_end)
+{
+       struct iomap_folio_state *ifs = folio->private;
+
+       if (*range_start >= range_end)
+               return 0;
+
+       if (ifs)
+               return ifs_find_dirty_range(folio, ifs, range_start, range_end);
+       return range_end - *range_start;
+}
+
 static void ifs_clear_range_dirty(struct folio *folio,
                struct iomap_folio_state *ifs, size_t off, size_t len)
 {
@@ -1454,15 +1492,10 @@ out_unlock:
 EXPORT_SYMBOL_GPL(iomap_page_mkwrite);
 
 static void iomap_finish_folio_write(struct inode *inode, struct folio *folio,
-               size_t len, int error)
+               size_t len)
 {
        struct iomap_folio_state *ifs = folio->private;
 
-       if (error) {
-               folio_set_error(folio);
-               mapping_set_error(inode->i_mapping, error);
-       }
-
        WARN_ON_ONCE(i_blocks_per_folio(inode, folio) > 1 && !ifs);
        WARN_ON_ONCE(ifs && atomic_read(&ifs->write_bytes_pending) <= 0);
 
@@ -1479,40 +1512,29 @@ static u32
 iomap_finish_ioend(struct iomap_ioend *ioend, int error)
 {
        struct inode *inode = ioend->io_inode;
-       struct bio *bio = &ioend->io_inline_bio;
-       struct bio *last = ioend->io_bio, *next;
-       u64 start = bio->bi_iter.bi_sector;
-       loff_t offset = ioend->io_offset;
-       bool quiet = bio_flagged(bio, BIO_QUIET);
+       struct bio *bio = &ioend->io_bio;
+       struct folio_iter fi;
        u32 folio_count = 0;
 
-       for (bio = &ioend->io_inline_bio; bio; bio = next) {
-               struct folio_iter fi;
-
-               /*
-                * For the last bio, bi_private points to the ioend, so we
-                * need to explicitly end the iteration here.
-                */
-               if (bio == last)
-                       next = NULL;
-               else
-                       next = bio->bi_private;
-
-               /* walk all folios in bio, ending page IO on them */
-               bio_for_each_folio_all(fi, bio) {
-                       iomap_finish_folio_write(inode, fi.folio, fi.length,
-                                       error);
-                       folio_count++;
+       if (error) {
+               mapping_set_error(inode->i_mapping, error);
+               if (!bio_flagged(bio, BIO_QUIET)) {
+                       pr_err_ratelimited(
+"%s: writeback error on inode %lu, offset %lld, sector %llu",
+                               inode->i_sb->s_id, inode->i_ino,
+                               ioend->io_offset, ioend->io_sector);
                }
-               bio_put(bio);
        }
-       /* The ioend has been freed by bio_put() */
 
-       if (unlikely(error && !quiet)) {
-               printk_ratelimited(KERN_ERR
-"%s: writeback error on inode %lu, offset %lld, sector %llu",
-                       inode->i_sb->s_id, inode->i_ino, offset, start);
+       /* walk all folios in bio, ending page IO on them */
+       bio_for_each_folio_all(fi, bio) {
+               if (error)
+                       folio_set_error(fi.folio);
+               iomap_finish_folio_write(inode, fi.folio, fi.length);
+               folio_count++;
        }
+
+       bio_put(bio);   /* frees the ioend */
        return folio_count;
 }
 
@@ -1553,7 +1575,7 @@ EXPORT_SYMBOL_GPL(iomap_finish_ioends);
 static bool
 iomap_ioend_can_merge(struct iomap_ioend *ioend, struct iomap_ioend *next)
 {
-       if (ioend->io_bio->bi_status != next->io_bio->bi_status)
+       if (ioend->io_bio.bi_status != next->io_bio.bi_status)
                return false;
        if ((ioend->io_flags & IOMAP_F_SHARED) ^
            (next->io_flags & IOMAP_F_SHARED))
@@ -1618,47 +1640,46 @@ EXPORT_SYMBOL_GPL(iomap_sort_ioends);
 
 static void iomap_writepage_end_bio(struct bio *bio)
 {
-       struct iomap_ioend *ioend = bio->bi_private;
-
-       iomap_finish_ioend(ioend, blk_status_to_errno(bio->bi_status));
+       iomap_finish_ioend(iomap_ioend_from_bio(bio),
+                       blk_status_to_errno(bio->bi_status));
 }
 
 /*
  * Submit the final bio for an ioend.
  *
  * If @error is non-zero, it means that we have a situation where some part of
- * the submission process has failed after we've marked pages for writeback
- * and unlocked them.  In this situation, we need to fail the bio instead of
- * submitting it.  This typically only happens on a filesystem shutdown.
+ * the submission process has failed after we've marked pages for writeback.
+ * We cannot cancel ioend directly in that case, so call the bio end I/O handler
+ * with the error status here to run the normal I/O completion handler to clear
+ * the writeback bit and let the file system proess the errors.
  */
-static int
-iomap_submit_ioend(struct iomap_writepage_ctx *wpc, struct iomap_ioend *ioend,
-               int error)
+static int iomap_submit_ioend(struct iomap_writepage_ctx *wpc, int error)
 {
-       ioend->io_bio->bi_private = ioend;
-       ioend->io_bio->bi_end_io = iomap_writepage_end_bio;
+       if (!wpc->ioend)
+               return error;
 
+       /*
+        * Let the file systems prepare the I/O submission and hook in an I/O
+        * comletion handler.  This also needs to happen in case after a
+        * failure happened so that the file system end I/O handler gets called
+        * to clean up.
+        */
        if (wpc->ops->prepare_ioend)
-               error = wpc->ops->prepare_ioend(ioend, error);
+               error = wpc->ops->prepare_ioend(wpc->ioend, error);
+
        if (error) {
-               /*
-                * If we're failing the IO now, just mark the ioend with an
-                * error and finish it.  This will run IO completion immediately
-                * as there is only one reference to the ioend at this point in
-                * time.
-                */
-               ioend->io_bio->bi_status = errno_to_blk_status(error);
-               bio_endio(ioend->io_bio);
-               return error;
+               wpc->ioend->io_bio.bi_status = errno_to_blk_status(error);
+               bio_endio(&wpc->ioend->io_bio);
+       } else {
+               submit_bio(&wpc->ioend->io_bio);
        }
 
-       submit_bio(ioend->io_bio);
-       return 0;
+       wpc->ioend = NULL;
+       return error;
 }
 
-static struct iomap_ioend *
-iomap_alloc_ioend(struct inode *inode, struct iomap_writepage_ctx *wpc,
-               loff_t offset, sector_t sector, struct writeback_control *wbc)
+static struct iomap_ioend *iomap_alloc_ioend(struct iomap_writepage_ctx *wpc,
+               struct writeback_control *wbc, struct inode *inode, loff_t pos)
 {
        struct iomap_ioend *ioend;
        struct bio *bio;
@@ -1666,63 +1687,42 @@ iomap_alloc_ioend(struct inode *inode, struct iomap_writepage_ctx *wpc,
        bio = bio_alloc_bioset(wpc->iomap.bdev, BIO_MAX_VECS,
                               REQ_OP_WRITE | wbc_to_write_flags(wbc),
                               GFP_NOFS, &iomap_ioend_bioset);
-       bio->bi_iter.bi_sector = sector;
+       bio->bi_iter.bi_sector = iomap_sector(&wpc->iomap, pos);
+       bio->bi_end_io = iomap_writepage_end_bio;
        wbc_init_bio(wbc, bio);
+       bio->bi_write_hint = inode->i_write_hint;
 
-       ioend = container_of(bio, struct iomap_ioend, io_inline_bio);
+       ioend = iomap_ioend_from_bio(bio);
        INIT_LIST_HEAD(&ioend->io_list);
        ioend->io_type = wpc->iomap.type;
        ioend->io_flags = wpc->iomap.flags;
        ioend->io_inode = inode;
        ioend->io_size = 0;
-       ioend->io_folios = 0;
-       ioend->io_offset = offset;
-       ioend->io_bio = bio;
-       ioend->io_sector = sector;
-       return ioend;
-}
-
-/*
- * Allocate a new bio, and chain the old bio to the new one.
- *
- * Note that we have to perform the chaining in this unintuitive order
- * so that the bi_private linkage is set up in the right direction for the
- * traversal in iomap_finish_ioend().
- */
-static struct bio *
-iomap_chain_bio(struct bio *prev)
-{
-       struct bio *new;
-
-       new = bio_alloc(prev->bi_bdev, BIO_MAX_VECS, prev->bi_opf, GFP_NOFS);
-       bio_clone_blkg_association(new, prev);
-       new->bi_iter.bi_sector = bio_end_sector(prev);
+       ioend->io_offset = pos;
+       ioend->io_sector = bio->bi_iter.bi_sector;
 
-       bio_chain(prev, new);
-       bio_get(prev);          /* for iomap_finish_ioend */
-       submit_bio(prev);
-       return new;
+       wpc->nr_folios = 0;
+       return ioend;
 }
 
-static bool
-iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t offset,
-               sector_t sector)
+static bool iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t pos)
 {
        if ((wpc->iomap.flags & IOMAP_F_SHARED) !=
            (wpc->ioend->io_flags & IOMAP_F_SHARED))
                return false;
        if (wpc->iomap.type != wpc->ioend->io_type)
                return false;
-       if (offset != wpc->ioend->io_offset + wpc->ioend->io_size)
+       if (pos != wpc->ioend->io_offset + wpc->ioend->io_size)
                return false;
-       if (sector != bio_end_sector(wpc->ioend->io_bio))
+       if (iomap_sector(&wpc->iomap, pos) !=
+           bio_end_sector(&wpc->ioend->io_bio))
                return false;
        /*
         * Limit ioend bio chain lengths to minimise IO completion latency. This
         * also prevents long tight loops ending page writeback on all the
         * folios in the ioend.
         */
-       if (wpc->ioend->io_folios >= IOEND_BATCH_SIZE)
+       if (wpc->nr_folios >= IOEND_BATCH_SIZE)
                return false;
        return true;
 }
@@ -1730,255 +1730,238 @@ iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t offset,
 /*
  * Test to see if we have an existing ioend structure that we could append to
  * first; otherwise finish off the current ioend and start another.
+ *
+ * If a new ioend is created and cached, the old ioend is submitted to the block
+ * layer instantly.  Batching optimisations are provided by higher level block
+ * plugging.
+ *
+ * At the end of a writeback pass, there will be a cached ioend remaining on the
+ * writepage context that the caller will need to submit.
  */
-static void
-iomap_add_to_ioend(struct inode *inode, loff_t pos, struct folio *folio,
-               struct iomap_folio_state *ifs, struct iomap_writepage_ctx *wpc,
-               struct writeback_control *wbc, struct list_head *iolist)
+static int iomap_add_to_ioend(struct iomap_writepage_ctx *wpc,
+               struct writeback_control *wbc, struct folio *folio,
+               struct inode *inode, loff_t pos, unsigned len)
 {
-       sector_t sector = iomap_sector(&wpc->iomap, pos);
-       unsigned len = i_blocksize(inode);
+       struct iomap_folio_state *ifs = folio->private;
        size_t poff = offset_in_folio(folio, pos);
+       int error;
 
-       if (!wpc->ioend || !iomap_can_add_to_ioend(wpc, pos, sector)) {
-               if (wpc->ioend)
-                       list_add(&wpc->ioend->io_list, iolist);
-               wpc->ioend = iomap_alloc_ioend(inode, wpc, pos, sector, wbc);
+       if (!wpc->ioend || !iomap_can_add_to_ioend(wpc, pos)) {
+new_ioend:
+               error = iomap_submit_ioend(wpc, 0);
+               if (error)
+                       return error;
+               wpc->ioend = iomap_alloc_ioend(wpc, wbc, inode, pos);
        }
 
-       if (!bio_add_folio(wpc->ioend->io_bio, folio, len, poff)) {
-               wpc->ioend->io_bio = iomap_chain_bio(wpc->ioend->io_bio);
-               bio_add_folio_nofail(wpc->ioend->io_bio, folio, len, poff);
-       }
+       if (!bio_add_folio(&wpc->ioend->io_bio, folio, len, poff))
+               goto new_ioend;
 
        if (ifs)
                atomic_add(len, &ifs->write_bytes_pending);
        wpc->ioend->io_size += len;
        wbc_account_cgroup_owner(wbc, &folio->page, len);
+       return 0;
 }
 
-/*
- * We implement an immediate ioend submission policy here to avoid needing to
- * chain multiple ioends and hence nest mempool allocations which can violate
- * the forward progress guarantees we need to provide. The current ioend we're
- * adding blocks to is cached in the writepage context, and if the new block
- * doesn't append to the cached ioend, it will create a new ioend and cache that
- * instead.
- *
- * If a new ioend is created and cached, the old ioend is returned and queued
- * locally for submission once the entire page is processed or an error has been
- * detected.  While ioends are submitted immediately after they are completed,
- * batching optimisations are provided by higher level block plugging.
- *
- * At the end of a writeback pass, there will be a cached ioend remaining on the
- * writepage context that the caller will need to submit.
- */
-static int
-iomap_writepage_map(struct iomap_writepage_ctx *wpc,
-               struct writeback_control *wbc, struct inode *inode,
-               struct folio *folio, u64 end_pos)
+static int iomap_writepage_map_blocks(struct iomap_writepage_ctx *wpc,
+               struct writeback_control *wbc, struct folio *folio,
+               struct inode *inode, u64 pos, unsigned dirty_len,
+               unsigned *count)
 {
-       struct iomap_folio_state *ifs = folio->private;
-       struct iomap_ioend *ioend, *next;
-       unsigned len = i_blocksize(inode);
-       unsigned nblocks = i_blocks_per_folio(inode, folio);
-       u64 pos = folio_pos(folio);
-       int error = 0, count = 0, i;
-       LIST_HEAD(submit_list);
-
-       WARN_ON_ONCE(end_pos <= pos);
-
-       if (!ifs && nblocks > 1) {
-               ifs = ifs_alloc(inode, folio, 0);
-               iomap_set_range_dirty(folio, 0, end_pos - pos);
-       }
+       int error;
 
-       WARN_ON_ONCE(ifs && atomic_read(&ifs->write_bytes_pending) != 0);
-
-       /*
-        * Walk through the folio to find areas to write back. If we
-        * run off the end of the current map or find the current map
-        * invalid, grab a new one.
-        */
-       for (i = 0; i < nblocks && pos < end_pos; i++, pos += len) {
-               if (ifs && !ifs_block_is_dirty(folio, ifs, i))
-                       continue;
+       do {
+               unsigned map_len;
 
-               error = wpc->ops->map_blocks(wpc, inode, pos);
+               error = wpc->ops->map_blocks(wpc, inode, pos, dirty_len);
                if (error)
                        break;
-               trace_iomap_writepage_map(inode, &wpc->iomap);
-               if (WARN_ON_ONCE(wpc->iomap.type == IOMAP_INLINE))
-                       continue;
-               if (wpc->iomap.type == IOMAP_HOLE)
-                       continue;
-               iomap_add_to_ioend(inode, pos, folio, ifs, wpc, wbc,
-                                &submit_list);
-               count++;
-       }
-       if (count)
-               wpc->ioend->io_folios++;
+               trace_iomap_writepage_map(inode, pos, dirty_len, &wpc->iomap);
 
-       WARN_ON_ONCE(!wpc->ioend && !list_empty(&submit_list));
-       WARN_ON_ONCE(!folio_test_locked(folio));
-       WARN_ON_ONCE(folio_test_writeback(folio));
-       WARN_ON_ONCE(folio_test_dirty(folio));
+               map_len = min_t(u64, dirty_len,
+                       wpc->iomap.offset + wpc->iomap.length - pos);
+               WARN_ON_ONCE(!folio->private && map_len < dirty_len);
+
+               switch (wpc->iomap.type) {
+               case IOMAP_INLINE:
+                       WARN_ON_ONCE(1);
+                       error = -EIO;
+                       break;
+               case IOMAP_HOLE:
+                       break;
+               default:
+                       error = iomap_add_to_ioend(wpc, wbc, folio, inode, pos,
+                                       map_len);
+                       if (!error)
+                               (*count)++;
+                       break;
+               }
+               dirty_len -= map_len;
+               pos += map_len;
+       } while (dirty_len && !error);
 
        /*
         * We cannot cancel the ioend directly here on error.  We may have
         * already set other pages under writeback and hence we have to run I/O
         * completion to mark the error state of the pages under writeback
         * appropriately.
+        *
+        * Just let the file system know what portion of the folio failed to
+        * map.
         */
-       if (unlikely(error)) {
-               /*
-                * Let the filesystem know what portion of the current page
-                * failed to map. If the page hasn't been added to ioend, it
-                * won't be affected by I/O completion and we must unlock it
-                * now.
-                */
-               if (wpc->ops->discard_folio)
-                       wpc->ops->discard_folio(folio, pos);
-               if (!count) {
-                       folio_unlock(folio);
-                       goto done;
-               }
-       }
-
-       /*
-        * We can have dirty bits set past end of file in page_mkwrite path
-        * while mapping the last partial folio. Hence it's better to clear
-        * all the dirty bits in the folio here.
-        */
-       iomap_clear_range_dirty(folio, 0, folio_size(folio));
-       folio_start_writeback(folio);
-       folio_unlock(folio);
-
-       /*
-        * Preserve the original error if there was one; catch
-        * submission errors here and propagate into subsequent ioend
-        * submissions.
-        */
-       list_for_each_entry_safe(ioend, next, &submit_list, io_list) {
-               int error2;
-
-               list_del_init(&ioend->io_list);
-               error2 = iomap_submit_ioend(wpc, ioend, error);
-               if (error2 && !error)
-                       error = error2;
-       }
-
-       /*
-        * We can end up here with no error and nothing to write only if we race
-        * with a partial page truncate on a sub-page block sized filesystem.
-        */
-       if (!count)
-               folio_end_writeback(folio);
-done:
-       mapping_set_error(inode->i_mapping, error);
+       if (error && wpc->ops->discard_folio)
+               wpc->ops->discard_folio(folio, pos);
        return error;
 }
 
 /*
- * Write out a dirty page.
+ * Check interaction of the folio with the file end.
  *
- * For delalloc space on the page, we need to allocate space and flush it.
- * For unwritten space on the page, we need to start the conversion to
- * regular allocated space.
+ * If the folio is entirely beyond i_size, return false.  If it straddles
+ * i_size, adjust end_pos and zero all data beyond i_size.
  */
-static int iomap_do_writepage(struct folio *folio,
-               struct writeback_control *wbc, void *data)
+static bool iomap_writepage_handle_eof(struct folio *folio, struct inode *inode,
+               u64 *end_pos)
 {
-       struct iomap_writepage_ctx *wpc = data;
-       struct inode *inode = folio->mapping->host;
-       u64 end_pos, isize;
-
-       trace_iomap_writepage(inode, folio_pos(folio), folio_size(folio));
+       u64 isize = i_size_read(inode);
 
-       /*
-        * Refuse to write the folio out if we're called from reclaim context.
-        *
-        * This avoids stack overflows when called from deeply used stacks in
-        * random callers for direct reclaim or memcg reclaim.  We explicitly
-        * allow reclaim from kswapd as the stack usage there is relatively low.
-        *
-        * This should never happen except in the case of a VM regression so
-        * warn about it.
-        */
-       if (WARN_ON_ONCE((current->flags & (PF_MEMALLOC|PF_KSWAPD)) ==
-                       PF_MEMALLOC))
-               goto redirty;
-
-       /*
-        * Is this folio beyond the end of the file?
-        *
-        * The folio index is less than the end_index, adjust the end_pos
-        * to the highest offset that this folio should represent.
-        * -----------------------------------------------------
-        * |                    file mapping           | <EOF> |
-        * -----------------------------------------------------
-        * | Page ... | Page N-2 | Page N-1 |  Page N  |       |
-        * ^--------------------------------^----------|--------
-        * |     desired writeback range    |      see else    |
-        * ---------------------------------^------------------|
-        */
-       isize = i_size_read(inode);
-       end_pos = folio_pos(folio) + folio_size(folio);
-       if (end_pos > isize) {
-               /*
-                * Check whether the page to write out is beyond or straddles
-                * i_size or not.
-                * -------------------------------------------------------
-                * |            file mapping                    | <EOF>  |
-                * -------------------------------------------------------
-                * | Page ... | Page N-2 | Page N-1 |  Page N   | Beyond |
-                * ^--------------------------------^-----------|---------
-                * |                                |      Straddles     |
-                * ---------------------------------^-----------|--------|
-                */
+       if (*end_pos > isize) {
                size_t poff = offset_in_folio(folio, isize);
                pgoff_t end_index = isize >> PAGE_SHIFT;
 
                /*
-                * Skip the page if it's fully outside i_size, e.g.
-                * due to a truncate operation that's in progress.  We've
-                * cleaned this page and truncate will finish things off for
-                * us.
+                * If the folio is entirely ouside of i_size, skip it.
+                *
+                * This can happen due to a truncate operation that is in
+                * progress and in that case truncate will finish it off once
+                * we've dropped the folio lock.
                 *
-                * Note that the end_index is unsigned long.  If the given
-                * offset is greater than 16TB on a 32-bit system then if we
-                * checked if the page is fully outside i_size with
-                * "if (page->index >= end_index + 1)", "end_index + 1" would
-                * overflow and evaluate to 0.  Hence this page would be
+                * Note that the pgoff_t used for end_index is an unsigned long.
+                * If the given offset is greater than 16TB on a 32-bit system,
+                * then if we checked if the folio is fully outside i_size with
+                * "if (folio->index >= end_index + 1)", "end_index + 1" would
+                * overflow and evaluate to 0.  Hence this folio would be
                 * redirtied and written out repeatedly, which would result in
                 * an infinite loop; the user program performing this operation
                 * would hang.  Instead, we can detect this situation by
-                * checking if the page is totally beyond i_size or if its
+                * checking if the folio is totally beyond i_size or if its
                 * offset is just equal to the EOF.
                 */
                if (folio->index > end_index ||
                    (folio->index == end_index && poff == 0))
-                       goto unlock;
+                       return false;
 
                /*
-                * The page straddles i_size.  It must be zeroed out on each
-                * and every writepage invocation because it may be mmapped.
-                * "A file is mapped in multiples of the page size.  For a file
-                * that is not a multiple of the page size, the remaining
-                * memory is zeroed when mapped, and writes to that region are
-                * not written out to the file."
+                * The folio straddles i_size.
+                *
+                * It must be zeroed out on each and every writepage invocation
+                * because it may be mmapped:
+                *
+                *    A file is mapped in multiples of the page size.  For a
+                *    file that is not a multiple of the page size, the
+                *    remaining memory is zeroed when mapped, and writes to that
+                *    region are not written out to the file.
+                *
+                * Also adjust the writeback range to skip all blocks entirely
+                * beyond i_size.
                 */
                folio_zero_segment(folio, poff, folio_size(folio));
-               end_pos = isize;
+               *end_pos = round_up(isize, i_blocksize(inode));
+       }
+
+       return true;
+}
+
+static int iomap_writepage_map(struct iomap_writepage_ctx *wpc,
+               struct writeback_control *wbc, struct folio *folio)
+{
+       struct iomap_folio_state *ifs = folio->private;
+       struct inode *inode = folio->mapping->host;
+       u64 pos = folio_pos(folio);
+       u64 end_pos = pos + folio_size(folio);
+       unsigned count = 0;
+       int error = 0;
+       u32 rlen;
+
+       WARN_ON_ONCE(!folio_test_locked(folio));
+       WARN_ON_ONCE(folio_test_dirty(folio));
+       WARN_ON_ONCE(folio_test_writeback(folio));
+
+       trace_iomap_writepage(inode, pos, folio_size(folio));
+
+       if (!iomap_writepage_handle_eof(folio, inode, &end_pos)) {
+               folio_unlock(folio);
+               return 0;
+       }
+       WARN_ON_ONCE(end_pos <= pos);
+
+       if (i_blocks_per_folio(inode, folio) > 1) {
+               if (!ifs) {
+                       ifs = ifs_alloc(inode, folio, 0);
+                       iomap_set_range_dirty(folio, 0, end_pos - pos);
+               }
+
+               /*
+                * Keep the I/O completion handler from clearing the writeback
+                * bit until we have submitted all blocks by adding a bias to
+                * ifs->write_bytes_pending, which is dropped after submitting
+                * all blocks.
+                */
+               WARN_ON_ONCE(atomic_read(&ifs->write_bytes_pending) != 0);
+               atomic_inc(&ifs->write_bytes_pending);
        }
 
-       return iomap_writepage_map(wpc, wbc, inode, folio, end_pos);
+       /*
+        * Set the writeback bit ASAP, as the I/O completion for the single
+        * block per folio case happen hit as soon as we're submitting the bio.
+        */
+       folio_start_writeback(folio);
 
-redirty:
-       folio_redirty_for_writepage(wbc, folio);
-unlock:
+       /*
+        * Walk through the folio to find dirty areas to write back.
+        */
+       while ((rlen = iomap_find_dirty_range(folio, &pos, end_pos))) {
+               error = iomap_writepage_map_blocks(wpc, wbc, folio, inode,
+                               pos, rlen, &count);
+               if (error)
+                       break;
+               pos += rlen;
+       }
+
+       if (count)
+               wpc->nr_folios++;
+
+       /*
+        * We can have dirty bits set past end of file in page_mkwrite path
+        * while mapping the last partial folio. Hence it's better to clear
+        * all the dirty bits in the folio here.
+        */
+       iomap_clear_range_dirty(folio, 0, folio_size(folio));
+
+       /*
+        * Usually the writeback bit is cleared by the I/O completion handler.
+        * But we may end up either not actually writing any blocks, or (when
+        * there are multiple blocks in a folio) all I/O might have finished
+        * already at this point.  In that case we need to clear the writeback
+        * bit ourselves right after unlocking the page.
+        */
        folio_unlock(folio);
-       return 0;
+       if (ifs) {
+               if (atomic_dec_and_test(&ifs->write_bytes_pending))
+                       folio_end_writeback(folio);
+       } else {
+               if (!count)
+                       folio_end_writeback(folio);
+       }
+       mapping_set_error(inode->i_mapping, error);
+       return error;
+}
+
+static int iomap_do_writepage(struct folio *folio,
+               struct writeback_control *wbc, void *data)
+{
+       return iomap_writepage_map(data, wbc, folio);
 }
 
 int
@@ -1988,18 +1971,24 @@ iomap_writepages(struct address_space *mapping, struct writeback_control *wbc,
 {
        int                     ret;
 
+       /*
+        * Writeback from reclaim context should never happen except in the case
+        * of a VM regression so warn about it and refuse to write the data.
+        */
+       if (WARN_ON_ONCE((current->flags & (PF_MEMALLOC | PF_KSWAPD)) ==
+                       PF_MEMALLOC))
+               return -EIO;
+
        wpc->ops = ops;
        ret = write_cache_pages(mapping, wbc, iomap_do_writepage, wpc);
-       if (!wpc->ioend)
-               return ret;
-       return iomap_submit_ioend(wpc, wpc->ioend, ret);
+       return iomap_submit_ioend(wpc, ret);
 }
 EXPORT_SYMBOL_GPL(iomap_writepages);
 
 static int __init iomap_init(void)
 {
        return bioset_init(&iomap_ioend_bioset, 4 * (PAGE_SIZE / SECTOR_SIZE),
-                          offsetof(struct iomap_ioend, io_inline_bio),
+                          offsetof(struct iomap_ioend, io_bio),
                           BIOSET_NEED_BVECS);
 }
 fs_initcall(iomap_init);
index bcd3f8cf5ea42f0fa0e4967510230f7e5d25b1fa..f3b43d223a46ee9064315b6bc902852f16172ce1 100644 (file)
@@ -380,6 +380,7 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter,
                fscrypt_set_bio_crypt_ctx(bio, inode, pos >> inode->i_blkbits,
                                          GFP_KERNEL);
                bio->bi_iter.bi_sector = iomap_sector(iomap, pos);
+               bio->bi_write_hint = inode->i_write_hint;
                bio->bi_ioprio = dio->iocb->ki_ioprio;
                bio->bi_private = dio;
                bio->bi_end_io = iomap_dio_bio_end_io;
index c16fd55f5595c2984c24ddf77002eab739eeffc8..0a991c4ce87d2c2ef1ec3e35bd8eefe716582d3c 100644 (file)
@@ -154,7 +154,48 @@ DEFINE_EVENT(iomap_class, name,    \
        TP_ARGS(inode, iomap))
 DEFINE_IOMAP_EVENT(iomap_iter_dstmap);
 DEFINE_IOMAP_EVENT(iomap_iter_srcmap);
-DEFINE_IOMAP_EVENT(iomap_writepage_map);
+
+TRACE_EVENT(iomap_writepage_map,
+       TP_PROTO(struct inode *inode, u64 pos, unsigned int dirty_len,
+                struct iomap *iomap),
+       TP_ARGS(inode, pos, dirty_len, iomap),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(u64, ino)
+               __field(u64, pos)
+               __field(u64, dirty_len)
+               __field(u64, addr)
+               __field(loff_t, offset)
+               __field(u64, length)
+               __field(u16, type)
+               __field(u16, flags)
+               __field(dev_t, bdev)
+       ),
+       TP_fast_assign(
+               __entry->dev = inode->i_sb->s_dev;
+               __entry->ino = inode->i_ino;
+               __entry->pos = pos;
+               __entry->dirty_len = dirty_len;
+               __entry->addr = iomap->addr;
+               __entry->offset = iomap->offset;
+               __entry->length = iomap->length;
+               __entry->type = iomap->type;
+               __entry->flags = iomap->flags;
+               __entry->bdev = iomap->bdev ? iomap->bdev->bd_dev : 0;
+       ),
+       TP_printk("dev %d:%d ino 0x%llx bdev %d:%d pos 0x%llx dirty len 0x%llx "
+                 "addr 0x%llx offset 0x%llx length 0x%llx type %s flags %s",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->ino,
+                 MAJOR(__entry->bdev), MINOR(__entry->bdev),
+                 __entry->pos,
+                 __entry->dirty_len,
+                 __entry->addr,
+                 __entry->offset,
+                 __entry->length,
+                 __print_symbolic(__entry->type, IOMAP_TYPE_STRINGS),
+                 __print_flags(__entry->flags, "|", IOMAP_F_FLAGS_STRINGS))
+);
 
 TRACE_EVENT(iomap_iter,
        TP_PROTO(struct iomap_iter *iter, const void *ops,
@@ -165,6 +206,7 @@ TRACE_EVENT(iomap_iter,
                __field(u64, ino)
                __field(loff_t, pos)
                __field(u64, length)
+               __field(s64, processed)
                __field(unsigned int, flags)
                __field(const void *, ops)
                __field(unsigned long, caller)
@@ -174,15 +216,17 @@ TRACE_EVENT(iomap_iter,
                __entry->ino = iter->inode->i_ino;
                __entry->pos = iter->pos;
                __entry->length = iomap_length(iter);
+               __entry->processed = iter->processed;
                __entry->flags = iter->flags;
                __entry->ops = ops;
                __entry->caller = caller;
        ),
-       TP_printk("dev %d:%d ino 0x%llx pos 0x%llx length 0x%llx flags %s (0x%x) ops %ps caller %pS",
+       TP_printk("dev %d:%d ino 0x%llx pos 0x%llx length 0x%llx processed %lld flags %s (0x%x) ops %ps caller %pS",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                   __entry->ino,
                   __entry->pos,
                   __entry->length,
+                  __entry->processed,
                   __print_flags(__entry->flags, "|", IOMAP_FLAGS_STRINGS),
                   __entry->flags,
                   __entry->ops,
index cb6d1fda66a7021a9ce5b42959122be9ad1934b2..73389c68e25170c81d6f84483f09b43216ba4b52 100644 (file)
@@ -1058,7 +1058,7 @@ void jfs_syncpt(struct jfs_log *log, int hard_sync)
 int lmLogOpen(struct super_block *sb)
 {
        int rc;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct jfs_log *log;
        struct jfs_sb_info *sbi = JFS_SBI(sb);
 
@@ -1070,7 +1070,7 @@ int lmLogOpen(struct super_block *sb)
 
        mutex_lock(&jfs_log_mutex);
        list_for_each_entry(log, &jfs_external_logs, journal_list) {
-               if (log->bdev_handle->bdev->bd_dev == sbi->logdev) {
+               if (file_bdev(log->bdev_file)->bd_dev == sbi->logdev) {
                        if (!uuid_equal(&log->uuid, &sbi->loguuid)) {
                                jfs_warn("wrong uuid on JFS journal");
                                mutex_unlock(&jfs_log_mutex);
@@ -1100,14 +1100,14 @@ int lmLogOpen(struct super_block *sb)
         * file systems to log may have n-to-1 relationship;
         */
 
-       bdev_handle = bdev_open_by_dev(sbi->logdev,
+       bdev_file = bdev_file_open_by_dev(sbi->logdev,
                        BLK_OPEN_READ | BLK_OPEN_WRITE, log, NULL);
-       if (IS_ERR(bdev_handle)) {
-               rc = PTR_ERR(bdev_handle);
+       if (IS_ERR(bdev_file)) {
+               rc = PTR_ERR(bdev_file);
                goto free;
        }
 
-       log->bdev_handle = bdev_handle;
+       log->bdev_file = bdev_file;
        uuid_copy(&log->uuid, &sbi->loguuid);
 
        /*
@@ -1141,7 +1141,7 @@ journal_found:
        lbmLogShutdown(log);
 
       close:           /* close external log device */
-       bdev_release(bdev_handle);
+       fput(bdev_file);
 
       free:            /* free log descriptor */
        mutex_unlock(&jfs_log_mutex);
@@ -1162,7 +1162,7 @@ static int open_inline_log(struct super_block *sb)
        init_waitqueue_head(&log->syncwait);
 
        set_bit(log_INLINELOG, &log->flag);
-       log->bdev_handle = sb->s_bdev_handle;
+       log->bdev_file = sb->s_bdev_file;
        log->base = addressPXD(&JFS_SBI(sb)->logpxd);
        log->size = lengthPXD(&JFS_SBI(sb)->logpxd) >>
            (L2LOGPSIZE - sb->s_blocksize_bits);
@@ -1436,7 +1436,7 @@ int lmLogClose(struct super_block *sb)
 {
        struct jfs_sb_info *sbi = JFS_SBI(sb);
        struct jfs_log *log = sbi->log;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        int rc = 0;
 
        jfs_info("lmLogClose: log:0x%p", log);
@@ -1482,10 +1482,10 @@ int lmLogClose(struct super_block *sb)
         *      external log as separate logical volume
         */
        list_del(&log->journal_list);
-       bdev_handle = log->bdev_handle;
+       bdev_file = log->bdev_file;
        rc = lmLogShutdown(log);
 
-       bdev_release(bdev_handle);
+       fput(bdev_file);
 
        kfree(log);
 
@@ -1972,7 +1972,7 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp)
 
        bp->l_flag |= lbmREAD;
 
-       bio = bio_alloc(log->bdev_handle->bdev, 1, REQ_OP_READ, GFP_NOFS);
+       bio = bio_alloc(file_bdev(log->bdev_file), 1, REQ_OP_READ, GFP_NOFS);
        bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9);
        __bio_add_page(bio, bp->l_page, LOGPSIZE, bp->l_offset);
        BUG_ON(bio->bi_iter.bi_size != LOGPSIZE);
@@ -2115,7 +2115,7 @@ static void lbmStartIO(struct lbuf * bp)
        jfs_info("lbmStartIO");
 
        if (!log->no_integrity)
-               bdev = log->bdev_handle->bdev;
+               bdev = file_bdev(log->bdev_file);
 
        bio = bio_alloc(bdev, 1, REQ_OP_WRITE | REQ_SYNC,
                        GFP_NOFS);
index 84aa2d2539074361cf6694dd9586f5925ad56d3a..8b8994e48cd080b4df8084108e89c06c5ce36417 100644 (file)
@@ -356,7 +356,7 @@ struct jfs_log {
                                 *    before writing syncpt.
                                 */
        struct list_head journal_list; /* Global list */
-       struct bdev_handle *bdev_handle; /* 4: log lv pointer */
+       struct file *bdev_file; /* 4: log lv pointer */
        int serial;             /* 4: log mount serial number */
 
        s64 base;               /* @8: log extent address (inline log ) */
index 9b5c6a20b30c8323f09aefcce6b4ff0482c9b2dc..98f9a432c33662f51b1236579299719bf732f11c 100644 (file)
@@ -431,7 +431,7 @@ int updateSuper(struct super_block *sb, uint state)
        if (state == FM_MOUNT) {
                /* record log's dev_t and mount serial number */
                j_sb->s_logdev = cpu_to_le32(
-                       new_encode_dev(sbi->log->bdev_handle->bdev->bd_dev));
+                       new_encode_dev(file_bdev(sbi->log->bdev_file)->bd_dev));
                j_sb->s_logserial = cpu_to_le32(sbi->log->serial);
        } else if (state == FM_CLEAN) {
                /*
index 8d8e556bd6104eca1ec55d7ea4da3bcfec0c967f..73f09a762b79b0495cfd56017e5e10e0362b2d30 100644 (file)
@@ -932,7 +932,7 @@ static int __init init_jfs_fs(void)
 
        jfs_inode_cachep =
            kmem_cache_create_usercopy("jfs_ip", sizeof(struct jfs_inode_info),
-                       0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT,
+                       0, SLAB_RECLAIM_ACCOUNT|SLAB_ACCOUNT,
                        offsetof(struct jfs_inode_info, i_inline_all),
                        sizeof_field(struct jfs_inode_info, i_inline_all),
                        init_once);
index 0c93cad0f0acac80425dcdbd21b1eedaffe8c4d6..e29f4edf9572e739c5da8e30f51ebfa05c4eb5ee 100644 (file)
@@ -358,7 +358,9 @@ int kernfs_get_tree(struct fs_context *fc)
                }
                sb->s_flags |= SB_ACTIVE;
 
-               uuid_gen(&sb->s_uuid);
+               uuid_t uuid;
+               uuid_gen(&uuid);
+               super_set_uuid(sb, uuid.b, sizeof(uuid));
 
                down_write(&root->kernfs_supers_rwsem);
                list_add(&info->node, &info->root->supers);
index eec6031b0155442eab924ce946c2295c711105d2..0d14ae808fcfdb314af5b95ccabec10f1dac8c15 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/fsnotify.h>
 #include <linux/unicode.h>
 #include <linux/fscrypt.h>
+#include <linux/pidfs.h>
 
 #include <linux/uaccess.h>
 
@@ -240,17 +241,22 @@ const struct inode_operations simple_dir_inode_operations = {
 };
 EXPORT_SYMBOL(simple_dir_inode_operations);
 
-static void offset_set(struct dentry *dentry, u32 offset)
+/* 0 is '.', 1 is '..', so always start with offset 2 or more */
+enum {
+       DIR_OFFSET_MIN  = 2,
+};
+
+static void offset_set(struct dentry *dentry, long offset)
 {
-       dentry->d_fsdata = (void *)((uintptr_t)(offset));
+       dentry->d_fsdata = (void *)offset;
 }
 
-static u32 dentry2offset(struct dentry *dentry)
+static long dentry2offset(struct dentry *dentry)
 {
-       return (u32)((uintptr_t)(dentry->d_fsdata));
+       return (long)dentry->d_fsdata;
 }
 
-static struct lock_class_key simple_offset_xa_lock;
+static struct lock_class_key simple_offset_lock_class;
 
 /**
  * simple_offset_init - initialize an offset_ctx
@@ -259,11 +265,9 @@ static struct lock_class_key simple_offset_xa_lock;
  */
 void simple_offset_init(struct offset_ctx *octx)
 {
-       xa_init_flags(&octx->xa, XA_FLAGS_ALLOC1);
-       lockdep_set_class(&octx->xa.xa_lock, &simple_offset_xa_lock);
-
-       /* 0 is '.', 1 is '..', so always start with offset 2 */
-       octx->next_offset = 2;
+       mt_init_flags(&octx->mt, MT_FLAGS_ALLOC_RANGE);
+       lockdep_set_class(&octx->mt.ma_lock, &simple_offset_lock_class);
+       octx->next_offset = DIR_OFFSET_MIN;
 }
 
 /**
@@ -271,20 +275,19 @@ void simple_offset_init(struct offset_ctx *octx)
  * @octx: directory offset ctx to be updated
  * @dentry: new dentry being added
  *
- * Returns zero on success. @so_ctx and the dentry offset are updated.
+ * Returns zero on success. @octx and the dentry's offset are updated.
  * Otherwise, a negative errno value is returned.
  */
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry)
 {
-       static const struct xa_limit limit = XA_LIMIT(2, U32_MAX);
-       u32 offset;
+       unsigned long offset;
        int ret;
 
        if (dentry2offset(dentry) != 0)
                return -EBUSY;
 
-       ret = xa_alloc_cyclic(&octx->xa, &offset, dentry, limit,
-                             &octx->next_offset, GFP_KERNEL);
+       ret = mtree_alloc_cyclic(&octx->mt, &offset, dentry, DIR_OFFSET_MIN,
+                                LONG_MAX, &octx->next_offset, GFP_KERNEL);
        if (ret < 0)
                return ret;
 
@@ -300,16 +303,48 @@ int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry)
  */
 void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry)
 {
-       u32 offset;
+       long offset;
 
        offset = dentry2offset(dentry);
        if (offset == 0)
                return;
 
-       xa_erase(&octx->xa, offset);
+       mtree_erase(&octx->mt, offset);
        offset_set(dentry, 0);
 }
 
+/**
+ * simple_offset_empty - Check if a dentry can be unlinked
+ * @dentry: dentry to be tested
+ *
+ * Returns 0 if @dentry is a non-empty directory; otherwise returns 1.
+ */
+int simple_offset_empty(struct dentry *dentry)
+{
+       struct inode *inode = d_inode(dentry);
+       struct offset_ctx *octx;
+       struct dentry *child;
+       unsigned long index;
+       int ret = 1;
+
+       if (!inode || !S_ISDIR(inode->i_mode))
+               return ret;
+
+       index = DIR_OFFSET_MIN;
+       octx = inode->i_op->get_offset_ctx(inode);
+       mt_for_each(&octx->mt, child, index, LONG_MAX) {
+               spin_lock(&child->d_lock);
+               if (simple_positive(child)) {
+                       spin_unlock(&child->d_lock);
+                       ret = 0;
+                       break;
+               }
+               spin_unlock(&child->d_lock);
+       }
+
+       return ret;
+}
+
 /**
  * simple_offset_rename_exchange - exchange rename with directory offsets
  * @old_dir: parent of dentry being moved
@@ -327,8 +362,8 @@ int simple_offset_rename_exchange(struct inode *old_dir,
 {
        struct offset_ctx *old_ctx = old_dir->i_op->get_offset_ctx(old_dir);
        struct offset_ctx *new_ctx = new_dir->i_op->get_offset_ctx(new_dir);
-       u32 old_index = dentry2offset(old_dentry);
-       u32 new_index = dentry2offset(new_dentry);
+       long old_index = dentry2offset(old_dentry);
+       long new_index = dentry2offset(new_dentry);
        int ret;
 
        simple_offset_remove(old_ctx, old_dentry);
@@ -354,9 +389,9 @@ int simple_offset_rename_exchange(struct inode *old_dir,
 
 out_restore:
        offset_set(old_dentry, old_index);
-       xa_store(&old_ctx->xa, old_index, old_dentry, GFP_KERNEL);
+       mtree_store(&old_ctx->mt, old_index, old_dentry, GFP_KERNEL);
        offset_set(new_dentry, new_index);
-       xa_store(&new_ctx->xa, new_index, new_dentry, GFP_KERNEL);
+       mtree_store(&new_ctx->mt, new_index, new_dentry, GFP_KERNEL);
        return ret;
 }
 
@@ -369,7 +404,7 @@ out_restore:
  */
 void simple_offset_destroy(struct offset_ctx *octx)
 {
-       xa_destroy(&octx->xa);
+       mtree_destroy(&octx->mt);
 }
 
 /**
@@ -399,15 +434,16 @@ static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence)
 
        /* In this case, ->private_data is protected by f_pos_lock */
        file->private_data = NULL;
-       return vfs_setpos(file, offset, U32_MAX);
+       return vfs_setpos(file, offset, LONG_MAX);
 }
 
-static struct dentry *offset_find_next(struct xa_state *xas)
+static struct dentry *offset_find_next(struct offset_ctx *octx, loff_t offset)
 {
+       MA_STATE(mas, &octx->mt, offset, offset);
        struct dentry *child, *found = NULL;
 
        rcu_read_lock();
-       child = xas_next_entry(xas, U32_MAX);
+       child = mas_find(&mas, LONG_MAX);
        if (!child)
                goto out;
        spin_lock(&child->d_lock);
@@ -421,8 +457,8 @@ out:
 
 static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry)
 {
-       u32 offset = dentry2offset(dentry);
        struct inode *inode = d_inode(dentry);
+       long offset = dentry2offset(dentry);
 
        return ctx->actor(ctx, dentry->d_name.name, dentry->d_name.len, offset,
                          inode->i_ino, fs_umode_to_dtype(inode->i_mode));
@@ -430,12 +466,11 @@ static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry)
 
 static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
 {
-       struct offset_ctx *so_ctx = inode->i_op->get_offset_ctx(inode);
-       XA_STATE(xas, &so_ctx->xa, ctx->pos);
+       struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode);
        struct dentry *dentry;
 
        while (true) {
-               dentry = offset_find_next(&xas);
+               dentry = offset_find_next(octx, ctx->pos);
                if (!dentry)
                        return ERR_PTR(-ENOENT);
 
@@ -444,8 +479,8 @@ static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
                        break;
                }
 
+               ctx->pos = dentry2offset(dentry) + 1;
                dput(dentry);
-               ctx->pos = xas.xa_index + 1;
        }
        return NULL;
 }
@@ -481,7 +516,7 @@ static int offset_readdir(struct file *file, struct dir_context *ctx)
                return 0;
 
        /* In this case, ->private_data is protected by f_pos_lock */
-       if (ctx->pos == 2)
+       if (ctx->pos == DIR_OFFSET_MIN)
                file->private_data = NULL;
        else if (file->private_data == ERR_PTR(-ENOENT))
                return 0;
@@ -1580,7 +1615,7 @@ EXPORT_SYMBOL(alloc_anon_inode);
  * All arguments are ignored and it just returns -EINVAL.
  */
 int
-simple_nosetlease(struct file *filp, int arg, struct file_lock **flp,
+simple_nosetlease(struct file *filp, int arg, struct file_lease **flp,
                  void **priv)
 {
        return -EINVAL;
@@ -1704,16 +1739,28 @@ bool is_empty_dir_inode(struct inode *inode)
 static int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
                                const char *str, const struct qstr *name)
 {
-       const struct dentry *parent = READ_ONCE(dentry->d_parent);
-       const struct inode *dir = READ_ONCE(parent->d_inode);
-       const struct super_block *sb = dentry->d_sb;
-       const struct unicode_map *um = sb->s_encoding;
-       struct qstr qstr = QSTR_INIT(str, len);
+       const struct dentry *parent;
+       const struct inode *dir;
        char strbuf[DNAME_INLINE_LEN];
-       int ret;
+       struct qstr qstr;
+
+       /*
+        * Attempt a case-sensitive match first. It is cheaper and
+        * should cover most lookups, including all the sane
+        * applications that expect a case-sensitive filesystem.
+        *
+        * This comparison is safe under RCU because the caller
+        * guarantees the consistency between str and len. See
+        * __d_lookup_rcu_op_compare() for details.
+        */
+       if (len == name->len && !memcmp(str, name->name, len))
+               return 0;
 
+       parent = READ_ONCE(dentry->d_parent);
+       dir = READ_ONCE(parent->d_inode);
        if (!dir || !IS_CASEFOLDED(dir))
-               goto fallback;
+               return 1;
+
        /*
         * If the dentry name is stored in-line, then it may be concurrently
         * modified by a rename.  If this happens, the VFS will eventually retry
@@ -1724,20 +1771,14 @@ static int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
        if (len <= DNAME_INLINE_LEN - 1) {
                memcpy(strbuf, str, len);
                strbuf[len] = 0;
-               qstr.name = strbuf;
+               str = strbuf;
                /* prevent compiler from optimizing out the temporary buffer */
                barrier();
        }
-       ret = utf8_strncasecmp(um, name, &qstr);
-       if (ret >= 0)
-               return ret;
+       qstr.len = len;
+       qstr.name = str;
 
-       if (sb_has_strict_encoding(sb))
-               return -EINVAL;
-fallback:
-       if (len != name->len)
-               return 1;
-       return !!memcmp(str, name->name, len);
+       return utf8_strncasecmp(dentry->d_sb->s_encoding, name, &qstr);
 }
 
 /**
@@ -1752,7 +1793,7 @@ static int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str)
        const struct inode *dir = READ_ONCE(dentry->d_inode);
        struct super_block *sb = dentry->d_sb;
        const struct unicode_map *um = sb->s_encoding;
-       int ret = 0;
+       int ret;
 
        if (!dir || !IS_CASEFOLDED(dir))
                return 0;
@@ -1766,73 +1807,45 @@ static int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str)
 static const struct dentry_operations generic_ci_dentry_ops = {
        .d_hash = generic_ci_d_hash,
        .d_compare = generic_ci_d_compare,
-};
-#endif
-
 #ifdef CONFIG_FS_ENCRYPTION
-static const struct dentry_operations generic_encrypted_dentry_ops = {
        .d_revalidate = fscrypt_d_revalidate,
+#endif
 };
 #endif
 
-#if defined(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_UNICODE)
-static const struct dentry_operations generic_encrypted_ci_dentry_ops = {
-       .d_hash = generic_ci_d_hash,
-       .d_compare = generic_ci_d_compare,
+#ifdef CONFIG_FS_ENCRYPTION
+static const struct dentry_operations generic_encrypted_dentry_ops = {
        .d_revalidate = fscrypt_d_revalidate,
 };
 #endif
 
 /**
- * generic_set_encrypted_ci_d_ops - helper for setting d_ops for given dentry
- * @dentry:    dentry to set ops on
- *
- * Casefolded directories need d_hash and d_compare set, so that the dentries
- * contained in them are handled case-insensitively.  Note that these operations
- * are needed on the parent directory rather than on the dentries in it, and
- * while the casefolding flag can be toggled on and off on an empty directory,
- * dentry_operations can't be changed later.  As a result, if the filesystem has
- * casefolding support enabled at all, we have to give all dentries the
- * casefolding operations even if their inode doesn't have the casefolding flag
- * currently (and thus the casefolding ops would be no-ops for now).
- *
- * Encryption works differently in that the only dentry operation it needs is
- * d_revalidate, which it only needs on dentries that have the no-key name flag.
- * The no-key flag can't be set "later", so we don't have to worry about that.
+ * generic_set_sb_d_ops - helper for choosing the set of
+ * filesystem-wide dentry operations for the enabled features
+ * @sb: superblock to be configured
  *
- * Finally, to maximize compatibility with overlayfs (which isn't compatible
- * with certain dentry operations) and to avoid taking an unnecessary
- * performance hit, we use custom dentry_operations for each possible
- * combination rather than always installing all operations.
+ * Filesystems supporting casefolding and/or fscrypt can call this
+ * helper at mount-time to configure sb->s_d_op to best set of dentry
+ * operations required for the enabled features. The helper must be
+ * called after these have been configured, but before the root dentry
+ * is created.
  */
-void generic_set_encrypted_ci_d_ops(struct dentry *dentry)
+void generic_set_sb_d_ops(struct super_block *sb)
 {
-#ifdef CONFIG_FS_ENCRYPTION
-       bool needs_encrypt_ops = dentry->d_flags & DCACHE_NOKEY_NAME;
-#endif
 #if IS_ENABLED(CONFIG_UNICODE)
-       bool needs_ci_ops = dentry->d_sb->s_encoding;
-#endif
-#if defined(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_UNICODE)
-       if (needs_encrypt_ops && needs_ci_ops) {
-               d_set_d_op(dentry, &generic_encrypted_ci_dentry_ops);
+       if (sb->s_encoding) {
+               sb->s_d_op = &generic_ci_dentry_ops;
                return;
        }
 #endif
 #ifdef CONFIG_FS_ENCRYPTION
-       if (needs_encrypt_ops) {
-               d_set_d_op(dentry, &generic_encrypted_dentry_ops);
-               return;
-       }
-#endif
-#if IS_ENABLED(CONFIG_UNICODE)
-       if (needs_ci_ops) {
-               d_set_d_op(dentry, &generic_ci_dentry_ops);
+       if (sb->s_cop) {
+               sb->s_d_op = &generic_encrypted_dentry_ops;
                return;
        }
 #endif
 }
-EXPORT_SYMBOL(generic_set_encrypted_ci_d_ops);
+EXPORT_SYMBOL(generic_set_sb_d_ops);
 
 /**
  * inode_maybe_inc_iversion - increments i_version
@@ -1973,3 +1986,144 @@ struct timespec64 simple_inode_init_ts(struct inode *inode)
        return ts;
 }
 EXPORT_SYMBOL(simple_inode_init_ts);
+
+static inline struct dentry *get_stashed_dentry(struct dentry *stashed)
+{
+       struct dentry *dentry;
+
+       guard(rcu)();
+       dentry = READ_ONCE(stashed);
+       if (!dentry)
+               return NULL;
+       if (!lockref_get_not_dead(&dentry->d_lockref))
+               return NULL;
+       return dentry;
+}
+
+static struct dentry *prepare_anon_dentry(struct dentry **stashed,
+                                         unsigned long ino,
+                                         struct super_block *sb,
+                                         void *data)
+{
+       struct dentry *dentry;
+       struct inode *inode;
+       const struct stashed_operations *sops = sb->s_fs_info;
+
+       dentry = d_alloc_anon(sb);
+       if (!dentry)
+               return ERR_PTR(-ENOMEM);
+
+       inode = new_inode_pseudo(sb);
+       if (!inode) {
+               dput(dentry);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       inode->i_ino = ino;
+       inode->i_flags |= S_IMMUTABLE;
+       inode->i_mode = S_IFREG;
+       simple_inode_init_ts(inode);
+       sops->init_inode(inode, data);
+
+       /* Notice when this is changed. */
+       WARN_ON_ONCE(!S_ISREG(inode->i_mode));
+       WARN_ON_ONCE(!IS_IMMUTABLE(inode));
+
+       /* Store address of location where dentry's supposed to be stashed. */
+       dentry->d_fsdata = stashed;
+
+       /* @data is now owned by the fs */
+       d_instantiate(dentry, inode);
+       return dentry;
+}
+
+static struct dentry *stash_dentry(struct dentry **stashed,
+                                  struct dentry *dentry)
+{
+       guard(rcu)();
+       for (;;) {
+               struct dentry *old;
+
+               /* Assume any old dentry was cleared out. */
+               old = cmpxchg(stashed, NULL, dentry);
+               if (likely(!old))
+                       return dentry;
+
+               /* Check if somebody else installed a reusable dentry. */
+               if (lockref_get_not_dead(&old->d_lockref))
+                       return old;
+
+               /* There's an old dead dentry there, try to take it over. */
+               if (likely(try_cmpxchg(stashed, &old, dentry)))
+                       return dentry;
+       }
+}
+
+/**
+ * path_from_stashed - create path from stashed or new dentry
+ * @stashed:    where to retrieve or stash dentry
+ * @ino:        inode number to use
+ * @mnt:        mnt of the filesystems to use
+ * @data:       data to store in inode->i_private
+ * @path:       path to create
+ *
+ * The function tries to retrieve a stashed dentry from @stashed. If the dentry
+ * is still valid then it will be reused. If the dentry isn't able the function
+ * will allocate a new dentry and inode. It will then check again whether it
+ * can reuse an existing dentry in case one has been added in the meantime or
+ * update @stashed with the newly added dentry.
+ *
+ * Special-purpose helper for nsfs and pidfs.
+ *
+ * Return: On success zero and on failure a negative error is returned.
+ */
+int path_from_stashed(struct dentry **stashed, unsigned long ino,
+                     struct vfsmount *mnt, void *data, struct path *path)
+{
+       struct dentry *dentry;
+       const struct stashed_operations *sops = mnt->mnt_sb->s_fs_info;
+
+       /* See if dentry can be reused. */
+       path->dentry = get_stashed_dentry(*stashed);
+       if (path->dentry) {
+               sops->put_data(data);
+               goto out_path;
+       }
+
+       /* Allocate a new dentry. */
+       dentry = prepare_anon_dentry(stashed, ino, mnt->mnt_sb, data);
+       if (IS_ERR(dentry)) {
+               sops->put_data(data);
+               return PTR_ERR(dentry);
+       }
+
+       /* Added a new dentry. @data is now owned by the filesystem. */
+       path->dentry = stash_dentry(stashed, dentry);
+       if (path->dentry != dentry)
+               dput(dentry);
+
+out_path:
+       WARN_ON_ONCE(path->dentry->d_fsdata != stashed);
+       WARN_ON_ONCE(d_inode(path->dentry)->i_private != data);
+       path->mnt = mntget(mnt);
+       return 0;
+}
+
+void stashed_dentry_prune(struct dentry *dentry)
+{
+       struct dentry **stashed = dentry->d_fsdata;
+       struct inode *inode = d_inode(dentry);
+
+       if (WARN_ON_ONCE(!stashed))
+               return;
+
+       if (!inode)
+               return;
+
+       /*
+        * Only replace our own @dentry as someone else might've
+        * already cleared out @dentry and stashed their own
+        * dentry in there.
+        */
+       cmpxchg(stashed, dentry, NULL);
+}
index 8161667c976f8c487de84ba9fcba189ae29072d9..527458db4525af3e76d9119feb6e5e5b62890741 100644 (file)
@@ -243,7 +243,7 @@ static void encode_nlm4_holder(struct xdr_stream *xdr,
        u64 l_offset, l_len;
        __be32 *p;
 
-       encode_bool(xdr, lock->fl.fl_type == F_RDLCK);
+       encode_bool(xdr, lock->fl.c.flc_type == F_RDLCK);
        encode_int32(xdr, lock->svid);
        encode_netobj(xdr, lock->oh.data, lock->oh.len);
 
@@ -270,7 +270,7 @@ static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result)
                goto out_overflow;
        exclusive = be32_to_cpup(p++);
        lock->svid = be32_to_cpup(p);
-       fl->fl_pid = (pid_t)lock->svid;
+       fl->c.flc_pid = (pid_t)lock->svid;
 
        error = decode_netobj(xdr, &lock->oh);
        if (unlikely(error))
@@ -280,8 +280,8 @@ static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result)
        if (unlikely(p == NULL))
                goto out_overflow;
 
-       fl->fl_flags = FL_POSIX;
-       fl->fl_type  = exclusive != 0 ? F_WRLCK : F_RDLCK;
+       fl->c.flc_flags = FL_POSIX;
+       fl->c.flc_type  = exclusive != 0 ? F_WRLCK : F_RDLCK;
        p = xdr_decode_hyper(p, &l_offset);
        xdr_decode_hyper(p, &l_len);
        nlm4svc_set_file_lock_range(fl, l_offset, l_len);
@@ -357,7 +357,7 @@ static void nlm4_xdr_enc_testargs(struct rpc_rqst *req,
        const struct nlm_lock *lock = &args->lock;
 
        encode_cookie(xdr, &args->cookie);
-       encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
+       encode_bool(xdr, lock->fl.c.flc_type == F_WRLCK);
        encode_nlm4_lock(xdr, lock);
 }
 
@@ -380,7 +380,7 @@ static void nlm4_xdr_enc_lockargs(struct rpc_rqst *req,
 
        encode_cookie(xdr, &args->cookie);
        encode_bool(xdr, args->block);
-       encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
+       encode_bool(xdr, lock->fl.c.flc_type == F_WRLCK);
        encode_nlm4_lock(xdr, lock);
        encode_bool(xdr, args->reclaim);
        encode_int32(xdr, args->state);
@@ -403,7 +403,7 @@ static void nlm4_xdr_enc_cancargs(struct rpc_rqst *req,
 
        encode_cookie(xdr, &args->cookie);
        encode_bool(xdr, args->block);
-       encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
+       encode_bool(xdr, lock->fl.c.flc_type == F_WRLCK);
        encode_nlm4_lock(xdr, lock);
 }
 
index 5d85715be763044ad2245815295567bcfb84c2d4..a7e0519ec024a9f73ca05d0d4a0ca29f22d0eb23 100644 (file)
@@ -185,7 +185,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
                        continue;
                if (!rpc_cmp_addr(nlm_addr(block->b_host), addr))
                        continue;
-               if (nfs_compare_fh(NFS_FH(file_inode(fl_blocked->fl_file)), fh) != 0)
+               if (nfs_compare_fh(NFS_FH(file_inode(fl_blocked->c.flc_file)), fh) != 0)
                        continue;
                /* Alright, we found a lock. Set the return status
                 * and wake up the caller
index fba6c7fa74747e9c411ed23917b744cc93c49ac3..cebcc283b7ce2e813944d9037de2a7462585a2c9 100644 (file)
@@ -133,7 +133,8 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
        char *nodename = req->a_host->h_rpcclnt->cl_nodename;
 
        nlmclnt_next_cookie(&argp->cookie);
-       memcpy(&lock->fh, NFS_FH(file_inode(fl->fl_file)), sizeof(struct nfs_fh));
+       memcpy(&lock->fh, NFS_FH(file_inode(fl->c.flc_file)),
+              sizeof(struct nfs_fh));
        lock->caller  = nodename;
        lock->oh.data = req->a_owner;
        lock->oh.len  = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
@@ -142,7 +143,7 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
        lock->svid = fl->fl_u.nfs_fl.owner->pid;
        lock->fl.fl_start = fl->fl_start;
        lock->fl.fl_end = fl->fl_end;
-       lock->fl.fl_type = fl->fl_type;
+       lock->fl.c.flc_type = fl->c.flc_type;
 }
 
 static void nlmclnt_release_lockargs(struct nlm_rqst *req)
@@ -182,7 +183,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl, void *dat
        call->a_callback_data = data;
 
        if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
-               if (fl->fl_type != F_UNLCK) {
+               if (fl->c.flc_type != F_UNLCK) {
                        call->a_args.block = IS_SETLKW(cmd) ? 1 : 0;
                        status = nlmclnt_lock(call, fl);
                } else
@@ -432,13 +433,14 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
 {
        int     status;
 
-       status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_TEST);
+       status = nlmclnt_call(nfs_file_cred(fl->c.flc_file), req,
+                             NLMPROC_TEST);
        if (status < 0)
                goto out;
 
        switch (req->a_res.status) {
                case nlm_granted:
-                       fl->fl_type = F_UNLCK;
+                       fl->c.flc_type = F_UNLCK;
                        break;
                case nlm_lck_denied:
                        /*
@@ -446,8 +448,8 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
                         */
                        fl->fl_start = req->a_res.lock.fl.fl_start;
                        fl->fl_end = req->a_res.lock.fl.fl_end;
-                       fl->fl_type = req->a_res.lock.fl.fl_type;
-                       fl->fl_pid = -req->a_res.lock.fl.fl_pid;
+                       fl->c.flc_type = req->a_res.lock.fl.c.flc_type;
+                       fl->c.flc_pid = -req->a_res.lock.fl.c.flc_pid;
                        break;
                default:
                        status = nlm_stat_to_errno(req->a_res.status);
@@ -485,14 +487,15 @@ static const struct file_lock_operations nlmclnt_lock_ops = {
 static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host)
 {
        fl->fl_u.nfs_fl.state = 0;
-       fl->fl_u.nfs_fl.owner = nlmclnt_find_lockowner(host, fl->fl_owner);
+       fl->fl_u.nfs_fl.owner = nlmclnt_find_lockowner(host,
+                                                      fl->c.flc_owner);
        INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list);
        fl->fl_ops = &nlmclnt_lock_ops;
 }
 
 static int do_vfs_lock(struct file_lock *fl)
 {
-       return locks_lock_file_wait(fl->fl_file, fl);
+       return locks_lock_file_wait(fl->c.flc_file, fl);
 }
 
 /*
@@ -518,12 +521,12 @@ static int do_vfs_lock(struct file_lock *fl)
 static int
 nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
 {
-       const struct cred *cred = nfs_file_cred(fl->fl_file);
+       const struct cred *cred = nfs_file_cred(fl->c.flc_file);
        struct nlm_host *host = req->a_host;
        struct nlm_res  *resp = &req->a_res;
        struct nlm_wait block;
-       unsigned char fl_flags = fl->fl_flags;
-       unsigned char fl_type;
+       unsigned char flags = fl->c.flc_flags;
+       unsigned char type;
        __be32 b_status;
        int status = -ENOLCK;
 
@@ -531,9 +534,9 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
                goto out;
        req->a_args.state = nsm_local_state;
 
-       fl->fl_flags |= FL_ACCESS;
+       fl->c.flc_flags |= FL_ACCESS;
        status = do_vfs_lock(fl);
-       fl->fl_flags = fl_flags;
+       fl->c.flc_flags = flags;
        if (status < 0)
                goto out;
 
@@ -591,11 +594,11 @@ again:
                        goto again;
                }
                /* Ensure the resulting lock will get added to granted list */
-               fl->fl_flags |= FL_SLEEP;
+               fl->c.flc_flags |= FL_SLEEP;
                if (do_vfs_lock(fl) < 0)
                        printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__);
                up_read(&host->h_rwsem);
-               fl->fl_flags = fl_flags;
+               fl->c.flc_flags = flags;
                status = 0;
        }
        if (status < 0)
@@ -605,7 +608,7 @@ again:
         * cases NLM_LCK_DENIED is returned for a permanent error.  So
         * turn it into an ENOLCK.
         */
-       if (resp->status == nlm_lck_denied && (fl_flags & FL_SLEEP))
+       if (resp->status == nlm_lck_denied && (flags & FL_SLEEP))
                status = -ENOLCK;
        else
                status = nlm_stat_to_errno(resp->status);
@@ -622,13 +625,13 @@ out_unlock:
                           req->a_host->h_addrlen, req->a_res.status);
        dprintk("lockd: lock attempt ended in fatal error.\n"
                "       Attempting to unlock.\n");
-       fl_type = fl->fl_type;
-       fl->fl_type = F_UNLCK;
+       type = fl->c.flc_type;
+       fl->c.flc_type = F_UNLCK;
        down_read(&host->h_rwsem);
        do_vfs_lock(fl);
        up_read(&host->h_rwsem);
-       fl->fl_type = fl_type;
-       fl->fl_flags = fl_flags;
+       fl->c.flc_type = type;
+       fl->c.flc_flags = flags;
        nlmclnt_async_call(cred, req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
        return status;
 }
@@ -651,12 +654,14 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl,
        nlmclnt_setlockargs(req, fl);
        req->a_args.reclaim = 1;
 
-       status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_LOCK);
+       status = nlmclnt_call(nfs_file_cred(fl->c.flc_file), req,
+                             NLMPROC_LOCK);
        if (status >= 0 && req->a_res.status == nlm_granted)
                return 0;
 
        printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d "
-                               "(errno %d, status %d)\n", fl->fl_pid,
+                               "(errno %d, status %d)\n",
+                               fl->c.flc_pid,
                                status, ntohl(req->a_res.status));
 
        /*
@@ -683,26 +688,26 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
        struct nlm_host *host = req->a_host;
        struct nlm_res  *resp = &req->a_res;
        int status;
-       unsigned char fl_flags = fl->fl_flags;
+       unsigned char flags = fl->c.flc_flags;
 
        /*
         * Note: the server is supposed to either grant us the unlock
         * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
         * case, we want to unlock.
         */
-       fl->fl_flags |= FL_EXISTS;
+       fl->c.flc_flags |= FL_EXISTS;
        down_read(&host->h_rwsem);
        status = do_vfs_lock(fl);
        up_read(&host->h_rwsem);
-       fl->fl_flags = fl_flags;
+       fl->c.flc_flags = flags;
        if (status == -ENOENT) {
                status = 0;
                goto out;
        }
 
        refcount_inc(&req->a_count);
-       status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req,
-                       NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
+       status = nlmclnt_async_call(nfs_file_cred(fl->c.flc_file), req,
+                                   NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
        if (status < 0)
                goto out;
 
@@ -795,8 +800,8 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl
        req->a_args.block = block;
 
        refcount_inc(&req->a_count);
-       status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req,
-                       NLMPROC_CANCEL, &nlmclnt_cancel_ops);
+       status = nlmclnt_async_call(nfs_file_cred(fl->c.flc_file), req,
+                                   NLMPROC_CANCEL, &nlmclnt_cancel_ops);
        if (status == 0 && req->a_res.status == nlm_lck_denied)
                status = -ENOLCK;
        nlmclnt_release_call(req);
index 4df62f6355295556a4efa65a7148ccc14334a975..a3e97278b997cfee94217ce3b83adbd0df5134f4 100644 (file)
@@ -238,7 +238,7 @@ static void encode_nlm_holder(struct xdr_stream *xdr,
        u32 l_offset, l_len;
        __be32 *p;
 
-       encode_bool(xdr, lock->fl.fl_type == F_RDLCK);
+       encode_bool(xdr, lock->fl.c.flc_type == F_RDLCK);
        encode_int32(xdr, lock->svid);
        encode_netobj(xdr, lock->oh.data, lock->oh.len);
 
@@ -265,7 +265,7 @@ static int decode_nlm_holder(struct xdr_stream *xdr, struct nlm_res *result)
                goto out_overflow;
        exclusive = be32_to_cpup(p++);
        lock->svid = be32_to_cpup(p);
-       fl->fl_pid = (pid_t)lock->svid;
+       fl->c.flc_pid = (pid_t)lock->svid;
 
        error = decode_netobj(xdr, &lock->oh);
        if (unlikely(error))
@@ -275,8 +275,8 @@ static int decode_nlm_holder(struct xdr_stream *xdr, struct nlm_res *result)
        if (unlikely(p == NULL))
                goto out_overflow;
 
-       fl->fl_flags = FL_POSIX;
-       fl->fl_type  = exclusive != 0 ? F_WRLCK : F_RDLCK;
+       fl->c.flc_flags = FL_POSIX;
+       fl->c.flc_type  = exclusive != 0 ? F_WRLCK : F_RDLCK;
        l_offset = be32_to_cpup(p++);
        l_len = be32_to_cpup(p);
        end = l_offset + l_len - 1;
@@ -357,7 +357,7 @@ static void nlm_xdr_enc_testargs(struct rpc_rqst *req,
        const struct nlm_lock *lock = &args->lock;
 
        encode_cookie(xdr, &args->cookie);
-       encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
+       encode_bool(xdr, lock->fl.c.flc_type == F_WRLCK);
        encode_nlm_lock(xdr, lock);
 }
 
@@ -380,7 +380,7 @@ static void nlm_xdr_enc_lockargs(struct rpc_rqst *req,
 
        encode_cookie(xdr, &args->cookie);
        encode_bool(xdr, args->block);
-       encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
+       encode_bool(xdr, lock->fl.c.flc_type == F_WRLCK);
        encode_nlm_lock(xdr, lock);
        encode_bool(xdr, args->reclaim);
        encode_int32(xdr, args->state);
@@ -403,7 +403,7 @@ static void nlm_xdr_enc_cancargs(struct rpc_rqst *req,
 
        encode_cookie(xdr, &args->cookie);
        encode_bool(xdr, args->block);
-       encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
+       encode_bool(xdr, lock->fl.c.flc_type == F_WRLCK);
        encode_nlm_lock(xdr, lock);
 }
 
index b72023a6b4c16d9fbdb4d9c0021d93e732bbc99b..8a72c418cdcc09b5172532964c0cbe8bc7eeda3a 100644 (file)
@@ -52,16 +52,16 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
                *filp = file;
 
                /* Set up the missing parts of the file_lock structure */
-               lock->fl.fl_flags = FL_POSIX;
-               lock->fl.fl_file  = file->f_file[mode];
-               lock->fl.fl_pid = current->tgid;
+               lock->fl.c.flc_flags = FL_POSIX;
+               lock->fl.c.flc_file  = file->f_file[mode];
+               lock->fl.c.flc_pid = current->tgid;
                lock->fl.fl_start = (loff_t)lock->lock_start;
                lock->fl.fl_end = lock->lock_len ?
                                   (loff_t)(lock->lock_start + lock->lock_len - 1) :
                                   OFFSET_MAX;
                lock->fl.fl_lmops = &nlmsvc_lock_operations;
                nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid);
-               if (!lock->fl.fl_owner) {
+               if (!lock->fl.c.flc_owner) {
                        /* lockowner allocation has failed */
                        nlmsvc_release_host(host);
                        return nlm_lck_denied_nolocks;
@@ -106,7 +106,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
        if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
-       test_owner = argp->lock.fl.fl_owner;
+       test_owner = argp->lock.fl.c.flc_owner;
        /* Now check for conflicting locks */
        resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie);
        if (resp->status == nlm_drop_reply)
index 2dc10900ad1c335415e1ee43f9310d18a79dacc7..1f2149db10f2469562fce16af291246dbeae9ee6 100644 (file)
@@ -150,16 +150,17 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
        struct file_lock        *fl;
 
        dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
-                               file, lock->fl.fl_pid,
+                               file, lock->fl.c.flc_pid,
                                (long long)lock->fl.fl_start,
-                               (long long)lock->fl.fl_end, lock->fl.fl_type);
+                               (long long)lock->fl.fl_end,
+                               lock->fl.c.flc_type);
        spin_lock(&nlm_blocked_lock);
        list_for_each_entry(block, &nlm_blocked, b_list) {
                fl = &block->b_call->a_args.lock.fl;
                dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
-                               block->b_file, fl->fl_pid,
+                               block->b_file, fl->c.flc_pid,
                                (long long)fl->fl_start,
-                               (long long)fl->fl_end, fl->fl_type,
+                               (long long)fl->fl_end, fl->c.flc_type,
                                nlmdbg_cookie2a(&block->b_call->a_args.cookie));
                if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
                        kref_get(&block->b_count);
@@ -244,7 +245,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_host *host,
                goto failed_free;
 
        /* Set notifier function for VFS, and init args */
-       call->a_args.lock.fl.fl_flags |= FL_SLEEP;
+       call->a_args.lock.fl.c.flc_flags |= FL_SLEEP;
        call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
        nlmclnt_next_cookie(&call->a_args.cookie);
 
@@ -402,14 +403,14 @@ static struct nlm_lockowner *nlmsvc_find_lockowner(struct nlm_host *host, pid_t
 void
 nlmsvc_release_lockowner(struct nlm_lock *lock)
 {
-       if (lock->fl.fl_owner)
-               nlmsvc_put_lockowner(lock->fl.fl_owner);
+       if (lock->fl.c.flc_owner)
+               nlmsvc_put_lockowner(lock->fl.c.flc_owner);
 }
 
 void nlmsvc_locks_init_private(struct file_lock *fl, struct nlm_host *host,
                                                pid_t pid)
 {
-       fl->fl_owner = nlmsvc_find_lockowner(host, pid);
+       fl->c.flc_owner = nlmsvc_find_lockowner(host, pid);
 }
 
 /*
@@ -425,7 +426,7 @@ static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
 
        /* set default data area */
        call->a_args.lock.oh.data = call->a_owner;
-       call->a_args.lock.svid = ((struct nlm_lockowner *)lock->fl.fl_owner)->pid;
+       call->a_args.lock.svid = ((struct nlm_lockowner *) lock->fl.c.flc_owner)->pid;
 
        if (lock->oh.len > NLMCLNT_OHSIZE) {
                void *data = kmalloc(lock->oh.len, GFP_KERNEL);
@@ -489,7 +490,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
 
        dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
                                inode->i_sb->s_id, inode->i_ino,
-                               lock->fl.fl_type, lock->fl.fl_pid,
+                               lock->fl.c.flc_type,
+                               lock->fl.c.flc_pid,
                                (long long)lock->fl.fl_start,
                                (long long)lock->fl.fl_end,
                                wait);
@@ -512,7 +514,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
                        goto out;
                lock = &block->b_call->a_args.lock;
        } else
-               lock->fl.fl_flags &= ~FL_SLEEP;
+               lock->fl.c.flc_flags &= ~FL_SLEEP;
 
        if (block->b_flags & B_QUEUED) {
                dprintk("lockd: nlmsvc_lock deferred block %p flags %d\n",
@@ -560,10 +562,10 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
        spin_unlock(&nlm_blocked_lock);
 
        if (!wait)
-               lock->fl.fl_flags &= ~FL_SLEEP;
+               lock->fl.c.flc_flags &= ~FL_SLEEP;
        mode = lock_to_openmode(&lock->fl);
        error = vfs_lock_file(file->f_file[mode], F_SETLK, &lock->fl, NULL);
-       lock->fl.fl_flags &= ~FL_SLEEP;
+       lock->fl.c.flc_flags &= ~FL_SLEEP;
 
        dprintk("lockd: vfs_lock_file returned %d\n", error);
        switch (error) {
@@ -616,7 +618,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
        dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
                                nlmsvc_file_inode(file)->i_sb->s_id,
                                nlmsvc_file_inode(file)->i_ino,
-                               lock->fl.fl_type,
+                               lock->fl.c.flc_type,
                                (long long)lock->fl.fl_start,
                                (long long)lock->fl.fl_end);
 
@@ -636,19 +638,19 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
                goto out;
        }
 
-       if (lock->fl.fl_type == F_UNLCK) {
+       if (lock->fl.c.flc_type == F_UNLCK) {
                ret = nlm_granted;
                goto out;
        }
 
        dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
-               lock->fl.fl_type, (long long)lock->fl.fl_start,
+               lock->fl.c.flc_type, (long long)lock->fl.fl_start,
                (long long)lock->fl.fl_end);
        conflock->caller = "somehost";  /* FIXME */
        conflock->len = strlen(conflock->caller);
        conflock->oh.len = 0;           /* don't return OH info */
-       conflock->svid = lock->fl.fl_pid;
-       conflock->fl.fl_type = lock->fl.fl_type;
+       conflock->svid = lock->fl.c.flc_pid;
+       conflock->fl.c.flc_type = lock->fl.c.flc_type;
        conflock->fl.fl_start = lock->fl.fl_start;
        conflock->fl.fl_end = lock->fl.fl_end;
        locks_release_private(&lock->fl);
@@ -673,21 +675,21 @@ nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
        dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n",
                                nlmsvc_file_inode(file)->i_sb->s_id,
                                nlmsvc_file_inode(file)->i_ino,
-                               lock->fl.fl_pid,
+                               lock->fl.c.flc_pid,
                                (long long)lock->fl.fl_start,
                                (long long)lock->fl.fl_end);
 
        /* First, cancel any lock that might be there */
        nlmsvc_cancel_blocked(net, file, lock);
 
-       lock->fl.fl_type = F_UNLCK;
-       lock->fl.fl_file = file->f_file[O_RDONLY];
-       if (lock->fl.fl_file)
-               error = vfs_lock_file(lock->fl.fl_file, F_SETLK,
+       lock->fl.c.flc_type = F_UNLCK;
+       lock->fl.c.flc_file = file->f_file[O_RDONLY];
+       if (lock->fl.c.flc_file)
+               error = vfs_lock_file(lock->fl.c.flc_file, F_SETLK,
                                        &lock->fl, NULL);
-       lock->fl.fl_file = file->f_file[O_WRONLY];
-       if (lock->fl.fl_file)
-               error |= vfs_lock_file(lock->fl.fl_file, F_SETLK,
+       lock->fl.c.flc_file = file->f_file[O_WRONLY];
+       if (lock->fl.c.flc_file)
+               error |= vfs_lock_file(lock->fl.c.flc_file, F_SETLK,
                                        &lock->fl, NULL);
 
        return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
@@ -710,7 +712,7 @@ nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *l
        dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n",
                                nlmsvc_file_inode(file)->i_sb->s_id,
                                nlmsvc_file_inode(file)->i_ino,
-                               lock->fl.fl_pid,
+                               lock->fl.c.flc_pid,
                                (long long)lock->fl.fl_start,
                                (long long)lock->fl.fl_end);
 
@@ -863,12 +865,12 @@ nlmsvc_grant_blocked(struct nlm_block *block)
        /* vfs_lock_file() can mangle fl_start and fl_end, but we need
         * them unchanged for the GRANT_MSG
         */
-       lock->fl.fl_flags |= FL_SLEEP;
+       lock->fl.c.flc_flags |= FL_SLEEP;
        fl_start = lock->fl.fl_start;
        fl_end = lock->fl.fl_end;
        mode = lock_to_openmode(&lock->fl);
        error = vfs_lock_file(file->f_file[mode], F_SETLK, &lock->fl, NULL);
-       lock->fl.fl_flags &= ~FL_SLEEP;
+       lock->fl.c.flc_flags &= ~FL_SLEEP;
        lock->fl.fl_start = fl_start;
        lock->fl.fl_end = fl_end;
 
@@ -993,8 +995,8 @@ nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
                /* Client doesn't want it, just unlock it */
                nlmsvc_unlink_block(block);
                fl = &block->b_call->a_args.lock.fl;
-               fl->fl_type = F_UNLCK;
-               error = vfs_lock_file(fl->fl_file, F_SETLK, fl, NULL);
+               fl->c.flc_type = F_UNLCK;
+               error = vfs_lock_file(fl->c.flc_file, F_SETLK, fl, NULL);
                if (error)
                        pr_warn("lockd: unable to unlock lock rejected by client!\n");
                break;
index 32784f508c8106313a4b1e7728b56e22bcd857b7..a03220e66ce02fe9a7b2a5fcfb56293df97e6f24 100644 (file)
@@ -77,12 +77,12 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
 
                /* Set up the missing parts of the file_lock structure */
                mode = lock_to_openmode(&lock->fl);
-               lock->fl.fl_flags = FL_POSIX;
-               lock->fl.fl_file  = file->f_file[mode];
-               lock->fl.fl_pid = current->tgid;
+               lock->fl.c.flc_flags = FL_POSIX;
+               lock->fl.c.flc_file  = file->f_file[mode];
+               lock->fl.c.flc_pid = current->tgid;
                lock->fl.fl_lmops = &nlmsvc_lock_operations;
                nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid);
-               if (!lock->fl.fl_owner) {
+               if (!lock->fl.c.flc_owner) {
                        /* lockowner allocation has failed */
                        nlmsvc_release_host(host);
                        return nlm_lck_denied_nolocks;
@@ -127,7 +127,7 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
        if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
-       test_owner = argp->lock.fl.fl_owner;
+       test_owner = argp->lock.fl.c.flc_owner;
 
        /* Now check for conflicting locks */
        resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie));
index e3b6229e7ae5cdd807198a47bbb8e8546a6ff3ba..9103896164f6886eec5adf65a55f4c29433dcb29 100644 (file)
@@ -73,7 +73,7 @@ static inline unsigned int file_hash(struct nfs_fh *f)
 
 int lock_to_openmode(struct file_lock *lock)
 {
-       return (lock->fl_type == F_WRLCK) ? O_WRONLY : O_RDONLY;
+       return lock_is_write(lock) ? O_WRONLY : O_RDONLY;
 }
 
 /*
@@ -181,18 +181,18 @@ static int nlm_unlock_files(struct nlm_file *file, const struct file_lock *fl)
        struct file_lock lock;
 
        locks_init_lock(&lock);
-       lock.fl_type  = F_UNLCK;
+       lock.c.flc_type  = F_UNLCK;
        lock.fl_start = 0;
        lock.fl_end   = OFFSET_MAX;
-       lock.fl_owner = fl->fl_owner;
-       lock.fl_pid   = fl->fl_pid;
-       lock.fl_flags = FL_POSIX;
+       lock.c.flc_owner = fl->c.flc_owner;
+       lock.c.flc_pid   = fl->c.flc_pid;
+       lock.c.flc_flags = FL_POSIX;
 
-       lock.fl_file = file->f_file[O_RDONLY];
-       if (lock.fl_file && vfs_lock_file(lock.fl_file, F_SETLK, &lock, NULL))
+       lock.c.flc_file = file->f_file[O_RDONLY];
+       if (lock.c.flc_file && vfs_lock_file(lock.c.flc_file, F_SETLK, &lock, NULL))
                goto out_err;
-       lock.fl_file = file->f_file[O_WRONLY];
-       if (lock.fl_file && vfs_lock_file(lock.fl_file, F_SETLK, &lock, NULL))
+       lock.c.flc_file = file->f_file[O_WRONLY];
+       if (lock.c.flc_file && vfs_lock_file(lock.c.flc_file, F_SETLK, &lock, NULL))
                goto out_err;
        return 0;
 out_err:
@@ -218,14 +218,14 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
 again:
        file->f_locks = 0;
        spin_lock(&flctx->flc_lock);
-       list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
+       for_each_file_lock(fl, &flctx->flc_posix) {
                if (fl->fl_lmops != &nlmsvc_lock_operations)
                        continue;
 
                /* update current lock count */
                file->f_locks++;
 
-               lockhost = ((struct nlm_lockowner *)fl->fl_owner)->host;
+               lockhost = ((struct nlm_lockowner *) fl->c.flc_owner)->host;
                if (match(lockhost, host)) {
 
                        spin_unlock(&flctx->flc_lock);
@@ -272,7 +272,7 @@ nlm_file_inuse(struct nlm_file *file)
 
        if (flctx && !list_empty_careful(&flctx->flc_posix)) {
                spin_lock(&flctx->flc_lock);
-               list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
+               for_each_file_lock(fl, &flctx->flc_posix) {
                        if (fl->fl_lmops == &nlmsvc_lock_operations) {
                                spin_unlock(&flctx->flc_lock);
                                return 1;
index 2fb5748dae0c808bfc55f1435cf6e79350357cd9..adfcce2bf11ba7081d5748f3978c43f13a922e49 100644 (file)
@@ -88,8 +88,8 @@ svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
                return false;
 
        locks_init_lock(fl);
-       fl->fl_flags = FL_POSIX;
-       fl->fl_type  = F_RDLCK;
+       fl->c.flc_flags = FL_POSIX;
+       fl->c.flc_type  = F_RDLCK;
        end = start + len - 1;
        fl->fl_start = s32_to_loff_t(start);
        if (len == 0 || end < 0)
@@ -107,7 +107,7 @@ svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock)
        s32 start, len;
 
        /* exclusive */
-       if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0)
+       if (xdr_stream_encode_bool(xdr, fl->c.flc_type != F_RDLCK) < 0)
                return false;
        if (xdr_stream_encode_u32(xdr, lock->svid) < 0)
                return false;
@@ -164,7 +164,7 @@ nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
        if (!svcxdr_decode_lock(xdr, &argp->lock))
                return false;
        if (exclusive)
-               argp->lock.fl.fl_type = F_WRLCK;
+               argp->lock.fl.c.flc_type = F_WRLCK;
 
        return true;
 }
@@ -184,7 +184,7 @@ nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
        if (!svcxdr_decode_lock(xdr, &argp->lock))
                return false;
        if (exclusive)
-               argp->lock.fl.fl_type = F_WRLCK;
+               argp->lock.fl.c.flc_type = F_WRLCK;
        if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
                return false;
        if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
@@ -209,7 +209,7 @@ nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
        if (!svcxdr_decode_lock(xdr, &argp->lock))
                return false;
        if (exclusive)
-               argp->lock.fl.fl_type = F_WRLCK;
+               argp->lock.fl.c.flc_type = F_WRLCK;
 
        return true;
 }
@@ -223,7 +223,7 @@ nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
                return false;
        if (!svcxdr_decode_lock(xdr, &argp->lock))
                return false;
-       argp->lock.fl.fl_type = F_UNLCK;
+       argp->lock.fl.c.flc_type = F_UNLCK;
 
        return true;
 }
index 5fcbf30cd275928d1d364cf63e4f39fb61cb2a5a..3d28b9c3ed1509a262cff891f0e1630791b9fcba 100644 (file)
@@ -89,8 +89,8 @@ svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
                return false;
 
        locks_init_lock(fl);
-       fl->fl_flags = FL_POSIX;
-       fl->fl_type  = F_RDLCK;
+       fl->c.flc_flags = FL_POSIX;
+       fl->c.flc_type  = F_RDLCK;
        nlm4svc_set_file_lock_range(fl, lock->lock_start, lock->lock_len);
        return true;
 }
@@ -102,7 +102,7 @@ svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock)
        s64 start, len;
 
        /* exclusive */
-       if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0)
+       if (xdr_stream_encode_bool(xdr, fl->c.flc_type != F_RDLCK) < 0)
                return false;
        if (xdr_stream_encode_u32(xdr, lock->svid) < 0)
                return false;
@@ -159,7 +159,7 @@ nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
        if (!svcxdr_decode_lock(xdr, &argp->lock))
                return false;
        if (exclusive)
-               argp->lock.fl.fl_type = F_WRLCK;
+               argp->lock.fl.c.flc_type = F_WRLCK;
 
        return true;
 }
@@ -179,7 +179,7 @@ nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
        if (!svcxdr_decode_lock(xdr, &argp->lock))
                return false;
        if (exclusive)
-               argp->lock.fl.fl_type = F_WRLCK;
+               argp->lock.fl.c.flc_type = F_WRLCK;
        if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
                return false;
        if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
@@ -204,7 +204,7 @@ nlm4svc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
        if (!svcxdr_decode_lock(xdr, &argp->lock))
                return false;
        if (exclusive)
-               argp->lock.fl.fl_type = F_WRLCK;
+               argp->lock.fl.c.flc_type = F_WRLCK;
 
        return true;
 }
@@ -218,7 +218,7 @@ nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
                return false;
        if (!svcxdr_decode_lock(xdr, &argp->lock))
                return false;
-       argp->lock.fl.fl_type = F_UNLCK;
+       argp->lock.fl.c.flc_type = F_UNLCK;
 
        return true;
 }
index cc7c117ee19294410b02333638ba5f810b0cdadd..90c8746874dedbbb71e14b8269bbbcd216fd1bf7 100644 (file)
@@ -48,7 +48,6 @@
  * children.
  *
  */
-
 #include <linux/capability.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
 
 #include <linux/uaccess.h>
 
-#define IS_POSIX(fl)   (fl->fl_flags & FL_POSIX)
-#define IS_FLOCK(fl)   (fl->fl_flags & FL_FLOCK)
-#define IS_LEASE(fl)   (fl->fl_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT))
-#define IS_OFDLCK(fl)  (fl->fl_flags & FL_OFDLCK)
-#define IS_REMOTELCK(fl)       (fl->fl_pid <= 0)
+static struct file_lock *file_lock(struct file_lock_core *flc)
+{
+       return container_of(flc, struct file_lock, c);
+}
+
+static struct file_lease *file_lease(struct file_lock_core *flc)
+{
+       return container_of(flc, struct file_lease, c);
+}
 
-static bool lease_breaking(struct file_lock *fl)
+static bool lease_breaking(struct file_lease *fl)
 {
-       return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING);
+       return fl->c.flc_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING);
 }
 
-static int target_leasetype(struct file_lock *fl)
+static int target_leasetype(struct file_lease *fl)
 {
-       if (fl->fl_flags & FL_UNLOCK_PENDING)
+       if (fl->c.flc_flags & FL_UNLOCK_PENDING)
                return F_UNLCK;
-       if (fl->fl_flags & FL_DOWNGRADE_PENDING)
+       if (fl->c.flc_flags & FL_DOWNGRADE_PENDING)
                return F_RDLCK;
-       return fl->fl_type;
+       return fl->c.flc_type;
 }
 
 static int leases_enable = 1;
@@ -168,6 +171,7 @@ static DEFINE_SPINLOCK(blocked_lock_lock);
 
 static struct kmem_cache *flctx_cache __ro_after_init;
 static struct kmem_cache *filelock_cache __ro_after_init;
+static struct kmem_cache *filelease_cache __ro_after_init;
 
 static struct file_lock_context *
 locks_get_lock_context(struct inode *inode, int type)
@@ -204,11 +208,12 @@ out:
 static void
 locks_dump_ctx_list(struct list_head *list, char *list_type)
 {
-       struct file_lock *fl;
+       struct file_lock_core *flc;
 
-       list_for_each_entry(fl, list, fl_list) {
-               pr_warn("%s: fl_owner=%p fl_flags=0x%x fl_type=0x%x fl_pid=%u\n", list_type, fl->fl_owner, fl->fl_flags, fl->fl_type, fl->fl_pid);
-       }
+       list_for_each_entry(flc, list, flc_list)
+               pr_warn("%s: fl_owner=%p fl_flags=0x%x fl_type=0x%x fl_pid=%u\n",
+                       list_type, flc->flc_owner, flc->flc_flags,
+                       flc->flc_type, flc->flc_pid);
 }
 
 static void
@@ -229,19 +234,19 @@ locks_check_ctx_lists(struct inode *inode)
 }
 
 static void
-locks_check_ctx_file_list(struct file *filp, struct list_head *list,
-                               char *list_type)
+locks_check_ctx_file_list(struct file *filp, struct list_head *list, char *list_type)
 {
-       struct file_lock *fl;
+       struct file_lock_core *flc;
        struct inode *inode = file_inode(filp);
 
-       list_for_each_entry(fl, list, fl_list)
-               if (fl->fl_file == filp)
+       list_for_each_entry(flc, list, flc_list)
+               if (flc->flc_file == filp)
                        pr_warn("Leaked %s lock on dev=0x%x:0x%x ino=0x%lx "
                                " fl_owner=%p fl_flags=0x%x fl_type=0x%x fl_pid=%u\n",
                                list_type, MAJOR(inode->i_sb->s_dev),
                                MINOR(inode->i_sb->s_dev), inode->i_ino,
-                               fl->fl_owner, fl->fl_flags, fl->fl_type, fl->fl_pid);
+                               flc->flc_owner, flc->flc_flags,
+                               flc->flc_type, flc->flc_pid);
 }
 
 void
@@ -255,13 +260,13 @@ locks_free_lock_context(struct inode *inode)
        }
 }
 
-static void locks_init_lock_heads(struct file_lock *fl)
+static void locks_init_lock_heads(struct file_lock_core *flc)
 {
-       INIT_HLIST_NODE(&fl->fl_link);
-       INIT_LIST_HEAD(&fl->fl_list);
-       INIT_LIST_HEAD(&fl->fl_blocked_requests);
-       INIT_LIST_HEAD(&fl->fl_blocked_member);
-       init_waitqueue_head(&fl->fl_wait);
+       INIT_HLIST_NODE(&flc->flc_link);
+       INIT_LIST_HEAD(&flc->flc_list);
+       INIT_LIST_HEAD(&flc->flc_blocked_requests);
+       INIT_LIST_HEAD(&flc->flc_blocked_member);
+       init_waitqueue_head(&flc->flc_wait);
 }
 
 /* Allocate an empty lock structure. */
@@ -270,19 +275,33 @@ struct file_lock *locks_alloc_lock(void)
        struct file_lock *fl = kmem_cache_zalloc(filelock_cache, GFP_KERNEL);
 
        if (fl)
-               locks_init_lock_heads(fl);
+               locks_init_lock_heads(&fl->c);
 
        return fl;
 }
 EXPORT_SYMBOL_GPL(locks_alloc_lock);
 
+/* Allocate an empty lock structure. */
+struct file_lease *locks_alloc_lease(void)
+{
+       struct file_lease *fl = kmem_cache_zalloc(filelease_cache, GFP_KERNEL);
+
+       if (fl)
+               locks_init_lock_heads(&fl->c);
+
+       return fl;
+}
+EXPORT_SYMBOL_GPL(locks_alloc_lease);
+
 void locks_release_private(struct file_lock *fl)
 {
-       BUG_ON(waitqueue_active(&fl->fl_wait));
-       BUG_ON(!list_empty(&fl->fl_list));
-       BUG_ON(!list_empty(&fl->fl_blocked_requests));
-       BUG_ON(!list_empty(&fl->fl_blocked_member));
-       BUG_ON(!hlist_unhashed(&fl->fl_link));
+       struct file_lock_core *flc = &fl->c;
+
+       BUG_ON(waitqueue_active(&flc->flc_wait));
+       BUG_ON(!list_empty(&flc->flc_list));
+       BUG_ON(!list_empty(&flc->flc_blocked_requests));
+       BUG_ON(!list_empty(&flc->flc_blocked_member));
+       BUG_ON(!hlist_unhashed(&flc->flc_link));
 
        if (fl->fl_ops) {
                if (fl->fl_ops->fl_release_private)
@@ -292,8 +311,8 @@ void locks_release_private(struct file_lock *fl)
 
        if (fl->fl_lmops) {
                if (fl->fl_lmops->lm_put_owner) {
-                       fl->fl_lmops->lm_put_owner(fl->fl_owner);
-                       fl->fl_owner = NULL;
+                       fl->fl_lmops->lm_put_owner(flc->flc_owner);
+                       flc->flc_owner = NULL;
                }
                fl->fl_lmops = NULL;
        }
@@ -309,16 +328,15 @@ EXPORT_SYMBOL_GPL(locks_release_private);
  *   %true: @owner has at least one blocker
  *   %false: @owner has no blockers
  */
-bool locks_owner_has_blockers(struct file_lock_context *flctx,
-               fl_owner_t owner)
+bool locks_owner_has_blockers(struct file_lock_context *flctx, fl_owner_t owner)
 {
-       struct file_lock *fl;
+       struct file_lock_core *flc;
 
        spin_lock(&flctx->flc_lock);
-       list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
-               if (fl->fl_owner != owner)
+       list_for_each_entry(flc, &flctx->flc_posix, flc_list) {
+               if (flc->flc_owner != owner)
                        continue;
-               if (!list_empty(&fl->fl_blocked_requests)) {
+               if (!list_empty(&flc->flc_blocked_requests)) {
                        spin_unlock(&flctx->flc_lock);
                        return true;
                }
@@ -336,35 +354,52 @@ void locks_free_lock(struct file_lock *fl)
 }
 EXPORT_SYMBOL(locks_free_lock);
 
+/* Free a lease which is not in use. */
+void locks_free_lease(struct file_lease *fl)
+{
+       kmem_cache_free(filelease_cache, fl);
+}
+EXPORT_SYMBOL(locks_free_lease);
+
 static void
 locks_dispose_list(struct list_head *dispose)
 {
-       struct file_lock *fl;
+       struct file_lock_core *flc;
 
        while (!list_empty(dispose)) {
-               fl = list_first_entry(dispose, struct file_lock, fl_list);
-               list_del_init(&fl->fl_list);
-               locks_free_lock(fl);
+               flc = list_first_entry(dispose, struct file_lock_core, flc_list);
+               list_del_init(&flc->flc_list);
+               if (flc->flc_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT))
+                       locks_free_lease(file_lease(flc));
+               else
+                       locks_free_lock(file_lock(flc));
        }
 }
 
 void locks_init_lock(struct file_lock *fl)
 {
        memset(fl, 0, sizeof(struct file_lock));
-       locks_init_lock_heads(fl);
+       locks_init_lock_heads(&fl->c);
 }
 EXPORT_SYMBOL(locks_init_lock);
 
+void locks_init_lease(struct file_lease *fl)
+{
+       memset(fl, 0, sizeof(*fl));
+       locks_init_lock_heads(&fl->c);
+}
+EXPORT_SYMBOL(locks_init_lease);
+
 /*
  * Initialize a new lock from an existing file_lock structure.
  */
 void locks_copy_conflock(struct file_lock *new, struct file_lock *fl)
 {
-       new->fl_owner = fl->fl_owner;
-       new->fl_pid = fl->fl_pid;
-       new->fl_file = NULL;
-       new->fl_flags = fl->fl_flags;
-       new->fl_type = fl->fl_type;
+       new->c.flc_owner = fl->c.flc_owner;
+       new->c.flc_pid = fl->c.flc_pid;
+       new->c.flc_file = NULL;
+       new->c.flc_flags = fl->c.flc_flags;
+       new->c.flc_type = fl->c.flc_type;
        new->fl_start = fl->fl_start;
        new->fl_end = fl->fl_end;
        new->fl_lmops = fl->fl_lmops;
@@ -372,7 +407,7 @@ void locks_copy_conflock(struct file_lock *new, struct file_lock *fl)
 
        if (fl->fl_lmops) {
                if (fl->fl_lmops->lm_get_owner)
-                       fl->fl_lmops->lm_get_owner(fl->fl_owner);
+                       fl->fl_lmops->lm_get_owner(fl->c.flc_owner);
        }
 }
 EXPORT_SYMBOL(locks_copy_conflock);
@@ -384,7 +419,7 @@ void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
 
        locks_copy_conflock(new, fl);
 
-       new->fl_file = fl->fl_file;
+       new->c.flc_file = fl->c.flc_file;
        new->fl_ops = fl->fl_ops;
 
        if (fl->fl_ops) {
@@ -400,15 +435,17 @@ static void locks_move_blocks(struct file_lock *new, struct file_lock *fl)
 
        /*
         * As ctx->flc_lock is held, new requests cannot be added to
-        * ->fl_blocked_requests, so we don't need a lock to check if it
+        * ->flc_blocked_requests, so we don't need a lock to check if it
         * is empty.
         */
-       if (list_empty(&fl->fl_blocked_requests))
+       if (list_empty(&fl->c.flc_blocked_requests))
                return;
        spin_lock(&blocked_lock_lock);
-       list_splice_init(&fl->fl_blocked_requests, &new->fl_blocked_requests);
-       list_for_each_entry(f, &new->fl_blocked_requests, fl_blocked_member)
-               f->fl_blocker = new;
+       list_splice_init(&fl->c.flc_blocked_requests,
+                        &new->c.flc_blocked_requests);
+       list_for_each_entry(f, &new->c.flc_blocked_requests,
+                           c.flc_blocked_member)
+               f->c.flc_blocker = &new->c;
        spin_unlock(&blocked_lock_lock);
 }
 
@@ -429,21 +466,21 @@ static void flock_make_lock(struct file *filp, struct file_lock *fl, int type)
 {
        locks_init_lock(fl);
 
-       fl->fl_file = filp;
-       fl->fl_owner = filp;
-       fl->fl_pid = current->tgid;
-       fl->fl_flags = FL_FLOCK;
-       fl->fl_type = type;
+       fl->c.flc_file = filp;
+       fl->c.flc_owner = filp;
+       fl->c.flc_pid = current->tgid;
+       fl->c.flc_flags = FL_FLOCK;
+       fl->c.flc_type = type;
        fl->fl_end = OFFSET_MAX;
 }
 
-static int assign_type(struct file_lock *fl, int type)
+static int assign_type(struct file_lock_core *flc, int type)
 {
        switch (type) {
        case F_RDLCK:
        case F_WRLCK:
        case F_UNLCK:
-               fl->fl_type = type;
+               flc->flc_type = type;
                break;
        default:
                return -EINVAL;
@@ -488,14 +525,14 @@ static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl,
        } else
                fl->fl_end = OFFSET_MAX;
 
-       fl->fl_owner = current->files;
-       fl->fl_pid = current->tgid;
-       fl->fl_file = filp;
-       fl->fl_flags = FL_POSIX;
+       fl->c.flc_owner = current->files;
+       fl->c.flc_pid = current->tgid;
+       fl->c.flc_file = filp;
+       fl->c.flc_flags = FL_POSIX;
        fl->fl_ops = NULL;
        fl->fl_lmops = NULL;
 
-       return assign_type(fl, l->l_type);
+       return assign_type(&fl->c, l->l_type);
 }
 
 /* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
@@ -516,16 +553,16 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
 
 /* default lease lock manager operations */
 static bool
-lease_break_callback(struct file_lock *fl)
+lease_break_callback(struct file_lease *fl)
 {
        kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
        return false;
 }
 
 static void
-lease_setup(struct file_lock *fl, void **priv)
+lease_setup(struct file_lease *fl, void **priv)
 {
-       struct file *filp = fl->fl_file;
+       struct file *filp = fl->c.flc_file;
        struct fasync_struct *fa = *priv;
 
        /*
@@ -539,7 +576,7 @@ lease_setup(struct file_lock *fl, void **priv)
        __f_setown(filp, task_pid(current), PIDTYPE_TGID, 0);
 }
 
-static const struct lock_manager_operations lease_manager_ops = {
+static const struct lease_manager_operations lease_manager_ops = {
        .lm_break = lease_break_callback,
        .lm_change = lease_modify,
        .lm_setup = lease_setup,
@@ -548,27 +585,24 @@ static const struct lock_manager_operations lease_manager_ops = {
 /*
  * Initialize a lease, use the default lock manager operations
  */
-static int lease_init(struct file *filp, int type, struct file_lock *fl)
+static int lease_init(struct file *filp, int type, struct file_lease *fl)
 {
-       if (assign_type(fl, type) != 0)
+       if (assign_type(&fl->c, type) != 0)
                return -EINVAL;
 
-       fl->fl_owner = filp;
-       fl->fl_pid = current->tgid;
+       fl->c.flc_owner = filp;
+       fl->c.flc_pid = current->tgid;
 
-       fl->fl_file = filp;
-       fl->fl_flags = FL_LEASE;
-       fl->fl_start = 0;
-       fl->fl_end = OFFSET_MAX;
-       fl->fl_ops = NULL;
+       fl->c.flc_file = filp;
+       fl->c.flc_flags = FL_LEASE;
        fl->fl_lmops = &lease_manager_ops;
        return 0;
 }
 
 /* Allocate a file_lock initialised to this type of lease */
-static struct file_lock *lease_alloc(struct file *filp, int type)
+static struct file_lease *lease_alloc(struct file *filp, int type)
 {
-       struct file_lock *fl = locks_alloc_lock();
+       struct file_lease *fl = locks_alloc_lease();
        int error = -ENOMEM;
 
        if (fl == NULL)
@@ -576,7 +610,7 @@ static struct file_lock *lease_alloc(struct file *filp, int type)
 
        error = lease_init(filp, type, fl);
        if (error) {
-               locks_free_lock(fl);
+               locks_free_lease(fl);
                return ERR_PTR(error);
        }
        return fl;
@@ -593,26 +627,26 @@ static inline int locks_overlap(struct file_lock *fl1, struct file_lock *fl2)
 /*
  * Check whether two locks have the same owner.
  */
-static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
+static int posix_same_owner(struct file_lock_core *fl1, struct file_lock_core *fl2)
 {
-       return fl1->fl_owner == fl2->fl_owner;
+       return fl1->flc_owner == fl2->flc_owner;
 }
 
 /* Must be called with the flc_lock held! */
-static void locks_insert_global_locks(struct file_lock *fl)
+static void locks_insert_global_locks(struct file_lock_core *flc)
 {
        struct file_lock_list_struct *fll = this_cpu_ptr(&file_lock_list);
 
        percpu_rwsem_assert_held(&file_rwsem);
 
        spin_lock(&fll->lock);
-       fl->fl_link_cpu = smp_processor_id();
-       hlist_add_head(&fl->fl_link, &fll->hlist);
+       flc->flc_link_cpu = smp_processor_id();
+       hlist_add_head(&flc->flc_link, &fll->hlist);
        spin_unlock(&fll->lock);
 }
 
 /* Must be called with the flc_lock held! */
-static void locks_delete_global_locks(struct file_lock *fl)
+static void locks_delete_global_locks(struct file_lock_core *flc)
 {
        struct file_lock_list_struct *fll;
 
@@ -623,33 +657,33 @@ static void locks_delete_global_locks(struct file_lock *fl)
         * is done while holding the flc_lock, and new insertions into the list
         * also require that it be held.
         */
-       if (hlist_unhashed(&fl->fl_link))
+       if (hlist_unhashed(&flc->flc_link))
                return;
 
-       fll = per_cpu_ptr(&file_lock_list, fl->fl_link_cpu);
+       fll = per_cpu_ptr(&file_lock_list, flc->flc_link_cpu);
        spin_lock(&fll->lock);
-       hlist_del_init(&fl->fl_link);
+       hlist_del_init(&flc->flc_link);
        spin_unlock(&fll->lock);
 }
 
 static unsigned long
-posix_owner_key(struct file_lock *fl)
+posix_owner_key(struct file_lock_core *flc)
 {
-       return (unsigned long)fl->fl_owner;
+       return (unsigned long) flc->flc_owner;
 }
 
-static void locks_insert_global_blocked(struct file_lock *waiter)
+static void locks_insert_global_blocked(struct file_lock_core *waiter)
 {
        lockdep_assert_held(&blocked_lock_lock);
 
-       hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter));
+       hash_add(blocked_hash, &waiter->flc_link, posix_owner_key(waiter));
 }
 
-static void locks_delete_global_blocked(struct file_lock *waiter)
+static void locks_delete_global_blocked(struct file_lock_core *waiter)
 {
        lockdep_assert_held(&blocked_lock_lock);
 
-       hash_del(&waiter->fl_link);
+       hash_del(&waiter->flc_link);
 }
 
 /* Remove waiter from blocker's block list.
@@ -657,41 +691,39 @@ static void locks_delete_global_blocked(struct file_lock *waiter)
  *
  * Must be called with blocked_lock_lock held.
  */
-static void __locks_delete_block(struct file_lock *waiter)
+static void __locks_unlink_block(struct file_lock_core *waiter)
 {
        locks_delete_global_blocked(waiter);
-       list_del_init(&waiter->fl_blocked_member);
+       list_del_init(&waiter->flc_blocked_member);
 }
 
-static void __locks_wake_up_blocks(struct file_lock *blocker)
+static void __locks_wake_up_blocks(struct file_lock_core *blocker)
 {
-       while (!list_empty(&blocker->fl_blocked_requests)) {
-               struct file_lock *waiter;
+       while (!list_empty(&blocker->flc_blocked_requests)) {
+               struct file_lock_core *waiter;
+               struct file_lock *fl;
 
-               waiter = list_first_entry(&blocker->fl_blocked_requests,
-                                         struct file_lock, fl_blocked_member);
-               __locks_delete_block(waiter);
-               if (waiter->fl_lmops && waiter->fl_lmops->lm_notify)
-                       waiter->fl_lmops->lm_notify(waiter);
+               waiter = list_first_entry(&blocker->flc_blocked_requests,
+                                         struct file_lock_core, flc_blocked_member);
+
+               fl = file_lock(waiter);
+               __locks_unlink_block(waiter);
+               if ((waiter->flc_flags & (FL_POSIX | FL_FLOCK)) &&
+                   fl->fl_lmops && fl->fl_lmops->lm_notify)
+                       fl->fl_lmops->lm_notify(fl);
                else
-                       wake_up(&waiter->fl_wait);
+                       locks_wake_up(fl);
 
                /*
-                * The setting of fl_blocker to NULL marks the "done"
+                * The setting of flc_blocker to NULL marks the "done"
                 * point in deleting a block. Paired with acquire at the top
                 * of locks_delete_block().
                 */
-               smp_store_release(&waiter->fl_blocker, NULL);
+               smp_store_release(&waiter->flc_blocker, NULL);
        }
 }
 
-/**
- *     locks_delete_block - stop waiting for a file lock
- *     @waiter: the lock which was waiting
- *
- *     lockd/nfsd need to disconnect the lock while working on it.
- */
-int locks_delete_block(struct file_lock *waiter)
+static int __locks_delete_block(struct file_lock_core *waiter)
 {
        int status = -ENOENT;
 
@@ -716,24 +748,35 @@ int locks_delete_block(struct file_lock *waiter)
         * no new locks can be inserted into its fl_blocked_requests list, and
         * can avoid doing anything further if the list is empty.
         */
-       if (!smp_load_acquire(&waiter->fl_blocker) &&
-           list_empty(&waiter->fl_blocked_requests))
+       if (!smp_load_acquire(&waiter->flc_blocker) &&
+           list_empty(&waiter->flc_blocked_requests))
                return status;
 
        spin_lock(&blocked_lock_lock);
-       if (waiter->fl_blocker)
+       if (waiter->flc_blocker)
                status = 0;
        __locks_wake_up_blocks(waiter);
-       __locks_delete_block(waiter);
+       __locks_unlink_block(waiter);
 
        /*
         * The setting of fl_blocker to NULL marks the "done" point in deleting
         * a block. Paired with acquire at the top of this function.
         */
-       smp_store_release(&waiter->fl_blocker, NULL);
+       smp_store_release(&waiter->flc_blocker, NULL);
        spin_unlock(&blocked_lock_lock);
        return status;
 }
+
+/**
+ *     locks_delete_block - stop waiting for a file lock
+ *     @waiter: the lock which was waiting
+ *
+ *     lockd/nfsd need to disconnect the lock while working on it.
+ */
+int locks_delete_block(struct file_lock *waiter)
+{
+       return __locks_delete_block(&waiter->c);
+}
 EXPORT_SYMBOL(locks_delete_block);
 
 /* Insert waiter into blocker's block list.
@@ -751,26 +794,28 @@ EXPORT_SYMBOL(locks_delete_block);
  * waiters, and add beneath any waiter that blocks the new waiter.
  * Thus wakeups don't happen until needed.
  */
-static void __locks_insert_block(struct file_lock *blocker,
-                                struct file_lock *waiter,
-                                bool conflict(struct file_lock *,
-                                              struct file_lock *))
+static void __locks_insert_block(struct file_lock_core *blocker,
+                                struct file_lock_core *waiter,
+                                bool conflict(struct file_lock_core *,
+                                              struct file_lock_core *))
 {
-       struct file_lock *fl;
-       BUG_ON(!list_empty(&waiter->fl_blocked_member));
+       struct file_lock_core *flc;
 
+       BUG_ON(!list_empty(&waiter->flc_blocked_member));
 new_blocker:
-       list_for_each_entry(fl, &blocker->fl_blocked_requests, fl_blocked_member)
-               if (conflict(fl, waiter)) {
-                       blocker =  fl;
+       list_for_each_entry(flc, &blocker->flc_blocked_requests, flc_blocked_member)
+               if (conflict(flc, waiter)) {
+                       blocker =  flc;
                        goto new_blocker;
                }
-       waiter->fl_blocker = blocker;
-       list_add_tail(&waiter->fl_blocked_member, &blocker->fl_blocked_requests);
-       if (IS_POSIX(blocker) && !IS_OFDLCK(blocker))
+       waiter->flc_blocker = blocker;
+       list_add_tail(&waiter->flc_blocked_member,
+                     &blocker->flc_blocked_requests);
+
+       if ((blocker->flc_flags & (FL_POSIX|FL_OFDLCK)) == FL_POSIX)
                locks_insert_global_blocked(waiter);
 
-       /* The requests in waiter->fl_blocked are known to conflict with
+       /* The requests in waiter->flc_blocked are known to conflict with
         * waiter, but might not conflict with blocker, or the requests
         * and lock which block it.  So they all need to be woken.
         */
@@ -778,10 +823,10 @@ new_blocker:
 }
 
 /* Must be called with flc_lock held. */
-static void locks_insert_block(struct file_lock *blocker,
-                              struct file_lock *waiter,
-                              bool conflict(struct file_lock *,
-                                            struct file_lock *))
+static void locks_insert_block(struct file_lock_core *blocker,
+                              struct file_lock_core *waiter,
+                              bool conflict(struct file_lock_core *,
+                                            struct file_lock_core *))
 {
        spin_lock(&blocked_lock_lock);
        __locks_insert_block(blocker, waiter, conflict);
@@ -793,7 +838,7 @@ static void locks_insert_block(struct file_lock *blocker,
  *
  * Must be called with the inode->flc_lock held!
  */
-static void locks_wake_up_blocks(struct file_lock *blocker)
+static void locks_wake_up_blocks(struct file_lock_core *blocker)
 {
        /*
         * Avoid taking global lock if list is empty. This is safe since new
@@ -802,7 +847,7 @@ static void locks_wake_up_blocks(struct file_lock *blocker)
         * fl_blocked_requests list does not require the flc_lock, so we must
         * recheck list_empty() after acquiring the blocked_lock_lock.
         */
-       if (list_empty(&blocker->fl_blocked_requests))
+       if (list_empty(&blocker->flc_blocked_requests))
                return;
 
        spin_lock(&blocked_lock_lock);
@@ -811,39 +856,39 @@ static void locks_wake_up_blocks(struct file_lock *blocker)
 }
 
 static void
-locks_insert_lock_ctx(struct file_lock *fl, struct list_head *before)
+locks_insert_lock_ctx(struct file_lock_core *fl, struct list_head *before)
 {
-       list_add_tail(&fl->fl_list, before);
+       list_add_tail(&fl->flc_list, before);
        locks_insert_global_locks(fl);
 }
 
 static void
-locks_unlink_lock_ctx(struct file_lock *fl)
+locks_unlink_lock_ctx(struct file_lock_core *fl)
 {
        locks_delete_global_locks(fl);
-       list_del_init(&fl->fl_list);
+       list_del_init(&fl->flc_list);
        locks_wake_up_blocks(fl);
 }
 
 static void
-locks_delete_lock_ctx(struct file_lock *fl, struct list_head *dispose)
+locks_delete_lock_ctx(struct file_lock_core *fl, struct list_head *dispose)
 {
        locks_unlink_lock_ctx(fl);
        if (dispose)
-               list_add(&fl->fl_list, dispose);
+               list_add(&fl->flc_list, dispose);
        else
-               locks_free_lock(fl);
+               locks_free_lock(file_lock(fl));
 }
 
 /* Determine if lock sys_fl blocks lock caller_fl. Common functionality
  * checks for shared/exclusive status of overlapping locks.
  */
-static bool locks_conflict(struct file_lock *caller_fl,
-                          struct file_lock *sys_fl)
+static bool locks_conflict(struct file_lock_core *caller_flc,
+                          struct file_lock_core *sys_flc)
 {
-       if (sys_fl->fl_type == F_WRLCK)
+       if (sys_flc->flc_type == F_WRLCK)
                return true;
-       if (caller_fl->fl_type == F_WRLCK)
+       if (caller_flc->flc_type == F_WRLCK)
                return true;
        return false;
 }
@@ -851,20 +896,23 @@ static bool locks_conflict(struct file_lock *caller_fl,
 /* Determine if lock sys_fl blocks lock caller_fl. POSIX specific
  * checking before calling the locks_conflict().
  */
-static bool posix_locks_conflict(struct file_lock *caller_fl,
-                                struct file_lock *sys_fl)
+static bool posix_locks_conflict(struct file_lock_core *caller_flc,
+                                struct file_lock_core *sys_flc)
 {
+       struct file_lock *caller_fl = file_lock(caller_flc);
+       struct file_lock *sys_fl = file_lock(sys_flc);
+
        /* POSIX locks owned by the same process do not conflict with
         * each other.
         */
-       if (posix_same_owner(caller_fl, sys_fl))
+       if (posix_same_owner(caller_flc, sys_flc))
                return false;
 
        /* Check whether they overlap */
        if (!locks_overlap(caller_fl, sys_fl))
                return false;
 
-       return locks_conflict(caller_fl, sys_fl);
+       return locks_conflict(caller_flc, sys_flc);
 }
 
 /* Determine if lock sys_fl blocks lock caller_fl. Used on xx_GETLK
@@ -873,28 +921,31 @@ static bool posix_locks_conflict(struct file_lock *caller_fl,
 static bool posix_test_locks_conflict(struct file_lock *caller_fl,
                                      struct file_lock *sys_fl)
 {
+       struct file_lock_core *caller = &caller_fl->c;
+       struct file_lock_core *sys = &sys_fl->c;
+
        /* F_UNLCK checks any locks on the same fd. */
-       if (caller_fl->fl_type == F_UNLCK) {
-               if (!posix_same_owner(caller_fl, sys_fl))
+       if (lock_is_unlock(caller_fl)) {
+               if (!posix_same_owner(caller, sys))
                        return false;
                return locks_overlap(caller_fl, sys_fl);
        }
-       return posix_locks_conflict(caller_fl, sys_fl);
+       return posix_locks_conflict(caller, sys);
 }
 
 /* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific
  * checking before calling the locks_conflict().
  */
-static bool flock_locks_conflict(struct file_lock *caller_fl,
-                                struct file_lock *sys_fl)
+static bool flock_locks_conflict(struct file_lock_core *caller_flc,
+                                struct file_lock_core *sys_flc)
 {
        /* FLOCK locks referring to the same filp do not conflict with
         * each other.
         */
-       if (caller_fl->fl_file == sys_fl->fl_file)
+       if (caller_flc->flc_file == sys_flc->flc_file)
                return false;
 
-       return locks_conflict(caller_fl, sys_fl);
+       return locks_conflict(caller_flc, sys_flc);
 }
 
 void
@@ -908,13 +959,13 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
 
        ctx = locks_inode_context(inode);
        if (!ctx || list_empty_careful(&ctx->flc_posix)) {
-               fl->fl_type = F_UNLCK;
+               fl->c.flc_type = F_UNLCK;
                return;
        }
 
 retry:
        spin_lock(&ctx->flc_lock);
-       list_for_each_entry(cfl, &ctx->flc_posix, fl_list) {
+       list_for_each_entry(cfl, &ctx->flc_posix, c.flc_list) {
                if (!posix_test_locks_conflict(fl, cfl))
                        continue;
                if (cfl->fl_lmops && cfl->fl_lmops->lm_lock_expirable
@@ -930,7 +981,7 @@ retry:
                locks_copy_conflock(fl, cfl);
                goto out;
        }
-       fl->fl_type = F_UNLCK;
+       fl->c.flc_type = F_UNLCK;
 out:
        spin_unlock(&ctx->flc_lock);
        return;
@@ -972,25 +1023,27 @@ EXPORT_SYMBOL(posix_test_lock);
 
 #define MAX_DEADLK_ITERATIONS 10
 
-/* Find a lock that the owner of the given block_fl is blocking on. */
-static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl)
+/* Find a lock that the owner of the given @blocker is blocking on. */
+static struct file_lock_core *what_owner_is_waiting_for(struct file_lock_core *blocker)
 {
-       struct file_lock *fl;
+       struct file_lock_core *flc;
 
-       hash_for_each_possible(blocked_hash, fl, fl_link, posix_owner_key(block_fl)) {
-               if (posix_same_owner(fl, block_fl)) {
-                       while (fl->fl_blocker)
-                               fl = fl->fl_blocker;
-                       return fl;
+       hash_for_each_possible(blocked_hash, flc, flc_link, posix_owner_key(blocker)) {
+               if (posix_same_owner(flc, blocker)) {
+                       while (flc->flc_blocker)
+                               flc = flc->flc_blocker;
+                       return flc;
                }
        }
        return NULL;
 }
 
 /* Must be called with the blocked_lock_lock held! */
-static int posix_locks_deadlock(struct file_lock *caller_fl,
-                               struct file_lock *block_fl)
+static bool posix_locks_deadlock(struct file_lock *caller_fl,
+                                struct file_lock *block_fl)
 {
+       struct file_lock_core *caller = &caller_fl->c;
+       struct file_lock_core *blocker = &block_fl->c;
        int i = 0;
 
        lockdep_assert_held(&blocked_lock_lock);
@@ -999,16 +1052,16 @@ static int posix_locks_deadlock(struct file_lock *caller_fl,
         * This deadlock detector can't reasonably detect deadlocks with
         * FL_OFDLCK locks, since they aren't owned by a process, per-se.
         */
-       if (IS_OFDLCK(caller_fl))
-               return 0;
+       if (caller->flc_flags & FL_OFDLCK)
+               return false;
 
-       while ((block_fl = what_owner_is_waiting_for(block_fl))) {
+       while ((blocker = what_owner_is_waiting_for(blocker))) {
                if (i++ > MAX_DEADLK_ITERATIONS)
-                       return 0;
-               if (posix_same_owner(caller_fl, block_fl))
-                       return 1;
+                       return false;
+               if (posix_same_owner(caller, blocker))
+                       return true;
        }
-       return 0;
+       return false;
 }
 
 /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
@@ -1027,14 +1080,14 @@ static int flock_lock_inode(struct inode *inode, struct file_lock *request)
        bool found = false;
        LIST_HEAD(dispose);
 
-       ctx = locks_get_lock_context(inode, request->fl_type);
+       ctx = locks_get_lock_context(inode, request->c.flc_type);
        if (!ctx) {
-               if (request->fl_type != F_UNLCK)
+               if (request->c.flc_type != F_UNLCK)
                        return -ENOMEM;
-               return (request->fl_flags & FL_EXISTS) ? -ENOENT : 0;
+               return (request->c.flc_flags & FL_EXISTS) ? -ENOENT : 0;
        }
 
-       if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) {
+       if (!(request->c.flc_flags & FL_ACCESS) && (request->c.flc_type != F_UNLCK)) {
                new_fl = locks_alloc_lock();
                if (!new_fl)
                        return -ENOMEM;
@@ -1042,41 +1095,41 @@ static int flock_lock_inode(struct inode *inode, struct file_lock *request)
 
        percpu_down_read(&file_rwsem);
        spin_lock(&ctx->flc_lock);
-       if (request->fl_flags & FL_ACCESS)
+       if (request->c.flc_flags & FL_ACCESS)
                goto find_conflict;
 
-       list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
-               if (request->fl_file != fl->fl_file)
+       list_for_each_entry(fl, &ctx->flc_flock, c.flc_list) {
+               if (request->c.flc_file != fl->c.flc_file)
                        continue;
-               if (request->fl_type == fl->fl_type)
+               if (request->c.flc_type == fl->c.flc_type)
                        goto out;
                found = true;
-               locks_delete_lock_ctx(fl, &dispose);
+               locks_delete_lock_ctx(&fl->c, &dispose);
                break;
        }
 
-       if (request->fl_type == F_UNLCK) {
-               if ((request->fl_flags & FL_EXISTS) && !found)
+       if (lock_is_unlock(request)) {
+               if ((request->c.flc_flags & FL_EXISTS) && !found)
                        error = -ENOENT;
                goto out;
        }
 
 find_conflict:
-       list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
-               if (!flock_locks_conflict(request, fl))
+       list_for_each_entry(fl, &ctx->flc_flock, c.flc_list) {
+               if (!flock_locks_conflict(&request->c, &fl->c))
                        continue;
                error = -EAGAIN;
-               if (!(request->fl_flags & FL_SLEEP))
+               if (!(request->c.flc_flags & FL_SLEEP))
                        goto out;
                error = FILE_LOCK_DEFERRED;
-               locks_insert_block(fl, request, flock_locks_conflict);
+               locks_insert_block(&fl->c, &request->c, flock_locks_conflict);
                goto out;
        }
-       if (request->fl_flags & FL_ACCESS)
+       if (request->c.flc_flags & FL_ACCESS)
                goto out;
        locks_copy_lock(new_fl, request);
        locks_move_blocks(new_fl, request);
-       locks_insert_lock_ctx(new_fl, &ctx->flc_flock);
+       locks_insert_lock_ctx(&new_fl->c, &ctx->flc_flock);
        new_fl = NULL;
        error = 0;
 
@@ -1105,9 +1158,9 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request,
        void *owner;
        void (*func)(void);
 
-       ctx = locks_get_lock_context(inode, request->fl_type);
+       ctx = locks_get_lock_context(inode, request->c.flc_type);
        if (!ctx)
-               return (request->fl_type == F_UNLCK) ? 0 : -ENOMEM;
+               return lock_is_unlock(request) ? 0 : -ENOMEM;
 
        /*
         * We may need two file_lock structures for this operation,
@@ -1115,8 +1168,8 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request,
         *
         * In some cases we can be sure, that no new locks will be needed
         */
-       if (!(request->fl_flags & FL_ACCESS) &&
-           (request->fl_type != F_UNLCK ||
+       if (!(request->c.flc_flags & FL_ACCESS) &&
+           (request->c.flc_type != F_UNLCK ||
             request->fl_start != 0 || request->fl_end != OFFSET_MAX)) {
                new_fl = locks_alloc_lock();
                new_fl2 = locks_alloc_lock();
@@ -1130,9 +1183,9 @@ retry:
         * there are any, either return error or put the request on the
         * blocker's list of waiters and the global blocked_hash.
         */
-       if (request->fl_type != F_UNLCK) {
-               list_for_each_entry(fl, &ctx->flc_posix, fl_list) {
-                       if (!posix_locks_conflict(request, fl))
+       if (request->c.flc_type != F_UNLCK) {
+               list_for_each_entry(fl, &ctx->flc_posix, c.flc_list) {
+                       if (!posix_locks_conflict(&request->c, &fl->c))
                                continue;
                        if (fl->fl_lmops && fl->fl_lmops->lm_lock_expirable
                                && (*fl->fl_lmops->lm_lock_expirable)(fl)) {
@@ -1148,7 +1201,7 @@ retry:
                        if (conflock)
                                locks_copy_conflock(conflock, fl);
                        error = -EAGAIN;
-                       if (!(request->fl_flags & FL_SLEEP))
+                       if (!(request->c.flc_flags & FL_SLEEP))
                                goto out;
                        /*
                         * Deadlock detection and insertion into the blocked
@@ -1160,10 +1213,10 @@ retry:
                         * Ensure that we don't find any locks blocked on this
                         * request during deadlock detection.
                         */
-                       __locks_wake_up_blocks(request);
+                       __locks_wake_up_blocks(&request->c);
                        if (likely(!posix_locks_deadlock(request, fl))) {
                                error = FILE_LOCK_DEFERRED;
-                               __locks_insert_block(fl, request,
+                               __locks_insert_block(&fl->c, &request->c,
                                                     posix_locks_conflict);
                        }
                        spin_unlock(&blocked_lock_lock);
@@ -1173,22 +1226,22 @@ retry:
 
        /* If we're just looking for a conflict, we're done. */
        error = 0;
-       if (request->fl_flags & FL_ACCESS)
+       if (request->c.flc_flags & FL_ACCESS)
                goto out;
 
        /* Find the first old lock with the same owner as the new lock */
-       list_for_each_entry(fl, &ctx->flc_posix, fl_list) {
-               if (posix_same_owner(request, fl))
+       list_for_each_entry(fl, &ctx->flc_posix, c.flc_list) {
+               if (posix_same_owner(&request->c, &fl->c))
                        break;
        }
 
        /* Process locks with this owner. */
-       list_for_each_entry_safe_from(fl, tmp, &ctx->flc_posix, fl_list) {
-               if (!posix_same_owner(request, fl))
+       list_for_each_entry_safe_from(fl, tmp, &ctx->flc_posix, c.flc_list) {
+               if (!posix_same_owner(&request->c, &fl->c))
                        break;
 
                /* Detect adjacent or overlapping regions (if same lock type) */
-               if (request->fl_type == fl->fl_type) {
+               if (request->c.flc_type == fl->c.flc_type) {
                        /* In all comparisons of start vs end, use
                         * "start - 1" rather than "end + 1". If end
                         * is OFFSET_MAX, end + 1 will become negative.
@@ -1215,7 +1268,7 @@ retry:
                        else
                                request->fl_end = fl->fl_end;
                        if (added) {
-                               locks_delete_lock_ctx(fl, &dispose);
+                               locks_delete_lock_ctx(&fl->c, &dispose);
                                continue;
                        }
                        request = fl;
@@ -1228,7 +1281,7 @@ retry:
                                continue;
                        if (fl->fl_start > request->fl_end)
                                break;
-                       if (request->fl_type == F_UNLCK)
+                       if (lock_is_unlock(request))
                                added = true;
                        if (fl->fl_start < request->fl_start)
                                left = fl;
@@ -1244,7 +1297,7 @@ retry:
                                 * one (This may happen several times).
                                 */
                                if (added) {
-                                       locks_delete_lock_ctx(fl, &dispose);
+                                       locks_delete_lock_ctx(&fl->c, &dispose);
                                        continue;
                                }
                                /*
@@ -1261,8 +1314,9 @@ retry:
                                locks_move_blocks(new_fl, request);
                                request = new_fl;
                                new_fl = NULL;
-                               locks_insert_lock_ctx(request, &fl->fl_list);
-                               locks_delete_lock_ctx(fl, &dispose);
+                               locks_insert_lock_ctx(&request->c,
+                                                     &fl->c.flc_list);
+                               locks_delete_lock_ctx(&fl->c, &dispose);
                                added = true;
                        }
                }
@@ -1279,8 +1333,8 @@ retry:
 
        error = 0;
        if (!added) {
-               if (request->fl_type == F_UNLCK) {
-                       if (request->fl_flags & FL_EXISTS)
+               if (lock_is_unlock(request)) {
+                       if (request->c.flc_flags & FL_EXISTS)
                                error = -ENOENT;
                        goto out;
                }
@@ -1291,7 +1345,7 @@ retry:
                }
                locks_copy_lock(new_fl, request);
                locks_move_blocks(new_fl, request);
-               locks_insert_lock_ctx(new_fl, &fl->fl_list);
+               locks_insert_lock_ctx(&new_fl->c, &fl->c.flc_list);
                fl = new_fl;
                new_fl = NULL;
        }
@@ -1303,14 +1357,14 @@ retry:
                        left = new_fl2;
                        new_fl2 = NULL;
                        locks_copy_lock(left, right);
-                       locks_insert_lock_ctx(left, &fl->fl_list);
+                       locks_insert_lock_ctx(&left->c, &fl->c.flc_list);
                }
                right->fl_start = request->fl_end + 1;
-               locks_wake_up_blocks(right);
+               locks_wake_up_blocks(&right->c);
        }
        if (left) {
                left->fl_end = request->fl_start - 1;
-               locks_wake_up_blocks(left);
+               locks_wake_up_blocks(&left->c);
        }
  out:
        spin_unlock(&ctx->flc_lock);
@@ -1364,8 +1418,8 @@ static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
                error = posix_lock_inode(inode, fl, NULL);
                if (error != FILE_LOCK_DEFERRED)
                        break;
-               error = wait_event_interruptible(fl->fl_wait,
-                                       list_empty(&fl->fl_blocked_member));
+               error = wait_event_interruptible(fl->c.flc_wait,
+                                                list_empty(&fl->c.flc_blocked_member));
                if (error)
                        break;
        }
@@ -1373,37 +1427,37 @@ static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
        return error;
 }
 
-static void lease_clear_pending(struct file_lock *fl, int arg)
+static void lease_clear_pending(struct file_lease *fl, int arg)
 {
        switch (arg) {
        case F_UNLCK:
-               fl->fl_flags &= ~FL_UNLOCK_PENDING;
+               fl->c.flc_flags &= ~FL_UNLOCK_PENDING;
                fallthrough;
        case F_RDLCK:
-               fl->fl_flags &= ~FL_DOWNGRADE_PENDING;
+               fl->c.flc_flags &= ~FL_DOWNGRADE_PENDING;
        }
 }
 
 /* We already had a lease on this file; just change its type */
-int lease_modify(struct file_lock *fl, int arg, struct list_head *dispose)
+int lease_modify(struct file_lease *fl, int arg, struct list_head *dispose)
 {
-       int error = assign_type(fl, arg);
+       int error = assign_type(&fl->c, arg);
 
        if (error)
                return error;
        lease_clear_pending(fl, arg);
-       locks_wake_up_blocks(fl);
+       locks_wake_up_blocks(&fl->c);
        if (arg == F_UNLCK) {
-               struct file *filp = fl->fl_file;
+               struct file *filp = fl->c.flc_file;
 
                f_delown(filp);
                filp->f_owner.signum = 0;
-               fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
+               fasync_helper(0, fl->c.flc_file, 0, &fl->fl_fasync);
                if (fl->fl_fasync != NULL) {
                        printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
                        fl->fl_fasync = NULL;
                }
-               locks_delete_lock_ctx(fl, dispose);
+               locks_delete_lock_ctx(&fl->c, dispose);
        }
        return 0;
 }
@@ -1420,11 +1474,11 @@ static bool past_time(unsigned long then)
 static void time_out_leases(struct inode *inode, struct list_head *dispose)
 {
        struct file_lock_context *ctx = inode->i_flctx;
-       struct file_lock *fl, *tmp;
+       struct file_lease *fl, *tmp;
 
        lockdep_assert_held(&ctx->flc_lock);
 
-       list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) {
+       list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, c.flc_list) {
                trace_time_out_leases(inode, fl);
                if (past_time(fl->fl_downgrade_time))
                        lease_modify(fl, F_RDLCK, dispose);
@@ -1433,38 +1487,40 @@ static void time_out_leases(struct inode *inode, struct list_head *dispose)
        }
 }
 
-static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
+static bool leases_conflict(struct file_lock_core *lc, struct file_lock_core *bc)
 {
        bool rc;
+       struct file_lease *lease = file_lease(lc);
+       struct file_lease *breaker = file_lease(bc);
 
        if (lease->fl_lmops->lm_breaker_owns_lease
                        && lease->fl_lmops->lm_breaker_owns_lease(lease))
                return false;
-       if ((breaker->fl_flags & FL_LAYOUT) != (lease->fl_flags & FL_LAYOUT)) {
+       if ((bc->flc_flags & FL_LAYOUT) != (lc->flc_flags & FL_LAYOUT)) {
                rc = false;
                goto trace;
        }
-       if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE)) {
+       if ((bc->flc_flags & FL_DELEG) && (lc->flc_flags & FL_LEASE)) {
                rc = false;
                goto trace;
        }
 
-       rc = locks_conflict(breaker, lease);
+       rc = locks_conflict(bc, lc);
 trace:
        trace_leases_conflict(rc, lease, breaker);
        return rc;
 }
 
 static bool
-any_leases_conflict(struct inode *inode, struct file_lock *breaker)
+any_leases_conflict(struct inode *inode, struct file_lease *breaker)
 {
        struct file_lock_context *ctx = inode->i_flctx;
-       struct file_lock *fl;
+       struct file_lock_core *flc;
 
        lockdep_assert_held(&ctx->flc_lock);
 
-       list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
-               if (leases_conflict(fl, breaker))
+       list_for_each_entry(flc, &ctx->flc_lease, flc_list) {
+               if (leases_conflict(flc, &breaker->c))
                        return true;
        }
        return false;
@@ -1487,7 +1543,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
 {
        int error = 0;
        struct file_lock_context *ctx;
-       struct file_lock *new_fl, *fl, *tmp;
+       struct file_lease *new_fl, *fl, *tmp;
        unsigned long break_time;
        int want_write = (mode & O_ACCMODE) != O_RDONLY;
        LIST_HEAD(dispose);
@@ -1495,7 +1551,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
        new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK);
        if (IS_ERR(new_fl))
                return PTR_ERR(new_fl);
-       new_fl->fl_flags = type;
+       new_fl->c.flc_flags = type;
 
        /* typically we will check that ctx is non-NULL before calling */
        ctx = locks_inode_context(inode);
@@ -1519,22 +1575,22 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
                        break_time++;   /* so that 0 means no break time */
        }
 
-       list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) {
-               if (!leases_conflict(fl, new_fl))
+       list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, c.flc_list) {
+               if (!leases_conflict(&fl->c, &new_fl->c))
                        continue;
                if (want_write) {
-                       if (fl->fl_flags & FL_UNLOCK_PENDING)
+                       if (fl->c.flc_flags & FL_UNLOCK_PENDING)
                                continue;
-                       fl->fl_flags |= FL_UNLOCK_PENDING;
+                       fl->c.flc_flags |= FL_UNLOCK_PENDING;
                        fl->fl_break_time = break_time;
                } else {
                        if (lease_breaking(fl))
                                continue;
-                       fl->fl_flags |= FL_DOWNGRADE_PENDING;
+                       fl->c.flc_flags |= FL_DOWNGRADE_PENDING;
                        fl->fl_downgrade_time = break_time;
                }
                if (fl->fl_lmops->lm_break(fl))
-                       locks_delete_lock_ctx(fl, &dispose);
+                       locks_delete_lock_ctx(&fl->c, &dispose);
        }
 
        if (list_empty(&ctx->flc_lease))
@@ -1547,26 +1603,26 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
        }
 
 restart:
-       fl = list_first_entry(&ctx->flc_lease, struct file_lock, fl_list);
+       fl = list_first_entry(&ctx->flc_lease, struct file_lease, c.flc_list);
        break_time = fl->fl_break_time;
        if (break_time != 0)
                break_time -= jiffies;
        if (break_time == 0)
                break_time++;
-       locks_insert_block(fl, new_fl, leases_conflict);
+       locks_insert_block(&fl->c, &new_fl->c, leases_conflict);
        trace_break_lease_block(inode, new_fl);
        spin_unlock(&ctx->flc_lock);
        percpu_up_read(&file_rwsem);
 
        locks_dispose_list(&dispose);
-       error = wait_event_interruptible_timeout(new_fl->fl_wait,
-                                       list_empty(&new_fl->fl_blocked_member),
-                                       break_time);
+       error = wait_event_interruptible_timeout(new_fl->c.flc_wait,
+                                                list_empty(&new_fl->c.flc_blocked_member),
+                                                break_time);
 
        percpu_down_read(&file_rwsem);
        spin_lock(&ctx->flc_lock);
        trace_break_lease_unblock(inode, new_fl);
-       locks_delete_block(new_fl);
+       __locks_delete_block(&new_fl->c);
        if (error >= 0) {
                /*
                 * Wait for the next conflicting lease that has not been
@@ -1583,7 +1639,7 @@ out:
        percpu_up_read(&file_rwsem);
        locks_dispose_list(&dispose);
 free_lock:
-       locks_free_lock(new_fl);
+       locks_free_lease(new_fl);
        return error;
 }
 EXPORT_SYMBOL(__break_lease);
@@ -1601,14 +1657,14 @@ void lease_get_mtime(struct inode *inode, struct timespec64 *time)
 {
        bool has_lease = false;
        struct file_lock_context *ctx;
-       struct file_lock *fl;
+       struct file_lock_core *flc;
 
        ctx = locks_inode_context(inode);
        if (ctx && !list_empty_careful(&ctx->flc_lease)) {
                spin_lock(&ctx->flc_lock);
-               fl = list_first_entry_or_null(&ctx->flc_lease,
-                                             struct file_lock, fl_list);
-               if (fl && (fl->fl_type == F_WRLCK))
+               flc = list_first_entry_or_null(&ctx->flc_lease,
+                                              struct file_lock_core, flc_list);
+               if (flc && flc->flc_type == F_WRLCK)
                        has_lease = true;
                spin_unlock(&ctx->flc_lock);
        }
@@ -1643,7 +1699,7 @@ EXPORT_SYMBOL(lease_get_mtime);
  */
 int fcntl_getlease(struct file *filp)
 {
-       struct file_lock *fl;
+       struct file_lease *fl;
        struct inode *inode = file_inode(filp);
        struct file_lock_context *ctx;
        int type = F_UNLCK;
@@ -1654,8 +1710,8 @@ int fcntl_getlease(struct file *filp)
                percpu_down_read(&file_rwsem);
                spin_lock(&ctx->flc_lock);
                time_out_leases(inode, &dispose);
-               list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
-                       if (fl->fl_file != filp)
+               list_for_each_entry(fl, &ctx->flc_lease, c.flc_list) {
+                       if (fl->c.flc_file != filp)
                                continue;
                        type = target_leasetype(fl);
                        break;
@@ -1715,12 +1771,12 @@ check_conflicting_open(struct file *filp, const int arg, int flags)
 }
 
 static int
-generic_add_lease(struct file *filp, int arg, struct file_lock **flp, void **priv)
+generic_add_lease(struct file *filp, int arg, struct file_lease **flp, void **priv)
 {
-       struct file_lock *fl, *my_fl = NULL, *lease;
+       struct file_lease *fl, *my_fl = NULL, *lease;
        struct inode *inode = file_inode(filp);
        struct file_lock_context *ctx;
-       bool is_deleg = (*flp)->fl_flags & FL_DELEG;
+       bool is_deleg = (*flp)->c.flc_flags & FL_DELEG;
        int error;
        LIST_HEAD(dispose);
 
@@ -1746,7 +1802,7 @@ generic_add_lease(struct file *filp, int arg, struct file_lock **flp, void **pri
        percpu_down_read(&file_rwsem);
        spin_lock(&ctx->flc_lock);
        time_out_leases(inode, &dispose);
-       error = check_conflicting_open(filp, arg, lease->fl_flags);
+       error = check_conflicting_open(filp, arg, lease->c.flc_flags);
        if (error)
                goto out;
 
@@ -1759,9 +1815,9 @@ generic_add_lease(struct file *filp, int arg, struct file_lock **flp, void **pri
         * except for this filp.
         */
        error = -EAGAIN;
-       list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
-               if (fl->fl_file == filp &&
-                   fl->fl_owner == lease->fl_owner) {
+       list_for_each_entry(fl, &ctx->flc_lease, c.flc_list) {
+               if (fl->c.flc_file == filp &&
+                   fl->c.flc_owner == lease->c.flc_owner) {
                        my_fl = fl;
                        continue;
                }
@@ -1776,7 +1832,7 @@ generic_add_lease(struct file *filp, int arg, struct file_lock **flp, void **pri
                 * Modifying our existing lease is OK, but no getting a
                 * new lease if someone else is opening for write:
                 */
-               if (fl->fl_flags & FL_UNLOCK_PENDING)
+               if (fl->c.flc_flags & FL_UNLOCK_PENDING)
                        goto out;
        }
 
@@ -1792,7 +1848,7 @@ generic_add_lease(struct file *filp, int arg, struct file_lock **flp, void **pri
        if (!leases_enable)
                goto out;
 
-       locks_insert_lock_ctx(lease, &ctx->flc_lease);
+       locks_insert_lock_ctx(&lease->c, &ctx->flc_lease);
        /*
         * The check in break_lease() is lockless. It's possible for another
         * open to race in after we did the earlier check for a conflicting
@@ -1803,9 +1859,9 @@ generic_add_lease(struct file *filp, int arg, struct file_lock **flp, void **pri
         * precedes these checks.
         */
        smp_mb();
-       error = check_conflicting_open(filp, arg, lease->fl_flags);
+       error = check_conflicting_open(filp, arg, lease->c.flc_flags);
        if (error) {
-               locks_unlink_lock_ctx(lease);
+               locks_unlink_lock_ctx(&lease->c);
                goto out;
        }
 
@@ -1826,7 +1882,7 @@ out:
 static int generic_delete_lease(struct file *filp, void *owner)
 {
        int error = -EAGAIN;
-       struct file_lock *fl, *victim = NULL;
+       struct file_lease *fl, *victim = NULL;
        struct inode *inode = file_inode(filp);
        struct file_lock_context *ctx;
        LIST_HEAD(dispose);
@@ -1839,9 +1895,9 @@ static int generic_delete_lease(struct file *filp, void *owner)
 
        percpu_down_read(&file_rwsem);
        spin_lock(&ctx->flc_lock);
-       list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
-               if (fl->fl_file == filp &&
-                   fl->fl_owner == owner) {
+       list_for_each_entry(fl, &ctx->flc_lease, c.flc_list) {
+               if (fl->c.flc_file == filp &&
+                   fl->c.flc_owner == owner) {
                        victim = fl;
                        break;
                }
@@ -1866,21 +1922,9 @@ static int generic_delete_lease(struct file *filp, void *owner)
  *     The (input) flp->fl_lmops->lm_break function is required
  *     by break_lease().
  */
-int generic_setlease(struct file *filp, int arg, struct file_lock **flp,
+int generic_setlease(struct file *filp, int arg, struct file_lease **flp,
                        void **priv)
 {
-       struct inode *inode = file_inode(filp);
-       vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_idmap(filp), inode);
-       int error;
-
-       if ((!vfsuid_eq_kuid(vfsuid, current_fsuid())) && !capable(CAP_LEASE))
-               return -EACCES;
-       if (!S_ISREG(inode->i_mode))
-               return -EINVAL;
-       error = security_file_lock(filp, arg);
-       if (error)
-               return error;
-
        switch (arg) {
        case F_UNLCK:
                return generic_delete_lease(filp, *priv);
@@ -1913,7 +1957,7 @@ lease_notifier_chain_init(void)
 }
 
 static inline void
-setlease_notifier(int arg, struct file_lock *lease)
+setlease_notifier(int arg, struct file_lease *lease)
 {
        if (arg != F_UNLCK)
                srcu_notifier_call_chain(&lease_notifier_chain, arg, lease);
@@ -1931,6 +1975,19 @@ void lease_unregister_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(lease_unregister_notifier);
 
+
+int
+kernel_setlease(struct file *filp, int arg, struct file_lease **lease, void **priv)
+{
+       if (lease)
+               setlease_notifier(arg, *lease);
+       if (filp->f_op->setlease)
+               return filp->f_op->setlease(filp, arg, lease, priv);
+       else
+               return generic_setlease(filp, arg, lease, priv);
+}
+EXPORT_SYMBOL_GPL(kernel_setlease);
+
 /**
  * vfs_setlease        -       sets a lease on an open file
  * @filp:      file pointer
@@ -1949,20 +2006,26 @@ EXPORT_SYMBOL_GPL(lease_unregister_notifier);
  * may be NULL if the lm_setup operation doesn't require it.
  */
 int
-vfs_setlease(struct file *filp, int arg, struct file_lock **lease, void **priv)
+vfs_setlease(struct file *filp, int arg, struct file_lease **lease, void **priv)
 {
-       if (lease)
-               setlease_notifier(arg, *lease);
-       if (filp->f_op->setlease)
-               return filp->f_op->setlease(filp, arg, lease, priv);
-       else
-               return generic_setlease(filp, arg, lease, priv);
+       struct inode *inode = file_inode(filp);
+       vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_idmap(filp), inode);
+       int error;
+
+       if ((!vfsuid_eq_kuid(vfsuid, current_fsuid())) && !capable(CAP_LEASE))
+               return -EACCES;
+       if (!S_ISREG(inode->i_mode))
+               return -EINVAL;
+       error = security_file_lock(filp, arg);
+       if (error)
+               return error;
+       return kernel_setlease(filp, arg, lease, priv);
 }
 EXPORT_SYMBOL_GPL(vfs_setlease);
 
 static int do_fcntl_add_lease(unsigned int fd, struct file *filp, int arg)
 {
-       struct file_lock *fl;
+       struct file_lease *fl;
        struct fasync_struct *new;
        int error;
 
@@ -1972,14 +2035,14 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, int arg)
 
        new = fasync_alloc();
        if (!new) {
-               locks_free_lock(fl);
+               locks_free_lease(fl);
                return -ENOMEM;
        }
        new->fa_fd = fd;
 
        error = vfs_setlease(filp, arg, &fl, (void **)&new);
        if (fl)
-               locks_free_lock(fl);
+               locks_free_lease(fl);
        if (new)
                fasync_free(new);
        return error;
@@ -2017,8 +2080,8 @@ static int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl)
                error = flock_lock_inode(inode, fl);
                if (error != FILE_LOCK_DEFERRED)
                        break;
-               error = wait_event_interruptible(fl->fl_wait,
-                               list_empty(&fl->fl_blocked_member));
+               error = wait_event_interruptible(fl->c.flc_wait,
+                                                list_empty(&fl->c.flc_blocked_member));
                if (error)
                        break;
        }
@@ -2036,7 +2099,7 @@ static int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl)
 int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl)
 {
        int res = 0;
-       switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
+       switch (fl->c.flc_flags & (FL_POSIX|FL_FLOCK)) {
                case FL_POSIX:
                        res = posix_lock_inode_wait(inode, fl);
                        break;
@@ -2098,13 +2161,13 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
 
        flock_make_lock(f.file, &fl, type);
 
-       error = security_file_lock(f.file, fl.fl_type);
+       error = security_file_lock(f.file, fl.c.flc_type);
        if (error)
                goto out_putf;
 
        can_sleep = !(cmd & LOCK_NB);
        if (can_sleep)
-               fl.fl_flags |= FL_SLEEP;
+               fl.c.flc_flags |= FL_SLEEP;
 
        if (f.file->f_op->flock)
                error = f.file->f_op->flock(f.file,
@@ -2130,7 +2193,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
  */
 int vfs_test_lock(struct file *filp, struct file_lock *fl)
 {
-       WARN_ON_ONCE(filp != fl->fl_file);
+       WARN_ON_ONCE(filp != fl->c.flc_file);
        if (filp->f_op->lock)
                return filp->f_op->lock(filp, F_GETLK, fl);
        posix_test_lock(filp, fl);
@@ -2145,25 +2208,28 @@ EXPORT_SYMBOL_GPL(vfs_test_lock);
  *
  * Used to translate a fl_pid into a namespace virtual pid number
  */
-static pid_t locks_translate_pid(struct file_lock *fl, struct pid_namespace *ns)
+static pid_t locks_translate_pid(struct file_lock_core *fl, struct pid_namespace *ns)
 {
        pid_t vnr;
        struct pid *pid;
 
-       if (IS_OFDLCK(fl))
+       if (fl->flc_flags & FL_OFDLCK)
                return -1;
-       if (IS_REMOTELCK(fl))
-               return fl->fl_pid;
+
+       /* Remote locks report a negative pid value */
+       if (fl->flc_pid <= 0)
+               return fl->flc_pid;
+
        /*
         * If the flock owner process is dead and its pid has been already
         * freed, the translation below won't work, but we still want to show
         * flock owner pid number in init pidns.
         */
        if (ns == &init_pid_ns)
-               return (pid_t)fl->fl_pid;
+               return (pid_t) fl->flc_pid;
 
        rcu_read_lock();
-       pid = find_pid_ns(fl->fl_pid, &init_pid_ns);
+       pid = find_pid_ns(fl->flc_pid, &init_pid_ns);
        vnr = pid_nr_ns(pid, ns);
        rcu_read_unlock();
        return vnr;
@@ -2171,7 +2237,7 @@ static pid_t locks_translate_pid(struct file_lock *fl, struct pid_namespace *ns)
 
 static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl)
 {
-       flock->l_pid = locks_translate_pid(fl, task_active_pid_ns(current));
+       flock->l_pid = locks_translate_pid(&fl->c, task_active_pid_ns(current));
 #if BITS_PER_LONG == 32
        /*
         * Make sure we can represent the posix lock via
@@ -2186,19 +2252,19 @@ static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl)
        flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
                fl->fl_end - fl->fl_start + 1;
        flock->l_whence = 0;
-       flock->l_type = fl->fl_type;
+       flock->l_type = fl->c.flc_type;
        return 0;
 }
 
 #if BITS_PER_LONG == 32
 static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl)
 {
-       flock->l_pid = locks_translate_pid(fl, task_active_pid_ns(current));
+       flock->l_pid = locks_translate_pid(&fl->c, task_active_pid_ns(current));
        flock->l_start = fl->fl_start;
        flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
                fl->fl_end - fl->fl_start + 1;
        flock->l_whence = 0;
-       flock->l_type = fl->fl_type;
+       flock->l_type = fl->c.flc_type;
 }
 #endif
 
@@ -2227,16 +2293,16 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock)
                if (flock->l_pid != 0)
                        goto out;
 
-               fl->fl_flags |= FL_OFDLCK;
-               fl->fl_owner = filp;
+               fl->c.flc_flags |= FL_OFDLCK;
+               fl->c.flc_owner = filp;
        }
 
        error = vfs_test_lock(filp, fl);
        if (error)
                goto out;
 
-       flock->l_type = fl->fl_type;
-       if (fl->fl_type != F_UNLCK) {
+       flock->l_type = fl->c.flc_type;
+       if (fl->c.flc_type != F_UNLCK) {
                error = posix_lock_to_flock(flock, fl);
                if (error)
                        goto out;
@@ -2283,7 +2349,7 @@ out:
  */
 int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
 {
-       WARN_ON_ONCE(filp != fl->fl_file);
+       WARN_ON_ONCE(filp != fl->c.flc_file);
        if (filp->f_op->lock)
                return filp->f_op->lock(filp, cmd, fl);
        else
@@ -2296,7 +2362,7 @@ static int do_lock_file_wait(struct file *filp, unsigned int cmd,
 {
        int error;
 
-       error = security_file_lock(filp, fl->fl_type);
+       error = security_file_lock(filp, fl->c.flc_type);
        if (error)
                return error;
 
@@ -2304,8 +2370,8 @@ static int do_lock_file_wait(struct file *filp, unsigned int cmd,
                error = vfs_lock_file(filp, cmd, fl, NULL);
                if (error != FILE_LOCK_DEFERRED)
                        break;
-               error = wait_event_interruptible(fl->fl_wait,
-                                       list_empty(&fl->fl_blocked_member));
+               error = wait_event_interruptible(fl->c.flc_wait,
+                                                list_empty(&fl->c.flc_blocked_member));
                if (error)
                        break;
        }
@@ -2318,13 +2384,13 @@ static int do_lock_file_wait(struct file *filp, unsigned int cmd,
 static int
 check_fmode_for_setlk(struct file_lock *fl)
 {
-       switch (fl->fl_type) {
+       switch (fl->c.flc_type) {
        case F_RDLCK:
-               if (!(fl->fl_file->f_mode & FMODE_READ))
+               if (!(fl->c.flc_file->f_mode & FMODE_READ))
                        return -EBADF;
                break;
        case F_WRLCK:
-               if (!(fl->fl_file->f_mode & FMODE_WRITE))
+               if (!(fl->c.flc_file->f_mode & FMODE_WRITE))
                        return -EBADF;
        }
        return 0;
@@ -2363,8 +2429,8 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
                        goto out;
 
                cmd = F_SETLK;
-               file_lock->fl_flags |= FL_OFDLCK;
-               file_lock->fl_owner = filp;
+               file_lock->c.flc_flags |= FL_OFDLCK;
+               file_lock->c.flc_owner = filp;
                break;
        case F_OFD_SETLKW:
                error = -EINVAL;
@@ -2372,11 +2438,11 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
                        goto out;
 
                cmd = F_SETLKW;
-               file_lock->fl_flags |= FL_OFDLCK;
-               file_lock->fl_owner = filp;
+               file_lock->c.flc_flags |= FL_OFDLCK;
+               file_lock->c.flc_owner = filp;
                fallthrough;
        case F_SETLKW:
-               file_lock->fl_flags |= FL_SLEEP;
+               file_lock->c.flc_flags |= FL_SLEEP;
        }
 
        error = do_lock_file_wait(filp, cmd, file_lock);
@@ -2386,8 +2452,8 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
         * lock that was just acquired. There is no need to do that when we're
         * unlocking though, or for OFD locks.
         */
-       if (!error && file_lock->fl_type != F_UNLCK &&
-           !(file_lock->fl_flags & FL_OFDLCK)) {
+       if (!error && file_lock->c.flc_type != F_UNLCK &&
+           !(file_lock->c.flc_flags & FL_OFDLCK)) {
                struct files_struct *files = current->files;
                /*
                 * We need that spin_lock here - it prevents reordering between
@@ -2398,7 +2464,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
                f = files_lookup_fd_locked(files, fd);
                spin_unlock(&files->file_lock);
                if (f != filp) {
-                       file_lock->fl_type = F_UNLCK;
+                       file_lock->c.flc_type = F_UNLCK;
                        error = do_lock_file_wait(filp, cmd, file_lock);
                        WARN_ON_ONCE(error);
                        error = -EBADF;
@@ -2437,16 +2503,16 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock)
                if (flock->l_pid != 0)
                        goto out;
 
-               fl->fl_flags |= FL_OFDLCK;
-               fl->fl_owner = filp;
+               fl->c.flc_flags |= FL_OFDLCK;
+               fl->c.flc_owner = filp;
        }
 
        error = vfs_test_lock(filp, fl);
        if (error)
                goto out;
 
-       flock->l_type = fl->fl_type;
-       if (fl->fl_type != F_UNLCK)
+       flock->l_type = fl->c.flc_type;
+       if (fl->c.flc_type != F_UNLCK)
                posix_lock_to_flock64(flock, fl);
 
 out:
@@ -2486,8 +2552,8 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
                        goto out;
 
                cmd = F_SETLK64;
-               file_lock->fl_flags |= FL_OFDLCK;
-               file_lock->fl_owner = filp;
+               file_lock->c.flc_flags |= FL_OFDLCK;
+               file_lock->c.flc_owner = filp;
                break;
        case F_OFD_SETLKW:
                error = -EINVAL;
@@ -2495,11 +2561,11 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
                        goto out;
 
                cmd = F_SETLKW64;
-               file_lock->fl_flags |= FL_OFDLCK;
-               file_lock->fl_owner = filp;
+               file_lock->c.flc_flags |= FL_OFDLCK;
+               file_lock->c.flc_owner = filp;
                fallthrough;
        case F_SETLKW64:
-               file_lock->fl_flags |= FL_SLEEP;
+               file_lock->c.flc_flags |= FL_SLEEP;
        }
 
        error = do_lock_file_wait(filp, cmd, file_lock);
@@ -2509,8 +2575,8 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
         * lock that was just acquired. There is no need to do that when we're
         * unlocking though, or for OFD locks.
         */
-       if (!error && file_lock->fl_type != F_UNLCK &&
-           !(file_lock->fl_flags & FL_OFDLCK)) {
+       if (!error && file_lock->c.flc_type != F_UNLCK &&
+           !(file_lock->c.flc_flags & FL_OFDLCK)) {
                struct files_struct *files = current->files;
                /*
                 * We need that spin_lock here - it prevents reordering between
@@ -2521,7 +2587,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
                f = files_lookup_fd_locked(files, fd);
                spin_unlock(&files->file_lock);
                if (f != filp) {
-                       file_lock->fl_type = F_UNLCK;
+                       file_lock->c.flc_type = F_UNLCK;
                        error = do_lock_file_wait(filp, cmd, file_lock);
                        WARN_ON_ONCE(error);
                        error = -EBADF;
@@ -2555,13 +2621,13 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
                return;
 
        locks_init_lock(&lock);
-       lock.fl_type = F_UNLCK;
-       lock.fl_flags = FL_POSIX | FL_CLOSE;
+       lock.c.flc_type = F_UNLCK;
+       lock.c.flc_flags = FL_POSIX | FL_CLOSE;
        lock.fl_start = 0;
        lock.fl_end = OFFSET_MAX;
-       lock.fl_owner = owner;
-       lock.fl_pid = current->tgid;
-       lock.fl_file = filp;
+       lock.c.flc_owner = owner;
+       lock.c.flc_pid = current->tgid;
+       lock.c.flc_file = filp;
        lock.fl_ops = NULL;
        lock.fl_lmops = NULL;
 
@@ -2584,7 +2650,7 @@ locks_remove_flock(struct file *filp, struct file_lock_context *flctx)
                return;
 
        flock_make_lock(filp, &fl, F_UNLCK);
-       fl.fl_flags |= FL_CLOSE;
+       fl.c.flc_flags |= FL_CLOSE;
 
        if (filp->f_op->flock)
                filp->f_op->flock(filp, F_SETLKW, &fl);
@@ -2599,7 +2665,7 @@ locks_remove_flock(struct file *filp, struct file_lock_context *flctx)
 static void
 locks_remove_lease(struct file *filp, struct file_lock_context *ctx)
 {
-       struct file_lock *fl, *tmp;
+       struct file_lease *fl, *tmp;
        LIST_HEAD(dispose);
 
        if (list_empty(&ctx->flc_lease))
@@ -2607,8 +2673,8 @@ locks_remove_lease(struct file *filp, struct file_lock_context *ctx)
 
        percpu_down_read(&file_rwsem);
        spin_lock(&ctx->flc_lock);
-       list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list)
-               if (filp == fl->fl_file)
+       list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, c.flc_list)
+               if (filp == fl->c.flc_file)
                        lease_modify(fl, F_UNLCK, &dispose);
        spin_unlock(&ctx->flc_lock);
        percpu_up_read(&file_rwsem);
@@ -2652,7 +2718,7 @@ void locks_remove_file(struct file *filp)
  */
 int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
 {
-       WARN_ON_ONCE(filp != fl->fl_file);
+       WARN_ON_ONCE(filp != fl->c.flc_file);
        if (filp->f_op->lock)
                return filp->f_op->lock(filp, F_CANCELLK, fl);
        return 0;
@@ -2691,69 +2757,73 @@ struct locks_iterator {
        loff_t  li_pos;
 };
 
-static void lock_get_status(struct seq_file *f, struct file_lock *fl,
+static void lock_get_status(struct seq_file *f, struct file_lock_core *flc,
                            loff_t id, char *pfx, int repeat)
 {
        struct inode *inode = NULL;
-       unsigned int fl_pid;
+       unsigned int pid;
        struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)->i_sb);
-       int type;
+       int type = flc->flc_type;
+       struct file_lock *fl = file_lock(flc);
+
+       pid = locks_translate_pid(flc, proc_pidns);
 
-       fl_pid = locks_translate_pid(fl, proc_pidns);
        /*
         * If lock owner is dead (and pid is freed) or not visible in current
         * pidns, zero is shown as a pid value. Check lock info from
         * init_pid_ns to get saved lock pid value.
         */
-
-       if (fl->fl_file != NULL)
-               inode = file_inode(fl->fl_file);
+       if (flc->flc_file != NULL)
+               inode = file_inode(flc->flc_file);
 
        seq_printf(f, "%lld: ", id);
 
        if (repeat)
                seq_printf(f, "%*s", repeat - 1 + (int)strlen(pfx), pfx);
 
-       if (IS_POSIX(fl)) {
-               if (fl->fl_flags & FL_ACCESS)
+       if (flc->flc_flags & FL_POSIX) {
+               if (flc->flc_flags & FL_ACCESS)
                        seq_puts(f, "ACCESS");
-               else if (IS_OFDLCK(fl))
+               else if (flc->flc_flags & FL_OFDLCK)
                        seq_puts(f, "OFDLCK");
                else
                        seq_puts(f, "POSIX ");
 
                seq_printf(f, " %s ",
                             (inode == NULL) ? "*NOINODE*" : "ADVISORY ");
-       } else if (IS_FLOCK(fl)) {
+       } else if (flc->flc_flags & FL_FLOCK) {
                seq_puts(f, "FLOCK  ADVISORY  ");
-       } else if (IS_LEASE(fl)) {
-               if (fl->fl_flags & FL_DELEG)
+       } else if (flc->flc_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT)) {
+               struct file_lease *lease = file_lease(flc);
+
+               type = target_leasetype(lease);
+
+               if (flc->flc_flags & FL_DELEG)
                        seq_puts(f, "DELEG  ");
                else
                        seq_puts(f, "LEASE  ");
 
-               if (lease_breaking(fl))
+               if (lease_breaking(lease))
                        seq_puts(f, "BREAKING  ");
-               else if (fl->fl_file)
+               else if (flc->flc_file)
                        seq_puts(f, "ACTIVE    ");
                else
                        seq_puts(f, "BREAKER   ");
        } else {
                seq_puts(f, "UNKNOWN UNKNOWN  ");
        }
-       type = IS_LEASE(fl) ? target_leasetype(fl) : fl->fl_type;
 
        seq_printf(f, "%s ", (type == F_WRLCK) ? "WRITE" :
                             (type == F_RDLCK) ? "READ" : "UNLCK");
        if (inode) {
                /* userspace relies on this representation of dev_t */
-               seq_printf(f, "%d %02x:%02x:%lu ", fl_pid,
+               seq_printf(f, "%d %02x:%02x:%lu ", pid,
                                MAJOR(inode->i_sb->s_dev),
                                MINOR(inode->i_sb->s_dev), inode->i_ino);
        } else {
-               seq_printf(f, "%d <none>:0 ", fl_pid);
+               seq_printf(f, "%d <none>:0 ", pid);
        }
-       if (IS_POSIX(fl)) {
+       if (flc->flc_flags & FL_POSIX) {
                if (fl->fl_end == OFFSET_MAX)
                        seq_printf(f, "%Ld EOF\n", fl->fl_start);
                else
@@ -2763,17 +2833,18 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
        }
 }
 
-static struct file_lock *get_next_blocked_member(struct file_lock *node)
+static struct file_lock_core *get_next_blocked_member(struct file_lock_core *node)
 {
-       struct file_lock *tmp;
+       struct file_lock_core *tmp;
 
        /* NULL node or root node */
-       if (node == NULL || node->fl_blocker == NULL)
+       if (node == NULL || node->flc_blocker == NULL)
                return NULL;
 
        /* Next member in the linked list could be itself */
-       tmp = list_next_entry(node, fl_blocked_member);
-       if (list_entry_is_head(tmp, &node->fl_blocker->fl_blocked_requests, fl_blocked_member)
+       tmp = list_next_entry(node, flc_blocked_member);
+       if (list_entry_is_head(tmp, &node->flc_blocker->flc_blocked_requests,
+                              flc_blocked_member)
                || tmp == node) {
                return NULL;
        }
@@ -2784,18 +2855,18 @@ static struct file_lock *get_next_blocked_member(struct file_lock *node)
 static int locks_show(struct seq_file *f, void *v)
 {
        struct locks_iterator *iter = f->private;
-       struct file_lock *cur, *tmp;
+       struct file_lock_core *cur, *tmp;
        struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)->i_sb);
        int level = 0;
 
-       cur = hlist_entry(v, struct file_lock, fl_link);
+       cur = hlist_entry(v, struct file_lock_core, flc_link);
 
        if (locks_translate_pid(cur, proc_pidns) == 0)
                return 0;
 
-       /* View this crossed linked list as a binary tree, the first member of fl_blocked_requests
-        * is the left child of current node, the next silibing in fl_blocked_member is the
-        * right child, we can alse get the parent of current node from fl_blocker, so this
+       /* View this crossed linked list as a binary tree, the first member of flc_blocked_requests
+        * is the left child of current node, the next silibing in flc_blocked_member is the
+        * right child, we can alse get the parent of current node from flc_blocker, so this
         * question becomes traversal of a binary tree
         */
        while (cur != NULL) {
@@ -2804,17 +2875,18 @@ static int locks_show(struct seq_file *f, void *v)
                else
                        lock_get_status(f, cur, iter->li_pos, "", level);
 
-               if (!list_empty(&cur->fl_blocked_requests)) {
+               if (!list_empty(&cur->flc_blocked_requests)) {
                        /* Turn left */
-                       cur = list_first_entry_or_null(&cur->fl_blocked_requests,
-                               struct file_lock, fl_blocked_member);
+                       cur = list_first_entry_or_null(&cur->flc_blocked_requests,
+                                                      struct file_lock_core,
+                                                      flc_blocked_member);
                        level++;
                } else {
                        /* Turn right */
                        tmp = get_next_blocked_member(cur);
                        /* Fall back to parent node */
-                       while (tmp == NULL && cur->fl_blocker != NULL) {
-                               cur = cur->fl_blocker;
+                       while (tmp == NULL && cur->flc_blocker != NULL) {
+                               cur = cur->flc_blocker;
                                level--;
                                tmp = get_next_blocked_member(cur);
                        }
@@ -2829,14 +2901,13 @@ static void __show_fd_locks(struct seq_file *f,
                        struct list_head *head, int *id,
                        struct file *filp, struct files_struct *files)
 {
-       struct file_lock *fl;
+       struct file_lock_core *fl;
 
-       list_for_each_entry(fl, head, fl_list) {
+       list_for_each_entry(fl, head, flc_list) {
 
-               if (filp != fl->fl_file)
+               if (filp != fl->flc_file)
                        continue;
-               if (fl->fl_owner != files &&
-                   fl->fl_owner != filp)
+               if (fl->flc_owner != files && fl->flc_owner != filp)
                        continue;
 
                (*id)++;
@@ -2915,6 +2986,9 @@ static int __init filelock_init(void)
        filelock_cache = kmem_cache_create("file_lock_cache",
                        sizeof(struct file_lock), 0, SLAB_PANIC, NULL);
 
+       filelease_cache = kmem_cache_create("file_lock_cache",
+                       sizeof(struct file_lease), 0, SLAB_PANIC, NULL);
+
        for_each_possible_cpu(i) {
                struct file_lock_list_struct *fll = per_cpu_ptr(&file_lock_list, i);
 
index 82aa7a35db26b3f45950f2ec0f0fb6b04036f811..e60a840999aa98315f7a6dd038fe7ae2eed749d5 100644 (file)
@@ -426,9 +426,7 @@ EXPORT_SYMBOL(mb_cache_destroy);
 
 static int __init mbcache_init(void)
 {
-       mb_entry_cache = kmem_cache_create("mbcache",
-                               sizeof(struct mb_cache_entry), 0,
-                               SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
+       mb_entry_cache = KMEM_CACHE(mb_cache_entry, SLAB_RECLAIM_ACCOUNT);
        if (!mb_entry_cache)
                return -ENOMEM;
        return 0;
index 73f37f298087d14b6201962c21706b6bab5a8374..7cbd2b9f4d115c4406a691b953477113a5bde4f1 100644 (file)
@@ -87,7 +87,7 @@ static int __init init_inodecache(void)
        minix_inode_cachep = kmem_cache_create("minix_inode_cache",
                                             sizeof(struct minix_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
-                                               SLAB_MEM_SPREAD|SLAB_ACCOUNT),
+                                               SLAB_ACCOUNT),
                                             init_once);
        if (minix_inode_cachep == NULL)
                return -ENOMEM;
index 64c5205e2b5e7dac35c3ee8470d0f65d3254d4fb..3c60f1eaca615a24588a3a7e1645dbaf71234774 100644 (file)
@@ -214,7 +214,7 @@ static int copy_mnt_idmap(struct uid_gid_map *map_from,
         * anything at all.
         */
        if (nr_extents == 0)
-               return 0;
+               return -EINVAL;
 
        /*
         * Here we know that nr_extents is greater than zero which means
index 738882e0766d083743698916df5f77ce1e68dea7..fa8b99a199fa70eed226ed9ea54927751849d62f 100644 (file)
@@ -605,6 +605,7 @@ alloc_new:
                                GFP_NOFS);
                bio->bi_iter.bi_sector = first_block << (blkbits - 9);
                wbc_init_bio(wbc, bio);
+               bio->bi_write_hint = inode->i_write_hint;
        }
 
        /*
index 4e0de939fea127034c24d7badb18253a9351b52e..d0c4a3e9278e444d0fd6e504ba89a3ba335c7fcf 100644 (file)
@@ -1717,7 +1717,11 @@ static inline int may_lookup(struct mnt_idmap *idmap,
 {
        if (nd->flags & LOOKUP_RCU) {
                int err = inode_permission(idmap, nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
-               if (err != -ECHILD || !try_to_unlazy(nd))
+               if (!err)               // success, keep going
+                       return 0;
+               if (!try_to_unlazy(nd))
+                       return -ECHILD; // redo it all non-lazy
+               if (err != -ECHILD)     // hard error
                        return err;
        }
        return inode_permission(idmap, nd->inode, MAY_EXEC);
@@ -2676,10 +2680,8 @@ static int lookup_one_common(struct mnt_idmap *idmap,
        if (!len)
                return -EACCES;
 
-       if (unlikely(name[0] == '.')) {
-               if (len < 2 || (len == 2 && name[1] == '.'))
-                       return -EACCES;
-       }
+       if (is_dot_dotdot(name, len))
+               return -EACCES;
 
        while (len--) {
                unsigned int c = *(const unsigned char *)name++;
index 437f60e96d405861683f7e3596063d26c0e55038..5a51315c6678145467520800ceedc3378df5e7da 100644 (file)
@@ -4472,10 +4472,15 @@ static int do_mount_setattr(struct path *path, struct mount_kattr *kattr)
        /*
         * If this is an attached mount make sure it's located in the callers
         * mount namespace. If it's not don't let the caller interact with it.
-        * If this is a detached mount make sure it has an anonymous mount
-        * namespace attached to it, i.e. we've created it via OPEN_TREE_CLONE.
+        *
+        * If this mount doesn't have a parent it's most often simply a
+        * detached mount with an anonymous mount namespace. IOW, something
+        * that's simply not attached yet. But there are apparently also users
+        * that do change mount properties on the rootfs itself. That obviously
+        * neither has a parent nor is it a detached mount so we cannot
+        * unconditionally check for detached mounts.
         */
-       if (!(mnt_has_parent(mnt) ? check_mnt(mnt) : is_anon_ns(mnt->mnt_ns)))
+       if ((mnt_has_parent(mnt) || !is_anon_ns(mnt->mnt_ns)) && !check_mnt(mnt))
                goto out;
 
        /*
index a3059b3168fd95756c7e57986ed999e205dfa8aa..9a0d32e4b422ad09518a6c6143638d0c68fb8b84 100644 (file)
@@ -477,6 +477,9 @@ ssize_t netfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 
        _enter("%llx,%zx,%llx", iocb->ki_pos, iov_iter_count(from), i_size_read(inode));
 
+       if (!iov_iter_count(from))
+               return 0;
+
        if ((iocb->ki_flags & IOCB_DIRECT) ||
            test_bit(NETFS_ICTX_UNBUFFERED, &ictx->flags))
                return netfs_unbuffered_write_iter(iocb, from);
index 60a40d293c87f5fd1088830f07488775b8725bb4..bee047e20f5d6933e3af452eb150e4eb2e97d941 100644 (file)
@@ -139,6 +139,9 @@ ssize_t netfs_unbuffered_write_iter(struct kiocb *iocb, struct iov_iter *from)
 
        _enter("%llx,%zx,%llx", iocb->ki_pos, iov_iter_count(from), i_size_read(inode));
 
+       if (!iov_iter_count(from))
+               return 0;
+
        trace_netfs_write_iter(iocb, from);
        netfs_stat(&netfs_n_rh_dio_write);
 
@@ -146,7 +149,7 @@ ssize_t netfs_unbuffered_write_iter(struct kiocb *iocb, struct iov_iter *from)
        if (ret < 0)
                return ret;
        ret = generic_write_checks(iocb, from);
-       if (ret < 0)
+       if (ret <= 0)
                goto out;
        ret = file_remove_privs(file);
        if (ret < 0)
index e8ff1e61ce79b7f67e1252f4b66aa461bfe1d4b8..4261ad6c55b664a7e3da006d007de03664790641 100644 (file)
@@ -748,6 +748,8 @@ int netfs_begin_read(struct netfs_io_request *rreq, bool sync)
 
        if (!rreq->submitted) {
                netfs_put_request(rreq, false, netfs_rreq_trace_put_no_submit);
+               if (rreq->origin == NETFS_DIO_READ)
+                       inode_dio_end(rreq->inode);
                ret = 0;
                goto out;
        }
index b4294a8aa2d4c5a75382951ce134507ec707b0e0..f1eeb49141992995fb422c830ce241e7612dc9a4 100644 (file)
@@ -108,7 +108,7 @@ struct pnfs_block_dev {
        struct pnfs_block_dev           *children;
        u64                             chunk_size;
 
-       struct bdev_handle              *bdev_handle;
+       struct file                     *bdev_file;
        u64                             disk_offset;
 
        u64                             pr_key;
index c97ebc42ec0fee283463be4ad79a8f0fece9a301..93ef7f864980b1dca830d5799c57f33cf21d2886 100644 (file)
@@ -25,17 +25,17 @@ bl_free_device(struct pnfs_block_dev *dev)
        } else {
                if (dev->pr_registered) {
                        const struct pr_ops *ops =
-                               dev->bdev_handle->bdev->bd_disk->fops->pr_ops;
+                               file_bdev(dev->bdev_file)->bd_disk->fops->pr_ops;
                        int error;
 
-                       error = ops->pr_register(dev->bdev_handle->bdev,
+                       error = ops->pr_register(file_bdev(dev->bdev_file),
                                dev->pr_key, 0, false);
                        if (error)
                                pr_err("failed to unregister PR key.\n");
                }
 
-               if (dev->bdev_handle)
-                       bdev_release(dev->bdev_handle);
+               if (dev->bdev_file)
+                       fput(dev->bdev_file);
        }
 }
 
@@ -169,7 +169,7 @@ static bool bl_map_simple(struct pnfs_block_dev *dev, u64 offset,
        map->start = dev->start;
        map->len = dev->len;
        map->disk_offset = dev->disk_offset;
-       map->bdev = dev->bdev_handle->bdev;
+       map->bdev = file_bdev(dev->bdev_file);
        return true;
 }
 
@@ -236,26 +236,26 @@ bl_parse_simple(struct nfs_server *server, struct pnfs_block_dev *d,
                struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask)
 {
        struct pnfs_block_volume *v = &volumes[idx];
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        dev_t dev;
 
        dev = bl_resolve_deviceid(server, v, gfp_mask);
        if (!dev)
                return -EIO;
 
-       bdev_handle = bdev_open_by_dev(dev, BLK_OPEN_READ | BLK_OPEN_WRITE,
+       bdev_file = bdev_file_open_by_dev(dev, BLK_OPEN_READ | BLK_OPEN_WRITE,
                                       NULL, NULL);
-       if (IS_ERR(bdev_handle)) {
+       if (IS_ERR(bdev_file)) {
                printk(KERN_WARNING "pNFS: failed to open device %d:%d (%ld)\n",
-                       MAJOR(dev), MINOR(dev), PTR_ERR(bdev_handle));
-               return PTR_ERR(bdev_handle);
+                       MAJOR(dev), MINOR(dev), PTR_ERR(bdev_file));
+               return PTR_ERR(bdev_file);
        }
-       d->bdev_handle = bdev_handle;
-       d->len = bdev_nr_bytes(bdev_handle->bdev);
+       d->bdev_file = bdev_file;
+       d->len = bdev_nr_bytes(file_bdev(bdev_file));
        d->map = bl_map_simple;
 
        printk(KERN_INFO "pNFS: using block device %s\n",
-               bdev_handle->bdev->bd_disk->disk_name);
+               file_bdev(bdev_file)->bd_disk->disk_name);
        return 0;
 }
 
@@ -300,10 +300,10 @@ bl_validate_designator(struct pnfs_block_volume *v)
        }
 }
 
-static struct bdev_handle *
+static struct file *
 bl_open_path(struct pnfs_block_volume *v, const char *prefix)
 {
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        const char *devname;
 
        devname = kasprintf(GFP_KERNEL, "/dev/disk/by-id/%s%*phN",
@@ -311,15 +311,15 @@ bl_open_path(struct pnfs_block_volume *v, const char *prefix)
        if (!devname)
                return ERR_PTR(-ENOMEM);
 
-       bdev_handle = bdev_open_by_path(devname, BLK_OPEN_READ | BLK_OPEN_WRITE,
+       bdev_file = bdev_file_open_by_path(devname, BLK_OPEN_READ | BLK_OPEN_WRITE,
                                        NULL, NULL);
-       if (IS_ERR(bdev_handle)) {
+       if (IS_ERR(bdev_file)) {
                pr_warn("pNFS: failed to open device %s (%ld)\n",
-                       devname, PTR_ERR(bdev_handle));
+                       devname, PTR_ERR(bdev_file));
        }
 
        kfree(devname);
-       return bdev_handle;
+       return bdev_file;
 }
 
 static int
@@ -327,7 +327,7 @@ bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d,
                struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask)
 {
        struct pnfs_block_volume *v = &volumes[idx];
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        const struct pr_ops *ops;
        int error;
 
@@ -340,14 +340,14 @@ bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d,
         * On other distributions like Debian, the default SCSI by-id path will
         * point to the dm-multipath device if one exists.
         */
-       bdev_handle = bl_open_path(v, "dm-uuid-mpath-0x");
-       if (IS_ERR(bdev_handle))
-               bdev_handle = bl_open_path(v, "wwn-0x");
-       if (IS_ERR(bdev_handle))
-               return PTR_ERR(bdev_handle);
-       d->bdev_handle = bdev_handle;
-
-       d->len = bdev_nr_bytes(d->bdev_handle->bdev);
+       bdev_file = bl_open_path(v, "dm-uuid-mpath-0x");
+       if (IS_ERR(bdev_file))
+               bdev_file = bl_open_path(v, "wwn-0x");
+       if (IS_ERR(bdev_file))
+               return PTR_ERR(bdev_file);
+       d->bdev_file = bdev_file;
+
+       d->len = bdev_nr_bytes(file_bdev(d->bdev_file));
        d->map = bl_map_simple;
        d->pr_key = v->scsi.pr_key;
 
@@ -355,20 +355,20 @@ bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d,
                return -ENODEV;
 
        pr_info("pNFS: using block device %s (reservation key 0x%llx)\n",
-               d->bdev_handle->bdev->bd_disk->disk_name, d->pr_key);
+               file_bdev(d->bdev_file)->bd_disk->disk_name, d->pr_key);
 
-       ops = d->bdev_handle->bdev->bd_disk->fops->pr_ops;
+       ops = file_bdev(d->bdev_file)->bd_disk->fops->pr_ops;
        if (!ops) {
                pr_err("pNFS: block device %s does not support reservations.",
-                               d->bdev_handle->bdev->bd_disk->disk_name);
+                               file_bdev(d->bdev_file)->bd_disk->disk_name);
                error = -EINVAL;
                goto out_blkdev_put;
        }
 
-       error = ops->pr_register(d->bdev_handle->bdev, 0, d->pr_key, true);
+       error = ops->pr_register(file_bdev(d->bdev_file), 0, d->pr_key, true);
        if (error) {
                pr_err("pNFS: failed to register key for block device %s.",
-                               d->bdev_handle->bdev->bd_disk->disk_name);
+                               file_bdev(d->bdev_file)->bd_disk->disk_name);
                goto out_blkdev_put;
        }
 
@@ -376,7 +376,7 @@ bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d,
        return 0;
 
 out_blkdev_put:
-       bdev_release(d->bdev_handle);
+       fput(d->bdev_file);
        return error;
 }
 
index 44eca51b28085d9deff764bfe6f9286388e93983..fbdc9ca80f714bdf3d3cad54e63d7c858612e5f1 100644 (file)
@@ -246,7 +246,7 @@ void nfs_free_client(struct nfs_client *clp)
        put_nfs_version(clp->cl_nfs_mod);
        kfree(clp->cl_hostname);
        kfree(clp->cl_acceptor);
-       kfree(clp);
+       kfree_rcu(clp, rcu);
 }
 EXPORT_SYMBOL_GPL(nfs_free_client);
 
@@ -1006,6 +1006,14 @@ struct nfs_server *nfs_alloc_server(void)
 }
 EXPORT_SYMBOL_GPL(nfs_alloc_server);
 
+static void delayed_free(struct rcu_head *p)
+{
+       struct nfs_server *server = container_of(p, struct nfs_server, rcu);
+
+       nfs_free_iostats(server->io_stats);
+       kfree(server);
+}
+
 /*
  * Free up a server record
  */
@@ -1031,10 +1039,9 @@ void nfs_free_server(struct nfs_server *server)
 
        ida_destroy(&server->lockowner_id);
        ida_destroy(&server->openowner_id);
-       nfs_free_iostats(server->io_stats);
        put_cred(server->cred);
-       kfree(server);
        nfs_release_automount_timer();
+       call_rcu(&server->rcu, delayed_free);
 }
 EXPORT_SYMBOL_GPL(nfs_free_server);
 
index fa1a14def45cea2fc485b598831becc9e7497992..d4a42ce0c7e3dfeef19884be272a8ddd449c143f 100644 (file)
@@ -156,8 +156,8 @@ static int nfs_delegation_claim_locks(struct nfs4_state *state, const nfs4_state
        list = &flctx->flc_posix;
        spin_lock(&flctx->flc_lock);
 restart:
-       list_for_each_entry(fl, list, fl_list) {
-               if (nfs_file_open_context(fl->fl_file)->state != state)
+       for_each_file_lock(fl, list) {
+               if (nfs_file_open_context(fl->c.flc_file)->state != state)
                        continue;
                spin_unlock(&flctx->flc_lock);
                status = nfs4_lock_delegation_recall(fl, state, stateid);
index c8ecbe99905960ccd63b7128f273fc38543d876d..ac505671efbdb7a91a346e4f300e352261562eae 100644 (file)
@@ -1431,9 +1431,9 @@ static bool nfs_verifier_is_delegated(struct dentry *dentry)
 static void nfs_set_verifier_locked(struct dentry *dentry, unsigned long verf)
 {
        struct inode *inode = d_inode(dentry);
-       struct inode *dir = d_inode(dentry->d_parent);
+       struct inode *dir = d_inode_rcu(dentry->d_parent);
 
-       if (!nfs_verify_change_attribute(dir, verf))
+       if (!dir || !nfs_verify_change_attribute(dir, verf))
                return;
        if (inode && NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
                nfs_set_verifier_delegated(&verf);
index 8577ccf621f5be6c72f6954a49867e03be9cd87a..407c6e15afe25c4fd5a6dc452f41d55438d7fb24 100644 (file)
@@ -720,15 +720,15 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
 {
        struct inode *inode = filp->f_mapping->host;
        int status = 0;
-       unsigned int saved_type = fl->fl_type;
+       unsigned int saved_type = fl->c.flc_type;
 
        /* Try local locking first */
        posix_test_lock(filp, fl);
-       if (fl->fl_type != F_UNLCK) {
+       if (fl->c.flc_type != F_UNLCK) {
                /* found a conflict */
                goto out;
        }
-       fl->fl_type = saved_type;
+       fl->c.flc_type = saved_type;
 
        if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
                goto out_noconflict;
@@ -740,7 +740,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
 out:
        return status;
 out_noconflict:
-       fl->fl_type = F_UNLCK;
+       fl->c.flc_type = F_UNLCK;
        goto out;
 }
 
@@ -765,7 +765,7 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
                 *      If we're signalled while cleaning up locks on process exit, we
                 *      still need to complete the unlock.
                 */
-               if (status < 0 && !(fl->fl_flags & FL_CLOSE))
+               if (status < 0 && !(fl->c.flc_flags & FL_CLOSE))
                        return status;
        }
 
@@ -832,12 +832,12 @@ int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
        int is_local = 0;
 
        dprintk("NFS: lock(%pD2, t=%x, fl=%x, r=%lld:%lld)\n",
-                       filp, fl->fl_type, fl->fl_flags,
+                       filp, fl->c.flc_type, fl->c.flc_flags,
                        (long long)fl->fl_start, (long long)fl->fl_end);
 
        nfs_inc_stats(inode, NFSIOS_VFSLOCK);
 
-       if (fl->fl_flags & FL_RECLAIM)
+       if (fl->c.flc_flags & FL_RECLAIM)
                return -ENOGRACE;
 
        if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FCNTL)
@@ -851,7 +851,7 @@ int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
 
        if (IS_GETLK(cmd))
                ret = do_getlk(filp, cmd, fl, is_local);
-       else if (fl->fl_type == F_UNLCK)
+       else if (lock_is_unlock(fl))
                ret = do_unlk(filp, cmd, fl, is_local);
        else
                ret = do_setlk(filp, cmd, fl, is_local);
@@ -869,16 +869,16 @@ int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
        int is_local = 0;
 
        dprintk("NFS: flock(%pD2, t=%x, fl=%x)\n",
-                       filp, fl->fl_type, fl->fl_flags);
+                       filp, fl->c.flc_type, fl->c.flc_flags);
 
-       if (!(fl->fl_flags & FL_FLOCK))
+       if (!(fl->c.flc_flags & FL_FLOCK))
                return -ENOLCK;
 
        if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FLOCK)
                is_local = 1;
 
        /* We're simulating flock() locks using posix locks on the server */
-       if (fl->fl_type == F_UNLCK)
+       if (lock_is_unlock(fl))
                return do_unlk(filp, cmd, fl, is_local);
        return do_setlk(filp, cmd, fl, is_local);
 }
index 2de66e4e8280a801b647dfe10c577e69192e236c..cbbe3f0193b8a34e5a64794248c2b0e4edd63fa0 100644 (file)
@@ -963,7 +963,7 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
        struct nfs_open_context *ctx = nfs_file_open_context(filp);
        int status;
 
-       if (fl->fl_flags & FL_CLOSE) {
+       if (fl->c.flc_flags & FL_CLOSE) {
                l_ctx = nfs_get_lock_context(ctx);
                if (IS_ERR(l_ctx))
                        l_ctx = NULL;
index 581698f1b7b2441025d5421b3b00b4fba42b2ab8..6ff41ceb9f1c770cfe0af2f032bfa3f23d95e290 100644 (file)
@@ -330,7 +330,7 @@ extern int update_open_stateid(struct nfs4_state *state,
                                const nfs4_stateid *deleg_stateid,
                                fmode_t fmode);
 extern int nfs4_proc_setlease(struct file *file, int arg,
-                             struct file_lock **lease, void **priv);
+                             struct file_lease **lease, void **priv);
 extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
                struct nfs_fsinfo *fsinfo);
 extern void nfs4_update_changeattr(struct inode *dir,
index e238abc78a13e72672fe0e635e433ce92252a669..1cd9652f3c280358209f22503ea573a906a6194e 100644 (file)
@@ -439,7 +439,7 @@ void nfs42_ssc_unregister_ops(void)
 }
 #endif /* CONFIG_NFS_V4_2 */
 
-static int nfs4_setlease(struct file *file, int arg, struct file_lock **lease,
+static int nfs4_setlease(struct file *file, int arg, struct file_lease **lease,
                         void **priv)
 {
        return nfs4_proc_setlease(file, arg, lease, priv);
index 23819a756508573efbcc61ecc0f529a7ad178e2a..815996cb27fc4589bed01827c086b32e766f0bc0 100644 (file)
@@ -6800,7 +6800,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
        status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
        switch (status) {
                case 0:
-                       request->fl_type = F_UNLCK;
+                       request->c.flc_type = F_UNLCK;
                        break;
                case -NFS4ERR_DENIED:
                        status = 0;
@@ -7018,8 +7018,8 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
        /* Ensure this is an unlock - when canceling a lock, the
         * canceled lock is passed in, and it won't be an unlock.
         */
-       fl->fl_type = F_UNLCK;
-       if (fl->fl_flags & FL_CLOSE)
+       fl->c.flc_type = F_UNLCK;
+       if (fl->c.flc_flags & FL_CLOSE)
                set_bit(NFS_CONTEXT_UNLOCK, &ctx->flags);
 
        data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid);
@@ -7045,11 +7045,11 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
        struct rpc_task *task;
        struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
        int status = 0;
-       unsigned char fl_flags = request->fl_flags;
+       unsigned char saved_flags = request->c.flc_flags;
 
        status = nfs4_set_lock_state(state, request);
        /* Unlock _before_ we do the RPC call */
-       request->fl_flags |= FL_EXISTS;
+       request->c.flc_flags |= FL_EXISTS;
        /* Exclude nfs_delegation_claim_locks() */
        mutex_lock(&sp->so_delegreturn_mutex);
        /* Exclude nfs4_reclaim_open_stateid() - note nesting! */
@@ -7073,14 +7073,16 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
        status = -ENOMEM;
        if (IS_ERR(seqid))
                goto out;
-       task = nfs4_do_unlck(request, nfs_file_open_context(request->fl_file), lsp, seqid);
+       task = nfs4_do_unlck(request,
+                            nfs_file_open_context(request->c.flc_file),
+                            lsp, seqid);
        status = PTR_ERR(task);
        if (IS_ERR(task))
                goto out;
        status = rpc_wait_for_completion_task(task);
        rpc_put_task(task);
 out:
-       request->fl_flags = fl_flags;
+       request->c.flc_flags = saved_flags;
        trace_nfs4_unlock(request, state, F_SETLK, status);
        return status;
 }
@@ -7191,7 +7193,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
                renew_lease(NFS_SERVER(d_inode(data->ctx->dentry)),
                                data->timestamp);
                if (data->arg.new_lock && !data->cancelled) {
-                       data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS);
+                       data->fl.c.flc_flags &= ~(FL_SLEEP | FL_ACCESS);
                        if (locks_lock_inode_wait(lsp->ls_state->inode, &data->fl) < 0)
                                goto out_restart;
                }
@@ -7292,7 +7294,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
        if (nfs_server_capable(state->inode, NFS_CAP_MOVEABLE))
                task_setup_data.flags |= RPC_TASK_MOVEABLE;
 
-       data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file),
+       data = nfs4_alloc_lockdata(fl,
+                                  nfs_file_open_context(fl->c.flc_file),
                                   fl->fl_u.nfs4_fl.owner, GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
@@ -7398,10 +7401,10 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
 {
        struct nfs_inode *nfsi = NFS_I(state->inode);
        struct nfs4_state_owner *sp = state->owner;
-       unsigned char fl_flags = request->fl_flags;
+       unsigned char flags = request->c.flc_flags;
        int status;
 
-       request->fl_flags |= FL_ACCESS;
+       request->c.flc_flags |= FL_ACCESS;
        status = locks_lock_inode_wait(state->inode, request);
        if (status < 0)
                goto out;
@@ -7410,7 +7413,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
        if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
                /* Yes: cache locks! */
                /* ...but avoid races with delegation recall... */
-               request->fl_flags = fl_flags & ~FL_SLEEP;
+               request->c.flc_flags = flags & ~FL_SLEEP;
                status = locks_lock_inode_wait(state->inode, request);
                up_read(&nfsi->rwsem);
                mutex_unlock(&sp->so_delegreturn_mutex);
@@ -7420,7 +7423,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
        mutex_unlock(&sp->so_delegreturn_mutex);
        status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
 out:
-       request->fl_flags = fl_flags;
+       request->c.flc_flags = flags;
        return status;
 }
 
@@ -7562,7 +7565,7 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
        if (!(IS_SETLK(cmd) || IS_SETLKW(cmd)))
                return -EINVAL;
 
-       if (request->fl_type == F_UNLCK) {
+       if (lock_is_unlock(request)) {
                if (state != NULL)
                        return nfs4_proc_unlck(state, cmd, request);
                return 0;
@@ -7571,7 +7574,7 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
        if (state == NULL)
                return -ENOLCK;
 
-       if ((request->fl_flags & FL_POSIX) &&
+       if ((request->c.flc_flags & FL_POSIX) &&
            !test_bit(NFS_STATE_POSIX_LOCKS, &state->flags))
                return -ENOLCK;
 
@@ -7579,7 +7582,7 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
         * Don't rely on the VFS having checked the file open mode,
         * since it won't do this for flock() locks.
         */
-       switch (request->fl_type) {
+       switch (request->c.flc_type) {
        case F_RDLCK:
                if (!(filp->f_mode & FMODE_READ))
                        return -EBADF;
@@ -7601,7 +7604,7 @@ static int nfs4_delete_lease(struct file *file, void **priv)
        return generic_setlease(file, F_UNLCK, NULL, priv);
 }
 
-static int nfs4_add_lease(struct file *file, int arg, struct file_lock **lease,
+static int nfs4_add_lease(struct file *file, int arg, struct file_lease **lease,
                          void **priv)
 {
        struct inode *inode = file_inode(file);
@@ -7619,7 +7622,7 @@ static int nfs4_add_lease(struct file *file, int arg, struct file_lock **lease,
        return -EAGAIN;
 }
 
-int nfs4_proc_setlease(struct file *file, int arg, struct file_lock **lease,
+int nfs4_proc_setlease(struct file *file, int arg, struct file_lease **lease,
                       void **priv)
 {
        switch (arg) {
index 9a5d911a7edc77cae53cac45aa43f196b32caf20..8cfabdbda33694912652eeb736126c673bdb745a 100644 (file)
@@ -847,15 +847,15 @@ void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
  */
 static struct nfs4_lock_state *
 __nfs4_find_lock_state(struct nfs4_state *state,
-                      fl_owner_t fl_owner, fl_owner_t fl_owner2)
+                      fl_owner_t owner, fl_owner_t owner2)
 {
        struct nfs4_lock_state *pos, *ret = NULL;
        list_for_each_entry(pos, &state->lock_states, ls_locks) {
-               if (pos->ls_owner == fl_owner) {
+               if (pos->ls_owner == owner) {
                        ret = pos;
                        break;
                }
-               if (pos->ls_owner == fl_owner2)
+               if (pos->ls_owner == owner2)
                        ret = pos;
        }
        if (ret)
@@ -868,7 +868,7 @@ __nfs4_find_lock_state(struct nfs4_state *state,
  * exists, return an uninitialized one.
  *
  */
-static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
+static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t owner)
 {
        struct nfs4_lock_state *lsp;
        struct nfs_server *server = state->owner->so_server;
@@ -879,7 +879,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
        nfs4_init_seqid_counter(&lsp->ls_seqid);
        refcount_set(&lsp->ls_count, 1);
        lsp->ls_state = state;
-       lsp->ls_owner = fl_owner;
+       lsp->ls_owner = owner;
        lsp->ls_seqid.owner_id = ida_alloc(&server->lockowner_id, GFP_KERNEL_ACCOUNT);
        if (lsp->ls_seqid.owner_id < 0)
                goto out_free;
@@ -980,7 +980,7 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
 
        if (fl->fl_ops != NULL)
                return 0;
-       lsp = nfs4_get_lock_state(state, fl->fl_owner);
+       lsp = nfs4_get_lock_state(state, fl->c.flc_owner);
        if (lsp == NULL)
                return -ENOMEM;
        fl->fl_u.nfs4_fl.owner = lsp;
@@ -993,7 +993,7 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
                const struct nfs_lock_context *l_ctx)
 {
        struct nfs4_lock_state *lsp;
-       fl_owner_t fl_owner, fl_flock_owner;
+       fl_owner_t owner, fl_flock_owner;
        int ret = -ENOENT;
 
        if (l_ctx == NULL)
@@ -1002,11 +1002,11 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
        if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
                goto out;
 
-       fl_owner = l_ctx->lockowner;
+       owner = l_ctx->lockowner;
        fl_flock_owner = l_ctx->open_context->flock_owner;
 
        spin_lock(&state->state_lock);
-       lsp = __nfs4_find_lock_state(state, fl_owner, fl_flock_owner);
+       lsp = __nfs4_find_lock_state(state, owner, fl_flock_owner);
        if (lsp && test_bit(NFS_LOCK_LOST, &lsp->ls_flags))
                ret = -EIO;
        else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
@@ -1529,8 +1529,8 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
        down_write(&nfsi->rwsem);
        spin_lock(&flctx->flc_lock);
 restart:
-       list_for_each_entry(fl, list, fl_list) {
-               if (nfs_file_open_context(fl->fl_file)->state != state)
+       for_each_file_lock(fl, list) {
+               if (nfs_file_open_context(fl->c.flc_file)->state != state)
                        continue;
                spin_unlock(&flctx->flc_lock);
                status = ops->recover_lock(state, fl);
index d27919d7241d389b257939c26cc134d4ff1be76f..fd7cb15b08b27628f205cdb4284b9035a7d3172a 100644 (file)
@@ -699,7 +699,7 @@ DECLARE_EVENT_CLASS(nfs4_lock_event,
 
                        __entry->error = error < 0 ? -error : 0;
                        __entry->cmd = cmd;
-                       __entry->type = request->fl_type;
+                       __entry->type = request->c.flc_type;
                        __entry->start = request->fl_start;
                        __entry->end = request->fl_end;
                        __entry->dev = inode->i_sb->s_dev;
@@ -771,7 +771,7 @@ TRACE_EVENT(nfs4_set_lock,
 
                        __entry->error = error < 0 ? -error : 0;
                        __entry->cmd = cmd;
-                       __entry->type = request->fl_type;
+                       __entry->type = request->c.flc_type;
                        __entry->start = request->fl_start;
                        __entry->end = request->fl_end;
                        __entry->dev = inode->i_sb->s_dev;
index 69406e60f391e274c83a215bdbd72fc36c8ad78e..1416099dfcd159a9cb4a0ffb21dbd826ad940a07 100644 (file)
@@ -1305,7 +1305,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct
 
 static inline int nfs4_lock_type(struct file_lock *fl, int block)
 {
-       if (fl->fl_type == F_RDLCK)
+       if (lock_is_read(fl))
                return block ? NFS4_READW_LT : NFS4_READ_LT;
        return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
 }
@@ -5052,10 +5052,10 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
                fl->fl_end = fl->fl_start + (loff_t)length - 1;
                if (length == ~(uint64_t)0)
                        fl->fl_end = OFFSET_MAX;
-               fl->fl_type = F_WRLCK;
+               fl->c.flc_type = F_WRLCK;
                if (type & 1)
-                       fl->fl_type = F_RDLCK;
-               fl->fl_pid = 0;
+                       fl->c.flc_type = F_RDLCK;
+               fl->c.flc_pid = 0;
        }
        p = xdr_decode_hyper(p, &clientid); /* read 8 bytes */
        namelen = be32_to_cpup(p); /* read 4 bytes */  /* have read all 32 bytes now */
index bb79d3a886ae83d15395371ec735b7d0e6075bae..84bb852645728b3edf427c5ac1020e38f329f325 100644 (file)
@@ -1301,7 +1301,7 @@ static bool
 is_whole_file_wrlock(struct file_lock *fl)
 {
        return fl->fl_start == 0 && fl->fl_end == OFFSET_MAX &&
-                       fl->fl_type == F_WRLCK;
+                       lock_is_write(fl);
 }
 
 /* If we know the page is up to date, and we're not using byte range locks (or
@@ -1335,13 +1335,13 @@ static int nfs_can_extend_write(struct file *file, struct folio *folio,
        spin_lock(&flctx->flc_lock);
        if (!list_empty(&flctx->flc_posix)) {
                fl = list_first_entry(&flctx->flc_posix, struct file_lock,
-                                       fl_list);
+                                       c.flc_list);
                if (is_whole_file_wrlock(fl))
                        ret = 1;
        } else if (!list_empty(&flctx->flc_flock)) {
                fl = list_first_entry(&flctx->flc_flock, struct file_lock,
-                                       fl_list);
-               if (fl->fl_type == F_WRLCK)
+                                       c.flc_list);
+               if (lock_is_write(fl))
                        ret = 1;
        }
        spin_unlock(&flctx->flc_lock);
index 9cb7f0c33df587875773bb91f7d20de73692f912..b86d8494052cd8b0d70a5b4bdd756f3dda3404ec 100644 (file)
@@ -662,8 +662,8 @@ nfsd_file_lease_notifier_call(struct notifier_block *nb, unsigned long arg,
        struct file_lock *fl = data;
 
        /* Only close files for F_SETLEASE leases */
-       if (fl->fl_flags & FL_LEASE)
-               nfsd_file_close_inode(file_inode(fl->fl_file));
+       if (fl->c.flc_flags & FL_LEASE)
+               nfsd_file_close_inode(file_inode(fl->c.flc_file));
        return 0;
 }
 
index 926c29879c6ab892e4d12329169eb1b5b43d2649..32d23ef3e5de5b4c0f50322ebbbc272439e37d76 100644 (file)
@@ -674,7 +674,7 @@ static void nfs4_xdr_enc_cb_notify_lock(struct rpc_rqst *req,
        const struct nfsd4_callback *cb = data;
        const struct nfsd4_blocked_lock *nbl =
                container_of(cb, struct nfsd4_blocked_lock, nbl_cb);
-       struct nfs4_lockowner *lo = (struct nfs4_lockowner *)nbl->nbl_lock.fl_owner;
+       struct nfs4_lockowner *lo = (struct nfs4_lockowner *)nbl->nbl_lock.c.flc_owner;
        struct nfs4_cb_compound_hdr hdr = {
                .ident = 0,
                .minorversion = cb->cb_clp->cl_minorversion,
index 5e8096bc5eaa452c9ef1d24cbfa58cfb2d9b35d5..4c0d00bdfbb1f3bdc7c3affdeb45bf9e8d7a0b4b 100644 (file)
@@ -25,7 +25,7 @@ static struct kmem_cache *nfs4_layout_cache;
 static struct kmem_cache *nfs4_layout_stateid_cache;
 
 static const struct nfsd4_callback_ops nfsd4_cb_layout_ops;
-static const struct lock_manager_operations nfsd4_layouts_lm_ops;
+static const struct lease_manager_operations nfsd4_layouts_lm_ops;
 
 const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] =  {
 #ifdef CONFIG_NFSD_FLEXFILELAYOUT
@@ -170,7 +170,7 @@ nfsd4_free_layout_stateid(struct nfs4_stid *stid)
        spin_unlock(&fp->fi_lock);
 
        if (!nfsd4_layout_ops[ls->ls_layout_type]->disable_recalls)
-               vfs_setlease(ls->ls_file->nf_file, F_UNLCK, NULL, (void **)&ls);
+               kernel_setlease(ls->ls_file->nf_file, F_UNLCK, NULL, (void **)&ls);
        nfsd_file_put(ls->ls_file);
 
        if (ls->ls_recalled)
@@ -182,27 +182,26 @@ nfsd4_free_layout_stateid(struct nfs4_stid *stid)
 static int
 nfsd4_layout_setlease(struct nfs4_layout_stateid *ls)
 {
-       struct file_lock *fl;
+       struct file_lease *fl;
        int status;
 
        if (nfsd4_layout_ops[ls->ls_layout_type]->disable_recalls)
                return 0;
 
-       fl = locks_alloc_lock();
+       fl = locks_alloc_lease();
        if (!fl)
                return -ENOMEM;
-       locks_init_lock(fl);
+       locks_init_lease(fl);
        fl->fl_lmops = &nfsd4_layouts_lm_ops;
-       fl->fl_flags = FL_LAYOUT;
-       fl->fl_type = F_RDLCK;
-       fl->fl_end = OFFSET_MAX;
-       fl->fl_owner = ls;
-       fl->fl_pid = current->tgid;
-       fl->fl_file = ls->ls_file->nf_file;
-
-       status = vfs_setlease(fl->fl_file, fl->fl_type, &fl, NULL);
+       fl->c.flc_flags = FL_LAYOUT;
+       fl->c.flc_type = F_RDLCK;
+       fl->c.flc_owner = ls;
+       fl->c.flc_pid = current->tgid;
+       fl->c.flc_file = ls->ls_file->nf_file;
+
+       status = kernel_setlease(fl->c.flc_file, fl->c.flc_type, &fl, NULL);
        if (status) {
-               locks_free_lock(fl);
+               locks_free_lease(fl);
                return status;
        }
        BUG_ON(fl != NULL);
@@ -723,7 +722,7 @@ static const struct nfsd4_callback_ops nfsd4_cb_layout_ops = {
 };
 
 static bool
-nfsd4_layout_lm_break(struct file_lock *fl)
+nfsd4_layout_lm_break(struct file_lease *fl)
 {
        /*
         * We don't want the locks code to timeout the lease for us;
@@ -731,19 +730,19 @@ nfsd4_layout_lm_break(struct file_lock *fl)
         * in time:
         */
        fl->fl_break_time = 0;
-       nfsd4_recall_file_layout(fl->fl_owner);
+       nfsd4_recall_file_layout(fl->c.flc_owner);
        return false;
 }
 
 static int
-nfsd4_layout_lm_change(struct file_lock *onlist, int arg,
+nfsd4_layout_lm_change(struct file_lease *onlist, int arg,
                struct list_head *dispose)
 {
        BUG_ON(!(arg & F_UNLCK));
        return lease_modify(onlist, arg, dispose);
 }
 
-static const struct lock_manager_operations nfsd4_layouts_lm_ops = {
+static const struct lease_manager_operations nfsd4_layouts_lm_ops = {
        .lm_break       = nfsd4_layout_lm_break,
        .lm_change      = nfsd4_layout_lm_change,
 };
index 7d6c657e0409ddc62567554304e4a51779dd2934..9257425cbd1a0d0e1dc87b9497e04409a23bd06a 100644 (file)
@@ -1249,7 +1249,7 @@ static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp)
 
        WARN_ON_ONCE(!fp->fi_delegees);
 
-       vfs_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp);
+       kernel_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp);
        put_deleg_file(fp);
 }
 
@@ -4922,9 +4922,9 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
 
 /* Called from break_lease() with flc_lock held. */
 static bool
-nfsd_break_deleg_cb(struct file_lock *fl)
+nfsd_break_deleg_cb(struct file_lease *fl)
 {
-       struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
+       struct nfs4_delegation *dp = (struct nfs4_delegation *) fl->c.flc_owner;
        struct nfs4_file *fp = dp->dl_stid.sc_file;
        struct nfs4_client *clp = dp->dl_stid.sc_client;
        struct nfsd_net *nn;
@@ -4958,9 +4958,9 @@ nfsd_break_deleg_cb(struct file_lock *fl)
  *   %true: Lease conflict was resolved
  *   %false: Lease conflict was not resolved.
  */
-static bool nfsd_breaker_owns_lease(struct file_lock *fl)
+static bool nfsd_breaker_owns_lease(struct file_lease *fl)
 {
-       struct nfs4_delegation *dl = fl->fl_owner;
+       struct nfs4_delegation *dl = fl->c.flc_owner;
        struct svc_rqst *rqst;
        struct nfs4_client *clp;
 
@@ -4975,10 +4975,10 @@ static bool nfsd_breaker_owns_lease(struct file_lock *fl)
 }
 
 static int
-nfsd_change_deleg_cb(struct file_lock *onlist, int arg,
+nfsd_change_deleg_cb(struct file_lease *onlist, int arg,
                     struct list_head *dispose)
 {
-       struct nfs4_delegation *dp = (struct nfs4_delegation *)onlist->fl_owner;
+       struct nfs4_delegation *dp = (struct nfs4_delegation *) onlist->c.flc_owner;
        struct nfs4_client *clp = dp->dl_stid.sc_client;
 
        if (arg & F_UNLCK) {
@@ -4989,7 +4989,7 @@ nfsd_change_deleg_cb(struct file_lock *onlist, int arg,
                return -EAGAIN;
 }
 
-static const struct lock_manager_operations nfsd_lease_mng_ops = {
+static const struct lease_manager_operations nfsd_lease_mng_ops = {
        .lm_breaker_owns_lease = nfsd_breaker_owns_lease,
        .lm_break = nfsd_break_deleg_cb,
        .lm_change = nfsd_change_deleg_cb,
@@ -5329,21 +5329,20 @@ static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
        return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
 }
 
-static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp,
+static struct file_lease *nfs4_alloc_init_lease(struct nfs4_delegation *dp,
                                                int flag)
 {
-       struct file_lock *fl;
+       struct file_lease *fl;
 
-       fl = locks_alloc_lock();
+       fl = locks_alloc_lease();
        if (!fl)
                return NULL;
        fl->fl_lmops = &nfsd_lease_mng_ops;
-       fl->fl_flags = FL_DELEG;
-       fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
-       fl->fl_end = OFFSET_MAX;
-       fl->fl_owner = (fl_owner_t)dp;
-       fl->fl_pid = current->tgid;
-       fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file;
+       fl->c.flc_flags = FL_DELEG;
+       fl->c.flc_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
+       fl->c.flc_owner = (fl_owner_t)dp;
+       fl->c.flc_pid = current->tgid;
+       fl->c.flc_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file;
        return fl;
 }
 
@@ -5461,7 +5460,7 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
        struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
        struct nfs4_delegation *dp;
        struct nfsd_file *nf = NULL;
-       struct file_lock *fl;
+       struct file_lease *fl;
        u32 dl_type;
 
        /*
@@ -5531,9 +5530,10 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
        if (!fl)
                goto out_clnt_odstate;
 
-       status = vfs_setlease(fp->fi_deleg_file->nf_file, fl->fl_type, &fl, NULL);
+       status = kernel_setlease(fp->fi_deleg_file->nf_file,
+                                     fl->c.flc_type, &fl, NULL);
        if (fl)
-               locks_free_lock(fl);
+               locks_free_lease(fl);
        if (status)
                goto out_clnt_odstate;
 
@@ -5570,7 +5570,7 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
 
        return dp;
 out_unlock:
-       vfs_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp);
+       kernel_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp);
 out_clnt_odstate:
        put_clnt_odstate(dp->dl_clnt_odstate);
        nfs4_put_stid(&dp->dl_stid);
@@ -7148,7 +7148,7 @@ nfsd4_lm_put_owner(fl_owner_t owner)
 static bool
 nfsd4_lm_lock_expirable(struct file_lock *cfl)
 {
-       struct nfs4_lockowner *lo = (struct nfs4_lockowner *)cfl->fl_owner;
+       struct nfs4_lockowner *lo = (struct nfs4_lockowner *) cfl->c.flc_owner;
        struct nfs4_client *clp = lo->lo_owner.so_client;
        struct nfsd_net *nn;
 
@@ -7170,7 +7170,7 @@ nfsd4_lm_expire_lock(void)
 static void
 nfsd4_lm_notify(struct file_lock *fl)
 {
-       struct nfs4_lockowner           *lo = (struct nfs4_lockowner *)fl->fl_owner;
+       struct nfs4_lockowner           *lo = (struct nfs4_lockowner *) fl->c.flc_owner;
        struct net                      *net = lo->lo_owner.so_client->net;
        struct nfsd_net                 *nn = net_generic(net, nfsd_net_id);
        struct nfsd4_blocked_lock       *nbl = container_of(fl,
@@ -7207,7 +7207,7 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
        struct nfs4_lockowner *lo;
 
        if (fl->fl_lmops == &nfsd_posix_mng_ops) {
-               lo = (struct nfs4_lockowner *) fl->fl_owner;
+               lo = (struct nfs4_lockowner *) fl->c.flc_owner;
                xdr_netobj_dup(&deny->ld_owner, &lo->lo_owner.so_owner,
                                                GFP_KERNEL);
                if (!deny->ld_owner.data)
@@ -7226,7 +7226,7 @@ nevermind:
        if (fl->fl_end != NFS4_MAX_UINT64)
                deny->ld_length = fl->fl_end - fl->fl_start + 1;        
        deny->ld_type = NFS4_READ_LT;
-       if (fl->fl_type != F_RDLCK)
+       if (fl->c.flc_type != F_RDLCK)
                deny->ld_type = NFS4_WRITE_LT;
 }
 
@@ -7492,8 +7492,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        int lkflg;
        int err;
        bool new = false;
-       unsigned char fl_type;
-       unsigned int fl_flags = FL_POSIX;
+       unsigned char type;
+       unsigned int flags = FL_POSIX;
        struct net *net = SVC_NET(rqstp);
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
@@ -7556,14 +7556,14 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                goto out;
 
        if (lock->lk_reclaim)
-               fl_flags |= FL_RECLAIM;
+               flags |= FL_RECLAIM;
 
        fp = lock_stp->st_stid.sc_file;
        switch (lock->lk_type) {
                case NFS4_READW_LT:
                        if (nfsd4_has_session(cstate) ||
                            exportfs_lock_op_is_async(sb->s_export_op))
-                               fl_flags |= FL_SLEEP;
+                               flags |= FL_SLEEP;
                        fallthrough;
                case NFS4_READ_LT:
                        spin_lock(&fp->fi_lock);
@@ -7571,12 +7571,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        if (nf)
                                get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
                        spin_unlock(&fp->fi_lock);
-                       fl_type = F_RDLCK;
+                       type = F_RDLCK;
                        break;
                case NFS4_WRITEW_LT:
                        if (nfsd4_has_session(cstate) ||
                            exportfs_lock_op_is_async(sb->s_export_op))
-                               fl_flags |= FL_SLEEP;
+                               flags |= FL_SLEEP;
                        fallthrough;
                case NFS4_WRITE_LT:
                        spin_lock(&fp->fi_lock);
@@ -7584,7 +7584,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        if (nf)
                                get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
                        spin_unlock(&fp->fi_lock);
-                       fl_type = F_WRLCK;
+                       type = F_WRLCK;
                        break;
                default:
                        status = nfserr_inval;
@@ -7604,7 +7604,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
         * on those filesystems:
         */
        if (!exportfs_lock_op_is_async(sb->s_export_op))
-               fl_flags &= ~FL_SLEEP;
+               flags &= ~FL_SLEEP;
 
        nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn);
        if (!nbl) {
@@ -7614,11 +7614,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        }
 
        file_lock = &nbl->nbl_lock;
-       file_lock->fl_type = fl_type;
-       file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner));
-       file_lock->fl_pid = current->tgid;
-       file_lock->fl_file = nf->nf_file;
-       file_lock->fl_flags = fl_flags;
+       file_lock->c.flc_type = type;
+       file_lock->c.flc_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner));
+       file_lock->c.flc_pid = current->tgid;
+       file_lock->c.flc_file = nf->nf_file;
+       file_lock->c.flc_flags = flags;
        file_lock->fl_lmops = &nfsd_posix_mng_ops;
        file_lock->fl_start = lock->lk_offset;
        file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
@@ -7631,7 +7631,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                goto out;
        }
 
-       if (fl_flags & FL_SLEEP) {
+       if (flags & FL_SLEEP) {
                nbl->nbl_time = ktime_get_boottime_seconds();
                spin_lock(&nn->blocked_locks_lock);
                list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked);
@@ -7668,7 +7668,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 out:
        if (nbl) {
                /* dequeue it if we queued it before */
-               if (fl_flags & FL_SLEEP) {
+               if (flags & FL_SLEEP) {
                        spin_lock(&nn->blocked_locks_lock);
                        if (!list_empty(&nbl->nbl_list) &&
                            !list_empty(&nbl->nbl_lru)) {
@@ -7736,9 +7736,9 @@ static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct
        err = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ));
        if (err)
                goto out;
-       lock->fl_file = nf->nf_file;
+       lock->c.flc_file = nf->nf_file;
        err = nfserrno(vfs_test_lock(nf->nf_file, lock));
-       lock->fl_file = NULL;
+       lock->c.flc_file = NULL;
 out:
        inode_unlock(inode);
        nfsd_file_put(nf);
@@ -7783,11 +7783,11 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        switch (lockt->lt_type) {
                case NFS4_READ_LT:
                case NFS4_READW_LT:
-                       file_lock->fl_type = F_RDLCK;
+                       file_lock->c.flc_type = F_RDLCK;
                        break;
                case NFS4_WRITE_LT:
                case NFS4_WRITEW_LT:
-                       file_lock->fl_type = F_WRLCK;
+                       file_lock->c.flc_type = F_WRLCK;
                        break;
                default:
                        dprintk("NFSD: nfs4_lockt: bad lock type!\n");
@@ -7797,9 +7797,9 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        lo = find_lockowner_str(cstate->clp, &lockt->lt_owner);
        if (lo)
-               file_lock->fl_owner = (fl_owner_t)lo;
-       file_lock->fl_pid = current->tgid;
-       file_lock->fl_flags = FL_POSIX;
+               file_lock->c.flc_owner = (fl_owner_t)lo;
+       file_lock->c.flc_pid = current->tgid;
+       file_lock->c.flc_flags = FL_POSIX;
 
        file_lock->fl_start = lockt->lt_offset;
        file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
@@ -7810,7 +7810,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        if (status)
                goto out;
 
-       if (file_lock->fl_type != F_UNLCK) {
+       if (file_lock->c.flc_type != F_UNLCK) {
                status = nfserr_denied;
                nfs4_set_lock_denied(file_lock, &lockt->lt_denied);
        }
@@ -7866,11 +7866,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                goto put_file;
        }
 
-       file_lock->fl_type = F_UNLCK;
-       file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner));
-       file_lock->fl_pid = current->tgid;
-       file_lock->fl_file = nf->nf_file;
-       file_lock->fl_flags = FL_POSIX;
+       file_lock->c.flc_type = F_UNLCK;
+       file_lock->c.flc_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner));
+       file_lock->c.flc_pid = current->tgid;
+       file_lock->c.flc_file = nf->nf_file;
+       file_lock->c.flc_flags = FL_POSIX;
        file_lock->fl_lmops = &nfsd_posix_mng_ops;
        file_lock->fl_start = locku->lu_offset;
 
@@ -7927,8 +7927,8 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
 
        if (flctx && !list_empty_careful(&flctx->flc_posix)) {
                spin_lock(&flctx->flc_lock);
-               list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
-                       if (fl->fl_owner == (fl_owner_t)lowner) {
+               for_each_file_lock(fl, &flctx->flc_posix) {
+                       if (fl->c.flc_owner == (fl_owner_t)lowner) {
                                status = true;
                                break;
                        }
@@ -8451,15 +8451,17 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode)
 {
        __be32 status;
        struct file_lock_context *ctx;
-       struct file_lock *fl;
+       struct file_lease *fl;
        struct nfs4_delegation *dp;
 
        ctx = locks_inode_context(inode);
        if (!ctx)
                return 0;
        spin_lock(&ctx->flc_lock);
-       list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
-               if (fl->fl_flags == FL_LAYOUT)
+       for_each_file_lock(fl, &ctx->flc_lease) {
+               unsigned char type = fl->c.flc_type;
+
+               if (fl->c.flc_flags == FL_LAYOUT)
                        continue;
                if (fl->fl_lmops != &nfsd_lease_mng_ops) {
                        /*
@@ -8467,12 +8469,12 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode)
                         * we are done; there isn't any write delegation
                         * on this inode
                         */
-                       if (fl->fl_type == F_RDLCK)
+                       if (type == F_RDLCK)
                                break;
                        goto break_lease;
                }
-               if (fl->fl_type == F_WRLCK) {
-                       dp = fl->fl_owner;
+               if (type == F_WRLCK) {
+                       dp = fl->c.flc_owner;
                        if (dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) {
                                spin_unlock(&ctx->flc_lock);
                                return 0;
index 34e1e3e36733da8ed12de3582123638095f30fab..7aaafb5cb9fc9f7792c7d7198b49f561ee14be0b 100644 (file)
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -27,26 +27,17 @@ static const struct file_operations ns_file_operations = {
 static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
 {
        struct inode *inode = d_inode(dentry);
-       const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
+       struct ns_common *ns = inode->i_private;
+       const struct proc_ns_operations *ns_ops = ns->ops;
 
        return dynamic_dname(buffer, buflen, "%s:[%lu]",
                ns_ops->name, inode->i_ino);
 }
 
-static void ns_prune_dentry(struct dentry *dentry)
-{
-       struct inode *inode = d_inode(dentry);
-       if (inode) {
-               struct ns_common *ns = inode->i_private;
-               atomic_long_set(&ns->stashed, 0);
-       }
-}
-
-const struct dentry_operations ns_dentry_operations =
-{
-       .d_prune        = ns_prune_dentry,
+const struct dentry_operations ns_dentry_operations = {
        .d_delete       = always_delete_dentry,
        .d_dname        = ns_dname,
+       .d_prune        = stashed_dentry_prune,
 };
 
 static void nsfs_evict(struct inode *inode)
@@ -56,67 +47,16 @@ static void nsfs_evict(struct inode *inode)
        ns->ops->put(ns);
 }
 
-static int __ns_get_path(struct path *path, struct ns_common *ns)
-{
-       struct vfsmount *mnt = nsfs_mnt;
-       struct dentry *dentry;
-       struct inode *inode;
-       unsigned long d;
-
-       rcu_read_lock();
-       d = atomic_long_read(&ns->stashed);
-       if (!d)
-               goto slow;
-       dentry = (struct dentry *)d;
-       if (!lockref_get_not_dead(&dentry->d_lockref))
-               goto slow;
-       rcu_read_unlock();
-       ns->ops->put(ns);
-got_it:
-       path->mnt = mntget(mnt);
-       path->dentry = dentry;
-       return 0;
-slow:
-       rcu_read_unlock();
-       inode = new_inode_pseudo(mnt->mnt_sb);
-       if (!inode) {
-               ns->ops->put(ns);
-               return -ENOMEM;
-       }
-       inode->i_ino = ns->inum;
-       simple_inode_init_ts(inode);
-       inode->i_flags |= S_IMMUTABLE;
-       inode->i_mode = S_IFREG | S_IRUGO;
-       inode->i_fop = &ns_file_operations;
-       inode->i_private = ns;
-
-       dentry = d_make_root(inode);    /* not the normal use, but... */
-       if (!dentry)
-               return -ENOMEM;
-       dentry->d_fsdata = (void *)ns->ops;
-       d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
-       if (d) {
-               d_delete(dentry);       /* make sure ->d_prune() does nothing */
-               dput(dentry);
-               cpu_relax();
-               return -EAGAIN;
-       }
-       goto got_it;
-}
-
 int ns_get_path_cb(struct path *path, ns_get_path_helper_t *ns_get_cb,
                     void *private_data)
 {
-       int ret;
+       struct ns_common *ns;
 
-       do {
-               struct ns_common *ns = ns_get_cb(private_data);
-               if (!ns)
-                       return -ENOENT;
-               ret = __ns_get_path(path, ns);
-       } while (ret == -EAGAIN);
+       ns = ns_get_cb(private_data);
+       if (!ns)
+               return -ENOENT;
 
-       return ret;
+       return path_from_stashed(&ns->stashed, ns->inum, nsfs_mnt, ns, path);
 }
 
 struct ns_get_path_task_args {
@@ -146,6 +86,7 @@ int open_related_ns(struct ns_common *ns,
                   struct ns_common *(*get_ns)(struct ns_common *ns))
 {
        struct path path = {};
+       struct ns_common *relative;
        struct file *f;
        int err;
        int fd;
@@ -154,19 +95,15 @@ int open_related_ns(struct ns_common *ns,
        if (fd < 0)
                return fd;
 
-       do {
-               struct ns_common *relative;
-
-               relative = get_ns(ns);
-               if (IS_ERR(relative)) {
-                       put_unused_fd(fd);
-                       return PTR_ERR(relative);
-               }
-
-               err = __ns_get_path(&path, relative);
-       } while (err == -EAGAIN);
+       relative = get_ns(ns);
+       if (IS_ERR(relative)) {
+               put_unused_fd(fd);
+               return PTR_ERR(relative);
+       }
 
-       if (err) {
+       err = path_from_stashed(&relative->stashed, relative->inum, nsfs_mnt,
+                               relative, &path);
+       if (err < 0) {
                put_unused_fd(fd);
                return err;
        }
@@ -249,7 +186,8 @@ bool ns_match(const struct ns_common *ns, dev_t dev, ino_t ino)
 static int nsfs_show_path(struct seq_file *seq, struct dentry *dentry)
 {
        struct inode *inode = d_inode(dentry);
-       const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
+       const struct ns_common *ns = inode->i_private;
+       const struct proc_ns_operations *ns_ops = ns->ops;
 
        seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino);
        return 0;
@@ -261,6 +199,24 @@ static const struct super_operations nsfs_ops = {
        .show_path = nsfs_show_path,
 };
 
+static void nsfs_init_inode(struct inode *inode, void *data)
+{
+       inode->i_private = data;
+       inode->i_mode |= S_IRUGO;
+       inode->i_fop = &ns_file_operations;
+}
+
+static void nsfs_put_data(void *data)
+{
+       struct ns_common *ns = data;
+       ns->ops->put(ns);
+}
+
+static const struct stashed_operations nsfs_stashed_ops = {
+       .init_inode = nsfs_init_inode,
+       .put_data = nsfs_put_data,
+};
+
 static int nsfs_init_fs_context(struct fs_context *fc)
 {
        struct pseudo_fs_context *ctx = init_pseudo(fc, NSFS_MAGIC);
@@ -268,6 +224,7 @@ static int nsfs_init_fs_context(struct fs_context *fc)
                return -ENOMEM;
        ctx->ops = &nsfs_ops;
        ctx->dops = &ns_dentry_operations;
+       fc->s_fs_info = (void *)&nsfs_stashed_ops;
        return 0;
 }
 
diff --git a/fs/ntfs/Kconfig b/fs/ntfs/Kconfig
deleted file mode 100644 (file)
index 7b25097..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config NTFS_FS
-       tristate "NTFS file system support"
-       select BUFFER_HEAD
-       select NLS
-       help
-         NTFS is the file system of Microsoft Windows NT, 2000, XP and 2003.
-
-         Saying Y or M here enables read support.  There is partial, but
-         safe, write support available.  For write support you must also
-         say Y to "NTFS write support" below.
-
-         There are also a number of user-space tools available, called
-         ntfsprogs.  These include ntfsundelete and ntfsresize, that work
-         without NTFS support enabled in the kernel.
-
-         This is a rewrite from scratch of Linux NTFS support and replaced
-         the old NTFS code starting with Linux 2.5.11.  A backport to
-         the Linux 2.4 kernel series is separately available as a patch
-         from the project web site.
-
-         For more information see <file:Documentation/filesystems/ntfs.rst>
-         and <http://www.linux-ntfs.org/>.
-
-         To compile this file system support as a module, choose M here: the
-         module will be called ntfs.
-
-         If you are not using Windows NT, 2000, XP or 2003 in addition to
-         Linux on your computer it is safe to say N.
-
-config NTFS_DEBUG
-       bool "NTFS debugging support"
-       depends on NTFS_FS
-       help
-         If you are experiencing any problems with the NTFS file system, say
-         Y here.  This will result in additional consistency checks to be
-         performed by the driver as well as additional debugging messages to
-         be written to the system log.  Note that debugging messages are
-         disabled by default.  To enable them, supply the option debug_msgs=1
-         at the kernel command line when booting the kernel or as an option
-         to insmod when loading the ntfs module.  Once the driver is active,
-         you can enable debugging messages by doing (as root):
-         echo 1 > /proc/sys/fs/ntfs-debug
-         Replacing the "1" with "0" would disable debug messages.
-
-         If you leave debugging messages disabled, this results in little
-         overhead, but enabling debug messages results in very significant
-         slowdown of the system.
-
-         When reporting bugs, please try to have available a full dump of
-         debugging messages while the misbehaviour was occurring.
-
-config NTFS_RW
-       bool "NTFS write support"
-       depends on NTFS_FS
-       depends on PAGE_SIZE_LESS_THAN_64KB
-       help
-         This enables the partial, but safe, write support in the NTFS driver.
-
-         The only supported operation is overwriting existing files, without
-         changing the file length.  No file or directory creation, deletion or
-         renaming is possible.  Note only non-resident files can be written to
-         so you may find that some very small files (<500 bytes or so) cannot
-         be written to.
-
-         While we cannot guarantee that it will not damage any data, we have
-         so far not received a single report where the driver would have
-         damaged someones data so we assume it is perfectly safe to use.
-
-         Note:  While write support is safe in this version (a rewrite from
-         scratch of the NTFS support), it should be noted that the old NTFS
-         write support, included in Linux 2.5.10 and before (since 1997),
-         is not safe.
-
-         This is currently useful with TopologiLinux.  TopologiLinux is run
-         on top of any DOS/Microsoft Windows system without partitioning your
-         hard disk.  Unlike other Linux distributions TopologiLinux does not
-         need its own partition.  For more information see
-         <http://topologi-linux.sourceforge.net/>
-
-         It is perfectly safe to say N here.
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile
deleted file mode 100644 (file)
index 3e73657..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Rules for making the NTFS driver.
-
-obj-$(CONFIG_NTFS_FS) += ntfs.o
-
-ntfs-y := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
-         index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
-         unistr.o upcase.o
-
-ntfs-$(CONFIG_NTFS_RW) += bitmap.o lcnalloc.o logfile.o quota.o usnjrnl.o
-
-ccflags-y := -DNTFS_VERSION=\"2.1.32\"
-ccflags-$(CONFIG_NTFS_DEBUG)   += -DDEBUG
-ccflags-$(CONFIG_NTFS_RW)      += -DNTFS_RW
-
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
deleted file mode 100644 (file)
index 2d01517..0000000
+++ /dev/null
@@ -1,1744 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * aops.c - NTFS kernel address space operations and page cache handling.
- *
- * Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc.
- * Copyright (c) 2002 Richard Russon
- */
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/gfp.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/swap.h>
-#include <linux/buffer_head.h>
-#include <linux/writeback.h>
-#include <linux/bit_spinlock.h>
-#include <linux/bio.h>
-
-#include "aops.h"
-#include "attrib.h"
-#include "debug.h"
-#include "inode.h"
-#include "mft.h"
-#include "runlist.h"
-#include "types.h"
-#include "ntfs.h"
-
-/**
- * ntfs_end_buffer_async_read - async io completion for reading attributes
- * @bh:                buffer head on which io is completed
- * @uptodate:  whether @bh is now uptodate or not
- *
- * Asynchronous I/O completion handler for reading pages belonging to the
- * attribute address space of an inode.  The inodes can either be files or
- * directories or they can be fake inodes describing some attribute.
- *
- * If NInoMstProtected(), perform the post read mst fixups when all IO on the
- * page has been completed and mark the page uptodate or set the error bit on
- * the page.  To determine the size of the records that need fixing up, we
- * cheat a little bit by setting the index_block_size in ntfs_inode to the ntfs
- * record size, and index_block_size_bits, to the log(base 2) of the ntfs
- * record size.
- */
-static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
-{
-       unsigned long flags;
-       struct buffer_head *first, *tmp;
-       struct page *page;
-       struct inode *vi;
-       ntfs_inode *ni;
-       int page_uptodate = 1;
-
-       page = bh->b_page;
-       vi = page->mapping->host;
-       ni = NTFS_I(vi);
-
-       if (likely(uptodate)) {
-               loff_t i_size;
-               s64 file_ofs, init_size;
-
-               set_buffer_uptodate(bh);
-
-               file_ofs = ((s64)page->index << PAGE_SHIFT) +
-                               bh_offset(bh);
-               read_lock_irqsave(&ni->size_lock, flags);
-               init_size = ni->initialized_size;
-               i_size = i_size_read(vi);
-               read_unlock_irqrestore(&ni->size_lock, flags);
-               if (unlikely(init_size > i_size)) {
-                       /* Race with shrinking truncate. */
-                       init_size = i_size;
-               }
-               /* Check for the current buffer head overflowing. */
-               if (unlikely(file_ofs + bh->b_size > init_size)) {
-                       int ofs;
-                       void *kaddr;
-
-                       ofs = 0;
-                       if (file_ofs < init_size)
-                               ofs = init_size - file_ofs;
-                       kaddr = kmap_atomic(page);
-                       memset(kaddr + bh_offset(bh) + ofs, 0,
-                                       bh->b_size - ofs);
-                       flush_dcache_page(page);
-                       kunmap_atomic(kaddr);
-               }
-       } else {
-               clear_buffer_uptodate(bh);
-               SetPageError(page);
-               ntfs_error(ni->vol->sb, "Buffer I/O error, logical block "
-                               "0x%llx.", (unsigned long long)bh->b_blocknr);
-       }
-       first = page_buffers(page);
-       spin_lock_irqsave(&first->b_uptodate_lock, flags);
-       clear_buffer_async_read(bh);
-       unlock_buffer(bh);
-       tmp = bh;
-       do {
-               if (!buffer_uptodate(tmp))
-                       page_uptodate = 0;
-               if (buffer_async_read(tmp)) {
-                       if (likely(buffer_locked(tmp)))
-                               goto still_busy;
-                       /* Async buffers must be locked. */
-                       BUG();
-               }
-               tmp = tmp->b_this_page;
-       } while (tmp != bh);
-       spin_unlock_irqrestore(&first->b_uptodate_lock, flags);
-       /*
-        * If none of the buffers had errors then we can set the page uptodate,
-        * but we first have to perform the post read mst fixups, if the
-        * attribute is mst protected, i.e. if NInoMstProteced(ni) is true.
-        * Note we ignore fixup errors as those are detected when
-        * map_mft_record() is called which gives us per record granularity
-        * rather than per page granularity.
-        */
-       if (!NInoMstProtected(ni)) {
-               if (likely(page_uptodate && !PageError(page)))
-                       SetPageUptodate(page);
-       } else {
-               u8 *kaddr;
-               unsigned int i, recs;
-               u32 rec_size;
-
-               rec_size = ni->itype.index.block_size;
-               recs = PAGE_SIZE / rec_size;
-               /* Should have been verified before we got here... */
-               BUG_ON(!recs);
-               kaddr = kmap_atomic(page);
-               for (i = 0; i < recs; i++)
-                       post_read_mst_fixup((NTFS_RECORD*)(kaddr +
-                                       i * rec_size), rec_size);
-               kunmap_atomic(kaddr);
-               flush_dcache_page(page);
-               if (likely(page_uptodate && !PageError(page)))
-                       SetPageUptodate(page);
-       }
-       unlock_page(page);
-       return;
-still_busy:
-       spin_unlock_irqrestore(&first->b_uptodate_lock, flags);
-       return;
-}
-
-/**
- * ntfs_read_block - fill a @folio of an address space with data
- * @folio:     page cache folio to fill with data
- *
- * We read each buffer asynchronously and when all buffers are read in, our io
- * completion handler ntfs_end_buffer_read_async(), if required, automatically
- * applies the mst fixups to the folio before finally marking it uptodate and
- * unlocking it.
- *
- * We only enforce allocated_size limit because i_size is checked for in
- * generic_file_read().
- *
- * Return 0 on success and -errno on error.
- *
- * Contains an adapted version of fs/buffer.c::block_read_full_folio().
- */
-static int ntfs_read_block(struct folio *folio)
-{
-       loff_t i_size;
-       VCN vcn;
-       LCN lcn;
-       s64 init_size;
-       struct inode *vi;
-       ntfs_inode *ni;
-       ntfs_volume *vol;
-       runlist_element *rl;
-       struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
-       sector_t iblock, lblock, zblock;
-       unsigned long flags;
-       unsigned int blocksize, vcn_ofs;
-       int i, nr;
-       unsigned char blocksize_bits;
-
-       vi = folio->mapping->host;
-       ni = NTFS_I(vi);
-       vol = ni->vol;
-
-       /* $MFT/$DATA must have its complete runlist in memory at all times. */
-       BUG_ON(!ni->runlist.rl && !ni->mft_no && !NInoAttr(ni));
-
-       blocksize = vol->sb->s_blocksize;
-       blocksize_bits = vol->sb->s_blocksize_bits;
-
-       head = folio_buffers(folio);
-       if (!head)
-               head = create_empty_buffers(folio, blocksize, 0);
-       bh = head;
-
-       /*
-        * We may be racing with truncate.  To avoid some of the problems we
-        * now take a snapshot of the various sizes and use those for the whole
-        * of the function.  In case of an extending truncate it just means we
-        * may leave some buffers unmapped which are now allocated.  This is
-        * not a problem since these buffers will just get mapped when a write
-        * occurs.  In case of a shrinking truncate, we will detect this later
-        * on due to the runlist being incomplete and if the folio is being
-        * fully truncated, truncate will throw it away as soon as we unlock
-        * it so no need to worry what we do with it.
-        */
-       iblock = (s64)folio->index << (PAGE_SHIFT - blocksize_bits);
-       read_lock_irqsave(&ni->size_lock, flags);
-       lblock = (ni->allocated_size + blocksize - 1) >> blocksize_bits;
-       init_size = ni->initialized_size;
-       i_size = i_size_read(vi);
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       if (unlikely(init_size > i_size)) {
-               /* Race with shrinking truncate. */
-               init_size = i_size;
-       }
-       zblock = (init_size + blocksize - 1) >> blocksize_bits;
-
-       /* Loop through all the buffers in the folio. */
-       rl = NULL;
-       nr = i = 0;
-       do {
-               int err = 0;
-
-               if (unlikely(buffer_uptodate(bh)))
-                       continue;
-               if (unlikely(buffer_mapped(bh))) {
-                       arr[nr++] = bh;
-                       continue;
-               }
-               bh->b_bdev = vol->sb->s_bdev;
-               /* Is the block within the allowed limits? */
-               if (iblock < lblock) {
-                       bool is_retry = false;
-
-                       /* Convert iblock into corresponding vcn and offset. */
-                       vcn = (VCN)iblock << blocksize_bits >>
-                                       vol->cluster_size_bits;
-                       vcn_ofs = ((VCN)iblock << blocksize_bits) &
-                                       vol->cluster_size_mask;
-                       if (!rl) {
-lock_retry_remap:
-                               down_read(&ni->runlist.lock);
-                               rl = ni->runlist.rl;
-                       }
-                       if (likely(rl != NULL)) {
-                               /* Seek to element containing target vcn. */
-                               while (rl->length && rl[1].vcn <= vcn)
-                                       rl++;
-                               lcn = ntfs_rl_vcn_to_lcn(rl, vcn);
-                       } else
-                               lcn = LCN_RL_NOT_MAPPED;
-                       /* Successful remap. */
-                       if (lcn >= 0) {
-                               /* Setup buffer head to correct block. */
-                               bh->b_blocknr = ((lcn << vol->cluster_size_bits)
-                                               + vcn_ofs) >> blocksize_bits;
-                               set_buffer_mapped(bh);
-                               /* Only read initialized data blocks. */
-                               if (iblock < zblock) {
-                                       arr[nr++] = bh;
-                                       continue;
-                               }
-                               /* Fully non-initialized data block, zero it. */
-                               goto handle_zblock;
-                       }
-                       /* It is a hole, need to zero it. */
-                       if (lcn == LCN_HOLE)
-                               goto handle_hole;
-                       /* If first try and runlist unmapped, map and retry. */
-                       if (!is_retry && lcn == LCN_RL_NOT_MAPPED) {
-                               is_retry = true;
-                               /*
-                                * Attempt to map runlist, dropping lock for
-                                * the duration.
-                                */
-                               up_read(&ni->runlist.lock);
-                               err = ntfs_map_runlist(ni, vcn);
-                               if (likely(!err))
-                                       goto lock_retry_remap;
-                               rl = NULL;
-                       } else if (!rl)
-                               up_read(&ni->runlist.lock);
-                       /*
-                        * If buffer is outside the runlist, treat it as a
-                        * hole.  This can happen due to concurrent truncate
-                        * for example.
-                        */
-                       if (err == -ENOENT || lcn == LCN_ENOENT) {
-                               err = 0;
-                               goto handle_hole;
-                       }
-                       /* Hard error, zero out region. */
-                       if (!err)
-                               err = -EIO;
-                       bh->b_blocknr = -1;
-                       folio_set_error(folio);
-                       ntfs_error(vol->sb, "Failed to read from inode 0x%lx, "
-                                       "attribute type 0x%x, vcn 0x%llx, "
-                                       "offset 0x%x because its location on "
-                                       "disk could not be determined%s "
-                                       "(error code %i).", ni->mft_no,
-                                       ni->type, (unsigned long long)vcn,
-                                       vcn_ofs, is_retry ? " even after "
-                                       "retrying" : "", err);
-               }
-               /*
-                * Either iblock was outside lblock limits or
-                * ntfs_rl_vcn_to_lcn() returned error.  Just zero that portion
-                * of the folio and set the buffer uptodate.
-                */
-handle_hole:
-               bh->b_blocknr = -1UL;
-               clear_buffer_mapped(bh);
-handle_zblock:
-               folio_zero_range(folio, i * blocksize, blocksize);
-               if (likely(!err))
-                       set_buffer_uptodate(bh);
-       } while (i++, iblock++, (bh = bh->b_this_page) != head);
-
-       /* Release the lock if we took it. */
-       if (rl)
-               up_read(&ni->runlist.lock);
-
-       /* Check we have at least one buffer ready for i/o. */
-       if (nr) {
-               struct buffer_head *tbh;
-
-               /* Lock the buffers. */
-               for (i = 0; i < nr; i++) {
-                       tbh = arr[i];
-                       lock_buffer(tbh);
-                       tbh->b_end_io = ntfs_end_buffer_async_read;
-                       set_buffer_async_read(tbh);
-               }
-               /* Finally, start i/o on the buffers. */
-               for (i = 0; i < nr; i++) {
-                       tbh = arr[i];
-                       if (likely(!buffer_uptodate(tbh)))
-                               submit_bh(REQ_OP_READ, tbh);
-                       else
-                               ntfs_end_buffer_async_read(tbh, 1);
-               }
-               return 0;
-       }
-       /* No i/o was scheduled on any of the buffers. */
-       if (likely(!folio_test_error(folio)))
-               folio_mark_uptodate(folio);
-       else /* Signal synchronous i/o error. */
-               nr = -EIO;
-       folio_unlock(folio);
-       return nr;
-}
-
-/**
- * ntfs_read_folio - fill a @folio of a @file with data from the device
- * @file:      open file to which the folio @folio belongs or NULL
- * @folio:     page cache folio to fill with data
- *
- * For non-resident attributes, ntfs_read_folio() fills the @folio of the open
- * file @file by calling the ntfs version of the generic block_read_full_folio()
- * function, ntfs_read_block(), which in turn creates and reads in the buffers
- * associated with the folio asynchronously.
- *
- * For resident attributes, OTOH, ntfs_read_folio() fills @folio by copying the
- * data from the mft record (which at this stage is most likely in memory) and
- * fills the remainder with zeroes. Thus, in this case, I/O is synchronous, as
- * even if the mft record is not cached at this point in time, we need to wait
- * for it to be read in before we can do the copy.
- *
- * Return 0 on success and -errno on error.
- */
-static int ntfs_read_folio(struct file *file, struct folio *folio)
-{
-       struct page *page = &folio->page;
-       loff_t i_size;
-       struct inode *vi;
-       ntfs_inode *ni, *base_ni;
-       u8 *addr;
-       ntfs_attr_search_ctx *ctx;
-       MFT_RECORD *mrec;
-       unsigned long flags;
-       u32 attr_len;
-       int err = 0;
-
-retry_readpage:
-       BUG_ON(!PageLocked(page));
-       vi = page->mapping->host;
-       i_size = i_size_read(vi);
-       /* Is the page fully outside i_size? (truncate in progress) */
-       if (unlikely(page->index >= (i_size + PAGE_SIZE - 1) >>
-                       PAGE_SHIFT)) {
-               zero_user(page, 0, PAGE_SIZE);
-               ntfs_debug("Read outside i_size - truncated?");
-               goto done;
-       }
-       /*
-        * This can potentially happen because we clear PageUptodate() during
-        * ntfs_writepage() of MstProtected() attributes.
-        */
-       if (PageUptodate(page)) {
-               unlock_page(page);
-               return 0;
-       }
-       ni = NTFS_I(vi);
-       /*
-        * Only $DATA attributes can be encrypted and only unnamed $DATA
-        * attributes can be compressed.  Index root can have the flags set but
-        * this means to create compressed/encrypted files, not that the
-        * attribute is compressed/encrypted.  Note we need to check for
-        * AT_INDEX_ALLOCATION since this is the type of both directory and
-        * index inodes.
-        */
-       if (ni->type != AT_INDEX_ALLOCATION) {
-               /* If attribute is encrypted, deny access, just like NT4. */
-               if (NInoEncrypted(ni)) {
-                       BUG_ON(ni->type != AT_DATA);
-                       err = -EACCES;
-                       goto err_out;
-               }
-               /* Compressed data streams are handled in compress.c. */
-               if (NInoNonResident(ni) && NInoCompressed(ni)) {
-                       BUG_ON(ni->type != AT_DATA);
-                       BUG_ON(ni->name_len);
-                       return ntfs_read_compressed_block(page);
-               }
-       }
-       /* NInoNonResident() == NInoIndexAllocPresent() */
-       if (NInoNonResident(ni)) {
-               /* Normal, non-resident data stream. */
-               return ntfs_read_block(folio);
-       }
-       /*
-        * Attribute is resident, implying it is not compressed or encrypted.
-        * This also means the attribute is smaller than an mft record and
-        * hence smaller than a page, so can simply zero out any pages with
-        * index above 0.  Note the attribute can actually be marked compressed
-        * but if it is resident the actual data is not compressed so we are
-        * ok to ignore the compressed flag here.
-        */
-       if (unlikely(page->index > 0)) {
-               zero_user(page, 0, PAGE_SIZE);
-               goto done;
-       }
-       if (!NInoAttr(ni))
-               base_ni = ni;
-       else
-               base_ni = ni->ext.base_ntfs_ino;
-       /* Map, pin, and lock the mft record. */
-       mrec = map_mft_record(base_ni);
-       if (IS_ERR(mrec)) {
-               err = PTR_ERR(mrec);
-               goto err_out;
-       }
-       /*
-        * If a parallel write made the attribute non-resident, drop the mft
-        * record and retry the read_folio.
-        */
-       if (unlikely(NInoNonResident(ni))) {
-               unmap_mft_record(base_ni);
-               goto retry_readpage;
-       }
-       ctx = ntfs_attr_get_search_ctx(base_ni, mrec);
-       if (unlikely(!ctx)) {
-               err = -ENOMEM;
-               goto unm_err_out;
-       }
-       err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err))
-               goto put_unm_err_out;
-       attr_len = le32_to_cpu(ctx->attr->data.resident.value_length);
-       read_lock_irqsave(&ni->size_lock, flags);
-       if (unlikely(attr_len > ni->initialized_size))
-               attr_len = ni->initialized_size;
-       i_size = i_size_read(vi);
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       if (unlikely(attr_len > i_size)) {
-               /* Race with shrinking truncate. */
-               attr_len = i_size;
-       }
-       addr = kmap_atomic(page);
-       /* Copy the data to the page. */
-       memcpy(addr, (u8*)ctx->attr +
-                       le16_to_cpu(ctx->attr->data.resident.value_offset),
-                       attr_len);
-       /* Zero the remainder of the page. */
-       memset(addr + attr_len, 0, PAGE_SIZE - attr_len);
-       flush_dcache_page(page);
-       kunmap_atomic(addr);
-put_unm_err_out:
-       ntfs_attr_put_search_ctx(ctx);
-unm_err_out:
-       unmap_mft_record(base_ni);
-done:
-       SetPageUptodate(page);
-err_out:
-       unlock_page(page);
-       return err;
-}
-
-#ifdef NTFS_RW
-
-/**
- * ntfs_write_block - write a @folio to the backing store
- * @folio:     page cache folio to write out
- * @wbc:       writeback control structure
- *
- * This function is for writing folios belonging to non-resident, non-mst
- * protected attributes to their backing store.
- *
- * For a folio with buffers, map and write the dirty buffers asynchronously
- * under folio writeback. For a folio without buffers, create buffers for the
- * folio, then proceed as above.
- *
- * If a folio doesn't have buffers the folio dirty state is definitive. If
- * a folio does have buffers, the folio dirty state is just a hint,
- * and the buffer dirty state is definitive. (A hint which has rules:
- * dirty buffers against a clean folio is illegal. Other combinations are
- * legal and need to be handled. In particular a dirty folio containing
- * clean buffers for example.)
- *
- * Return 0 on success and -errno on error.
- *
- * Based on ntfs_read_block() and __block_write_full_folio().
- */
-static int ntfs_write_block(struct folio *folio, struct writeback_control *wbc)
-{
-       VCN vcn;
-       LCN lcn;
-       s64 initialized_size;
-       loff_t i_size;
-       sector_t block, dblock, iblock;
-       struct inode *vi;
-       ntfs_inode *ni;
-       ntfs_volume *vol;
-       runlist_element *rl;
-       struct buffer_head *bh, *head;
-       unsigned long flags;
-       unsigned int blocksize, vcn_ofs;
-       int err;
-       bool need_end_writeback;
-       unsigned char blocksize_bits;
-
-       vi = folio->mapping->host;
-       ni = NTFS_I(vi);
-       vol = ni->vol;
-
-       ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index "
-                       "0x%lx.", ni->mft_no, ni->type, folio->index);
-
-       BUG_ON(!NInoNonResident(ni));
-       BUG_ON(NInoMstProtected(ni));
-       blocksize = vol->sb->s_blocksize;
-       blocksize_bits = vol->sb->s_blocksize_bits;
-       head = folio_buffers(folio);
-       if (!head) {
-               BUG_ON(!folio_test_uptodate(folio));
-               head = create_empty_buffers(folio, blocksize,
-                               (1 << BH_Uptodate) | (1 << BH_Dirty));
-       }
-       bh = head;
-
-       /* NOTE: Different naming scheme to ntfs_read_block()! */
-
-       /* The first block in the folio. */
-       block = (s64)folio->index << (PAGE_SHIFT - blocksize_bits);
-
-       read_lock_irqsave(&ni->size_lock, flags);
-       i_size = i_size_read(vi);
-       initialized_size = ni->initialized_size;
-       read_unlock_irqrestore(&ni->size_lock, flags);
-
-       /* The first out of bounds block for the data size. */
-       dblock = (i_size + blocksize - 1) >> blocksize_bits;
-
-       /* The last (fully or partially) initialized block. */
-       iblock = initialized_size >> blocksize_bits;
-
-       /*
-        * Be very careful.  We have no exclusion from block_dirty_folio
-        * here, and the (potentially unmapped) buffers may become dirty at
-        * any time.  If a buffer becomes dirty here after we've inspected it
-        * then we just miss that fact, and the folio stays dirty.
-        *
-        * Buffers outside i_size may be dirtied by block_dirty_folio;
-        * handle that here by just cleaning them.
-        */
-
-       /*
-        * Loop through all the buffers in the folio, mapping all the dirty
-        * buffers to disk addresses and handling any aliases from the
-        * underlying block device's mapping.
-        */
-       rl = NULL;
-       err = 0;
-       do {
-               bool is_retry = false;
-
-               if (unlikely(block >= dblock)) {
-                       /*
-                        * Mapped buffers outside i_size will occur, because
-                        * this folio can be outside i_size when there is a
-                        * truncate in progress. The contents of such buffers
-                        * were zeroed by ntfs_writepage().
-                        *
-                        * FIXME: What about the small race window where
-                        * ntfs_writepage() has not done any clearing because
-                        * the folio was within i_size but before we get here,
-                        * vmtruncate() modifies i_size?
-                        */
-                       clear_buffer_dirty(bh);
-                       set_buffer_uptodate(bh);
-                       continue;
-               }
-
-               /* Clean buffers are not written out, so no need to map them. */
-               if (!buffer_dirty(bh))
-                       continue;
-
-               /* Make sure we have enough initialized size. */
-               if (unlikely((block >= iblock) &&
-                               (initialized_size < i_size))) {
-                       /*
-                        * If this folio is fully outside initialized
-                        * size, zero out all folios between the current
-                        * initialized size and the current folio. Just
-                        * use ntfs_read_folio() to do the zeroing
-                        * transparently.
-                        */
-                       if (block > iblock) {
-                               // TODO:
-                               // For each folio do:
-                               // - read_cache_folio()
-                               // Again for each folio do:
-                               // - wait_on_folio_locked()
-                               // - Check (folio_test_uptodate(folio) &&
-                               //              !folio_test_error(folio))
-                               // Update initialized size in the attribute and
-                               // in the inode.
-                               // Again, for each folio do:
-                               //      block_dirty_folio();
-                               // folio_put()
-                               // We don't need to wait on the writes.
-                               // Update iblock.
-                       }
-                       /*
-                        * The current folio straddles initialized size. Zero
-                        * all non-uptodate buffers and set them uptodate (and
-                        * dirty?). Note, there aren't any non-uptodate buffers
-                        * if the folio is uptodate.
-                        * FIXME: For an uptodate folio, the buffers may need to
-                        * be written out because they were not initialized on
-                        * disk before.
-                        */
-                       if (!folio_test_uptodate(folio)) {
-                               // TODO:
-                               // Zero any non-uptodate buffers up to i_size.
-                               // Set them uptodate and dirty.
-                       }
-                       // TODO:
-                       // Update initialized size in the attribute and in the
-                       // inode (up to i_size).
-                       // Update iblock.
-                       // FIXME: This is inefficient. Try to batch the two
-                       // size changes to happen in one go.
-                       ntfs_error(vol->sb, "Writing beyond initialized size "
-                                       "is not supported yet. Sorry.");
-                       err = -EOPNOTSUPP;
-                       break;
-                       // Do NOT set_buffer_new() BUT DO clear buffer range
-                       // outside write request range.
-                       // set_buffer_uptodate() on complete buffers as well as
-                       // set_buffer_dirty().
-               }
-
-               /* No need to map buffers that are already mapped. */
-               if (buffer_mapped(bh))
-                       continue;
-
-               /* Unmapped, dirty buffer. Need to map it. */
-               bh->b_bdev = vol->sb->s_bdev;
-
-               /* Convert block into corresponding vcn and offset. */
-               vcn = (VCN)block << blocksize_bits;
-               vcn_ofs = vcn & vol->cluster_size_mask;
-               vcn >>= vol->cluster_size_bits;
-               if (!rl) {
-lock_retry_remap:
-                       down_read(&ni->runlist.lock);
-                       rl = ni->runlist.rl;
-               }
-               if (likely(rl != NULL)) {
-                       /* Seek to element containing target vcn. */
-                       while (rl->length && rl[1].vcn <= vcn)
-                               rl++;
-                       lcn = ntfs_rl_vcn_to_lcn(rl, vcn);
-               } else
-                       lcn = LCN_RL_NOT_MAPPED;
-               /* Successful remap. */
-               if (lcn >= 0) {
-                       /* Setup buffer head to point to correct block. */
-                       bh->b_blocknr = ((lcn << vol->cluster_size_bits) +
-                                       vcn_ofs) >> blocksize_bits;
-                       set_buffer_mapped(bh);
-                       continue;
-               }
-               /* It is a hole, need to instantiate it. */
-               if (lcn == LCN_HOLE) {
-                       u8 *kaddr;
-                       unsigned long *bpos, *bend;
-
-                       /* Check if the buffer is zero. */
-                       kaddr = kmap_local_folio(folio, bh_offset(bh));
-                       bpos = (unsigned long *)kaddr;
-                       bend = (unsigned long *)(kaddr + blocksize);
-                       do {
-                               if (unlikely(*bpos))
-                                       break;
-                       } while (likely(++bpos < bend));
-                       kunmap_local(kaddr);
-                       if (bpos == bend) {
-                               /*
-                                * Buffer is zero and sparse, no need to write
-                                * it.
-                                */
-                               bh->b_blocknr = -1;
-                               clear_buffer_dirty(bh);
-                               continue;
-                       }
-                       // TODO: Instantiate the hole.
-                       // clear_buffer_new(bh);
-                       // clean_bdev_bh_alias(bh);
-                       ntfs_error(vol->sb, "Writing into sparse regions is "
-                                       "not supported yet. Sorry.");
-                       err = -EOPNOTSUPP;
-                       break;
-               }
-               /* If first try and runlist unmapped, map and retry. */
-               if (!is_retry && lcn == LCN_RL_NOT_MAPPED) {
-                       is_retry = true;
-                       /*
-                        * Attempt to map runlist, dropping lock for
-                        * the duration.
-                        */
-                       up_read(&ni->runlist.lock);
-                       err = ntfs_map_runlist(ni, vcn);
-                       if (likely(!err))
-                               goto lock_retry_remap;
-                       rl = NULL;
-               } else if (!rl)
-                       up_read(&ni->runlist.lock);
-               /*
-                * If buffer is outside the runlist, truncate has cut it out
-                * of the runlist.  Just clean and clear the buffer and set it
-                * uptodate so it can get discarded by the VM.
-                */
-               if (err == -ENOENT || lcn == LCN_ENOENT) {
-                       bh->b_blocknr = -1;
-                       clear_buffer_dirty(bh);
-                       folio_zero_range(folio, bh_offset(bh), blocksize);
-                       set_buffer_uptodate(bh);
-                       err = 0;
-                       continue;
-               }
-               /* Failed to map the buffer, even after retrying. */
-               if (!err)
-                       err = -EIO;
-               bh->b_blocknr = -1;
-               ntfs_error(vol->sb, "Failed to write to inode 0x%lx, "
-                               "attribute type 0x%x, vcn 0x%llx, offset 0x%x "
-                               "because its location on disk could not be "
-                               "determined%s (error code %i).", ni->mft_no,
-                               ni->type, (unsigned long long)vcn,
-                               vcn_ofs, is_retry ? " even after "
-                               "retrying" : "", err);
-               break;
-       } while (block++, (bh = bh->b_this_page) != head);
-
-       /* Release the lock if we took it. */
-       if (rl)
-               up_read(&ni->runlist.lock);
-
-       /* For the error case, need to reset bh to the beginning. */
-       bh = head;
-
-       /* Just an optimization, so ->read_folio() is not called later. */
-       if (unlikely(!folio_test_uptodate(folio))) {
-               int uptodate = 1;
-               do {
-                       if (!buffer_uptodate(bh)) {
-                               uptodate = 0;
-                               bh = head;
-                               break;
-                       }
-               } while ((bh = bh->b_this_page) != head);
-               if (uptodate)
-                       folio_mark_uptodate(folio);
-       }
-
-       /* Setup all mapped, dirty buffers for async write i/o. */
-       do {
-               if (buffer_mapped(bh) && buffer_dirty(bh)) {
-                       lock_buffer(bh);
-                       if (test_clear_buffer_dirty(bh)) {
-                               BUG_ON(!buffer_uptodate(bh));
-                               mark_buffer_async_write(bh);
-                       } else
-                               unlock_buffer(bh);
-               } else if (unlikely(err)) {
-                       /*
-                        * For the error case. The buffer may have been set
-                        * dirty during attachment to a dirty folio.
-                        */
-                       if (err != -ENOMEM)
-                               clear_buffer_dirty(bh);
-               }
-       } while ((bh = bh->b_this_page) != head);
-
-       if (unlikely(err)) {
-               // TODO: Remove the -EOPNOTSUPP check later on...
-               if (unlikely(err == -EOPNOTSUPP))
-                       err = 0;
-               else if (err == -ENOMEM) {
-                       ntfs_warning(vol->sb, "Error allocating memory. "
-                                       "Redirtying folio so we try again "
-                                       "later.");
-                       /*
-                        * Put the folio back on mapping->dirty_pages, but
-                        * leave its buffer's dirty state as-is.
-                        */
-                       folio_redirty_for_writepage(wbc, folio);
-                       err = 0;
-               } else
-                       folio_set_error(folio);
-       }
-
-       BUG_ON(folio_test_writeback(folio));
-       folio_start_writeback(folio);   /* Keeps try_to_free_buffers() away. */
-
-       /* Submit the prepared buffers for i/o. */
-       need_end_writeback = true;
-       do {
-               struct buffer_head *next = bh->b_this_page;
-               if (buffer_async_write(bh)) {
-                       submit_bh(REQ_OP_WRITE, bh);
-                       need_end_writeback = false;
-               }
-               bh = next;
-       } while (bh != head);
-       folio_unlock(folio);
-
-       /* If no i/o was started, need to end writeback here. */
-       if (unlikely(need_end_writeback))
-               folio_end_writeback(folio);
-
-       ntfs_debug("Done.");
-       return err;
-}
-
-/**
- * ntfs_write_mst_block - write a @page to the backing store
- * @page:      page cache page to write out
- * @wbc:       writeback control structure
- *
- * This function is for writing pages belonging to non-resident, mst protected
- * attributes to their backing store.  The only supported attributes are index
- * allocation and $MFT/$DATA.  Both directory inodes and index inodes are
- * supported for the index allocation case.
- *
- * The page must remain locked for the duration of the write because we apply
- * the mst fixups, write, and then undo the fixups, so if we were to unlock the
- * page before undoing the fixups, any other user of the page will see the
- * page contents as corrupt.
- *
- * We clear the page uptodate flag for the duration of the function to ensure
- * exclusion for the $MFT/$DATA case against someone mapping an mft record we
- * are about to apply the mst fixups to.
- *
- * Return 0 on success and -errno on error.
- *
- * Based on ntfs_write_block(), ntfs_mft_writepage(), and
- * write_mft_record_nolock().
- */
-static int ntfs_write_mst_block(struct page *page,
-               struct writeback_control *wbc)
-{
-       sector_t block, dblock, rec_block;
-       struct inode *vi = page->mapping->host;
-       ntfs_inode *ni = NTFS_I(vi);
-       ntfs_volume *vol = ni->vol;
-       u8 *kaddr;
-       unsigned int rec_size = ni->itype.index.block_size;
-       ntfs_inode *locked_nis[PAGE_SIZE / NTFS_BLOCK_SIZE];
-       struct buffer_head *bh, *head, *tbh, *rec_start_bh;
-       struct buffer_head *bhs[MAX_BUF_PER_PAGE];
-       runlist_element *rl;
-       int i, nr_locked_nis, nr_recs, nr_bhs, max_bhs, bhs_per_rec, err, err2;
-       unsigned bh_size, rec_size_bits;
-       bool sync, is_mft, page_is_dirty, rec_is_dirty;
-       unsigned char bh_size_bits;
-
-       if (WARN_ON(rec_size < NTFS_BLOCK_SIZE))
-               return -EINVAL;
-
-       ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index "
-                       "0x%lx.", vi->i_ino, ni->type, page->index);
-       BUG_ON(!NInoNonResident(ni));
-       BUG_ON(!NInoMstProtected(ni));
-       is_mft = (S_ISREG(vi->i_mode) && !vi->i_ino);
-       /*
-        * NOTE: ntfs_write_mst_block() would be called for $MFTMirr if a page
-        * in its page cache were to be marked dirty.  However this should
-        * never happen with the current driver and considering we do not
-        * handle this case here we do want to BUG(), at least for now.
-        */
-       BUG_ON(!(is_mft || S_ISDIR(vi->i_mode) ||
-                       (NInoAttr(ni) && ni->type == AT_INDEX_ALLOCATION)));
-       bh_size = vol->sb->s_blocksize;
-       bh_size_bits = vol->sb->s_blocksize_bits;
-       max_bhs = PAGE_SIZE / bh_size;
-       BUG_ON(!max_bhs);
-       BUG_ON(max_bhs > MAX_BUF_PER_PAGE);
-
-       /* Were we called for sync purposes? */
-       sync = (wbc->sync_mode == WB_SYNC_ALL);
-
-       /* Make sure we have mapped buffers. */
-       bh = head = page_buffers(page);
-       BUG_ON(!bh);
-
-       rec_size_bits = ni->itype.index.block_size_bits;
-       BUG_ON(!(PAGE_SIZE >> rec_size_bits));
-       bhs_per_rec = rec_size >> bh_size_bits;
-       BUG_ON(!bhs_per_rec);
-
-       /* The first block in the page. */
-       rec_block = block = (sector_t)page->index <<
-                       (PAGE_SHIFT - bh_size_bits);
-
-       /* The first out of bounds block for the data size. */
-       dblock = (i_size_read(vi) + bh_size - 1) >> bh_size_bits;
-
-       rl = NULL;
-       err = err2 = nr_bhs = nr_recs = nr_locked_nis = 0;
-       page_is_dirty = rec_is_dirty = false;
-       rec_start_bh = NULL;
-       do {
-               bool is_retry = false;
-
-               if (likely(block < rec_block)) {
-                       if (unlikely(block >= dblock)) {
-                               clear_buffer_dirty(bh);
-                               set_buffer_uptodate(bh);
-                               continue;
-                       }
-                       /*
-                        * This block is not the first one in the record.  We
-                        * ignore the buffer's dirty state because we could
-                        * have raced with a parallel mark_ntfs_record_dirty().
-                        */
-                       if (!rec_is_dirty)
-                               continue;
-                       if (unlikely(err2)) {
-                               if (err2 != -ENOMEM)
-                                       clear_buffer_dirty(bh);
-                               continue;
-                       }
-               } else /* if (block == rec_block) */ {
-                       BUG_ON(block > rec_block);
-                       /* This block is the first one in the record. */
-                       rec_block += bhs_per_rec;
-                       err2 = 0;
-                       if (unlikely(block >= dblock)) {
-                               clear_buffer_dirty(bh);
-                               continue;
-                       }
-                       if (!buffer_dirty(bh)) {
-                               /* Clean records are not written out. */
-                               rec_is_dirty = false;
-                               continue;
-                       }
-                       rec_is_dirty = true;
-                       rec_start_bh = bh;
-               }
-               /* Need to map the buffer if it is not mapped already. */
-               if (unlikely(!buffer_mapped(bh))) {
-                       VCN vcn;
-                       LCN lcn;
-                       unsigned int vcn_ofs;
-
-                       bh->b_bdev = vol->sb->s_bdev;
-                       /* Obtain the vcn and offset of the current block. */
-                       vcn = (VCN)block << bh_size_bits;
-                       vcn_ofs = vcn & vol->cluster_size_mask;
-                       vcn >>= vol->cluster_size_bits;
-                       if (!rl) {
-lock_retry_remap:
-                               down_read(&ni->runlist.lock);
-                               rl = ni->runlist.rl;
-                       }
-                       if (likely(rl != NULL)) {
-                               /* Seek to element containing target vcn. */
-                               while (rl->length && rl[1].vcn <= vcn)
-                                       rl++;
-                               lcn = ntfs_rl_vcn_to_lcn(rl, vcn);
-                       } else
-                               lcn = LCN_RL_NOT_MAPPED;
-                       /* Successful remap. */
-                       if (likely(lcn >= 0)) {
-                               /* Setup buffer head to correct block. */
-                               bh->b_blocknr = ((lcn <<
-                                               vol->cluster_size_bits) +
-                                               vcn_ofs) >> bh_size_bits;
-                               set_buffer_mapped(bh);
-                       } else {
-                               /*
-                                * Remap failed.  Retry to map the runlist once
-                                * unless we are working on $MFT which always
-                                * has the whole of its runlist in memory.
-                                */
-                               if (!is_mft && !is_retry &&
-                                               lcn == LCN_RL_NOT_MAPPED) {
-                                       is_retry = true;
-                                       /*
-                                        * Attempt to map runlist, dropping
-                                        * lock for the duration.
-                                        */
-                                       up_read(&ni->runlist.lock);
-                                       err2 = ntfs_map_runlist(ni, vcn);
-                                       if (likely(!err2))
-                                               goto lock_retry_remap;
-                                       if (err2 == -ENOMEM)
-                                               page_is_dirty = true;
-                                       lcn = err2;
-                               } else {
-                                       err2 = -EIO;
-                                       if (!rl)
-                                               up_read(&ni->runlist.lock);
-                               }
-                               /* Hard error.  Abort writing this record. */
-                               if (!err || err == -ENOMEM)
-                                       err = err2;
-                               bh->b_blocknr = -1;
-                               ntfs_error(vol->sb, "Cannot write ntfs record "
-                                               "0x%llx (inode 0x%lx, "
-                                               "attribute type 0x%x) because "
-                                               "its location on disk could "
-                                               "not be determined (error "
-                                               "code %lli).",
-                                               (long long)block <<
-                                               bh_size_bits >>
-                                               vol->mft_record_size_bits,
-                                               ni->mft_no, ni->type,
-                                               (long long)lcn);
-                               /*
-                                * If this is not the first buffer, remove the
-                                * buffers in this record from the list of
-                                * buffers to write and clear their dirty bit
-                                * if not error -ENOMEM.
-                                */
-                               if (rec_start_bh != bh) {
-                                       while (bhs[--nr_bhs] != rec_start_bh)
-                                               ;
-                                       if (err2 != -ENOMEM) {
-                                               do {
-                                                       clear_buffer_dirty(
-                                                               rec_start_bh);
-                                               } while ((rec_start_bh =
-                                                               rec_start_bh->
-                                                               b_this_page) !=
-                                                               bh);
-                                       }
-                               }
-                               continue;
-                       }
-               }
-               BUG_ON(!buffer_uptodate(bh));
-               BUG_ON(nr_bhs >= max_bhs);
-               bhs[nr_bhs++] = bh;
-       } while (block++, (bh = bh->b_this_page) != head);
-       if (unlikely(rl))
-               up_read(&ni->runlist.lock);
-       /* If there were no dirty buffers, we are done. */
-       if (!nr_bhs)
-               goto done;
-       /* Map the page so we can access its contents. */
-       kaddr = kmap(page);
-       /* Clear the page uptodate flag whilst the mst fixups are applied. */
-       BUG_ON(!PageUptodate(page));
-       ClearPageUptodate(page);
-       for (i = 0; i < nr_bhs; i++) {
-               unsigned int ofs;
-
-               /* Skip buffers which are not at the beginning of records. */
-               if (i % bhs_per_rec)
-                       continue;
-               tbh = bhs[i];
-               ofs = bh_offset(tbh);
-               if (is_mft) {
-                       ntfs_inode *tni;
-                       unsigned long mft_no;
-
-                       /* Get the mft record number. */
-                       mft_no = (((s64)page->index << PAGE_SHIFT) + ofs)
-                                       >> rec_size_bits;
-                       /* Check whether to write this mft record. */
-                       tni = NULL;
-                       if (!ntfs_may_write_mft_record(vol, mft_no,
-                                       (MFT_RECORD*)(kaddr + ofs), &tni)) {
-                               /*
-                                * The record should not be written.  This
-                                * means we need to redirty the page before
-                                * returning.
-                                */
-                               page_is_dirty = true;
-                               /*
-                                * Remove the buffers in this mft record from
-                                * the list of buffers to write.
-                                */
-                               do {
-                                       bhs[i] = NULL;
-                               } while (++i % bhs_per_rec);
-                               continue;
-                       }
-                       /*
-                        * The record should be written.  If a locked ntfs
-                        * inode was returned, add it to the array of locked
-                        * ntfs inodes.
-                        */
-                       if (tni)
-                               locked_nis[nr_locked_nis++] = tni;
-               }
-               /* Apply the mst protection fixups. */
-               err2 = pre_write_mst_fixup((NTFS_RECORD*)(kaddr + ofs),
-                               rec_size);
-               if (unlikely(err2)) {
-                       if (!err || err == -ENOMEM)
-                               err = -EIO;
-                       ntfs_error(vol->sb, "Failed to apply mst fixups "
-                                       "(inode 0x%lx, attribute type 0x%x, "
-                                       "page index 0x%lx, page offset 0x%x)!"
-                                       "  Unmount and run chkdsk.", vi->i_ino,
-                                       ni->type, page->index, ofs);
-                       /*
-                        * Mark all the buffers in this record clean as we do
-                        * not want to write corrupt data to disk.
-                        */
-                       do {
-                               clear_buffer_dirty(bhs[i]);
-                               bhs[i] = NULL;
-                       } while (++i % bhs_per_rec);
-                       continue;
-               }
-               nr_recs++;
-       }
-       /* If no records are to be written out, we are done. */
-       if (!nr_recs)
-               goto unm_done;
-       flush_dcache_page(page);
-       /* Lock buffers and start synchronous write i/o on them. */
-       for (i = 0; i < nr_bhs; i++) {
-               tbh = bhs[i];
-               if (!tbh)
-                       continue;
-               if (!trylock_buffer(tbh))
-                       BUG();
-               /* The buffer dirty state is now irrelevant, just clean it. */
-               clear_buffer_dirty(tbh);
-               BUG_ON(!buffer_uptodate(tbh));
-               BUG_ON(!buffer_mapped(tbh));
-               get_bh(tbh);
-               tbh->b_end_io = end_buffer_write_sync;
-               submit_bh(REQ_OP_WRITE, tbh);
-       }
-       /* Synchronize the mft mirror now if not @sync. */
-       if (is_mft && !sync)
-               goto do_mirror;
-do_wait:
-       /* Wait on i/o completion of buffers. */
-       for (i = 0; i < nr_bhs; i++) {
-               tbh = bhs[i];
-               if (!tbh)
-                       continue;
-               wait_on_buffer(tbh);
-               if (unlikely(!buffer_uptodate(tbh))) {
-                       ntfs_error(vol->sb, "I/O error while writing ntfs "
-                                       "record buffer (inode 0x%lx, "
-                                       "attribute type 0x%x, page index "
-                                       "0x%lx, page offset 0x%lx)!  Unmount "
-                                       "and run chkdsk.", vi->i_ino, ni->type,
-                                       page->index, bh_offset(tbh));
-                       if (!err || err == -ENOMEM)
-                               err = -EIO;
-                       /*
-                        * Set the buffer uptodate so the page and buffer
-                        * states do not become out of sync.
-                        */
-                       set_buffer_uptodate(tbh);
-               }
-       }
-       /* If @sync, now synchronize the mft mirror. */
-       if (is_mft && sync) {
-do_mirror:
-               for (i = 0; i < nr_bhs; i++) {
-                       unsigned long mft_no;
-                       unsigned int ofs;
-
-                       /*
-                        * Skip buffers which are not at the beginning of
-                        * records.
-                        */
-                       if (i % bhs_per_rec)
-                               continue;
-                       tbh = bhs[i];
-                       /* Skip removed buffers (and hence records). */
-                       if (!tbh)
-                               continue;
-                       ofs = bh_offset(tbh);
-                       /* Get the mft record number. */
-                       mft_no = (((s64)page->index << PAGE_SHIFT) + ofs)
-                                       >> rec_size_bits;
-                       if (mft_no < vol->mftmirr_size)
-                               ntfs_sync_mft_mirror(vol, mft_no,
-                                               (MFT_RECORD*)(kaddr + ofs),
-                                               sync);
-               }
-               if (!sync)
-                       goto do_wait;
-       }
-       /* Remove the mst protection fixups again. */
-       for (i = 0; i < nr_bhs; i++) {
-               if (!(i % bhs_per_rec)) {
-                       tbh = bhs[i];
-                       if (!tbh)
-                               continue;
-                       post_write_mst_fixup((NTFS_RECORD*)(kaddr +
-                                       bh_offset(tbh)));
-               }
-       }
-       flush_dcache_page(page);
-unm_done:
-       /* Unlock any locked inodes. */
-       while (nr_locked_nis-- > 0) {
-               ntfs_inode *tni, *base_tni;
-               
-               tni = locked_nis[nr_locked_nis];
-               /* Get the base inode. */
-               mutex_lock(&tni->extent_lock);
-               if (tni->nr_extents >= 0)
-                       base_tni = tni;
-               else {
-                       base_tni = tni->ext.base_ntfs_ino;
-                       BUG_ON(!base_tni);
-               }
-               mutex_unlock(&tni->extent_lock);
-               ntfs_debug("Unlocking %s inode 0x%lx.",
-                               tni == base_tni ? "base" : "extent",
-                               tni->mft_no);
-               mutex_unlock(&tni->mrec_lock);
-               atomic_dec(&tni->count);
-               iput(VFS_I(base_tni));
-       }
-       SetPageUptodate(page);
-       kunmap(page);
-done:
-       if (unlikely(err && err != -ENOMEM)) {
-               /*
-                * Set page error if there is only one ntfs record in the page.
-                * Otherwise we would loose per-record granularity.
-                */
-               if (ni->itype.index.block_size == PAGE_SIZE)
-                       SetPageError(page);
-               NVolSetErrors(vol);
-       }
-       if (page_is_dirty) {
-               ntfs_debug("Page still contains one or more dirty ntfs "
-                               "records.  Redirtying the page starting at "
-                               "record 0x%lx.", page->index <<
-                               (PAGE_SHIFT - rec_size_bits));
-               redirty_page_for_writepage(wbc, page);
-               unlock_page(page);
-       } else {
-               /*
-                * Keep the VM happy.  This must be done otherwise the
-                * radix-tree tag PAGECACHE_TAG_DIRTY remains set even though
-                * the page is clean.
-                */
-               BUG_ON(PageWriteback(page));
-               set_page_writeback(page);
-               unlock_page(page);
-               end_page_writeback(page);
-       }
-       if (likely(!err))
-               ntfs_debug("Done.");
-       return err;
-}
-
-/**
- * ntfs_writepage - write a @page to the backing store
- * @page:      page cache page to write out
- * @wbc:       writeback control structure
- *
- * This is called from the VM when it wants to have a dirty ntfs page cache
- * page cleaned.  The VM has already locked the page and marked it clean.
- *
- * For non-resident attributes, ntfs_writepage() writes the @page by calling
- * the ntfs version of the generic block_write_full_folio() function,
- * ntfs_write_block(), which in turn if necessary creates and writes the
- * buffers associated with the page asynchronously.
- *
- * For resident attributes, OTOH, ntfs_writepage() writes the @page by copying
- * the data to the mft record (which at this stage is most likely in memory).
- * The mft record is then marked dirty and written out asynchronously via the
- * vfs inode dirty code path for the inode the mft record belongs to or via the
- * vm page dirty code path for the page the mft record is in.
- *
- * Based on ntfs_read_folio() and fs/buffer.c::block_write_full_folio().
- *
- * Return 0 on success and -errno on error.
- */
-static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
-{
-       struct folio *folio = page_folio(page);
-       loff_t i_size;
-       struct inode *vi = folio->mapping->host;
-       ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi);
-       char *addr;
-       ntfs_attr_search_ctx *ctx = NULL;
-       MFT_RECORD *m = NULL;
-       u32 attr_len;
-       int err;
-
-retry_writepage:
-       BUG_ON(!folio_test_locked(folio));
-       i_size = i_size_read(vi);
-       /* Is the folio fully outside i_size? (truncate in progress) */
-       if (unlikely(folio->index >= (i_size + PAGE_SIZE - 1) >>
-                       PAGE_SHIFT)) {
-               /*
-                * The folio may have dirty, unmapped buffers.  Make them
-                * freeable here, so the page does not leak.
-                */
-               block_invalidate_folio(folio, 0, folio_size(folio));
-               folio_unlock(folio);
-               ntfs_debug("Write outside i_size - truncated?");
-               return 0;
-       }
-       /*
-        * Only $DATA attributes can be encrypted and only unnamed $DATA
-        * attributes can be compressed.  Index root can have the flags set but
-        * this means to create compressed/encrypted files, not that the
-        * attribute is compressed/encrypted.  Note we need to check for
-        * AT_INDEX_ALLOCATION since this is the type of both directory and
-        * index inodes.
-        */
-       if (ni->type != AT_INDEX_ALLOCATION) {
-               /* If file is encrypted, deny access, just like NT4. */
-               if (NInoEncrypted(ni)) {
-                       folio_unlock(folio);
-                       BUG_ON(ni->type != AT_DATA);
-                       ntfs_debug("Denying write access to encrypted file.");
-                       return -EACCES;
-               }
-               /* Compressed data streams are handled in compress.c. */
-               if (NInoNonResident(ni) && NInoCompressed(ni)) {
-                       BUG_ON(ni->type != AT_DATA);
-                       BUG_ON(ni->name_len);
-                       // TODO: Implement and replace this with
-                       // return ntfs_write_compressed_block(page);
-                       folio_unlock(folio);
-                       ntfs_error(vi->i_sb, "Writing to compressed files is "
-                                       "not supported yet.  Sorry.");
-                       return -EOPNOTSUPP;
-               }
-               // TODO: Implement and remove this check.
-               if (NInoNonResident(ni) && NInoSparse(ni)) {
-                       folio_unlock(folio);
-                       ntfs_error(vi->i_sb, "Writing to sparse files is not "
-                                       "supported yet.  Sorry.");
-                       return -EOPNOTSUPP;
-               }
-       }
-       /* NInoNonResident() == NInoIndexAllocPresent() */
-       if (NInoNonResident(ni)) {
-               /* We have to zero every time due to mmap-at-end-of-file. */
-               if (folio->index >= (i_size >> PAGE_SHIFT)) {
-                       /* The folio straddles i_size. */
-                       unsigned int ofs = i_size & (folio_size(folio) - 1);
-                       folio_zero_segment(folio, ofs, folio_size(folio));
-               }
-               /* Handle mst protected attributes. */
-               if (NInoMstProtected(ni))
-                       return ntfs_write_mst_block(page, wbc);
-               /* Normal, non-resident data stream. */
-               return ntfs_write_block(folio, wbc);
-       }
-       /*
-        * Attribute is resident, implying it is not compressed, encrypted, or
-        * mst protected.  This also means the attribute is smaller than an mft
-        * record and hence smaller than a folio, so can simply return error on
-        * any folios with index above 0.  Note the attribute can actually be
-        * marked compressed but if it is resident the actual data is not
-        * compressed so we are ok to ignore the compressed flag here.
-        */
-       BUG_ON(folio_buffers(folio));
-       BUG_ON(!folio_test_uptodate(folio));
-       if (unlikely(folio->index > 0)) {
-               ntfs_error(vi->i_sb, "BUG()! folio->index (0x%lx) > 0.  "
-                               "Aborting write.", folio->index);
-               BUG_ON(folio_test_writeback(folio));
-               folio_start_writeback(folio);
-               folio_unlock(folio);
-               folio_end_writeback(folio);
-               return -EIO;
-       }
-       if (!NInoAttr(ni))
-               base_ni = ni;
-       else
-               base_ni = ni->ext.base_ntfs_ino;
-       /* Map, pin, and lock the mft record. */
-       m = map_mft_record(base_ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               m = NULL;
-               ctx = NULL;
-               goto err_out;
-       }
-       /*
-        * If a parallel write made the attribute non-resident, drop the mft
-        * record and retry the writepage.
-        */
-       if (unlikely(NInoNonResident(ni))) {
-               unmap_mft_record(base_ni);
-               goto retry_writepage;
-       }
-       ctx = ntfs_attr_get_search_ctx(base_ni, m);
-       if (unlikely(!ctx)) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err))
-               goto err_out;
-       /*
-        * Keep the VM happy.  This must be done otherwise
-        * PAGECACHE_TAG_DIRTY remains set even though the folio is clean.
-        */
-       BUG_ON(folio_test_writeback(folio));
-       folio_start_writeback(folio);
-       folio_unlock(folio);
-       attr_len = le32_to_cpu(ctx->attr->data.resident.value_length);
-       i_size = i_size_read(vi);
-       if (unlikely(attr_len > i_size)) {
-               /* Race with shrinking truncate or a failed truncate. */
-               attr_len = i_size;
-               /*
-                * If the truncate failed, fix it up now.  If a concurrent
-                * truncate, we do its job, so it does not have to do anything.
-                */
-               err = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
-                               attr_len);
-               /* Shrinking cannot fail. */
-               BUG_ON(err);
-       }
-       addr = kmap_local_folio(folio, 0);
-       /* Copy the data from the folio to the mft record. */
-       memcpy((u8*)ctx->attr +
-                       le16_to_cpu(ctx->attr->data.resident.value_offset),
-                       addr, attr_len);
-       /* Zero out of bounds area in the page cache folio. */
-       memset(addr + attr_len, 0, folio_size(folio) - attr_len);
-       kunmap_local(addr);
-       flush_dcache_folio(folio);
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       /* We are done with the folio. */
-       folio_end_writeback(folio);
-       /* Finally, mark the mft record dirty, so it gets written back. */
-       mark_mft_record_dirty(ctx->ntfs_ino);
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(base_ni);
-       return 0;
-err_out:
-       if (err == -ENOMEM) {
-               ntfs_warning(vi->i_sb, "Error allocating memory. Redirtying "
-                               "page so we try again later.");
-               /*
-                * Put the folio back on mapping->dirty_pages, but leave its
-                * buffers' dirty state as-is.
-                */
-               folio_redirty_for_writepage(wbc, folio);
-               err = 0;
-       } else {
-               ntfs_error(vi->i_sb, "Resident attribute write failed with "
-                               "error %i.", err);
-               folio_set_error(folio);
-               NVolSetErrors(ni->vol);
-       }
-       folio_unlock(folio);
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(base_ni);
-       return err;
-}
-
-#endif /* NTFS_RW */
-
-/**
- * ntfs_bmap - map logical file block to physical device block
- * @mapping:   address space mapping to which the block to be mapped belongs
- * @block:     logical block to map to its physical device block
- *
- * For regular, non-resident files (i.e. not compressed and not encrypted), map
- * the logical @block belonging to the file described by the address space
- * mapping @mapping to its physical device block.
- *
- * The size of the block is equal to the @s_blocksize field of the super block
- * of the mounted file system which is guaranteed to be smaller than or equal
- * to the cluster size thus the block is guaranteed to fit entirely inside the
- * cluster which means we do not need to care how many contiguous bytes are
- * available after the beginning of the block.
- *
- * Return the physical device block if the mapping succeeded or 0 if the block
- * is sparse or there was an error.
- *
- * Note: This is a problem if someone tries to run bmap() on $Boot system file
- * as that really is in block zero but there is nothing we can do.  bmap() is
- * just broken in that respect (just like it cannot distinguish sparse from
- * not available or error).
- */
-static sector_t ntfs_bmap(struct address_space *mapping, sector_t block)
-{
-       s64 ofs, size;
-       loff_t i_size;
-       LCN lcn;
-       unsigned long blocksize, flags;
-       ntfs_inode *ni = NTFS_I(mapping->host);
-       ntfs_volume *vol = ni->vol;
-       unsigned delta;
-       unsigned char blocksize_bits, cluster_size_shift;
-
-       ntfs_debug("Entering for mft_no 0x%lx, logical block 0x%llx.",
-                       ni->mft_no, (unsigned long long)block);
-       if (ni->type != AT_DATA || !NInoNonResident(ni) || NInoEncrypted(ni)) {
-               ntfs_error(vol->sb, "BMAP does not make sense for %s "
-                               "attributes, returning 0.",
-                               (ni->type != AT_DATA) ? "non-data" :
-                               (!NInoNonResident(ni) ? "resident" :
-                               "encrypted"));
-               return 0;
-       }
-       /* None of these can happen. */
-       BUG_ON(NInoCompressed(ni));
-       BUG_ON(NInoMstProtected(ni));
-       blocksize = vol->sb->s_blocksize;
-       blocksize_bits = vol->sb->s_blocksize_bits;
-       ofs = (s64)block << blocksize_bits;
-       read_lock_irqsave(&ni->size_lock, flags);
-       size = ni->initialized_size;
-       i_size = i_size_read(VFS_I(ni));
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       /*
-        * If the offset is outside the initialized size or the block straddles
-        * the initialized size then pretend it is a hole unless the
-        * initialized size equals the file size.
-        */
-       if (unlikely(ofs >= size || (ofs + blocksize > size && size < i_size)))
-               goto hole;
-       cluster_size_shift = vol->cluster_size_bits;
-       down_read(&ni->runlist.lock);
-       lcn = ntfs_attr_vcn_to_lcn_nolock(ni, ofs >> cluster_size_shift, false);
-       up_read(&ni->runlist.lock);
-       if (unlikely(lcn < LCN_HOLE)) {
-               /*
-                * Step down to an integer to avoid gcc doing a long long
-                * comparision in the switch when we know @lcn is between
-                * LCN_HOLE and LCN_EIO (i.e. -1 to -5).
-                *
-                * Otherwise older gcc (at least on some architectures) will
-                * try to use __cmpdi2() which is of course not available in
-                * the kernel.
-                */
-               switch ((int)lcn) {
-               case LCN_ENOENT:
-                       /*
-                        * If the offset is out of bounds then pretend it is a
-                        * hole.
-                        */
-                       goto hole;
-               case LCN_ENOMEM:
-                       ntfs_error(vol->sb, "Not enough memory to complete "
-                                       "mapping for inode 0x%lx.  "
-                                       "Returning 0.", ni->mft_no);
-                       break;
-               default:
-                       ntfs_error(vol->sb, "Failed to complete mapping for "
-                                       "inode 0x%lx.  Run chkdsk.  "
-                                       "Returning 0.", ni->mft_no);
-                       break;
-               }
-               return 0;
-       }
-       if (lcn < 0) {
-               /* It is a hole. */
-hole:
-               ntfs_debug("Done (returning hole).");
-               return 0;
-       }
-       /*
-        * The block is really allocated and fullfils all our criteria.
-        * Convert the cluster to units of block size and return the result.
-        */
-       delta = ofs & vol->cluster_size_mask;
-       if (unlikely(sizeof(block) < sizeof(lcn))) {
-               block = lcn = ((lcn << cluster_size_shift) + delta) >>
-                               blocksize_bits;
-               /* If the block number was truncated return 0. */
-               if (unlikely(block != lcn)) {
-                       ntfs_error(vol->sb, "Physical block 0x%llx is too "
-                                       "large to be returned, returning 0.",
-                                       (long long)lcn);
-                       return 0;
-               }
-       } else
-               block = ((lcn << cluster_size_shift) + delta) >>
-                               blocksize_bits;
-       ntfs_debug("Done (returning block 0x%llx).", (unsigned long long)lcn);
-       return block;
-}
-
-/*
- * ntfs_normal_aops - address space operations for normal inodes and attributes
- *
- * Note these are not used for compressed or mst protected inodes and
- * attributes.
- */
-const struct address_space_operations ntfs_normal_aops = {
-       .read_folio     = ntfs_read_folio,
-#ifdef NTFS_RW
-       .writepage      = ntfs_writepage,
-       .dirty_folio    = block_dirty_folio,
-#endif /* NTFS_RW */
-       .bmap           = ntfs_bmap,
-       .migrate_folio  = buffer_migrate_folio,
-       .is_partially_uptodate = block_is_partially_uptodate,
-       .error_remove_folio = generic_error_remove_folio,
-};
-
-/*
- * ntfs_compressed_aops - address space operations for compressed inodes
- */
-const struct address_space_operations ntfs_compressed_aops = {
-       .read_folio     = ntfs_read_folio,
-#ifdef NTFS_RW
-       .writepage      = ntfs_writepage,
-       .dirty_folio    = block_dirty_folio,
-#endif /* NTFS_RW */
-       .migrate_folio  = buffer_migrate_folio,
-       .is_partially_uptodate = block_is_partially_uptodate,
-       .error_remove_folio = generic_error_remove_folio,
-};
-
-/*
- * ntfs_mst_aops - general address space operations for mst protecteed inodes
- *                       and attributes
- */
-const struct address_space_operations ntfs_mst_aops = {
-       .read_folio     = ntfs_read_folio,      /* Fill page with data. */
-#ifdef NTFS_RW
-       .writepage      = ntfs_writepage,       /* Write dirty page to disk. */
-       .dirty_folio    = filemap_dirty_folio,
-#endif /* NTFS_RW */
-       .migrate_folio  = buffer_migrate_folio,
-       .is_partially_uptodate  = block_is_partially_uptodate,
-       .error_remove_folio = generic_error_remove_folio,
-};
-
-#ifdef NTFS_RW
-
-/**
- * mark_ntfs_record_dirty - mark an ntfs record dirty
- * @page:      page containing the ntfs record to mark dirty
- * @ofs:       byte offset within @page at which the ntfs record begins
- *
- * Set the buffers and the page in which the ntfs record is located dirty.
- *
- * The latter also marks the vfs inode the ntfs record belongs to dirty
- * (I_DIRTY_PAGES only).
- *
- * If the page does not have buffers, we create them and set them uptodate.
- * The page may not be locked which is why we need to handle the buffers under
- * the mapping->i_private_lock.  Once the buffers are marked dirty we no longer
- * need the lock since try_to_free_buffers() does not free dirty buffers.
- */
-void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs) {
-       struct address_space *mapping = page->mapping;
-       ntfs_inode *ni = NTFS_I(mapping->host);
-       struct buffer_head *bh, *head, *buffers_to_free = NULL;
-       unsigned int end, bh_size, bh_ofs;
-
-       BUG_ON(!PageUptodate(page));
-       end = ofs + ni->itype.index.block_size;
-       bh_size = VFS_I(ni)->i_sb->s_blocksize;
-       spin_lock(&mapping->i_private_lock);
-       if (unlikely(!page_has_buffers(page))) {
-               spin_unlock(&mapping->i_private_lock);
-               bh = head = alloc_page_buffers(page, bh_size, true);
-               spin_lock(&mapping->i_private_lock);
-               if (likely(!page_has_buffers(page))) {
-                       struct buffer_head *tail;
-
-                       do {
-                               set_buffer_uptodate(bh);
-                               tail = bh;
-                               bh = bh->b_this_page;
-                       } while (bh);
-                       tail->b_this_page = head;
-                       attach_page_private(page, head);
-               } else
-                       buffers_to_free = bh;
-       }
-       bh = head = page_buffers(page);
-       BUG_ON(!bh);
-       do {
-               bh_ofs = bh_offset(bh);
-               if (bh_ofs + bh_size <= ofs)
-                       continue;
-               if (unlikely(bh_ofs >= end))
-                       break;
-               set_buffer_dirty(bh);
-       } while ((bh = bh->b_this_page) != head);
-       spin_unlock(&mapping->i_private_lock);
-       filemap_dirty_folio(mapping, page_folio(page));
-       if (unlikely(buffers_to_free)) {
-               do {
-                       bh = buffers_to_free->b_this_page;
-                       free_buffer_head(buffers_to_free);
-                       buffers_to_free = bh;
-               } while (buffers_to_free);
-       }
-}
-
-#endif /* NTFS_RW */
diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h
deleted file mode 100644 (file)
index 8d0958a..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * aops.h - Defines for NTFS kernel address space operations and page cache
- *         handling.  Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2004 Anton Altaparmakov
- * Copyright (c) 2002 Richard Russon
- */
-
-#ifndef _LINUX_NTFS_AOPS_H
-#define _LINUX_NTFS_AOPS_H
-
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/pagemap.h>
-#include <linux/fs.h>
-
-#include "inode.h"
-
-/**
- * ntfs_unmap_page - release a page that was mapped using ntfs_map_page()
- * @page:      the page to release
- *
- * Unpin, unmap and release a page that was obtained from ntfs_map_page().
- */
-static inline void ntfs_unmap_page(struct page *page)
-{
-       kunmap(page);
-       put_page(page);
-}
-
-/**
- * ntfs_map_page - map a page into accessible memory, reading it if necessary
- * @mapping:   address space for which to obtain the page
- * @index:     index into the page cache for @mapping of the page to map
- *
- * Read a page from the page cache of the address space @mapping at position
- * @index, where @index is in units of PAGE_SIZE, and not in bytes.
- *
- * If the page is not in memory it is loaded from disk first using the
- * read_folio method defined in the address space operations of @mapping
- * and the page is added to the page cache of @mapping in the process.
- *
- * If the page belongs to an mst protected attribute and it is marked as such
- * in its ntfs inode (NInoMstProtected()) the mst fixups are applied but no
- * error checking is performed.  This means the caller has to verify whether
- * the ntfs record(s) contained in the page are valid or not using one of the
- * ntfs_is_XXXX_record{,p}() macros, where XXXX is the record type you are
- * expecting to see.  (For details of the macros, see fs/ntfs/layout.h.)
- *
- * If the page is in high memory it is mapped into memory directly addressible
- * by the kernel.
- *
- * Finally the page count is incremented, thus pinning the page into place.
- *
- * The above means that page_address(page) can be used on all pages obtained
- * with ntfs_map_page() to get the kernel virtual address of the page.
- *
- * When finished with the page, the caller has to call ntfs_unmap_page() to
- * unpin, unmap and release the page.
- *
- * Note this does not grant exclusive access. If such is desired, the caller
- * must provide it independently of the ntfs_{un}map_page() calls by using
- * a {rw_}semaphore or other means of serialization. A spin lock cannot be
- * used as ntfs_map_page() can block.
- *
- * The unlocked and uptodate page is returned on success or an encoded error
- * on failure. Caller has to test for error using the IS_ERR() macro on the
- * return value. If that evaluates to 'true', the negative error code can be
- * obtained using PTR_ERR() on the return value of ntfs_map_page().
- */
-static inline struct page *ntfs_map_page(struct address_space *mapping,
-               unsigned long index)
-{
-       struct page *page = read_mapping_page(mapping, index, NULL);
-
-       if (!IS_ERR(page))
-               kmap(page);
-       return page;
-}
-
-#ifdef NTFS_RW
-
-extern void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs);
-
-#endif /* NTFS_RW */
-
-#endif /* _LINUX_NTFS_AOPS_H */
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
deleted file mode 100644 (file)
index f79408f..0000000
+++ /dev/null
@@ -1,2624 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * attrib.c - NTFS attribute operations.  Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2012 Anton Altaparmakov and Tuxera Inc.
- * Copyright (c) 2002 Richard Russon
- */
-
-#include <linux/buffer_head.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/swap.h>
-#include <linux/writeback.h>
-
-#include "attrib.h"
-#include "debug.h"
-#include "layout.h"
-#include "lcnalloc.h"
-#include "malloc.h"
-#include "mft.h"
-#include "ntfs.h"
-#include "types.h"
-
-/**
- * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode
- * @ni:                ntfs inode for which to map (part of) a runlist
- * @vcn:       map runlist part containing this vcn
- * @ctx:       active attribute search context if present or NULL if not
- *
- * Map the part of a runlist containing the @vcn of the ntfs inode @ni.
- *
- * If @ctx is specified, it is an active search context of @ni and its base mft
- * record.  This is needed when ntfs_map_runlist_nolock() encounters unmapped
- * runlist fragments and allows their mapping.  If you do not have the mft
- * record mapped, you can specify @ctx as NULL and ntfs_map_runlist_nolock()
- * will perform the necessary mapping and unmapping.
- *
- * Note, ntfs_map_runlist_nolock() saves the state of @ctx on entry and
- * restores it before returning.  Thus, @ctx will be left pointing to the same
- * attribute on return as on entry.  However, the actual pointers in @ctx may
- * point to different memory locations on return, so you must remember to reset
- * any cached pointers from the @ctx, i.e. after the call to
- * ntfs_map_runlist_nolock(), you will probably want to do:
- *     m = ctx->mrec;
- *     a = ctx->attr;
- * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that
- * you cache ctx->mrec in a variable @m of type MFT_RECORD *.
- *
- * Return 0 on success and -errno on error.  There is one special error code
- * which is not an error as such.  This is -ENOENT.  It means that @vcn is out
- * of bounds of the runlist.
- *
- * Note the runlist can be NULL after this function returns if @vcn is zero and
- * the attribute has zero allocated size, i.e. there simply is no runlist.
- *
- * WARNING: If @ctx is supplied, regardless of whether success or failure is
- *         returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
- *         is no longer valid, i.e. you need to either call
- *         ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
- *         In that case PTR_ERR(@ctx->mrec) will give you the error code for
- *         why the mapping of the old inode failed.
- *
- * Locking: - The runlist described by @ni must be locked for writing on entry
- *           and is locked on return.  Note the runlist will be modified.
- *         - If @ctx is NULL, the base mft record of @ni must not be mapped on
- *           entry and it will be left unmapped on return.
- *         - If @ctx is not NULL, the base mft record must be mapped on entry
- *           and it will be left mapped on return.
- */
-int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx)
-{
-       VCN end_vcn;
-       unsigned long flags;
-       ntfs_inode *base_ni;
-       MFT_RECORD *m;
-       ATTR_RECORD *a;
-       runlist_element *rl;
-       struct page *put_this_page = NULL;
-       int err = 0;
-       bool ctx_is_temporary, ctx_needs_reset;
-       ntfs_attr_search_ctx old_ctx = { NULL, };
-
-       ntfs_debug("Mapping runlist part containing vcn 0x%llx.",
-                       (unsigned long long)vcn);
-       if (!NInoAttr(ni))
-               base_ni = ni;
-       else
-               base_ni = ni->ext.base_ntfs_ino;
-       if (!ctx) {
-               ctx_is_temporary = ctx_needs_reset = true;
-               m = map_mft_record(base_ni);
-               if (IS_ERR(m))
-                       return PTR_ERR(m);
-               ctx = ntfs_attr_get_search_ctx(base_ni, m);
-               if (unlikely(!ctx)) {
-                       err = -ENOMEM;
-                       goto err_out;
-               }
-       } else {
-               VCN allocated_size_vcn;
-
-               BUG_ON(IS_ERR(ctx->mrec));
-               a = ctx->attr;
-               BUG_ON(!a->non_resident);
-               ctx_is_temporary = false;
-               end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn);
-               read_lock_irqsave(&ni->size_lock, flags);
-               allocated_size_vcn = ni->allocated_size >>
-                               ni->vol->cluster_size_bits;
-               read_unlock_irqrestore(&ni->size_lock, flags);
-               if (!a->data.non_resident.lowest_vcn && end_vcn <= 0)
-                       end_vcn = allocated_size_vcn - 1;
-               /*
-                * If we already have the attribute extent containing @vcn in
-                * @ctx, no need to look it up again.  We slightly cheat in
-                * that if vcn exceeds the allocated size, we will refuse to
-                * map the runlist below, so there is definitely no need to get
-                * the right attribute extent.
-                */
-               if (vcn >= allocated_size_vcn || (a->type == ni->type &&
-                               a->name_length == ni->name_len &&
-                               !memcmp((u8*)a + le16_to_cpu(a->name_offset),
-                               ni->name, ni->name_len) &&
-                               sle64_to_cpu(a->data.non_resident.lowest_vcn)
-                               <= vcn && end_vcn >= vcn))
-                       ctx_needs_reset = false;
-               else {
-                       /* Save the old search context. */
-                       old_ctx = *ctx;
-                       /*
-                        * If the currently mapped (extent) inode is not the
-                        * base inode we will unmap it when we reinitialize the
-                        * search context which means we need to get a
-                        * reference to the page containing the mapped mft
-                        * record so we do not accidentally drop changes to the
-                        * mft record when it has not been marked dirty yet.
-                        */
-                       if (old_ctx.base_ntfs_ino && old_ctx.ntfs_ino !=
-                                       old_ctx.base_ntfs_ino) {
-                               put_this_page = old_ctx.ntfs_ino->page;
-                               get_page(put_this_page);
-                       }
-                       /*
-                        * Reinitialize the search context so we can lookup the
-                        * needed attribute extent.
-                        */
-                       ntfs_attr_reinit_search_ctx(ctx);
-                       ctx_needs_reset = true;
-               }
-       }
-       if (ctx_needs_reset) {
-               err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                               CASE_SENSITIVE, vcn, NULL, 0, ctx);
-               if (unlikely(err)) {
-                       if (err == -ENOENT)
-                               err = -EIO;
-                       goto err_out;
-               }
-               BUG_ON(!ctx->attr->non_resident);
-       }
-       a = ctx->attr;
-       /*
-        * Only decompress the mapping pairs if @vcn is inside it.  Otherwise
-        * we get into problems when we try to map an out of bounds vcn because
-        * we then try to map the already mapped runlist fragment and
-        * ntfs_mapping_pairs_decompress() fails.
-        */
-       end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1;
-       if (unlikely(vcn && vcn >= end_vcn)) {
-               err = -ENOENT;
-               goto err_out;
-       }
-       rl = ntfs_mapping_pairs_decompress(ni->vol, a, ni->runlist.rl);
-       if (IS_ERR(rl))
-               err = PTR_ERR(rl);
-       else
-               ni->runlist.rl = rl;
-err_out:
-       if (ctx_is_temporary) {
-               if (likely(ctx))
-                       ntfs_attr_put_search_ctx(ctx);
-               unmap_mft_record(base_ni);
-       } else if (ctx_needs_reset) {
-               /*
-                * If there is no attribute list, restoring the search context
-                * is accomplished simply by copying the saved context back over
-                * the caller supplied context.  If there is an attribute list,
-                * things are more complicated as we need to deal with mapping
-                * of mft records and resulting potential changes in pointers.
-                */
-               if (NInoAttrList(base_ni)) {
-                       /*
-                        * If the currently mapped (extent) inode is not the
-                        * one we had before, we need to unmap it and map the
-                        * old one.
-                        */
-                       if (ctx->ntfs_ino != old_ctx.ntfs_ino) {
-                               /*
-                                * If the currently mapped inode is not the
-                                * base inode, unmap it.
-                                */
-                               if (ctx->base_ntfs_ino && ctx->ntfs_ino !=
-                                               ctx->base_ntfs_ino) {
-                                       unmap_extent_mft_record(ctx->ntfs_ino);
-                                       ctx->mrec = ctx->base_mrec;
-                                       BUG_ON(!ctx->mrec);
-                               }
-                               /*
-                                * If the old mapped inode is not the base
-                                * inode, map it.
-                                */
-                               if (old_ctx.base_ntfs_ino &&
-                                               old_ctx.ntfs_ino !=
-                                               old_ctx.base_ntfs_ino) {
-retry_map:
-                                       ctx->mrec = map_mft_record(
-                                                       old_ctx.ntfs_ino);
-                                       /*
-                                        * Something bad has happened.  If out
-                                        * of memory retry till it succeeds.
-                                        * Any other errors are fatal and we
-                                        * return the error code in ctx->mrec.
-                                        * Let the caller deal with it...  We
-                                        * just need to fudge things so the
-                                        * caller can reinit and/or put the
-                                        * search context safely.
-                                        */
-                                       if (IS_ERR(ctx->mrec)) {
-                                               if (PTR_ERR(ctx->mrec) ==
-                                                               -ENOMEM) {
-                                                       schedule();
-                                                       goto retry_map;
-                                               } else
-                                                       old_ctx.ntfs_ino =
-                                                               old_ctx.
-                                                               base_ntfs_ino;
-                                       }
-                               }
-                       }
-                       /* Update the changed pointers in the saved context. */
-                       if (ctx->mrec != old_ctx.mrec) {
-                               if (!IS_ERR(ctx->mrec))
-                                       old_ctx.attr = (ATTR_RECORD*)(
-                                                       (u8*)ctx->mrec +
-                                                       ((u8*)old_ctx.attr -
-                                                       (u8*)old_ctx.mrec));
-                               old_ctx.mrec = ctx->mrec;
-                       }
-               }
-               /* Restore the search context to the saved one. */
-               *ctx = old_ctx;
-               /*
-                * We drop the reference on the page we took earlier.  In the
-                * case that IS_ERR(ctx->mrec) is true this means we might lose
-                * some changes to the mft record that had been made between
-                * the last time it was marked dirty/written out and now.  This
-                * at this stage is not a problem as the mapping error is fatal
-                * enough that the mft record cannot be written out anyway and
-                * the caller is very likely to shutdown the whole inode
-                * immediately and mark the volume dirty for chkdsk to pick up
-                * the pieces anyway.
-                */
-               if (put_this_page)
-                       put_page(put_this_page);
-       }
-       return err;
-}
-
-/**
- * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode
- * @ni:                ntfs inode for which to map (part of) a runlist
- * @vcn:       map runlist part containing this vcn
- *
- * Map the part of a runlist containing the @vcn of the ntfs inode @ni.
- *
- * Return 0 on success and -errno on error.  There is one special error code
- * which is not an error as such.  This is -ENOENT.  It means that @vcn is out
- * of bounds of the runlist.
- *
- * Locking: - The runlist must be unlocked on entry and is unlocked on return.
- *         - This function takes the runlist lock for writing and may modify
- *           the runlist.
- */
-int ntfs_map_runlist(ntfs_inode *ni, VCN vcn)
-{
-       int err = 0;
-
-       down_write(&ni->runlist.lock);
-       /* Make sure someone else didn't do the work while we were sleeping. */
-       if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <=
-                       LCN_RL_NOT_MAPPED))
-               err = ntfs_map_runlist_nolock(ni, vcn, NULL);
-       up_write(&ni->runlist.lock);
-       return err;
-}
-
-/**
- * ntfs_attr_vcn_to_lcn_nolock - convert a vcn into a lcn given an ntfs inode
- * @ni:                        ntfs inode of the attribute whose runlist to search
- * @vcn:               vcn to convert
- * @write_locked:      true if the runlist is locked for writing
- *
- * Find the virtual cluster number @vcn in the runlist of the ntfs attribute
- * described by the ntfs inode @ni and return the corresponding logical cluster
- * number (lcn).
- *
- * If the @vcn is not mapped yet, the attempt is made to map the attribute
- * extent containing the @vcn and the vcn to lcn conversion is retried.
- *
- * If @write_locked is true the caller has locked the runlist for writing and
- * if false for reading.
- *
- * Since lcns must be >= 0, we use negative return codes with special meaning:
- *
- * Return code Meaning / Description
- * ==========================================
- *  LCN_HOLE   Hole / not allocated on disk.
- *  LCN_ENOENT There is no such vcn in the runlist, i.e. @vcn is out of bounds.
- *  LCN_ENOMEM Not enough memory to map runlist.
- *  LCN_EIO    Critical error (runlist/file is corrupt, i/o error, etc).
- *
- * Locking: - The runlist must be locked on entry and is left locked on return.
- *         - If @write_locked is 'false', i.e. the runlist is locked for reading,
- *           the lock may be dropped inside the function so you cannot rely on
- *           the runlist still being the same when this function returns.
- */
-LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
-               const bool write_locked)
-{
-       LCN lcn;
-       unsigned long flags;
-       bool is_retry = false;
-
-       BUG_ON(!ni);
-       ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.",
-                       ni->mft_no, (unsigned long long)vcn,
-                       write_locked ? "write" : "read");
-       BUG_ON(!NInoNonResident(ni));
-       BUG_ON(vcn < 0);
-       if (!ni->runlist.rl) {
-               read_lock_irqsave(&ni->size_lock, flags);
-               if (!ni->allocated_size) {
-                       read_unlock_irqrestore(&ni->size_lock, flags);
-                       return LCN_ENOENT;
-               }
-               read_unlock_irqrestore(&ni->size_lock, flags);
-       }
-retry_remap:
-       /* Convert vcn to lcn.  If that fails map the runlist and retry once. */
-       lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn);
-       if (likely(lcn >= LCN_HOLE)) {
-               ntfs_debug("Done, lcn 0x%llx.", (long long)lcn);
-               return lcn;
-       }
-       if (lcn != LCN_RL_NOT_MAPPED) {
-               if (lcn != LCN_ENOENT)
-                       lcn = LCN_EIO;
-       } else if (!is_retry) {
-               int err;
-
-               if (!write_locked) {
-                       up_read(&ni->runlist.lock);
-                       down_write(&ni->runlist.lock);
-                       if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) !=
-                                       LCN_RL_NOT_MAPPED)) {
-                               up_write(&ni->runlist.lock);
-                               down_read(&ni->runlist.lock);
-                               goto retry_remap;
-                       }
-               }
-               err = ntfs_map_runlist_nolock(ni, vcn, NULL);
-               if (!write_locked) {
-                       up_write(&ni->runlist.lock);
-                       down_read(&ni->runlist.lock);
-               }
-               if (likely(!err)) {
-                       is_retry = true;
-                       goto retry_remap;
-               }
-               if (err == -ENOENT)
-                       lcn = LCN_ENOENT;
-               else if (err == -ENOMEM)
-                       lcn = LCN_ENOMEM;
-               else
-                       lcn = LCN_EIO;
-       }
-       if (lcn != LCN_ENOENT)
-               ntfs_error(ni->vol->sb, "Failed with error code %lli.",
-                               (long long)lcn);
-       return lcn;
-}
-
-/**
- * ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode
- * @ni:                ntfs inode describing the runlist to search
- * @vcn:       vcn to find
- * @ctx:       active attribute search context if present or NULL if not
- *
- * Find the virtual cluster number @vcn in the runlist described by the ntfs
- * inode @ni and return the address of the runlist element containing the @vcn.
- *
- * If the @vcn is not mapped yet, the attempt is made to map the attribute
- * extent containing the @vcn and the vcn to lcn conversion is retried.
- *
- * If @ctx is specified, it is an active search context of @ni and its base mft
- * record.  This is needed when ntfs_attr_find_vcn_nolock() encounters unmapped
- * runlist fragments and allows their mapping.  If you do not have the mft
- * record mapped, you can specify @ctx as NULL and ntfs_attr_find_vcn_nolock()
- * will perform the necessary mapping and unmapping.
- *
- * Note, ntfs_attr_find_vcn_nolock() saves the state of @ctx on entry and
- * restores it before returning.  Thus, @ctx will be left pointing to the same
- * attribute on return as on entry.  However, the actual pointers in @ctx may
- * point to different memory locations on return, so you must remember to reset
- * any cached pointers from the @ctx, i.e. after the call to
- * ntfs_attr_find_vcn_nolock(), you will probably want to do:
- *     m = ctx->mrec;
- *     a = ctx->attr;
- * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that
- * you cache ctx->mrec in a variable @m of type MFT_RECORD *.
- * Note you need to distinguish between the lcn of the returned runlist element
- * being >= 0 and LCN_HOLE.  In the later case you have to return zeroes on
- * read and allocate clusters on write.
- *
- * Return the runlist element containing the @vcn on success and
- * ERR_PTR(-errno) on error.  You need to test the return value with IS_ERR()
- * to decide if the return is success or failure and PTR_ERR() to get to the
- * error code if IS_ERR() is true.
- *
- * The possible error return codes are:
- *     -ENOENT - No such vcn in the runlist, i.e. @vcn is out of bounds.
- *     -ENOMEM - Not enough memory to map runlist.
- *     -EIO    - Critical error (runlist/file is corrupt, i/o error, etc).
- *
- * WARNING: If @ctx is supplied, regardless of whether success or failure is
- *         returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
- *         is no longer valid, i.e. you need to either call
- *         ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
- *         In that case PTR_ERR(@ctx->mrec) will give you the error code for
- *         why the mapping of the old inode failed.
- *
- * Locking: - The runlist described by @ni must be locked for writing on entry
- *           and is locked on return.  Note the runlist may be modified when
- *           needed runlist fragments need to be mapped.
- *         - If @ctx is NULL, the base mft record of @ni must not be mapped on
- *           entry and it will be left unmapped on return.
- *         - If @ctx is not NULL, the base mft record must be mapped on entry
- *           and it will be left mapped on return.
- */
-runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn,
-               ntfs_attr_search_ctx *ctx)
-{
-       unsigned long flags;
-       runlist_element *rl;
-       int err = 0;
-       bool is_retry = false;
-
-       BUG_ON(!ni);
-       ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.",
-                       ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out");
-       BUG_ON(!NInoNonResident(ni));
-       BUG_ON(vcn < 0);
-       if (!ni->runlist.rl) {
-               read_lock_irqsave(&ni->size_lock, flags);
-               if (!ni->allocated_size) {
-                       read_unlock_irqrestore(&ni->size_lock, flags);
-                       return ERR_PTR(-ENOENT);
-               }
-               read_unlock_irqrestore(&ni->size_lock, flags);
-       }
-retry_remap:
-       rl = ni->runlist.rl;
-       if (likely(rl && vcn >= rl[0].vcn)) {
-               while (likely(rl->length)) {
-                       if (unlikely(vcn < rl[1].vcn)) {
-                               if (likely(rl->lcn >= LCN_HOLE)) {
-                                       ntfs_debug("Done.");
-                                       return rl;
-                               }
-                               break;
-                       }
-                       rl++;
-               }
-               if (likely(rl->lcn != LCN_RL_NOT_MAPPED)) {
-                       if (likely(rl->lcn == LCN_ENOENT))
-                               err = -ENOENT;
-                       else
-                               err = -EIO;
-               }
-       }
-       if (!err && !is_retry) {
-               /*
-                * If the search context is invalid we cannot map the unmapped
-                * region.
-                */
-               if (IS_ERR(ctx->mrec))
-                       err = PTR_ERR(ctx->mrec);
-               else {
-                       /*
-                        * The @vcn is in an unmapped region, map the runlist
-                        * and retry.
-                        */
-                       err = ntfs_map_runlist_nolock(ni, vcn, ctx);
-                       if (likely(!err)) {
-                               is_retry = true;
-                               goto retry_remap;
-                       }
-               }
-               if (err == -EINVAL)
-                       err = -EIO;
-       } else if (!err)
-               err = -EIO;
-       if (err != -ENOENT)
-               ntfs_error(ni->vol->sb, "Failed with error code %i.", err);
-       return ERR_PTR(err);
-}
-
-/**
- * ntfs_attr_find - find (next) attribute in mft record
- * @type:      attribute type to find
- * @name:      attribute name to find (optional, i.e. NULL means don't care)
- * @name_len:  attribute name length (only needed if @name present)
- * @ic:                IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
- * @val:       attribute value to find (optional, resident attributes only)
- * @val_len:   attribute value length
- * @ctx:       search context with mft record and attribute to search from
- *
- * You should not need to call this function directly.  Use ntfs_attr_lookup()
- * instead.
- *
- * ntfs_attr_find() takes a search context @ctx as parameter and searches the
- * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an
- * attribute of @type, optionally @name and @val.
- *
- * If the attribute is found, ntfs_attr_find() returns 0 and @ctx->attr will
- * point to the found attribute.
- *
- * If the attribute is not found, ntfs_attr_find() returns -ENOENT and
- * @ctx->attr will point to the attribute before which the attribute being
- * searched for would need to be inserted if such an action were to be desired.
- *
- * On actual error, ntfs_attr_find() returns -EIO.  In this case @ctx->attr is
- * undefined and in particular do not rely on it not changing.
- *
- * If @ctx->is_first is 'true', the search begins with @ctx->attr itself.  If it
- * is 'false', the search begins after @ctx->attr.
- *
- * If @ic is IGNORE_CASE, the @name comparisson is not case sensitive and
- * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record
- * @ctx->mrec belongs.  This is so we can get at the ntfs volume and hence at
- * the upcase table.  If @ic is CASE_SENSITIVE, the comparison is case
- * sensitive.  When @name is present, @name_len is the @name length in Unicode
- * characters.
- *
- * If @name is not present (NULL), we assume that the unnamed attribute is
- * being searched for.
- *
- * Finally, the resident attribute value @val is looked for, if present.  If
- * @val is not present (NULL), @val_len is ignored.
- *
- * ntfs_attr_find() only searches the specified mft record and it ignores the
- * presence of an attribute list attribute (unless it is the one being searched
- * for, obviously).  If you need to take attribute lists into consideration,
- * use ntfs_attr_lookup() instead (see below).  This also means that you cannot
- * use ntfs_attr_find() to search for extent records of non-resident
- * attributes, as extents with lowest_vcn != 0 are usually described by the
- * attribute list attribute only. - Note that it is possible that the first
- * extent is only in the attribute list while the last extent is in the base
- * mft record, so do not rely on being able to find the first extent in the
- * base mft record.
- *
- * Warning: Never use @val when looking for attribute types which can be
- *         non-resident as this most likely will result in a crash!
- */
-static int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name,
-               const u32 name_len, const IGNORE_CASE_BOOL ic,
-               const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx)
-{
-       ATTR_RECORD *a;
-       ntfs_volume *vol = ctx->ntfs_ino->vol;
-       ntfschar *upcase = vol->upcase;
-       u32 upcase_len = vol->upcase_len;
-
-       /*
-        * Iterate over attributes in mft record starting at @ctx->attr, or the
-        * attribute following that, if @ctx->is_first is 'true'.
-        */
-       if (ctx->is_first) {
-               a = ctx->attr;
-               ctx->is_first = false;
-       } else
-               a = (ATTR_RECORD*)((u8*)ctx->attr +
-                               le32_to_cpu(ctx->attr->length));
-       for (;; a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) {
-               u8 *mrec_end = (u8 *)ctx->mrec +
-                              le32_to_cpu(ctx->mrec->bytes_allocated);
-               u8 *name_end;
-
-               /* check whether ATTR_RECORD wrap */
-               if ((u8 *)a < (u8 *)ctx->mrec)
-                       break;
-
-               /* check whether Attribute Record Header is within bounds */
-               if ((u8 *)a > mrec_end ||
-                   (u8 *)a + sizeof(ATTR_RECORD) > mrec_end)
-                       break;
-
-               /* check whether ATTR_RECORD's name is within bounds */
-               name_end = (u8 *)a + le16_to_cpu(a->name_offset) +
-                          a->name_length * sizeof(ntfschar);
-               if (name_end > mrec_end)
-                       break;
-
-               ctx->attr = a;
-               if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) ||
-                               a->type == AT_END))
-                       return -ENOENT;
-               if (unlikely(!a->length))
-                       break;
-
-               /* check whether ATTR_RECORD's length wrap */
-               if ((u8 *)a + le32_to_cpu(a->length) < (u8 *)a)
-                       break;
-               /* check whether ATTR_RECORD's length is within bounds */
-               if ((u8 *)a + le32_to_cpu(a->length) > mrec_end)
-                       break;
-
-               if (a->type != type)
-                       continue;
-               /*
-                * If @name is present, compare the two names.  If @name is
-                * missing, assume we want an unnamed attribute.
-                */
-               if (!name) {
-                       /* The search failed if the found attribute is named. */
-                       if (a->name_length)
-                               return -ENOENT;
-               } else if (!ntfs_are_names_equal(name, name_len,
-                           (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
-                           a->name_length, ic, upcase, upcase_len)) {
-                       register int rc;
-
-                       rc = ntfs_collate_names(name, name_len,
-                                       (ntfschar*)((u8*)a +
-                                       le16_to_cpu(a->name_offset)),
-                                       a->name_length, 1, IGNORE_CASE,
-                                       upcase, upcase_len);
-                       /*
-                        * If @name collates before a->name, there is no
-                        * matching attribute.
-                        */
-                       if (rc == -1)
-                               return -ENOENT;
-                       /* If the strings are not equal, continue search. */
-                       if (rc)
-                               continue;
-                       rc = ntfs_collate_names(name, name_len,
-                                       (ntfschar*)((u8*)a +
-                                       le16_to_cpu(a->name_offset)),
-                                       a->name_length, 1, CASE_SENSITIVE,
-                                       upcase, upcase_len);
-                       if (rc == -1)
-                               return -ENOENT;
-                       if (rc)
-                               continue;
-               }
-               /*
-                * The names match or @name not present and attribute is
-                * unnamed.  If no @val specified, we have found the attribute
-                * and are done.
-                */
-               if (!val)
-                       return 0;
-               /* @val is present; compare values. */
-               else {
-                       register int rc;
-
-                       rc = memcmp(val, (u8*)a + le16_to_cpu(
-                                       a->data.resident.value_offset),
-                                       min_t(u32, val_len, le32_to_cpu(
-                                       a->data.resident.value_length)));
-                       /*
-                        * If @val collates before the current attribute's
-                        * value, there is no matching attribute.
-                        */
-                       if (!rc) {
-                               register u32 avl;
-
-                               avl = le32_to_cpu(
-                                               a->data.resident.value_length);
-                               if (val_len == avl)
-                                       return 0;
-                               if (val_len < avl)
-                                       return -ENOENT;
-                       } else if (rc < 0)
-                               return -ENOENT;
-               }
-       }
-       ntfs_error(vol->sb, "Inode is corrupt.  Run chkdsk.");
-       NVolSetErrors(vol);
-       return -EIO;
-}
-
-/**
- * load_attribute_list - load an attribute list into memory
- * @vol:               ntfs volume from which to read
- * @runlist:           runlist of the attribute list
- * @al_start:          destination buffer
- * @size:              size of the destination buffer in bytes
- * @initialized_size:  initialized size of the attribute list
- *
- * Walk the runlist @runlist and load all clusters from it copying them into
- * the linear buffer @al. The maximum number of bytes copied to @al is @size
- * bytes. Note, @size does not need to be a multiple of the cluster size. If
- * @initialized_size is less than @size, the region in @al between
- * @initialized_size and @size will be zeroed and not read from disk.
- *
- * Return 0 on success or -errno on error.
- */
-int load_attribute_list(ntfs_volume *vol, runlist *runlist, u8 *al_start,
-               const s64 size, const s64 initialized_size)
-{
-       LCN lcn;
-       u8 *al = al_start;
-       u8 *al_end = al + initialized_size;
-       runlist_element *rl;
-       struct buffer_head *bh;
-       struct super_block *sb;
-       unsigned long block_size;
-       unsigned long block, max_block;
-       int err = 0;
-       unsigned char block_size_bits;
-
-       ntfs_debug("Entering.");
-       if (!vol || !runlist || !al || size <= 0 || initialized_size < 0 ||
-                       initialized_size > size)
-               return -EINVAL;
-       if (!initialized_size) {
-               memset(al, 0, size);
-               return 0;
-       }
-       sb = vol->sb;
-       block_size = sb->s_blocksize;
-       block_size_bits = sb->s_blocksize_bits;
-       down_read(&runlist->lock);
-       rl = runlist->rl;
-       if (!rl) {
-               ntfs_error(sb, "Cannot read attribute list since runlist is "
-                               "missing.");
-               goto err_out;   
-       }
-       /* Read all clusters specified by the runlist one run at a time. */
-       while (rl->length) {
-               lcn = ntfs_rl_vcn_to_lcn(rl, rl->vcn);
-               ntfs_debug("Reading vcn = 0x%llx, lcn = 0x%llx.",
-                               (unsigned long long)rl->vcn,
-                               (unsigned long long)lcn);
-               /* The attribute list cannot be sparse. */
-               if (lcn < 0) {
-                       ntfs_error(sb, "ntfs_rl_vcn_to_lcn() failed.  Cannot "
-                                       "read attribute list.");
-                       goto err_out;
-               }
-               block = lcn << vol->cluster_size_bits >> block_size_bits;
-               /* Read the run from device in chunks of block_size bytes. */
-               max_block = block + (rl->length << vol->cluster_size_bits >>
-                               block_size_bits);
-               ntfs_debug("max_block = 0x%lx.", max_block);
-               do {
-                       ntfs_debug("Reading block = 0x%lx.", block);
-                       bh = sb_bread(sb, block);
-                       if (!bh) {
-                               ntfs_error(sb, "sb_bread() failed. Cannot "
-                                               "read attribute list.");
-                               goto err_out;
-                       }
-                       if (al + block_size >= al_end)
-                               goto do_final;
-                       memcpy(al, bh->b_data, block_size);
-                       brelse(bh);
-                       al += block_size;
-               } while (++block < max_block);
-               rl++;
-       }
-       if (initialized_size < size) {
-initialize:
-               memset(al_start + initialized_size, 0, size - initialized_size);
-       }
-done:
-       up_read(&runlist->lock);
-       return err;
-do_final:
-       if (al < al_end) {
-               /*
-                * Partial block.
-                *
-                * Note: The attribute list can be smaller than its allocation
-                * by multiple clusters.  This has been encountered by at least
-                * two people running Windows XP, thus we cannot do any
-                * truncation sanity checking here. (AIA)
-                */
-               memcpy(al, bh->b_data, al_end - al);
-               brelse(bh);
-               if (initialized_size < size)
-                       goto initialize;
-               goto done;
-       }
-       brelse(bh);
-       /* Real overflow! */
-       ntfs_error(sb, "Attribute list buffer overflow. Read attribute list "
-                       "is truncated.");
-err_out:
-       err = -EIO;
-       goto done;
-}
-
-/**
- * ntfs_external_attr_find - find an attribute in the attribute list of an inode
- * @type:      attribute type to find
- * @name:      attribute name to find (optional, i.e. NULL means don't care)
- * @name_len:  attribute name length (only needed if @name present)
- * @ic:                IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
- * @lowest_vcn:        lowest vcn to find (optional, non-resident attributes only)
- * @val:       attribute value to find (optional, resident attributes only)
- * @val_len:   attribute value length
- * @ctx:       search context with mft record and attribute to search from
- *
- * You should not need to call this function directly.  Use ntfs_attr_lookup()
- * instead.
- *
- * Find an attribute by searching the attribute list for the corresponding
- * attribute list entry.  Having found the entry, map the mft record if the
- * attribute is in a different mft record/inode, ntfs_attr_find() the attribute
- * in there and return it.
- *
- * On first search @ctx->ntfs_ino must be the base mft record and @ctx must
- * have been obtained from a call to ntfs_attr_get_search_ctx().  On subsequent
- * calls @ctx->ntfs_ino can be any extent inode, too (@ctx->base_ntfs_ino is
- * then the base inode).
- *
- * After finishing with the attribute/mft record you need to call
- * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any
- * mapped inodes, etc).
- *
- * If the attribute is found, ntfs_external_attr_find() returns 0 and
- * @ctx->attr will point to the found attribute.  @ctx->mrec will point to the
- * mft record in which @ctx->attr is located and @ctx->al_entry will point to
- * the attribute list entry for the attribute.
- *
- * If the attribute is not found, ntfs_external_attr_find() returns -ENOENT and
- * @ctx->attr will point to the attribute in the base mft record before which
- * the attribute being searched for would need to be inserted if such an action
- * were to be desired.  @ctx->mrec will point to the mft record in which
- * @ctx->attr is located and @ctx->al_entry will point to the attribute list
- * entry of the attribute before which the attribute being searched for would
- * need to be inserted if such an action were to be desired.
- *
- * Thus to insert the not found attribute, one wants to add the attribute to
- * @ctx->mrec (the base mft record) and if there is not enough space, the
- * attribute should be placed in a newly allocated extent mft record.  The
- * attribute list entry for the inserted attribute should be inserted in the
- * attribute list attribute at @ctx->al_entry.
- *
- * On actual error, ntfs_external_attr_find() returns -EIO.  In this case
- * @ctx->attr is undefined and in particular do not rely on it not changing.
- */
-static int ntfs_external_attr_find(const ATTR_TYPE type,
-               const ntfschar *name, const u32 name_len,
-               const IGNORE_CASE_BOOL ic, const VCN lowest_vcn,
-               const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx)
-{
-       ntfs_inode *base_ni, *ni;
-       ntfs_volume *vol;
-       ATTR_LIST_ENTRY *al_entry, *next_al_entry;
-       u8 *al_start, *al_end;
-       ATTR_RECORD *a;
-       ntfschar *al_name;
-       u32 al_name_len;
-       int err = 0;
-       static const char *es = " Unmount and run chkdsk.";
-
-       ni = ctx->ntfs_ino;
-       base_ni = ctx->base_ntfs_ino;
-       ntfs_debug("Entering for inode 0x%lx, type 0x%x.", ni->mft_no, type);
-       if (!base_ni) {
-               /* First call happens with the base mft record. */
-               base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino;
-               ctx->base_mrec = ctx->mrec;
-       }
-       if (ni == base_ni)
-               ctx->base_attr = ctx->attr;
-       if (type == AT_END)
-               goto not_found;
-       vol = base_ni->vol;
-       al_start = base_ni->attr_list;
-       al_end = al_start + base_ni->attr_list_size;
-       if (!ctx->al_entry)
-               ctx->al_entry = (ATTR_LIST_ENTRY*)al_start;
-       /*
-        * Iterate over entries in attribute list starting at @ctx->al_entry,
-        * or the entry following that, if @ctx->is_first is 'true'.
-        */
-       if (ctx->is_first) {
-               al_entry = ctx->al_entry;
-               ctx->is_first = false;
-       } else
-               al_entry = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +
-                               le16_to_cpu(ctx->al_entry->length));
-       for (;; al_entry = next_al_entry) {
-               /* Out of bounds check. */
-               if ((u8*)al_entry < base_ni->attr_list ||
-                               (u8*)al_entry > al_end)
-                       break;  /* Inode is corrupt. */
-               ctx->al_entry = al_entry;
-               /* Catch the end of the attribute list. */
-               if ((u8*)al_entry == al_end)
-                       goto not_found;
-               if (!al_entry->length)
-                       break;
-               if ((u8*)al_entry + 6 > al_end || (u8*)al_entry +
-                               le16_to_cpu(al_entry->length) > al_end)
-                       break;
-               next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry +
-                               le16_to_cpu(al_entry->length));
-               if (le32_to_cpu(al_entry->type) > le32_to_cpu(type))
-                       goto not_found;
-               if (type != al_entry->type)
-                       continue;
-               /*
-                * If @name is present, compare the two names.  If @name is
-                * missing, assume we want an unnamed attribute.
-                */
-               al_name_len = al_entry->name_length;
-               al_name = (ntfschar*)((u8*)al_entry + al_entry->name_offset);
-               if (!name) {
-                       if (al_name_len)
-                               goto not_found;
-               } else if (!ntfs_are_names_equal(al_name, al_name_len, name,
-                               name_len, ic, vol->upcase, vol->upcase_len)) {
-                       register int rc;
-
-                       rc = ntfs_collate_names(name, name_len, al_name,
-                                       al_name_len, 1, IGNORE_CASE,
-                                       vol->upcase, vol->upcase_len);
-                       /*
-                        * If @name collates before al_name, there is no
-                        * matching attribute.
-                        */
-                       if (rc == -1)
-                               goto not_found;
-                       /* If the strings are not equal, continue search. */
-                       if (rc)
-                               continue;
-                       /*
-                        * FIXME: Reverse engineering showed 0, IGNORE_CASE but
-                        * that is inconsistent with ntfs_attr_find().  The
-                        * subsequent rc checks were also different.  Perhaps I
-                        * made a mistake in one of the two.  Need to recheck
-                        * which is correct or at least see what is going on...
-                        * (AIA)
-                        */
-                       rc = ntfs_collate_names(name, name_len, al_name,
-                                       al_name_len, 1, CASE_SENSITIVE,
-                                       vol->upcase, vol->upcase_len);
-                       if (rc == -1)
-                               goto not_found;
-                       if (rc)
-                               continue;
-               }
-               /*
-                * The names match or @name not present and attribute is
-                * unnamed.  Now check @lowest_vcn.  Continue search if the
-                * next attribute list entry still fits @lowest_vcn.  Otherwise
-                * we have reached the right one or the search has failed.
-                */
-               if (lowest_vcn && (u8*)next_al_entry >= al_start            &&
-                               (u8*)next_al_entry + 6 < al_end             &&
-                               (u8*)next_al_entry + le16_to_cpu(
-                                       next_al_entry->length) <= al_end    &&
-                               sle64_to_cpu(next_al_entry->lowest_vcn) <=
-                                       lowest_vcn                          &&
-                               next_al_entry->type == al_entry->type       &&
-                               next_al_entry->name_length == al_name_len   &&
-                               ntfs_are_names_equal((ntfschar*)((u8*)
-                                       next_al_entry +
-                                       next_al_entry->name_offset),
-                                       next_al_entry->name_length,
-                                       al_name, al_name_len, CASE_SENSITIVE,
-                                       vol->upcase, vol->upcase_len))
-                       continue;
-               if (MREF_LE(al_entry->mft_reference) == ni->mft_no) {
-                       if (MSEQNO_LE(al_entry->mft_reference) != ni->seq_no) {
-                               ntfs_error(vol->sb, "Found stale mft "
-                                               "reference in attribute list "
-                                               "of base inode 0x%lx.%s",
-                                               base_ni->mft_no, es);
-                               err = -EIO;
-                               break;
-                       }
-               } else { /* Mft references do not match. */
-                       /* If there is a mapped record unmap it first. */
-                       if (ni != base_ni)
-                               unmap_extent_mft_record(ni);
-                       /* Do we want the base record back? */
-                       if (MREF_LE(al_entry->mft_reference) ==
-                                       base_ni->mft_no) {
-                               ni = ctx->ntfs_ino = base_ni;
-                               ctx->mrec = ctx->base_mrec;
-                       } else {
-                               /* We want an extent record. */
-                               ctx->mrec = map_extent_mft_record(base_ni,
-                                               le64_to_cpu(
-                                               al_entry->mft_reference), &ni);
-                               if (IS_ERR(ctx->mrec)) {
-                                       ntfs_error(vol->sb, "Failed to map "
-                                                       "extent mft record "
-                                                       "0x%lx of base inode "
-                                                       "0x%lx.%s",
-                                                       MREF_LE(al_entry->
-                                                       mft_reference),
-                                                       base_ni->mft_no, es);
-                                       err = PTR_ERR(ctx->mrec);
-                                       if (err == -ENOENT)
-                                               err = -EIO;
-                                       /* Cause @ctx to be sanitized below. */
-                                       ni = NULL;
-                                       break;
-                               }
-                               ctx->ntfs_ino = ni;
-                       }
-                       ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
-                                       le16_to_cpu(ctx->mrec->attrs_offset));
-               }
-               /*
-                * ctx->vfs_ino, ctx->mrec, and ctx->attr now point to the
-                * mft record containing the attribute represented by the
-                * current al_entry.
-                */
-               /*
-                * We could call into ntfs_attr_find() to find the right
-                * attribute in this mft record but this would be less
-                * efficient and not quite accurate as ntfs_attr_find() ignores
-                * the attribute instance numbers for example which become
-                * important when one plays with attribute lists.  Also,
-                * because a proper match has been found in the attribute list
-                * entry above, the comparison can now be optimized.  So it is
-                * worth re-implementing a simplified ntfs_attr_find() here.
-                */
-               a = ctx->attr;
-               /*
-                * Use a manual loop so we can still use break and continue
-                * with the same meanings as above.
-                */
-do_next_attr_loop:
-               if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec +
-                               le32_to_cpu(ctx->mrec->bytes_allocated))
-                       break;
-               if (a->type == AT_END)
-                       break;
-               if (!a->length)
-                       break;
-               if (al_entry->instance != a->instance)
-                       goto do_next_attr;
-               /*
-                * If the type and/or the name are mismatched between the
-                * attribute list entry and the attribute record, there is
-                * corruption so we break and return error EIO.
-                */
-               if (al_entry->type != a->type)
-                       break;
-               if (!ntfs_are_names_equal((ntfschar*)((u8*)a +
-                               le16_to_cpu(a->name_offset)), a->name_length,
-                               al_name, al_name_len, CASE_SENSITIVE,
-                               vol->upcase, vol->upcase_len))
-                       break;
-               ctx->attr = a;
-               /*
-                * If no @val specified or @val specified and it matches, we
-                * have found it!
-                */
-               if (!val || (!a->non_resident && le32_to_cpu(
-                               a->data.resident.value_length) == val_len &&
-                               !memcmp((u8*)a +
-                               le16_to_cpu(a->data.resident.value_offset),
-                               val, val_len))) {
-                       ntfs_debug("Done, found.");
-                       return 0;
-               }
-do_next_attr:
-               /* Proceed to the next attribute in the current mft record. */
-               a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length));
-               goto do_next_attr_loop;
-       }
-       if (!err) {
-               ntfs_error(vol->sb, "Base inode 0x%lx contains corrupt "
-                               "attribute list attribute.%s", base_ni->mft_no,
-                               es);
-               err = -EIO;
-       }
-       if (ni != base_ni) {
-               if (ni)
-                       unmap_extent_mft_record(ni);
-               ctx->ntfs_ino = base_ni;
-               ctx->mrec = ctx->base_mrec;
-               ctx->attr = ctx->base_attr;
-       }
-       if (err != -ENOMEM)
-               NVolSetErrors(vol);
-       return err;
-not_found:
-       /*
-        * If we were looking for AT_END, we reset the search context @ctx and
-        * use ntfs_attr_find() to seek to the end of the base mft record.
-        */
-       if (type == AT_END) {
-               ntfs_attr_reinit_search_ctx(ctx);
-               return ntfs_attr_find(AT_END, name, name_len, ic, val, val_len,
-                               ctx);
-       }
-       /*
-        * The attribute was not found.  Before we return, we want to ensure
-        * @ctx->mrec and @ctx->attr indicate the position at which the
-        * attribute should be inserted in the base mft record.  Since we also
-        * want to preserve @ctx->al_entry we cannot reinitialize the search
-        * context using ntfs_attr_reinit_search_ctx() as this would set
-        * @ctx->al_entry to NULL.  Thus we do the necessary bits manually (see
-        * ntfs_attr_init_search_ctx() below).  Note, we _only_ preserve
-        * @ctx->al_entry as the remaining fields (base_*) are identical to
-        * their non base_ counterparts and we cannot set @ctx->base_attr
-        * correctly yet as we do not know what @ctx->attr will be set to by
-        * the call to ntfs_attr_find() below.
-        */
-       if (ni != base_ni)
-               unmap_extent_mft_record(ni);
-       ctx->mrec = ctx->base_mrec;
-       ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
-                       le16_to_cpu(ctx->mrec->attrs_offset));
-       ctx->is_first = true;
-       ctx->ntfs_ino = base_ni;
-       ctx->base_ntfs_ino = NULL;
-       ctx->base_mrec = NULL;
-       ctx->base_attr = NULL;
-       /*
-        * In case there are multiple matches in the base mft record, need to
-        * keep enumerating until we get an attribute not found response (or
-        * another error), otherwise we would keep returning the same attribute
-        * over and over again and all programs using us for enumeration would
-        * lock up in a tight loop.
-        */
-       do {
-               err = ntfs_attr_find(type, name, name_len, ic, val, val_len,
-                               ctx);
-       } while (!err);
-       ntfs_debug("Done, not found.");
-       return err;
-}
-
-/**
- * ntfs_attr_lookup - find an attribute in an ntfs inode
- * @type:      attribute type to find
- * @name:      attribute name to find (optional, i.e. NULL means don't care)
- * @name_len:  attribute name length (only needed if @name present)
- * @ic:                IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
- * @lowest_vcn:        lowest vcn to find (optional, non-resident attributes only)
- * @val:       attribute value to find (optional, resident attributes only)
- * @val_len:   attribute value length
- * @ctx:       search context with mft record and attribute to search from
- *
- * Find an attribute in an ntfs inode.  On first search @ctx->ntfs_ino must
- * be the base mft record and @ctx must have been obtained from a call to
- * ntfs_attr_get_search_ctx().
- *
- * This function transparently handles attribute lists and @ctx is used to
- * continue searches where they were left off at.
- *
- * After finishing with the attribute/mft record you need to call
- * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any
- * mapped inodes, etc).
- *
- * Return 0 if the search was successful and -errno if not.
- *
- * When 0, @ctx->attr is the found attribute and it is in mft record
- * @ctx->mrec.  If an attribute list attribute is present, @ctx->al_entry is
- * the attribute list entry of the found attribute.
- *
- * When -ENOENT, @ctx->attr is the attribute which collates just after the
- * attribute being searched for, i.e. if one wants to add the attribute to the
- * mft record this is the correct place to insert it into.  If an attribute
- * list attribute is present, @ctx->al_entry is the attribute list entry which
- * collates just after the attribute list entry of the attribute being searched
- * for, i.e. if one wants to add the attribute to the mft record this is the
- * correct place to insert its attribute list entry into.
- *
- * When -errno != -ENOENT, an error occurred during the lookup.  @ctx->attr is
- * then undefined and in particular you should not rely on it not changing.
- */
-int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name,
-               const u32 name_len, const IGNORE_CASE_BOOL ic,
-               const VCN lowest_vcn, const u8 *val, const u32 val_len,
-               ntfs_attr_search_ctx *ctx)
-{
-       ntfs_inode *base_ni;
-
-       ntfs_debug("Entering.");
-       BUG_ON(IS_ERR(ctx->mrec));
-       if (ctx->base_ntfs_ino)
-               base_ni = ctx->base_ntfs_ino;
-       else
-               base_ni = ctx->ntfs_ino;
-       /* Sanity check, just for debugging really. */
-       BUG_ON(!base_ni);
-       if (!NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST)
-               return ntfs_attr_find(type, name, name_len, ic, val, val_len,
-                               ctx);
-       return ntfs_external_attr_find(type, name, name_len, ic, lowest_vcn,
-                       val, val_len, ctx);
-}
-
-/**
- * ntfs_attr_init_search_ctx - initialize an attribute search context
- * @ctx:       attribute search context to initialize
- * @ni:                ntfs inode with which to initialize the search context
- * @mrec:      mft record with which to initialize the search context
- *
- * Initialize the attribute search context @ctx with @ni and @mrec.
- */
-static inline void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx,
-               ntfs_inode *ni, MFT_RECORD *mrec)
-{
-       *ctx = (ntfs_attr_search_ctx) {
-               .mrec = mrec,
-               /* Sanity checks are performed elsewhere. */
-               .attr = (ATTR_RECORD*)((u8*)mrec +
-                               le16_to_cpu(mrec->attrs_offset)),
-               .is_first = true,
-               .ntfs_ino = ni,
-       };
-}
-
-/**
- * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context
- * @ctx:       attribute search context to reinitialize
- *
- * Reinitialize the attribute search context @ctx, unmapping an associated
- * extent mft record if present, and initialize the search context again.
- *
- * This is used when a search for a new attribute is being started to reset
- * the search context to the beginning.
- */
-void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx)
-{
-       if (likely(!ctx->base_ntfs_ino)) {
-               /* No attribute list. */
-               ctx->is_first = true;
-               /* Sanity checks are performed elsewhere. */
-               ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
-                               le16_to_cpu(ctx->mrec->attrs_offset));
-               /*
-                * This needs resetting due to ntfs_external_attr_find() which
-                * can leave it set despite having zeroed ctx->base_ntfs_ino.
-                */
-               ctx->al_entry = NULL;
-               return;
-       } /* Attribute list. */
-       if (ctx->ntfs_ino != ctx->base_ntfs_ino)
-               unmap_extent_mft_record(ctx->ntfs_ino);
-       ntfs_attr_init_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec);
-       return;
-}
-
-/**
- * ntfs_attr_get_search_ctx - allocate/initialize a new attribute search context
- * @ni:                ntfs inode with which to initialize the search context
- * @mrec:      mft record with which to initialize the search context
- *
- * Allocate a new attribute search context, initialize it with @ni and @mrec,
- * and return it. Return NULL if allocation failed.
- */
-ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec)
-{
-       ntfs_attr_search_ctx *ctx;
-
-       ctx = kmem_cache_alloc(ntfs_attr_ctx_cache, GFP_NOFS);
-       if (ctx)
-               ntfs_attr_init_search_ctx(ctx, ni, mrec);
-       return ctx;
-}
-
-/**
- * ntfs_attr_put_search_ctx - release an attribute search context
- * @ctx:       attribute search context to free
- *
- * Release the attribute search context @ctx, unmapping an associated extent
- * mft record if present.
- */
-void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx)
-{
-       if (ctx->base_ntfs_ino && ctx->ntfs_ino != ctx->base_ntfs_ino)
-               unmap_extent_mft_record(ctx->ntfs_ino);
-       kmem_cache_free(ntfs_attr_ctx_cache, ctx);
-       return;
-}
-
-#ifdef NTFS_RW
-
-/**
- * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file
- * @vol:       ntfs volume to which the attribute belongs
- * @type:      attribute type which to find
- *
- * Search for the attribute definition record corresponding to the attribute
- * @type in the $AttrDef system file.
- *
- * Return the attribute type definition record if found and NULL if not found.
- */
-static ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
-               const ATTR_TYPE type)
-{
-       ATTR_DEF *ad;
-
-       BUG_ON(!vol->attrdef);
-       BUG_ON(!type);
-       for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef <
-                       vol->attrdef_size && ad->type; ++ad) {
-               /* We have not found it yet, carry on searching. */
-               if (likely(le32_to_cpu(ad->type) < le32_to_cpu(type)))
-                       continue;
-               /* We found the attribute; return it. */
-               if (likely(ad->type == type))
-                       return ad;
-               /* We have gone too far already.  No point in continuing. */
-               break;
-       }
-       /* Attribute not found. */
-       ntfs_debug("Attribute type 0x%x not found in $AttrDef.",
-                       le32_to_cpu(type));
-       return NULL;
-}
-
-/**
- * ntfs_attr_size_bounds_check - check a size of an attribute type for validity
- * @vol:       ntfs volume to which the attribute belongs
- * @type:      attribute type which to check
- * @size:      size which to check
- *
- * Check whether the @size in bytes is valid for an attribute of @type on the
- * ntfs volume @vol.  This information is obtained from $AttrDef system file.
- *
- * Return 0 if valid, -ERANGE if not valid, or -ENOENT if the attribute is not
- * listed in $AttrDef.
- */
-int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPE type,
-               const s64 size)
-{
-       ATTR_DEF *ad;
-
-       BUG_ON(size < 0);
-       /*
-        * $ATTRIBUTE_LIST has a maximum size of 256kiB, but this is not
-        * listed in $AttrDef.
-        */
-       if (unlikely(type == AT_ATTRIBUTE_LIST && size > 256 * 1024))
-               return -ERANGE;
-       /* Get the $AttrDef entry for the attribute @type. */
-       ad = ntfs_attr_find_in_attrdef(vol, type);
-       if (unlikely(!ad))
-               return -ENOENT;
-       /* Do the bounds check. */
-       if (((sle64_to_cpu(ad->min_size) > 0) &&
-                       size < sle64_to_cpu(ad->min_size)) ||
-                       ((sle64_to_cpu(ad->max_size) > 0) && size >
-                       sle64_to_cpu(ad->max_size)))
-               return -ERANGE;
-       return 0;
-}
-
-/**
- * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident
- * @vol:       ntfs volume to which the attribute belongs
- * @type:      attribute type which to check
- *
- * Check whether the attribute of @type on the ntfs volume @vol is allowed to
- * be non-resident.  This information is obtained from $AttrDef system file.
- *
- * Return 0 if the attribute is allowed to be non-resident, -EPERM if not, and
- * -ENOENT if the attribute is not listed in $AttrDef.
- */
-int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPE type)
-{
-       ATTR_DEF *ad;
-
-       /* Find the attribute definition record in $AttrDef. */
-       ad = ntfs_attr_find_in_attrdef(vol, type);
-       if (unlikely(!ad))
-               return -ENOENT;
-       /* Check the flags and return the result. */
-       if (ad->flags & ATTR_DEF_RESIDENT)
-               return -EPERM;
-       return 0;
-}
-
-/**
- * ntfs_attr_can_be_resident - check if an attribute can be resident
- * @vol:       ntfs volume to which the attribute belongs
- * @type:      attribute type which to check
- *
- * Check whether the attribute of @type on the ntfs volume @vol is allowed to
- * be resident.  This information is derived from our ntfs knowledge and may
- * not be completely accurate, especially when user defined attributes are
- * present.  Basically we allow everything to be resident except for index
- * allocation and $EA attributes.
- *
- * Return 0 if the attribute is allowed to be non-resident and -EPERM if not.
- *
- * Warning: In the system file $MFT the attribute $Bitmap must be non-resident
- *         otherwise windows will not boot (blue screen of death)!  We cannot
- *         check for this here as we do not know which inode's $Bitmap is
- *         being asked about so the caller needs to special case this.
- */
-int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPE type)
-{
-       if (type == AT_INDEX_ALLOCATION)
-               return -EPERM;
-       return 0;
-}
-
-/**
- * ntfs_attr_record_resize - resize an attribute record
- * @m:         mft record containing attribute record
- * @a:         attribute record to resize
- * @new_size:  new size in bytes to which to resize the attribute record @a
- *
- * Resize the attribute record @a, i.e. the resident part of the attribute, in
- * the mft record @m to @new_size bytes.
- *
- * Return 0 on success and -errno on error.  The following error codes are
- * defined:
- *     -ENOSPC - Not enough space in the mft record @m to perform the resize.
- *
- * Note: On error, no modifications have been performed whatsoever.
- *
- * Warning: If you make a record smaller without having copied all the data you
- *         are interested in the data may be overwritten.
- */
-int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size)
-{
-       ntfs_debug("Entering for new_size %u.", new_size);
-       /* Align to 8 bytes if it is not already done. */
-       if (new_size & 7)
-               new_size = (new_size + 7) & ~7;
-       /* If the actual attribute length has changed, move things around. */
-       if (new_size != le32_to_cpu(a->length)) {
-               u32 new_muse = le32_to_cpu(m->bytes_in_use) -
-                               le32_to_cpu(a->length) + new_size;
-               /* Not enough space in this mft record. */
-               if (new_muse > le32_to_cpu(m->bytes_allocated))
-                       return -ENOSPC;
-               /* Move attributes following @a to their new location. */
-               memmove((u8*)a + new_size, (u8*)a + le32_to_cpu(a->length),
-                               le32_to_cpu(m->bytes_in_use) - ((u8*)a -
-                               (u8*)m) - le32_to_cpu(a->length));
-               /* Adjust @m to reflect the change in used space. */
-               m->bytes_in_use = cpu_to_le32(new_muse);
-               /* Adjust @a to reflect the new size. */
-               if (new_size >= offsetof(ATTR_REC, length) + sizeof(a->length))
-                       a->length = cpu_to_le32(new_size);
-       }
-       return 0;
-}
-
-/**
- * ntfs_resident_attr_value_resize - resize the value of a resident attribute
- * @m:         mft record containing attribute record
- * @a:         attribute record whose value to resize
- * @new_size:  new size in bytes to which to resize the attribute value of @a
- *
- * Resize the value of the attribute @a in the mft record @m to @new_size bytes.
- * If the value is made bigger, the newly allocated space is cleared.
- *
- * Return 0 on success and -errno on error.  The following error codes are
- * defined:
- *     -ENOSPC - Not enough space in the mft record @m to perform the resize.
- *
- * Note: On error, no modifications have been performed whatsoever.
- *
- * Warning: If you make a record smaller without having copied all the data you
- *         are interested in the data may be overwritten.
- */
-int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
-               const u32 new_size)
-{
-       u32 old_size;
-
-       /* Resize the resident part of the attribute record. */
-       if (ntfs_attr_record_resize(m, a,
-                       le16_to_cpu(a->data.resident.value_offset) + new_size))
-               return -ENOSPC;
-       /*
-        * The resize succeeded!  If we made the attribute value bigger, clear
-        * the area between the old size and @new_size.
-        */
-       old_size = le32_to_cpu(a->data.resident.value_length);
-       if (new_size > old_size)
-               memset((u8*)a + le16_to_cpu(a->data.resident.value_offset) +
-                               old_size, 0, new_size - old_size);
-       /* Finally update the length of the attribute value. */
-       a->data.resident.value_length = cpu_to_le32(new_size);
-       return 0;
-}
-
-/**
- * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute
- * @ni:                ntfs inode describing the attribute to convert
- * @data_size: size of the resident data to copy to the non-resident attribute
- *
- * Convert the resident ntfs attribute described by the ntfs inode @ni to a
- * non-resident one.
- *
- * @data_size must be equal to the attribute value size.  This is needed since
- * we need to know the size before we can map the mft record and our callers
- * always know it.  The reason we cannot simply read the size from the vfs
- * inode i_size is that this is not necessarily uptodate.  This happens when
- * ntfs_attr_make_non_resident() is called in the ->truncate call path(s).
- *
- * Return 0 on success and -errno on error.  The following error return codes
- * are defined:
- *     -EPERM  - The attribute is not allowed to be non-resident.
- *     -ENOMEM - Not enough memory.
- *     -ENOSPC - Not enough disk space.
- *     -EINVAL - Attribute not defined on the volume.
- *     -EIO    - I/o error or other error.
- * Note that -ENOSPC is also returned in the case that there is not enough
- * space in the mft record to do the conversion.  This can happen when the mft
- * record is already very full.  The caller is responsible for trying to make
- * space in the mft record and trying again.  FIXME: Do we need a separate
- * error return code for this kind of -ENOSPC or is it always worth trying
- * again in case the attribute may then fit in a resident state so no need to
- * make it non-resident at all?  Ho-hum...  (AIA)
- *
- * NOTE to self: No changes in the attribute list are required to move from
- *              a resident to a non-resident attribute.
- *
- * Locking: - The caller must hold i_mutex on the inode.
- */
-int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size)
-{
-       s64 new_size;
-       struct inode *vi = VFS_I(ni);
-       ntfs_volume *vol = ni->vol;
-       ntfs_inode *base_ni;
-       MFT_RECORD *m;
-       ATTR_RECORD *a;
-       ntfs_attr_search_ctx *ctx;
-       struct page *page;
-       runlist_element *rl;
-       u8 *kaddr;
-       unsigned long flags;
-       int mp_size, mp_ofs, name_ofs, arec_size, err, err2;
-       u32 attr_size;
-       u8 old_res_attr_flags;
-
-       /* Check that the attribute is allowed to be non-resident. */
-       err = ntfs_attr_can_be_non_resident(vol, ni->type);
-       if (unlikely(err)) {
-               if (err == -EPERM)
-                       ntfs_debug("Attribute is not allowed to be "
-                                       "non-resident.");
-               else
-                       ntfs_debug("Attribute not defined on the NTFS "
-                                       "volume!");
-               return err;
-       }
-       /*
-        * FIXME: Compressed and encrypted attributes are not supported when
-        * writing and we should never have gotten here for them.
-        */
-       BUG_ON(NInoCompressed(ni));
-       BUG_ON(NInoEncrypted(ni));
-       /*
-        * The size needs to be aligned to a cluster boundary for allocation
-        * purposes.
-        */
-       new_size = (data_size + vol->cluster_size - 1) &
-                       ~(vol->cluster_size - 1);
-       if (new_size > 0) {
-               /*
-                * Will need the page later and since the page lock nests
-                * outside all ntfs locks, we need to get the page now.
-                */
-               page = find_or_create_page(vi->i_mapping, 0,
-                               mapping_gfp_mask(vi->i_mapping));
-               if (unlikely(!page))
-                       return -ENOMEM;
-               /* Start by allocating clusters to hold the attribute value. */
-               rl = ntfs_cluster_alloc(vol, 0, new_size >>
-                               vol->cluster_size_bits, -1, DATA_ZONE, true);
-               if (IS_ERR(rl)) {
-                       err = PTR_ERR(rl);
-                       ntfs_debug("Failed to allocate cluster%s, error code "
-                                       "%i.", (new_size >>
-                                       vol->cluster_size_bits) > 1 ? "s" : "",
-                                       err);
-                       goto page_err_out;
-               }
-       } else {
-               rl = NULL;
-               page = NULL;
-       }
-       /* Determine the size of the mapping pairs array. */
-       mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, -1);
-       if (unlikely(mp_size < 0)) {
-               err = mp_size;
-               ntfs_debug("Failed to get size for mapping pairs array, error "
-                               "code %i.", err);
-               goto rl_err_out;
-       }
-       down_write(&ni->runlist.lock);
-       if (!NInoAttr(ni))
-               base_ni = ni;
-       else
-               base_ni = ni->ext.base_ntfs_ino;
-       m = map_mft_record(base_ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               m = NULL;
-               ctx = NULL;
-               goto err_out;
-       }
-       ctx = ntfs_attr_get_search_ctx(base_ni, m);
-       if (unlikely(!ctx)) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err)) {
-               if (err == -ENOENT)
-                       err = -EIO;
-               goto err_out;
-       }
-       m = ctx->mrec;
-       a = ctx->attr;
-       BUG_ON(NInoNonResident(ni));
-       BUG_ON(a->non_resident);
-       /*
-        * Calculate new offsets for the name and the mapping pairs array.
-        */
-       if (NInoSparse(ni) || NInoCompressed(ni))
-               name_ofs = (offsetof(ATTR_REC,
-                               data.non_resident.compressed_size) +
-                               sizeof(a->data.non_resident.compressed_size) +
-                               7) & ~7;
-       else
-               name_ofs = (offsetof(ATTR_REC,
-                               data.non_resident.compressed_size) + 7) & ~7;
-       mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7;
-       /*
-        * Determine the size of the resident part of the now non-resident
-        * attribute record.
-        */
-       arec_size = (mp_ofs + mp_size + 7) & ~7;
-       /*
-        * If the page is not uptodate bring it uptodate by copying from the
-        * attribute value.
-        */
-       attr_size = le32_to_cpu(a->data.resident.value_length);
-       BUG_ON(attr_size != data_size);
-       if (page && !PageUptodate(page)) {
-               kaddr = kmap_atomic(page);
-               memcpy(kaddr, (u8*)a +
-                               le16_to_cpu(a->data.resident.value_offset),
-                               attr_size);
-               memset(kaddr + attr_size, 0, PAGE_SIZE - attr_size);
-               kunmap_atomic(kaddr);
-               flush_dcache_page(page);
-               SetPageUptodate(page);
-       }
-       /* Backup the attribute flag. */
-       old_res_attr_flags = a->data.resident.flags;
-       /* Resize the resident part of the attribute record. */
-       err = ntfs_attr_record_resize(m, a, arec_size);
-       if (unlikely(err))
-               goto err_out;
-       /*
-        * Convert the resident part of the attribute record to describe a
-        * non-resident attribute.
-        */
-       a->non_resident = 1;
-       /* Move the attribute name if it exists and update the offset. */
-       if (a->name_length)
-               memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset),
-                               a->name_length * sizeof(ntfschar));
-       a->name_offset = cpu_to_le16(name_ofs);
-       /* Setup the fields specific to non-resident attributes. */
-       a->data.non_resident.lowest_vcn = 0;
-       a->data.non_resident.highest_vcn = cpu_to_sle64((new_size - 1) >>
-                       vol->cluster_size_bits);
-       a->data.non_resident.mapping_pairs_offset = cpu_to_le16(mp_ofs);
-       memset(&a->data.non_resident.reserved, 0,
-                       sizeof(a->data.non_resident.reserved));
-       a->data.non_resident.allocated_size = cpu_to_sle64(new_size);
-       a->data.non_resident.data_size =
-                       a->data.non_resident.initialized_size =
-                       cpu_to_sle64(attr_size);
-       if (NInoSparse(ni) || NInoCompressed(ni)) {
-               a->data.non_resident.compression_unit = 0;
-               if (NInoCompressed(ni) || vol->major_ver < 3)
-                       a->data.non_resident.compression_unit = 4;
-               a->data.non_resident.compressed_size =
-                               a->data.non_resident.allocated_size;
-       } else
-               a->data.non_resident.compression_unit = 0;
-       /* Generate the mapping pairs array into the attribute record. */
-       err = ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs,
-                       arec_size - mp_ofs, rl, 0, -1, NULL);
-       if (unlikely(err)) {
-               ntfs_debug("Failed to build mapping pairs, error code %i.",
-                               err);
-               goto undo_err_out;
-       }
-       /* Setup the in-memory attribute structure to be non-resident. */
-       ni->runlist.rl = rl;
-       write_lock_irqsave(&ni->size_lock, flags);
-       ni->allocated_size = new_size;
-       if (NInoSparse(ni) || NInoCompressed(ni)) {
-               ni->itype.compressed.size = ni->allocated_size;
-               if (a->data.non_resident.compression_unit) {
-                       ni->itype.compressed.block_size = 1U << (a->data.
-                                       non_resident.compression_unit +
-                                       vol->cluster_size_bits);
-                       ni->itype.compressed.block_size_bits =
-                                       ffs(ni->itype.compressed.block_size) -
-                                       1;
-                       ni->itype.compressed.block_clusters = 1U <<
-                                       a->data.non_resident.compression_unit;
-               } else {
-                       ni->itype.compressed.block_size = 0;
-                       ni->itype.compressed.block_size_bits = 0;
-                       ni->itype.compressed.block_clusters = 0;
-               }
-               vi->i_blocks = ni->itype.compressed.size >> 9;
-       } else
-               vi->i_blocks = ni->allocated_size >> 9;
-       write_unlock_irqrestore(&ni->size_lock, flags);
-       /*
-        * This needs to be last since the address space operations ->read_folio
-        * and ->writepage can run concurrently with us as they are not
-        * serialized on i_mutex.  Note, we are not allowed to fail once we flip
-        * this switch, which is another reason to do this last.
-        */
-       NInoSetNonResident(ni);
-       /* Mark the mft record dirty, so it gets written back. */
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(base_ni);
-       up_write(&ni->runlist.lock);
-       if (page) {
-               set_page_dirty(page);
-               unlock_page(page);
-               put_page(page);
-       }
-       ntfs_debug("Done.");
-       return 0;
-undo_err_out:
-       /* Convert the attribute back into a resident attribute. */
-       a->non_resident = 0;
-       /* Move the attribute name if it exists and update the offset. */
-       name_ofs = (offsetof(ATTR_RECORD, data.resident.reserved) +
-                       sizeof(a->data.resident.reserved) + 7) & ~7;
-       if (a->name_length)
-               memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset),
-                               a->name_length * sizeof(ntfschar));
-       mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7;
-       a->name_offset = cpu_to_le16(name_ofs);
-       arec_size = (mp_ofs + attr_size + 7) & ~7;
-       /* Resize the resident part of the attribute record. */
-       err2 = ntfs_attr_record_resize(m, a, arec_size);
-       if (unlikely(err2)) {
-               /*
-                * This cannot happen (well if memory corruption is at work it
-                * could happen in theory), but deal with it as well as we can.
-                * If the old size is too small, truncate the attribute,
-                * otherwise simply give it a larger allocated size.
-                * FIXME: Should check whether chkdsk complains when the
-                * allocated size is much bigger than the resident value size.
-                */
-               arec_size = le32_to_cpu(a->length);
-               if ((mp_ofs + attr_size) > arec_size) {
-                       err2 = attr_size;
-                       attr_size = arec_size - mp_ofs;
-                       ntfs_error(vol->sb, "Failed to undo partial resident "
-                                       "to non-resident attribute "
-                                       "conversion.  Truncating inode 0x%lx, "
-                                       "attribute type 0x%x from %i bytes to "
-                                       "%i bytes to maintain metadata "
-                                       "consistency.  THIS MEANS YOU ARE "
-                                       "LOSING %i BYTES DATA FROM THIS %s.",
-                                       vi->i_ino,
-                                       (unsigned)le32_to_cpu(ni->type),
-                                       err2, attr_size, err2 - attr_size,
-                                       ((ni->type == AT_DATA) &&
-                                       !ni->name_len) ? "FILE": "ATTRIBUTE");
-                       write_lock_irqsave(&ni->size_lock, flags);
-                       ni->initialized_size = attr_size;
-                       i_size_write(vi, attr_size);
-                       write_unlock_irqrestore(&ni->size_lock, flags);
-               }
-       }
-       /* Setup the fields specific to resident attributes. */
-       a->data.resident.value_length = cpu_to_le32(attr_size);
-       a->data.resident.value_offset = cpu_to_le16(mp_ofs);
-       a->data.resident.flags = old_res_attr_flags;
-       memset(&a->data.resident.reserved, 0,
-                       sizeof(a->data.resident.reserved));
-       /* Copy the data from the page back to the attribute value. */
-       if (page) {
-               kaddr = kmap_atomic(page);
-               memcpy((u8*)a + mp_ofs, kaddr, attr_size);
-               kunmap_atomic(kaddr);
-       }
-       /* Setup the allocated size in the ntfs inode in case it changed. */
-       write_lock_irqsave(&ni->size_lock, flags);
-       ni->allocated_size = arec_size - mp_ofs;
-       write_unlock_irqrestore(&ni->size_lock, flags);
-       /* Mark the mft record dirty, so it gets written back. */
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-err_out:
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(base_ni);
-       ni->runlist.rl = NULL;
-       up_write(&ni->runlist.lock);
-rl_err_out:
-       if (rl) {
-               if (ntfs_cluster_free_from_rl(vol, rl) < 0) {
-                       ntfs_error(vol->sb, "Failed to release allocated "
-                                       "cluster(s) in error code path.  Run "
-                                       "chkdsk to recover the lost "
-                                       "cluster(s).");
-                       NVolSetErrors(vol);
-               }
-               ntfs_free(rl);
-page_err_out:
-               unlock_page(page);
-               put_page(page);
-       }
-       if (err == -EINVAL)
-               err = -EIO;
-       return err;
-}
-
-/**
- * ntfs_attr_extend_allocation - extend the allocated space of an attribute
- * @ni:                        ntfs inode of the attribute whose allocation to extend
- * @new_alloc_size:    new size in bytes to which to extend the allocation to
- * @new_data_size:     new size in bytes to which to extend the data to
- * @data_start:                beginning of region which is required to be non-sparse
- *
- * Extend the allocated space of an attribute described by the ntfs inode @ni
- * to @new_alloc_size bytes.  If @data_start is -1, the whole extension may be
- * implemented as a hole in the file (as long as both the volume and the ntfs
- * inode @ni have sparse support enabled).  If @data_start is >= 0, then the
- * region between the old allocated size and @data_start - 1 may be made sparse
- * but the regions between @data_start and @new_alloc_size must be backed by
- * actual clusters.
- *
- * If @new_data_size is -1, it is ignored.  If it is >= 0, then the data size
- * of the attribute is extended to @new_data_size.  Note that the i_size of the
- * vfs inode is not updated.  Only the data size in the base attribute record
- * is updated.  The caller has to update i_size separately if this is required.
- * WARNING: It is a BUG() for @new_data_size to be smaller than the old data
- * size as well as for @new_data_size to be greater than @new_alloc_size.
- *
- * For resident attributes this involves resizing the attribute record and if
- * necessary moving it and/or other attributes into extent mft records and/or
- * converting the attribute to a non-resident attribute which in turn involves
- * extending the allocation of a non-resident attribute as described below.
- *
- * For non-resident attributes this involves allocating clusters in the data
- * zone on the volume (except for regions that are being made sparse) and
- * extending the run list to describe the allocated clusters as well as
- * updating the mapping pairs array of the attribute.  This in turn involves
- * resizing the attribute record and if necessary moving it and/or other
- * attributes into extent mft records and/or splitting the attribute record
- * into multiple extent attribute records.
- *
- * Also, the attribute list attribute is updated if present and in some of the
- * above cases (the ones where extent mft records/attributes come into play),
- * an attribute list attribute is created if not already present.
- *
- * Return the new allocated size on success and -errno on error.  In the case
- * that an error is encountered but a partial extension at least up to
- * @data_start (if present) is possible, the allocation is partially extended
- * and this is returned.  This means the caller must check the returned size to
- * determine if the extension was partial.  If @data_start is -1 then partial
- * allocations are not performed.
- *
- * WARNING: Do not call ntfs_attr_extend_allocation() for $MFT/$DATA.
- *
- * Locking: This function takes the runlist lock of @ni for writing as well as
- * locking the mft record of the base ntfs inode.  These locks are maintained
- * throughout execution of the function.  These locks are required so that the
- * attribute can be resized safely and so that it can for example be converted
- * from resident to non-resident safely.
- *
- * TODO: At present attribute list attribute handling is not implemented.
- *
- * TODO: At present it is not safe to call this function for anything other
- * than the $DATA attribute(s) of an uncompressed and unencrypted file.
- */
-s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size,
-               const s64 new_data_size, const s64 data_start)
-{
-       VCN vcn;
-       s64 ll, allocated_size, start = data_start;
-       struct inode *vi = VFS_I(ni);
-       ntfs_volume *vol = ni->vol;
-       ntfs_inode *base_ni;
-       MFT_RECORD *m;
-       ATTR_RECORD *a;
-       ntfs_attr_search_ctx *ctx;
-       runlist_element *rl, *rl2;
-       unsigned long flags;
-       int err, mp_size;
-       u32 attr_len = 0; /* Silence stupid gcc warning. */
-       bool mp_rebuilt;
-
-#ifdef DEBUG
-       read_lock_irqsave(&ni->size_lock, flags);
-       allocated_size = ni->allocated_size;
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, "
-                       "old_allocated_size 0x%llx, "
-                       "new_allocated_size 0x%llx, new_data_size 0x%llx, "
-                       "data_start 0x%llx.", vi->i_ino,
-                       (unsigned)le32_to_cpu(ni->type),
-                       (unsigned long long)allocated_size,
-                       (unsigned long long)new_alloc_size,
-                       (unsigned long long)new_data_size,
-                       (unsigned long long)start);
-#endif
-retry_extend:
-       /*
-        * For non-resident attributes, @start and @new_size need to be aligned
-        * to cluster boundaries for allocation purposes.
-        */
-       if (NInoNonResident(ni)) {
-               if (start > 0)
-                       start &= ~(s64)vol->cluster_size_mask;
-               new_alloc_size = (new_alloc_size + vol->cluster_size - 1) &
-                               ~(s64)vol->cluster_size_mask;
-       }
-       BUG_ON(new_data_size >= 0 && new_data_size > new_alloc_size);
-       /* Check if new size is allowed in $AttrDef. */
-       err = ntfs_attr_size_bounds_check(vol, ni->type, new_alloc_size);
-       if (unlikely(err)) {
-               /* Only emit errors when the write will fail completely. */
-               read_lock_irqsave(&ni->size_lock, flags);
-               allocated_size = ni->allocated_size;
-               read_unlock_irqrestore(&ni->size_lock, flags);
-               if (start < 0 || start >= allocated_size) {
-                       if (err == -ERANGE) {
-                               ntfs_error(vol->sb, "Cannot extend allocation "
-                                               "of inode 0x%lx, attribute "
-                                               "type 0x%x, because the new "
-                                               "allocation would exceed the "
-                                               "maximum allowed size for "
-                                               "this attribute type.",
-                                               vi->i_ino, (unsigned)
-                                               le32_to_cpu(ni->type));
-                       } else {
-                               ntfs_error(vol->sb, "Cannot extend allocation "
-                                               "of inode 0x%lx, attribute "
-                                               "type 0x%x, because this "
-                                               "attribute type is not "
-                                               "defined on the NTFS volume.  "
-                                               "Possible corruption!  You "
-                                               "should run chkdsk!",
-                                               vi->i_ino, (unsigned)
-                                               le32_to_cpu(ni->type));
-                       }
-               }
-               /* Translate error code to be POSIX conformant for write(2). */
-               if (err == -ERANGE)
-                       err = -EFBIG;
-               else
-                       err = -EIO;
-               return err;
-       }
-       if (!NInoAttr(ni))
-               base_ni = ni;
-       else
-               base_ni = ni->ext.base_ntfs_ino;
-       /*
-        * We will be modifying both the runlist (if non-resident) and the mft
-        * record so lock them both down.
-        */
-       down_write(&ni->runlist.lock);
-       m = map_mft_record(base_ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               m = NULL;
-               ctx = NULL;
-               goto err_out;
-       }
-       ctx = ntfs_attr_get_search_ctx(base_ni, m);
-       if (unlikely(!ctx)) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       read_lock_irqsave(&ni->size_lock, flags);
-       allocated_size = ni->allocated_size;
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       /*
-        * If non-resident, seek to the last extent.  If resident, there is
-        * only one extent, so seek to that.
-        */
-       vcn = NInoNonResident(ni) ? allocated_size >> vol->cluster_size_bits :
-                       0;
-       /*
-        * Abort if someone did the work whilst we waited for the locks.  If we
-        * just converted the attribute from resident to non-resident it is
-        * likely that exactly this has happened already.  We cannot quite
-        * abort if we need to update the data size.
-        */
-       if (unlikely(new_alloc_size <= allocated_size)) {
-               ntfs_debug("Allocated size already exceeds requested size.");
-               new_alloc_size = allocated_size;
-               if (new_data_size < 0)
-                       goto done;
-               /*
-                * We want the first attribute extent so that we can update the
-                * data size.
-                */
-               vcn = 0;
-       }
-       err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                       CASE_SENSITIVE, vcn, NULL, 0, ctx);
-       if (unlikely(err)) {
-               if (err == -ENOENT)
-                       err = -EIO;
-               goto err_out;
-       }
-       m = ctx->mrec;
-       a = ctx->attr;
-       /* Use goto to reduce indentation. */
-       if (a->non_resident)
-               goto do_non_resident_extend;
-       BUG_ON(NInoNonResident(ni));
-       /* The total length of the attribute value. */
-       attr_len = le32_to_cpu(a->data.resident.value_length);
-       /*
-        * Extend the attribute record to be able to store the new attribute
-        * size.  ntfs_attr_record_resize() will not do anything if the size is
-        * not changing.
-        */
-       if (new_alloc_size < vol->mft_record_size &&
-                       !ntfs_attr_record_resize(m, a,
-                       le16_to_cpu(a->data.resident.value_offset) +
-                       new_alloc_size)) {
-               /* The resize succeeded! */
-               write_lock_irqsave(&ni->size_lock, flags);
-               ni->allocated_size = le32_to_cpu(a->length) -
-                               le16_to_cpu(a->data.resident.value_offset);
-               write_unlock_irqrestore(&ni->size_lock, flags);
-               if (new_data_size >= 0) {
-                       BUG_ON(new_data_size < attr_len);
-                       a->data.resident.value_length =
-                                       cpu_to_le32((u32)new_data_size);
-               }
-               goto flush_done;
-       }
-       /*
-        * We have to drop all the locks so we can call
-        * ntfs_attr_make_non_resident().  This could be optimised by try-
-        * locking the first page cache page and only if that fails dropping
-        * the locks, locking the page, and redoing all the locking and
-        * lookups.  While this would be a huge optimisation, it is not worth
-        * it as this is definitely a slow code path.
-        */
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(base_ni);
-       up_write(&ni->runlist.lock);
-       /*
-        * Not enough space in the mft record, try to make the attribute
-        * non-resident and if successful restart the extension process.
-        */
-       err = ntfs_attr_make_non_resident(ni, attr_len);
-       if (likely(!err))
-               goto retry_extend;
-       /*
-        * Could not make non-resident.  If this is due to this not being
-        * permitted for this attribute type or there not being enough space,
-        * try to make other attributes non-resident.  Otherwise fail.
-        */
-       if (unlikely(err != -EPERM && err != -ENOSPC)) {
-               /* Only emit errors when the write will fail completely. */
-               read_lock_irqsave(&ni->size_lock, flags);
-               allocated_size = ni->allocated_size;
-               read_unlock_irqrestore(&ni->size_lock, flags);
-               if (start < 0 || start >= allocated_size)
-                       ntfs_error(vol->sb, "Cannot extend allocation of "
-                                       "inode 0x%lx, attribute type 0x%x, "
-                                       "because the conversion from resident "
-                                       "to non-resident attribute failed "
-                                       "with error code %i.", vi->i_ino,
-                                       (unsigned)le32_to_cpu(ni->type), err);
-               if (err != -ENOMEM)
-                       err = -EIO;
-               goto conv_err_out;
-       }
-       /* TODO: Not implemented from here, abort. */
-       read_lock_irqsave(&ni->size_lock, flags);
-       allocated_size = ni->allocated_size;
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       if (start < 0 || start >= allocated_size) {
-               if (err == -ENOSPC)
-                       ntfs_error(vol->sb, "Not enough space in the mft "
-                                       "record/on disk for the non-resident "
-                                       "attribute value.  This case is not "
-                                       "implemented yet.");
-               else /* if (err == -EPERM) */
-                       ntfs_error(vol->sb, "This attribute type may not be "
-                                       "non-resident.  This case is not "
-                                       "implemented yet.");
-       }
-       err = -EOPNOTSUPP;
-       goto conv_err_out;
-#if 0
-       // TODO: Attempt to make other attributes non-resident.
-       if (!err)
-               goto do_resident_extend;
-       /*
-        * Both the attribute list attribute and the standard information
-        * attribute must remain in the base inode.  Thus, if this is one of
-        * these attributes, we have to try to move other attributes out into
-        * extent mft records instead.
-        */
-       if (ni->type == AT_ATTRIBUTE_LIST ||
-                       ni->type == AT_STANDARD_INFORMATION) {
-               // TODO: Attempt to move other attributes into extent mft
-               // records.
-               err = -EOPNOTSUPP;
-               if (!err)
-                       goto do_resident_extend;
-               goto err_out;
-       }
-       // TODO: Attempt to move this attribute to an extent mft record, but
-       // only if it is not already the only attribute in an mft record in
-       // which case there would be nothing to gain.
-       err = -EOPNOTSUPP;
-       if (!err)
-               goto do_resident_extend;
-       /* There is nothing we can do to make enough space. )-: */
-       goto err_out;
-#endif
-do_non_resident_extend:
-       BUG_ON(!NInoNonResident(ni));
-       if (new_alloc_size == allocated_size) {
-               BUG_ON(vcn);
-               goto alloc_done;
-       }
-       /*
-        * If the data starts after the end of the old allocation, this is a
-        * $DATA attribute and sparse attributes are enabled on the volume and
-        * for this inode, then create a sparse region between the old
-        * allocated size and the start of the data.  Otherwise simply proceed
-        * with filling the whole space between the old allocated size and the
-        * new allocated size with clusters.
-        */
-       if ((start >= 0 && start <= allocated_size) || ni->type != AT_DATA ||
-                       !NVolSparseEnabled(vol) || NInoSparseDisabled(ni))
-               goto skip_sparse;
-       // TODO: This is not implemented yet.  We just fill in with real
-       // clusters for now...
-       ntfs_debug("Inserting holes is not-implemented yet.  Falling back to "
-                       "allocating real clusters instead.");
-skip_sparse:
-       rl = ni->runlist.rl;
-       if (likely(rl)) {
-               /* Seek to the end of the runlist. */
-               while (rl->length)
-                       rl++;
-       }
-       /* If this attribute extent is not mapped, map it now. */
-       if (unlikely(!rl || rl->lcn == LCN_RL_NOT_MAPPED ||
-                       (rl->lcn == LCN_ENOENT && rl > ni->runlist.rl &&
-                       (rl-1)->lcn == LCN_RL_NOT_MAPPED))) {
-               if (!rl && !allocated_size)
-                       goto first_alloc;
-               rl = ntfs_mapping_pairs_decompress(vol, a, ni->runlist.rl);
-               if (IS_ERR(rl)) {
-                       err = PTR_ERR(rl);
-                       if (start < 0 || start >= allocated_size)
-                               ntfs_error(vol->sb, "Cannot extend allocation "
-                                               "of inode 0x%lx, attribute "
-                                               "type 0x%x, because the "
-                                               "mapping of a runlist "
-                                               "fragment failed with error "
-                                               "code %i.", vi->i_ino,
-                                               (unsigned)le32_to_cpu(ni->type),
-                                               err);
-                       if (err != -ENOMEM)
-                               err = -EIO;
-                       goto err_out;
-               }
-               ni->runlist.rl = rl;
-               /* Seek to the end of the runlist. */
-               while (rl->length)
-                       rl++;
-       }
-       /*
-        * We now know the runlist of the last extent is mapped and @rl is at
-        * the end of the runlist.  We want to begin allocating clusters
-        * starting at the last allocated cluster to reduce fragmentation.  If
-        * there are no valid LCNs in the attribute we let the cluster
-        * allocator choose the starting cluster.
-        */
-       /* If the last LCN is a hole or simillar seek back to last real LCN. */
-       while (rl->lcn < 0 && rl > ni->runlist.rl)
-               rl--;
-first_alloc:
-       // FIXME: Need to implement partial allocations so at least part of the
-       // write can be performed when start >= 0.  (Needed for POSIX write(2)
-       // conformance.)
-       rl2 = ntfs_cluster_alloc(vol, allocated_size >> vol->cluster_size_bits,
-                       (new_alloc_size - allocated_size) >>
-                       vol->cluster_size_bits, (rl && (rl->lcn >= 0)) ?
-                       rl->lcn + rl->length : -1, DATA_ZONE, true);
-       if (IS_ERR(rl2)) {
-               err = PTR_ERR(rl2);
-               if (start < 0 || start >= allocated_size)
-                       ntfs_error(vol->sb, "Cannot extend allocation of "
-                                       "inode 0x%lx, attribute type 0x%x, "
-                                       "because the allocation of clusters "
-                                       "failed with error code %i.", vi->i_ino,
-                                       (unsigned)le32_to_cpu(ni->type), err);
-               if (err != -ENOMEM && err != -ENOSPC)
-                       err = -EIO;
-               goto err_out;
-       }
-       rl = ntfs_runlists_merge(ni->runlist.rl, rl2);
-       if (IS_ERR(rl)) {
-               err = PTR_ERR(rl);
-               if (start < 0 || start >= allocated_size)
-                       ntfs_error(vol->sb, "Cannot extend allocation of "
-                                       "inode 0x%lx, attribute type 0x%x, "
-                                       "because the runlist merge failed "
-                                       "with error code %i.", vi->i_ino,
-                                       (unsigned)le32_to_cpu(ni->type), err);
-               if (err != -ENOMEM)
-                       err = -EIO;
-               if (ntfs_cluster_free_from_rl(vol, rl2)) {
-                       ntfs_error(vol->sb, "Failed to release allocated "
-                                       "cluster(s) in error code path.  Run "
-                                       "chkdsk to recover the lost "
-                                       "cluster(s).");
-                       NVolSetErrors(vol);
-               }
-               ntfs_free(rl2);
-               goto err_out;
-       }
-       ni->runlist.rl = rl;
-       ntfs_debug("Allocated 0x%llx clusters.", (long long)(new_alloc_size -
-                       allocated_size) >> vol->cluster_size_bits);
-       /* Find the runlist element with which the attribute extent starts. */
-       ll = sle64_to_cpu(a->data.non_resident.lowest_vcn);
-       rl2 = ntfs_rl_find_vcn_nolock(rl, ll);
-       BUG_ON(!rl2);
-       BUG_ON(!rl2->length);
-       BUG_ON(rl2->lcn < LCN_HOLE);
-       mp_rebuilt = false;
-       /* Get the size for the new mapping pairs array for this extent. */
-       mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1);
-       if (unlikely(mp_size <= 0)) {
-               err = mp_size;
-               if (start < 0 || start >= allocated_size)
-                       ntfs_error(vol->sb, "Cannot extend allocation of "
-                                       "inode 0x%lx, attribute type 0x%x, "
-                                       "because determining the size for the "
-                                       "mapping pairs failed with error code "
-                                       "%i.", vi->i_ino,
-                                       (unsigned)le32_to_cpu(ni->type), err);
-               err = -EIO;
-               goto undo_alloc;
-       }
-       /* Extend the attribute record to fit the bigger mapping pairs array. */
-       attr_len = le32_to_cpu(a->length);
-       err = ntfs_attr_record_resize(m, a, mp_size +
-                       le16_to_cpu(a->data.non_resident.mapping_pairs_offset));
-       if (unlikely(err)) {
-               BUG_ON(err != -ENOSPC);
-               // TODO: Deal with this by moving this extent to a new mft
-               // record or by starting a new extent in a new mft record,
-               // possibly by extending this extent partially and filling it
-               // and creating a new extent for the remainder, or by making
-               // other attributes non-resident and/or by moving other
-               // attributes out of this mft record.
-               if (start < 0 || start >= allocated_size)
-                       ntfs_error(vol->sb, "Not enough space in the mft "
-                                       "record for the extended attribute "
-                                       "record.  This case is not "
-                                       "implemented yet.");
-               err = -EOPNOTSUPP;
-               goto undo_alloc;
-       }
-       mp_rebuilt = true;
-       /* Generate the mapping pairs array directly into the attr record. */
-       err = ntfs_mapping_pairs_build(vol, (u8*)a +
-                       le16_to_cpu(a->data.non_resident.mapping_pairs_offset),
-                       mp_size, rl2, ll, -1, NULL);
-       if (unlikely(err)) {
-               if (start < 0 || start >= allocated_size)
-                       ntfs_error(vol->sb, "Cannot extend allocation of "
-                                       "inode 0x%lx, attribute type 0x%x, "
-                                       "because building the mapping pairs "
-                                       "failed with error code %i.", vi->i_ino,
-                                       (unsigned)le32_to_cpu(ni->type), err);
-               err = -EIO;
-               goto undo_alloc;
-       }
-       /* Update the highest_vcn. */
-       a->data.non_resident.highest_vcn = cpu_to_sle64((new_alloc_size >>
-                       vol->cluster_size_bits) - 1);
-       /*
-        * We now have extended the allocated size of the attribute.  Reflect
-        * this in the ntfs_inode structure and the attribute record.
-        */
-       if (a->data.non_resident.lowest_vcn) {
-               /*
-                * We are not in the first attribute extent, switch to it, but
-                * first ensure the changes will make it to disk later.
-                */
-               flush_dcache_mft_record_page(ctx->ntfs_ino);
-               mark_mft_record_dirty(ctx->ntfs_ino);
-               ntfs_attr_reinit_search_ctx(ctx);
-               err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                               CASE_SENSITIVE, 0, NULL, 0, ctx);
-               if (unlikely(err))
-                       goto restore_undo_alloc;
-               /* @m is not used any more so no need to set it. */
-               a = ctx->attr;
-       }
-       write_lock_irqsave(&ni->size_lock, flags);
-       ni->allocated_size = new_alloc_size;
-       a->data.non_resident.allocated_size = cpu_to_sle64(new_alloc_size);
-       /*
-        * FIXME: This would fail if @ni is a directory, $MFT, or an index,
-        * since those can have sparse/compressed set.  For example can be
-        * set compressed even though it is not compressed itself and in that
-        * case the bit means that files are to be created compressed in the
-        * directory...  At present this is ok as this code is only called for
-        * regular files, and only for their $DATA attribute(s).
-        * FIXME: The calculation is wrong if we created a hole above.  For now
-        * it does not matter as we never create holes.
-        */
-       if (NInoSparse(ni) || NInoCompressed(ni)) {
-               ni->itype.compressed.size += new_alloc_size - allocated_size;
-               a->data.non_resident.compressed_size =
-                               cpu_to_sle64(ni->itype.compressed.size);
-               vi->i_blocks = ni->itype.compressed.size >> 9;
-       } else
-               vi->i_blocks = new_alloc_size >> 9;
-       write_unlock_irqrestore(&ni->size_lock, flags);
-alloc_done:
-       if (new_data_size >= 0) {
-               BUG_ON(new_data_size <
-                               sle64_to_cpu(a->data.non_resident.data_size));
-               a->data.non_resident.data_size = cpu_to_sle64(new_data_size);
-       }
-flush_done:
-       /* Ensure the changes make it to disk. */
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-done:
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(base_ni);
-       up_write(&ni->runlist.lock);
-       ntfs_debug("Done, new_allocated_size 0x%llx.",
-                       (unsigned long long)new_alloc_size);
-       return new_alloc_size;
-restore_undo_alloc:
-       if (start < 0 || start >= allocated_size)
-               ntfs_error(vol->sb, "Cannot complete extension of allocation "
-                               "of inode 0x%lx, attribute type 0x%x, because "
-                               "lookup of first attribute extent failed with "
-                               "error code %i.", vi->i_ino,
-                               (unsigned)le32_to_cpu(ni->type), err);
-       if (err == -ENOENT)
-               err = -EIO;
-       ntfs_attr_reinit_search_ctx(ctx);
-       if (ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE,
-                       allocated_size >> vol->cluster_size_bits, NULL, 0,
-                       ctx)) {
-               ntfs_error(vol->sb, "Failed to find last attribute extent of "
-                               "attribute in error code path.  Run chkdsk to "
-                               "recover.");
-               write_lock_irqsave(&ni->size_lock, flags);
-               ni->allocated_size = new_alloc_size;
-               /*
-                * FIXME: This would fail if @ni is a directory...  See above.
-                * FIXME: The calculation is wrong if we created a hole above.
-                * For now it does not matter as we never create holes.
-                */
-               if (NInoSparse(ni) || NInoCompressed(ni)) {
-                       ni->itype.compressed.size += new_alloc_size -
-                                       allocated_size;
-                       vi->i_blocks = ni->itype.compressed.size >> 9;
-               } else
-                       vi->i_blocks = new_alloc_size >> 9;
-               write_unlock_irqrestore(&ni->size_lock, flags);
-               ntfs_attr_put_search_ctx(ctx);
-               unmap_mft_record(base_ni);
-               up_write(&ni->runlist.lock);
-               /*
-                * The only thing that is now wrong is the allocated size of the
-                * base attribute extent which chkdsk should be able to fix.
-                */
-               NVolSetErrors(vol);
-               return err;
-       }
-       ctx->attr->data.non_resident.highest_vcn = cpu_to_sle64(
-                       (allocated_size >> vol->cluster_size_bits) - 1);
-undo_alloc:
-       ll = allocated_size >> vol->cluster_size_bits;
-       if (ntfs_cluster_free(ni, ll, -1, ctx) < 0) {
-               ntfs_error(vol->sb, "Failed to release allocated cluster(s) "
-                               "in error code path.  Run chkdsk to recover "
-                               "the lost cluster(s).");
-               NVolSetErrors(vol);
-       }
-       m = ctx->mrec;
-       a = ctx->attr;
-       /*
-        * If the runlist truncation fails and/or the search context is no
-        * longer valid, we cannot resize the attribute record or build the
-        * mapping pairs array thus we mark the inode bad so that no access to
-        * the freed clusters can happen.
-        */
-       if (ntfs_rl_truncate_nolock(vol, &ni->runlist, ll) || IS_ERR(m)) {
-               ntfs_error(vol->sb, "Failed to %s in error code path.  Run "
-                               "chkdsk to recover.", IS_ERR(m) ?
-                               "restore attribute search context" :
-                               "truncate attribute runlist");
-               NVolSetErrors(vol);
-       } else if (mp_rebuilt) {
-               if (ntfs_attr_record_resize(m, a, attr_len)) {
-                       ntfs_error(vol->sb, "Failed to restore attribute "
-                                       "record in error code path.  Run "
-                                       "chkdsk to recover.");
-                       NVolSetErrors(vol);
-               } else /* if (success) */ {
-                       if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(
-                                       a->data.non_resident.
-                                       mapping_pairs_offset), attr_len -
-                                       le16_to_cpu(a->data.non_resident.
-                                       mapping_pairs_offset), rl2, ll, -1,
-                                       NULL)) {
-                               ntfs_error(vol->sb, "Failed to restore "
-                                               "mapping pairs array in error "
-                                               "code path.  Run chkdsk to "
-                                               "recover.");
-                               NVolSetErrors(vol);
-                       }
-                       flush_dcache_mft_record_page(ctx->ntfs_ino);
-                       mark_mft_record_dirty(ctx->ntfs_ino);
-               }
-       }
-err_out:
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(base_ni);
-       up_write(&ni->runlist.lock);
-conv_err_out:
-       ntfs_debug("Failed.  Returning error code %i.", err);
-       return err;
-}
-
-/**
- * ntfs_attr_set - fill (a part of) an attribute with a byte
- * @ni:                ntfs inode describing the attribute to fill
- * @ofs:       offset inside the attribute at which to start to fill
- * @cnt:       number of bytes to fill
- * @val:       the unsigned 8-bit value with which to fill the attribute
- *
- * Fill @cnt bytes of the attribute described by the ntfs inode @ni starting at
- * byte offset @ofs inside the attribute with the constant byte @val.
- *
- * This function is effectively like memset() applied to an ntfs attribute.
- * Note this function actually only operates on the page cache pages belonging
- * to the ntfs attribute and it marks them dirty after doing the memset().
- * Thus it relies on the vm dirty page write code paths to cause the modified
- * pages to be written to the mft record/disk.
- *
- * Return 0 on success and -errno on error.  An error code of -ESPIPE means
- * that @ofs + @cnt were outside the end of the attribute and no write was
- * performed.
- */
-int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
-{
-       ntfs_volume *vol = ni->vol;
-       struct address_space *mapping;
-       struct page *page;
-       u8 *kaddr;
-       pgoff_t idx, end;
-       unsigned start_ofs, end_ofs, size;
-
-       ntfs_debug("Entering for ofs 0x%llx, cnt 0x%llx, val 0x%hx.",
-                       (long long)ofs, (long long)cnt, val);
-       BUG_ON(ofs < 0);
-       BUG_ON(cnt < 0);
-       if (!cnt)
-               goto done;
-       /*
-        * FIXME: Compressed and encrypted attributes are not supported when
-        * writing and we should never have gotten here for them.
-        */
-       BUG_ON(NInoCompressed(ni));
-       BUG_ON(NInoEncrypted(ni));
-       mapping = VFS_I(ni)->i_mapping;
-       /* Work out the starting index and page offset. */
-       idx = ofs >> PAGE_SHIFT;
-       start_ofs = ofs & ~PAGE_MASK;
-       /* Work out the ending index and page offset. */
-       end = ofs + cnt;
-       end_ofs = end & ~PAGE_MASK;
-       /* If the end is outside the inode size return -ESPIPE. */
-       if (unlikely(end > i_size_read(VFS_I(ni)))) {
-               ntfs_error(vol->sb, "Request exceeds end of attribute.");
-               return -ESPIPE;
-       }
-       end >>= PAGE_SHIFT;
-       /* If there is a first partial page, need to do it the slow way. */
-       if (start_ofs) {
-               page = read_mapping_page(mapping, idx, NULL);
-               if (IS_ERR(page)) {
-                       ntfs_error(vol->sb, "Failed to read first partial "
-                                       "page (error, index 0x%lx).", idx);
-                       return PTR_ERR(page);
-               }
-               /*
-                * If the last page is the same as the first page, need to
-                * limit the write to the end offset.
-                */
-               size = PAGE_SIZE;
-               if (idx == end)
-                       size = end_ofs;
-               kaddr = kmap_atomic(page);
-               memset(kaddr + start_ofs, val, size - start_ofs);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr);
-               set_page_dirty(page);
-               put_page(page);
-               balance_dirty_pages_ratelimited(mapping);
-               cond_resched();
-               if (idx == end)
-                       goto done;
-               idx++;
-       }
-       /* Do the whole pages the fast way. */
-       for (; idx < end; idx++) {
-               /* Find or create the current page.  (The page is locked.) */
-               page = grab_cache_page(mapping, idx);
-               if (unlikely(!page)) {
-                       ntfs_error(vol->sb, "Insufficient memory to grab "
-                                       "page (index 0x%lx).", idx);
-                       return -ENOMEM;
-               }
-               kaddr = kmap_atomic(page);
-               memset(kaddr, val, PAGE_SIZE);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr);
-               /*
-                * If the page has buffers, mark them uptodate since buffer
-                * state and not page state is definitive in 2.6 kernels.
-                */
-               if (page_has_buffers(page)) {
-                       struct buffer_head *bh, *head;
-
-                       bh = head = page_buffers(page);
-                       do {
-                               set_buffer_uptodate(bh);
-                       } while ((bh = bh->b_this_page) != head);
-               }
-               /* Now that buffers are uptodate, set the page uptodate, too. */
-               SetPageUptodate(page);
-               /*
-                * Set the page and all its buffers dirty and mark the inode
-                * dirty, too.  The VM will write the page later on.
-                */
-               set_page_dirty(page);
-               /* Finally unlock and release the page. */
-               unlock_page(page);
-               put_page(page);
-               balance_dirty_pages_ratelimited(mapping);
-               cond_resched();
-       }
-       /* If there is a last partial page, need to do it the slow way. */
-       if (end_ofs) {
-               page = read_mapping_page(mapping, idx, NULL);
-               if (IS_ERR(page)) {
-                       ntfs_error(vol->sb, "Failed to read last partial page "
-                                       "(error, index 0x%lx).", idx);
-                       return PTR_ERR(page);
-               }
-               kaddr = kmap_atomic(page);
-               memset(kaddr, val, end_ofs);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr);
-               set_page_dirty(page);
-               put_page(page);
-               balance_dirty_pages_ratelimited(mapping);
-               cond_resched();
-       }
-done:
-       ntfs_debug("Done.");
-       return 0;
-}
-
-#endif /* NTFS_RW */
diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h
deleted file mode 100644 (file)
index fe0890d..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * attrib.h - Defines for attribute handling in NTFS Linux kernel driver.
- *           Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2005 Anton Altaparmakov
- * Copyright (c) 2002 Richard Russon
- */
-
-#ifndef _LINUX_NTFS_ATTRIB_H
-#define _LINUX_NTFS_ATTRIB_H
-
-#include "endian.h"
-#include "types.h"
-#include "layout.h"
-#include "inode.h"
-#include "runlist.h"
-#include "volume.h"
-
-/**
- * ntfs_attr_search_ctx - used in attribute search functions
- * @mrec:      buffer containing mft record to search
- * @attr:      attribute record in @mrec where to begin/continue search
- * @is_first:  if true ntfs_attr_lookup() begins search with @attr, else after
- *
- * Structure must be initialized to zero before the first call to one of the
- * attribute search functions. Initialize @mrec to point to the mft record to
- * search, and @attr to point to the first attribute within @mrec (not necessary
- * if calling the _first() functions), and set @is_first to 'true' (not necessary
- * if calling the _first() functions).
- *
- * If @is_first is 'true', the search begins with @attr. If @is_first is 'false',
- * the search begins after @attr. This is so that, after the first call to one
- * of the search attribute functions, we can call the function again, without
- * any modification of the search context, to automagically get the next
- * matching attribute.
- */
-typedef struct {
-       MFT_RECORD *mrec;
-       ATTR_RECORD *attr;
-       bool is_first;
-       ntfs_inode *ntfs_ino;
-       ATTR_LIST_ENTRY *al_entry;
-       ntfs_inode *base_ntfs_ino;
-       MFT_RECORD *base_mrec;
-       ATTR_RECORD *base_attr;
-} ntfs_attr_search_ctx;
-
-extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn,
-               ntfs_attr_search_ctx *ctx);
-extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn);
-
-extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
-               const bool write_locked);
-
-extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni,
-               const VCN vcn, ntfs_attr_search_ctx *ctx);
-
-int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name,
-               const u32 name_len, const IGNORE_CASE_BOOL ic,
-               const VCN lowest_vcn, const u8 *val, const u32 val_len,
-               ntfs_attr_search_ctx *ctx);
-
-extern int load_attribute_list(ntfs_volume *vol, runlist *rl, u8 *al_start,
-               const s64 size, const s64 initialized_size);
-
-static inline s64 ntfs_attr_size(const ATTR_RECORD *a)
-{
-       if (!a->non_resident)
-               return (s64)le32_to_cpu(a->data.resident.value_length);
-       return sle64_to_cpu(a->data.non_resident.data_size);
-}
-
-extern void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx);
-extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni,
-               MFT_RECORD *mrec);
-extern void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx);
-
-#ifdef NTFS_RW
-
-extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol,
-               const ATTR_TYPE type, const s64 size);
-extern int ntfs_attr_can_be_non_resident(const ntfs_volume *vol,
-               const ATTR_TYPE type);
-extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
-               const ATTR_TYPE type);
-
-extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size);
-extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
-               const u32 new_size);
-
-extern int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size);
-
-extern s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size,
-               const s64 new_data_size, const s64 data_start);
-
-extern int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt,
-               const u8 val);
-
-#endif /* NTFS_RW */
-
-#endif /* _LINUX_NTFS_ATTRIB_H */
diff --git a/fs/ntfs/bitmap.c b/fs/ntfs/bitmap.c
deleted file mode 100644 (file)
index 0675b24..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * bitmap.c - NTFS kernel bitmap handling.  Part of the Linux-NTFS project.
- *
- * Copyright (c) 2004-2005 Anton Altaparmakov
- */
-
-#ifdef NTFS_RW
-
-#include <linux/pagemap.h>
-
-#include "bitmap.h"
-#include "debug.h"
-#include "aops.h"
-#include "ntfs.h"
-
-/**
- * __ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value
- * @vi:                        vfs inode describing the bitmap
- * @start_bit:         first bit to set
- * @count:             number of bits to set
- * @value:             value to set the bits to (i.e. 0 or 1)
- * @is_rollback:       if 'true' this is a rollback operation
- *
- * Set @count bits starting at bit @start_bit in the bitmap described by the
- * vfs inode @vi to @value, where @value is either 0 or 1.
- *
- * @is_rollback should always be 'false', it is for internal use to rollback
- * errors.  You probably want to use ntfs_bitmap_set_bits_in_run() instead.
- *
- * Return 0 on success and -errno on error.
- */
-int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
-               const s64 count, const u8 value, const bool is_rollback)
-{
-       s64 cnt = count;
-       pgoff_t index, end_index;
-       struct address_space *mapping;
-       struct page *page;
-       u8 *kaddr;
-       int pos, len;
-       u8 bit;
-
-       BUG_ON(!vi);
-       ntfs_debug("Entering for i_ino 0x%lx, start_bit 0x%llx, count 0x%llx, "
-                       "value %u.%s", vi->i_ino, (unsigned long long)start_bit,
-                       (unsigned long long)cnt, (unsigned int)value,
-                       is_rollback ? " (rollback)" : "");
-       BUG_ON(start_bit < 0);
-       BUG_ON(cnt < 0);
-       BUG_ON(value > 1);
-       /*
-        * Calculate the indices for the pages containing the first and last
-        * bits, i.e. @start_bit and @start_bit + @cnt - 1, respectively.
-        */
-       index = start_bit >> (3 + PAGE_SHIFT);
-       end_index = (start_bit + cnt - 1) >> (3 + PAGE_SHIFT);
-
-       /* Get the page containing the first bit (@start_bit). */
-       mapping = vi->i_mapping;
-       page = ntfs_map_page(mapping, index);
-       if (IS_ERR(page)) {
-               if (!is_rollback)
-                       ntfs_error(vi->i_sb, "Failed to map first page (error "
-                                       "%li), aborting.", PTR_ERR(page));
-               return PTR_ERR(page);
-       }
-       kaddr = page_address(page);
-
-       /* Set @pos to the position of the byte containing @start_bit. */
-       pos = (start_bit >> 3) & ~PAGE_MASK;
-
-       /* Calculate the position of @start_bit in the first byte. */
-       bit = start_bit & 7;
-
-       /* If the first byte is partial, modify the appropriate bits in it. */
-       if (bit) {
-               u8 *byte = kaddr + pos;
-               while ((bit & 7) && cnt) {
-                       cnt--;
-                       if (value)
-                               *byte |= 1 << bit++;
-                       else
-                               *byte &= ~(1 << bit++);
-               }
-               /* If we are done, unmap the page and return success. */
-               if (!cnt)
-                       goto done;
-
-               /* Update @pos to the new position. */
-               pos++;
-       }
-       /*
-        * Depending on @value, modify all remaining whole bytes in the page up
-        * to @cnt.
-        */
-       len = min_t(s64, cnt >> 3, PAGE_SIZE - pos);
-       memset(kaddr + pos, value ? 0xff : 0, len);
-       cnt -= len << 3;
-
-       /* Update @len to point to the first not-done byte in the page. */
-       if (cnt < 8)
-               len += pos;
-
-       /* If we are not in the last page, deal with all subsequent pages. */
-       while (index < end_index) {
-               BUG_ON(cnt <= 0);
-
-               /* Update @index and get the next page. */
-               flush_dcache_page(page);
-               set_page_dirty(page);
-               ntfs_unmap_page(page);
-               page = ntfs_map_page(mapping, ++index);
-               if (IS_ERR(page))
-                       goto rollback;
-               kaddr = page_address(page);
-               /*
-                * Depending on @value, modify all remaining whole bytes in the
-                * page up to @cnt.
-                */
-               len = min_t(s64, cnt >> 3, PAGE_SIZE);
-               memset(kaddr, value ? 0xff : 0, len);
-               cnt -= len << 3;
-       }
-       /*
-        * The currently mapped page is the last one.  If the last byte is
-        * partial, modify the appropriate bits in it.  Note, @len is the
-        * position of the last byte inside the page.
-        */
-       if (cnt) {
-               u8 *byte;
-
-               BUG_ON(cnt > 7);
-
-               bit = cnt;
-               byte = kaddr + len;
-               while (bit--) {
-                       if (value)
-                               *byte |= 1 << bit;
-                       else
-                               *byte &= ~(1 << bit);
-               }
-       }
-done:
-       /* We are done.  Unmap the page and return success. */
-       flush_dcache_page(page);
-       set_page_dirty(page);
-       ntfs_unmap_page(page);
-       ntfs_debug("Done.");
-       return 0;
-rollback:
-       /*
-        * Current state:
-        *      - no pages are mapped
-        *      - @count - @cnt is the number of bits that have been modified
-        */
-       if (is_rollback)
-               return PTR_ERR(page);
-       if (count != cnt)
-               pos = __ntfs_bitmap_set_bits_in_run(vi, start_bit, count - cnt,
-                               value ? 0 : 1, true);
-       else
-               pos = 0;
-       if (!pos) {
-               /* Rollback was successful. */
-               ntfs_error(vi->i_sb, "Failed to map subsequent page (error "
-                               "%li), aborting.", PTR_ERR(page));
-       } else {
-               /* Rollback failed. */
-               ntfs_error(vi->i_sb, "Failed to map subsequent page (error "
-                               "%li) and rollback failed (error %i).  "
-                               "Aborting and leaving inconsistent metadata.  "
-                               "Unmount and run chkdsk.", PTR_ERR(page), pos);
-               NVolSetErrors(NTFS_SB(vi->i_sb));
-       }
-       return PTR_ERR(page);
-}
-
-#endif /* NTFS_RW */
diff --git a/fs/ntfs/bitmap.h b/fs/ntfs/bitmap.h
deleted file mode 100644 (file)
index 9dd2224..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * bitmap.h - Defines for NTFS kernel bitmap handling.  Part of the Linux-NTFS
- *           project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_BITMAP_H
-#define _LINUX_NTFS_BITMAP_H
-
-#ifdef NTFS_RW
-
-#include <linux/fs.h>
-
-#include "types.h"
-
-extern int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
-               const s64 count, const u8 value, const bool is_rollback);
-
-/**
- * ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value
- * @vi:                        vfs inode describing the bitmap
- * @start_bit:         first bit to set
- * @count:             number of bits to set
- * @value:             value to set the bits to (i.e. 0 or 1)
- *
- * Set @count bits starting at bit @start_bit in the bitmap described by the
- * vfs inode @vi to @value, where @value is either 0 or 1.
- *
- * Return 0 on success and -errno on error.
- */
-static inline int ntfs_bitmap_set_bits_in_run(struct inode *vi,
-               const s64 start_bit, const s64 count, const u8 value)
-{
-       return __ntfs_bitmap_set_bits_in_run(vi, start_bit, count, value,
-                       false);
-}
-
-/**
- * ntfs_bitmap_set_run - set a run of bits in a bitmap
- * @vi:                vfs inode describing the bitmap
- * @start_bit: first bit to set
- * @count:     number of bits to set
- *
- * Set @count bits starting at bit @start_bit in the bitmap described by the
- * vfs inode @vi.
- *
- * Return 0 on success and -errno on error.
- */
-static inline int ntfs_bitmap_set_run(struct inode *vi, const s64 start_bit,
-               const s64 count)
-{
-       return ntfs_bitmap_set_bits_in_run(vi, start_bit, count, 1);
-}
-
-/**
- * ntfs_bitmap_clear_run - clear a run of bits in a bitmap
- * @vi:                vfs inode describing the bitmap
- * @start_bit: first bit to clear
- * @count:     number of bits to clear
- *
- * Clear @count bits starting at bit @start_bit in the bitmap described by the
- * vfs inode @vi.
- *
- * Return 0 on success and -errno on error.
- */
-static inline int ntfs_bitmap_clear_run(struct inode *vi, const s64 start_bit,
-               const s64 count)
-{
-       return ntfs_bitmap_set_bits_in_run(vi, start_bit, count, 0);
-}
-
-/**
- * ntfs_bitmap_set_bit - set a bit in a bitmap
- * @vi:                vfs inode describing the bitmap
- * @bit:       bit to set
- *
- * Set bit @bit in the bitmap described by the vfs inode @vi.
- *
- * Return 0 on success and -errno on error.
- */
-static inline int ntfs_bitmap_set_bit(struct inode *vi, const s64 bit)
-{
-       return ntfs_bitmap_set_run(vi, bit, 1);
-}
-
-/**
- * ntfs_bitmap_clear_bit - clear a bit in a bitmap
- * @vi:                vfs inode describing the bitmap
- * @bit:       bit to clear
- *
- * Clear bit @bit in the bitmap described by the vfs inode @vi.
- *
- * Return 0 on success and -errno on error.
- */
-static inline int ntfs_bitmap_clear_bit(struct inode *vi, const s64 bit)
-{
-       return ntfs_bitmap_clear_run(vi, bit, 1);
-}
-
-#endif /* NTFS_RW */
-
-#endif /* defined _LINUX_NTFS_BITMAP_H */
diff --git a/fs/ntfs/collate.c b/fs/ntfs/collate.c
deleted file mode 100644 (file)
index 3ab6ec9..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * collate.c - NTFS kernel collation handling.  Part of the Linux-NTFS project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- */
-
-#include "collate.h"
-#include "debug.h"
-#include "ntfs.h"
-
-static int ntfs_collate_binary(ntfs_volume *vol,
-               const void *data1, const int data1_len,
-               const void *data2, const int data2_len)
-{
-       int rc;
-
-       ntfs_debug("Entering.");
-       rc = memcmp(data1, data2, min(data1_len, data2_len));
-       if (!rc && (data1_len != data2_len)) {
-               if (data1_len < data2_len)
-                       rc = -1;
-               else
-                       rc = 1;
-       }
-       ntfs_debug("Done, returning %i", rc);
-       return rc;
-}
-
-static int ntfs_collate_ntofs_ulong(ntfs_volume *vol,
-               const void *data1, const int data1_len,
-               const void *data2, const int data2_len)
-{
-       int rc;
-       u32 d1, d2;
-
-       ntfs_debug("Entering.");
-       // FIXME:  We don't really want to bug here.
-       BUG_ON(data1_len != data2_len);
-       BUG_ON(data1_len != 4);
-       d1 = le32_to_cpup(data1);
-       d2 = le32_to_cpup(data2);
-       if (d1 < d2)
-               rc = -1;
-       else {
-               if (d1 == d2)
-                       rc = 0;
-               else
-                       rc = 1;
-       }
-       ntfs_debug("Done, returning %i", rc);
-       return rc;
-}
-
-typedef int (*ntfs_collate_func_t)(ntfs_volume *, const void *, const int,
-               const void *, const int);
-
-static ntfs_collate_func_t ntfs_do_collate0x0[3] = {
-       ntfs_collate_binary,
-       NULL/*ntfs_collate_file_name*/,
-       NULL/*ntfs_collate_unicode_string*/,
-};
-
-static ntfs_collate_func_t ntfs_do_collate0x1[4] = {
-       ntfs_collate_ntofs_ulong,
-       NULL/*ntfs_collate_ntofs_sid*/,
-       NULL/*ntfs_collate_ntofs_security_hash*/,
-       NULL/*ntfs_collate_ntofs_ulongs*/,
-};
-
-/**
- * ntfs_collate - collate two data items using a specified collation rule
- * @vol:       ntfs volume to which the data items belong
- * @cr:                collation rule to use when comparing the items
- * @data1:     first data item to collate
- * @data1_len: length in bytes of @data1
- * @data2:     second data item to collate
- * @data2_len: length in bytes of @data2
- *
- * Collate the two data items @data1 and @data2 using the collation rule @cr
- * and return -1, 0, ir 1 if @data1 is found, respectively, to collate before,
- * to match, or to collate after @data2.
- *
- * For speed we use the collation rule @cr as an index into two tables of
- * function pointers to call the appropriate collation function.
- */
-int ntfs_collate(ntfs_volume *vol, COLLATION_RULE cr,
-               const void *data1, const int data1_len,
-               const void *data2, const int data2_len) {
-       int i;
-
-       ntfs_debug("Entering.");
-       /*
-        * FIXME:  At the moment we only support COLLATION_BINARY and
-        * COLLATION_NTOFS_ULONG, so we BUG() for everything else for now.
-        */
-       BUG_ON(cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG);
-       i = le32_to_cpu(cr);
-       BUG_ON(i < 0);
-       if (i <= 0x02)
-               return ntfs_do_collate0x0[i](vol, data1, data1_len,
-                               data2, data2_len);
-       BUG_ON(i < 0x10);
-       i -= 0x10;
-       if (likely(i <= 3))
-               return ntfs_do_collate0x1[i](vol, data1, data1_len,
-                               data2, data2_len);
-       BUG();
-       return 0;
-}
diff --git a/fs/ntfs/collate.h b/fs/ntfs/collate.h
deleted file mode 100644 (file)
index f225561..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * collate.h - Defines for NTFS kernel collation handling.  Part of the
- *            Linux-NTFS project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_COLLATE_H
-#define _LINUX_NTFS_COLLATE_H
-
-#include "types.h"
-#include "volume.h"
-
-static inline bool ntfs_is_collation_rule_supported(COLLATION_RULE cr) {
-       int i;
-
-       /*
-        * FIXME:  At the moment we only support COLLATION_BINARY and
-        * COLLATION_NTOFS_ULONG, so we return false for everything else for
-        * now.
-        */
-       if (unlikely(cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG))
-               return false;
-       i = le32_to_cpu(cr);
-       if (likely(((i >= 0) && (i <= 0x02)) ||
-                       ((i >= 0x10) && (i <= 0x13))))
-               return true;
-       return false;
-}
-
-extern int ntfs_collate(ntfs_volume *vol, COLLATION_RULE cr,
-               const void *data1, const int data1_len,
-               const void *data2, const int data2_len);
-
-#endif /* _LINUX_NTFS_COLLATE_H */
diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c
deleted file mode 100644 (file)
index 761aaa0..0000000
+++ /dev/null
@@ -1,950 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * compress.c - NTFS kernel compressed attributes handling.
- *             Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2004 Anton Altaparmakov
- * Copyright (c) 2002 Richard Russon
- */
-
-#include <linux/fs.h>
-#include <linux/buffer_head.h>
-#include <linux/blkdev.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-
-#include "attrib.h"
-#include "inode.h"
-#include "debug.h"
-#include "ntfs.h"
-
-/**
- * ntfs_compression_constants - enum of constants used in the compression code
- */
-typedef enum {
-       /* Token types and access mask. */
-       NTFS_SYMBOL_TOKEN       =       0,
-       NTFS_PHRASE_TOKEN       =       1,
-       NTFS_TOKEN_MASK         =       1,
-
-       /* Compression sub-block constants. */
-       NTFS_SB_SIZE_MASK       =       0x0fff,
-       NTFS_SB_SIZE            =       0x1000,
-       NTFS_SB_IS_COMPRESSED   =       0x8000,
-
-       /*
-        * The maximum compression block size is by definition 16 * the cluster
-        * size, with the maximum supported cluster size being 4kiB. Thus the
-        * maximum compression buffer size is 64kiB, so we use this when
-        * initializing the compression buffer.
-        */
-       NTFS_MAX_CB_SIZE        = 64 * 1024,
-} ntfs_compression_constants;
-
-/*
- * ntfs_compression_buffer - one buffer for the decompression engine
- */
-static u8 *ntfs_compression_buffer;
-
-/*
- * ntfs_cb_lock - spinlock which protects ntfs_compression_buffer
- */
-static DEFINE_SPINLOCK(ntfs_cb_lock);
-
-/**
- * allocate_compression_buffers - allocate the decompression buffers
- *
- * Caller has to hold the ntfs_lock mutex.
- *
- * Return 0 on success or -ENOMEM if the allocations failed.
- */
-int allocate_compression_buffers(void)
-{
-       BUG_ON(ntfs_compression_buffer);
-
-       ntfs_compression_buffer = vmalloc(NTFS_MAX_CB_SIZE);
-       if (!ntfs_compression_buffer)
-               return -ENOMEM;
-       return 0;
-}
-
-/**
- * free_compression_buffers - free the decompression buffers
- *
- * Caller has to hold the ntfs_lock mutex.
- */
-void free_compression_buffers(void)
-{
-       BUG_ON(!ntfs_compression_buffer);
-       vfree(ntfs_compression_buffer);
-       ntfs_compression_buffer = NULL;
-}
-
-/**
- * zero_partial_compressed_page - zero out of bounds compressed page region
- */
-static void zero_partial_compressed_page(struct page *page,
-               const s64 initialized_size)
-{
-       u8 *kp = page_address(page);
-       unsigned int kp_ofs;
-
-       ntfs_debug("Zeroing page region outside initialized size.");
-       if (((s64)page->index << PAGE_SHIFT) >= initialized_size) {
-               clear_page(kp);
-               return;
-       }
-       kp_ofs = initialized_size & ~PAGE_MASK;
-       memset(kp + kp_ofs, 0, PAGE_SIZE - kp_ofs);
-       return;
-}
-
-/**
- * handle_bounds_compressed_page - test for&handle out of bounds compressed page
- */
-static inline void handle_bounds_compressed_page(struct page *page,
-               const loff_t i_size, const s64 initialized_size)
-{
-       if ((page->index >= (initialized_size >> PAGE_SHIFT)) &&
-                       (initialized_size < i_size))
-               zero_partial_compressed_page(page, initialized_size);
-       return;
-}
-
-/**
- * ntfs_decompress - decompress a compression block into an array of pages
- * @dest_pages:                destination array of pages
- * @completed_pages:   scratch space to track completed pages
- * @dest_index:                current index into @dest_pages (IN/OUT)
- * @dest_ofs:          current offset within @dest_pages[@dest_index] (IN/OUT)
- * @dest_max_index:    maximum index into @dest_pages (IN)
- * @dest_max_ofs:      maximum offset within @dest_pages[@dest_max_index] (IN)
- * @xpage:             the target page (-1 if none) (IN)
- * @xpage_done:                set to 1 if xpage was completed successfully (IN/OUT)
- * @cb_start:          compression block to decompress (IN)
- * @cb_size:           size of compression block @cb_start in bytes (IN)
- * @i_size:            file size when we started the read (IN)
- * @initialized_size:  initialized file size when we started the read (IN)
- *
- * The caller must have disabled preemption. ntfs_decompress() reenables it when
- * the critical section is finished.
- *
- * This decompresses the compression block @cb_start into the array of
- * destination pages @dest_pages starting at index @dest_index into @dest_pages
- * and at offset @dest_pos into the page @dest_pages[@dest_index].
- *
- * When the page @dest_pages[@xpage] is completed, @xpage_done is set to 1.
- * If xpage is -1 or @xpage has not been completed, @xpage_done is not modified.
- *
- * @cb_start is a pointer to the compression block which needs decompressing
- * and @cb_size is the size of @cb_start in bytes (8-64kiB).
- *
- * Return 0 if success or -EOVERFLOW on error in the compressed stream.
- * @xpage_done indicates whether the target page (@dest_pages[@xpage]) was
- * completed during the decompression of the compression block (@cb_start).
- *
- * Warning: This function *REQUIRES* PAGE_SIZE >= 4096 or it will blow up
- * unpredicatbly! You have been warned!
- *
- * Note to hackers: This function may not sleep until it has finished accessing
- * the compression block @cb_start as it is a per-CPU buffer.
- */
-static int ntfs_decompress(struct page *dest_pages[], int completed_pages[],
-               int *dest_index, int *dest_ofs, const int dest_max_index,
-               const int dest_max_ofs, const int xpage, char *xpage_done,
-               u8 *const cb_start, const u32 cb_size, const loff_t i_size,
-               const s64 initialized_size)
-{
-       /*
-        * Pointers into the compressed data, i.e. the compression block (cb),
-        * and the therein contained sub-blocks (sb).
-        */
-       u8 *cb_end = cb_start + cb_size; /* End of cb. */
-       u8 *cb = cb_start;      /* Current position in cb. */
-       u8 *cb_sb_start;        /* Beginning of the current sb in the cb. */
-       u8 *cb_sb_end;          /* End of current sb / beginning of next sb. */
-
-       /* Variables for uncompressed data / destination. */
-       struct page *dp;        /* Current destination page being worked on. */
-       u8 *dp_addr;            /* Current pointer into dp. */
-       u8 *dp_sb_start;        /* Start of current sub-block in dp. */
-       u8 *dp_sb_end;          /* End of current sb in dp (dp_sb_start +
-                                  NTFS_SB_SIZE). */
-       u16 do_sb_start;        /* @dest_ofs when starting this sub-block. */
-       u16 do_sb_end;          /* @dest_ofs of end of this sb (do_sb_start +
-                                  NTFS_SB_SIZE). */
-
-       /* Variables for tag and token parsing. */
-       u8 tag;                 /* Current tag. */
-       int token;              /* Loop counter for the eight tokens in tag. */
-       int nr_completed_pages = 0;
-
-       /* Default error code. */
-       int err = -EOVERFLOW;
-
-       ntfs_debug("Entering, cb_size = 0x%x.", cb_size);
-do_next_sb:
-       ntfs_debug("Beginning sub-block at offset = 0x%zx in the cb.",
-                       cb - cb_start);
-       /*
-        * Have we reached the end of the compression block or the end of the
-        * decompressed data?  The latter can happen for example if the current
-        * position in the compression block is one byte before its end so the
-        * first two checks do not detect it.
-        */
-       if (cb == cb_end || !le16_to_cpup((le16*)cb) ||
-                       (*dest_index == dest_max_index &&
-                       *dest_ofs == dest_max_ofs)) {
-               int i;
-
-               ntfs_debug("Completed. Returning success (0).");
-               err = 0;
-return_error:
-               /* We can sleep from now on, so we drop lock. */
-               spin_unlock(&ntfs_cb_lock);
-               /* Second stage: finalize completed pages. */
-               if (nr_completed_pages > 0) {
-                       for (i = 0; i < nr_completed_pages; i++) {
-                               int di = completed_pages[i];
-
-                               dp = dest_pages[di];
-                               /*
-                                * If we are outside the initialized size, zero
-                                * the out of bounds page range.
-                                */
-                               handle_bounds_compressed_page(dp, i_size,
-                                               initialized_size);
-                               flush_dcache_page(dp);
-                               kunmap(dp);
-                               SetPageUptodate(dp);
-                               unlock_page(dp);
-                               if (di == xpage)
-                                       *xpage_done = 1;
-                               else
-                                       put_page(dp);
-                               dest_pages[di] = NULL;
-                       }
-               }
-               return err;
-       }
-
-       /* Setup offsets for the current sub-block destination. */
-       do_sb_start = *dest_ofs;
-       do_sb_end = do_sb_start + NTFS_SB_SIZE;
-
-       /* Check that we are still within allowed boundaries. */
-       if (*dest_index == dest_max_index && do_sb_end > dest_max_ofs)
-               goto return_overflow;
-
-       /* Does the minimum size of a compressed sb overflow valid range? */
-       if (cb + 6 > cb_end)
-               goto return_overflow;
-
-       /* Setup the current sub-block source pointers and validate range. */
-       cb_sb_start = cb;
-       cb_sb_end = cb_sb_start + (le16_to_cpup((le16*)cb) & NTFS_SB_SIZE_MASK)
-                       + 3;
-       if (cb_sb_end > cb_end)
-               goto return_overflow;
-
-       /* Get the current destination page. */
-       dp = dest_pages[*dest_index];
-       if (!dp) {
-               /* No page present. Skip decompression of this sub-block. */
-               cb = cb_sb_end;
-
-               /* Advance destination position to next sub-block. */
-               *dest_ofs = (*dest_ofs + NTFS_SB_SIZE) & ~PAGE_MASK;
-               if (!*dest_ofs && (++*dest_index > dest_max_index))
-                       goto return_overflow;
-               goto do_next_sb;
-       }
-
-       /* We have a valid destination page. Setup the destination pointers. */
-       dp_addr = (u8*)page_address(dp) + do_sb_start;
-
-       /* Now, we are ready to process the current sub-block (sb). */
-       if (!(le16_to_cpup((le16*)cb) & NTFS_SB_IS_COMPRESSED)) {
-               ntfs_debug("Found uncompressed sub-block.");
-               /* This sb is not compressed, just copy it into destination. */
-
-               /* Advance source position to first data byte. */
-               cb += 2;
-
-               /* An uncompressed sb must be full size. */
-               if (cb_sb_end - cb != NTFS_SB_SIZE)
-                       goto return_overflow;
-
-               /* Copy the block and advance the source position. */
-               memcpy(dp_addr, cb, NTFS_SB_SIZE);
-               cb += NTFS_SB_SIZE;
-
-               /* Advance destination position to next sub-block. */
-               *dest_ofs += NTFS_SB_SIZE;
-               if (!(*dest_ofs &= ~PAGE_MASK)) {
-finalize_page:
-                       /*
-                        * First stage: add current page index to array of
-                        * completed pages.
-                        */
-                       completed_pages[nr_completed_pages++] = *dest_index;
-                       if (++*dest_index > dest_max_index)
-                               goto return_overflow;
-               }
-               goto do_next_sb;
-       }
-       ntfs_debug("Found compressed sub-block.");
-       /* This sb is compressed, decompress it into destination. */
-
-       /* Setup destination pointers. */
-       dp_sb_start = dp_addr;
-       dp_sb_end = dp_sb_start + NTFS_SB_SIZE;
-
-       /* Forward to the first tag in the sub-block. */
-       cb += 2;
-do_next_tag:
-       if (cb == cb_sb_end) {
-               /* Check if the decompressed sub-block was not full-length. */
-               if (dp_addr < dp_sb_end) {
-                       int nr_bytes = do_sb_end - *dest_ofs;
-
-                       ntfs_debug("Filling incomplete sub-block with "
-                                       "zeroes.");
-                       /* Zero remainder and update destination position. */
-                       memset(dp_addr, 0, nr_bytes);
-                       *dest_ofs += nr_bytes;
-               }
-               /* We have finished the current sub-block. */
-               if (!(*dest_ofs &= ~PAGE_MASK))
-                       goto finalize_page;
-               goto do_next_sb;
-       }
-
-       /* Check we are still in range. */
-       if (cb > cb_sb_end || dp_addr > dp_sb_end)
-               goto return_overflow;
-
-       /* Get the next tag and advance to first token. */
-       tag = *cb++;
-
-       /* Parse the eight tokens described by the tag. */
-       for (token = 0; token < 8; token++, tag >>= 1) {
-               u16 lg, pt, length, max_non_overlap;
-               register u16 i;
-               u8 *dp_back_addr;
-
-               /* Check if we are done / still in range. */
-               if (cb >= cb_sb_end || dp_addr > dp_sb_end)
-                       break;
-
-               /* Determine token type and parse appropriately.*/
-               if ((tag & NTFS_TOKEN_MASK) == NTFS_SYMBOL_TOKEN) {
-                       /*
-                        * We have a symbol token, copy the symbol across, and
-                        * advance the source and destination positions.
-                        */
-                       *dp_addr++ = *cb++;
-                       ++*dest_ofs;
-
-                       /* Continue with the next token. */
-                       continue;
-               }
-
-               /*
-                * We have a phrase token. Make sure it is not the first tag in
-                * the sb as this is illegal and would confuse the code below.
-                */
-               if (dp_addr == dp_sb_start)
-                       goto return_overflow;
-
-               /*
-                * Determine the number of bytes to go back (p) and the number
-                * of bytes to copy (l). We use an optimized algorithm in which
-                * we first calculate log2(current destination position in sb),
-                * which allows determination of l and p in O(1) rather than
-                * O(n). We just need an arch-optimized log2() function now.
-                */
-               lg = 0;
-               for (i = *dest_ofs - do_sb_start - 1; i >= 0x10; i >>= 1)
-                       lg++;
-
-               /* Get the phrase token into i. */
-               pt = le16_to_cpup((le16*)cb);
-
-               /*
-                * Calculate starting position of the byte sequence in
-                * the destination using the fact that p = (pt >> (12 - lg)) + 1
-                * and make sure we don't go too far back.
-                */
-               dp_back_addr = dp_addr - (pt >> (12 - lg)) - 1;
-               if (dp_back_addr < dp_sb_start)
-                       goto return_overflow;
-
-               /* Now calculate the length of the byte sequence. */
-               length = (pt & (0xfff >> lg)) + 3;
-
-               /* Advance destination position and verify it is in range. */
-               *dest_ofs += length;
-               if (*dest_ofs > do_sb_end)
-                       goto return_overflow;
-
-               /* The number of non-overlapping bytes. */
-               max_non_overlap = dp_addr - dp_back_addr;
-
-               if (length <= max_non_overlap) {
-                       /* The byte sequence doesn't overlap, just copy it. */
-                       memcpy(dp_addr, dp_back_addr, length);
-
-                       /* Advance destination pointer. */
-                       dp_addr += length;
-               } else {
-                       /*
-                        * The byte sequence does overlap, copy non-overlapping
-                        * part and then do a slow byte by byte copy for the
-                        * overlapping part. Also, advance the destination
-                        * pointer.
-                        */
-                       memcpy(dp_addr, dp_back_addr, max_non_overlap);
-                       dp_addr += max_non_overlap;
-                       dp_back_addr += max_non_overlap;
-                       length -= max_non_overlap;
-                       while (length--)
-                               *dp_addr++ = *dp_back_addr++;
-               }
-
-               /* Advance source position and continue with the next token. */
-               cb += 2;
-       }
-
-       /* No tokens left in the current tag. Continue with the next tag. */
-       goto do_next_tag;
-
-return_overflow:
-       ntfs_error(NULL, "Failed. Returning -EOVERFLOW.");
-       goto return_error;
-}
-
-/**
- * ntfs_read_compressed_block - read a compressed block into the page cache
- * @page:      locked page in the compression block(s) we need to read
- *
- * When we are called the page has already been verified to be locked and the
- * attribute is known to be non-resident, not encrypted, but compressed.
- *
- * 1. Determine which compression block(s) @page is in.
- * 2. Get hold of all pages corresponding to this/these compression block(s).
- * 3. Read the (first) compression block.
- * 4. Decompress it into the corresponding pages.
- * 5. Throw the compressed data away and proceed to 3. for the next compression
- *    block or return success if no more compression blocks left.
- *
- * Warning: We have to be careful what we do about existing pages. They might
- * have been written to so that we would lose data if we were to just overwrite
- * them with the out-of-date uncompressed data.
- *
- * FIXME: For PAGE_SIZE > cb_size we are not doing the Right Thing(TM) at
- * the end of the file I think. We need to detect this case and zero the out
- * of bounds remainder of the page in question and mark it as handled. At the
- * moment we would just return -EIO on such a page. This bug will only become
- * apparent if pages are above 8kiB and the NTFS volume only uses 512 byte
- * clusters so is probably not going to be seen by anyone. Still this should
- * be fixed. (AIA)
- *
- * FIXME: Again for PAGE_SIZE > cb_size we are screwing up both in
- * handling sparse and compressed cbs. (AIA)
- *
- * FIXME: At the moment we don't do any zeroing out in the case that
- * initialized_size is less than data_size. This should be safe because of the
- * nature of the compression algorithm used. Just in case we check and output
- * an error message in read inode if the two sizes are not equal for a
- * compressed file. (AIA)
- */
-int ntfs_read_compressed_block(struct page *page)
-{
-       loff_t i_size;
-       s64 initialized_size;
-       struct address_space *mapping = page->mapping;
-       ntfs_inode *ni = NTFS_I(mapping->host);
-       ntfs_volume *vol = ni->vol;
-       struct super_block *sb = vol->sb;
-       runlist_element *rl;
-       unsigned long flags, block_size = sb->s_blocksize;
-       unsigned char block_size_bits = sb->s_blocksize_bits;
-       u8 *cb, *cb_pos, *cb_end;
-       struct buffer_head **bhs;
-       unsigned long offset, index = page->index;
-       u32 cb_size = ni->itype.compressed.block_size;
-       u64 cb_size_mask = cb_size - 1UL;
-       VCN vcn;
-       LCN lcn;
-       /* The first wanted vcn (minimum alignment is PAGE_SIZE). */
-       VCN start_vcn = (((s64)index << PAGE_SHIFT) & ~cb_size_mask) >>
-                       vol->cluster_size_bits;
-       /*
-        * The first vcn after the last wanted vcn (minimum alignment is again
-        * PAGE_SIZE.
-        */
-       VCN end_vcn = ((((s64)(index + 1UL) << PAGE_SHIFT) + cb_size - 1)
-                       & ~cb_size_mask) >> vol->cluster_size_bits;
-       /* Number of compression blocks (cbs) in the wanted vcn range. */
-       unsigned int nr_cbs = (end_vcn - start_vcn) << vol->cluster_size_bits
-                       >> ni->itype.compressed.block_size_bits;
-       /*
-        * Number of pages required to store the uncompressed data from all
-        * compression blocks (cbs) overlapping @page. Due to alignment
-        * guarantees of start_vcn and end_vcn, no need to round up here.
-        */
-       unsigned int nr_pages = (end_vcn - start_vcn) <<
-                       vol->cluster_size_bits >> PAGE_SHIFT;
-       unsigned int xpage, max_page, cur_page, cur_ofs, i;
-       unsigned int cb_clusters, cb_max_ofs;
-       int block, max_block, cb_max_page, bhs_size, nr_bhs, err = 0;
-       struct page **pages;
-       int *completed_pages;
-       unsigned char xpage_done = 0;
-
-       ntfs_debug("Entering, page->index = 0x%lx, cb_size = 0x%x, nr_pages = "
-                       "%i.", index, cb_size, nr_pages);
-       /*
-        * Bad things happen if we get here for anything that is not an
-        * unnamed $DATA attribute.
-        */
-       BUG_ON(ni->type != AT_DATA);
-       BUG_ON(ni->name_len);
-
-       pages = kmalloc_array(nr_pages, sizeof(struct page *), GFP_NOFS);
-       completed_pages = kmalloc_array(nr_pages + 1, sizeof(int), GFP_NOFS);
-
-       /* Allocate memory to store the buffer heads we need. */
-       bhs_size = cb_size / block_size * sizeof(struct buffer_head *);
-       bhs = kmalloc(bhs_size, GFP_NOFS);
-
-       if (unlikely(!pages || !bhs || !completed_pages)) {
-               kfree(bhs);
-               kfree(pages);
-               kfree(completed_pages);
-               unlock_page(page);
-               ntfs_error(vol->sb, "Failed to allocate internal buffers.");
-               return -ENOMEM;
-       }
-
-       /*
-        * We have already been given one page, this is the one we must do.
-        * Once again, the alignment guarantees keep it simple.
-        */
-       offset = start_vcn << vol->cluster_size_bits >> PAGE_SHIFT;
-       xpage = index - offset;
-       pages[xpage] = page;
-       /*
-        * The remaining pages need to be allocated and inserted into the page
-        * cache, alignment guarantees keep all the below much simpler. (-8
-        */
-       read_lock_irqsave(&ni->size_lock, flags);
-       i_size = i_size_read(VFS_I(ni));
-       initialized_size = ni->initialized_size;
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       max_page = ((i_size + PAGE_SIZE - 1) >> PAGE_SHIFT) -
-                       offset;
-       /* Is the page fully outside i_size? (truncate in progress) */
-       if (xpage >= max_page) {
-               kfree(bhs);
-               kfree(pages);
-               kfree(completed_pages);
-               zero_user(page, 0, PAGE_SIZE);
-               ntfs_debug("Compressed read outside i_size - truncated?");
-               SetPageUptodate(page);
-               unlock_page(page);
-               return 0;
-       }
-       if (nr_pages < max_page)
-               max_page = nr_pages;
-       for (i = 0; i < max_page; i++, offset++) {
-               if (i != xpage)
-                       pages[i] = grab_cache_page_nowait(mapping, offset);
-               page = pages[i];
-               if (page) {
-                       /*
-                        * We only (re)read the page if it isn't already read
-                        * in and/or dirty or we would be losing data or at
-                        * least wasting our time.
-                        */
-                       if (!PageDirty(page) && (!PageUptodate(page) ||
-                                       PageError(page))) {
-                               ClearPageError(page);
-                               kmap(page);
-                               continue;
-                       }
-                       unlock_page(page);
-                       put_page(page);
-                       pages[i] = NULL;
-               }
-       }
-
-       /*
-        * We have the runlist, and all the destination pages we need to fill.
-        * Now read the first compression block.
-        */
-       cur_page = 0;
-       cur_ofs = 0;
-       cb_clusters = ni->itype.compressed.block_clusters;
-do_next_cb:
-       nr_cbs--;
-       nr_bhs = 0;
-
-       /* Read all cb buffer heads one cluster at a time. */
-       rl = NULL;
-       for (vcn = start_vcn, start_vcn += cb_clusters; vcn < start_vcn;
-                       vcn++) {
-               bool is_retry = false;
-
-               if (!rl) {
-lock_retry_remap:
-                       down_read(&ni->runlist.lock);
-                       rl = ni->runlist.rl;
-               }
-               if (likely(rl != NULL)) {
-                       /* Seek to element containing target vcn. */
-                       while (rl->length && rl[1].vcn <= vcn)
-                               rl++;
-                       lcn = ntfs_rl_vcn_to_lcn(rl, vcn);
-               } else
-                       lcn = LCN_RL_NOT_MAPPED;
-               ntfs_debug("Reading vcn = 0x%llx, lcn = 0x%llx.",
-                               (unsigned long long)vcn,
-                               (unsigned long long)lcn);
-               if (lcn < 0) {
-                       /*
-                        * When we reach the first sparse cluster we have
-                        * finished with the cb.
-                        */
-                       if (lcn == LCN_HOLE)
-                               break;
-                       if (is_retry || lcn != LCN_RL_NOT_MAPPED)
-                               goto rl_err;
-                       is_retry = true;
-                       /*
-                        * Attempt to map runlist, dropping lock for the
-                        * duration.
-                        */
-                       up_read(&ni->runlist.lock);
-                       if (!ntfs_map_runlist(ni, vcn))
-                               goto lock_retry_remap;
-                       goto map_rl_err;
-               }
-               block = lcn << vol->cluster_size_bits >> block_size_bits;
-               /* Read the lcn from device in chunks of block_size bytes. */
-               max_block = block + (vol->cluster_size >> block_size_bits);
-               do {
-                       ntfs_debug("block = 0x%x.", block);
-                       if (unlikely(!(bhs[nr_bhs] = sb_getblk(sb, block))))
-                               goto getblk_err;
-                       nr_bhs++;
-               } while (++block < max_block);
-       }
-
-       /* Release the lock if we took it. */
-       if (rl)
-               up_read(&ni->runlist.lock);
-
-       /* Setup and initiate io on all buffer heads. */
-       for (i = 0; i < nr_bhs; i++) {
-               struct buffer_head *tbh = bhs[i];
-
-               if (!trylock_buffer(tbh))
-                       continue;
-               if (unlikely(buffer_uptodate(tbh))) {
-                       unlock_buffer(tbh);
-                       continue;
-               }
-               get_bh(tbh);
-               tbh->b_end_io = end_buffer_read_sync;
-               submit_bh(REQ_OP_READ, tbh);
-       }
-
-       /* Wait for io completion on all buffer heads. */
-       for (i = 0; i < nr_bhs; i++) {
-               struct buffer_head *tbh = bhs[i];
-
-               if (buffer_uptodate(tbh))
-                       continue;
-               wait_on_buffer(tbh);
-               /*
-                * We need an optimization barrier here, otherwise we start
-                * hitting the below fixup code when accessing a loopback
-                * mounted ntfs partition. This indicates either there is a
-                * race condition in the loop driver or, more likely, gcc
-                * overoptimises the code without the barrier and it doesn't
-                * do the Right Thing(TM).
-                */
-               barrier();
-               if (unlikely(!buffer_uptodate(tbh))) {
-                       ntfs_warning(vol->sb, "Buffer is unlocked but not "
-                                       "uptodate! Unplugging the disk queue "
-                                       "and rescheduling.");
-                       get_bh(tbh);
-                       io_schedule();
-                       put_bh(tbh);
-                       if (unlikely(!buffer_uptodate(tbh)))
-                               goto read_err;
-                       ntfs_warning(vol->sb, "Buffer is now uptodate. Good.");
-               }
-       }
-
-       /*
-        * Get the compression buffer. We must not sleep any more
-        * until we are finished with it.
-        */
-       spin_lock(&ntfs_cb_lock);
-       cb = ntfs_compression_buffer;
-
-       BUG_ON(!cb);
-
-       cb_pos = cb;
-       cb_end = cb + cb_size;
-
-       /* Copy the buffer heads into the contiguous buffer. */
-       for (i = 0; i < nr_bhs; i++) {
-               memcpy(cb_pos, bhs[i]->b_data, block_size);
-               cb_pos += block_size;
-       }
-
-       /* Just a precaution. */
-       if (cb_pos + 2 <= cb + cb_size)
-               *(u16*)cb_pos = 0;
-
-       /* Reset cb_pos back to the beginning. */
-       cb_pos = cb;
-
-       /* We now have both source (if present) and destination. */
-       ntfs_debug("Successfully read the compression block.");
-
-       /* The last page and maximum offset within it for the current cb. */
-       cb_max_page = (cur_page << PAGE_SHIFT) + cur_ofs + cb_size;
-       cb_max_ofs = cb_max_page & ~PAGE_MASK;
-       cb_max_page >>= PAGE_SHIFT;
-
-       /* Catch end of file inside a compression block. */
-       if (cb_max_page > max_page)
-               cb_max_page = max_page;
-
-       if (vcn == start_vcn - cb_clusters) {
-               /* Sparse cb, zero out page range overlapping the cb. */
-               ntfs_debug("Found sparse compression block.");
-               /* We can sleep from now on, so we drop lock. */
-               spin_unlock(&ntfs_cb_lock);
-               if (cb_max_ofs)
-                       cb_max_page--;
-               for (; cur_page < cb_max_page; cur_page++) {
-                       page = pages[cur_page];
-                       if (page) {
-                               if (likely(!cur_ofs))
-                                       clear_page(page_address(page));
-                               else
-                                       memset(page_address(page) + cur_ofs, 0,
-                                                       PAGE_SIZE -
-                                                       cur_ofs);
-                               flush_dcache_page(page);
-                               kunmap(page);
-                               SetPageUptodate(page);
-                               unlock_page(page);
-                               if (cur_page == xpage)
-                                       xpage_done = 1;
-                               else
-                                       put_page(page);
-                               pages[cur_page] = NULL;
-                       }
-                       cb_pos += PAGE_SIZE - cur_ofs;
-                       cur_ofs = 0;
-                       if (cb_pos >= cb_end)
-                               break;
-               }
-               /* If we have a partial final page, deal with it now. */
-               if (cb_max_ofs && cb_pos < cb_end) {
-                       page = pages[cur_page];
-                       if (page)
-                               memset(page_address(page) + cur_ofs, 0,
-                                               cb_max_ofs - cur_ofs);
-                       /*
-                        * No need to update cb_pos at this stage:
-                        *      cb_pos += cb_max_ofs - cur_ofs;
-                        */
-                       cur_ofs = cb_max_ofs;
-               }
-       } else if (vcn == start_vcn) {
-               /* We can't sleep so we need two stages. */
-               unsigned int cur2_page = cur_page;
-               unsigned int cur_ofs2 = cur_ofs;
-               u8 *cb_pos2 = cb_pos;
-
-               ntfs_debug("Found uncompressed compression block.");
-               /* Uncompressed cb, copy it to the destination pages. */
-               /*
-                * TODO: As a big optimization, we could detect this case
-                * before we read all the pages and use block_read_full_folio()
-                * on all full pages instead (we still have to treat partial
-                * pages especially but at least we are getting rid of the
-                * synchronous io for the majority of pages.
-                * Or if we choose not to do the read-ahead/-behind stuff, we
-                * could just return block_read_full_folio(pages[xpage]) as long
-                * as PAGE_SIZE <= cb_size.
-                */
-               if (cb_max_ofs)
-                       cb_max_page--;
-               /* First stage: copy data into destination pages. */
-               for (; cur_page < cb_max_page; cur_page++) {
-                       page = pages[cur_page];
-                       if (page)
-                               memcpy(page_address(page) + cur_ofs, cb_pos,
-                                               PAGE_SIZE - cur_ofs);
-                       cb_pos += PAGE_SIZE - cur_ofs;
-                       cur_ofs = 0;
-                       if (cb_pos >= cb_end)
-                               break;
-               }
-               /* If we have a partial final page, deal with it now. */
-               if (cb_max_ofs && cb_pos < cb_end) {
-                       page = pages[cur_page];
-                       if (page)
-                               memcpy(page_address(page) + cur_ofs, cb_pos,
-                                               cb_max_ofs - cur_ofs);
-                       cb_pos += cb_max_ofs - cur_ofs;
-                       cur_ofs = cb_max_ofs;
-               }
-               /* We can sleep from now on, so drop lock. */
-               spin_unlock(&ntfs_cb_lock);
-               /* Second stage: finalize pages. */
-               for (; cur2_page < cb_max_page; cur2_page++) {
-                       page = pages[cur2_page];
-                       if (page) {
-                               /*
-                                * If we are outside the initialized size, zero
-                                * the out of bounds page range.
-                                */
-                               handle_bounds_compressed_page(page, i_size,
-                                               initialized_size);
-                               flush_dcache_page(page);
-                               kunmap(page);
-                               SetPageUptodate(page);
-                               unlock_page(page);
-                               if (cur2_page == xpage)
-                                       xpage_done = 1;
-                               else
-                                       put_page(page);
-                               pages[cur2_page] = NULL;
-                       }
-                       cb_pos2 += PAGE_SIZE - cur_ofs2;
-                       cur_ofs2 = 0;
-                       if (cb_pos2 >= cb_end)
-                               break;
-               }
-       } else {
-               /* Compressed cb, decompress it into the destination page(s). */
-               unsigned int prev_cur_page = cur_page;
-
-               ntfs_debug("Found compressed compression block.");
-               err = ntfs_decompress(pages, completed_pages, &cur_page,
-                               &cur_ofs, cb_max_page, cb_max_ofs, xpage,
-                               &xpage_done, cb_pos, cb_size - (cb_pos - cb),
-                               i_size, initialized_size);
-               /*
-                * We can sleep from now on, lock already dropped by
-                * ntfs_decompress().
-                */
-               if (err) {
-                       ntfs_error(vol->sb, "ntfs_decompress() failed in inode "
-                                       "0x%lx with error code %i. Skipping "
-                                       "this compression block.",
-                                       ni->mft_no, -err);
-                       /* Release the unfinished pages. */
-                       for (; prev_cur_page < cur_page; prev_cur_page++) {
-                               page = pages[prev_cur_page];
-                               if (page) {
-                                       flush_dcache_page(page);
-                                       kunmap(page);
-                                       unlock_page(page);
-                                       if (prev_cur_page != xpage)
-                                               put_page(page);
-                                       pages[prev_cur_page] = NULL;
-                               }
-                       }
-               }
-       }
-
-       /* Release the buffer heads. */
-       for (i = 0; i < nr_bhs; i++)
-               brelse(bhs[i]);
-
-       /* Do we have more work to do? */
-       if (nr_cbs)
-               goto do_next_cb;
-
-       /* We no longer need the list of buffer heads. */
-       kfree(bhs);
-
-       /* Clean up if we have any pages left. Should never happen. */
-       for (cur_page = 0; cur_page < max_page; cur_page++) {
-               page = pages[cur_page];
-               if (page) {
-                       ntfs_error(vol->sb, "Still have pages left! "
-                                       "Terminating them with extreme "
-                                       "prejudice.  Inode 0x%lx, page index "
-                                       "0x%lx.", ni->mft_no, page->index);
-                       flush_dcache_page(page);
-                       kunmap(page);
-                       unlock_page(page);
-                       if (cur_page != xpage)
-                               put_page(page);
-                       pages[cur_page] = NULL;
-               }
-       }
-
-       /* We no longer need the list of pages. */
-       kfree(pages);
-       kfree(completed_pages);
-
-       /* If we have completed the requested page, we return success. */
-       if (likely(xpage_done))
-               return 0;
-
-       ntfs_debug("Failed. Returning error code %s.", err == -EOVERFLOW ?
-                       "EOVERFLOW" : (!err ? "EIO" : "unknown error"));
-       return err < 0 ? err : -EIO;
-
-read_err:
-       ntfs_error(vol->sb, "IO error while reading compressed data.");
-       /* Release the buffer heads. */
-       for (i = 0; i < nr_bhs; i++)
-               brelse(bhs[i]);
-       goto err_out;
-
-map_rl_err:
-       ntfs_error(vol->sb, "ntfs_map_runlist() failed. Cannot read "
-                       "compression block.");
-       goto err_out;
-
-rl_err:
-       up_read(&ni->runlist.lock);
-       ntfs_error(vol->sb, "ntfs_rl_vcn_to_lcn() failed. Cannot read "
-                       "compression block.");
-       goto err_out;
-
-getblk_err:
-       up_read(&ni->runlist.lock);
-       ntfs_error(vol->sb, "getblk() failed. Cannot read compression block.");
-
-err_out:
-       kfree(bhs);
-       for (i = cur_page; i < max_page; i++) {
-               page = pages[i];
-               if (page) {
-                       flush_dcache_page(page);
-                       kunmap(page);
-                       unlock_page(page);
-                       if (i != xpage)
-                               put_page(page);
-               }
-       }
-       kfree(pages);
-       kfree(completed_pages);
-       return -EIO;
-}
diff --git a/fs/ntfs/debug.c b/fs/ntfs/debug.c
deleted file mode 100644 (file)
index a3c1c56..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * debug.c - NTFS kernel debug support. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2004 Anton Altaparmakov
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include "debug.h"
-
-/**
- * __ntfs_warning - output a warning to the syslog
- * @function:  name of function outputting the warning
- * @sb:                super block of mounted ntfs filesystem
- * @fmt:       warning string containing format specifications
- * @...:       a variable number of arguments specified in @fmt
- *
- * Outputs a warning to the syslog for the mounted ntfs filesystem described
- * by @sb.
- *
- * @fmt and the corresponding @... is printf style format string containing
- * the warning string and the corresponding format arguments, respectively.
- *
- * @function is the name of the function from which __ntfs_warning is being
- * called.
- *
- * Note, you should be using debug.h::ntfs_warning(@sb, @fmt, @...) instead
- * as this provides the @function parameter automatically.
- */
-void __ntfs_warning(const char *function, const struct super_block *sb,
-               const char *fmt, ...)
-{
-       struct va_format vaf;
-       va_list args;
-       int flen = 0;
-
-#ifndef DEBUG
-       if (!printk_ratelimit())
-               return;
-#endif
-       if (function)
-               flen = strlen(function);
-       va_start(args, fmt);
-       vaf.fmt = fmt;
-       vaf.va = &args;
-       if (sb)
-               pr_warn("(device %s): %s(): %pV\n",
-                       sb->s_id, flen ? function : "", &vaf);
-       else
-               pr_warn("%s(): %pV\n", flen ? function : "", &vaf);
-       va_end(args);
-}
-
-/**
- * __ntfs_error - output an error to the syslog
- * @function:  name of function outputting the error
- * @sb:                super block of mounted ntfs filesystem
- * @fmt:       error string containing format specifications
- * @...:       a variable number of arguments specified in @fmt
- *
- * Outputs an error to the syslog for the mounted ntfs filesystem described
- * by @sb.
- *
- * @fmt and the corresponding @... is printf style format string containing
- * the error string and the corresponding format arguments, respectively.
- *
- * @function is the name of the function from which __ntfs_error is being
- * called.
- *
- * Note, you should be using debug.h::ntfs_error(@sb, @fmt, @...) instead
- * as this provides the @function parameter automatically.
- */
-void __ntfs_error(const char *function, const struct super_block *sb,
-               const char *fmt, ...)
-{
-       struct va_format vaf;
-       va_list args;
-       int flen = 0;
-
-#ifndef DEBUG
-       if (!printk_ratelimit())
-               return;
-#endif
-       if (function)
-               flen = strlen(function);
-       va_start(args, fmt);
-       vaf.fmt = fmt;
-       vaf.va = &args;
-       if (sb)
-               pr_err("(device %s): %s(): %pV\n",
-                      sb->s_id, flen ? function : "", &vaf);
-       else
-               pr_err("%s(): %pV\n", flen ? function : "", &vaf);
-       va_end(args);
-}
-
-#ifdef DEBUG
-
-/* If 1, output debug messages, and if 0, don't. */
-int debug_msgs = 0;
-
-void __ntfs_debug(const char *file, int line, const char *function,
-               const char *fmt, ...)
-{
-       struct va_format vaf;
-       va_list args;
-       int flen = 0;
-
-       if (!debug_msgs)
-               return;
-       if (function)
-               flen = strlen(function);
-       va_start(args, fmt);
-       vaf.fmt = fmt;
-       vaf.va = &args;
-       pr_debug("(%s, %d): %s(): %pV", file, line, flen ? function : "", &vaf);
-       va_end(args);
-}
-
-/* Dump a runlist. Caller has to provide synchronisation for @rl. */
-void ntfs_debug_dump_runlist(const runlist_element *rl)
-{
-       int i;
-       const char *lcn_str[5] = { "LCN_HOLE         ", "LCN_RL_NOT_MAPPED",
-                                  "LCN_ENOENT       ", "LCN_unknown      " };
-
-       if (!debug_msgs)
-               return;
-       pr_debug("Dumping runlist (values in hex):\n");
-       if (!rl) {
-               pr_debug("Run list not present.\n");
-               return;
-       }
-       pr_debug("VCN              LCN               Run length\n");
-       for (i = 0; ; i++) {
-               LCN lcn = (rl + i)->lcn;
-
-               if (lcn < (LCN)0) {
-                       int index = -lcn - 1;
-
-                       if (index > -LCN_ENOENT - 1)
-                               index = 3;
-                       pr_debug("%-16Lx %s %-16Lx%s\n",
-                                       (long long)(rl + i)->vcn, lcn_str[index],
-                                       (long long)(rl + i)->length,
-                                       (rl + i)->length ? "" :
-                                               " (runlist end)");
-               } else
-                       pr_debug("%-16Lx %-16Lx  %-16Lx%s\n",
-                                       (long long)(rl + i)->vcn,
-                                       (long long)(rl + i)->lcn,
-                                       (long long)(rl + i)->length,
-                                       (rl + i)->length ? "" :
-                                               " (runlist end)");
-               if (!(rl + i)->length)
-                       break;
-       }
-}
-
-#endif
diff --git a/fs/ntfs/debug.h b/fs/ntfs/debug.h
deleted file mode 100644 (file)
index 6fdef38..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * debug.h - NTFS kernel debug support. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2004 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_DEBUG_H
-#define _LINUX_NTFS_DEBUG_H
-
-#include <linux/fs.h>
-
-#include "runlist.h"
-
-#ifdef DEBUG
-
-extern int debug_msgs;
-
-extern __printf(4, 5)
-void __ntfs_debug(const char *file, int line, const char *function,
-                 const char *format, ...);
-/**
- * ntfs_debug - write a debug level message to syslog
- * @f:         a printf format string containing the message
- * @...:       the variables to substitute into @f
- *
- * ntfs_debug() writes a DEBUG level message to the syslog but only if the
- * driver was compiled with -DDEBUG. Otherwise, the call turns into a NOP.
- */
-#define ntfs_debug(f, a...)                                            \
-       __ntfs_debug(__FILE__, __LINE__, __func__, f, ##a)
-
-extern void ntfs_debug_dump_runlist(const runlist_element *rl);
-
-#else  /* !DEBUG */
-
-#define ntfs_debug(fmt, ...)                                           \
-do {                                                                   \
-       if (0)                                                          \
-               no_printk(fmt, ##__VA_ARGS__);                          \
-} while (0)
-
-#define ntfs_debug_dump_runlist(rl)    do {} while (0)
-
-#endif /* !DEBUG */
-
-extern  __printf(3, 4)
-void __ntfs_warning(const char *function, const struct super_block *sb,
-                   const char *fmt, ...);
-#define ntfs_warning(sb, f, a...)      __ntfs_warning(__func__, sb, f, ##a)
-
-extern  __printf(3, 4)
-void __ntfs_error(const char *function, const struct super_block *sb,
-                 const char *fmt, ...);
-#define ntfs_error(sb, f, a...)                __ntfs_error(__func__, sb, f, ##a)
-
-#endif /* _LINUX_NTFS_DEBUG_H */
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
deleted file mode 100644 (file)
index 629723a..0000000
+++ /dev/null
@@ -1,1540 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2007 Anton Altaparmakov
- * Copyright (c) 2002 Richard Russon
- */
-
-#include <linux/buffer_head.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-
-#include "dir.h"
-#include "aops.h"
-#include "attrib.h"
-#include "mft.h"
-#include "debug.h"
-#include "ntfs.h"
-
-/*
- * The little endian Unicode string $I30 as a global constant.
- */
-ntfschar I30[5] = { cpu_to_le16('$'), cpu_to_le16('I'),
-               cpu_to_le16('3'),       cpu_to_le16('0'), 0 };
-
-/**
- * ntfs_lookup_inode_by_name - find an inode in a directory given its name
- * @dir_ni:    ntfs inode of the directory in which to search for the name
- * @uname:     Unicode name for which to search in the directory
- * @uname_len: length of the name @uname in Unicode characters
- * @res:       return the found file name if necessary (see below)
- *
- * Look for an inode with name @uname in the directory with inode @dir_ni.
- * ntfs_lookup_inode_by_name() walks the contents of the directory looking for
- * the Unicode name. If the name is found in the directory, the corresponding
- * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it
- * is a 64-bit number containing the sequence number.
- *
- * On error, a negative value is returned corresponding to the error code. In
- * particular if the inode is not found -ENOENT is returned. Note that you
- * can't just check the return value for being negative, you have to check the
- * inode number for being negative which you can extract using MREC(return
- * value).
- *
- * Note, @uname_len does not include the (optional) terminating NULL character.
- *
- * Note, we look for a case sensitive match first but we also look for a case
- * insensitive match at the same time. If we find a case insensitive match, we
- * save that for the case that we don't find an exact match, where we return
- * the case insensitive match and setup @res (which we allocate!) with the mft
- * reference, the file name type, length and with a copy of the little endian
- * Unicode file name itself. If we match a file name which is in the DOS name
- * space, we only return the mft reference and file name type in @res.
- * ntfs_lookup() then uses this to find the long file name in the inode itself.
- * This is to avoid polluting the dcache with short file names. We want them to
- * work but we don't care for how quickly one can access them. This also fixes
- * the dcache aliasing issues.
- *
- * Locking:  - Caller must hold i_mutex on the directory.
- *          - Each page cache page in the index allocation mapping must be
- *            locked whilst being accessed otherwise we may find a corrupt
- *            page due to it being under ->writepage at the moment which
- *            applies the mst protection fixups before writing out and then
- *            removes them again after the write is complete after which it 
- *            unlocks the page.
- */
-MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
-               const int uname_len, ntfs_name **res)
-{
-       ntfs_volume *vol = dir_ni->vol;
-       struct super_block *sb = vol->sb;
-       MFT_RECORD *m;
-       INDEX_ROOT *ir;
-       INDEX_ENTRY *ie;
-       INDEX_ALLOCATION *ia;
-       u8 *index_end;
-       u64 mref;
-       ntfs_attr_search_ctx *ctx;
-       int err, rc;
-       VCN vcn, old_vcn;
-       struct address_space *ia_mapping;
-       struct page *page;
-       u8 *kaddr;
-       ntfs_name *name = NULL;
-
-       BUG_ON(!S_ISDIR(VFS_I(dir_ni)->i_mode));
-       BUG_ON(NInoAttr(dir_ni));
-       /* Get hold of the mft record for the directory. */
-       m = map_mft_record(dir_ni);
-       if (IS_ERR(m)) {
-               ntfs_error(sb, "map_mft_record() failed with error code %ld.",
-                               -PTR_ERR(m));
-               return ERR_MREF(PTR_ERR(m));
-       }
-       ctx = ntfs_attr_get_search_ctx(dir_ni, m);
-       if (unlikely(!ctx)) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       /* Find the index root attribute in the mft record. */
-       err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
-                       0, ctx);
-       if (unlikely(err)) {
-               if (err == -ENOENT) {
-                       ntfs_error(sb, "Index root attribute missing in "
-                                       "directory inode 0x%lx.",
-                                       dir_ni->mft_no);
-                       err = -EIO;
-               }
-               goto err_out;
-       }
-       /* Get to the index root value (it's been verified in read_inode). */
-       ir = (INDEX_ROOT*)((u8*)ctx->attr +
-                       le16_to_cpu(ctx->attr->data.resident.value_offset));
-       index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
-       /* The first index entry. */
-       ie = (INDEX_ENTRY*)((u8*)&ir->index +
-                       le32_to_cpu(ir->index.entries_offset));
-       /*
-        * Loop until we exceed valid memory (corruption case) or until we
-        * reach the last entry.
-        */
-       for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
-               /* Bounds checks. */
-               if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
-                               sizeof(INDEX_ENTRY_HEADER) > index_end ||
-                               (u8*)ie + le16_to_cpu(ie->key_length) >
-                               index_end)
-                       goto dir_err_out;
-               /*
-                * The last entry cannot contain a name. It can however contain
-                * a pointer to a child node in the B+tree so we just break out.
-                */
-               if (ie->flags & INDEX_ENTRY_END)
-                       break;
-               /*
-                * We perform a case sensitive comparison and if that matches
-                * we are done and return the mft reference of the inode (i.e.
-                * the inode number together with the sequence number for
-                * consistency checking). We convert it to cpu format before
-                * returning.
-                */
-               if (ntfs_are_names_equal(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length,
-                               CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
-found_it:
-                       /*
-                        * We have a perfect match, so we don't need to care
-                        * about having matched imperfectly before, so we can
-                        * free name and set *res to NULL.
-                        * However, if the perfect match is a short file name,
-                        * we need to signal this through *res, so that
-                        * ntfs_lookup() can fix dcache aliasing issues.
-                        * As an optimization we just reuse an existing
-                        * allocation of *res.
-                        */
-                       if (ie->key.file_name.file_name_type == FILE_NAME_DOS) {
-                               if (!name) {
-                                       name = kmalloc(sizeof(ntfs_name),
-                                                       GFP_NOFS);
-                                       if (!name) {
-                                               err = -ENOMEM;
-                                               goto err_out;
-                                       }
-                               }
-                               name->mref = le64_to_cpu(
-                                               ie->data.dir.indexed_file);
-                               name->type = FILE_NAME_DOS;
-                               name->len = 0;
-                               *res = name;
-                       } else {
-                               kfree(name);
-                               *res = NULL;
-                       }
-                       mref = le64_to_cpu(ie->data.dir.indexed_file);
-                       ntfs_attr_put_search_ctx(ctx);
-                       unmap_mft_record(dir_ni);
-                       return mref;
-               }
-               /*
-                * For a case insensitive mount, we also perform a case
-                * insensitive comparison (provided the file name is not in the
-                * POSIX namespace). If the comparison matches, and the name is
-                * in the WIN32 namespace, we cache the filename in *res so
-                * that the caller, ntfs_lookup(), can work on it. If the
-                * comparison matches, and the name is in the DOS namespace, we
-                * only cache the mft reference and the file name type (we set
-                * the name length to zero for simplicity).
-                */
-               if (!NVolCaseSensitive(vol) &&
-                               ie->key.file_name.file_name_type &&
-                               ntfs_are_names_equal(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length,
-                               IGNORE_CASE, vol->upcase, vol->upcase_len)) {
-                       int name_size = sizeof(ntfs_name);
-                       u8 type = ie->key.file_name.file_name_type;
-                       u8 len = ie->key.file_name.file_name_length;
-
-                       /* Only one case insensitive matching name allowed. */
-                       if (name) {
-                               ntfs_error(sb, "Found already allocated name "
-                                               "in phase 1. Please run chkdsk "
-                                               "and if that doesn't find any "
-                                               "errors please report you saw "
-                                               "this message to "
-                                               "linux-ntfs-dev@lists."
-                                               "sourceforge.net.");
-                               goto dir_err_out;
-                       }
-
-                       if (type != FILE_NAME_DOS)
-                               name_size += len * sizeof(ntfschar);
-                       name = kmalloc(name_size, GFP_NOFS);
-                       if (!name) {
-                               err = -ENOMEM;
-                               goto err_out;
-                       }
-                       name->mref = le64_to_cpu(ie->data.dir.indexed_file);
-                       name->type = type;
-                       if (type != FILE_NAME_DOS) {
-                               name->len = len;
-                               memcpy(name->name, ie->key.file_name.file_name,
-                                               len * sizeof(ntfschar));
-                       } else
-                               name->len = 0;
-                       *res = name;
-               }
-               /*
-                * Not a perfect match, need to do full blown collation so we
-                * know which way in the B+tree we have to go.
-                */
-               rc = ntfs_collate_names(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length, 1,
-                               IGNORE_CASE, vol->upcase, vol->upcase_len);
-               /*
-                * If uname collates before the name of the current entry, there
-                * is definitely no such name in this index but we might need to
-                * descend into the B+tree so we just break out of the loop.
-                */
-               if (rc == -1)
-                       break;
-               /* The names are not equal, continue the search. */
-               if (rc)
-                       continue;
-               /*
-                * Names match with case insensitive comparison, now try the
-                * case sensitive comparison, which is required for proper
-                * collation.
-                */
-               rc = ntfs_collate_names(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length, 1,
-                               CASE_SENSITIVE, vol->upcase, vol->upcase_len);
-               if (rc == -1)
-                       break;
-               if (rc)
-                       continue;
-               /*
-                * Perfect match, this will never happen as the
-                * ntfs_are_names_equal() call will have gotten a match but we
-                * still treat it correctly.
-                */
-               goto found_it;
-       }
-       /*
-        * We have finished with this index without success. Check for the
-        * presence of a child node and if not present return -ENOENT, unless
-        * we have got a matching name cached in name in which case return the
-        * mft reference associated with it.
-        */
-       if (!(ie->flags & INDEX_ENTRY_NODE)) {
-               if (name) {
-                       ntfs_attr_put_search_ctx(ctx);
-                       unmap_mft_record(dir_ni);
-                       return name->mref;
-               }
-               ntfs_debug("Entry not found.");
-               err = -ENOENT;
-               goto err_out;
-       } /* Child node present, descend into it. */
-       /* Consistency check: Verify that an index allocation exists. */
-       if (!NInoIndexAllocPresent(dir_ni)) {
-               ntfs_error(sb, "No index allocation attribute but index entry "
-                               "requires one. Directory inode 0x%lx is "
-                               "corrupt or driver bug.", dir_ni->mft_no);
-               goto err_out;
-       }
-       /* Get the starting vcn of the index_block holding the child node. */
-       vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
-       ia_mapping = VFS_I(dir_ni)->i_mapping;
-       /*
-        * We are done with the index root and the mft record. Release them,
-        * otherwise we deadlock with ntfs_map_page().
-        */
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(dir_ni);
-       m = NULL;
-       ctx = NULL;
-descend_into_child_node:
-       /*
-        * Convert vcn to index into the index allocation attribute in units
-        * of PAGE_SIZE and map the page cache page, reading it from
-        * disk if necessary.
-        */
-       page = ntfs_map_page(ia_mapping, vcn <<
-                       dir_ni->itype.index.vcn_size_bits >> PAGE_SHIFT);
-       if (IS_ERR(page)) {
-               ntfs_error(sb, "Failed to map directory index page, error %ld.",
-                               -PTR_ERR(page));
-               err = PTR_ERR(page);
-               goto err_out;
-       }
-       lock_page(page);
-       kaddr = (u8*)page_address(page);
-fast_descend_into_child_node:
-       /* Get to the index allocation block. */
-       ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
-                       dir_ni->itype.index.vcn_size_bits) & ~PAGE_MASK));
-       /* Bounds checks. */
-       if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) {
-               ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
-                               "inode 0x%lx or driver bug.", dir_ni->mft_no);
-               goto unm_err_out;
-       }
-       /* Catch multi sector transfer fixup errors. */
-       if (unlikely(!ntfs_is_indx_record(ia->magic))) {
-               ntfs_error(sb, "Directory index record with vcn 0x%llx is "
-                               "corrupt.  Corrupt inode 0x%lx.  Run chkdsk.",
-                               (unsigned long long)vcn, dir_ni->mft_no);
-               goto unm_err_out;
-       }
-       if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
-               ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
-                               "different from expected VCN (0x%llx). "
-                               "Directory inode 0x%lx is corrupt or driver "
-                               "bug.", (unsigned long long)
-                               sle64_to_cpu(ia->index_block_vcn),
-                               (unsigned long long)vcn, dir_ni->mft_no);
-               goto unm_err_out;
-       }
-       if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
-                       dir_ni->itype.index.block_size) {
-               ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
-                               "0x%lx has a size (%u) differing from the "
-                               "directory specified size (%u). Directory "
-                               "inode is corrupt or driver bug.",
-                               (unsigned long long)vcn, dir_ni->mft_no,
-                               le32_to_cpu(ia->index.allocated_size) + 0x18,
-                               dir_ni->itype.index.block_size);
-               goto unm_err_out;
-       }
-       index_end = (u8*)ia + dir_ni->itype.index.block_size;
-       if (index_end > kaddr + PAGE_SIZE) {
-               ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
-                               "0x%lx crosses page boundary. Impossible! "
-                               "Cannot access! This is probably a bug in the "
-                               "driver.", (unsigned long long)vcn,
-                               dir_ni->mft_no);
-               goto unm_err_out;
-       }
-       index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
-       if (index_end > (u8*)ia + dir_ni->itype.index.block_size) {
-               ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
-                               "inode 0x%lx exceeds maximum size.",
-                               (unsigned long long)vcn, dir_ni->mft_no);
-               goto unm_err_out;
-       }
-       /* The first index entry. */
-       ie = (INDEX_ENTRY*)((u8*)&ia->index +
-                       le32_to_cpu(ia->index.entries_offset));
-       /*
-        * Iterate similar to above big loop but applied to index buffer, thus
-        * loop until we exceed valid memory (corruption case) or until we
-        * reach the last entry.
-        */
-       for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
-               /* Bounds check. */
-               if ((u8*)ie < (u8*)ia || (u8*)ie +
-                               sizeof(INDEX_ENTRY_HEADER) > index_end ||
-                               (u8*)ie + le16_to_cpu(ie->key_length) >
-                               index_end) {
-                       ntfs_error(sb, "Index entry out of bounds in "
-                                       "directory inode 0x%lx.",
-                                       dir_ni->mft_no);
-                       goto unm_err_out;
-               }
-               /*
-                * The last entry cannot contain a name. It can however contain
-                * a pointer to a child node in the B+tree so we just break out.
-                */
-               if (ie->flags & INDEX_ENTRY_END)
-                       break;
-               /*
-                * We perform a case sensitive comparison and if that matches
-                * we are done and return the mft reference of the inode (i.e.
-                * the inode number together with the sequence number for
-                * consistency checking). We convert it to cpu format before
-                * returning.
-                */
-               if (ntfs_are_names_equal(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length,
-                               CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
-found_it2:
-                       /*
-                        * We have a perfect match, so we don't need to care
-                        * about having matched imperfectly before, so we can
-                        * free name and set *res to NULL.
-                        * However, if the perfect match is a short file name,
-                        * we need to signal this through *res, so that
-                        * ntfs_lookup() can fix dcache aliasing issues.
-                        * As an optimization we just reuse an existing
-                        * allocation of *res.
-                        */
-                       if (ie->key.file_name.file_name_type == FILE_NAME_DOS) {
-                               if (!name) {
-                                       name = kmalloc(sizeof(ntfs_name),
-                                                       GFP_NOFS);
-                                       if (!name) {
-                                               err = -ENOMEM;
-                                               goto unm_err_out;
-                                       }
-                               }
-                               name->mref = le64_to_cpu(
-                                               ie->data.dir.indexed_file);
-                               name->type = FILE_NAME_DOS;
-                               name->len = 0;
-                               *res = name;
-                       } else {
-                               kfree(name);
-                               *res = NULL;
-                       }
-                       mref = le64_to_cpu(ie->data.dir.indexed_file);
-                       unlock_page(page);
-                       ntfs_unmap_page(page);
-                       return mref;
-               }
-               /*
-                * For a case insensitive mount, we also perform a case
-                * insensitive comparison (provided the file name is not in the
-                * POSIX namespace). If the comparison matches, and the name is
-                * in the WIN32 namespace, we cache the filename in *res so
-                * that the caller, ntfs_lookup(), can work on it. If the
-                * comparison matches, and the name is in the DOS namespace, we
-                * only cache the mft reference and the file name type (we set
-                * the name length to zero for simplicity).
-                */
-               if (!NVolCaseSensitive(vol) &&
-                               ie->key.file_name.file_name_type &&
-                               ntfs_are_names_equal(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length,
-                               IGNORE_CASE, vol->upcase, vol->upcase_len)) {
-                       int name_size = sizeof(ntfs_name);
-                       u8 type = ie->key.file_name.file_name_type;
-                       u8 len = ie->key.file_name.file_name_length;
-
-                       /* Only one case insensitive matching name allowed. */
-                       if (name) {
-                               ntfs_error(sb, "Found already allocated name "
-                                               "in phase 2. Please run chkdsk "
-                                               "and if that doesn't find any "
-                                               "errors please report you saw "
-                                               "this message to "
-                                               "linux-ntfs-dev@lists."
-                                               "sourceforge.net.");
-                               unlock_page(page);
-                               ntfs_unmap_page(page);
-                               goto dir_err_out;
-                       }
-
-                       if (type != FILE_NAME_DOS)
-                               name_size += len * sizeof(ntfschar);
-                       name = kmalloc(name_size, GFP_NOFS);
-                       if (!name) {
-                               err = -ENOMEM;
-                               goto unm_err_out;
-                       }
-                       name->mref = le64_to_cpu(ie->data.dir.indexed_file);
-                       name->type = type;
-                       if (type != FILE_NAME_DOS) {
-                               name->len = len;
-                               memcpy(name->name, ie->key.file_name.file_name,
-                                               len * sizeof(ntfschar));
-                       } else
-                               name->len = 0;
-                       *res = name;
-               }
-               /*
-                * Not a perfect match, need to do full blown collation so we
-                * know which way in the B+tree we have to go.
-                */
-               rc = ntfs_collate_names(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length, 1,
-                               IGNORE_CASE, vol->upcase, vol->upcase_len);
-               /*
-                * If uname collates before the name of the current entry, there
-                * is definitely no such name in this index but we might need to
-                * descend into the B+tree so we just break out of the loop.
-                */
-               if (rc == -1)
-                       break;
-               /* The names are not equal, continue the search. */
-               if (rc)
-                       continue;
-               /*
-                * Names match with case insensitive comparison, now try the
-                * case sensitive comparison, which is required for proper
-                * collation.
-                */
-               rc = ntfs_collate_names(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length, 1,
-                               CASE_SENSITIVE, vol->upcase, vol->upcase_len);
-               if (rc == -1)
-                       break;
-               if (rc)
-                       continue;
-               /*
-                * Perfect match, this will never happen as the
-                * ntfs_are_names_equal() call will have gotten a match but we
-                * still treat it correctly.
-                */
-               goto found_it2;
-       }
-       /*
-        * We have finished with this index buffer without success. Check for
-        * the presence of a child node.
-        */
-       if (ie->flags & INDEX_ENTRY_NODE) {
-               if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
-                       ntfs_error(sb, "Index entry with child node found in "
-                                       "a leaf node in directory inode 0x%lx.",
-                                       dir_ni->mft_no);
-                       goto unm_err_out;
-               }
-               /* Child node present, descend into it. */
-               old_vcn = vcn;
-               vcn = sle64_to_cpup((sle64*)((u8*)ie +
-                               le16_to_cpu(ie->length) - 8));
-               if (vcn >= 0) {
-                       /* If vcn is in the same page cache page as old_vcn we
-                        * recycle the mapped page. */
-                       if (old_vcn << vol->cluster_size_bits >>
-                                       PAGE_SHIFT == vcn <<
-                                       vol->cluster_size_bits >>
-                                       PAGE_SHIFT)
-                               goto fast_descend_into_child_node;
-                       unlock_page(page);
-                       ntfs_unmap_page(page);
-                       goto descend_into_child_node;
-               }
-               ntfs_error(sb, "Negative child node vcn in directory inode "
-                               "0x%lx.", dir_ni->mft_no);
-               goto unm_err_out;
-       }
-       /*
-        * No child node present, return -ENOENT, unless we have got a matching
-        * name cached in name in which case return the mft reference
-        * associated with it.
-        */
-       if (name) {
-               unlock_page(page);
-               ntfs_unmap_page(page);
-               return name->mref;
-       }
-       ntfs_debug("Entry not found.");
-       err = -ENOENT;
-unm_err_out:
-       unlock_page(page);
-       ntfs_unmap_page(page);
-err_out:
-       if (!err)
-               err = -EIO;
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(dir_ni);
-       if (name) {
-               kfree(name);
-               *res = NULL;
-       }
-       return ERR_MREF(err);
-dir_err_out:
-       ntfs_error(sb, "Corrupt directory.  Aborting lookup.");
-       goto err_out;
-}
-
-#if 0
-
-// TODO: (AIA)
-// The algorithm embedded in this code will be required for the time when we
-// want to support adding of entries to directories, where we require correct
-// collation of file names in order not to cause corruption of the filesystem.
-
-/**
- * ntfs_lookup_inode_by_name - find an inode in a directory given its name
- * @dir_ni:    ntfs inode of the directory in which to search for the name
- * @uname:     Unicode name for which to search in the directory
- * @uname_len: length of the name @uname in Unicode characters
- *
- * Look for an inode with name @uname in the directory with inode @dir_ni.
- * ntfs_lookup_inode_by_name() walks the contents of the directory looking for
- * the Unicode name. If the name is found in the directory, the corresponding
- * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it
- * is a 64-bit number containing the sequence number.
- *
- * On error, a negative value is returned corresponding to the error code. In
- * particular if the inode is not found -ENOENT is returned. Note that you
- * can't just check the return value for being negative, you have to check the
- * inode number for being negative which you can extract using MREC(return
- * value).
- *
- * Note, @uname_len does not include the (optional) terminating NULL character.
- */
-u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
-               const int uname_len)
-{
-       ntfs_volume *vol = dir_ni->vol;
-       struct super_block *sb = vol->sb;
-       MFT_RECORD *m;
-       INDEX_ROOT *ir;
-       INDEX_ENTRY *ie;
-       INDEX_ALLOCATION *ia;
-       u8 *index_end;
-       u64 mref;
-       ntfs_attr_search_ctx *ctx;
-       int err, rc;
-       IGNORE_CASE_BOOL ic;
-       VCN vcn, old_vcn;
-       struct address_space *ia_mapping;
-       struct page *page;
-       u8 *kaddr;
-
-       /* Get hold of the mft record for the directory. */
-       m = map_mft_record(dir_ni);
-       if (IS_ERR(m)) {
-               ntfs_error(sb, "map_mft_record() failed with error code %ld.",
-                               -PTR_ERR(m));
-               return ERR_MREF(PTR_ERR(m));
-       }
-       ctx = ntfs_attr_get_search_ctx(dir_ni, m);
-       if (!ctx) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       /* Find the index root attribute in the mft record. */
-       err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
-                       0, ctx);
-       if (unlikely(err)) {
-               if (err == -ENOENT) {
-                       ntfs_error(sb, "Index root attribute missing in "
-                                       "directory inode 0x%lx.",
-                                       dir_ni->mft_no);
-                       err = -EIO;
-               }
-               goto err_out;
-       }
-       /* Get to the index root value (it's been verified in read_inode). */
-       ir = (INDEX_ROOT*)((u8*)ctx->attr +
-                       le16_to_cpu(ctx->attr->data.resident.value_offset));
-       index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
-       /* The first index entry. */
-       ie = (INDEX_ENTRY*)((u8*)&ir->index +
-                       le32_to_cpu(ir->index.entries_offset));
-       /*
-        * Loop until we exceed valid memory (corruption case) or until we
-        * reach the last entry.
-        */
-       for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
-               /* Bounds checks. */
-               if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
-                               sizeof(INDEX_ENTRY_HEADER) > index_end ||
-                               (u8*)ie + le16_to_cpu(ie->key_length) >
-                               index_end)
-                       goto dir_err_out;
-               /*
-                * The last entry cannot contain a name. It can however contain
-                * a pointer to a child node in the B+tree so we just break out.
-                */
-               if (ie->flags & INDEX_ENTRY_END)
-                       break;
-               /*
-                * If the current entry has a name type of POSIX, the name is
-                * case sensitive and not otherwise. This has the effect of us
-                * not being able to access any POSIX file names which collate
-                * after the non-POSIX one when they only differ in case, but
-                * anyone doing screwy stuff like that deserves to burn in
-                * hell... Doing that kind of stuff on NT4 actually causes
-                * corruption on the partition even when using SP6a and Linux
-                * is not involved at all.
-                */
-               ic = ie->key.file_name.file_name_type ? IGNORE_CASE :
-                               CASE_SENSITIVE;
-               /*
-                * If the names match perfectly, we are done and return the
-                * mft reference of the inode (i.e. the inode number together
-                * with the sequence number for consistency checking. We
-                * convert it to cpu format before returning.
-                */
-               if (ntfs_are_names_equal(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length, ic,
-                               vol->upcase, vol->upcase_len)) {
-found_it:
-                       mref = le64_to_cpu(ie->data.dir.indexed_file);
-                       ntfs_attr_put_search_ctx(ctx);
-                       unmap_mft_record(dir_ni);
-                       return mref;
-               }
-               /*
-                * Not a perfect match, need to do full blown collation so we
-                * know which way in the B+tree we have to go.
-                */
-               rc = ntfs_collate_names(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length, 1,
-                               IGNORE_CASE, vol->upcase, vol->upcase_len);
-               /*
-                * If uname collates before the name of the current entry, there
-                * is definitely no such name in this index but we might need to
-                * descend into the B+tree so we just break out of the loop.
-                */
-               if (rc == -1)
-                       break;
-               /* The names are not equal, continue the search. */
-               if (rc)
-                       continue;
-               /*
-                * Names match with case insensitive comparison, now try the
-                * case sensitive comparison, which is required for proper
-                * collation.
-                */
-               rc = ntfs_collate_names(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length, 1,
-                               CASE_SENSITIVE, vol->upcase, vol->upcase_len);
-               if (rc == -1)
-                       break;
-               if (rc)
-                       continue;
-               /*
-                * Perfect match, this will never happen as the
-                * ntfs_are_names_equal() call will have gotten a match but we
-                * still treat it correctly.
-                */
-               goto found_it;
-       }
-       /*
-        * We have finished with this index without success. Check for the
-        * presence of a child node.
-        */
-       if (!(ie->flags & INDEX_ENTRY_NODE)) {
-               /* No child node, return -ENOENT. */
-               err = -ENOENT;
-               goto err_out;
-       } /* Child node present, descend into it. */
-       /* Consistency check: Verify that an index allocation exists. */
-       if (!NInoIndexAllocPresent(dir_ni)) {
-               ntfs_error(sb, "No index allocation attribute but index entry "
-                               "requires one. Directory inode 0x%lx is "
-                               "corrupt or driver bug.", dir_ni->mft_no);
-               goto err_out;
-       }
-       /* Get the starting vcn of the index_block holding the child node. */
-       vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
-       ia_mapping = VFS_I(dir_ni)->i_mapping;
-       /*
-        * We are done with the index root and the mft record. Release them,
-        * otherwise we deadlock with ntfs_map_page().
-        */
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(dir_ni);
-       m = NULL;
-       ctx = NULL;
-descend_into_child_node:
-       /*
-        * Convert vcn to index into the index allocation attribute in units
-        * of PAGE_SIZE and map the page cache page, reading it from
-        * disk if necessary.
-        */
-       page = ntfs_map_page(ia_mapping, vcn <<
-                       dir_ni->itype.index.vcn_size_bits >> PAGE_SHIFT);
-       if (IS_ERR(page)) {
-               ntfs_error(sb, "Failed to map directory index page, error %ld.",
-                               -PTR_ERR(page));
-               err = PTR_ERR(page);
-               goto err_out;
-       }
-       lock_page(page);
-       kaddr = (u8*)page_address(page);
-fast_descend_into_child_node:
-       /* Get to the index allocation block. */
-       ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
-                       dir_ni->itype.index.vcn_size_bits) & ~PAGE_MASK));
-       /* Bounds checks. */
-       if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) {
-               ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
-                               "inode 0x%lx or driver bug.", dir_ni->mft_no);
-               goto unm_err_out;
-       }
-       /* Catch multi sector transfer fixup errors. */
-       if (unlikely(!ntfs_is_indx_record(ia->magic))) {
-               ntfs_error(sb, "Directory index record with vcn 0x%llx is "
-                               "corrupt.  Corrupt inode 0x%lx.  Run chkdsk.",
-                               (unsigned long long)vcn, dir_ni->mft_no);
-               goto unm_err_out;
-       }
-       if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
-               ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
-                               "different from expected VCN (0x%llx). "
-                               "Directory inode 0x%lx is corrupt or driver "
-                               "bug.", (unsigned long long)
-                               sle64_to_cpu(ia->index_block_vcn),
-                               (unsigned long long)vcn, dir_ni->mft_no);
-               goto unm_err_out;
-       }
-       if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
-                       dir_ni->itype.index.block_size) {
-               ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
-                               "0x%lx has a size (%u) differing from the "
-                               "directory specified size (%u). Directory "
-                               "inode is corrupt or driver bug.",
-                               (unsigned long long)vcn, dir_ni->mft_no,
-                               le32_to_cpu(ia->index.allocated_size) + 0x18,
-                               dir_ni->itype.index.block_size);
-               goto unm_err_out;
-       }
-       index_end = (u8*)ia + dir_ni->itype.index.block_size;
-       if (index_end > kaddr + PAGE_SIZE) {
-               ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
-                               "0x%lx crosses page boundary. Impossible! "
-                               "Cannot access! This is probably a bug in the "
-                               "driver.", (unsigned long long)vcn,
-                               dir_ni->mft_no);
-               goto unm_err_out;
-       }
-       index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
-       if (index_end > (u8*)ia + dir_ni->itype.index.block_size) {
-               ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
-                               "inode 0x%lx exceeds maximum size.",
-                               (unsigned long long)vcn, dir_ni->mft_no);
-               goto unm_err_out;
-       }
-       /* The first index entry. */
-       ie = (INDEX_ENTRY*)((u8*)&ia->index +
-                       le32_to_cpu(ia->index.entries_offset));
-       /*
-        * Iterate similar to above big loop but applied to index buffer, thus
-        * loop until we exceed valid memory (corruption case) or until we
-        * reach the last entry.
-        */
-       for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
-               /* Bounds check. */
-               if ((u8*)ie < (u8*)ia || (u8*)ie +
-                               sizeof(INDEX_ENTRY_HEADER) > index_end ||
-                               (u8*)ie + le16_to_cpu(ie->key_length) >
-                               index_end) {
-                       ntfs_error(sb, "Index entry out of bounds in "
-                                       "directory inode 0x%lx.",
-                                       dir_ni->mft_no);
-                       goto unm_err_out;
-               }
-               /*
-                * The last entry cannot contain a name. It can however contain
-                * a pointer to a child node in the B+tree so we just break out.
-                */
-               if (ie->flags & INDEX_ENTRY_END)
-                       break;
-               /*
-                * If the current entry has a name type of POSIX, the name is
-                * case sensitive and not otherwise. This has the effect of us
-                * not being able to access any POSIX file names which collate
-                * after the non-POSIX one when they only differ in case, but
-                * anyone doing screwy stuff like that deserves to burn in
-                * hell... Doing that kind of stuff on NT4 actually causes
-                * corruption on the partition even when using SP6a and Linux
-                * is not involved at all.
-                */
-               ic = ie->key.file_name.file_name_type ? IGNORE_CASE :
-                               CASE_SENSITIVE;
-               /*
-                * If the names match perfectly, we are done and return the
-                * mft reference of the inode (i.e. the inode number together
-                * with the sequence number for consistency checking. We
-                * convert it to cpu format before returning.
-                */
-               if (ntfs_are_names_equal(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length, ic,
-                               vol->upcase, vol->upcase_len)) {
-found_it2:
-                       mref = le64_to_cpu(ie->data.dir.indexed_file);
-                       unlock_page(page);
-                       ntfs_unmap_page(page);
-                       return mref;
-               }
-               /*
-                * Not a perfect match, need to do full blown collation so we
-                * know which way in the B+tree we have to go.
-                */
-               rc = ntfs_collate_names(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length, 1,
-                               IGNORE_CASE, vol->upcase, vol->upcase_len);
-               /*
-                * If uname collates before the name of the current entry, there
-                * is definitely no such name in this index but we might need to
-                * descend into the B+tree so we just break out of the loop.
-                */
-               if (rc == -1)
-                       break;
-               /* The names are not equal, continue the search. */
-               if (rc)
-                       continue;
-               /*
-                * Names match with case insensitive comparison, now try the
-                * case sensitive comparison, which is required for proper
-                * collation.
-                */
-               rc = ntfs_collate_names(uname, uname_len,
-                               (ntfschar*)&ie->key.file_name.file_name,
-                               ie->key.file_name.file_name_length, 1,
-                               CASE_SENSITIVE, vol->upcase, vol->upcase_len);
-               if (rc == -1)
-                       break;
-               if (rc)
-                       continue;
-               /*
-                * Perfect match, this will never happen as the
-                * ntfs_are_names_equal() call will have gotten a match but we
-                * still treat it correctly.
-                */
-               goto found_it2;
-       }
-       /*
-        * We have finished with this index buffer without success. Check for
-        * the presence of a child node.
-        */
-       if (ie->flags & INDEX_ENTRY_NODE) {
-               if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
-                       ntfs_error(sb, "Index entry with child node found in "
-                                       "a leaf node in directory inode 0x%lx.",
-                                       dir_ni->mft_no);
-                       goto unm_err_out;
-               }
-               /* Child node present, descend into it. */
-               old_vcn = vcn;
-               vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
-               if (vcn >= 0) {
-                       /* If vcn is in the same page cache page as old_vcn we
-                        * recycle the mapped page. */
-                       if (old_vcn << vol->cluster_size_bits >>
-                                       PAGE_SHIFT == vcn <<
-                                       vol->cluster_size_bits >>
-                                       PAGE_SHIFT)
-                               goto fast_descend_into_child_node;
-                       unlock_page(page);
-                       ntfs_unmap_page(page);
-                       goto descend_into_child_node;
-               }
-               ntfs_error(sb, "Negative child node vcn in directory inode "
-                               "0x%lx.", dir_ni->mft_no);
-               goto unm_err_out;
-       }
-       /* No child node, return -ENOENT. */
-       ntfs_debug("Entry not found.");
-       err = -ENOENT;
-unm_err_out:
-       unlock_page(page);
-       ntfs_unmap_page(page);
-err_out:
-       if (!err)
-               err = -EIO;
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(dir_ni);
-       return ERR_MREF(err);
-dir_err_out:
-       ntfs_error(sb, "Corrupt directory. Aborting lookup.");
-       goto err_out;
-}
-
-#endif
-
-/**
- * ntfs_filldir - ntfs specific filldir method
- * @vol:       current ntfs volume
- * @ndir:      ntfs inode of current directory
- * @ia_page:   page in which the index allocation buffer @ie is in resides
- * @ie:                current index entry
- * @name:      buffer to use for the converted name
- * @actor:     what to feed the entries to
- *
- * Convert the Unicode @name to the loaded NLS and pass it to the @filldir
- * callback.
- *
- * If @ia_page is not NULL it is the locked page containing the index
- * allocation block containing the index entry @ie.
- *
- * Note, we drop (and then reacquire) the page lock on @ia_page across the
- * @filldir() call otherwise we would deadlock with NFSd when it calls ->lookup
- * since ntfs_lookup() will lock the same page.  As an optimization, we do not
- * retake the lock if we are returning a non-zero value as ntfs_readdir()
- * would need to drop the lock immediately anyway.
- */
-static inline int ntfs_filldir(ntfs_volume *vol,
-               ntfs_inode *ndir, struct page *ia_page, INDEX_ENTRY *ie,
-               u8 *name, struct dir_context *actor)
-{
-       unsigned long mref;
-       int name_len;
-       unsigned dt_type;
-       FILE_NAME_TYPE_FLAGS name_type;
-
-       name_type = ie->key.file_name.file_name_type;
-       if (name_type == FILE_NAME_DOS) {
-               ntfs_debug("Skipping DOS name space entry.");
-               return 0;
-       }
-       if (MREF_LE(ie->data.dir.indexed_file) == FILE_root) {
-               ntfs_debug("Skipping root directory self reference entry.");
-               return 0;
-       }
-       if (MREF_LE(ie->data.dir.indexed_file) < FILE_first_user &&
-                       !NVolShowSystemFiles(vol)) {
-               ntfs_debug("Skipping system file.");
-               return 0;
-       }
-       name_len = ntfs_ucstonls(vol, (ntfschar*)&ie->key.file_name.file_name,
-                       ie->key.file_name.file_name_length, &name,
-                       NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1);
-       if (name_len <= 0) {
-               ntfs_warning(vol->sb, "Skipping unrepresentable inode 0x%llx.",
-                               (long long)MREF_LE(ie->data.dir.indexed_file));
-               return 0;
-       }
-       if (ie->key.file_name.file_attributes &
-                       FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT)
-               dt_type = DT_DIR;
-       else
-               dt_type = DT_REG;
-       mref = MREF_LE(ie->data.dir.indexed_file);
-       /*
-        * Drop the page lock otherwise we deadlock with NFS when it calls
-        * ->lookup since ntfs_lookup() will lock the same page.
-        */
-       if (ia_page)
-               unlock_page(ia_page);
-       ntfs_debug("Calling filldir for %s with len %i, fpos 0x%llx, inode "
-                       "0x%lx, DT_%s.", name, name_len, actor->pos, mref,
-                       dt_type == DT_DIR ? "DIR" : "REG");
-       if (!dir_emit(actor, name, name_len, mref, dt_type))
-               return 1;
-       /* Relock the page but not if we are aborting ->readdir. */
-       if (ia_page)
-               lock_page(ia_page);
-       return 0;
-}
-
-/*
- * We use the same basic approach as the old NTFS driver, i.e. we parse the
- * index root entries and then the index allocation entries that are marked
- * as in use in the index bitmap.
- *
- * While this will return the names in random order this doesn't matter for
- * ->readdir but OTOH results in a faster ->readdir.
- *
- * VFS calls ->readdir without BKL but with i_mutex held. This protects the VFS
- * parts (e.g. ->f_pos and ->i_size, and it also protects against directory
- * modifications).
- *
- * Locking:  - Caller must hold i_mutex on the directory.
- *          - Each page cache page in the index allocation mapping must be
- *            locked whilst being accessed otherwise we may find a corrupt
- *            page due to it being under ->writepage at the moment which
- *            applies the mst protection fixups before writing out and then
- *            removes them again after the write is complete after which it 
- *            unlocks the page.
- */
-static int ntfs_readdir(struct file *file, struct dir_context *actor)
-{
-       s64 ia_pos, ia_start, prev_ia_pos, bmp_pos;
-       loff_t i_size;
-       struct inode *bmp_vi, *vdir = file_inode(file);
-       struct super_block *sb = vdir->i_sb;
-       ntfs_inode *ndir = NTFS_I(vdir);
-       ntfs_volume *vol = NTFS_SB(sb);
-       MFT_RECORD *m;
-       INDEX_ROOT *ir = NULL;
-       INDEX_ENTRY *ie;
-       INDEX_ALLOCATION *ia;
-       u8 *name = NULL;
-       int rc, err, ir_pos, cur_bmp_pos;
-       struct address_space *ia_mapping, *bmp_mapping;
-       struct page *bmp_page = NULL, *ia_page = NULL;
-       u8 *kaddr, *bmp, *index_end;
-       ntfs_attr_search_ctx *ctx;
-
-       ntfs_debug("Entering for inode 0x%lx, fpos 0x%llx.",
-                       vdir->i_ino, actor->pos);
-       rc = err = 0;
-       /* Are we at end of dir yet? */
-       i_size = i_size_read(vdir);
-       if (actor->pos >= i_size + vol->mft_record_size)
-               return 0;
-       /* Emulate . and .. for all directories. */
-       if (!dir_emit_dots(file, actor))
-               return 0;
-       m = NULL;
-       ctx = NULL;
-       /*
-        * Allocate a buffer to store the current name being processed
-        * converted to format determined by current NLS.
-        */
-       name = kmalloc(NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1, GFP_NOFS);
-       if (unlikely(!name)) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       /* Are we jumping straight into the index allocation attribute? */
-       if (actor->pos >= vol->mft_record_size)
-               goto skip_index_root;
-       /* Get hold of the mft record for the directory. */
-       m = map_mft_record(ndir);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               m = NULL;
-               goto err_out;
-       }
-       ctx = ntfs_attr_get_search_ctx(ndir, m);
-       if (unlikely(!ctx)) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       /* Get the offset into the index root attribute. */
-       ir_pos = (s64)actor->pos;
-       /* Find the index root attribute in the mft record. */
-       err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
-                       0, ctx);
-       if (unlikely(err)) {
-               ntfs_error(sb, "Index root attribute missing in directory "
-                               "inode 0x%lx.", vdir->i_ino);
-               goto err_out;
-       }
-       /*
-        * Copy the index root attribute value to a buffer so that we can put
-        * the search context and unmap the mft record before calling the
-        * filldir() callback.  We need to do this because of NFSd which calls
-        * ->lookup() from its filldir callback() and this causes NTFS to
-        * deadlock as ntfs_lookup() maps the mft record of the directory and
-        * we have got it mapped here already.  The only solution is for us to
-        * unmap the mft record here so that a call to ntfs_lookup() is able to
-        * map the mft record without deadlocking.
-        */
-       rc = le32_to_cpu(ctx->attr->data.resident.value_length);
-       ir = kmalloc(rc, GFP_NOFS);
-       if (unlikely(!ir)) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       /* Copy the index root value (it has been verified in read_inode). */
-       memcpy(ir, (u8*)ctx->attr +
-                       le16_to_cpu(ctx->attr->data.resident.value_offset), rc);
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(ndir);
-       ctx = NULL;
-       m = NULL;
-       index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
-       /* The first index entry. */
-       ie = (INDEX_ENTRY*)((u8*)&ir->index +
-                       le32_to_cpu(ir->index.entries_offset));
-       /*
-        * Loop until we exceed valid memory (corruption case) or until we
-        * reach the last entry or until filldir tells us it has had enough
-        * or signals an error (both covered by the rc test).
-        */
-       for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
-               ntfs_debug("In index root, offset 0x%zx.", (u8*)ie - (u8*)ir);
-               /* Bounds checks. */
-               if (unlikely((u8*)ie < (u8*)ir || (u8*)ie +
-                               sizeof(INDEX_ENTRY_HEADER) > index_end ||
-                               (u8*)ie + le16_to_cpu(ie->key_length) >
-                               index_end))
-                       goto err_out;
-               /* The last entry cannot contain a name. */
-               if (ie->flags & INDEX_ENTRY_END)
-                       break;
-               /* Skip index root entry if continuing previous readdir. */
-               if (ir_pos > (u8*)ie - (u8*)ir)
-                       continue;
-               /* Advance the position even if going to skip the entry. */
-               actor->pos = (u8*)ie - (u8*)ir;
-               /* Submit the name to the filldir callback. */
-               rc = ntfs_filldir(vol, ndir, NULL, ie, name, actor);
-               if (rc) {
-                       kfree(ir);
-                       goto abort;
-               }
-       }
-       /* We are done with the index root and can free the buffer. */
-       kfree(ir);
-       ir = NULL;
-       /* If there is no index allocation attribute we are finished. */
-       if (!NInoIndexAllocPresent(ndir))
-               goto EOD;
-       /* Advance fpos to the beginning of the index allocation. */
-       actor->pos = vol->mft_record_size;
-skip_index_root:
-       kaddr = NULL;
-       prev_ia_pos = -1LL;
-       /* Get the offset into the index allocation attribute. */
-       ia_pos = (s64)actor->pos - vol->mft_record_size;
-       ia_mapping = vdir->i_mapping;
-       ntfs_debug("Inode 0x%lx, getting index bitmap.", vdir->i_ino);
-       bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4);
-       if (IS_ERR(bmp_vi)) {
-               ntfs_error(sb, "Failed to get bitmap attribute.");
-               err = PTR_ERR(bmp_vi);
-               goto err_out;
-       }
-       bmp_mapping = bmp_vi->i_mapping;
-       /* Get the starting bitmap bit position and sanity check it. */
-       bmp_pos = ia_pos >> ndir->itype.index.block_size_bits;
-       if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) {
-               ntfs_error(sb, "Current index allocation position exceeds "
-                               "index bitmap size.");
-               goto iput_err_out;
-       }
-       /* Get the starting bit position in the current bitmap page. */
-       cur_bmp_pos = bmp_pos & ((PAGE_SIZE * 8) - 1);
-       bmp_pos &= ~(u64)((PAGE_SIZE * 8) - 1);
-get_next_bmp_page:
-       ntfs_debug("Reading bitmap with page index 0x%llx, bit ofs 0x%llx",
-                       (unsigned long long)bmp_pos >> (3 + PAGE_SHIFT),
-                       (unsigned long long)bmp_pos &
-                       (unsigned long long)((PAGE_SIZE * 8) - 1));
-       bmp_page = ntfs_map_page(bmp_mapping,
-                       bmp_pos >> (3 + PAGE_SHIFT));
-       if (IS_ERR(bmp_page)) {
-               ntfs_error(sb, "Reading index bitmap failed.");
-               err = PTR_ERR(bmp_page);
-               bmp_page = NULL;
-               goto iput_err_out;
-       }
-       bmp = (u8*)page_address(bmp_page);
-       /* Find next index block in use. */
-       while (!(bmp[cur_bmp_pos >> 3] & (1 << (cur_bmp_pos & 7)))) {
-find_next_index_buffer:
-               cur_bmp_pos++;
-               /*
-                * If we have reached the end of the bitmap page, get the next
-                * page, and put away the old one.
-                */
-               if (unlikely((cur_bmp_pos >> 3) >= PAGE_SIZE)) {
-                       ntfs_unmap_page(bmp_page);
-                       bmp_pos += PAGE_SIZE * 8;
-                       cur_bmp_pos = 0;
-                       goto get_next_bmp_page;
-               }
-               /* If we have reached the end of the bitmap, we are done. */
-               if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= i_size))
-                       goto unm_EOD;
-               ia_pos = (bmp_pos + cur_bmp_pos) <<
-                               ndir->itype.index.block_size_bits;
-       }
-       ntfs_debug("Handling index buffer 0x%llx.",
-                       (unsigned long long)bmp_pos + cur_bmp_pos);
-       /* If the current index buffer is in the same page we reuse the page. */
-       if ((prev_ia_pos & (s64)PAGE_MASK) !=
-                       (ia_pos & (s64)PAGE_MASK)) {
-               prev_ia_pos = ia_pos;
-               if (likely(ia_page != NULL)) {
-                       unlock_page(ia_page);
-                       ntfs_unmap_page(ia_page);
-               }
-               /*
-                * Map the page cache page containing the current ia_pos,
-                * reading it from disk if necessary.
-                */
-               ia_page = ntfs_map_page(ia_mapping, ia_pos >> PAGE_SHIFT);
-               if (IS_ERR(ia_page)) {
-                       ntfs_error(sb, "Reading index allocation data failed.");
-                       err = PTR_ERR(ia_page);
-                       ia_page = NULL;
-                       goto err_out;
-               }
-               lock_page(ia_page);
-               kaddr = (u8*)page_address(ia_page);
-       }
-       /* Get the current index buffer. */
-       ia = (INDEX_ALLOCATION*)(kaddr + (ia_pos & ~PAGE_MASK &
-                                         ~(s64)(ndir->itype.index.block_size - 1)));
-       /* Bounds checks. */
-       if (unlikely((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE)) {
-               ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
-                               "inode 0x%lx or driver bug.", vdir->i_ino);
-               goto err_out;
-       }
-       /* Catch multi sector transfer fixup errors. */
-       if (unlikely(!ntfs_is_indx_record(ia->magic))) {
-               ntfs_error(sb, "Directory index record with vcn 0x%llx is "
-                               "corrupt.  Corrupt inode 0x%lx.  Run chkdsk.",
-                               (unsigned long long)ia_pos >>
-                               ndir->itype.index.vcn_size_bits, vdir->i_ino);
-               goto err_out;
-       }
-       if (unlikely(sle64_to_cpu(ia->index_block_vcn) != (ia_pos &
-                       ~(s64)(ndir->itype.index.block_size - 1)) >>
-                       ndir->itype.index.vcn_size_bits)) {
-               ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
-                               "different from expected VCN (0x%llx). "
-                               "Directory inode 0x%lx is corrupt or driver "
-                               "bug. ", (unsigned long long)
-                               sle64_to_cpu(ia->index_block_vcn),
-                               (unsigned long long)ia_pos >>
-                               ndir->itype.index.vcn_size_bits, vdir->i_ino);
-               goto err_out;
-       }
-       if (unlikely(le32_to_cpu(ia->index.allocated_size) + 0x18 !=
-                       ndir->itype.index.block_size)) {
-               ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
-                               "0x%lx has a size (%u) differing from the "
-                               "directory specified size (%u). Directory "
-                               "inode is corrupt or driver bug.",
-                               (unsigned long long)ia_pos >>
-                               ndir->itype.index.vcn_size_bits, vdir->i_ino,
-                               le32_to_cpu(ia->index.allocated_size) + 0x18,
-                               ndir->itype.index.block_size);
-               goto err_out;
-       }
-       index_end = (u8*)ia + ndir->itype.index.block_size;
-       if (unlikely(index_end > kaddr + PAGE_SIZE)) {
-               ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
-                               "0x%lx crosses page boundary. Impossible! "
-                               "Cannot access! This is probably a bug in the "
-                               "driver.", (unsigned long long)ia_pos >>
-                               ndir->itype.index.vcn_size_bits, vdir->i_ino);
-               goto err_out;
-       }
-       ia_start = ia_pos & ~(s64)(ndir->itype.index.block_size - 1);
-       index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
-       if (unlikely(index_end > (u8*)ia + ndir->itype.index.block_size)) {
-               ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
-                               "inode 0x%lx exceeds maximum size.",
-                               (unsigned long long)ia_pos >>
-                               ndir->itype.index.vcn_size_bits, vdir->i_ino);
-               goto err_out;
-       }
-       /* The first index entry in this index buffer. */
-       ie = (INDEX_ENTRY*)((u8*)&ia->index +
-                       le32_to_cpu(ia->index.entries_offset));
-       /*
-        * Loop until we exceed valid memory (corruption case) or until we
-        * reach the last entry or until filldir tells us it has had enough
-        * or signals an error (both covered by the rc test).
-        */
-       for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
-               ntfs_debug("In index allocation, offset 0x%llx.",
-                               (unsigned long long)ia_start +
-                               (unsigned long long)((u8*)ie - (u8*)ia));
-               /* Bounds checks. */
-               if (unlikely((u8*)ie < (u8*)ia || (u8*)ie +
-                               sizeof(INDEX_ENTRY_HEADER) > index_end ||
-                               (u8*)ie + le16_to_cpu(ie->key_length) >
-                               index_end))
-                       goto err_out;
-               /* The last entry cannot contain a name. */
-               if (ie->flags & INDEX_ENTRY_END)
-                       break;
-               /* Skip index block entry if continuing previous readdir. */
-               if (ia_pos - ia_start > (u8*)ie - (u8*)ia)
-                       continue;
-               /* Advance the position even if going to skip the entry. */
-               actor->pos = (u8*)ie - (u8*)ia +
-                               (sle64_to_cpu(ia->index_block_vcn) <<
-                               ndir->itype.index.vcn_size_bits) +
-                               vol->mft_record_size;
-               /*
-                * Submit the name to the @filldir callback.  Note,
-                * ntfs_filldir() drops the lock on @ia_page but it retakes it
-                * before returning, unless a non-zero value is returned in
-                * which case the page is left unlocked.
-                */
-               rc = ntfs_filldir(vol, ndir, ia_page, ie, name, actor);
-               if (rc) {
-                       /* @ia_page is already unlocked in this case. */
-                       ntfs_unmap_page(ia_page);
-                       ntfs_unmap_page(bmp_page);
-                       iput(bmp_vi);
-                       goto abort;
-               }
-       }
-       goto find_next_index_buffer;
-unm_EOD:
-       if (ia_page) {
-               unlock_page(ia_page);
-               ntfs_unmap_page(ia_page);
-       }
-       ntfs_unmap_page(bmp_page);
-       iput(bmp_vi);
-EOD:
-       /* We are finished, set fpos to EOD. */
-       actor->pos = i_size + vol->mft_record_size;
-abort:
-       kfree(name);
-       return 0;
-err_out:
-       if (bmp_page) {
-               ntfs_unmap_page(bmp_page);
-iput_err_out:
-               iput(bmp_vi);
-       }
-       if (ia_page) {
-               unlock_page(ia_page);
-               ntfs_unmap_page(ia_page);
-       }
-       kfree(ir);
-       kfree(name);
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(ndir);
-       if (!err)
-               err = -EIO;
-       ntfs_debug("Failed. Returning error code %i.", -err);
-       return err;
-}
-
-/**
- * ntfs_dir_open - called when an inode is about to be opened
- * @vi:                inode to be opened
- * @filp:      file structure describing the inode
- *
- * Limit directory size to the page cache limit on architectures where unsigned
- * long is 32-bits. This is the most we can do for now without overflowing the
- * page cache page index. Doing it this way means we don't run into problems
- * because of existing too large directories. It would be better to allow the
- * user to read the accessible part of the directory but I doubt very much
- * anyone is going to hit this check on a 32-bit architecture, so there is no
- * point in adding the extra complexity required to support this.
- *
- * On 64-bit architectures, the check is hopefully optimized away by the
- * compiler.
- */
-static int ntfs_dir_open(struct inode *vi, struct file *filp)
-{
-       if (sizeof(unsigned long) < 8) {
-               if (i_size_read(vi) > MAX_LFS_FILESIZE)
-                       return -EFBIG;
-       }
-       return 0;
-}
-
-#ifdef NTFS_RW
-
-/**
- * ntfs_dir_fsync - sync a directory to disk
- * @filp:      directory to be synced
- * @start:     offset in bytes of the beginning of data range to sync
- * @end:       offset in bytes of the end of data range (inclusive)
- * @datasync:  if non-zero only flush user data and not metadata
- *
- * Data integrity sync of a directory to disk.  Used for fsync, fdatasync, and
- * msync system calls.  This function is based on file.c::ntfs_file_fsync().
- *
- * Write the mft record and all associated extent mft records as well as the
- * $INDEX_ALLOCATION and $BITMAP attributes and then sync the block device.
- *
- * If @datasync is true, we do not wait on the inode(s) to be written out
- * but we always wait on the page cache pages to be written out.
- *
- * Note: In the past @filp could be NULL so we ignore it as we don't need it
- * anyway.
- *
- * Locking: Caller must hold i_mutex on the inode.
- *
- * TODO: We should probably also write all attribute/index inodes associated
- * with this inode but since we have no simple way of getting to them we ignore
- * this problem for now.  We do write the $BITMAP attribute if it is present
- * which is the important one for a directory so things are not too bad.
- */
-static int ntfs_dir_fsync(struct file *filp, loff_t start, loff_t end,
-                         int datasync)
-{
-       struct inode *bmp_vi, *vi = filp->f_mapping->host;
-       int err, ret;
-       ntfs_attr na;
-
-       ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
-
-       err = file_write_and_wait_range(filp, start, end);
-       if (err)
-               return err;
-       inode_lock(vi);
-
-       BUG_ON(!S_ISDIR(vi->i_mode));
-       /* If the bitmap attribute inode is in memory sync it, too. */
-       na.mft_no = vi->i_ino;
-       na.type = AT_BITMAP;
-       na.name = I30;
-       na.name_len = 4;
-       bmp_vi = ilookup5(vi->i_sb, vi->i_ino, ntfs_test_inode, &na);
-       if (bmp_vi) {
-               write_inode_now(bmp_vi, !datasync);
-               iput(bmp_vi);
-       }
-       ret = __ntfs_write_inode(vi, 1);
-       write_inode_now(vi, !datasync);
-       err = sync_blockdev(vi->i_sb->s_bdev);
-       if (unlikely(err && !ret))
-               ret = err;
-       if (likely(!ret))
-               ntfs_debug("Done.");
-       else
-               ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx.  Error "
-                               "%u.", datasync ? "data" : "", vi->i_ino, -ret);
-       inode_unlock(vi);
-       return ret;
-}
-
-#endif /* NTFS_RW */
-
-WRAP_DIR_ITER(ntfs_readdir) // FIXME!
-const struct file_operations ntfs_dir_ops = {
-       .llseek         = generic_file_llseek,  /* Seek inside directory. */
-       .read           = generic_read_dir,     /* Return -EISDIR. */
-       .iterate_shared = shared_ntfs_readdir,  /* Read directory contents. */
-#ifdef NTFS_RW
-       .fsync          = ntfs_dir_fsync,       /* Sync a directory to disk. */
-#endif /* NTFS_RW */
-       /*.ioctl        = ,*/                   /* Perform function on the
-                                                  mounted filesystem. */
-       .open           = ntfs_dir_open,        /* Open directory. */
-};
diff --git a/fs/ntfs/dir.h b/fs/ntfs/dir.h
deleted file mode 100644 (file)
index 0e32675..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * dir.h - Defines for directory handling in NTFS Linux kernel driver. Part of
- *        the Linux-NTFS project.
- *
- * Copyright (c) 2002-2004 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_DIR_H
-#define _LINUX_NTFS_DIR_H
-
-#include "layout.h"
-#include "inode.h"
-#include "types.h"
-
-/*
- * ntfs_name is used to return the file name to the caller of
- * ntfs_lookup_inode_by_name() in order for the caller (namei.c::ntfs_lookup())
- * to be able to deal with dcache aliasing issues.
- */
-typedef struct {
-       MFT_REF mref;
-       FILE_NAME_TYPE_FLAGS type;
-       u8 len;
-       ntfschar name[0];
-} __attribute__ ((__packed__)) ntfs_name;
-
-/* The little endian Unicode string $I30 as a global constant. */
-extern ntfschar I30[5];
-
-extern MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni,
-               const ntfschar *uname, const int uname_len, ntfs_name **res);
-
-#endif /* _LINUX_NTFS_FS_DIR_H */
diff --git a/fs/ntfs/endian.h b/fs/ntfs/endian.h
deleted file mode 100644 (file)
index f30c139..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * endian.h - Defines for endianness handling in NTFS Linux kernel driver.
- *           Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2004 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_ENDIAN_H
-#define _LINUX_NTFS_ENDIAN_H
-
-#include <asm/byteorder.h>
-#include "types.h"
-
-/*
- * Signed endianness conversion functions.
- */
-
-static inline s16 sle16_to_cpu(sle16 x)
-{
-       return le16_to_cpu((__force le16)x);
-}
-
-static inline s32 sle32_to_cpu(sle32 x)
-{
-       return le32_to_cpu((__force le32)x);
-}
-
-static inline s64 sle64_to_cpu(sle64 x)
-{
-       return le64_to_cpu((__force le64)x);
-}
-
-static inline s16 sle16_to_cpup(sle16 *x)
-{
-       return le16_to_cpu(*(__force le16*)x);
-}
-
-static inline s32 sle32_to_cpup(sle32 *x)
-{
-       return le32_to_cpu(*(__force le32*)x);
-}
-
-static inline s64 sle64_to_cpup(sle64 *x)
-{
-       return le64_to_cpu(*(__force le64*)x);
-}
-
-static inline sle16 cpu_to_sle16(s16 x)
-{
-       return (__force sle16)cpu_to_le16(x);
-}
-
-static inline sle32 cpu_to_sle32(s32 x)
-{
-       return (__force sle32)cpu_to_le32(x);
-}
-
-static inline sle64 cpu_to_sle64(s64 x)
-{
-       return (__force sle64)cpu_to_le64(x);
-}
-
-static inline sle16 cpu_to_sle16p(s16 *x)
-{
-       return (__force sle16)cpu_to_le16(*x);
-}
-
-static inline sle32 cpu_to_sle32p(s32 *x)
-{
-       return (__force sle32)cpu_to_le32(*x);
-}
-
-static inline sle64 cpu_to_sle64p(s64 *x)
-{
-       return (__force sle64)cpu_to_le64(*x);
-}
-
-#endif /* _LINUX_NTFS_ENDIAN_H */
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
deleted file mode 100644 (file)
index 297c0b9..0000000
+++ /dev/null
@@ -1,1997 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * file.c - NTFS kernel file operations.  Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2015 Anton Altaparmakov and Tuxera Inc.
- */
-
-#include <linux/blkdev.h>
-#include <linux/backing-dev.h>
-#include <linux/buffer_head.h>
-#include <linux/gfp.h>
-#include <linux/pagemap.h>
-#include <linux/pagevec.h>
-#include <linux/sched/signal.h>
-#include <linux/swap.h>
-#include <linux/uio.h>
-#include <linux/writeback.h>
-
-#include <asm/page.h>
-#include <linux/uaccess.h>
-
-#include "attrib.h"
-#include "bitmap.h"
-#include "inode.h"
-#include "debug.h"
-#include "lcnalloc.h"
-#include "malloc.h"
-#include "mft.h"
-#include "ntfs.h"
-
-/**
- * ntfs_file_open - called when an inode is about to be opened
- * @vi:                inode to be opened
- * @filp:      file structure describing the inode
- *
- * Limit file size to the page cache limit on architectures where unsigned long
- * is 32-bits. This is the most we can do for now without overflowing the page
- * cache page index. Doing it this way means we don't run into problems because
- * of existing too large files. It would be better to allow the user to read
- * the beginning of the file but I doubt very much anyone is going to hit this
- * check on a 32-bit architecture, so there is no point in adding the extra
- * complexity required to support this.
- *
- * On 64-bit architectures, the check is hopefully optimized away by the
- * compiler.
- *
- * After the check passes, just call generic_file_open() to do its work.
- */
-static int ntfs_file_open(struct inode *vi, struct file *filp)
-{
-       if (sizeof(unsigned long) < 8) {
-               if (i_size_read(vi) > MAX_LFS_FILESIZE)
-                       return -EOVERFLOW;
-       }
-       return generic_file_open(vi, filp);
-}
-
-#ifdef NTFS_RW
-
-/**
- * ntfs_attr_extend_initialized - extend the initialized size of an attribute
- * @ni:                        ntfs inode of the attribute to extend
- * @new_init_size:     requested new initialized size in bytes
- *
- * Extend the initialized size of an attribute described by the ntfs inode @ni
- * to @new_init_size bytes.  This involves zeroing any non-sparse space between
- * the old initialized size and @new_init_size both in the page cache and on
- * disk (if relevant complete pages are already uptodate in the page cache then
- * these are simply marked dirty).
- *
- * As a side-effect, the file size (vfs inode->i_size) may be incremented as,
- * in the resident attribute case, it is tied to the initialized size and, in
- * the non-resident attribute case, it may not fall below the initialized size.
- *
- * Note that if the attribute is resident, we do not need to touch the page
- * cache at all.  This is because if the page cache page is not uptodate we
- * bring it uptodate later, when doing the write to the mft record since we
- * then already have the page mapped.  And if the page is uptodate, the
- * non-initialized region will already have been zeroed when the page was
- * brought uptodate and the region may in fact already have been overwritten
- * with new data via mmap() based writes, so we cannot just zero it.  And since
- * POSIX specifies that the behaviour of resizing a file whilst it is mmap()ped
- * is unspecified, we choose not to do zeroing and thus we do not need to touch
- * the page at all.  For a more detailed explanation see ntfs_truncate() in
- * fs/ntfs/inode.c.
- *
- * Return 0 on success and -errno on error.  In the case that an error is
- * encountered it is possible that the initialized size will already have been
- * incremented some way towards @new_init_size but it is guaranteed that if
- * this is the case, the necessary zeroing will also have happened and that all
- * metadata is self-consistent.
- *
- * Locking: i_mutex on the vfs inode corrseponsind to the ntfs inode @ni must be
- *         held by the caller.
- */
-static int ntfs_attr_extend_initialized(ntfs_inode *ni, const s64 new_init_size)
-{
-       s64 old_init_size;
-       loff_t old_i_size;
-       pgoff_t index, end_index;
-       unsigned long flags;
-       struct inode *vi = VFS_I(ni);
-       ntfs_inode *base_ni;
-       MFT_RECORD *m = NULL;
-       ATTR_RECORD *a;
-       ntfs_attr_search_ctx *ctx = NULL;
-       struct address_space *mapping;
-       struct page *page = NULL;
-       u8 *kattr;
-       int err;
-       u32 attr_len;
-
-       read_lock_irqsave(&ni->size_lock, flags);
-       old_init_size = ni->initialized_size;
-       old_i_size = i_size_read(vi);
-       BUG_ON(new_init_size > ni->allocated_size);
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, "
-                       "old_initialized_size 0x%llx, "
-                       "new_initialized_size 0x%llx, i_size 0x%llx.",
-                       vi->i_ino, (unsigned)le32_to_cpu(ni->type),
-                       (unsigned long long)old_init_size,
-                       (unsigned long long)new_init_size, old_i_size);
-       if (!NInoAttr(ni))
-               base_ni = ni;
-       else
-               base_ni = ni->ext.base_ntfs_ino;
-       /* Use goto to reduce indentation and we need the label below anyway. */
-       if (NInoNonResident(ni))
-               goto do_non_resident_extend;
-       BUG_ON(old_init_size != old_i_size);
-       m = map_mft_record(base_ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               m = NULL;
-               goto err_out;
-       }
-       ctx = ntfs_attr_get_search_ctx(base_ni, m);
-       if (unlikely(!ctx)) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err)) {
-               if (err == -ENOENT)
-                       err = -EIO;
-               goto err_out;
-       }
-       m = ctx->mrec;
-       a = ctx->attr;
-       BUG_ON(a->non_resident);
-       /* The total length of the attribute value. */
-       attr_len = le32_to_cpu(a->data.resident.value_length);
-       BUG_ON(old_i_size != (loff_t)attr_len);
-       /*
-        * Do the zeroing in the mft record and update the attribute size in
-        * the mft record.
-        */
-       kattr = (u8*)a + le16_to_cpu(a->data.resident.value_offset);
-       memset(kattr + attr_len, 0, new_init_size - attr_len);
-       a->data.resident.value_length = cpu_to_le32((u32)new_init_size);
-       /* Finally, update the sizes in the vfs and ntfs inodes. */
-       write_lock_irqsave(&ni->size_lock, flags);
-       i_size_write(vi, new_init_size);
-       ni->initialized_size = new_init_size;
-       write_unlock_irqrestore(&ni->size_lock, flags);
-       goto done;
-do_non_resident_extend:
-       /*
-        * If the new initialized size @new_init_size exceeds the current file
-        * size (vfs inode->i_size), we need to extend the file size to the
-        * new initialized size.
-        */
-       if (new_init_size > old_i_size) {
-               m = map_mft_record(base_ni);
-               if (IS_ERR(m)) {
-                       err = PTR_ERR(m);
-                       m = NULL;
-                       goto err_out;
-               }
-               ctx = ntfs_attr_get_search_ctx(base_ni, m);
-               if (unlikely(!ctx)) {
-                       err = -ENOMEM;
-                       goto err_out;
-               }
-               err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                               CASE_SENSITIVE, 0, NULL, 0, ctx);
-               if (unlikely(err)) {
-                       if (err == -ENOENT)
-                               err = -EIO;
-                       goto err_out;
-               }
-               m = ctx->mrec;
-               a = ctx->attr;
-               BUG_ON(!a->non_resident);
-               BUG_ON(old_i_size != (loff_t)
-                               sle64_to_cpu(a->data.non_resident.data_size));
-               a->data.non_resident.data_size = cpu_to_sle64(new_init_size);
-               flush_dcache_mft_record_page(ctx->ntfs_ino);
-               mark_mft_record_dirty(ctx->ntfs_ino);
-               /* Update the file size in the vfs inode. */
-               i_size_write(vi, new_init_size);
-               ntfs_attr_put_search_ctx(ctx);
-               ctx = NULL;
-               unmap_mft_record(base_ni);
-               m = NULL;
-       }
-       mapping = vi->i_mapping;
-       index = old_init_size >> PAGE_SHIFT;
-       end_index = (new_init_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       do {
-               /*
-                * Read the page.  If the page is not present, this will zero
-                * the uninitialized regions for us.
-                */
-               page = read_mapping_page(mapping, index, NULL);
-               if (IS_ERR(page)) {
-                       err = PTR_ERR(page);
-                       goto init_err_out;
-               }
-               /*
-                * Update the initialized size in the ntfs inode.  This is
-                * enough to make ntfs_writepage() work.
-                */
-               write_lock_irqsave(&ni->size_lock, flags);
-               ni->initialized_size = (s64)(index + 1) << PAGE_SHIFT;
-               if (ni->initialized_size > new_init_size)
-                       ni->initialized_size = new_init_size;
-               write_unlock_irqrestore(&ni->size_lock, flags);
-               /* Set the page dirty so it gets written out. */
-               set_page_dirty(page);
-               put_page(page);
-               /*
-                * Play nice with the vm and the rest of the system.  This is
-                * very much needed as we can potentially be modifying the
-                * initialised size from a very small value to a really huge
-                * value, e.g.
-                *      f = open(somefile, O_TRUNC);
-                *      truncate(f, 10GiB);
-                *      seek(f, 10GiB);
-                *      write(f, 1);
-                * And this would mean we would be marking dirty hundreds of
-                * thousands of pages or as in the above example more than
-                * two and a half million pages!
-                *
-                * TODO: For sparse pages could optimize this workload by using
-                * the FsMisc / MiscFs page bit as a "PageIsSparse" bit.  This
-                * would be set in read_folio for sparse pages and here we would
-                * not need to mark dirty any pages which have this bit set.
-                * The only caveat is that we have to clear the bit everywhere
-                * where we allocate any clusters that lie in the page or that
-                * contain the page.
-                *
-                * TODO: An even greater optimization would be for us to only
-                * call read_folio() on pages which are not in sparse regions as
-                * determined from the runlist.  This would greatly reduce the
-                * number of pages we read and make dirty in the case of sparse
-                * files.
-                */
-               balance_dirty_pages_ratelimited(mapping);
-               cond_resched();
-       } while (++index < end_index);
-       read_lock_irqsave(&ni->size_lock, flags);
-       BUG_ON(ni->initialized_size != new_init_size);
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       /* Now bring in sync the initialized_size in the mft record. */
-       m = map_mft_record(base_ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               m = NULL;
-               goto init_err_out;
-       }
-       ctx = ntfs_attr_get_search_ctx(base_ni, m);
-       if (unlikely(!ctx)) {
-               err = -ENOMEM;
-               goto init_err_out;
-       }
-       err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err)) {
-               if (err == -ENOENT)
-                       err = -EIO;
-               goto init_err_out;
-       }
-       m = ctx->mrec;
-       a = ctx->attr;
-       BUG_ON(!a->non_resident);
-       a->data.non_resident.initialized_size = cpu_to_sle64(new_init_size);
-done:
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(base_ni);
-       ntfs_debug("Done, initialized_size 0x%llx, i_size 0x%llx.",
-                       (unsigned long long)new_init_size, i_size_read(vi));
-       return 0;
-init_err_out:
-       write_lock_irqsave(&ni->size_lock, flags);
-       ni->initialized_size = old_init_size;
-       write_unlock_irqrestore(&ni->size_lock, flags);
-err_out:
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(base_ni);
-       ntfs_debug("Failed.  Returning error code %i.", err);
-       return err;
-}
-
-static ssize_t ntfs_prepare_file_for_write(struct kiocb *iocb,
-               struct iov_iter *from)
-{
-       loff_t pos;
-       s64 end, ll;
-       ssize_t err;
-       unsigned long flags;
-       struct file *file = iocb->ki_filp;
-       struct inode *vi = file_inode(file);
-       ntfs_inode *ni = NTFS_I(vi);
-       ntfs_volume *vol = ni->vol;
-
-       ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, pos "
-                       "0x%llx, count 0x%zx.", vi->i_ino,
-                       (unsigned)le32_to_cpu(ni->type),
-                       (unsigned long long)iocb->ki_pos,
-                       iov_iter_count(from));
-       err = generic_write_checks(iocb, from);
-       if (unlikely(err <= 0))
-               goto out;
-       /*
-        * All checks have passed.  Before we start doing any writing we want
-        * to abort any totally illegal writes.
-        */
-       BUG_ON(NInoMstProtected(ni));
-       BUG_ON(ni->type != AT_DATA);
-       /* If file is encrypted, deny access, just like NT4. */
-       if (NInoEncrypted(ni)) {
-               /* Only $DATA attributes can be encrypted. */
-               /*
-                * Reminder for later: Encrypted files are _always_
-                * non-resident so that the content can always be encrypted.
-                */
-               ntfs_debug("Denying write access to encrypted file.");
-               err = -EACCES;
-               goto out;
-       }
-       if (NInoCompressed(ni)) {
-               /* Only unnamed $DATA attribute can be compressed. */
-               BUG_ON(ni->name_len);
-               /*
-                * Reminder for later: If resident, the data is not actually
-                * compressed.  Only on the switch to non-resident does
-                * compression kick in.  This is in contrast to encrypted files
-                * (see above).
-                */
-               ntfs_error(vi->i_sb, "Writing to compressed files is not "
-                               "implemented yet.  Sorry.");
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-       err = file_remove_privs(file);
-       if (unlikely(err))
-               goto out;
-       /*
-        * Our ->update_time method always succeeds thus file_update_time()
-        * cannot fail either so there is no need to check the return code.
-        */
-       file_update_time(file);
-       pos = iocb->ki_pos;
-       /* The first byte after the last cluster being written to. */
-       end = (pos + iov_iter_count(from) + vol->cluster_size_mask) &
-                       ~(u64)vol->cluster_size_mask;
-       /*
-        * If the write goes beyond the allocated size, extend the allocation
-        * to cover the whole of the write, rounded up to the nearest cluster.
-        */
-       read_lock_irqsave(&ni->size_lock, flags);
-       ll = ni->allocated_size;
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       if (end > ll) {
-               /*
-                * Extend the allocation without changing the data size.
-                *
-                * Note we ensure the allocation is big enough to at least
-                * write some data but we do not require the allocation to be
-                * complete, i.e. it may be partial.
-                */
-               ll = ntfs_attr_extend_allocation(ni, end, -1, pos);
-               if (likely(ll >= 0)) {
-                       BUG_ON(pos >= ll);
-                       /* If the extension was partial truncate the write. */
-                       if (end > ll) {
-                               ntfs_debug("Truncating write to inode 0x%lx, "
-                                               "attribute type 0x%x, because "
-                                               "the allocation was only "
-                                               "partially extended.",
-                                               vi->i_ino, (unsigned)
-                                               le32_to_cpu(ni->type));
-                               iov_iter_truncate(from, ll - pos);
-                       }
-               } else {
-                       err = ll;
-                       read_lock_irqsave(&ni->size_lock, flags);
-                       ll = ni->allocated_size;
-                       read_unlock_irqrestore(&ni->size_lock, flags);
-                       /* Perform a partial write if possible or fail. */
-                       if (pos < ll) {
-                               ntfs_debug("Truncating write to inode 0x%lx "
-                                               "attribute type 0x%x, because "
-                                               "extending the allocation "
-                                               "failed (error %d).",
-                                               vi->i_ino, (unsigned)
-                                               le32_to_cpu(ni->type),
-                                               (int)-err);
-                               iov_iter_truncate(from, ll - pos);
-                       } else {
-                               if (err != -ENOSPC)
-                                       ntfs_error(vi->i_sb, "Cannot perform "
-                                                       "write to inode "
-                                                       "0x%lx, attribute "
-                                                       "type 0x%x, because "
-                                                       "extending the "
-                                                       "allocation failed "
-                                                       "(error %ld).",
-                                                       vi->i_ino, (unsigned)
-                                                       le32_to_cpu(ni->type),
-                                                       (long)-err);
-                               else
-                                       ntfs_debug("Cannot perform write to "
-                                                       "inode 0x%lx, "
-                                                       "attribute type 0x%x, "
-                                                       "because there is not "
-                                                       "space left.",
-                                                       vi->i_ino, (unsigned)
-                                                       le32_to_cpu(ni->type));
-                               goto out;
-                       }
-               }
-       }
-       /*
-        * If the write starts beyond the initialized size, extend it up to the
-        * beginning of the write and initialize all non-sparse space between
-        * the old initialized size and the new one.  This automatically also
-        * increments the vfs inode->i_size to keep it above or equal to the
-        * initialized_size.
-        */
-       read_lock_irqsave(&ni->size_lock, flags);
-       ll = ni->initialized_size;
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       if (pos > ll) {
-               /*
-                * Wait for ongoing direct i/o to complete before proceeding.
-                * New direct i/o cannot start as we hold i_mutex.
-                */
-               inode_dio_wait(vi);
-               err = ntfs_attr_extend_initialized(ni, pos);
-               if (unlikely(err < 0))
-                       ntfs_error(vi->i_sb, "Cannot perform write to inode "
-                                       "0x%lx, attribute type 0x%x, because "
-                                       "extending the initialized size "
-                                       "failed (error %d).", vi->i_ino,
-                                       (unsigned)le32_to_cpu(ni->type),
-                                       (int)-err);
-       }
-out:
-       return err;
-}
-
-/**
- * __ntfs_grab_cache_pages - obtain a number of locked pages
- * @mapping:   address space mapping from which to obtain page cache pages
- * @index:     starting index in @mapping at which to begin obtaining pages
- * @nr_pages:  number of page cache pages to obtain
- * @pages:     array of pages in which to return the obtained page cache pages
- * @cached_page: allocated but as yet unused page
- *
- * Obtain @nr_pages locked page cache pages from the mapping @mapping and
- * starting at index @index.
- *
- * If a page is newly created, add it to lru list
- *
- * Note, the page locks are obtained in ascending page index order.
- */
-static inline int __ntfs_grab_cache_pages(struct address_space *mapping,
-               pgoff_t index, const unsigned nr_pages, struct page **pages,
-               struct page **cached_page)
-{
-       int err, nr;
-
-       BUG_ON(!nr_pages);
-       err = nr = 0;
-       do {
-               pages[nr] = find_get_page_flags(mapping, index, FGP_LOCK |
-                               FGP_ACCESSED);
-               if (!pages[nr]) {
-                       if (!*cached_page) {
-                               *cached_page = page_cache_alloc(mapping);
-                               if (unlikely(!*cached_page)) {
-                                       err = -ENOMEM;
-                                       goto err_out;
-                               }
-                       }
-                       err = add_to_page_cache_lru(*cached_page, mapping,
-                                  index,
-                                  mapping_gfp_constraint(mapping, GFP_KERNEL));
-                       if (unlikely(err)) {
-                               if (err == -EEXIST)
-                                       continue;
-                               goto err_out;
-                       }
-                       pages[nr] = *cached_page;
-                       *cached_page = NULL;
-               }
-               index++;
-               nr++;
-       } while (nr < nr_pages);
-out:
-       return err;
-err_out:
-       while (nr > 0) {
-               unlock_page(pages[--nr]);
-               put_page(pages[nr]);
-       }
-       goto out;
-}
-
-static inline void ntfs_submit_bh_for_read(struct buffer_head *bh)
-{
-       lock_buffer(bh);
-       get_bh(bh);
-       bh->b_end_io = end_buffer_read_sync;
-       submit_bh(REQ_OP_READ, bh);
-}
-
-/**
- * ntfs_prepare_pages_for_non_resident_write - prepare pages for receiving data
- * @pages:     array of destination pages
- * @nr_pages:  number of pages in @pages
- * @pos:       byte position in file at which the write begins
- * @bytes:     number of bytes to be written
- *
- * This is called for non-resident attributes from ntfs_file_buffered_write()
- * with i_mutex held on the inode (@pages[0]->mapping->host).  There are
- * @nr_pages pages in @pages which are locked but not kmap()ped.  The source
- * data has not yet been copied into the @pages.
- * 
- * Need to fill any holes with actual clusters, allocate buffers if necessary,
- * ensure all the buffers are mapped, and bring uptodate any buffers that are
- * only partially being written to.
- *
- * If @nr_pages is greater than one, we are guaranteed that the cluster size is
- * greater than PAGE_SIZE, that all pages in @pages are entirely inside
- * the same cluster and that they are the entirety of that cluster, and that
- * the cluster is sparse, i.e. we need to allocate a cluster to fill the hole.
- *
- * i_size is not to be modified yet.
- *
- * Return 0 on success or -errno on error.
- */
-static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
-               unsigned nr_pages, s64 pos, size_t bytes)
-{
-       VCN vcn, highest_vcn = 0, cpos, cend, bh_cpos, bh_cend;
-       LCN lcn;
-       s64 bh_pos, vcn_len, end, initialized_size;
-       sector_t lcn_block;
-       struct folio *folio;
-       struct inode *vi;
-       ntfs_inode *ni, *base_ni = NULL;
-       ntfs_volume *vol;
-       runlist_element *rl, *rl2;
-       struct buffer_head *bh, *head, *wait[2], **wait_bh = wait;
-       ntfs_attr_search_ctx *ctx = NULL;
-       MFT_RECORD *m = NULL;
-       ATTR_RECORD *a = NULL;
-       unsigned long flags;
-       u32 attr_rec_len = 0;
-       unsigned blocksize, u;
-       int err, mp_size;
-       bool rl_write_locked, was_hole, is_retry;
-       unsigned char blocksize_bits;
-       struct {
-               u8 runlist_merged:1;
-               u8 mft_attr_mapped:1;
-               u8 mp_rebuilt:1;
-               u8 attr_switched:1;
-       } status = { 0, 0, 0, 0 };
-
-       BUG_ON(!nr_pages);
-       BUG_ON(!pages);
-       BUG_ON(!*pages);
-       vi = pages[0]->mapping->host;
-       ni = NTFS_I(vi);
-       vol = ni->vol;
-       ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, start page "
-                       "index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%zx.",
-                       vi->i_ino, ni->type, pages[0]->index, nr_pages,
-                       (long long)pos, bytes);
-       blocksize = vol->sb->s_blocksize;
-       blocksize_bits = vol->sb->s_blocksize_bits;
-       rl_write_locked = false;
-       rl = NULL;
-       err = 0;
-       vcn = lcn = -1;
-       vcn_len = 0;
-       lcn_block = -1;
-       was_hole = false;
-       cpos = pos >> vol->cluster_size_bits;
-       end = pos + bytes;
-       cend = (end + vol->cluster_size - 1) >> vol->cluster_size_bits;
-       /*
-        * Loop over each buffer in each folio.  Use goto to
-        * reduce indentation.
-        */
-       u = 0;
-do_next_folio:
-       folio = page_folio(pages[u]);
-       bh_pos = folio_pos(folio);
-       head = folio_buffers(folio);
-       if (!head)
-               /*
-                * create_empty_buffers() will create uptodate/dirty
-                * buffers if the folio is uptodate/dirty.
-                */
-               head = create_empty_buffers(folio, blocksize, 0);
-       bh = head;
-       do {
-               VCN cdelta;
-               s64 bh_end;
-               unsigned bh_cofs;
-
-               /* Clear buffer_new on all buffers to reinitialise state. */
-               if (buffer_new(bh))
-                       clear_buffer_new(bh);
-               bh_end = bh_pos + blocksize;
-               bh_cpos = bh_pos >> vol->cluster_size_bits;
-               bh_cofs = bh_pos & vol->cluster_size_mask;
-               if (buffer_mapped(bh)) {
-                       /*
-                        * The buffer is already mapped.  If it is uptodate,
-                        * ignore it.
-                        */
-                       if (buffer_uptodate(bh))
-                               continue;
-                       /*
-                        * The buffer is not uptodate.  If the folio is uptodate
-                        * set the buffer uptodate and otherwise ignore it.
-                        */
-                       if (folio_test_uptodate(folio)) {
-                               set_buffer_uptodate(bh);
-                               continue;
-                       }
-                       /*
-                        * Neither the folio nor the buffer are uptodate.  If
-                        * the buffer is only partially being written to, we
-                        * need to read it in before the write, i.e. now.
-                        */
-                       if ((bh_pos < pos && bh_end > pos) ||
-                                       (bh_pos < end && bh_end > end)) {
-                               /*
-                                * If the buffer is fully or partially within
-                                * the initialized size, do an actual read.
-                                * Otherwise, simply zero the buffer.
-                                */
-                               read_lock_irqsave(&ni->size_lock, flags);
-                               initialized_size = ni->initialized_size;
-                               read_unlock_irqrestore(&ni->size_lock, flags);
-                               if (bh_pos < initialized_size) {
-                                       ntfs_submit_bh_for_read(bh);
-                                       *wait_bh++ = bh;
-                               } else {
-                                       folio_zero_range(folio, bh_offset(bh),
-                                                       blocksize);
-                                       set_buffer_uptodate(bh);
-                               }
-                       }
-                       continue;
-               }
-               /* Unmapped buffer.  Need to map it. */
-               bh->b_bdev = vol->sb->s_bdev;
-               /*
-                * If the current buffer is in the same clusters as the map
-                * cache, there is no need to check the runlist again.  The
-                * map cache is made up of @vcn, which is the first cached file
-                * cluster, @vcn_len which is the number of cached file
-                * clusters, @lcn is the device cluster corresponding to @vcn,
-                * and @lcn_block is the block number corresponding to @lcn.
-                */
-               cdelta = bh_cpos - vcn;
-               if (likely(!cdelta || (cdelta > 0 && cdelta < vcn_len))) {
-map_buffer_cached:
-                       BUG_ON(lcn < 0);
-                       bh->b_blocknr = lcn_block +
-                                       (cdelta << (vol->cluster_size_bits -
-                                       blocksize_bits)) +
-                                       (bh_cofs >> blocksize_bits);
-                       set_buffer_mapped(bh);
-                       /*
-                        * If the folio is uptodate so is the buffer.  If the
-                        * buffer is fully outside the write, we ignore it if
-                        * it was already allocated and we mark it dirty so it
-                        * gets written out if we allocated it.  On the other
-                        * hand, if we allocated the buffer but we are not
-                        * marking it dirty we set buffer_new so we can do
-                        * error recovery.
-                        */
-                       if (folio_test_uptodate(folio)) {
-                               if (!buffer_uptodate(bh))
-                                       set_buffer_uptodate(bh);
-                               if (unlikely(was_hole)) {
-                                       /* We allocated the buffer. */
-                                       clean_bdev_bh_alias(bh);
-                                       if (bh_end <= pos || bh_pos >= end)
-                                               mark_buffer_dirty(bh);
-                                       else
-                                               set_buffer_new(bh);
-                               }
-                               continue;
-                       }
-                       /* Page is _not_ uptodate. */
-                       if (likely(!was_hole)) {
-                               /*
-                                * Buffer was already allocated.  If it is not
-                                * uptodate and is only partially being written
-                                * to, we need to read it in before the write,
-                                * i.e. now.
-                                */
-                               if (!buffer_uptodate(bh) && bh_pos < end &&
-                                               bh_end > pos &&
-                                               (bh_pos < pos ||
-                                               bh_end > end)) {
-                                       /*
-                                        * If the buffer is fully or partially
-                                        * within the initialized size, do an
-                                        * actual read.  Otherwise, simply zero
-                                        * the buffer.
-                                        */
-                                       read_lock_irqsave(&ni->size_lock,
-                                                       flags);
-                                       initialized_size = ni->initialized_size;
-                                       read_unlock_irqrestore(&ni->size_lock,
-                                                       flags);
-                                       if (bh_pos < initialized_size) {
-                                               ntfs_submit_bh_for_read(bh);
-                                               *wait_bh++ = bh;
-                                       } else {
-                                               folio_zero_range(folio,
-                                                               bh_offset(bh),
-                                                               blocksize);
-                                               set_buffer_uptodate(bh);
-                                       }
-                               }
-                               continue;
-                       }
-                       /* We allocated the buffer. */
-                       clean_bdev_bh_alias(bh);
-                       /*
-                        * If the buffer is fully outside the write, zero it,
-                        * set it uptodate, and mark it dirty so it gets
-                        * written out.  If it is partially being written to,
-                        * zero region surrounding the write but leave it to
-                        * commit write to do anything else.  Finally, if the
-                        * buffer is fully being overwritten, do nothing.
-                        */
-                       if (bh_end <= pos || bh_pos >= end) {
-                               if (!buffer_uptodate(bh)) {
-                                       folio_zero_range(folio, bh_offset(bh),
-                                                       blocksize);
-                                       set_buffer_uptodate(bh);
-                               }
-                               mark_buffer_dirty(bh);
-                               continue;
-                       }
-                       set_buffer_new(bh);
-                       if (!buffer_uptodate(bh) &&
-                                       (bh_pos < pos || bh_end > end)) {
-                               u8 *kaddr;
-                               unsigned pofs;
-                                       
-                               kaddr = kmap_local_folio(folio, 0);
-                               if (bh_pos < pos) {
-                                       pofs = bh_pos & ~PAGE_MASK;
-                                       memset(kaddr + pofs, 0, pos - bh_pos);
-                               }
-                               if (bh_end > end) {
-                                       pofs = end & ~PAGE_MASK;
-                                       memset(kaddr + pofs, 0, bh_end - end);
-                               }
-                               kunmap_local(kaddr);
-                               flush_dcache_folio(folio);
-                       }
-                       continue;
-               }
-               /*
-                * Slow path: this is the first buffer in the cluster.  If it
-                * is outside allocated size and is not uptodate, zero it and
-                * set it uptodate.
-                */
-               read_lock_irqsave(&ni->size_lock, flags);
-               initialized_size = ni->allocated_size;
-               read_unlock_irqrestore(&ni->size_lock, flags);
-               if (bh_pos > initialized_size) {
-                       if (folio_test_uptodate(folio)) {
-                               if (!buffer_uptodate(bh))
-                                       set_buffer_uptodate(bh);
-                       } else if (!buffer_uptodate(bh)) {
-                               folio_zero_range(folio, bh_offset(bh),
-                                               blocksize);
-                               set_buffer_uptodate(bh);
-                       }
-                       continue;
-               }
-               is_retry = false;
-               if (!rl) {
-                       down_read(&ni->runlist.lock);
-retry_remap:
-                       rl = ni->runlist.rl;
-               }
-               if (likely(rl != NULL)) {
-                       /* Seek to element containing target cluster. */
-                       while (rl->length && rl[1].vcn <= bh_cpos)
-                               rl++;
-                       lcn = ntfs_rl_vcn_to_lcn(rl, bh_cpos);
-                       if (likely(lcn >= 0)) {
-                               /*
-                                * Successful remap, setup the map cache and
-                                * use that to deal with the buffer.
-                                */
-                               was_hole = false;
-                               vcn = bh_cpos;
-                               vcn_len = rl[1].vcn - vcn;
-                               lcn_block = lcn << (vol->cluster_size_bits -
-                                               blocksize_bits);
-                               cdelta = 0;
-                               /*
-                                * If the number of remaining clusters touched
-                                * by the write is smaller or equal to the
-                                * number of cached clusters, unlock the
-                                * runlist as the map cache will be used from
-                                * now on.
-                                */
-                               if (likely(vcn + vcn_len >= cend)) {
-                                       if (rl_write_locked) {
-                                               up_write(&ni->runlist.lock);
-                                               rl_write_locked = false;
-                                       } else
-                                               up_read(&ni->runlist.lock);
-                                       rl = NULL;
-                               }
-                               goto map_buffer_cached;
-                       }
-               } else
-                       lcn = LCN_RL_NOT_MAPPED;
-               /*
-                * If it is not a hole and not out of bounds, the runlist is
-                * probably unmapped so try to map it now.
-                */
-               if (unlikely(lcn != LCN_HOLE && lcn != LCN_ENOENT)) {
-                       if (likely(!is_retry && lcn == LCN_RL_NOT_MAPPED)) {
-                               /* Attempt to map runlist. */
-                               if (!rl_write_locked) {
-                                       /*
-                                        * We need the runlist locked for
-                                        * writing, so if it is locked for
-                                        * reading relock it now and retry in
-                                        * case it changed whilst we dropped
-                                        * the lock.
-                                        */
-                                       up_read(&ni->runlist.lock);
-                                       down_write(&ni->runlist.lock);
-                                       rl_write_locked = true;
-                                       goto retry_remap;
-                               }
-                               err = ntfs_map_runlist_nolock(ni, bh_cpos,
-                                               NULL);
-                               if (likely(!err)) {
-                                       is_retry = true;
-                                       goto retry_remap;
-                               }
-                               /*
-                                * If @vcn is out of bounds, pretend @lcn is
-                                * LCN_ENOENT.  As long as the buffer is out
-                                * of bounds this will work fine.
-                                */
-                               if (err == -ENOENT) {
-                                       lcn = LCN_ENOENT;
-                                       err = 0;
-                                       goto rl_not_mapped_enoent;
-                               }
-                       } else
-                               err = -EIO;
-                       /* Failed to map the buffer, even after retrying. */
-                       bh->b_blocknr = -1;
-                       ntfs_error(vol->sb, "Failed to write to inode 0x%lx, "
-                                       "attribute type 0x%x, vcn 0x%llx, "
-                                       "vcn offset 0x%x, because its "
-                                       "location on disk could not be "
-                                       "determined%s (error code %i).",
-                                       ni->mft_no, ni->type,
-                                       (unsigned long long)bh_cpos,
-                                       (unsigned)bh_pos &
-                                       vol->cluster_size_mask,
-                                       is_retry ? " even after retrying" : "",
-                                       err);
-                       break;
-               }
-rl_not_mapped_enoent:
-               /*
-                * The buffer is in a hole or out of bounds.  We need to fill
-                * the hole, unless the buffer is in a cluster which is not
-                * touched by the write, in which case we just leave the buffer
-                * unmapped.  This can only happen when the cluster size is
-                * less than the page cache size.
-                */
-               if (unlikely(vol->cluster_size < PAGE_SIZE)) {
-                       bh_cend = (bh_end + vol->cluster_size - 1) >>
-                                       vol->cluster_size_bits;
-                       if ((bh_cend <= cpos || bh_cpos >= cend)) {
-                               bh->b_blocknr = -1;
-                               /*
-                                * If the buffer is uptodate we skip it.  If it
-                                * is not but the folio is uptodate, we can set
-                                * the buffer uptodate.  If the folio is not
-                                * uptodate, we can clear the buffer and set it
-                                * uptodate.  Whether this is worthwhile is
-                                * debatable and this could be removed.
-                                */
-                               if (folio_test_uptodate(folio)) {
-                                       if (!buffer_uptodate(bh))
-                                               set_buffer_uptodate(bh);
-                               } else if (!buffer_uptodate(bh)) {
-                                       folio_zero_range(folio, bh_offset(bh),
-                                               blocksize);
-                                       set_buffer_uptodate(bh);
-                               }
-                               continue;
-                       }
-               }
-               /*
-                * Out of bounds buffer is invalid if it was not really out of
-                * bounds.
-                */
-               BUG_ON(lcn != LCN_HOLE);
-               /*
-                * We need the runlist locked for writing, so if it is locked
-                * for reading relock it now and retry in case it changed
-                * whilst we dropped the lock.
-                */
-               BUG_ON(!rl);
-               if (!rl_write_locked) {
-                       up_read(&ni->runlist.lock);
-                       down_write(&ni->runlist.lock);
-                       rl_write_locked = true;
-                       goto retry_remap;
-               }
-               /* Find the previous last allocated cluster. */
-               BUG_ON(rl->lcn != LCN_HOLE);
-               lcn = -1;
-               rl2 = rl;
-               while (--rl2 >= ni->runlist.rl) {
-                       if (rl2->lcn >= 0) {
-                               lcn = rl2->lcn + rl2->length;
-                               break;
-                       }
-               }
-               rl2 = ntfs_cluster_alloc(vol, bh_cpos, 1, lcn, DATA_ZONE,
-                               false);
-               if (IS_ERR(rl2)) {
-                       err = PTR_ERR(rl2);
-                       ntfs_debug("Failed to allocate cluster, error code %i.",
-                                       err);
-                       break;
-               }
-               lcn = rl2->lcn;
-               rl = ntfs_runlists_merge(ni->runlist.rl, rl2);
-               if (IS_ERR(rl)) {
-                       err = PTR_ERR(rl);
-                       if (err != -ENOMEM)
-                               err = -EIO;
-                       if (ntfs_cluster_free_from_rl(vol, rl2)) {
-                               ntfs_error(vol->sb, "Failed to release "
-                                               "allocated cluster in error "
-                                               "code path.  Run chkdsk to "
-                                               "recover the lost cluster.");
-                               NVolSetErrors(vol);
-                       }
-                       ntfs_free(rl2);
-                       break;
-               }
-               ni->runlist.rl = rl;
-               status.runlist_merged = 1;
-               ntfs_debug("Allocated cluster, lcn 0x%llx.",
-                               (unsigned long long)lcn);
-               /* Map and lock the mft record and get the attribute record. */
-               if (!NInoAttr(ni))
-                       base_ni = ni;
-               else
-                       base_ni = ni->ext.base_ntfs_ino;
-               m = map_mft_record(base_ni);
-               if (IS_ERR(m)) {
-                       err = PTR_ERR(m);
-                       break;
-               }
-               ctx = ntfs_attr_get_search_ctx(base_ni, m);
-               if (unlikely(!ctx)) {
-                       err = -ENOMEM;
-                       unmap_mft_record(base_ni);
-                       break;
-               }
-               status.mft_attr_mapped = 1;
-               err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                               CASE_SENSITIVE, bh_cpos, NULL, 0, ctx);
-               if (unlikely(err)) {
-                       if (err == -ENOENT)
-                               err = -EIO;
-                       break;
-               }
-               m = ctx->mrec;
-               a = ctx->attr;
-               /*
-                * Find the runlist element with which the attribute extent
-                * starts.  Note, we cannot use the _attr_ version because we
-                * have mapped the mft record.  That is ok because we know the
-                * runlist fragment must be mapped already to have ever gotten
-                * here, so we can just use the _rl_ version.
-                */
-               vcn = sle64_to_cpu(a->data.non_resident.lowest_vcn);
-               rl2 = ntfs_rl_find_vcn_nolock(rl, vcn);
-               BUG_ON(!rl2);
-               BUG_ON(!rl2->length);
-               BUG_ON(rl2->lcn < LCN_HOLE);
-               highest_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn);
-               /*
-                * If @highest_vcn is zero, calculate the real highest_vcn
-                * (which can really be zero).
-                */
-               if (!highest_vcn)
-                       highest_vcn = (sle64_to_cpu(
-                                       a->data.non_resident.allocated_size) >>
-                                       vol->cluster_size_bits) - 1;
-               /*
-                * Determine the size of the mapping pairs array for the new
-                * extent, i.e. the old extent with the hole filled.
-                */
-               mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, vcn,
-                               highest_vcn);
-               if (unlikely(mp_size <= 0)) {
-                       if (!(err = mp_size))
-                               err = -EIO;
-                       ntfs_debug("Failed to get size for mapping pairs "
-                                       "array, error code %i.", err);
-                       break;
-               }
-               /*
-                * Resize the attribute record to fit the new mapping pairs
-                * array.
-                */
-               attr_rec_len = le32_to_cpu(a->length);
-               err = ntfs_attr_record_resize(m, a, mp_size + le16_to_cpu(
-                               a->data.non_resident.mapping_pairs_offset));
-               if (unlikely(err)) {
-                       BUG_ON(err != -ENOSPC);
-                       // TODO: Deal with this by using the current attribute
-                       // and fill it with as much of the mapping pairs
-                       // array as possible.  Then loop over each attribute
-                       // extent rewriting the mapping pairs arrays as we go
-                       // along and if when we reach the end we have not
-                       // enough space, try to resize the last attribute
-                       // extent and if even that fails, add a new attribute
-                       // extent.
-                       // We could also try to resize at each step in the hope
-                       // that we will not need to rewrite every single extent.
-                       // Note, we may need to decompress some extents to fill
-                       // the runlist as we are walking the extents...
-                       ntfs_error(vol->sb, "Not enough space in the mft "
-                                       "record for the extended attribute "
-                                       "record.  This case is not "
-                                       "implemented yet.");
-                       err = -EOPNOTSUPP;
-                       break ;
-               }
-               status.mp_rebuilt = 1;
-               /*
-                * Generate the mapping pairs array directly into the attribute
-                * record.
-                */
-               err = ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(
-                               a->data.non_resident.mapping_pairs_offset),
-                               mp_size, rl2, vcn, highest_vcn, NULL);
-               if (unlikely(err)) {
-                       ntfs_error(vol->sb, "Cannot fill hole in inode 0x%lx, "
-                                       "attribute type 0x%x, because building "
-                                       "the mapping pairs failed with error "
-                                       "code %i.", vi->i_ino,
-                                       (unsigned)le32_to_cpu(ni->type), err);
-                       err = -EIO;
-                       break;
-               }
-               /* Update the highest_vcn but only if it was not set. */
-               if (unlikely(!a->data.non_resident.highest_vcn))
-                       a->data.non_resident.highest_vcn =
-                                       cpu_to_sle64(highest_vcn);
-               /*
-                * If the attribute is sparse/compressed, update the compressed
-                * size in the ntfs_inode structure and the attribute record.
-                */
-               if (likely(NInoSparse(ni) || NInoCompressed(ni))) {
-                       /*
-                        * If we are not in the first attribute extent, switch
-                        * to it, but first ensure the changes will make it to
-                        * disk later.
-                        */
-                       if (a->data.non_resident.lowest_vcn) {
-                               flush_dcache_mft_record_page(ctx->ntfs_ino);
-                               mark_mft_record_dirty(ctx->ntfs_ino);
-                               ntfs_attr_reinit_search_ctx(ctx);
-                               err = ntfs_attr_lookup(ni->type, ni->name,
-                                               ni->name_len, CASE_SENSITIVE,
-                                               0, NULL, 0, ctx);
-                               if (unlikely(err)) {
-                                       status.attr_switched = 1;
-                                       break;
-                               }
-                               /* @m is not used any more so do not set it. */
-                               a = ctx->attr;
-                       }
-                       write_lock_irqsave(&ni->size_lock, flags);
-                       ni->itype.compressed.size += vol->cluster_size;
-                       a->data.non_resident.compressed_size =
-                                       cpu_to_sle64(ni->itype.compressed.size);
-                       write_unlock_irqrestore(&ni->size_lock, flags);
-               }
-               /* Ensure the changes make it to disk. */
-               flush_dcache_mft_record_page(ctx->ntfs_ino);
-               mark_mft_record_dirty(ctx->ntfs_ino);
-               ntfs_attr_put_search_ctx(ctx);
-               unmap_mft_record(base_ni);
-               /* Successfully filled the hole. */
-               status.runlist_merged = 0;
-               status.mft_attr_mapped = 0;
-               status.mp_rebuilt = 0;
-               /* Setup the map cache and use that to deal with the buffer. */
-               was_hole = true;
-               vcn = bh_cpos;
-               vcn_len = 1;
-               lcn_block = lcn << (vol->cluster_size_bits - blocksize_bits);
-               cdelta = 0;
-               /*
-                * If the number of remaining clusters in the @pages is smaller
-                * or equal to the number of cached clusters, unlock the
-                * runlist as the map cache will be used from now on.
-                */
-               if (likely(vcn + vcn_len >= cend)) {
-                       up_write(&ni->runlist.lock);
-                       rl_write_locked = false;
-                       rl = NULL;
-               }
-               goto map_buffer_cached;
-       } while (bh_pos += blocksize, (bh = bh->b_this_page) != head);
-       /* If there are no errors, do the next page. */
-       if (likely(!err && ++u < nr_pages))
-               goto do_next_folio;
-       /* If there are no errors, release the runlist lock if we took it. */
-       if (likely(!err)) {
-               if (unlikely(rl_write_locked)) {
-                       up_write(&ni->runlist.lock);
-                       rl_write_locked = false;
-               } else if (unlikely(rl))
-                       up_read(&ni->runlist.lock);
-               rl = NULL;
-       }
-       /* If we issued read requests, let them complete. */
-       read_lock_irqsave(&ni->size_lock, flags);
-       initialized_size = ni->initialized_size;
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       while (wait_bh > wait) {
-               bh = *--wait_bh;
-               wait_on_buffer(bh);
-               if (likely(buffer_uptodate(bh))) {
-                       folio = bh->b_folio;
-                       bh_pos = folio_pos(folio) + bh_offset(bh);
-                       /*
-                        * If the buffer overflows the initialized size, need
-                        * to zero the overflowing region.
-                        */
-                       if (unlikely(bh_pos + blocksize > initialized_size)) {
-                               int ofs = 0;
-
-                               if (likely(bh_pos < initialized_size))
-                                       ofs = initialized_size - bh_pos;
-                               folio_zero_segment(folio, bh_offset(bh) + ofs,
-                                               blocksize);
-                       }
-               } else /* if (unlikely(!buffer_uptodate(bh))) */
-                       err = -EIO;
-       }
-       if (likely(!err)) {
-               /* Clear buffer_new on all buffers. */
-               u = 0;
-               do {
-                       bh = head = page_buffers(pages[u]);
-                       do {
-                               if (buffer_new(bh))
-                                       clear_buffer_new(bh);
-                       } while ((bh = bh->b_this_page) != head);
-               } while (++u < nr_pages);
-               ntfs_debug("Done.");
-               return err;
-       }
-       if (status.attr_switched) {
-               /* Get back to the attribute extent we modified. */
-               ntfs_attr_reinit_search_ctx(ctx);
-               if (ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                               CASE_SENSITIVE, bh_cpos, NULL, 0, ctx)) {
-                       ntfs_error(vol->sb, "Failed to find required "
-                                       "attribute extent of attribute in "
-                                       "error code path.  Run chkdsk to "
-                                       "recover.");
-                       write_lock_irqsave(&ni->size_lock, flags);
-                       ni->itype.compressed.size += vol->cluster_size;
-                       write_unlock_irqrestore(&ni->size_lock, flags);
-                       flush_dcache_mft_record_page(ctx->ntfs_ino);
-                       mark_mft_record_dirty(ctx->ntfs_ino);
-                       /*
-                        * The only thing that is now wrong is the compressed
-                        * size of the base attribute extent which chkdsk
-                        * should be able to fix.
-                        */
-                       NVolSetErrors(vol);
-               } else {
-                       m = ctx->mrec;
-                       a = ctx->attr;
-                       status.attr_switched = 0;
-               }
-       }
-       /*
-        * If the runlist has been modified, need to restore it by punching a
-        * hole into it and we then need to deallocate the on-disk cluster as
-        * well.  Note, we only modify the runlist if we are able to generate a
-        * new mapping pairs array, i.e. only when the mapped attribute extent
-        * is not switched.
-        */
-       if (status.runlist_merged && !status.attr_switched) {
-               BUG_ON(!rl_write_locked);
-               /* Make the file cluster we allocated sparse in the runlist. */
-               if (ntfs_rl_punch_nolock(vol, &ni->runlist, bh_cpos, 1)) {
-                       ntfs_error(vol->sb, "Failed to punch hole into "
-                                       "attribute runlist in error code "
-                                       "path.  Run chkdsk to recover the "
-                                       "lost cluster.");
-                       NVolSetErrors(vol);
-               } else /* if (success) */ {
-                       status.runlist_merged = 0;
-                       /*
-                        * Deallocate the on-disk cluster we allocated but only
-                        * if we succeeded in punching its vcn out of the
-                        * runlist.
-                        */
-                       down_write(&vol->lcnbmp_lock);
-                       if (ntfs_bitmap_clear_bit(vol->lcnbmp_ino, lcn)) {
-                               ntfs_error(vol->sb, "Failed to release "
-                                               "allocated cluster in error "
-                                               "code path.  Run chkdsk to "
-                                               "recover the lost cluster.");
-                               NVolSetErrors(vol);
-                       }
-                       up_write(&vol->lcnbmp_lock);
-               }
-       }
-       /*
-        * Resize the attribute record to its old size and rebuild the mapping
-        * pairs array.  Note, we only can do this if the runlist has been
-        * restored to its old state which also implies that the mapped
-        * attribute extent is not switched.
-        */
-       if (status.mp_rebuilt && !status.runlist_merged) {
-               if (ntfs_attr_record_resize(m, a, attr_rec_len)) {
-                       ntfs_error(vol->sb, "Failed to restore attribute "
-                                       "record in error code path.  Run "
-                                       "chkdsk to recover.");
-                       NVolSetErrors(vol);
-               } else /* if (success) */ {
-                       if (ntfs_mapping_pairs_build(vol, (u8*)a +
-                                       le16_to_cpu(a->data.non_resident.
-                                       mapping_pairs_offset), attr_rec_len -
-                                       le16_to_cpu(a->data.non_resident.
-                                       mapping_pairs_offset), ni->runlist.rl,
-                                       vcn, highest_vcn, NULL)) {
-                               ntfs_error(vol->sb, "Failed to restore "
-                                               "mapping pairs array in error "
-                                               "code path.  Run chkdsk to "
-                                               "recover.");
-                               NVolSetErrors(vol);
-                       }
-                       flush_dcache_mft_record_page(ctx->ntfs_ino);
-                       mark_mft_record_dirty(ctx->ntfs_ino);
-               }
-       }
-       /* Release the mft record and the attribute. */
-       if (status.mft_attr_mapped) {
-               ntfs_attr_put_search_ctx(ctx);
-               unmap_mft_record(base_ni);
-       }
-       /* Release the runlist lock. */
-       if (rl_write_locked)
-               up_write(&ni->runlist.lock);
-       else if (rl)
-               up_read(&ni->runlist.lock);
-       /*
-        * Zero out any newly allocated blocks to avoid exposing stale data.
-        * If BH_New is set, we know that the block was newly allocated above
-        * and that it has not been fully zeroed and marked dirty yet.
-        */
-       nr_pages = u;
-       u = 0;
-       end = bh_cpos << vol->cluster_size_bits;
-       do {
-               folio = page_folio(pages[u]);
-               bh = head = folio_buffers(folio);
-               do {
-                       if (u == nr_pages &&
-                           folio_pos(folio) + bh_offset(bh) >= end)
-                               break;
-                       if (!buffer_new(bh))
-                               continue;
-                       clear_buffer_new(bh);
-                       if (!buffer_uptodate(bh)) {
-                               if (folio_test_uptodate(folio))
-                                       set_buffer_uptodate(bh);
-                               else {
-                                       folio_zero_range(folio, bh_offset(bh),
-                                                       blocksize);
-                                       set_buffer_uptodate(bh);
-                               }
-                       }
-                       mark_buffer_dirty(bh);
-               } while ((bh = bh->b_this_page) != head);
-       } while (++u <= nr_pages);
-       ntfs_error(vol->sb, "Failed.  Returning error code %i.", err);
-       return err;
-}
-
-static inline void ntfs_flush_dcache_pages(struct page **pages,
-               unsigned nr_pages)
-{
-       BUG_ON(!nr_pages);
-       /*
-        * Warning: Do not do the decrement at the same time as the call to
-        * flush_dcache_page() because it is a NULL macro on i386 and hence the
-        * decrement never happens so the loop never terminates.
-        */
-       do {
-               --nr_pages;
-               flush_dcache_page(pages[nr_pages]);
-       } while (nr_pages > 0);
-}
-
-/**
- * ntfs_commit_pages_after_non_resident_write - commit the received data
- * @pages:     array of destination pages
- * @nr_pages:  number of pages in @pages
- * @pos:       byte position in file at which the write begins
- * @bytes:     number of bytes to be written
- *
- * See description of ntfs_commit_pages_after_write(), below.
- */
-static inline int ntfs_commit_pages_after_non_resident_write(
-               struct page **pages, const unsigned nr_pages,
-               s64 pos, size_t bytes)
-{
-       s64 end, initialized_size;
-       struct inode *vi;
-       ntfs_inode *ni, *base_ni;
-       struct buffer_head *bh, *head;
-       ntfs_attr_search_ctx *ctx;
-       MFT_RECORD *m;
-       ATTR_RECORD *a;
-       unsigned long flags;
-       unsigned blocksize, u;
-       int err;
-
-       vi = pages[0]->mapping->host;
-       ni = NTFS_I(vi);
-       blocksize = vi->i_sb->s_blocksize;
-       end = pos + bytes;
-       u = 0;
-       do {
-               s64 bh_pos;
-               struct page *page;
-               bool partial;
-
-               page = pages[u];
-               bh_pos = (s64)page->index << PAGE_SHIFT;
-               bh = head = page_buffers(page);
-               partial = false;
-               do {
-                       s64 bh_end;
-
-                       bh_end = bh_pos + blocksize;
-                       if (bh_end <= pos || bh_pos >= end) {
-                               if (!buffer_uptodate(bh))
-                                       partial = true;
-                       } else {
-                               set_buffer_uptodate(bh);
-                               mark_buffer_dirty(bh);
-                       }
-               } while (bh_pos += blocksize, (bh = bh->b_this_page) != head);
-               /*
-                * If all buffers are now uptodate but the page is not, set the
-                * page uptodate.
-                */
-               if (!partial && !PageUptodate(page))
-                       SetPageUptodate(page);
-       } while (++u < nr_pages);
-       /*
-        * Finally, if we do not need to update initialized_size or i_size we
-        * are finished.
-        */
-       read_lock_irqsave(&ni->size_lock, flags);
-       initialized_size = ni->initialized_size;
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       if (end <= initialized_size) {
-               ntfs_debug("Done.");
-               return 0;
-       }
-       /*
-        * Update initialized_size/i_size as appropriate, both in the inode and
-        * the mft record.
-        */
-       if (!NInoAttr(ni))
-               base_ni = ni;
-       else
-               base_ni = ni->ext.base_ntfs_ino;
-       /* Map, pin, and lock the mft record. */
-       m = map_mft_record(base_ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               m = NULL;
-               ctx = NULL;
-               goto err_out;
-       }
-       BUG_ON(!NInoNonResident(ni));
-       ctx = ntfs_attr_get_search_ctx(base_ni, m);
-       if (unlikely(!ctx)) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err)) {
-               if (err == -ENOENT)
-                       err = -EIO;
-               goto err_out;
-       }
-       a = ctx->attr;
-       BUG_ON(!a->non_resident);
-       write_lock_irqsave(&ni->size_lock, flags);
-       BUG_ON(end > ni->allocated_size);
-       ni->initialized_size = end;
-       a->data.non_resident.initialized_size = cpu_to_sle64(end);
-       if (end > i_size_read(vi)) {
-               i_size_write(vi, end);
-               a->data.non_resident.data_size =
-                               a->data.non_resident.initialized_size;
-       }
-       write_unlock_irqrestore(&ni->size_lock, flags);
-       /* Mark the mft record dirty, so it gets written back. */
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(base_ni);
-       ntfs_debug("Done.");
-       return 0;
-err_out:
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(base_ni);
-       ntfs_error(vi->i_sb, "Failed to update initialized_size/i_size (error "
-                       "code %i).", err);
-       if (err != -ENOMEM)
-               NVolSetErrors(ni->vol);
-       return err;
-}
-
-/**
- * ntfs_commit_pages_after_write - commit the received data
- * @pages:     array of destination pages
- * @nr_pages:  number of pages in @pages
- * @pos:       byte position in file at which the write begins
- * @bytes:     number of bytes to be written
- *
- * This is called from ntfs_file_buffered_write() with i_mutex held on the inode
- * (@pages[0]->mapping->host).  There are @nr_pages pages in @pages which are
- * locked but not kmap()ped.  The source data has already been copied into the
- * @page.  ntfs_prepare_pages_for_non_resident_write() has been called before
- * the data was copied (for non-resident attributes only) and it returned
- * success.
- *
- * Need to set uptodate and mark dirty all buffers within the boundary of the
- * write.  If all buffers in a page are uptodate we set the page uptodate, too.
- *
- * Setting the buffers dirty ensures that they get written out later when
- * ntfs_writepage() is invoked by the VM.
- *
- * Finally, we need to update i_size and initialized_size as appropriate both
- * in the inode and the mft record.
- *
- * This is modelled after fs/buffer.c::generic_commit_write(), which marks
- * buffers uptodate and dirty, sets the page uptodate if all buffers in the
- * page are uptodate, and updates i_size if the end of io is beyond i_size.  In
- * that case, it also marks the inode dirty.
- *
- * If things have gone as outlined in
- * ntfs_prepare_pages_for_non_resident_write(), we do not need to do any page
- * content modifications here for non-resident attributes.  For resident
- * attributes we need to do the uptodate bringing here which we combine with
- * the copying into the mft record which means we save one atomic kmap.
- *
- * Return 0 on success or -errno on error.
- */
-static int ntfs_commit_pages_after_write(struct page **pages,
-               const unsigned nr_pages, s64 pos, size_t bytes)
-{
-       s64 end, initialized_size;
-       loff_t i_size;
-       struct inode *vi;
-       ntfs_inode *ni, *base_ni;
-       struct page *page;
-       ntfs_attr_search_ctx *ctx;
-       MFT_RECORD *m;
-       ATTR_RECORD *a;
-       char *kattr, *kaddr;
-       unsigned long flags;
-       u32 attr_len;
-       int err;
-
-       BUG_ON(!nr_pages);
-       BUG_ON(!pages);
-       page = pages[0];
-       BUG_ON(!page);
-       vi = page->mapping->host;
-       ni = NTFS_I(vi);
-       ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, start page "
-                       "index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%zx.",
-                       vi->i_ino, ni->type, page->index, nr_pages,
-                       (long long)pos, bytes);
-       if (NInoNonResident(ni))
-               return ntfs_commit_pages_after_non_resident_write(pages,
-                               nr_pages, pos, bytes);
-       BUG_ON(nr_pages > 1);
-       /*
-        * Attribute is resident, implying it is not compressed, encrypted, or
-        * sparse.
-        */
-       if (!NInoAttr(ni))
-               base_ni = ni;
-       else
-               base_ni = ni->ext.base_ntfs_ino;
-       BUG_ON(NInoNonResident(ni));
-       /* Map, pin, and lock the mft record. */
-       m = map_mft_record(base_ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               m = NULL;
-               ctx = NULL;
-               goto err_out;
-       }
-       ctx = ntfs_attr_get_search_ctx(base_ni, m);
-       if (unlikely(!ctx)) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err)) {
-               if (err == -ENOENT)
-                       err = -EIO;
-               goto err_out;
-       }
-       a = ctx->attr;
-       BUG_ON(a->non_resident);
-       /* The total length of the attribute value. */
-       attr_len = le32_to_cpu(a->data.resident.value_length);
-       i_size = i_size_read(vi);
-       BUG_ON(attr_len != i_size);
-       BUG_ON(pos > attr_len);
-       end = pos + bytes;
-       BUG_ON(end > le32_to_cpu(a->length) -
-                       le16_to_cpu(a->data.resident.value_offset));
-       kattr = (u8*)a + le16_to_cpu(a->data.resident.value_offset);
-       kaddr = kmap_atomic(page);
-       /* Copy the received data from the page to the mft record. */
-       memcpy(kattr + pos, kaddr + pos, bytes);
-       /* Update the attribute length if necessary. */
-       if (end > attr_len) {
-               attr_len = end;
-               a->data.resident.value_length = cpu_to_le32(attr_len);
-       }
-       /*
-        * If the page is not uptodate, bring the out of bounds area(s)
-        * uptodate by copying data from the mft record to the page.
-        */
-       if (!PageUptodate(page)) {
-               if (pos > 0)
-                       memcpy(kaddr, kattr, pos);
-               if (end < attr_len)
-                       memcpy(kaddr + end, kattr + end, attr_len - end);
-               /* Zero the region outside the end of the attribute value. */
-               memset(kaddr + attr_len, 0, PAGE_SIZE - attr_len);
-               flush_dcache_page(page);
-               SetPageUptodate(page);
-       }
-       kunmap_atomic(kaddr);
-       /* Update initialized_size/i_size if necessary. */
-       read_lock_irqsave(&ni->size_lock, flags);
-       initialized_size = ni->initialized_size;
-       BUG_ON(end > ni->allocated_size);
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       BUG_ON(initialized_size != i_size);
-       if (end > initialized_size) {
-               write_lock_irqsave(&ni->size_lock, flags);
-               ni->initialized_size = end;
-               i_size_write(vi, end);
-               write_unlock_irqrestore(&ni->size_lock, flags);
-       }
-       /* Mark the mft record dirty, so it gets written back. */
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(base_ni);
-       ntfs_debug("Done.");
-       return 0;
-err_out:
-       if (err == -ENOMEM) {
-               ntfs_warning(vi->i_sb, "Error allocating memory required to "
-                               "commit the write.");
-               if (PageUptodate(page)) {
-                       ntfs_warning(vi->i_sb, "Page is uptodate, setting "
-                                       "dirty so the write will be retried "
-                                       "later on by the VM.");
-                       /*
-                        * Put the page on mapping->dirty_pages, but leave its
-                        * buffers' dirty state as-is.
-                        */
-                       __set_page_dirty_nobuffers(page);
-                       err = 0;
-               } else
-                       ntfs_error(vi->i_sb, "Page is not uptodate.  Written "
-                                       "data has been lost.");
-       } else {
-               ntfs_error(vi->i_sb, "Resident attribute commit write failed "
-                               "with error %i.", err);
-               NVolSetErrors(ni->vol);
-       }
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(base_ni);
-       return err;
-}
-
-/*
- * Copy as much as we can into the pages and return the number of bytes which
- * were successfully copied.  If a fault is encountered then clear the pages
- * out to (ofs + bytes) and return the number of bytes which were copied.
- */
-static size_t ntfs_copy_from_user_iter(struct page **pages, unsigned nr_pages,
-               unsigned ofs, struct iov_iter *i, size_t bytes)
-{
-       struct page **last_page = pages + nr_pages;
-       size_t total = 0;
-       unsigned len, copied;
-
-       do {
-               len = PAGE_SIZE - ofs;
-               if (len > bytes)
-                       len = bytes;
-               copied = copy_page_from_iter_atomic(*pages, ofs, len, i);
-               total += copied;
-               bytes -= copied;
-               if (!bytes)
-                       break;
-               if (copied < len)
-                       goto err;
-               ofs = 0;
-       } while (++pages < last_page);
-out:
-       return total;
-err:
-       /* Zero the rest of the target like __copy_from_user(). */
-       len = PAGE_SIZE - copied;
-       do {
-               if (len > bytes)
-                       len = bytes;
-               zero_user(*pages, copied, len);
-               bytes -= len;
-               copied = 0;
-               len = PAGE_SIZE;
-       } while (++pages < last_page);
-       goto out;
-}
-
-/**
- * ntfs_perform_write - perform buffered write to a file
- * @file:      file to write to
- * @i:         iov_iter with data to write
- * @pos:       byte offset in file at which to begin writing to
- */
-static ssize_t ntfs_perform_write(struct file *file, struct iov_iter *i,
-               loff_t pos)
-{
-       struct address_space *mapping = file->f_mapping;
-       struct inode *vi = mapping->host;
-       ntfs_inode *ni = NTFS_I(vi);
-       ntfs_volume *vol = ni->vol;
-       struct page *pages[NTFS_MAX_PAGES_PER_CLUSTER];
-       struct page *cached_page = NULL;
-       VCN last_vcn;
-       LCN lcn;
-       size_t bytes;
-       ssize_t status, written = 0;
-       unsigned nr_pages;
-
-       ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, pos "
-                       "0x%llx, count 0x%lx.", vi->i_ino,
-                       (unsigned)le32_to_cpu(ni->type),
-                       (unsigned long long)pos,
-                       (unsigned long)iov_iter_count(i));
-       /*
-        * If a previous ntfs_truncate() failed, repeat it and abort if it
-        * fails again.
-        */
-       if (unlikely(NInoTruncateFailed(ni))) {
-               int err;
-
-               inode_dio_wait(vi);
-               err = ntfs_truncate(vi);
-               if (err || NInoTruncateFailed(ni)) {
-                       if (!err)
-                               err = -EIO;
-                       ntfs_error(vol->sb, "Cannot perform write to inode "
-                                       "0x%lx, attribute type 0x%x, because "
-                                       "ntfs_truncate() failed (error code "
-                                       "%i).", vi->i_ino,
-                                       (unsigned)le32_to_cpu(ni->type), err);
-                       return err;
-               }
-       }
-       /*
-        * Determine the number of pages per cluster for non-resident
-        * attributes.
-        */
-       nr_pages = 1;
-       if (vol->cluster_size > PAGE_SIZE && NInoNonResident(ni))
-               nr_pages = vol->cluster_size >> PAGE_SHIFT;
-       last_vcn = -1;
-       do {
-               VCN vcn;
-               pgoff_t start_idx;
-               unsigned ofs, do_pages, u;
-               size_t copied;
-
-               start_idx = pos >> PAGE_SHIFT;
-               ofs = pos & ~PAGE_MASK;
-               bytes = PAGE_SIZE - ofs;
-               do_pages = 1;
-               if (nr_pages > 1) {
-                       vcn = pos >> vol->cluster_size_bits;
-                       if (vcn != last_vcn) {
-                               last_vcn = vcn;
-                               /*
-                                * Get the lcn of the vcn the write is in.  If
-                                * it is a hole, need to lock down all pages in
-                                * the cluster.
-                                */
-                               down_read(&ni->runlist.lock);
-                               lcn = ntfs_attr_vcn_to_lcn_nolock(ni, pos >>
-                                               vol->cluster_size_bits, false);
-                               up_read(&ni->runlist.lock);
-                               if (unlikely(lcn < LCN_HOLE)) {
-                                       if (lcn == LCN_ENOMEM)
-                                               status = -ENOMEM;
-                                       else {
-                                               status = -EIO;
-                                               ntfs_error(vol->sb, "Cannot "
-                                                       "perform write to "
-                                                       "inode 0x%lx, "
-                                                       "attribute type 0x%x, "
-                                                       "because the attribute "
-                                                       "is corrupt.",
-                                                       vi->i_ino, (unsigned)
-                                                       le32_to_cpu(ni->type));
-                                       }
-                                       break;
-                               }
-                               if (lcn == LCN_HOLE) {
-                                       start_idx = (pos & ~(s64)
-                                                       vol->cluster_size_mask)
-                                                       >> PAGE_SHIFT;
-                                       bytes = vol->cluster_size - (pos &
-                                                       vol->cluster_size_mask);
-                                       do_pages = nr_pages;
-                               }
-                       }
-               }
-               if (bytes > iov_iter_count(i))
-                       bytes = iov_iter_count(i);
-again:
-               /*
-                * Bring in the user page(s) that we will copy from _first_.
-                * Otherwise there is a nasty deadlock on copying from the same
-                * page(s) as we are writing to, without it/them being marked
-                * up-to-date.  Note, at present there is nothing to stop the
-                * pages being swapped out between us bringing them into memory
-                * and doing the actual copying.
-                */
-               if (unlikely(fault_in_iov_iter_readable(i, bytes))) {
-                       status = -EFAULT;
-                       break;
-               }
-               /* Get and lock @do_pages starting at index @start_idx. */
-               status = __ntfs_grab_cache_pages(mapping, start_idx, do_pages,
-                               pages, &cached_page);
-               if (unlikely(status))
-                       break;
-               /*
-                * For non-resident attributes, we need to fill any holes with
-                * actual clusters and ensure all bufferes are mapped.  We also
-                * need to bring uptodate any buffers that are only partially
-                * being written to.
-                */
-               if (NInoNonResident(ni)) {
-                       status = ntfs_prepare_pages_for_non_resident_write(
-                                       pages, do_pages, pos, bytes);
-                       if (unlikely(status)) {
-                               do {
-                                       unlock_page(pages[--do_pages]);
-                                       put_page(pages[do_pages]);
-                               } while (do_pages);
-                               break;
-                       }
-               }
-               u = (pos >> PAGE_SHIFT) - pages[0]->index;
-               copied = ntfs_copy_from_user_iter(pages + u, do_pages - u, ofs,
-                                       i, bytes);
-               ntfs_flush_dcache_pages(pages + u, do_pages - u);
-               status = 0;
-               if (likely(copied == bytes)) {
-                       status = ntfs_commit_pages_after_write(pages, do_pages,
-                                       pos, bytes);
-               }
-               do {
-                       unlock_page(pages[--do_pages]);
-                       put_page(pages[do_pages]);
-               } while (do_pages);
-               if (unlikely(status < 0)) {
-                       iov_iter_revert(i, copied);
-                       break;
-               }
-               cond_resched();
-               if (unlikely(copied < bytes)) {
-                       iov_iter_revert(i, copied);
-                       if (copied)
-                               bytes = copied;
-                       else if (bytes > PAGE_SIZE - ofs)
-                               bytes = PAGE_SIZE - ofs;
-                       goto again;
-               }
-               pos += copied;
-               written += copied;
-               balance_dirty_pages_ratelimited(mapping);
-               if (fatal_signal_pending(current)) {
-                       status = -EINTR;
-                       break;
-               }
-       } while (iov_iter_count(i));
-       if (cached_page)
-               put_page(cached_page);
-       ntfs_debug("Done.  Returning %s (written 0x%lx, status %li).",
-                       written ? "written" : "status", (unsigned long)written,
-                       (long)status);
-       return written ? written : status;
-}
-
-/**
- * ntfs_file_write_iter - simple wrapper for ntfs_file_write_iter_nolock()
- * @iocb:      IO state structure
- * @from:      iov_iter with data to write
- *
- * Basically the same as generic_file_write_iter() except that it ends up
- * up calling ntfs_perform_write() instead of generic_perform_write() and that
- * O_DIRECT is not implemented.
- */
-static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
-{
-       struct file *file = iocb->ki_filp;
-       struct inode *vi = file_inode(file);
-       ssize_t written = 0;
-       ssize_t err;
-
-       inode_lock(vi);
-       /* We can write back this queue in page reclaim. */
-       err = ntfs_prepare_file_for_write(iocb, from);
-       if (iov_iter_count(from) && !err)
-               written = ntfs_perform_write(file, from, iocb->ki_pos);
-       inode_unlock(vi);
-       iocb->ki_pos += written;
-       if (likely(written > 0))
-               written = generic_write_sync(iocb, written);
-       return written ? written : err;
-}
-
-/**
- * ntfs_file_fsync - sync a file to disk
- * @filp:      file to be synced
- * @datasync:  if non-zero only flush user data and not metadata
- *
- * Data integrity sync of a file to disk.  Used for fsync, fdatasync, and msync
- * system calls.  This function is inspired by fs/buffer.c::file_fsync().
- *
- * If @datasync is false, write the mft record and all associated extent mft
- * records as well as the $DATA attribute and then sync the block device.
- *
- * If @datasync is true and the attribute is non-resident, we skip the writing
- * of the mft record and all associated extent mft records (this might still
- * happen due to the write_inode_now() call).
- *
- * Also, if @datasync is true, we do not wait on the inode to be written out
- * but we always wait on the page cache pages to be written out.
- *
- * Locking: Caller must hold i_mutex on the inode.
- *
- * TODO: We should probably also write all attribute/index inodes associated
- * with this inode but since we have no simple way of getting to them we ignore
- * this problem for now.
- */
-static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end,
-                          int datasync)
-{
-       struct inode *vi = filp->f_mapping->host;
-       int err, ret = 0;
-
-       ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
-
-       err = file_write_and_wait_range(filp, start, end);
-       if (err)
-               return err;
-       inode_lock(vi);
-
-       BUG_ON(S_ISDIR(vi->i_mode));
-       if (!datasync || !NInoNonResident(NTFS_I(vi)))
-               ret = __ntfs_write_inode(vi, 1);
-       write_inode_now(vi, !datasync);
-       /*
-        * NOTE: If we were to use mapping->private_list (see ext2 and
-        * fs/buffer.c) for dirty blocks then we could optimize the below to be
-        * sync_mapping_buffers(vi->i_mapping).
-        */
-       err = sync_blockdev(vi->i_sb->s_bdev);
-       if (unlikely(err && !ret))
-               ret = err;
-       if (likely(!ret))
-               ntfs_debug("Done.");
-       else
-               ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx.  Error "
-                               "%u.", datasync ? "data" : "", vi->i_ino, -ret);
-       inode_unlock(vi);
-       return ret;
-}
-
-#endif /* NTFS_RW */
-
-const struct file_operations ntfs_file_ops = {
-       .llseek         = generic_file_llseek,
-       .read_iter      = generic_file_read_iter,
-#ifdef NTFS_RW
-       .write_iter     = ntfs_file_write_iter,
-       .fsync          = ntfs_file_fsync,
-#endif /* NTFS_RW */
-       .mmap           = generic_file_mmap,
-       .open           = ntfs_file_open,
-       .splice_read    = filemap_splice_read,
-};
-
-const struct inode_operations ntfs_file_inode_ops = {
-#ifdef NTFS_RW
-       .setattr        = ntfs_setattr,
-#endif /* NTFS_RW */
-};
-
-const struct file_operations ntfs_empty_file_ops = {};
-
-const struct inode_operations ntfs_empty_inode_ops = {};
diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c
deleted file mode 100644 (file)
index d46c2c0..0000000
+++ /dev/null
@@ -1,440 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * index.c - NTFS kernel index handling.  Part of the Linux-NTFS project.
- *
- * Copyright (c) 2004-2005 Anton Altaparmakov
- */
-
-#include <linux/slab.h>
-
-#include "aops.h"
-#include "collate.h"
-#include "debug.h"
-#include "index.h"
-#include "ntfs.h"
-
-/**
- * ntfs_index_ctx_get - allocate and initialize a new index context
- * @idx_ni:    ntfs index inode with which to initialize the context
- *
- * Allocate a new index context, initialize it with @idx_ni and return it.
- * Return NULL if allocation failed.
- *
- * Locking:  Caller must hold i_mutex on the index inode.
- */
-ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *idx_ni)
-{
-       ntfs_index_context *ictx;
-
-       ictx = kmem_cache_alloc(ntfs_index_ctx_cache, GFP_NOFS);
-       if (ictx)
-               *ictx = (ntfs_index_context){ .idx_ni = idx_ni };
-       return ictx;
-}
-
-/**
- * ntfs_index_ctx_put - release an index context
- * @ictx:      index context to free
- *
- * Release the index context @ictx, releasing all associated resources.
- *
- * Locking:  Caller must hold i_mutex on the index inode.
- */
-void ntfs_index_ctx_put(ntfs_index_context *ictx)
-{
-       if (ictx->entry) {
-               if (ictx->is_in_root) {
-                       if (ictx->actx)
-                               ntfs_attr_put_search_ctx(ictx->actx);
-                       if (ictx->base_ni)
-                               unmap_mft_record(ictx->base_ni);
-               } else {
-                       struct page *page = ictx->page;
-                       if (page) {
-                               BUG_ON(!PageLocked(page));
-                               unlock_page(page);
-                               ntfs_unmap_page(page);
-                       }
-               }
-       }
-       kmem_cache_free(ntfs_index_ctx_cache, ictx);
-       return;
-}
-
-/**
- * ntfs_index_lookup - find a key in an index and return its index entry
- * @key:       [IN] key for which to search in the index
- * @key_len:   [IN] length of @key in bytes
- * @ictx:      [IN/OUT] context describing the index and the returned entry
- *
- * Before calling ntfs_index_lookup(), @ictx must have been obtained from a
- * call to ntfs_index_ctx_get().
- *
- * Look for the @key in the index specified by the index lookup context @ictx.
- * ntfs_index_lookup() walks the contents of the index looking for the @key.
- *
- * If the @key is found in the index, 0 is returned and @ictx is setup to
- * describe the index entry containing the matching @key.  @ictx->entry is the
- * index entry and @ictx->data and @ictx->data_len are the index entry data and
- * its length in bytes, respectively.
- *
- * If the @key is not found in the index, -ENOENT is returned and @ictx is
- * setup to describe the index entry whose key collates immediately after the
- * search @key, i.e. this is the position in the index at which an index entry
- * with a key of @key would need to be inserted.
- *
- * If an error occurs return the negative error code and @ictx is left
- * untouched.
- *
- * When finished with the entry and its data, call ntfs_index_ctx_put() to free
- * the context and other associated resources.
- *
- * If the index entry was modified, call flush_dcache_index_entry_page()
- * immediately after the modification and either ntfs_index_entry_mark_dirty()
- * or ntfs_index_entry_write() before the call to ntfs_index_ctx_put() to
- * ensure that the changes are written to disk.
- *
- * Locking:  - Caller must hold i_mutex on the index inode.
- *          - Each page cache page in the index allocation mapping must be
- *            locked whilst being accessed otherwise we may find a corrupt
- *            page due to it being under ->writepage at the moment which
- *            applies the mst protection fixups before writing out and then
- *            removes them again after the write is complete after which it 
- *            unlocks the page.
- */
-int ntfs_index_lookup(const void *key, const int key_len,
-               ntfs_index_context *ictx)
-{
-       VCN vcn, old_vcn;
-       ntfs_inode *idx_ni = ictx->idx_ni;
-       ntfs_volume *vol = idx_ni->vol;
-       struct super_block *sb = vol->sb;
-       ntfs_inode *base_ni = idx_ni->ext.base_ntfs_ino;
-       MFT_RECORD *m;
-       INDEX_ROOT *ir;
-       INDEX_ENTRY *ie;
-       INDEX_ALLOCATION *ia;
-       u8 *index_end, *kaddr;
-       ntfs_attr_search_ctx *actx;
-       struct address_space *ia_mapping;
-       struct page *page;
-       int rc, err = 0;
-
-       ntfs_debug("Entering.");
-       BUG_ON(!NInoAttr(idx_ni));
-       BUG_ON(idx_ni->type != AT_INDEX_ALLOCATION);
-       BUG_ON(idx_ni->nr_extents != -1);
-       BUG_ON(!base_ni);
-       BUG_ON(!key);
-       BUG_ON(key_len <= 0);
-       if (!ntfs_is_collation_rule_supported(
-                       idx_ni->itype.index.collation_rule)) {
-               ntfs_error(sb, "Index uses unsupported collation rule 0x%x.  "
-                               "Aborting lookup.", le32_to_cpu(
-                               idx_ni->itype.index.collation_rule));
-               return -EOPNOTSUPP;
-       }
-       /* Get hold of the mft record for the index inode. */
-       m = map_mft_record(base_ni);
-       if (IS_ERR(m)) {
-               ntfs_error(sb, "map_mft_record() failed with error code %ld.",
-                               -PTR_ERR(m));
-               return PTR_ERR(m);
-       }
-       actx = ntfs_attr_get_search_ctx(base_ni, m);
-       if (unlikely(!actx)) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-       /* Find the index root attribute in the mft record. */
-       err = ntfs_attr_lookup(AT_INDEX_ROOT, idx_ni->name, idx_ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, actx);
-       if (unlikely(err)) {
-               if (err == -ENOENT) {
-                       ntfs_error(sb, "Index root attribute missing in inode "
-                                       "0x%lx.", idx_ni->mft_no);
-                       err = -EIO;
-               }
-               goto err_out;
-       }
-       /* Get to the index root value (it has been verified in read_inode). */
-       ir = (INDEX_ROOT*)((u8*)actx->attr +
-                       le16_to_cpu(actx->attr->data.resident.value_offset));
-       index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
-       /* The first index entry. */
-       ie = (INDEX_ENTRY*)((u8*)&ir->index +
-                       le32_to_cpu(ir->index.entries_offset));
-       /*
-        * Loop until we exceed valid memory (corruption case) or until we
-        * reach the last entry.
-        */
-       for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
-               /* Bounds checks. */
-               if ((u8*)ie < (u8*)actx->mrec || (u8*)ie +
-                               sizeof(INDEX_ENTRY_HEADER) > index_end ||
-                               (u8*)ie + le16_to_cpu(ie->length) > index_end)
-                       goto idx_err_out;
-               /*
-                * The last entry cannot contain a key.  It can however contain
-                * a pointer to a child node in the B+tree so we just break out.
-                */
-               if (ie->flags & INDEX_ENTRY_END)
-                       break;
-               /* Further bounds checks. */
-               if ((u32)sizeof(INDEX_ENTRY_HEADER) +
-                               le16_to_cpu(ie->key_length) >
-                               le16_to_cpu(ie->data.vi.data_offset) ||
-                               (u32)le16_to_cpu(ie->data.vi.data_offset) +
-                               le16_to_cpu(ie->data.vi.data_length) >
-                               le16_to_cpu(ie->length))
-                       goto idx_err_out;
-               /* If the keys match perfectly, we setup @ictx and return 0. */
-               if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key,
-                               &ie->key, key_len)) {
-ir_done:
-                       ictx->is_in_root = true;
-                       ictx->ir = ir;
-                       ictx->actx = actx;
-                       ictx->base_ni = base_ni;
-                       ictx->ia = NULL;
-                       ictx->page = NULL;
-done:
-                       ictx->entry = ie;
-                       ictx->data = (u8*)ie +
-                                       le16_to_cpu(ie->data.vi.data_offset);
-                       ictx->data_len = le16_to_cpu(ie->data.vi.data_length);
-                       ntfs_debug("Done.");
-                       return err;
-               }
-               /*
-                * Not a perfect match, need to do full blown collation so we
-                * know which way in the B+tree we have to go.
-                */
-               rc = ntfs_collate(vol, idx_ni->itype.index.collation_rule, key,
-                               key_len, &ie->key, le16_to_cpu(ie->key_length));
-               /*
-                * If @key collates before the key of the current entry, there
-                * is definitely no such key in this index but we might need to
-                * descend into the B+tree so we just break out of the loop.
-                */
-               if (rc == -1)
-                       break;
-               /*
-                * A match should never happen as the memcmp() call should have
-                * cought it, but we still treat it correctly.
-                */
-               if (!rc)
-                       goto ir_done;
-               /* The keys are not equal, continue the search. */
-       }
-       /*
-        * We have finished with this index without success.  Check for the
-        * presence of a child node and if not present setup @ictx and return
-        * -ENOENT.
-        */
-       if (!(ie->flags & INDEX_ENTRY_NODE)) {
-               ntfs_debug("Entry not found.");
-               err = -ENOENT;
-               goto ir_done;
-       } /* Child node present, descend into it. */
-       /* Consistency check: Verify that an index allocation exists. */
-       if (!NInoIndexAllocPresent(idx_ni)) {
-               ntfs_error(sb, "No index allocation attribute but index entry "
-                               "requires one.  Inode 0x%lx is corrupt or "
-                               "driver bug.", idx_ni->mft_no);
-               goto err_out;
-       }
-       /* Get the starting vcn of the index_block holding the child node. */
-       vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
-       ia_mapping = VFS_I(idx_ni)->i_mapping;
-       /*
-        * We are done with the index root and the mft record.  Release them,
-        * otherwise we deadlock with ntfs_map_page().
-        */
-       ntfs_attr_put_search_ctx(actx);
-       unmap_mft_record(base_ni);
-       m = NULL;
-       actx = NULL;
-descend_into_child_node:
-       /*
-        * Convert vcn to index into the index allocation attribute in units
-        * of PAGE_SIZE and map the page cache page, reading it from
-        * disk if necessary.
-        */
-       page = ntfs_map_page(ia_mapping, vcn <<
-                       idx_ni->itype.index.vcn_size_bits >> PAGE_SHIFT);
-       if (IS_ERR(page)) {
-               ntfs_error(sb, "Failed to map index page, error %ld.",
-                               -PTR_ERR(page));
-               err = PTR_ERR(page);
-               goto err_out;
-       }
-       lock_page(page);
-       kaddr = (u8*)page_address(page);
-fast_descend_into_child_node:
-       /* Get to the index allocation block. */
-       ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
-                       idx_ni->itype.index.vcn_size_bits) & ~PAGE_MASK));
-       /* Bounds checks. */
-       if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) {
-               ntfs_error(sb, "Out of bounds check failed.  Corrupt inode "
-                               "0x%lx or driver bug.", idx_ni->mft_no);
-               goto unm_err_out;
-       }
-       /* Catch multi sector transfer fixup errors. */
-       if (unlikely(!ntfs_is_indx_record(ia->magic))) {
-               ntfs_error(sb, "Index record with vcn 0x%llx is corrupt.  "
-                               "Corrupt inode 0x%lx.  Run chkdsk.",
-                               (long long)vcn, idx_ni->mft_no);
-               goto unm_err_out;
-       }
-       if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
-               ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
-                               "different from expected VCN (0x%llx).  Inode "
-                               "0x%lx is corrupt or driver bug.",
-                               (unsigned long long)
-                               sle64_to_cpu(ia->index_block_vcn),
-                               (unsigned long long)vcn, idx_ni->mft_no);
-               goto unm_err_out;
-       }
-       if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
-                       idx_ni->itype.index.block_size) {
-               ntfs_error(sb, "Index buffer (VCN 0x%llx) of inode 0x%lx has "
-                               "a size (%u) differing from the index "
-                               "specified size (%u).  Inode is corrupt or "
-                               "driver bug.", (unsigned long long)vcn,
-                               idx_ni->mft_no,
-                               le32_to_cpu(ia->index.allocated_size) + 0x18,
-                               idx_ni->itype.index.block_size);
-               goto unm_err_out;
-       }
-       index_end = (u8*)ia + idx_ni->itype.index.block_size;
-       if (index_end > kaddr + PAGE_SIZE) {
-               ntfs_error(sb, "Index buffer (VCN 0x%llx) of inode 0x%lx "
-                               "crosses page boundary.  Impossible!  Cannot "
-                               "access!  This is probably a bug in the "
-                               "driver.", (unsigned long long)vcn,
-                               idx_ni->mft_no);
-               goto unm_err_out;
-       }
-       index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
-       if (index_end > (u8*)ia + idx_ni->itype.index.block_size) {
-               ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of inode "
-                               "0x%lx exceeds maximum size.",
-                               (unsigned long long)vcn, idx_ni->mft_no);
-               goto unm_err_out;
-       }
-       /* The first index entry. */
-       ie = (INDEX_ENTRY*)((u8*)&ia->index +
-                       le32_to_cpu(ia->index.entries_offset));
-       /*
-        * Iterate similar to above big loop but applied to index buffer, thus
-        * loop until we exceed valid memory (corruption case) or until we
-        * reach the last entry.
-        */
-       for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
-               /* Bounds checks. */
-               if ((u8*)ie < (u8*)ia || (u8*)ie +
-                               sizeof(INDEX_ENTRY_HEADER) > index_end ||
-                               (u8*)ie + le16_to_cpu(ie->length) > index_end) {
-                       ntfs_error(sb, "Index entry out of bounds in inode "
-                                       "0x%lx.", idx_ni->mft_no);
-                       goto unm_err_out;
-               }
-               /*
-                * The last entry cannot contain a key.  It can however contain
-                * a pointer to a child node in the B+tree so we just break out.
-                */
-               if (ie->flags & INDEX_ENTRY_END)
-                       break;
-               /* Further bounds checks. */
-               if ((u32)sizeof(INDEX_ENTRY_HEADER) +
-                               le16_to_cpu(ie->key_length) >
-                               le16_to_cpu(ie->data.vi.data_offset) ||
-                               (u32)le16_to_cpu(ie->data.vi.data_offset) +
-                               le16_to_cpu(ie->data.vi.data_length) >
-                               le16_to_cpu(ie->length)) {
-                       ntfs_error(sb, "Index entry out of bounds in inode "
-                                       "0x%lx.", idx_ni->mft_no);
-                       goto unm_err_out;
-               }
-               /* If the keys match perfectly, we setup @ictx and return 0. */
-               if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key,
-                               &ie->key, key_len)) {
-ia_done:
-                       ictx->is_in_root = false;
-                       ictx->actx = NULL;
-                       ictx->base_ni = NULL;
-                       ictx->ia = ia;
-                       ictx->page = page;
-                       goto done;
-               }
-               /*
-                * Not a perfect match, need to do full blown collation so we
-                * know which way in the B+tree we have to go.
-                */
-               rc = ntfs_collate(vol, idx_ni->itype.index.collation_rule, key,
-                               key_len, &ie->key, le16_to_cpu(ie->key_length));
-               /*
-                * If @key collates before the key of the current entry, there
-                * is definitely no such key in this index but we might need to
-                * descend into the B+tree so we just break out of the loop.
-                */
-               if (rc == -1)
-                       break;
-               /*
-                * A match should never happen as the memcmp() call should have
-                * cought it, but we still treat it correctly.
-                */
-               if (!rc)
-                       goto ia_done;
-               /* The keys are not equal, continue the search. */
-       }
-       /*
-        * We have finished with this index buffer without success.  Check for
-        * the presence of a child node and if not present return -ENOENT.
-        */
-       if (!(ie->flags & INDEX_ENTRY_NODE)) {
-               ntfs_debug("Entry not found.");
-               err = -ENOENT;
-               goto ia_done;
-       }
-       if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
-               ntfs_error(sb, "Index entry with child node found in a leaf "
-                               "node in inode 0x%lx.", idx_ni->mft_no);
-               goto unm_err_out;
-       }
-       /* Child node present, descend into it. */
-       old_vcn = vcn;
-       vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
-       if (vcn >= 0) {
-               /*
-                * If vcn is in the same page cache page as old_vcn we recycle
-                * the mapped page.
-                */
-               if (old_vcn << vol->cluster_size_bits >>
-                               PAGE_SHIFT == vcn <<
-                               vol->cluster_size_bits >>
-                               PAGE_SHIFT)
-                       goto fast_descend_into_child_node;
-               unlock_page(page);
-               ntfs_unmap_page(page);
-               goto descend_into_child_node;
-       }
-       ntfs_error(sb, "Negative child node vcn in inode 0x%lx.",
-                       idx_ni->mft_no);
-unm_err_out:
-       unlock_page(page);
-       ntfs_unmap_page(page);
-err_out:
-       if (!err)
-               err = -EIO;
-       if (actx)
-               ntfs_attr_put_search_ctx(actx);
-       if (m)
-               unmap_mft_record(base_ni);
-       return err;
-idx_err_out:
-       ntfs_error(sb, "Corrupt index.  Aborting lookup.");
-       goto err_out;
-}
diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h
deleted file mode 100644 (file)
index bb3c3ae..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * index.h - Defines for NTFS kernel index handling.  Part of the Linux-NTFS
- *          project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_INDEX_H
-#define _LINUX_NTFS_INDEX_H
-
-#include <linux/fs.h>
-
-#include "types.h"
-#include "layout.h"
-#include "inode.h"
-#include "attrib.h"
-#include "mft.h"
-#include "aops.h"
-
-/**
- * @idx_ni:    index inode containing the @entry described by this context
- * @entry:     index entry (points into @ir or @ia)
- * @data:      index entry data (points into @entry)
- * @data_len:  length in bytes of @data
- * @is_in_root:        'true' if @entry is in @ir and 'false' if it is in @ia
- * @ir:                index root if @is_in_root and NULL otherwise
- * @actx:      attribute search context if @is_in_root and NULL otherwise
- * @base_ni:   base inode if @is_in_root and NULL otherwise
- * @ia:                index block if @is_in_root is 'false' and NULL otherwise
- * @page:      page if @is_in_root is 'false' and NULL otherwise
- *
- * @idx_ni is the index inode this context belongs to.
- *
- * @entry is the index entry described by this context.  @data and @data_len
- * are the index entry data and its length in bytes, respectively.  @data
- * simply points into @entry.  This is probably what the user is interested in.
- *
- * If @is_in_root is 'true', @entry is in the index root attribute @ir described
- * by the attribute search context @actx and the base inode @base_ni.  @ia and
- * @page are NULL in this case.
- *
- * If @is_in_root is 'false', @entry is in the index allocation attribute and @ia
- * and @page point to the index allocation block and the mapped, locked page it
- * is in, respectively.  @ir, @actx and @base_ni are NULL in this case.
- *
- * To obtain a context call ntfs_index_ctx_get().
- *
- * We use this context to allow ntfs_index_lookup() to return the found index
- * @entry and its @data without having to allocate a buffer and copy the @entry
- * and/or its @data into it.
- *
- * When finished with the @entry and its @data, call ntfs_index_ctx_put() to
- * free the context and other associated resources.
- *
- * If the index entry was modified, call flush_dcache_index_entry_page()
- * immediately after the modification and either ntfs_index_entry_mark_dirty()
- * or ntfs_index_entry_write() before the call to ntfs_index_ctx_put() to
- * ensure that the changes are written to disk.
- */
-typedef struct {
-       ntfs_inode *idx_ni;
-       INDEX_ENTRY *entry;
-       void *data;
-       u16 data_len;
-       bool is_in_root;
-       INDEX_ROOT *ir;
-       ntfs_attr_search_ctx *actx;
-       ntfs_inode *base_ni;
-       INDEX_ALLOCATION *ia;
-       struct page *page;
-} ntfs_index_context;
-
-extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *idx_ni);
-extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
-
-extern int ntfs_index_lookup(const void *key, const int key_len,
-               ntfs_index_context *ictx);
-
-#ifdef NTFS_RW
-
-/**
- * ntfs_index_entry_flush_dcache_page - flush_dcache_page() for index entries
- * @ictx:      ntfs index context describing the index entry
- *
- * Call flush_dcache_page() for the page in which an index entry resides.
- *
- * This must be called every time an index entry is modified, just after the
- * modification.
- *
- * If the index entry is in the index root attribute, simply flush the page
- * containing the mft record containing the index root attribute.
- *
- * If the index entry is in an index block belonging to the index allocation
- * attribute, simply flush the page cache page containing the index block.
- */
-static inline void ntfs_index_entry_flush_dcache_page(ntfs_index_context *ictx)
-{
-       if (ictx->is_in_root)
-               flush_dcache_mft_record_page(ictx->actx->ntfs_ino);
-       else
-               flush_dcache_page(ictx->page);
-}
-
-/**
- * ntfs_index_entry_mark_dirty - mark an index entry dirty
- * @ictx:      ntfs index context describing the index entry
- *
- * Mark the index entry described by the index entry context @ictx dirty.
- *
- * If the index entry is in the index root attribute, simply mark the mft
- * record containing the index root attribute dirty.  This ensures the mft
- * record, and hence the index root attribute, will be written out to disk
- * later.
- *
- * If the index entry is in an index block belonging to the index allocation
- * attribute, mark the buffers belonging to the index record as well as the
- * page cache page the index block is in dirty.  This automatically marks the
- * VFS inode of the ntfs index inode to which the index entry belongs dirty,
- * too (I_DIRTY_PAGES) and this in turn ensures the page buffers, and hence the
- * dirty index block, will be written out to disk later.
- */
-static inline void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx)
-{
-       if (ictx->is_in_root)
-               mark_mft_record_dirty(ictx->actx->ntfs_ino);
-       else
-               mark_ntfs_record_dirty(ictx->page,
-                               (u8*)ictx->ia - (u8*)page_address(ictx->page));
-}
-
-#endif /* NTFS_RW */
-
-#endif /* _LINUX_NTFS_INDEX_H */
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
deleted file mode 100644 (file)
index aba1e22..0000000
+++ /dev/null
@@ -1,3102 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * inode.c - NTFS kernel inode handling.
- *
- * Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc.
- */
-
-#include <linux/buffer_head.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/mount.h>
-#include <linux/mutex.h>
-#include <linux/pagemap.h>
-#include <linux/quotaops.h>
-#include <linux/slab.h>
-#include <linux/log2.h>
-
-#include "aops.h"
-#include "attrib.h"
-#include "bitmap.h"
-#include "dir.h"
-#include "debug.h"
-#include "inode.h"
-#include "lcnalloc.h"
-#include "malloc.h"
-#include "mft.h"
-#include "time.h"
-#include "ntfs.h"
-
-/**
- * ntfs_test_inode - compare two (possibly fake) inodes for equality
- * @vi:                vfs inode which to test
- * @data:      data which is being tested with
- *
- * Compare the ntfs attribute embedded in the ntfs specific part of the vfs
- * inode @vi for equality with the ntfs attribute @data.
- *
- * If searching for the normal file/directory inode, set @na->type to AT_UNUSED.
- * @na->name and @na->name_len are then ignored.
- *
- * Return 1 if the attributes match and 0 if not.
- *
- * NOTE: This function runs with the inode_hash_lock spin lock held so it is not
- * allowed to sleep.
- */
-int ntfs_test_inode(struct inode *vi, void *data)
-{
-       ntfs_attr *na = (ntfs_attr *)data;
-       ntfs_inode *ni;
-
-       if (vi->i_ino != na->mft_no)
-               return 0;
-       ni = NTFS_I(vi);
-       /* If !NInoAttr(ni), @vi is a normal file or directory inode. */
-       if (likely(!NInoAttr(ni))) {
-               /* If not looking for a normal inode this is a mismatch. */
-               if (unlikely(na->type != AT_UNUSED))
-                       return 0;
-       } else {
-               /* A fake inode describing an attribute. */
-               if (ni->type != na->type)
-                       return 0;
-               if (ni->name_len != na->name_len)
-                       return 0;
-               if (na->name_len && memcmp(ni->name, na->name,
-                               na->name_len * sizeof(ntfschar)))
-                       return 0;
-       }
-       /* Match! */
-       return 1;
-}
-
-/**
- * ntfs_init_locked_inode - initialize an inode
- * @vi:                vfs inode to initialize
- * @data:      data which to initialize @vi to
- *
- * Initialize the vfs inode @vi with the values from the ntfs attribute @data in
- * order to enable ntfs_test_inode() to do its work.
- *
- * If initializing the normal file/directory inode, set @na->type to AT_UNUSED.
- * In that case, @na->name and @na->name_len should be set to NULL and 0,
- * respectively. Although that is not strictly necessary as
- * ntfs_read_locked_inode() will fill them in later.
- *
- * Return 0 on success and -errno on error.
- *
- * NOTE: This function runs with the inode->i_lock spin lock held so it is not
- * allowed to sleep. (Hence the GFP_ATOMIC allocation.)
- */
-static int ntfs_init_locked_inode(struct inode *vi, void *data)
-{
-       ntfs_attr *na = (ntfs_attr *)data;
-       ntfs_inode *ni = NTFS_I(vi);
-
-       vi->i_ino = na->mft_no;
-
-       ni->type = na->type;
-       if (na->type == AT_INDEX_ALLOCATION)
-               NInoSetMstProtected(ni);
-
-       ni->name = na->name;
-       ni->name_len = na->name_len;
-
-       /* If initializing a normal inode, we are done. */
-       if (likely(na->type == AT_UNUSED)) {
-               BUG_ON(na->name);
-               BUG_ON(na->name_len);
-               return 0;
-       }
-
-       /* It is a fake inode. */
-       NInoSetAttr(ni);
-
-       /*
-        * We have I30 global constant as an optimization as it is the name
-        * in >99.9% of named attributes! The other <0.1% incur a GFP_ATOMIC
-        * allocation but that is ok. And most attributes are unnamed anyway,
-        * thus the fraction of named attributes with name != I30 is actually
-        * absolutely tiny.
-        */
-       if (na->name_len && na->name != I30) {
-               unsigned int i;
-
-               BUG_ON(!na->name);
-               i = na->name_len * sizeof(ntfschar);
-               ni->name = kmalloc(i + sizeof(ntfschar), GFP_ATOMIC);
-               if (!ni->name)
-                       return -ENOMEM;
-               memcpy(ni->name, na->name, i);
-               ni->name[na->name_len] = 0;
-       }
-       return 0;
-}
-
-static int ntfs_read_locked_inode(struct inode *vi);
-static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi);
-static int ntfs_read_locked_index_inode(struct inode *base_vi,
-               struct inode *vi);
-
-/**
- * ntfs_iget - obtain a struct inode corresponding to a specific normal inode
- * @sb:                super block of mounted volume
- * @mft_no:    mft record number / inode number to obtain
- *
- * Obtain the struct inode corresponding to a specific normal inode (i.e. a
- * file or directory).
- *
- * If the inode is in the cache, it is just returned with an increased
- * reference count. Otherwise, a new struct inode is allocated and initialized,
- * and finally ntfs_read_locked_inode() is called to read in the inode and
- * fill in the remainder of the inode structure.
- *
- * Return the struct inode on success. Check the return value with IS_ERR() and
- * if true, the function failed and the error code is obtained from PTR_ERR().
- */
-struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no)
-{
-       struct inode *vi;
-       int err;
-       ntfs_attr na;
-
-       na.mft_no = mft_no;
-       na.type = AT_UNUSED;
-       na.name = NULL;
-       na.name_len = 0;
-
-       vi = iget5_locked(sb, mft_no, ntfs_test_inode,
-                       ntfs_init_locked_inode, &na);
-       if (unlikely(!vi))
-               return ERR_PTR(-ENOMEM);
-
-       err = 0;
-
-       /* If this is a freshly allocated inode, need to read it now. */
-       if (vi->i_state & I_NEW) {
-               err = ntfs_read_locked_inode(vi);
-               unlock_new_inode(vi);
-       }
-       /*
-        * There is no point in keeping bad inodes around if the failure was
-        * due to ENOMEM. We want to be able to retry again later.
-        */
-       if (unlikely(err == -ENOMEM)) {
-               iput(vi);
-               vi = ERR_PTR(err);
-       }
-       return vi;
-}
-
-/**
- * ntfs_attr_iget - obtain a struct inode corresponding to an attribute
- * @base_vi:   vfs base inode containing the attribute
- * @type:      attribute type
- * @name:      Unicode name of the attribute (NULL if unnamed)
- * @name_len:  length of @name in Unicode characters (0 if unnamed)
- *
- * Obtain the (fake) struct inode corresponding to the attribute specified by
- * @type, @name, and @name_len, which is present in the base mft record
- * specified by the vfs inode @base_vi.
- *
- * If the attribute inode is in the cache, it is just returned with an
- * increased reference count. Otherwise, a new struct inode is allocated and
- * initialized, and finally ntfs_read_locked_attr_inode() is called to read the
- * attribute and fill in the inode structure.
- *
- * Note, for index allocation attributes, you need to use ntfs_index_iget()
- * instead of ntfs_attr_iget() as working with indices is a lot more complex.
- *
- * Return the struct inode of the attribute inode on success. Check the return
- * value with IS_ERR() and if true, the function failed and the error code is
- * obtained from PTR_ERR().
- */
-struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPE type,
-               ntfschar *name, u32 name_len)
-{
-       struct inode *vi;
-       int err;
-       ntfs_attr na;
-
-       /* Make sure no one calls ntfs_attr_iget() for indices. */
-       BUG_ON(type == AT_INDEX_ALLOCATION);
-
-       na.mft_no = base_vi->i_ino;
-       na.type = type;
-       na.name = name;
-       na.name_len = name_len;
-
-       vi = iget5_locked(base_vi->i_sb, na.mft_no, ntfs_test_inode,
-                       ntfs_init_locked_inode, &na);
-       if (unlikely(!vi))
-               return ERR_PTR(-ENOMEM);
-
-       err = 0;
-
-       /* If this is a freshly allocated inode, need to read it now. */
-       if (vi->i_state & I_NEW) {
-               err = ntfs_read_locked_attr_inode(base_vi, vi);
-               unlock_new_inode(vi);
-       }
-       /*
-        * There is no point in keeping bad attribute inodes around. This also
-        * simplifies things in that we never need to check for bad attribute
-        * inodes elsewhere.
-        */
-       if (unlikely(err)) {
-               iput(vi);
-               vi = ERR_PTR(err);
-       }
-       return vi;
-}
-
-/**
- * ntfs_index_iget - obtain a struct inode corresponding to an index
- * @base_vi:   vfs base inode containing the index related attributes
- * @name:      Unicode name of the index
- * @name_len:  length of @name in Unicode characters
- *
- * Obtain the (fake) struct inode corresponding to the index specified by @name
- * and @name_len, which is present in the base mft record specified by the vfs
- * inode @base_vi.
- *
- * If the index inode is in the cache, it is just returned with an increased
- * reference count.  Otherwise, a new struct inode is allocated and
- * initialized, and finally ntfs_read_locked_index_inode() is called to read
- * the index related attributes and fill in the inode structure.
- *
- * Return the struct inode of the index inode on success. Check the return
- * value with IS_ERR() and if true, the function failed and the error code is
- * obtained from PTR_ERR().
- */
-struct inode *ntfs_index_iget(struct inode *base_vi, ntfschar *name,
-               u32 name_len)
-{
-       struct inode *vi;
-       int err;
-       ntfs_attr na;
-
-       na.mft_no = base_vi->i_ino;
-       na.type = AT_INDEX_ALLOCATION;
-       na.name = name;
-       na.name_len = name_len;
-
-       vi = iget5_locked(base_vi->i_sb, na.mft_no, ntfs_test_inode,
-                       ntfs_init_locked_inode, &na);
-       if (unlikely(!vi))
-               return ERR_PTR(-ENOMEM);
-
-       err = 0;
-
-       /* If this is a freshly allocated inode, need to read it now. */
-       if (vi->i_state & I_NEW) {
-               err = ntfs_read_locked_index_inode(base_vi, vi);
-               unlock_new_inode(vi);
-       }
-       /*
-        * There is no point in keeping bad index inodes around.  This also
-        * simplifies things in that we never need to check for bad index
-        * inodes elsewhere.
-        */
-       if (unlikely(err)) {
-               iput(vi);
-               vi = ERR_PTR(err);
-       }
-       return vi;
-}
-
-struct inode *ntfs_alloc_big_inode(struct super_block *sb)
-{
-       ntfs_inode *ni;
-
-       ntfs_debug("Entering.");
-       ni = alloc_inode_sb(sb, ntfs_big_inode_cache, GFP_NOFS);
-       if (likely(ni != NULL)) {
-               ni->state = 0;
-               return VFS_I(ni);
-       }
-       ntfs_error(sb, "Allocation of NTFS big inode structure failed.");
-       return NULL;
-}
-
-void ntfs_free_big_inode(struct inode *inode)
-{
-       kmem_cache_free(ntfs_big_inode_cache, NTFS_I(inode));
-}
-
-static inline ntfs_inode *ntfs_alloc_extent_inode(void)
-{
-       ntfs_inode *ni;
-
-       ntfs_debug("Entering.");
-       ni = kmem_cache_alloc(ntfs_inode_cache, GFP_NOFS);
-       if (likely(ni != NULL)) {
-               ni->state = 0;
-               return ni;
-       }
-       ntfs_error(NULL, "Allocation of NTFS inode structure failed.");
-       return NULL;
-}
-
-static void ntfs_destroy_extent_inode(ntfs_inode *ni)
-{
-       ntfs_debug("Entering.");
-       BUG_ON(ni->page);
-       if (!atomic_dec_and_test(&ni->count))
-               BUG();
-       kmem_cache_free(ntfs_inode_cache, ni);
-}
-
-/*
- * The attribute runlist lock has separate locking rules from the
- * normal runlist lock, so split the two lock-classes:
- */
-static struct lock_class_key attr_list_rl_lock_class;
-
-/**
- * __ntfs_init_inode - initialize ntfs specific part of an inode
- * @sb:                super block of mounted volume
- * @ni:                freshly allocated ntfs inode which to initialize
- *
- * Initialize an ntfs inode to defaults.
- *
- * NOTE: ni->mft_no, ni->state, ni->type, ni->name, and ni->name_len are left
- * untouched. Make sure to initialize them elsewhere.
- *
- * Return zero on success and -ENOMEM on error.
- */
-void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
-{
-       ntfs_debug("Entering.");
-       rwlock_init(&ni->size_lock);
-       ni->initialized_size = ni->allocated_size = 0;
-       ni->seq_no = 0;
-       atomic_set(&ni->count, 1);
-       ni->vol = NTFS_SB(sb);
-       ntfs_init_runlist(&ni->runlist);
-       mutex_init(&ni->mrec_lock);
-       ni->page = NULL;
-       ni->page_ofs = 0;
-       ni->attr_list_size = 0;
-       ni->attr_list = NULL;
-       ntfs_init_runlist(&ni->attr_list_rl);
-       lockdep_set_class(&ni->attr_list_rl.lock,
-                               &attr_list_rl_lock_class);
-       ni->itype.index.block_size = 0;
-       ni->itype.index.vcn_size = 0;
-       ni->itype.index.collation_rule = 0;
-       ni->itype.index.block_size_bits = 0;
-       ni->itype.index.vcn_size_bits = 0;
-       mutex_init(&ni->extent_lock);
-       ni->nr_extents = 0;
-       ni->ext.base_ntfs_ino = NULL;
-}
-
-/*
- * Extent inodes get MFT-mapped in a nested way, while the base inode
- * is still mapped. Teach this nesting to the lock validator by creating
- * a separate class for nested inode's mrec_lock's:
- */
-static struct lock_class_key extent_inode_mrec_lock_key;
-
-inline ntfs_inode *ntfs_new_extent_inode(struct super_block *sb,
-               unsigned long mft_no)
-{
-       ntfs_inode *ni = ntfs_alloc_extent_inode();
-
-       ntfs_debug("Entering.");
-       if (likely(ni != NULL)) {
-               __ntfs_init_inode(sb, ni);
-               lockdep_set_class(&ni->mrec_lock, &extent_inode_mrec_lock_key);
-               ni->mft_no = mft_no;
-               ni->type = AT_UNUSED;
-               ni->name = NULL;
-               ni->name_len = 0;
-       }
-       return ni;
-}
-
-/**
- * ntfs_is_extended_system_file - check if a file is in the $Extend directory
- * @ctx:       initialized attribute search context
- *
- * Search all file name attributes in the inode described by the attribute
- * search context @ctx and check if any of the names are in the $Extend system
- * directory.
- *
- * Return values:
- *        1: file is in $Extend directory
- *        0: file is not in $Extend directory
- *    -errno: failed to determine if the file is in the $Extend directory
- */
-static int ntfs_is_extended_system_file(ntfs_attr_search_ctx *ctx)
-{
-       int nr_links, err;
-
-       /* Restart search. */
-       ntfs_attr_reinit_search_ctx(ctx);
-
-       /* Get number of hard links. */
-       nr_links = le16_to_cpu(ctx->mrec->link_count);
-
-       /* Loop through all hard links. */
-       while (!(err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0,
-                       ctx))) {
-               FILE_NAME_ATTR *file_name_attr;
-               ATTR_RECORD *attr = ctx->attr;
-               u8 *p, *p2;
-
-               nr_links--;
-               /*
-                * Maximum sanity checking as we are called on an inode that
-                * we suspect might be corrupt.
-                */
-               p = (u8*)attr + le32_to_cpu(attr->length);
-               if (p < (u8*)ctx->mrec || (u8*)p > (u8*)ctx->mrec +
-                               le32_to_cpu(ctx->mrec->bytes_in_use)) {
-err_corrupt_attr:
-                       ntfs_error(ctx->ntfs_ino->vol->sb, "Corrupt file name "
-                                       "attribute. You should run chkdsk.");
-                       return -EIO;
-               }
-               if (attr->non_resident) {
-                       ntfs_error(ctx->ntfs_ino->vol->sb, "Non-resident file "
-                                       "name. You should run chkdsk.");
-                       return -EIO;
-               }
-               if (attr->flags) {
-                       ntfs_error(ctx->ntfs_ino->vol->sb, "File name with "
-                                       "invalid flags. You should run "
-                                       "chkdsk.");
-                       return -EIO;
-               }
-               if (!(attr->data.resident.flags & RESIDENT_ATTR_IS_INDEXED)) {
-                       ntfs_error(ctx->ntfs_ino->vol->sb, "Unindexed file "
-                                       "name. You should run chkdsk.");
-                       return -EIO;
-               }
-               file_name_attr = (FILE_NAME_ATTR*)((u8*)attr +
-                               le16_to_cpu(attr->data.resident.value_offset));
-               p2 = (u8 *)file_name_attr + le32_to_cpu(attr->data.resident.value_length);
-               if (p2 < (u8*)attr || p2 > p)
-                       goto err_corrupt_attr;
-               /* This attribute is ok, but is it in the $Extend directory? */
-               if (MREF_LE(file_name_attr->parent_directory) == FILE_Extend)
-                       return 1;       /* YES, it's an extended system file. */
-       }
-       if (unlikely(err != -ENOENT))
-               return err;
-       if (unlikely(nr_links)) {
-               ntfs_error(ctx->ntfs_ino->vol->sb, "Inode hard link count "
-                               "doesn't match number of name attributes. You "
-                               "should run chkdsk.");
-               return -EIO;
-       }
-       return 0;       /* NO, it is not an extended system file. */
-}
-
-/**
- * ntfs_read_locked_inode - read an inode from its device
- * @vi:                inode to read
- *
- * ntfs_read_locked_inode() is called from ntfs_iget() to read the inode
- * described by @vi into memory from the device.
- *
- * The only fields in @vi that we need to/can look at when the function is
- * called are i_sb, pointing to the mounted device's super block, and i_ino,
- * the number of the inode to load.
- *
- * ntfs_read_locked_inode() maps, pins and locks the mft record number i_ino
- * for reading and sets up the necessary @vi fields as well as initializing
- * the ntfs inode.
- *
- * Q: What locks are held when the function is called?
- * A: i_state has I_NEW set, hence the inode is locked, also
- *    i_count is set to 1, so it is not going to go away
- *    i_flags is set to 0 and we have no business touching it.  Only an ioctl()
- *    is allowed to write to them. We should of course be honouring them but
- *    we need to do that using the IS_* macros defined in include/linux/fs.h.
- *    In any case ntfs_read_locked_inode() has nothing to do with i_flags.
- *
- * Return 0 on success and -errno on error.  In the error case, the inode will
- * have had make_bad_inode() executed on it.
- */
-static int ntfs_read_locked_inode(struct inode *vi)
-{
-       ntfs_volume *vol = NTFS_SB(vi->i_sb);
-       ntfs_inode *ni;
-       struct inode *bvi;
-       MFT_RECORD *m;
-       ATTR_RECORD *a;
-       STANDARD_INFORMATION *si;
-       ntfs_attr_search_ctx *ctx;
-       int err = 0;
-
-       ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino);
-
-       /* Setup the generic vfs inode parts now. */
-       vi->i_uid = vol->uid;
-       vi->i_gid = vol->gid;
-       vi->i_mode = 0;
-
-       /*
-        * Initialize the ntfs specific part of @vi special casing
-        * FILE_MFT which we need to do at mount time.
-        */
-       if (vi->i_ino != FILE_MFT)
-               ntfs_init_big_inode(vi);
-       ni = NTFS_I(vi);
-
-       m = map_mft_record(ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               goto err_out;
-       }
-       ctx = ntfs_attr_get_search_ctx(ni, m);
-       if (!ctx) {
-               err = -ENOMEM;
-               goto unm_err_out;
-       }
-
-       if (!(m->flags & MFT_RECORD_IN_USE)) {
-               ntfs_error(vi->i_sb, "Inode is not in use!");
-               goto unm_err_out;
-       }
-       if (m->base_mft_record) {
-               ntfs_error(vi->i_sb, "Inode is an extent inode!");
-               goto unm_err_out;
-       }
-
-       /* Transfer information from mft record into vfs and ntfs inodes. */
-       vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
-
-       /*
-        * FIXME: Keep in mind that link_count is two for files which have both
-        * a long file name and a short file name as separate entries, so if
-        * we are hiding short file names this will be too high. Either we need
-        * to account for the short file names by subtracting them or we need
-        * to make sure we delete files even though i_nlink is not zero which
-        * might be tricky due to vfs interactions. Need to think about this
-        * some more when implementing the unlink command.
-        */
-       set_nlink(vi, le16_to_cpu(m->link_count));
-       /*
-        * FIXME: Reparse points can have the directory bit set even though
-        * they would be S_IFLNK. Need to deal with this further below when we
-        * implement reparse points / symbolic links but it will do for now.
-        * Also if not a directory, it could be something else, rather than
-        * a regular file. But again, will do for now.
-        */
-       /* Everyone gets all permissions. */
-       vi->i_mode |= S_IRWXUGO;
-       /* If read-only, no one gets write permissions. */
-       if (IS_RDONLY(vi))
-               vi->i_mode &= ~S_IWUGO;
-       if (m->flags & MFT_RECORD_IS_DIRECTORY) {
-               vi->i_mode |= S_IFDIR;
-               /*
-                * Apply the directory permissions mask set in the mount
-                * options.
-                */
-               vi->i_mode &= ~vol->dmask;
-               /* Things break without this kludge! */
-               if (vi->i_nlink > 1)
-                       set_nlink(vi, 1);
-       } else {
-               vi->i_mode |= S_IFREG;
-               /* Apply the file permissions mask set in the mount options. */
-               vi->i_mode &= ~vol->fmask;
-       }
-       /*
-        * Find the standard information attribute in the mft record. At this
-        * stage we haven't setup the attribute list stuff yet, so this could
-        * in fact fail if the standard information is in an extent record, but
-        * I don't think this actually ever happens.
-        */
-       err = ntfs_attr_lookup(AT_STANDARD_INFORMATION, NULL, 0, 0, 0, NULL, 0,
-                       ctx);
-       if (unlikely(err)) {
-               if (err == -ENOENT) {
-                       /*
-                        * TODO: We should be performing a hot fix here (if the
-                        * recover mount option is set) by creating a new
-                        * attribute.
-                        */
-                       ntfs_error(vi->i_sb, "$STANDARD_INFORMATION attribute "
-                                       "is missing.");
-               }
-               goto unm_err_out;
-       }
-       a = ctx->attr;
-       /* Get the standard information attribute value. */
-       if ((u8 *)a + le16_to_cpu(a->data.resident.value_offset)
-                       + le32_to_cpu(a->data.resident.value_length) >
-                       (u8 *)ctx->mrec + vol->mft_record_size) {
-               ntfs_error(vi->i_sb, "Corrupt standard information attribute in inode.");
-               goto unm_err_out;
-       }
-       si = (STANDARD_INFORMATION*)((u8*)a +
-                       le16_to_cpu(a->data.resident.value_offset));
-
-       /* Transfer information from the standard information into vi. */
-       /*
-        * Note: The i_?times do not quite map perfectly onto the NTFS times,
-        * but they are close enough, and in the end it doesn't really matter
-        * that much...
-        */
-       /*
-        * mtime is the last change of the data within the file. Not changed
-        * when only metadata is changed, e.g. a rename doesn't affect mtime.
-        */
-       inode_set_mtime_to_ts(vi, ntfs2utc(si->last_data_change_time));
-       /*
-        * ctime is the last change of the metadata of the file. This obviously
-        * always changes, when mtime is changed. ctime can be changed on its
-        * own, mtime is then not changed, e.g. when a file is renamed.
-        */
-       inode_set_ctime_to_ts(vi, ntfs2utc(si->last_mft_change_time));
-       /*
-        * Last access to the data within the file. Not changed during a rename
-        * for example but changed whenever the file is written to.
-        */
-       inode_set_atime_to_ts(vi, ntfs2utc(si->last_access_time));
-
-       /* Find the attribute list attribute if present. */
-       ntfs_attr_reinit_search_ctx(ctx);
-       err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx);
-       if (err) {
-               if (unlikely(err != -ENOENT)) {
-                       ntfs_error(vi->i_sb, "Failed to lookup attribute list "
-                                       "attribute.");
-                       goto unm_err_out;
-               }
-       } else /* if (!err) */ {
-               if (vi->i_ino == FILE_MFT)
-                       goto skip_attr_list_load;
-               ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino);
-               NInoSetAttrList(ni);
-               a = ctx->attr;
-               if (a->flags & ATTR_COMPRESSION_MASK) {
-                       ntfs_error(vi->i_sb, "Attribute list attribute is "
-                                       "compressed.");
-                       goto unm_err_out;
-               }
-               if (a->flags & ATTR_IS_ENCRYPTED ||
-                               a->flags & ATTR_IS_SPARSE) {
-                       if (a->non_resident) {
-                               ntfs_error(vi->i_sb, "Non-resident attribute "
-                                               "list attribute is encrypted/"
-                                               "sparse.");
-                               goto unm_err_out;
-                       }
-                       ntfs_warning(vi->i_sb, "Resident attribute list "
-                                       "attribute in inode 0x%lx is marked "
-                                       "encrypted/sparse which is not true.  "
-                                       "However, Windows allows this and "
-                                       "chkdsk does not detect or correct it "
-                                       "so we will just ignore the invalid "
-                                       "flags and pretend they are not set.",
-                                       vi->i_ino);
-               }
-               /* Now allocate memory for the attribute list. */
-               ni->attr_list_size = (u32)ntfs_attr_size(a);
-               ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);
-               if (!ni->attr_list) {
-                       ntfs_error(vi->i_sb, "Not enough memory to allocate "
-                                       "buffer for attribute list.");
-                       err = -ENOMEM;
-                       goto unm_err_out;
-               }
-               if (a->non_resident) {
-                       NInoSetAttrListNonResident(ni);
-                       if (a->data.non_resident.lowest_vcn) {
-                               ntfs_error(vi->i_sb, "Attribute list has non "
-                                               "zero lowest_vcn.");
-                               goto unm_err_out;
-                       }
-                       /*
-                        * Setup the runlist. No need for locking as we have
-                        * exclusive access to the inode at this time.
-                        */
-                       ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol,
-                                       a, NULL);
-                       if (IS_ERR(ni->attr_list_rl.rl)) {
-                               err = PTR_ERR(ni->attr_list_rl.rl);
-                               ni->attr_list_rl.rl = NULL;
-                               ntfs_error(vi->i_sb, "Mapping pairs "
-                                               "decompression failed.");
-                               goto unm_err_out;
-                       }
-                       /* Now load the attribute list. */
-                       if ((err = load_attribute_list(vol, &ni->attr_list_rl,
-                                       ni->attr_list, ni->attr_list_size,
-                                       sle64_to_cpu(a->data.non_resident.
-                                       initialized_size)))) {
-                               ntfs_error(vi->i_sb, "Failed to load "
-                                               "attribute list attribute.");
-                               goto unm_err_out;
-                       }
-               } else /* if (!a->non_resident) */ {
-                       if ((u8*)a + le16_to_cpu(a->data.resident.value_offset)
-                                       + le32_to_cpu(
-                                       a->data.resident.value_length) >
-                                       (u8*)ctx->mrec + vol->mft_record_size) {
-                               ntfs_error(vi->i_sb, "Corrupt attribute list "
-                                               "in inode.");
-                               goto unm_err_out;
-                       }
-                       /* Now copy the attribute list. */
-                       memcpy(ni->attr_list, (u8*)a + le16_to_cpu(
-                                       a->data.resident.value_offset),
-                                       le32_to_cpu(
-                                       a->data.resident.value_length));
-               }
-       }
-skip_attr_list_load:
-       /*
-        * If an attribute list is present we now have the attribute list value
-        * in ntfs_ino->attr_list and it is ntfs_ino->attr_list_size bytes.
-        */
-       if (S_ISDIR(vi->i_mode)) {
-               loff_t bvi_size;
-               ntfs_inode *bni;
-               INDEX_ROOT *ir;
-               u8 *ir_end, *index_end;
-
-               /* It is a directory, find index root attribute. */
-               ntfs_attr_reinit_search_ctx(ctx);
-               err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE,
-                               0, NULL, 0, ctx);
-               if (unlikely(err)) {
-                       if (err == -ENOENT) {
-                               // FIXME: File is corrupt! Hot-fix with empty
-                               // index root attribute if recovery option is
-                               // set.
-                               ntfs_error(vi->i_sb, "$INDEX_ROOT attribute "
-                                               "is missing.");
-                       }
-                       goto unm_err_out;
-               }
-               a = ctx->attr;
-               /* Set up the state. */
-               if (unlikely(a->non_resident)) {
-                       ntfs_error(vol->sb, "$INDEX_ROOT attribute is not "
-                                       "resident.");
-                       goto unm_err_out;
-               }
-               /* Ensure the attribute name is placed before the value. */
-               if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
-                               le16_to_cpu(a->data.resident.value_offset)))) {
-                       ntfs_error(vol->sb, "$INDEX_ROOT attribute name is "
-                                       "placed after the attribute value.");
-                       goto unm_err_out;
-               }
-               /*
-                * Compressed/encrypted index root just means that the newly
-                * created files in that directory should be created compressed/
-                * encrypted. However index root cannot be both compressed and
-                * encrypted.
-                */
-               if (a->flags & ATTR_COMPRESSION_MASK)
-                       NInoSetCompressed(ni);
-               if (a->flags & ATTR_IS_ENCRYPTED) {
-                       if (a->flags & ATTR_COMPRESSION_MASK) {
-                               ntfs_error(vi->i_sb, "Found encrypted and "
-                                               "compressed attribute.");
-                               goto unm_err_out;
-                       }
-                       NInoSetEncrypted(ni);
-               }
-               if (a->flags & ATTR_IS_SPARSE)
-                       NInoSetSparse(ni);
-               ir = (INDEX_ROOT*)((u8*)a +
-                               le16_to_cpu(a->data.resident.value_offset));
-               ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length);
-               if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) {
-                       ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
-                                       "corrupt.");
-                       goto unm_err_out;
-               }
-               index_end = (u8*)&ir->index +
-                               le32_to_cpu(ir->index.index_length);
-               if (index_end > ir_end) {
-                       ntfs_error(vi->i_sb, "Directory index is corrupt.");
-                       goto unm_err_out;
-               }
-               if (ir->type != AT_FILE_NAME) {
-                       ntfs_error(vi->i_sb, "Indexed attribute is not "
-                                       "$FILE_NAME.");
-                       goto unm_err_out;
-               }
-               if (ir->collation_rule != COLLATION_FILE_NAME) {
-                       ntfs_error(vi->i_sb, "Index collation rule is not "
-                                       "COLLATION_FILE_NAME.");
-                       goto unm_err_out;
-               }
-               ni->itype.index.collation_rule = ir->collation_rule;
-               ni->itype.index.block_size = le32_to_cpu(ir->index_block_size);
-               if (ni->itype.index.block_size &
-                               (ni->itype.index.block_size - 1)) {
-                       ntfs_error(vi->i_sb, "Index block size (%u) is not a "
-                                       "power of two.",
-                                       ni->itype.index.block_size);
-                       goto unm_err_out;
-               }
-               if (ni->itype.index.block_size > PAGE_SIZE) {
-                       ntfs_error(vi->i_sb, "Index block size (%u) > "
-                                       "PAGE_SIZE (%ld) is not "
-                                       "supported.  Sorry.",
-                                       ni->itype.index.block_size,
-                                       PAGE_SIZE);
-                       err = -EOPNOTSUPP;
-                       goto unm_err_out;
-               }
-               if (ni->itype.index.block_size < NTFS_BLOCK_SIZE) {
-                       ntfs_error(vi->i_sb, "Index block size (%u) < "
-                                       "NTFS_BLOCK_SIZE (%i) is not "
-                                       "supported.  Sorry.",
-                                       ni->itype.index.block_size,
-                                       NTFS_BLOCK_SIZE);
-                       err = -EOPNOTSUPP;
-                       goto unm_err_out;
-               }
-               ni->itype.index.block_size_bits =
-                               ffs(ni->itype.index.block_size) - 1;
-               /* Determine the size of a vcn in the directory index. */
-               if (vol->cluster_size <= ni->itype.index.block_size) {
-                       ni->itype.index.vcn_size = vol->cluster_size;
-                       ni->itype.index.vcn_size_bits = vol->cluster_size_bits;
-               } else {
-                       ni->itype.index.vcn_size = vol->sector_size;
-                       ni->itype.index.vcn_size_bits = vol->sector_size_bits;
-               }
-
-               /* Setup the index allocation attribute, even if not present. */
-               NInoSetMstProtected(ni);
-               ni->type = AT_INDEX_ALLOCATION;
-               ni->name = I30;
-               ni->name_len = 4;
-
-               if (!(ir->index.flags & LARGE_INDEX)) {
-                       /* No index allocation. */
-                       vi->i_size = ni->initialized_size =
-                                       ni->allocated_size = 0;
-                       /* We are done with the mft record, so we release it. */
-                       ntfs_attr_put_search_ctx(ctx);
-                       unmap_mft_record(ni);
-                       m = NULL;
-                       ctx = NULL;
-                       goto skip_large_dir_stuff;
-               } /* LARGE_INDEX: Index allocation present. Setup state. */
-               NInoSetIndexAllocPresent(ni);
-               /* Find index allocation attribute. */
-               ntfs_attr_reinit_search_ctx(ctx);
-               err = ntfs_attr_lookup(AT_INDEX_ALLOCATION, I30, 4,
-                               CASE_SENSITIVE, 0, NULL, 0, ctx);
-               if (unlikely(err)) {
-                       if (err == -ENOENT)
-                               ntfs_error(vi->i_sb, "$INDEX_ALLOCATION "
-                                               "attribute is not present but "
-                                               "$INDEX_ROOT indicated it is.");
-                       else
-                               ntfs_error(vi->i_sb, "Failed to lookup "
-                                               "$INDEX_ALLOCATION "
-                                               "attribute.");
-                       goto unm_err_out;
-               }
-               a = ctx->attr;
-               if (!a->non_resident) {
-                       ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
-                                       "is resident.");
-                       goto unm_err_out;
-               }
-               /*
-                * Ensure the attribute name is placed before the mapping pairs
-                * array.
-                */
-               if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
-                               le16_to_cpu(
-                               a->data.non_resident.mapping_pairs_offset)))) {
-                       ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name "
-                                       "is placed after the mapping pairs "
-                                       "array.");
-                       goto unm_err_out;
-               }
-               if (a->flags & ATTR_IS_ENCRYPTED) {
-                       ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
-                                       "is encrypted.");
-                       goto unm_err_out;
-               }
-               if (a->flags & ATTR_IS_SPARSE) {
-                       ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
-                                       "is sparse.");
-                       goto unm_err_out;
-               }
-               if (a->flags & ATTR_COMPRESSION_MASK) {
-                       ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
-                                       "is compressed.");
-                       goto unm_err_out;
-               }
-               if (a->data.non_resident.lowest_vcn) {
-                       ntfs_error(vi->i_sb, "First extent of "
-                                       "$INDEX_ALLOCATION attribute has non "
-                                       "zero lowest_vcn.");
-                       goto unm_err_out;
-               }
-               vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);
-               ni->initialized_size = sle64_to_cpu(
-                               a->data.non_resident.initialized_size);
-               ni->allocated_size = sle64_to_cpu(
-                               a->data.non_resident.allocated_size);
-               /*
-                * We are done with the mft record, so we release it. Otherwise
-                * we would deadlock in ntfs_attr_iget().
-                */
-               ntfs_attr_put_search_ctx(ctx);
-               unmap_mft_record(ni);
-               m = NULL;
-               ctx = NULL;
-               /* Get the index bitmap attribute inode. */
-               bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4);
-               if (IS_ERR(bvi)) {
-                       ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");
-                       err = PTR_ERR(bvi);
-                       goto unm_err_out;
-               }
-               bni = NTFS_I(bvi);
-               if (NInoCompressed(bni) || NInoEncrypted(bni) ||
-                               NInoSparse(bni)) {
-                       ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
-                                       "and/or encrypted and/or sparse.");
-                       goto iput_unm_err_out;
-               }
-               /* Consistency check bitmap size vs. index allocation size. */
-               bvi_size = i_size_read(bvi);
-               if ((bvi_size << 3) < (vi->i_size >>
-                               ni->itype.index.block_size_bits)) {
-                       ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) "
-                                       "for index allocation (0x%llx).",
-                                       bvi_size << 3, vi->i_size);
-                       goto iput_unm_err_out;
-               }
-               /* No longer need the bitmap attribute inode. */
-               iput(bvi);
-skip_large_dir_stuff:
-               /* Setup the operations for this inode. */
-               vi->i_op = &ntfs_dir_inode_ops;
-               vi->i_fop = &ntfs_dir_ops;
-               vi->i_mapping->a_ops = &ntfs_mst_aops;
-       } else {
-               /* It is a file. */
-               ntfs_attr_reinit_search_ctx(ctx);
-
-               /* Setup the data attribute, even if not present. */
-               ni->type = AT_DATA;
-               ni->name = NULL;
-               ni->name_len = 0;
-
-               /* Find first extent of the unnamed data attribute. */
-               err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx);
-               if (unlikely(err)) {
-                       vi->i_size = ni->initialized_size =
-                                       ni->allocated_size = 0;
-                       if (err != -ENOENT) {
-                               ntfs_error(vi->i_sb, "Failed to lookup $DATA "
-                                               "attribute.");
-                               goto unm_err_out;
-                       }
-                       /*
-                        * FILE_Secure does not have an unnamed $DATA
-                        * attribute, so we special case it here.
-                        */
-                       if (vi->i_ino == FILE_Secure)
-                               goto no_data_attr_special_case;
-                       /*
-                        * Most if not all the system files in the $Extend
-                        * system directory do not have unnamed data
-                        * attributes so we need to check if the parent
-                        * directory of the file is FILE_Extend and if it is
-                        * ignore this error. To do this we need to get the
-                        * name of this inode from the mft record as the name
-                        * contains the back reference to the parent directory.
-                        */
-                       if (ntfs_is_extended_system_file(ctx) > 0)
-                               goto no_data_attr_special_case;
-                       // FIXME: File is corrupt! Hot-fix with empty data
-                       // attribute if recovery option is set.
-                       ntfs_error(vi->i_sb, "$DATA attribute is missing.");
-                       goto unm_err_out;
-               }
-               a = ctx->attr;
-               /* Setup the state. */
-               if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) {
-                       if (a->flags & ATTR_COMPRESSION_MASK) {
-                               NInoSetCompressed(ni);
-                               if (vol->cluster_size > 4096) {
-                                       ntfs_error(vi->i_sb, "Found "
-                                                       "compressed data but "
-                                                       "compression is "
-                                                       "disabled due to "
-                                                       "cluster size (%i) > "
-                                                       "4kiB.",
-                                                       vol->cluster_size);
-                                       goto unm_err_out;
-                               }
-                               if ((a->flags & ATTR_COMPRESSION_MASK)
-                                               != ATTR_IS_COMPRESSED) {
-                                       ntfs_error(vi->i_sb, "Found unknown "
-                                                       "compression method "
-                                                       "or corrupt file.");
-                                       goto unm_err_out;
-                               }
-                       }
-                       if (a->flags & ATTR_IS_SPARSE)
-                               NInoSetSparse(ni);
-               }
-               if (a->flags & ATTR_IS_ENCRYPTED) {
-                       if (NInoCompressed(ni)) {
-                               ntfs_error(vi->i_sb, "Found encrypted and "
-                                               "compressed data.");
-                               goto unm_err_out;
-                       }
-                       NInoSetEncrypted(ni);
-               }
-               if (a->non_resident) {
-                       NInoSetNonResident(ni);
-                       if (NInoCompressed(ni) || NInoSparse(ni)) {
-                               if (NInoCompressed(ni) && a->data.non_resident.
-                                               compression_unit != 4) {
-                                       ntfs_error(vi->i_sb, "Found "
-                                                       "non-standard "
-                                                       "compression unit (%u "
-                                                       "instead of 4).  "
-                                                       "Cannot handle this.",
-                                                       a->data.non_resident.
-                                                       compression_unit);
-                                       err = -EOPNOTSUPP;
-                                       goto unm_err_out;
-                               }
-                               if (a->data.non_resident.compression_unit) {
-                                       ni->itype.compressed.block_size = 1U <<
-                                                       (a->data.non_resident.
-                                                       compression_unit +
-                                                       vol->cluster_size_bits);
-                                       ni->itype.compressed.block_size_bits =
-                                                       ffs(ni->itype.
-                                                       compressed.
-                                                       block_size) - 1;
-                                       ni->itype.compressed.block_clusters =
-                                                       1U << a->data.
-                                                       non_resident.
-                                                       compression_unit;
-                               } else {
-                                       ni->itype.compressed.block_size = 0;
-                                       ni->itype.compressed.block_size_bits =
-                                                       0;
-                                       ni->itype.compressed.block_clusters =
-                                                       0;
-                               }
-                               ni->itype.compressed.size = sle64_to_cpu(
-                                               a->data.non_resident.
-                                               compressed_size);
-                       }
-                       if (a->data.non_resident.lowest_vcn) {
-                               ntfs_error(vi->i_sb, "First extent of $DATA "
-                                               "attribute has non zero "
-                                               "lowest_vcn.");
-                               goto unm_err_out;
-                       }
-                       vi->i_size = sle64_to_cpu(
-                                       a->data.non_resident.data_size);
-                       ni->initialized_size = sle64_to_cpu(
-                                       a->data.non_resident.initialized_size);
-                       ni->allocated_size = sle64_to_cpu(
-                                       a->data.non_resident.allocated_size);
-               } else { /* Resident attribute. */
-                       vi->i_size = ni->initialized_size = le32_to_cpu(
-                                       a->data.resident.value_length);
-                       ni->allocated_size = le32_to_cpu(a->length) -
-                                       le16_to_cpu(
-                                       a->data.resident.value_offset);
-                       if (vi->i_size > ni->allocated_size) {
-                               ntfs_error(vi->i_sb, "Resident data attribute "
-                                               "is corrupt (size exceeds "
-                                               "allocation).");
-                               goto unm_err_out;
-                       }
-               }
-no_data_attr_special_case:
-               /* We are done with the mft record, so we release it. */
-               ntfs_attr_put_search_ctx(ctx);
-               unmap_mft_record(ni);
-               m = NULL;
-               ctx = NULL;
-               /* Setup the operations for this inode. */
-               vi->i_op = &ntfs_file_inode_ops;
-               vi->i_fop = &ntfs_file_ops;
-               vi->i_mapping->a_ops = &ntfs_normal_aops;
-               if (NInoMstProtected(ni))
-                       vi->i_mapping->a_ops = &ntfs_mst_aops;
-               else if (NInoCompressed(ni))
-                       vi->i_mapping->a_ops = &ntfs_compressed_aops;
-       }
-       /*
-        * The number of 512-byte blocks used on disk (for stat). This is in so
-        * far inaccurate as it doesn't account for any named streams or other
-        * special non-resident attributes, but that is how Windows works, too,
-        * so we are at least consistent with Windows, if not entirely
-        * consistent with the Linux Way. Doing it the Linux Way would cause a
-        * significant slowdown as it would involve iterating over all
-        * attributes in the mft record and adding the allocated/compressed
-        * sizes of all non-resident attributes present to give us the Linux
-        * correct size that should go into i_blocks (after division by 512).
-        */
-       if (S_ISREG(vi->i_mode) && (NInoCompressed(ni) || NInoSparse(ni)))
-               vi->i_blocks = ni->itype.compressed.size >> 9;
-       else
-               vi->i_blocks = ni->allocated_size >> 9;
-       ntfs_debug("Done.");
-       return 0;
-iput_unm_err_out:
-       iput(bvi);
-unm_err_out:
-       if (!err)
-               err = -EIO;
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(ni);
-err_out:
-       ntfs_error(vol->sb, "Failed with error code %i.  Marking corrupt "
-                       "inode 0x%lx as bad.  Run chkdsk.", err, vi->i_ino);
-       make_bad_inode(vi);
-       if (err != -EOPNOTSUPP && err != -ENOMEM)
-               NVolSetErrors(vol);
-       return err;
-}
-
-/**
- * ntfs_read_locked_attr_inode - read an attribute inode from its base inode
- * @base_vi:   base inode
- * @vi:                attribute inode to read
- *
- * ntfs_read_locked_attr_inode() is called from ntfs_attr_iget() to read the
- * attribute inode described by @vi into memory from the base mft record
- * described by @base_ni.
- *
- * ntfs_read_locked_attr_inode() maps, pins and locks the base inode for
- * reading and looks up the attribute described by @vi before setting up the
- * necessary fields in @vi as well as initializing the ntfs inode.
- *
- * Q: What locks are held when the function is called?
- * A: i_state has I_NEW set, hence the inode is locked, also
- *    i_count is set to 1, so it is not going to go away
- *
- * Return 0 on success and -errno on error.  In the error case, the inode will
- * have had make_bad_inode() executed on it.
- *
- * Note this cannot be called for AT_INDEX_ALLOCATION.
- */
-static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
-{
-       ntfs_volume *vol = NTFS_SB(vi->i_sb);
-       ntfs_inode *ni, *base_ni;
-       MFT_RECORD *m;
-       ATTR_RECORD *a;
-       ntfs_attr_search_ctx *ctx;
-       int err = 0;
-
-       ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino);
-
-       ntfs_init_big_inode(vi);
-
-       ni      = NTFS_I(vi);
-       base_ni = NTFS_I(base_vi);
-
-       /* Just mirror the values from the base inode. */
-       vi->i_uid       = base_vi->i_uid;
-       vi->i_gid       = base_vi->i_gid;
-       set_nlink(vi, base_vi->i_nlink);
-       inode_set_mtime_to_ts(vi, inode_get_mtime(base_vi));
-       inode_set_ctime_to_ts(vi, inode_get_ctime(base_vi));
-       inode_set_atime_to_ts(vi, inode_get_atime(base_vi));
-       vi->i_generation = ni->seq_no = base_ni->seq_no;
-
-       /* Set inode type to zero but preserve permissions. */
-       vi->i_mode      = base_vi->i_mode & ~S_IFMT;
-
-       m = map_mft_record(base_ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               goto err_out;
-       }
-       ctx = ntfs_attr_get_search_ctx(base_ni, m);
-       if (!ctx) {
-               err = -ENOMEM;
-               goto unm_err_out;
-       }
-       /* Find the attribute. */
-       err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err))
-               goto unm_err_out;
-       a = ctx->attr;
-       if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) {
-               if (a->flags & ATTR_COMPRESSION_MASK) {
-                       NInoSetCompressed(ni);
-                       if ((ni->type != AT_DATA) || (ni->type == AT_DATA &&
-                                       ni->name_len)) {
-                               ntfs_error(vi->i_sb, "Found compressed "
-                                               "non-data or named data "
-                                               "attribute.  Please report "
-                                               "you saw this message to "
-                                               "linux-ntfs-dev@lists."
-                                               "sourceforge.net");
-                               goto unm_err_out;
-                       }
-                       if (vol->cluster_size > 4096) {
-                               ntfs_error(vi->i_sb, "Found compressed "
-                                               "attribute but compression is "
-                                               "disabled due to cluster size "
-                                               "(%i) > 4kiB.",
-                                               vol->cluster_size);
-                               goto unm_err_out;
-                       }
-                       if ((a->flags & ATTR_COMPRESSION_MASK) !=
-                                       ATTR_IS_COMPRESSED) {
-                               ntfs_error(vi->i_sb, "Found unknown "
-                                               "compression method.");
-                               goto unm_err_out;
-                       }
-               }
-               /*
-                * The compressed/sparse flag set in an index root just means
-                * to compress all files.
-                */
-               if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) {
-                       ntfs_error(vi->i_sb, "Found mst protected attribute "
-                                       "but the attribute is %s.  Please "
-                                       "report you saw this message to "
-                                       "linux-ntfs-dev@lists.sourceforge.net",
-                                       NInoCompressed(ni) ? "compressed" :
-                                       "sparse");
-                       goto unm_err_out;
-               }
-               if (a->flags & ATTR_IS_SPARSE)
-                       NInoSetSparse(ni);
-       }
-       if (a->flags & ATTR_IS_ENCRYPTED) {
-               if (NInoCompressed(ni)) {
-                       ntfs_error(vi->i_sb, "Found encrypted and compressed "
-                                       "data.");
-                       goto unm_err_out;
-               }
-               /*
-                * The encryption flag set in an index root just means to
-                * encrypt all files.
-                */
-               if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) {
-                       ntfs_error(vi->i_sb, "Found mst protected attribute "
-                                       "but the attribute is encrypted.  "
-                                       "Please report you saw this message "
-                                       "to linux-ntfs-dev@lists.sourceforge."
-                                       "net");
-                       goto unm_err_out;
-               }
-               if (ni->type != AT_DATA) {
-                       ntfs_error(vi->i_sb, "Found encrypted non-data "
-                                       "attribute.");
-                       goto unm_err_out;
-               }
-               NInoSetEncrypted(ni);
-       }
-       if (!a->non_resident) {
-               /* Ensure the attribute name is placed before the value. */
-               if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
-                               le16_to_cpu(a->data.resident.value_offset)))) {
-                       ntfs_error(vol->sb, "Attribute name is placed after "
-                                       "the attribute value.");
-                       goto unm_err_out;
-               }
-               if (NInoMstProtected(ni)) {
-                       ntfs_error(vi->i_sb, "Found mst protected attribute "
-                                       "but the attribute is resident.  "
-                                       "Please report you saw this message to "
-                                       "linux-ntfs-dev@lists.sourceforge.net");
-                       goto unm_err_out;
-               }
-               vi->i_size = ni->initialized_size = le32_to_cpu(
-                               a->data.resident.value_length);
-               ni->allocated_size = le32_to_cpu(a->length) -
-                               le16_to_cpu(a->data.resident.value_offset);
-               if (vi->i_size > ni->allocated_size) {
-                       ntfs_error(vi->i_sb, "Resident attribute is corrupt "
-                                       "(size exceeds allocation).");
-                       goto unm_err_out;
-               }
-       } else {
-               NInoSetNonResident(ni);
-               /*
-                * Ensure the attribute name is placed before the mapping pairs
-                * array.
-                */
-               if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
-                               le16_to_cpu(
-                               a->data.non_resident.mapping_pairs_offset)))) {
-                       ntfs_error(vol->sb, "Attribute name is placed after "
-                                       "the mapping pairs array.");
-                       goto unm_err_out;
-               }
-               if (NInoCompressed(ni) || NInoSparse(ni)) {
-                       if (NInoCompressed(ni) && a->data.non_resident.
-                                       compression_unit != 4) {
-                               ntfs_error(vi->i_sb, "Found non-standard "
-                                               "compression unit (%u instead "
-                                               "of 4).  Cannot handle this.",
-                                               a->data.non_resident.
-                                               compression_unit);
-                               err = -EOPNOTSUPP;
-                               goto unm_err_out;
-                       }
-                       if (a->data.non_resident.compression_unit) {
-                               ni->itype.compressed.block_size = 1U <<
-                                               (a->data.non_resident.
-                                               compression_unit +
-                                               vol->cluster_size_bits);
-                               ni->itype.compressed.block_size_bits =
-                                               ffs(ni->itype.compressed.
-                                               block_size) - 1;
-                               ni->itype.compressed.block_clusters = 1U <<
-                                               a->data.non_resident.
-                                               compression_unit;
-                       } else {
-                               ni->itype.compressed.block_size = 0;
-                               ni->itype.compressed.block_size_bits = 0;
-                               ni->itype.compressed.block_clusters = 0;
-                       }
-                       ni->itype.compressed.size = sle64_to_cpu(
-                                       a->data.non_resident.compressed_size);
-               }
-               if (a->data.non_resident.lowest_vcn) {
-                       ntfs_error(vi->i_sb, "First extent of attribute has "
-                                       "non-zero lowest_vcn.");
-                       goto unm_err_out;
-               }
-               vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);
-               ni->initialized_size = sle64_to_cpu(
-                               a->data.non_resident.initialized_size);
-               ni->allocated_size = sle64_to_cpu(
-                               a->data.non_resident.allocated_size);
-       }
-       vi->i_mapping->a_ops = &ntfs_normal_aops;
-       if (NInoMstProtected(ni))
-               vi->i_mapping->a_ops = &ntfs_mst_aops;
-       else if (NInoCompressed(ni))
-               vi->i_mapping->a_ops = &ntfs_compressed_aops;
-       if ((NInoCompressed(ni) || NInoSparse(ni)) && ni->type != AT_INDEX_ROOT)
-               vi->i_blocks = ni->itype.compressed.size >> 9;
-       else
-               vi->i_blocks = ni->allocated_size >> 9;
-       /*
-        * Make sure the base inode does not go away and attach it to the
-        * attribute inode.
-        */
-       igrab(base_vi);
-       ni->ext.base_ntfs_ino = base_ni;
-       ni->nr_extents = -1;
-
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(base_ni);
-
-       ntfs_debug("Done.");
-       return 0;
-
-unm_err_out:
-       if (!err)
-               err = -EIO;
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(base_ni);
-err_out:
-       ntfs_error(vol->sb, "Failed with error code %i while reading attribute "
-                       "inode (mft_no 0x%lx, type 0x%x, name_len %i).  "
-                       "Marking corrupt inode and base inode 0x%lx as bad.  "
-                       "Run chkdsk.", err, vi->i_ino, ni->type, ni->name_len,
-                       base_vi->i_ino);
-       make_bad_inode(vi);
-       if (err != -ENOMEM)
-               NVolSetErrors(vol);
-       return err;
-}
-
-/**
- * ntfs_read_locked_index_inode - read an index inode from its base inode
- * @base_vi:   base inode
- * @vi:                index inode to read
- *
- * ntfs_read_locked_index_inode() is called from ntfs_index_iget() to read the
- * index inode described by @vi into memory from the base mft record described
- * by @base_ni.
- *
- * ntfs_read_locked_index_inode() maps, pins and locks the base inode for
- * reading and looks up the attributes relating to the index described by @vi
- * before setting up the necessary fields in @vi as well as initializing the
- * ntfs inode.
- *
- * Note, index inodes are essentially attribute inodes (NInoAttr() is true)
- * with the attribute type set to AT_INDEX_ALLOCATION.  Apart from that, they
- * are setup like directory inodes since directories are a special case of
- * indices ao they need to be treated in much the same way.  Most importantly,
- * for small indices the index allocation attribute might not actually exist.
- * However, the index root attribute always exists but this does not need to
- * have an inode associated with it and this is why we define a new inode type
- * index.  Also, like for directories, we need to have an attribute inode for
- * the bitmap attribute corresponding to the index allocation attribute and we
- * can store this in the appropriate field of the inode, just like we do for
- * normal directory inodes.
- *
- * Q: What locks are held when the function is called?
- * A: i_state has I_NEW set, hence the inode is locked, also
- *    i_count is set to 1, so it is not going to go away
- *
- * Return 0 on success and -errno on error.  In the error case, the inode will
- * have had make_bad_inode() executed on it.
- */
-static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
-{
-       loff_t bvi_size;
-       ntfs_volume *vol = NTFS_SB(vi->i_sb);
-       ntfs_inode *ni, *base_ni, *bni;
-       struct inode *bvi;
-       MFT_RECORD *m;
-       ATTR_RECORD *a;
-       ntfs_attr_search_ctx *ctx;
-       INDEX_ROOT *ir;
-       u8 *ir_end, *index_end;
-       int err = 0;
-
-       ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino);
-       ntfs_init_big_inode(vi);
-       ni      = NTFS_I(vi);
-       base_ni = NTFS_I(base_vi);
-       /* Just mirror the values from the base inode. */
-       vi->i_uid       = base_vi->i_uid;
-       vi->i_gid       = base_vi->i_gid;
-       set_nlink(vi, base_vi->i_nlink);
-       inode_set_mtime_to_ts(vi, inode_get_mtime(base_vi));
-       inode_set_ctime_to_ts(vi, inode_get_ctime(base_vi));
-       inode_set_atime_to_ts(vi, inode_get_atime(base_vi));
-       vi->i_generation = ni->seq_no = base_ni->seq_no;
-       /* Set inode type to zero but preserve permissions. */
-       vi->i_mode      = base_vi->i_mode & ~S_IFMT;
-       /* Map the mft record for the base inode. */
-       m = map_mft_record(base_ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               goto err_out;
-       }
-       ctx = ntfs_attr_get_search_ctx(base_ni, m);
-       if (!ctx) {
-               err = -ENOMEM;
-               goto unm_err_out;
-       }
-       /* Find the index root attribute. */
-       err = ntfs_attr_lookup(AT_INDEX_ROOT, ni->name, ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err)) {
-               if (err == -ENOENT)
-                       ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
-                                       "missing.");
-               goto unm_err_out;
-       }
-       a = ctx->attr;
-       /* Set up the state. */
-       if (unlikely(a->non_resident)) {
-               ntfs_error(vol->sb, "$INDEX_ROOT attribute is not resident.");
-               goto unm_err_out;
-       }
-       /* Ensure the attribute name is placed before the value. */
-       if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
-                       le16_to_cpu(a->data.resident.value_offset)))) {
-               ntfs_error(vol->sb, "$INDEX_ROOT attribute name is placed "
-                               "after the attribute value.");
-               goto unm_err_out;
-       }
-       /*
-        * Compressed/encrypted/sparse index root is not allowed, except for
-        * directories of course but those are not dealt with here.
-        */
-       if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED |
-                       ATTR_IS_SPARSE)) {
-               ntfs_error(vi->i_sb, "Found compressed/encrypted/sparse index "
-                               "root attribute.");
-               goto unm_err_out;
-       }
-       ir = (INDEX_ROOT*)((u8*)a + le16_to_cpu(a->data.resident.value_offset));
-       ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length);
-       if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) {
-               ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is corrupt.");
-               goto unm_err_out;
-       }
-       index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
-       if (index_end > ir_end) {
-               ntfs_error(vi->i_sb, "Index is corrupt.");
-               goto unm_err_out;
-       }
-       if (ir->type) {
-               ntfs_error(vi->i_sb, "Index type is not 0 (type is 0x%x).",
-                               le32_to_cpu(ir->type));
-               goto unm_err_out;
-       }
-       ni->itype.index.collation_rule = ir->collation_rule;
-       ntfs_debug("Index collation rule is 0x%x.",
-                       le32_to_cpu(ir->collation_rule));
-       ni->itype.index.block_size = le32_to_cpu(ir->index_block_size);
-       if (!is_power_of_2(ni->itype.index.block_size)) {
-               ntfs_error(vi->i_sb, "Index block size (%u) is not a power of "
-                               "two.", ni->itype.index.block_size);
-               goto unm_err_out;
-       }
-       if (ni->itype.index.block_size > PAGE_SIZE) {
-               ntfs_error(vi->i_sb, "Index block size (%u) > PAGE_SIZE "
-                               "(%ld) is not supported.  Sorry.",
-                               ni->itype.index.block_size, PAGE_SIZE);
-               err = -EOPNOTSUPP;
-               goto unm_err_out;
-       }
-       if (ni->itype.index.block_size < NTFS_BLOCK_SIZE) {
-               ntfs_error(vi->i_sb, "Index block size (%u) < NTFS_BLOCK_SIZE "
-                               "(%i) is not supported.  Sorry.",
-                               ni->itype.index.block_size, NTFS_BLOCK_SIZE);
-               err = -EOPNOTSUPP;
-               goto unm_err_out;
-       }
-       ni->itype.index.block_size_bits = ffs(ni->itype.index.block_size) - 1;
-       /* Determine the size of a vcn in the index. */
-       if (vol->cluster_size <= ni->itype.index.block_size) {
-               ni->itype.index.vcn_size = vol->cluster_size;
-               ni->itype.index.vcn_size_bits = vol->cluster_size_bits;
-       } else {
-               ni->itype.index.vcn_size = vol->sector_size;
-               ni->itype.index.vcn_size_bits = vol->sector_size_bits;
-       }
-       /* Check for presence of index allocation attribute. */
-       if (!(ir->index.flags & LARGE_INDEX)) {
-               /* No index allocation. */
-               vi->i_size = ni->initialized_size = ni->allocated_size = 0;
-               /* We are done with the mft record, so we release it. */
-               ntfs_attr_put_search_ctx(ctx);
-               unmap_mft_record(base_ni);
-               m = NULL;
-               ctx = NULL;
-               goto skip_large_index_stuff;
-       } /* LARGE_INDEX:  Index allocation present.  Setup state. */
-       NInoSetIndexAllocPresent(ni);
-       /* Find index allocation attribute. */
-       ntfs_attr_reinit_search_ctx(ctx);
-       err = ntfs_attr_lookup(AT_INDEX_ALLOCATION, ni->name, ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err)) {
-               if (err == -ENOENT)
-                       ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is "
-                                       "not present but $INDEX_ROOT "
-                                       "indicated it is.");
-               else
-                       ntfs_error(vi->i_sb, "Failed to lookup "
-                                       "$INDEX_ALLOCATION attribute.");
-               goto unm_err_out;
-       }
-       a = ctx->attr;
-       if (!a->non_resident) {
-               ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is "
-                               "resident.");
-               goto unm_err_out;
-       }
-       /*
-        * Ensure the attribute name is placed before the mapping pairs array.
-        */
-       if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
-                       le16_to_cpu(
-                       a->data.non_resident.mapping_pairs_offset)))) {
-               ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name is "
-                               "placed after the mapping pairs array.");
-               goto unm_err_out;
-       }
-       if (a->flags & ATTR_IS_ENCRYPTED) {
-               ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is "
-                               "encrypted.");
-               goto unm_err_out;
-       }
-       if (a->flags & ATTR_IS_SPARSE) {
-               ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is sparse.");
-               goto unm_err_out;
-       }
-       if (a->flags & ATTR_COMPRESSION_MASK) {
-               ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is "
-                               "compressed.");
-               goto unm_err_out;
-       }
-       if (a->data.non_resident.lowest_vcn) {
-               ntfs_error(vi->i_sb, "First extent of $INDEX_ALLOCATION "
-                               "attribute has non zero lowest_vcn.");
-               goto unm_err_out;
-       }
-       vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);
-       ni->initialized_size = sle64_to_cpu(
-                       a->data.non_resident.initialized_size);
-       ni->allocated_size = sle64_to_cpu(a->data.non_resident.allocated_size);
-       /*
-        * We are done with the mft record, so we release it.  Otherwise
-        * we would deadlock in ntfs_attr_iget().
-        */
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(base_ni);
-       m = NULL;
-       ctx = NULL;
-       /* Get the index bitmap attribute inode. */
-       bvi = ntfs_attr_iget(base_vi, AT_BITMAP, ni->name, ni->name_len);
-       if (IS_ERR(bvi)) {
-               ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");
-               err = PTR_ERR(bvi);
-               goto unm_err_out;
-       }
-       bni = NTFS_I(bvi);
-       if (NInoCompressed(bni) || NInoEncrypted(bni) ||
-                       NInoSparse(bni)) {
-               ntfs_error(vi->i_sb, "$BITMAP attribute is compressed and/or "
-                               "encrypted and/or sparse.");
-               goto iput_unm_err_out;
-       }
-       /* Consistency check bitmap size vs. index allocation size. */
-       bvi_size = i_size_read(bvi);
-       if ((bvi_size << 3) < (vi->i_size >> ni->itype.index.block_size_bits)) {
-               ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) for "
-                               "index allocation (0x%llx).", bvi_size << 3,
-                               vi->i_size);
-               goto iput_unm_err_out;
-       }
-       iput(bvi);
-skip_large_index_stuff:
-       /* Setup the operations for this index inode. */
-       vi->i_mapping->a_ops = &ntfs_mst_aops;
-       vi->i_blocks = ni->allocated_size >> 9;
-       /*
-        * Make sure the base inode doesn't go away and attach it to the
-        * index inode.
-        */
-       igrab(base_vi);
-       ni->ext.base_ntfs_ino = base_ni;
-       ni->nr_extents = -1;
-
-       ntfs_debug("Done.");
-       return 0;
-iput_unm_err_out:
-       iput(bvi);
-unm_err_out:
-       if (!err)
-               err = -EIO;
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(base_ni);
-err_out:
-       ntfs_error(vi->i_sb, "Failed with error code %i while reading index "
-                       "inode (mft_no 0x%lx, name_len %i.", err, vi->i_ino,
-                       ni->name_len);
-       make_bad_inode(vi);
-       if (err != -EOPNOTSUPP && err != -ENOMEM)
-               NVolSetErrors(vol);
-       return err;
-}
-
-/*
- * The MFT inode has special locking, so teach the lock validator
- * about this by splitting off the locking rules of the MFT from
- * the locking rules of other inodes. The MFT inode can never be
- * accessed from the VFS side (or even internally), only by the
- * map_mft functions.
- */
-static struct lock_class_key mft_ni_runlist_lock_key, mft_ni_mrec_lock_key;
-
-/**
- * ntfs_read_inode_mount - special read_inode for mount time use only
- * @vi:                inode to read
- *
- * Read inode FILE_MFT at mount time, only called with super_block lock
- * held from within the read_super() code path.
- *
- * This function exists because when it is called the page cache for $MFT/$DATA
- * is not initialized and hence we cannot get at the contents of mft records
- * by calling map_mft_record*().
- *
- * Further it needs to cope with the circular references problem, i.e. cannot
- * load any attributes other than $ATTRIBUTE_LIST until $DATA is loaded, because
- * we do not know where the other extent mft records are yet and again, because
- * we cannot call map_mft_record*() yet.  Obviously this applies only when an
- * attribute list is actually present in $MFT inode.
- *
- * We solve these problems by starting with the $DATA attribute before anything
- * else and iterating using ntfs_attr_lookup($DATA) over all extents.  As each
- * extent is found, we ntfs_mapping_pairs_decompress() including the implied
- * ntfs_runlists_merge().  Each step of the iteration necessarily provides
- * sufficient information for the next step to complete.
- *
- * This should work but there are two possible pit falls (see inline comments
- * below), but only time will tell if they are real pits or just smoke...
- */
-int ntfs_read_inode_mount(struct inode *vi)
-{
-       VCN next_vcn, last_vcn, highest_vcn;
-       s64 block;
-       struct super_block *sb = vi->i_sb;
-       ntfs_volume *vol = NTFS_SB(sb);
-       struct buffer_head *bh;
-       ntfs_inode *ni;
-       MFT_RECORD *m = NULL;
-       ATTR_RECORD *a;
-       ntfs_attr_search_ctx *ctx;
-       unsigned int i, nr_blocks;
-       int err;
-
-       ntfs_debug("Entering.");
-
-       /* Initialize the ntfs specific part of @vi. */
-       ntfs_init_big_inode(vi);
-
-       ni = NTFS_I(vi);
-
-       /* Setup the data attribute. It is special as it is mst protected. */
-       NInoSetNonResident(ni);
-       NInoSetMstProtected(ni);
-       NInoSetSparseDisabled(ni);
-       ni->type = AT_DATA;
-       ni->name = NULL;
-       ni->name_len = 0;
-       /*
-        * This sets up our little cheat allowing us to reuse the async read io
-        * completion handler for directories.
-        */
-       ni->itype.index.block_size = vol->mft_record_size;
-       ni->itype.index.block_size_bits = vol->mft_record_size_bits;
-
-       /* Very important! Needed to be able to call map_mft_record*(). */
-       vol->mft_ino = vi;
-
-       /* Allocate enough memory to read the first mft record. */
-       if (vol->mft_record_size > 64 * 1024) {
-               ntfs_error(sb, "Unsupported mft record size %i (max 64kiB).",
-                               vol->mft_record_size);
-               goto err_out;
-       }
-       i = vol->mft_record_size;
-       if (i < sb->s_blocksize)
-               i = sb->s_blocksize;
-       m = (MFT_RECORD*)ntfs_malloc_nofs(i);
-       if (!m) {
-               ntfs_error(sb, "Failed to allocate buffer for $MFT record 0.");
-               goto err_out;
-       }
-
-       /* Determine the first block of the $MFT/$DATA attribute. */
-       block = vol->mft_lcn << vol->cluster_size_bits >>
-                       sb->s_blocksize_bits;
-       nr_blocks = vol->mft_record_size >> sb->s_blocksize_bits;
-       if (!nr_blocks)
-               nr_blocks = 1;
-
-       /* Load $MFT/$DATA's first mft record. */
-       for (i = 0; i < nr_blocks; i++) {
-               bh = sb_bread(sb, block++);
-               if (!bh) {
-                       ntfs_error(sb, "Device read failed.");
-                       goto err_out;
-               }
-               memcpy((char*)m + (i << sb->s_blocksize_bits), bh->b_data,
-                               sb->s_blocksize);
-               brelse(bh);
-       }
-
-       if (le32_to_cpu(m->bytes_allocated) != vol->mft_record_size) {
-               ntfs_error(sb, "Incorrect mft record size %u in superblock, should be %u.",
-                               le32_to_cpu(m->bytes_allocated), vol->mft_record_size);
-               goto err_out;
-       }
-
-       /* Apply the mst fixups. */
-       if (post_read_mst_fixup((NTFS_RECORD*)m, vol->mft_record_size)) {
-               /* FIXME: Try to use the $MFTMirr now. */
-               ntfs_error(sb, "MST fixup failed. $MFT is corrupt.");
-               goto err_out;
-       }
-
-       /* Sanity check offset to the first attribute */
-       if (le16_to_cpu(m->attrs_offset) >= le32_to_cpu(m->bytes_allocated)) {
-               ntfs_error(sb, "Incorrect mft offset to the first attribute %u in superblock.",
-                              le16_to_cpu(m->attrs_offset));
-               goto err_out;
-       }
-
-       /* Need this to sanity check attribute list references to $MFT. */
-       vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
-
-       /* Provides read_folio() for map_mft_record(). */
-       vi->i_mapping->a_ops = &ntfs_mst_aops;
-
-       ctx = ntfs_attr_get_search_ctx(ni, m);
-       if (!ctx) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-
-       /* Find the attribute list attribute if present. */
-       err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx);
-       if (err) {
-               if (unlikely(err != -ENOENT)) {
-                       ntfs_error(sb, "Failed to lookup attribute list "
-                                       "attribute. You should run chkdsk.");
-                       goto put_err_out;
-               }
-       } else /* if (!err) */ {
-               ATTR_LIST_ENTRY *al_entry, *next_al_entry;
-               u8 *al_end;
-               static const char *es = "  Not allowed.  $MFT is corrupt.  "
-                               "You should run chkdsk.";
-
-               ntfs_debug("Attribute list attribute found in $MFT.");
-               NInoSetAttrList(ni);
-               a = ctx->attr;
-               if (a->flags & ATTR_COMPRESSION_MASK) {
-                       ntfs_error(sb, "Attribute list attribute is "
-                                       "compressed.%s", es);
-                       goto put_err_out;
-               }
-               if (a->flags & ATTR_IS_ENCRYPTED ||
-                               a->flags & ATTR_IS_SPARSE) {
-                       if (a->non_resident) {
-                               ntfs_error(sb, "Non-resident attribute list "
-                                               "attribute is encrypted/"
-                                               "sparse.%s", es);
-                               goto put_err_out;
-                       }
-                       ntfs_warning(sb, "Resident attribute list attribute "
-                                       "in $MFT system file is marked "
-                                       "encrypted/sparse which is not true.  "
-                                       "However, Windows allows this and "
-                                       "chkdsk does not detect or correct it "
-                                       "so we will just ignore the invalid "
-                                       "flags and pretend they are not set.");
-               }
-               /* Now allocate memory for the attribute list. */
-               ni->attr_list_size = (u32)ntfs_attr_size(a);
-               if (!ni->attr_list_size) {
-                       ntfs_error(sb, "Attr_list_size is zero");
-                       goto put_err_out;
-               }
-               ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);
-               if (!ni->attr_list) {
-                       ntfs_error(sb, "Not enough memory to allocate buffer "
-                                       "for attribute list.");
-                       goto put_err_out;
-               }
-               if (a->non_resident) {
-                       NInoSetAttrListNonResident(ni);
-                       if (a->data.non_resident.lowest_vcn) {
-                               ntfs_error(sb, "Attribute list has non zero "
-                                               "lowest_vcn. $MFT is corrupt. "
-                                               "You should run chkdsk.");
-                               goto put_err_out;
-                       }
-                       /* Setup the runlist. */
-                       ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol,
-                                       a, NULL);
-                       if (IS_ERR(ni->attr_list_rl.rl)) {
-                               err = PTR_ERR(ni->attr_list_rl.rl);
-                               ni->attr_list_rl.rl = NULL;
-                               ntfs_error(sb, "Mapping pairs decompression "
-                                               "failed with error code %i.",
-                                               -err);
-                               goto put_err_out;
-                       }
-                       /* Now load the attribute list. */
-                       if ((err = load_attribute_list(vol, &ni->attr_list_rl,
-                                       ni->attr_list, ni->attr_list_size,
-                                       sle64_to_cpu(a->data.
-                                       non_resident.initialized_size)))) {
-                               ntfs_error(sb, "Failed to load attribute list "
-                                               "attribute with error code %i.",
-                                               -err);
-                               goto put_err_out;
-                       }
-               } else /* if (!ctx.attr->non_resident) */ {
-                       if ((u8*)a + le16_to_cpu(
-                                       a->data.resident.value_offset) +
-                                       le32_to_cpu(
-                                       a->data.resident.value_length) >
-                                       (u8*)ctx->mrec + vol->mft_record_size) {
-                               ntfs_error(sb, "Corrupt attribute list "
-                                               "attribute.");
-                               goto put_err_out;
-                       }
-                       /* Now copy the attribute list. */
-                       memcpy(ni->attr_list, (u8*)a + le16_to_cpu(
-                                       a->data.resident.value_offset),
-                                       le32_to_cpu(
-                                       a->data.resident.value_length));
-               }
-               /* The attribute list is now setup in memory. */
-               /*
-                * FIXME: I don't know if this case is actually possible.
-                * According to logic it is not possible but I have seen too
-                * many weird things in MS software to rely on logic... Thus we
-                * perform a manual search and make sure the first $MFT/$DATA
-                * extent is in the base inode. If it is not we abort with an
-                * error and if we ever see a report of this error we will need
-                * to do some magic in order to have the necessary mft record
-                * loaded and in the right place in the page cache. But
-                * hopefully logic will prevail and this never happens...
-                */
-               al_entry = (ATTR_LIST_ENTRY*)ni->attr_list;
-               al_end = (u8*)al_entry + ni->attr_list_size;
-               for (;; al_entry = next_al_entry) {
-                       /* Out of bounds check. */
-                       if ((u8*)al_entry < ni->attr_list ||
-                                       (u8*)al_entry > al_end)
-                               goto em_put_err_out;
-                       /* Catch the end of the attribute list. */
-                       if ((u8*)al_entry == al_end)
-                               goto em_put_err_out;
-                       if (!al_entry->length)
-                               goto em_put_err_out;
-                       if ((u8*)al_entry + 6 > al_end || (u8*)al_entry +
-                                       le16_to_cpu(al_entry->length) > al_end)
-                               goto em_put_err_out;
-                       next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry +
-                                       le16_to_cpu(al_entry->length));
-                       if (le32_to_cpu(al_entry->type) > le32_to_cpu(AT_DATA))
-                               goto em_put_err_out;
-                       if (AT_DATA != al_entry->type)
-                               continue;
-                       /* We want an unnamed attribute. */
-                       if (al_entry->name_length)
-                               goto em_put_err_out;
-                       /* Want the first entry, i.e. lowest_vcn == 0. */
-                       if (al_entry->lowest_vcn)
-                               goto em_put_err_out;
-                       /* First entry has to be in the base mft record. */
-                       if (MREF_LE(al_entry->mft_reference) != vi->i_ino) {
-                               /* MFT references do not match, logic fails. */
-                               ntfs_error(sb, "BUG: The first $DATA extent "
-                                               "of $MFT is not in the base "
-                                               "mft record. Please report "
-                                               "you saw this message to "
-                                               "linux-ntfs-dev@lists."
-                                               "sourceforge.net");
-                               goto put_err_out;
-                       } else {
-                               /* Sequence numbers must match. */
-                               if (MSEQNO_LE(al_entry->mft_reference) !=
-                                               ni->seq_no)
-                                       goto em_put_err_out;
-                               /* Got it. All is ok. We can stop now. */
-                               break;
-                       }
-               }
-       }
-
-       ntfs_attr_reinit_search_ctx(ctx);
-
-       /* Now load all attribute extents. */
-       a = NULL;
-       next_vcn = last_vcn = highest_vcn = 0;
-       while (!(err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, next_vcn, NULL, 0,
-                       ctx))) {
-               runlist_element *nrl;
-
-               /* Cache the current attribute. */
-               a = ctx->attr;
-               /* $MFT must be non-resident. */
-               if (!a->non_resident) {
-                       ntfs_error(sb, "$MFT must be non-resident but a "
-                                       "resident extent was found. $MFT is "
-                                       "corrupt. Run chkdsk.");
-                       goto put_err_out;
-               }
-               /* $MFT must be uncompressed and unencrypted. */
-               if (a->flags & ATTR_COMPRESSION_MASK ||
-                               a->flags & ATTR_IS_ENCRYPTED ||
-                               a->flags & ATTR_IS_SPARSE) {
-                       ntfs_error(sb, "$MFT must be uncompressed, "
-                                       "non-sparse, and unencrypted but a "
-                                       "compressed/sparse/encrypted extent "
-                                       "was found. $MFT is corrupt. Run "
-                                       "chkdsk.");
-                       goto put_err_out;
-               }
-               /*
-                * Decompress the mapping pairs array of this extent and merge
-                * the result into the existing runlist. No need for locking
-                * as we have exclusive access to the inode at this time and we
-                * are a mount in progress task, too.
-                */
-               nrl = ntfs_mapping_pairs_decompress(vol, a, ni->runlist.rl);
-               if (IS_ERR(nrl)) {
-                       ntfs_error(sb, "ntfs_mapping_pairs_decompress() "
-                                       "failed with error code %ld.  $MFT is "
-                                       "corrupt.", PTR_ERR(nrl));
-                       goto put_err_out;
-               }
-               ni->runlist.rl = nrl;
-
-               /* Are we in the first extent? */
-               if (!next_vcn) {
-                       if (a->data.non_resident.lowest_vcn) {
-                               ntfs_error(sb, "First extent of $DATA "
-                                               "attribute has non zero "
-                                               "lowest_vcn. $MFT is corrupt. "
-                                               "You should run chkdsk.");
-                               goto put_err_out;
-                       }
-                       /* Get the last vcn in the $DATA attribute. */
-                       last_vcn = sle64_to_cpu(
-                                       a->data.non_resident.allocated_size)
-                                       >> vol->cluster_size_bits;
-                       /* Fill in the inode size. */
-                       vi->i_size = sle64_to_cpu(
-                                       a->data.non_resident.data_size);
-                       ni->initialized_size = sle64_to_cpu(
-                                       a->data.non_resident.initialized_size);
-                       ni->allocated_size = sle64_to_cpu(
-                                       a->data.non_resident.allocated_size);
-                       /*
-                        * Verify the number of mft records does not exceed
-                        * 2^32 - 1.
-                        */
-                       if ((vi->i_size >> vol->mft_record_size_bits) >=
-                                       (1ULL << 32)) {
-                               ntfs_error(sb, "$MFT is too big! Aborting.");
-                               goto put_err_out;
-                       }
-                       /*
-                        * We have got the first extent of the runlist for
-                        * $MFT which means it is now relatively safe to call
-                        * the normal ntfs_read_inode() function.
-                        * Complete reading the inode, this will actually
-                        * re-read the mft record for $MFT, this time entering
-                        * it into the page cache with which we complete the
-                        * kick start of the volume. It should be safe to do
-                        * this now as the first extent of $MFT/$DATA is
-                        * already known and we would hope that we don't need
-                        * further extents in order to find the other
-                        * attributes belonging to $MFT. Only time will tell if
-                        * this is really the case. If not we will have to play
-                        * magic at this point, possibly duplicating a lot of
-                        * ntfs_read_inode() at this point. We will need to
-                        * ensure we do enough of its work to be able to call
-                        * ntfs_read_inode() on extents of $MFT/$DATA. But lets
-                        * hope this never happens...
-                        */
-                       ntfs_read_locked_inode(vi);
-                       if (is_bad_inode(vi)) {
-                               ntfs_error(sb, "ntfs_read_inode() of $MFT "
-                                               "failed. BUG or corrupt $MFT. "
-                                               "Run chkdsk and if no errors "
-                                               "are found, please report you "
-                                               "saw this message to "
-                                               "linux-ntfs-dev@lists."
-                                               "sourceforge.net");
-                               ntfs_attr_put_search_ctx(ctx);
-                               /* Revert to the safe super operations. */
-                               ntfs_free(m);
-                               return -1;
-                       }
-                       /*
-                        * Re-initialize some specifics about $MFT's inode as
-                        * ntfs_read_inode() will have set up the default ones.
-                        */
-                       /* Set uid and gid to root. */
-                       vi->i_uid = GLOBAL_ROOT_UID;
-                       vi->i_gid = GLOBAL_ROOT_GID;
-                       /* Regular file. No access for anyone. */
-                       vi->i_mode = S_IFREG;
-                       /* No VFS initiated operations allowed for $MFT. */
-                       vi->i_op = &ntfs_empty_inode_ops;
-                       vi->i_fop = &ntfs_empty_file_ops;
-               }
-
-               /* Get the lowest vcn for the next extent. */
-               highest_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn);
-               next_vcn = highest_vcn + 1;
-
-               /* Only one extent or error, which we catch below. */
-               if (next_vcn <= 0)
-                       break;
-
-               /* Avoid endless loops due to corruption. */
-               if (next_vcn < sle64_to_cpu(
-                               a->data.non_resident.lowest_vcn)) {
-                       ntfs_error(sb, "$MFT has corrupt attribute list "
-                                       "attribute. Run chkdsk.");
-                       goto put_err_out;
-               }
-       }
-       if (err != -ENOENT) {
-               ntfs_error(sb, "Failed to lookup $MFT/$DATA attribute extent. "
-                               "$MFT is corrupt. Run chkdsk.");
-               goto put_err_out;
-       }
-       if (!a) {
-               ntfs_error(sb, "$MFT/$DATA attribute not found. $MFT is "
-                               "corrupt. Run chkdsk.");
-               goto put_err_out;
-       }
-       if (highest_vcn && highest_vcn != last_vcn - 1) {
-               ntfs_error(sb, "Failed to load the complete runlist for "
-                               "$MFT/$DATA. Driver bug or corrupt $MFT. "
-                               "Run chkdsk.");
-               ntfs_debug("highest_vcn = 0x%llx, last_vcn - 1 = 0x%llx",
-                               (unsigned long long)highest_vcn,
-                               (unsigned long long)last_vcn - 1);
-               goto put_err_out;
-       }
-       ntfs_attr_put_search_ctx(ctx);
-       ntfs_debug("Done.");
-       ntfs_free(m);
-
-       /*
-        * Split the locking rules of the MFT inode from the
-        * locking rules of other inodes:
-        */
-       lockdep_set_class(&ni->runlist.lock, &mft_ni_runlist_lock_key);
-       lockdep_set_class(&ni->mrec_lock, &mft_ni_mrec_lock_key);
-
-       return 0;
-
-em_put_err_out:
-       ntfs_error(sb, "Couldn't find first extent of $DATA attribute in "
-                       "attribute list. $MFT is corrupt. Run chkdsk.");
-put_err_out:
-       ntfs_attr_put_search_ctx(ctx);
-err_out:
-       ntfs_error(sb, "Failed. Marking inode as bad.");
-       make_bad_inode(vi);
-       ntfs_free(m);
-       return -1;
-}
-
-static void __ntfs_clear_inode(ntfs_inode *ni)
-{
-       /* Free all alocated memory. */
-       down_write(&ni->runlist.lock);
-       if (ni->runlist.rl) {
-               ntfs_free(ni->runlist.rl);
-               ni->runlist.rl = NULL;
-       }
-       up_write(&ni->runlist.lock);
-
-       if (ni->attr_list) {
-               ntfs_free(ni->attr_list);
-               ni->attr_list = NULL;
-       }
-
-       down_write(&ni->attr_list_rl.lock);
-       if (ni->attr_list_rl.rl) {
-               ntfs_free(ni->attr_list_rl.rl);
-               ni->attr_list_rl.rl = NULL;
-       }
-       up_write(&ni->attr_list_rl.lock);
-
-       if (ni->name_len && ni->name != I30) {
-               /* Catch bugs... */
-               BUG_ON(!ni->name);
-               kfree(ni->name);
-       }
-}
-
-void ntfs_clear_extent_inode(ntfs_inode *ni)
-{
-       ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
-
-       BUG_ON(NInoAttr(ni));
-       BUG_ON(ni->nr_extents != -1);
-
-#ifdef NTFS_RW
-       if (NInoDirty(ni)) {
-               if (!is_bad_inode(VFS_I(ni->ext.base_ntfs_ino)))
-                       ntfs_error(ni->vol->sb, "Clearing dirty extent inode!  "
-                                       "Losing data!  This is a BUG!!!");
-               // FIXME:  Do something!!!
-       }
-#endif /* NTFS_RW */
-
-       __ntfs_clear_inode(ni);
-
-       /* Bye, bye... */
-       ntfs_destroy_extent_inode(ni);
-}
-
-/**
- * ntfs_evict_big_inode - clean up the ntfs specific part of an inode
- * @vi:                vfs inode pending annihilation
- *
- * When the VFS is going to remove an inode from memory, ntfs_clear_big_inode()
- * is called, which deallocates all memory belonging to the NTFS specific part
- * of the inode and returns.
- *
- * If the MFT record is dirty, we commit it before doing anything else.
- */
-void ntfs_evict_big_inode(struct inode *vi)
-{
-       ntfs_inode *ni = NTFS_I(vi);
-
-       truncate_inode_pages_final(&vi->i_data);
-       clear_inode(vi);
-
-#ifdef NTFS_RW
-       if (NInoDirty(ni)) {
-               bool was_bad = (is_bad_inode(vi));
-
-               /* Committing the inode also commits all extent inodes. */
-               ntfs_commit_inode(vi);
-
-               if (!was_bad && (is_bad_inode(vi) || NInoDirty(ni))) {
-                       ntfs_error(vi->i_sb, "Failed to commit dirty inode "
-                                       "0x%lx.  Losing data!", vi->i_ino);
-                       // FIXME:  Do something!!!
-               }
-       }
-#endif /* NTFS_RW */
-
-       /* No need to lock at this stage as no one else has a reference. */
-       if (ni->nr_extents > 0) {
-               int i;
-
-               for (i = 0; i < ni->nr_extents; i++)
-                       ntfs_clear_extent_inode(ni->ext.extent_ntfs_inos[i]);
-               kfree(ni->ext.extent_ntfs_inos);
-       }
-
-       __ntfs_clear_inode(ni);
-
-       if (NInoAttr(ni)) {
-               /* Release the base inode if we are holding it. */
-               if (ni->nr_extents == -1) {
-                       iput(VFS_I(ni->ext.base_ntfs_ino));
-                       ni->nr_extents = 0;
-                       ni->ext.base_ntfs_ino = NULL;
-               }
-       }
-       BUG_ON(ni->page);
-       if (!atomic_dec_and_test(&ni->count))
-               BUG();
-       return;
-}
-
-/**
- * ntfs_show_options - show mount options in /proc/mounts
- * @sf:                seq_file in which to write our mount options
- * @root:      root of the mounted tree whose mount options to display
- *
- * Called by the VFS once for each mounted ntfs volume when someone reads
- * /proc/mounts in order to display the NTFS specific mount options of each
- * mount. The mount options of fs specified by @root are written to the seq file
- * @sf and success is returned.
- */
-int ntfs_show_options(struct seq_file *sf, struct dentry *root)
-{
-       ntfs_volume *vol = NTFS_SB(root->d_sb);
-       int i;
-
-       seq_printf(sf, ",uid=%i", from_kuid_munged(&init_user_ns, vol->uid));
-       seq_printf(sf, ",gid=%i", from_kgid_munged(&init_user_ns, vol->gid));
-       if (vol->fmask == vol->dmask)
-               seq_printf(sf, ",umask=0%o", vol->fmask);
-       else {
-               seq_printf(sf, ",fmask=0%o", vol->fmask);
-               seq_printf(sf, ",dmask=0%o", vol->dmask);
-       }
-       seq_printf(sf, ",nls=%s", vol->nls_map->charset);
-       if (NVolCaseSensitive(vol))
-               seq_printf(sf, ",case_sensitive");
-       if (NVolShowSystemFiles(vol))
-               seq_printf(sf, ",show_sys_files");
-       if (!NVolSparseEnabled(vol))
-               seq_printf(sf, ",disable_sparse");
-       for (i = 0; on_errors_arr[i].val; i++) {
-               if (on_errors_arr[i].val & vol->on_errors)
-                       seq_printf(sf, ",errors=%s", on_errors_arr[i].str);
-       }
-       seq_printf(sf, ",mft_zone_multiplier=%i", vol->mft_zone_multiplier);
-       return 0;
-}
-
-#ifdef NTFS_RW
-
-static const char *es = "  Leaving inconsistent metadata.  Unmount and run "
-               "chkdsk.";
-
-/**
- * ntfs_truncate - called when the i_size of an ntfs inode is changed
- * @vi:                inode for which the i_size was changed
- *
- * We only support i_size changes for normal files at present, i.e. not
- * compressed and not encrypted.  This is enforced in ntfs_setattr(), see
- * below.
- *
- * The kernel guarantees that @vi is a regular file (S_ISREG() is true) and
- * that the change is allowed.
- *
- * This implies for us that @vi is a file inode rather than a directory, index,
- * or attribute inode as well as that @vi is a base inode.
- *
- * Returns 0 on success or -errno on error.
- *
- * Called with ->i_mutex held.
- */
-int ntfs_truncate(struct inode *vi)
-{
-       s64 new_size, old_size, nr_freed, new_alloc_size, old_alloc_size;
-       VCN highest_vcn;
-       unsigned long flags;
-       ntfs_inode *base_ni, *ni = NTFS_I(vi);
-       ntfs_volume *vol = ni->vol;
-       ntfs_attr_search_ctx *ctx;
-       MFT_RECORD *m;
-       ATTR_RECORD *a;
-       const char *te = "  Leaving file length out of sync with i_size.";
-       int err, mp_size, size_change, alloc_change;
-
-       ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
-       BUG_ON(NInoAttr(ni));
-       BUG_ON(S_ISDIR(vi->i_mode));
-       BUG_ON(NInoMstProtected(ni));
-       BUG_ON(ni->nr_extents < 0);
-retry_truncate:
-       /*
-        * Lock the runlist for writing and map the mft record to ensure it is
-        * safe to mess with the attribute runlist and sizes.
-        */
-       down_write(&ni->runlist.lock);
-       if (!NInoAttr(ni))
-               base_ni = ni;
-       else
-               base_ni = ni->ext.base_ntfs_ino;
-       m = map_mft_record(base_ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               ntfs_error(vi->i_sb, "Failed to map mft record for inode 0x%lx "
-                               "(error code %d).%s", vi->i_ino, err, te);
-               ctx = NULL;
-               m = NULL;
-               goto old_bad_out;
-       }
-       ctx = ntfs_attr_get_search_ctx(base_ni, m);
-       if (unlikely(!ctx)) {
-               ntfs_error(vi->i_sb, "Failed to allocate a search context for "
-                               "inode 0x%lx (not enough memory).%s",
-                               vi->i_ino, te);
-               err = -ENOMEM;
-               goto old_bad_out;
-       }
-       err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err)) {
-               if (err == -ENOENT) {
-                       ntfs_error(vi->i_sb, "Open attribute is missing from "
-                                       "mft record.  Inode 0x%lx is corrupt.  "
-                                       "Run chkdsk.%s", vi->i_ino, te);
-                       err = -EIO;
-               } else
-                       ntfs_error(vi->i_sb, "Failed to lookup attribute in "
-                                       "inode 0x%lx (error code %d).%s",
-                                       vi->i_ino, err, te);
-               goto old_bad_out;
-       }
-       m = ctx->mrec;
-       a = ctx->attr;
-       /*
-        * The i_size of the vfs inode is the new size for the attribute value.
-        */
-       new_size = i_size_read(vi);
-       /* The current size of the attribute value is the old size. */
-       old_size = ntfs_attr_size(a);
-       /* Calculate the new allocated size. */
-       if (NInoNonResident(ni))
-               new_alloc_size = (new_size + vol->cluster_size - 1) &
-                               ~(s64)vol->cluster_size_mask;
-       else
-               new_alloc_size = (new_size + 7) & ~7;
-       /* The current allocated size is the old allocated size. */
-       read_lock_irqsave(&ni->size_lock, flags);
-       old_alloc_size = ni->allocated_size;
-       read_unlock_irqrestore(&ni->size_lock, flags);
-       /*
-        * The change in the file size.  This will be 0 if no change, >0 if the
-        * size is growing, and <0 if the size is shrinking.
-        */
-       size_change = -1;
-       if (new_size - old_size >= 0) {
-               size_change = 1;
-               if (new_size == old_size)
-                       size_change = 0;
-       }
-       /* As above for the allocated size. */
-       alloc_change = -1;
-       if (new_alloc_size - old_alloc_size >= 0) {
-               alloc_change = 1;
-               if (new_alloc_size == old_alloc_size)
-                       alloc_change = 0;
-       }
-       /*
-        * If neither the size nor the allocation are being changed there is
-        * nothing to do.
-        */
-       if (!size_change && !alloc_change)
-               goto unm_done;
-       /* If the size is changing, check if new size is allowed in $AttrDef. */
-       if (size_change) {
-               err = ntfs_attr_size_bounds_check(vol, ni->type, new_size);
-               if (unlikely(err)) {
-                       if (err == -ERANGE) {
-                               ntfs_error(vol->sb, "Truncate would cause the "
-                                               "inode 0x%lx to %simum size "
-                                               "for its attribute type "
-                                               "(0x%x).  Aborting truncate.",
-                                               vi->i_ino,
-                                               new_size > old_size ? "exceed "
-                                               "the max" : "go under the min",
-                                               le32_to_cpu(ni->type));
-                               err = -EFBIG;
-                       } else {
-                               ntfs_error(vol->sb, "Inode 0x%lx has unknown "
-                                               "attribute type 0x%x.  "
-                                               "Aborting truncate.",
-                                               vi->i_ino,
-                                               le32_to_cpu(ni->type));
-                               err = -EIO;
-                       }
-                       /* Reset the vfs inode size to the old size. */
-                       i_size_write(vi, old_size);
-                       goto err_out;
-               }
-       }
-       if (NInoCompressed(ni) || NInoEncrypted(ni)) {
-               ntfs_warning(vi->i_sb, "Changes in inode size are not "
-                               "supported yet for %s files, ignoring.",
-                               NInoCompressed(ni) ? "compressed" :
-                               "encrypted");
-               err = -EOPNOTSUPP;
-               goto bad_out;
-       }
-       if (a->non_resident)
-               goto do_non_resident_truncate;
-       BUG_ON(NInoNonResident(ni));
-       /* Resize the attribute record to best fit the new attribute size. */
-       if (new_size < vol->mft_record_size &&
-                       !ntfs_resident_attr_value_resize(m, a, new_size)) {
-               /* The resize succeeded! */
-               flush_dcache_mft_record_page(ctx->ntfs_ino);
-               mark_mft_record_dirty(ctx->ntfs_ino);
-               write_lock_irqsave(&ni->size_lock, flags);
-               /* Update the sizes in the ntfs inode and all is done. */
-               ni->allocated_size = le32_to_cpu(a->length) -
-                               le16_to_cpu(a->data.resident.value_offset);
-               /*
-                * Note ntfs_resident_attr_value_resize() has already done any
-                * necessary data clearing in the attribute record.  When the
-                * file is being shrunk vmtruncate() will already have cleared
-                * the top part of the last partial page, i.e. since this is
-                * the resident case this is the page with index 0.  However,
-                * when the file is being expanded, the page cache page data
-                * between the old data_size, i.e. old_size, and the new_size
-                * has not been zeroed.  Fortunately, we do not need to zero it
-                * either since on one hand it will either already be zero due
-                * to both read_folio and writepage clearing partial page data
-                * beyond i_size in which case there is nothing to do or in the
-                * case of the file being mmap()ped at the same time, POSIX
-                * specifies that the behaviour is unspecified thus we do not
-                * have to do anything.  This means that in our implementation
-                * in the rare case that the file is mmap()ped and a write
-                * occurred into the mmap()ped region just beyond the file size
-                * and writepage has not yet been called to write out the page
-                * (which would clear the area beyond the file size) and we now
-                * extend the file size to incorporate this dirty region
-                * outside the file size, a write of the page would result in
-                * this data being written to disk instead of being cleared.
-                * Given both POSIX and the Linux mmap(2) man page specify that
-                * this corner case is undefined, we choose to leave it like
-                * that as this is much simpler for us as we cannot lock the
-                * relevant page now since we are holding too many ntfs locks
-                * which would result in a lock reversal deadlock.
-                */
-               ni->initialized_size = new_size;
-               write_unlock_irqrestore(&ni->size_lock, flags);
-               goto unm_done;
-       }
-       /* If the above resize failed, this must be an attribute extension. */
-       BUG_ON(size_change < 0);
-       /*
-        * We have to drop all the locks so we can call
-        * ntfs_attr_make_non_resident().  This could be optimised by try-
-        * locking the first page cache page and only if that fails dropping
-        * the locks, locking the page, and redoing all the locking and
-        * lookups.  While this would be a huge optimisation, it is not worth
-        * it as this is definitely a slow code path as it only ever can happen
-        * once for any given file.
-        */
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(base_ni);
-       up_write(&ni->runlist.lock);
-       /*
-        * Not enough space in the mft record, try to make the attribute
-        * non-resident and if successful restart the truncation process.
-        */
-       err = ntfs_attr_make_non_resident(ni, old_size);
-       if (likely(!err))
-               goto retry_truncate;
-       /*
-        * Could not make non-resident.  If this is due to this not being
-        * permitted for this attribute type or there not being enough space,
-        * try to make other attributes non-resident.  Otherwise fail.
-        */
-       if (unlikely(err != -EPERM && err != -ENOSPC)) {
-               ntfs_error(vol->sb, "Cannot truncate inode 0x%lx, attribute "
-                               "type 0x%x, because the conversion from "
-                               "resident to non-resident attribute failed "
-                               "with error code %i.", vi->i_ino,
-                               (unsigned)le32_to_cpu(ni->type), err);
-               if (err != -ENOMEM)
-                       err = -EIO;
-               goto conv_err_out;
-       }
-       /* TODO: Not implemented from here, abort. */
-       if (err == -ENOSPC)
-               ntfs_error(vol->sb, "Not enough space in the mft record/on "
-                               "disk for the non-resident attribute value.  "
-                               "This case is not implemented yet.");
-       else /* if (err == -EPERM) */
-               ntfs_error(vol->sb, "This attribute type may not be "
-                               "non-resident.  This case is not implemented "
-                               "yet.");
-       err = -EOPNOTSUPP;
-       goto conv_err_out;
-#if 0
-       // TODO: Attempt to make other attributes non-resident.
-       if (!err)
-               goto do_resident_extend;
-       /*
-        * Both the attribute list attribute and the standard information
-        * attribute must remain in the base inode.  Thus, if this is one of
-        * these attributes, we have to try to move other attributes out into
-        * extent mft records instead.
-        */
-       if (ni->type == AT_ATTRIBUTE_LIST ||
-                       ni->type == AT_STANDARD_INFORMATION) {
-               // TODO: Attempt to move other attributes into extent mft
-               // records.
-               err = -EOPNOTSUPP;
-               if (!err)
-                       goto do_resident_extend;
-               goto err_out;
-       }
-       // TODO: Attempt to move this attribute to an extent mft record, but
-       // only if it is not already the only attribute in an mft record in
-       // which case there would be nothing to gain.
-       err = -EOPNOTSUPP;
-       if (!err)
-               goto do_resident_extend;
-       /* There is nothing we can do to make enough space. )-: */
-       goto err_out;
-#endif
-do_non_resident_truncate:
-       BUG_ON(!NInoNonResident(ni));
-       if (alloc_change < 0) {
-               highest_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn);
-               if (highest_vcn > 0 &&
-                               old_alloc_size >> vol->cluster_size_bits >
-                               highest_vcn + 1) {
-                       /*
-                        * This attribute has multiple extents.  Not yet
-                        * supported.
-                        */
-                       ntfs_error(vol->sb, "Cannot truncate inode 0x%lx, "
-                                       "attribute type 0x%x, because the "
-                                       "attribute is highly fragmented (it "
-                                       "consists of multiple extents) and "
-                                       "this case is not implemented yet.",
-                                       vi->i_ino,
-                                       (unsigned)le32_to_cpu(ni->type));
-                       err = -EOPNOTSUPP;
-                       goto bad_out;
-               }
-       }
-       /*
-        * If the size is shrinking, need to reduce the initialized_size and
-        * the data_size before reducing the allocation.
-        */
-       if (size_change < 0) {
-               /*
-                * Make the valid size smaller (i_size is already up-to-date).
-                */
-               write_lock_irqsave(&ni->size_lock, flags);
-               if (new_size < ni->initialized_size) {
-                       ni->initialized_size = new_size;
-                       a->data.non_resident.initialized_size =
-                                       cpu_to_sle64(new_size);
-               }
-               a->data.non_resident.data_size = cpu_to_sle64(new_size);
-               write_unlock_irqrestore(&ni->size_lock, flags);
-               flush_dcache_mft_record_page(ctx->ntfs_ino);
-               mark_mft_record_dirty(ctx->ntfs_ino);
-               /* If the allocated size is not changing, we are done. */
-               if (!alloc_change)
-                       goto unm_done;
-               /*
-                * If the size is shrinking it makes no sense for the
-                * allocation to be growing.
-                */
-               BUG_ON(alloc_change > 0);
-       } else /* if (size_change >= 0) */ {
-               /*
-                * The file size is growing or staying the same but the
-                * allocation can be shrinking, growing or staying the same.
-                */
-               if (alloc_change > 0) {
-                       /*
-                        * We need to extend the allocation and possibly update
-                        * the data size.  If we are updating the data size,
-                        * since we are not touching the initialized_size we do
-                        * not need to worry about the actual data on disk.
-                        * And as far as the page cache is concerned, there
-                        * will be no pages beyond the old data size and any
-                        * partial region in the last page between the old and
-                        * new data size (or the end of the page if the new
-                        * data size is outside the page) does not need to be
-                        * modified as explained above for the resident
-                        * attribute truncate case.  To do this, we simply drop
-                        * the locks we hold and leave all the work to our
-                        * friendly helper ntfs_attr_extend_allocation().
-                        */
-                       ntfs_attr_put_search_ctx(ctx);
-                       unmap_mft_record(base_ni);
-                       up_write(&ni->runlist.lock);
-                       err = ntfs_attr_extend_allocation(ni, new_size,
-                                       size_change > 0 ? new_size : -1, -1);
-                       /*
-                        * ntfs_attr_extend_allocation() will have done error
-                        * output already.
-                        */
-                       goto done;
-               }
-               if (!alloc_change)
-                       goto alloc_done;
-       }
-       /* alloc_change < 0 */
-       /* Free the clusters. */
-       nr_freed = ntfs_cluster_free(ni, new_alloc_size >>
-                       vol->cluster_size_bits, -1, ctx);
-       m = ctx->mrec;
-       a = ctx->attr;
-       if (unlikely(nr_freed < 0)) {
-               ntfs_error(vol->sb, "Failed to release cluster(s) (error code "
-                               "%lli).  Unmount and run chkdsk to recover "
-                               "the lost cluster(s).", (long long)nr_freed);
-               NVolSetErrors(vol);
-               nr_freed = 0;
-       }
-       /* Truncate the runlist. */
-       err = ntfs_rl_truncate_nolock(vol, &ni->runlist,
-                       new_alloc_size >> vol->cluster_size_bits);
-       /*
-        * If the runlist truncation failed and/or the search context is no
-        * longer valid, we cannot resize the attribute record or build the
-        * mapping pairs array thus we mark the inode bad so that no access to
-        * the freed clusters can happen.
-        */
-       if (unlikely(err || IS_ERR(m))) {
-               ntfs_error(vol->sb, "Failed to %s (error code %li).%s",
-                               IS_ERR(m) ?
-                               "restore attribute search context" :
-                               "truncate attribute runlist",
-                               IS_ERR(m) ? PTR_ERR(m) : err, es);
-               err = -EIO;
-               goto bad_out;
-       }
-       /* Get the size for the shrunk mapping pairs array for the runlist. */
-       mp_size = ntfs_get_size_for_mapping_pairs(vol, ni->runlist.rl, 0, -1);
-       if (unlikely(mp_size <= 0)) {
-               ntfs_error(vol->sb, "Cannot shrink allocation of inode 0x%lx, "
-                               "attribute type 0x%x, because determining the "
-                               "size for the mapping pairs failed with error "
-                               "code %i.%s", vi->i_ino,
-                               (unsigned)le32_to_cpu(ni->type), mp_size, es);
-               err = -EIO;
-               goto bad_out;
-       }
-       /*
-        * Shrink the attribute record for the new mapping pairs array.  Note,
-        * this cannot fail since we are making the attribute smaller thus by
-        * definition there is enough space to do so.
-        */
-       err = ntfs_attr_record_resize(m, a, mp_size +
-                       le16_to_cpu(a->data.non_resident.mapping_pairs_offset));
-       BUG_ON(err);
-       /*
-        * Generate the mapping pairs array directly into the attribute record.
-        */
-       err = ntfs_mapping_pairs_build(vol, (u8*)a +
-                       le16_to_cpu(a->data.non_resident.mapping_pairs_offset),
-                       mp_size, ni->runlist.rl, 0, -1, NULL);
-       if (unlikely(err)) {
-               ntfs_error(vol->sb, "Cannot shrink allocation of inode 0x%lx, "
-                               "attribute type 0x%x, because building the "
-                               "mapping pairs failed with error code %i.%s",
-                               vi->i_ino, (unsigned)le32_to_cpu(ni->type),
-                               err, es);
-               err = -EIO;
-               goto bad_out;
-       }
-       /* Update the allocated/compressed size as well as the highest vcn. */
-       a->data.non_resident.highest_vcn = cpu_to_sle64((new_alloc_size >>
-                       vol->cluster_size_bits) - 1);
-       write_lock_irqsave(&ni->size_lock, flags);
-       ni->allocated_size = new_alloc_size;
-       a->data.non_resident.allocated_size = cpu_to_sle64(new_alloc_size);
-       if (NInoSparse(ni) || NInoCompressed(ni)) {
-               if (nr_freed) {
-                       ni->itype.compressed.size -= nr_freed <<
-                                       vol->cluster_size_bits;
-                       BUG_ON(ni->itype.compressed.size < 0);
-                       a->data.non_resident.compressed_size = cpu_to_sle64(
-                                       ni->itype.compressed.size);
-                       vi->i_blocks = ni->itype.compressed.size >> 9;
-               }
-       } else
-               vi->i_blocks = new_alloc_size >> 9;
-       write_unlock_irqrestore(&ni->size_lock, flags);
-       /*
-        * We have shrunk the allocation.  If this is a shrinking truncate we
-        * have already dealt with the initialized_size and the data_size above
-        * and we are done.  If the truncate is only changing the allocation
-        * and not the data_size, we are also done.  If this is an extending
-        * truncate, need to extend the data_size now which is ensured by the
-        * fact that @size_change is positive.
-        */
-alloc_done:
-       /*
-        * If the size is growing, need to update it now.  If it is shrinking,
-        * we have already updated it above (before the allocation change).
-        */
-       if (size_change > 0)
-               a->data.non_resident.data_size = cpu_to_sle64(new_size);
-       /* Ensure the modified mft record is written out. */
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-unm_done:
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(base_ni);
-       up_write(&ni->runlist.lock);
-done:
-       /* Update the mtime and ctime on the base inode. */
-       /* normally ->truncate shouldn't update ctime or mtime,
-        * but ntfs did before so it got a copy & paste version
-        * of file_update_time.  one day someone should fix this
-        * for real.
-        */
-       if (!IS_NOCMTIME(VFS_I(base_ni)) && !IS_RDONLY(VFS_I(base_ni))) {
-               struct timespec64 now = current_time(VFS_I(base_ni));
-               struct timespec64 ctime = inode_get_ctime(VFS_I(base_ni));
-               struct timespec64 mtime = inode_get_mtime(VFS_I(base_ni));
-               int sync_it = 0;
-
-               if (!timespec64_equal(&mtime, &now) ||
-                   !timespec64_equal(&ctime, &now))
-                       sync_it = 1;
-               inode_set_ctime_to_ts(VFS_I(base_ni), now);
-               inode_set_mtime_to_ts(VFS_I(base_ni), now);
-
-               if (sync_it)
-                       mark_inode_dirty_sync(VFS_I(base_ni));
-       }
-
-       if (likely(!err)) {
-               NInoClearTruncateFailed(ni);
-               ntfs_debug("Done.");
-       }
-       return err;
-old_bad_out:
-       old_size = -1;
-bad_out:
-       if (err != -ENOMEM && err != -EOPNOTSUPP)
-               NVolSetErrors(vol);
-       if (err != -EOPNOTSUPP)
-               NInoSetTruncateFailed(ni);
-       else if (old_size >= 0)
-               i_size_write(vi, old_size);
-err_out:
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(base_ni);
-       up_write(&ni->runlist.lock);
-out:
-       ntfs_debug("Failed.  Returning error code %i.", err);
-       return err;
-conv_err_out:
-       if (err != -ENOMEM && err != -EOPNOTSUPP)
-               NVolSetErrors(vol);
-       if (err != -EOPNOTSUPP)
-               NInoSetTruncateFailed(ni);
-       else
-               i_size_write(vi, old_size);
-       goto out;
-}
-
-/**
- * ntfs_truncate_vfs - wrapper for ntfs_truncate() that has no return value
- * @vi:                inode for which the i_size was changed
- *
- * Wrapper for ntfs_truncate() that has no return value.
- *
- * See ntfs_truncate() description above for details.
- */
-#ifdef NTFS_RW
-void ntfs_truncate_vfs(struct inode *vi) {
-       ntfs_truncate(vi);
-}
-#endif
-
-/**
- * ntfs_setattr - called from notify_change() when an attribute is being changed
- * @idmap:     idmap of the mount the inode was found from
- * @dentry:    dentry whose attributes to change
- * @attr:      structure describing the attributes and the changes
- *
- * We have to trap VFS attempts to truncate the file described by @dentry as
- * soon as possible, because we do not implement changes in i_size yet.  So we
- * abort all i_size changes here.
- *
- * We also abort all changes of user, group, and mode as we do not implement
- * the NTFS ACLs yet.
- *
- * Called with ->i_mutex held.
- */
-int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
-                struct iattr *attr)
-{
-       struct inode *vi = d_inode(dentry);
-       int err;
-       unsigned int ia_valid = attr->ia_valid;
-
-       err = setattr_prepare(&nop_mnt_idmap, dentry, attr);
-       if (err)
-               goto out;
-       /* We do not support NTFS ACLs yet. */
-       if (ia_valid & (ATTR_UID | ATTR_GID | ATTR_MODE)) {
-               ntfs_warning(vi->i_sb, "Changes in user/group/mode are not "
-                               "supported yet, ignoring.");
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-       if (ia_valid & ATTR_SIZE) {
-               if (attr->ia_size != i_size_read(vi)) {
-                       ntfs_inode *ni = NTFS_I(vi);
-                       /*
-                        * FIXME: For now we do not support resizing of
-                        * compressed or encrypted files yet.
-                        */
-                       if (NInoCompressed(ni) || NInoEncrypted(ni)) {
-                               ntfs_warning(vi->i_sb, "Changes in inode size "
-                                               "are not supported yet for "
-                                               "%s files, ignoring.",
-                                               NInoCompressed(ni) ?
-                                               "compressed" : "encrypted");
-                               err = -EOPNOTSUPP;
-                       } else {
-                               truncate_setsize(vi, attr->ia_size);
-                               ntfs_truncate_vfs(vi);
-                       }
-                       if (err || ia_valid == ATTR_SIZE)
-                               goto out;
-               } else {
-                       /*
-                        * We skipped the truncate but must still update
-                        * timestamps.
-                        */
-                       ia_valid |= ATTR_MTIME | ATTR_CTIME;
-               }
-       }
-       if (ia_valid & ATTR_ATIME)
-               inode_set_atime_to_ts(vi, attr->ia_atime);
-       if (ia_valid & ATTR_MTIME)
-               inode_set_mtime_to_ts(vi, attr->ia_mtime);
-       if (ia_valid & ATTR_CTIME)
-               inode_set_ctime_to_ts(vi, attr->ia_ctime);
-       mark_inode_dirty(vi);
-out:
-       return err;
-}
-
-/**
- * __ntfs_write_inode - write out a dirty inode
- * @vi:                inode to write out
- * @sync:      if true, write out synchronously
- *
- * Write out a dirty inode to disk including any extent inodes if present.
- *
- * If @sync is true, commit the inode to disk and wait for io completion.  This
- * is done using write_mft_record().
- *
- * If @sync is false, just schedule the write to happen but do not wait for i/o
- * completion.  In 2.6 kernels, scheduling usually happens just by virtue of
- * marking the page (and in this case mft record) dirty but we do not implement
- * this yet as write_mft_record() largely ignores the @sync parameter and
- * always performs synchronous writes.
- *
- * Return 0 on success and -errno on error.
- */
-int __ntfs_write_inode(struct inode *vi, int sync)
-{
-       sle64 nt;
-       ntfs_inode *ni = NTFS_I(vi);
-       ntfs_attr_search_ctx *ctx;
-       MFT_RECORD *m;
-       STANDARD_INFORMATION *si;
-       int err = 0;
-       bool modified = false;
-
-       ntfs_debug("Entering for %sinode 0x%lx.", NInoAttr(ni) ? "attr " : "",
-                       vi->i_ino);
-       /*
-        * Dirty attribute inodes are written via their real inodes so just
-        * clean them here.  Access time updates are taken care off when the
-        * real inode is written.
-        */
-       if (NInoAttr(ni)) {
-               NInoClearDirty(ni);
-               ntfs_debug("Done.");
-               return 0;
-       }
-       /* Map, pin, and lock the mft record belonging to the inode. */
-       m = map_mft_record(ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               goto err_out;
-       }
-       /* Update the access times in the standard information attribute. */
-       ctx = ntfs_attr_get_search_ctx(ni, m);
-       if (unlikely(!ctx)) {
-               err = -ENOMEM;
-               goto unm_err_out;
-       }
-       err = ntfs_attr_lookup(AT_STANDARD_INFORMATION, NULL, 0,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err)) {
-               ntfs_attr_put_search_ctx(ctx);
-               goto unm_err_out;
-       }
-       si = (STANDARD_INFORMATION*)((u8*)ctx->attr +
-                       le16_to_cpu(ctx->attr->data.resident.value_offset));
-       /* Update the access times if they have changed. */
-       nt = utc2ntfs(inode_get_mtime(vi));
-       if (si->last_data_change_time != nt) {
-               ntfs_debug("Updating mtime for inode 0x%lx: old = 0x%llx, "
-                               "new = 0x%llx", vi->i_ino, (long long)
-                               sle64_to_cpu(si->last_data_change_time),
-                               (long long)sle64_to_cpu(nt));
-               si->last_data_change_time = nt;
-               modified = true;
-       }
-       nt = utc2ntfs(inode_get_ctime(vi));
-       if (si->last_mft_change_time != nt) {
-               ntfs_debug("Updating ctime for inode 0x%lx: old = 0x%llx, "
-                               "new = 0x%llx", vi->i_ino, (long long)
-                               sle64_to_cpu(si->last_mft_change_time),
-                               (long long)sle64_to_cpu(nt));
-               si->last_mft_change_time = nt;
-               modified = true;
-       }
-       nt = utc2ntfs(inode_get_atime(vi));
-       if (si->last_access_time != nt) {
-               ntfs_debug("Updating atime for inode 0x%lx: old = 0x%llx, "
-                               "new = 0x%llx", vi->i_ino,
-                               (long long)sle64_to_cpu(si->last_access_time),
-                               (long long)sle64_to_cpu(nt));
-               si->last_access_time = nt;
-               modified = true;
-       }
-       /*
-        * If we just modified the standard information attribute we need to
-        * mark the mft record it is in dirty.  We do this manually so that
-        * mark_inode_dirty() is not called which would redirty the inode and
-        * hence result in an infinite loop of trying to write the inode.
-        * There is no need to mark the base inode nor the base mft record
-        * dirty, since we are going to write this mft record below in any case
-        * and the base mft record may actually not have been modified so it
-        * might not need to be written out.
-        * NOTE: It is not a problem when the inode for $MFT itself is being
-        * written out as mark_ntfs_record_dirty() will only set I_DIRTY_PAGES
-        * on the $MFT inode and hence __ntfs_write_inode() will not be
-        * re-invoked because of it which in turn is ok since the dirtied mft
-        * record will be cleaned and written out to disk below, i.e. before
-        * this function returns.
-        */
-       if (modified) {
-               flush_dcache_mft_record_page(ctx->ntfs_ino);
-               if (!NInoTestSetDirty(ctx->ntfs_ino))
-                       mark_ntfs_record_dirty(ctx->ntfs_ino->page,
-                                       ctx->ntfs_ino->page_ofs);
-       }
-       ntfs_attr_put_search_ctx(ctx);
-       /* Now the access times are updated, write the base mft record. */
-       if (NInoDirty(ni))
-               err = write_mft_record(ni, m, sync);
-       /* Write all attached extent mft records. */
-       mutex_lock(&ni->extent_lock);
-       if (ni->nr_extents > 0) {
-               ntfs_inode **extent_nis = ni->ext.extent_ntfs_inos;
-               int i;
-
-               ntfs_debug("Writing %i extent inodes.", ni->nr_extents);
-               for (i = 0; i < ni->nr_extents; i++) {
-                       ntfs_inode *tni = extent_nis[i];
-
-                       if (NInoDirty(tni)) {
-                               MFT_RECORD *tm = map_mft_record(tni);
-                               int ret;
-
-                               if (IS_ERR(tm)) {
-                                       if (!err || err == -ENOMEM)
-                                               err = PTR_ERR(tm);
-                                       continue;
-                               }
-                               ret = write_mft_record(tni, tm, sync);
-                               unmap_mft_record(tni);
-                               if (unlikely(ret)) {
-                                       if (!err || err == -ENOMEM)
-                                               err = ret;
-                               }
-                       }
-               }
-       }
-       mutex_unlock(&ni->extent_lock);
-       unmap_mft_record(ni);
-       if (unlikely(err))
-               goto err_out;
-       ntfs_debug("Done.");
-       return 0;
-unm_err_out:
-       unmap_mft_record(ni);
-err_out:
-       if (err == -ENOMEM) {
-               ntfs_warning(vi->i_sb, "Not enough memory to write inode.  "
-                               "Marking the inode dirty again, so the VFS "
-                               "retries later.");
-               mark_inode_dirty(vi);
-       } else {
-               ntfs_error(vi->i_sb, "Failed (error %i):  Run chkdsk.", -err);
-               NVolSetErrors(ni->vol);
-       }
-       return err;
-}
-
-#endif /* NTFS_RW */
diff --git a/fs/ntfs/inode.h b/fs/ntfs/inode.h
deleted file mode 100644 (file)
index 147ef4d..0000000
+++ /dev/null
@@ -1,310 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * inode.h - Defines for inode structures NTFS Linux kernel driver. Part of
- *          the Linux-NTFS project.
- *
- * Copyright (c) 2001-2007 Anton Altaparmakov
- * Copyright (c) 2002 Richard Russon
- */
-
-#ifndef _LINUX_NTFS_INODE_H
-#define _LINUX_NTFS_INODE_H
-
-#include <linux/atomic.h>
-
-#include <linux/fs.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/mutex.h>
-#include <linux/seq_file.h>
-
-#include "layout.h"
-#include "volume.h"
-#include "types.h"
-#include "runlist.h"
-#include "debug.h"
-
-typedef struct _ntfs_inode ntfs_inode;
-
-/*
- * The NTFS in-memory inode structure. It is just used as an extension to the
- * fields already provided in the VFS inode.
- */
-struct _ntfs_inode {
-       rwlock_t size_lock;     /* Lock serializing access to inode sizes. */
-       s64 initialized_size;   /* Copy from the attribute record. */
-       s64 allocated_size;     /* Copy from the attribute record. */
-       unsigned long state;    /* NTFS specific flags describing this inode.
-                                  See ntfs_inode_state_bits below. */
-       unsigned long mft_no;   /* Number of the mft record / inode. */
-       u16 seq_no;             /* Sequence number of the mft record. */
-       atomic_t count;         /* Inode reference count for book keeping. */
-       ntfs_volume *vol;       /* Pointer to the ntfs volume of this inode. */
-       /*
-        * If NInoAttr() is true, the below fields describe the attribute which
-        * this fake inode belongs to. The actual inode of this attribute is
-        * pointed to by base_ntfs_ino and nr_extents is always set to -1 (see
-        * below). For real inodes, we also set the type (AT_DATA for files and
-        * AT_INDEX_ALLOCATION for directories), with the name = NULL and
-        * name_len = 0 for files and name = I30 (global constant) and
-        * name_len = 4 for directories.
-        */
-       ATTR_TYPE type; /* Attribute type of this fake inode. */
-       ntfschar *name;         /* Attribute name of this fake inode. */
-       u32 name_len;           /* Attribute name length of this fake inode. */
-       runlist runlist;        /* If state has the NI_NonResident bit set,
-                                  the runlist of the unnamed data attribute
-                                  (if a file) or of the index allocation
-                                  attribute (directory) or of the attribute
-                                  described by the fake inode (if NInoAttr()).
-                                  If runlist.rl is NULL, the runlist has not
-                                  been read in yet or has been unmapped. If
-                                  NI_NonResident is clear, the attribute is
-                                  resident (file and fake inode) or there is
-                                  no $I30 index allocation attribute
-                                  (small directory). In the latter case
-                                  runlist.rl is always NULL.*/
-       /*
-        * The following fields are only valid for real inodes and extent
-        * inodes.
-        */
-       struct mutex mrec_lock; /* Lock for serializing access to the
-                                  mft record belonging to this inode. */
-       struct page *page;      /* The page containing the mft record of the
-                                  inode. This should only be touched by the
-                                  (un)map_mft_record*() functions. */
-       int page_ofs;           /* Offset into the page at which the mft record
-                                  begins. This should only be touched by the
-                                  (un)map_mft_record*() functions. */
-       /*
-        * Attribute list support (only for use by the attribute lookup
-        * functions). Setup during read_inode for all inodes with attribute
-        * lists. Only valid if NI_AttrList is set in state, and attr_list_rl is
-        * further only valid if NI_AttrListNonResident is set.
-        */
-       u32 attr_list_size;     /* Length of attribute list value in bytes. */
-       u8 *attr_list;          /* Attribute list value itself. */
-       runlist attr_list_rl;   /* Run list for the attribute list value. */
-       union {
-               struct { /* It is a directory, $MFT, or an index inode. */
-                       u32 block_size;         /* Size of an index block. */
-                       u32 vcn_size;           /* Size of a vcn in this
-                                                  index. */
-                       COLLATION_RULE collation_rule; /* The collation rule
-                                                  for the index. */
-                       u8 block_size_bits;     /* Log2 of the above. */
-                       u8 vcn_size_bits;       /* Log2 of the above. */
-               } index;
-               struct { /* It is a compressed/sparse file/attribute inode. */
-                       s64 size;               /* Copy of compressed_size from
-                                                  $DATA. */
-                       u32 block_size;         /* Size of a compression block
-                                                  (cb). */
-                       u8 block_size_bits;     /* Log2 of the size of a cb. */
-                       u8 block_clusters;      /* Number of clusters per cb. */
-               } compressed;
-       } itype;
-       struct mutex extent_lock;       /* Lock for accessing/modifying the
-                                          below . */
-       s32 nr_extents; /* For a base mft record, the number of attached extent
-                          inodes (0 if none), for extent records and for fake
-                          inodes describing an attribute this is -1. */
-       union {         /* This union is only used if nr_extents != 0. */
-               ntfs_inode **extent_ntfs_inos;  /* For nr_extents > 0, array of
-                                                  the ntfs inodes of the extent
-                                                  mft records belonging to
-                                                  this base inode which have
-                                                  been loaded. */
-               ntfs_inode *base_ntfs_ino;      /* For nr_extents == -1, the
-                                                  ntfs inode of the base mft
-                                                  record. For fake inodes, the
-                                                  real (base) inode to which
-                                                  the attribute belongs. */
-       } ext;
-};
-
-/*
- * Defined bits for the state field in the ntfs_inode structure.
- * (f) = files only, (d) = directories only, (a) = attributes/fake inodes only
- */
-typedef enum {
-       NI_Dirty,               /* 1: Mft record needs to be written to disk. */
-       NI_AttrList,            /* 1: Mft record contains an attribute list. */
-       NI_AttrListNonResident, /* 1: Attribute list is non-resident. Implies
-                                     NI_AttrList is set. */
-
-       NI_Attr,                /* 1: Fake inode for attribute i/o.
-                                  0: Real inode or extent inode. */
-
-       NI_MstProtected,        /* 1: Attribute is protected by MST fixups.
-                                  0: Attribute is not protected by fixups. */
-       NI_NonResident,         /* 1: Unnamed data attr is non-resident (f).
-                                  1: Attribute is non-resident (a). */
-       NI_IndexAllocPresent = NI_NonResident,  /* 1: $I30 index alloc attr is
-                                                  present (d). */
-       NI_Compressed,          /* 1: Unnamed data attr is compressed (f).
-                                  1: Create compressed files by default (d).
-                                  1: Attribute is compressed (a). */
-       NI_Encrypted,           /* 1: Unnamed data attr is encrypted (f).
-                                  1: Create encrypted files by default (d).
-                                  1: Attribute is encrypted (a). */
-       NI_Sparse,              /* 1: Unnamed data attr is sparse (f).
-                                  1: Create sparse files by default (d).
-                                  1: Attribute is sparse (a). */
-       NI_SparseDisabled,      /* 1: May not create sparse regions. */
-       NI_TruncateFailed,      /* 1: Last ntfs_truncate() call failed. */
-} ntfs_inode_state_bits;
-
-/*
- * NOTE: We should be adding dirty mft records to a list somewhere and they
- * should be independent of the (ntfs/vfs) inode structure so that an inode can
- * be removed but the record can be left dirty for syncing later.
- */
-
-/*
- * Macro tricks to expand the NInoFoo(), NInoSetFoo(), and NInoClearFoo()
- * functions.
- */
-#define NINO_FNS(flag)                                 \
-static inline int NIno##flag(ntfs_inode *ni)           \
-{                                                      \
-       return test_bit(NI_##flag, &(ni)->state);       \
-}                                                      \
-static inline void NInoSet##flag(ntfs_inode *ni)       \
-{                                                      \
-       set_bit(NI_##flag, &(ni)->state);               \
-}                                                      \
-static inline void NInoClear##flag(ntfs_inode *ni)     \
-{                                                      \
-       clear_bit(NI_##flag, &(ni)->state);             \
-}
-
-/*
- * As above for NInoTestSetFoo() and NInoTestClearFoo().
- */
-#define TAS_NINO_FNS(flag)                                     \
-static inline int NInoTestSet##flag(ntfs_inode *ni)            \
-{                                                              \
-       return test_and_set_bit(NI_##flag, &(ni)->state);       \
-}                                                              \
-static inline int NInoTestClear##flag(ntfs_inode *ni)          \
-{                                                              \
-       return test_and_clear_bit(NI_##flag, &(ni)->state);     \
-}
-
-/* Emit the ntfs inode bitops functions. */
-NINO_FNS(Dirty)
-TAS_NINO_FNS(Dirty)
-NINO_FNS(AttrList)
-NINO_FNS(AttrListNonResident)
-NINO_FNS(Attr)
-NINO_FNS(MstProtected)
-NINO_FNS(NonResident)
-NINO_FNS(IndexAllocPresent)
-NINO_FNS(Compressed)
-NINO_FNS(Encrypted)
-NINO_FNS(Sparse)
-NINO_FNS(SparseDisabled)
-NINO_FNS(TruncateFailed)
-
-/*
- * The full structure containing a ntfs_inode and a vfs struct inode. Used for
- * all real and fake inodes but not for extent inodes which lack the vfs struct
- * inode.
- */
-typedef struct {
-       ntfs_inode ntfs_inode;
-       struct inode vfs_inode;         /* The vfs inode structure. */
-} big_ntfs_inode;
-
-/**
- * NTFS_I - return the ntfs inode given a vfs inode
- * @inode:     VFS inode
- *
- * NTFS_I() returns the ntfs inode associated with the VFS @inode.
- */
-static inline ntfs_inode *NTFS_I(struct inode *inode)
-{
-       return (ntfs_inode *)container_of(inode, big_ntfs_inode, vfs_inode);
-}
-
-static inline struct inode *VFS_I(ntfs_inode *ni)
-{
-       return &((big_ntfs_inode *)ni)->vfs_inode;
-}
-
-/**
- * ntfs_attr - ntfs in memory attribute structure
- * @mft_no:    mft record number of the base mft record of this attribute
- * @name:      Unicode name of the attribute (NULL if unnamed)
- * @name_len:  length of @name in Unicode characters (0 if unnamed)
- * @type:      attribute type (see layout.h)
- *
- * This structure exists only to provide a small structure for the
- * ntfs_{attr_}iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism.
- *
- * NOTE: Elements are ordered by size to make the structure as compact as
- * possible on all architectures.
- */
-typedef struct {
-       unsigned long mft_no;
-       ntfschar *name;
-       u32 name_len;
-       ATTR_TYPE type;
-} ntfs_attr;
-
-extern int ntfs_test_inode(struct inode *vi, void *data);
-
-extern struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no);
-extern struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPE type,
-               ntfschar *name, u32 name_len);
-extern struct inode *ntfs_index_iget(struct inode *base_vi, ntfschar *name,
-               u32 name_len);
-
-extern struct inode *ntfs_alloc_big_inode(struct super_block *sb);
-extern void ntfs_free_big_inode(struct inode *inode);
-extern void ntfs_evict_big_inode(struct inode *vi);
-
-extern void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni);
-
-static inline void ntfs_init_big_inode(struct inode *vi)
-{
-       ntfs_inode *ni = NTFS_I(vi);
-
-       ntfs_debug("Entering.");
-       __ntfs_init_inode(vi->i_sb, ni);
-       ni->mft_no = vi->i_ino;
-}
-
-extern ntfs_inode *ntfs_new_extent_inode(struct super_block *sb,
-               unsigned long mft_no);
-extern void ntfs_clear_extent_inode(ntfs_inode *ni);
-
-extern int ntfs_read_inode_mount(struct inode *vi);
-
-extern int ntfs_show_options(struct seq_file *sf, struct dentry *root);
-
-#ifdef NTFS_RW
-
-extern int ntfs_truncate(struct inode *vi);
-extern void ntfs_truncate_vfs(struct inode *vi);
-
-extern int ntfs_setattr(struct mnt_idmap *idmap,
-                       struct dentry *dentry, struct iattr *attr);
-
-extern int __ntfs_write_inode(struct inode *vi, int sync);
-
-static inline void ntfs_commit_inode(struct inode *vi)
-{
-       if (!is_bad_inode(vi))
-               __ntfs_write_inode(vi, 1);
-       return;
-}
-
-#else
-
-static inline void ntfs_truncate_vfs(struct inode *vi) {}
-
-#endif /* NTFS_RW */
-
-#endif /* _LINUX_NTFS_INODE_H */
diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h
deleted file mode 100644 (file)
index 5d4bf7a..0000000
+++ /dev/null
@@ -1,2421 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * layout.h - All NTFS associated on-disk structures. Part of the Linux-NTFS
- *           project.
- *
- * Copyright (c) 2001-2005 Anton Altaparmakov
- * Copyright (c) 2002 Richard Russon
- */
-
-#ifndef _LINUX_NTFS_LAYOUT_H
-#define _LINUX_NTFS_LAYOUT_H
-
-#include <linux/types.h>
-#include <linux/bitops.h>
-#include <linux/list.h>
-#include <asm/byteorder.h>
-
-#include "types.h"
-
-/* The NTFS oem_id "NTFS    " */
-#define magicNTFS      cpu_to_le64(0x202020205346544eULL)
-
-/*
- * Location of bootsector on partition:
- *     The standard NTFS_BOOT_SECTOR is on sector 0 of the partition.
- *     On NT4 and above there is one backup copy of the boot sector to
- *     be found on the last sector of the partition (not normally accessible
- *     from within Windows as the bootsector contained number of sectors
- *     value is one less than the actual value!).
- *     On versions of NT 3.51 and earlier, the backup copy was located at
- *     number of sectors/2 (integer divide), i.e. in the middle of the volume.
- */
-
-/*
- * BIOS parameter block (bpb) structure.
- */
-typedef struct {
-       le16 bytes_per_sector;          /* Size of a sector in bytes. */
-       u8  sectors_per_cluster;        /* Size of a cluster in sectors. */
-       le16 reserved_sectors;          /* zero */
-       u8  fats;                       /* zero */
-       le16 root_entries;              /* zero */
-       le16 sectors;                   /* zero */
-       u8  media_type;                 /* 0xf8 = hard disk */
-       le16 sectors_per_fat;           /* zero */
-       le16 sectors_per_track;         /* irrelevant */
-       le16 heads;                     /* irrelevant */
-       le32 hidden_sectors;            /* zero */
-       le32 large_sectors;             /* zero */
-} __attribute__ ((__packed__)) BIOS_PARAMETER_BLOCK;
-
-/*
- * NTFS boot sector structure.
- */
-typedef struct {
-       u8  jump[3];                    /* Irrelevant (jump to boot up code).*/
-       le64 oem_id;                    /* Magic "NTFS    ". */
-       BIOS_PARAMETER_BLOCK bpb;       /* See BIOS_PARAMETER_BLOCK. */
-       u8  unused[4];                  /* zero, NTFS diskedit.exe states that
-                                          this is actually:
-                                               __u8 physical_drive;    // 0x80
-                                               __u8 current_head;      // zero
-                                               __u8 extended_boot_signature;
-                                                                       // 0x80
-                                               __u8 unused;            // zero
-                                        */
-/*0x28*/sle64 number_of_sectors;       /* Number of sectors in volume. Gives
-                                          maximum volume size of 2^63 sectors.
-                                          Assuming standard sector size of 512
-                                          bytes, the maximum byte size is
-                                          approx. 4.7x10^21 bytes. (-; */
-       sle64 mft_lcn;                  /* Cluster location of mft data. */
-       sle64 mftmirr_lcn;              /* Cluster location of copy of mft. */
-       s8  clusters_per_mft_record;    /* Mft record size in clusters. */
-       u8  reserved0[3];               /* zero */
-       s8  clusters_per_index_record;  /* Index block size in clusters. */
-       u8  reserved1[3];               /* zero */
-       le64 volume_serial_number;      /* Irrelevant (serial number). */
-       le32 checksum;                  /* Boot sector checksum. */
-/*0x54*/u8  bootstrap[426];            /* Irrelevant (boot up code). */
-       le16 end_of_sector_marker;      /* End of bootsector magic. Always is
-                                          0xaa55 in little endian. */
-/* sizeof() = 512 (0x200) bytes */
-} __attribute__ ((__packed__)) NTFS_BOOT_SECTOR;
-
-/*
- * Magic identifiers present at the beginning of all ntfs record containing
- * records (like mft records for example).
- */
-enum {
-       /* Found in $MFT/$DATA. */
-       magic_FILE = cpu_to_le32(0x454c4946), /* Mft entry. */
-       magic_INDX = cpu_to_le32(0x58444e49), /* Index buffer. */
-       magic_HOLE = cpu_to_le32(0x454c4f48), /* ? (NTFS 3.0+?) */
-
-       /* Found in $LogFile/$DATA. */
-       magic_RSTR = cpu_to_le32(0x52545352), /* Restart page. */
-       magic_RCRD = cpu_to_le32(0x44524352), /* Log record page. */
-
-       /* Found in $LogFile/$DATA.  (May be found in $MFT/$DATA, also?) */
-       magic_CHKD = cpu_to_le32(0x444b4843), /* Modified by chkdsk. */
-
-       /* Found in all ntfs record containing records. */
-       magic_BAAD = cpu_to_le32(0x44414142), /* Failed multi sector
-                                                      transfer was detected. */
-       /*
-        * Found in $LogFile/$DATA when a page is full of 0xff bytes and is
-        * thus not initialized.  Page must be initialized before using it.
-        */
-       magic_empty = cpu_to_le32(0xffffffff) /* Record is empty. */
-};
-
-typedef le32 NTFS_RECORD_TYPE;
-
-/*
- * Generic magic comparison macros. Finally found a use for the ## preprocessor
- * operator! (-8
- */
-
-static inline bool __ntfs_is_magic(le32 x, NTFS_RECORD_TYPE r)
-{
-       return (x == r);
-}
-#define ntfs_is_magic(x, m)    __ntfs_is_magic(x, magic_##m)
-
-static inline bool __ntfs_is_magicp(le32 *p, NTFS_RECORD_TYPE r)
-{
-       return (*p == r);
-}
-#define ntfs_is_magicp(p, m)   __ntfs_is_magicp(p, magic_##m)
-
-/*
- * Specialised magic comparison macros for the NTFS_RECORD_TYPEs defined above.
- */
-#define ntfs_is_file_record(x)         ( ntfs_is_magic (x, FILE) )
-#define ntfs_is_file_recordp(p)                ( ntfs_is_magicp(p, FILE) )
-#define ntfs_is_mft_record(x)          ( ntfs_is_file_record (x) )
-#define ntfs_is_mft_recordp(p)         ( ntfs_is_file_recordp(p) )
-#define ntfs_is_indx_record(x)         ( ntfs_is_magic (x, INDX) )
-#define ntfs_is_indx_recordp(p)                ( ntfs_is_magicp(p, INDX) )
-#define ntfs_is_hole_record(x)         ( ntfs_is_magic (x, HOLE) )
-#define ntfs_is_hole_recordp(p)                ( ntfs_is_magicp(p, HOLE) )
-
-#define ntfs_is_rstr_record(x)         ( ntfs_is_magic (x, RSTR) )
-#define ntfs_is_rstr_recordp(p)                ( ntfs_is_magicp(p, RSTR) )
-#define ntfs_is_rcrd_record(x)         ( ntfs_is_magic (x, RCRD) )
-#define ntfs_is_rcrd_recordp(p)                ( ntfs_is_magicp(p, RCRD) )
-
-#define ntfs_is_chkd_record(x)         ( ntfs_is_magic (x, CHKD) )
-#define ntfs_is_chkd_recordp(p)                ( ntfs_is_magicp(p, CHKD) )
-
-#define ntfs_is_baad_record(x)         ( ntfs_is_magic (x, BAAD) )
-#define ntfs_is_baad_recordp(p)                ( ntfs_is_magicp(p, BAAD) )
-
-#define ntfs_is_empty_record(x)                ( ntfs_is_magic (x, empty) )
-#define ntfs_is_empty_recordp(p)       ( ntfs_is_magicp(p, empty) )
-
-/*
- * The Update Sequence Array (usa) is an array of the le16 values which belong
- * to the end of each sector protected by the update sequence record in which
- * this array is contained. Note that the first entry is the Update Sequence
- * Number (usn), a cyclic counter of how many times the protected record has
- * been written to disk. The values 0 and -1 (ie. 0xffff) are not used. All
- * last le16's of each sector have to be equal to the usn (during reading) or
- * are set to it (during writing). If they are not, an incomplete multi sector
- * transfer has occurred when the data was written.
- * The maximum size for the update sequence array is fixed to:
- *     maximum size = usa_ofs + (usa_count * 2) = 510 bytes
- * The 510 bytes comes from the fact that the last le16 in the array has to
- * (obviously) finish before the last le16 of the first 512-byte sector.
- * This formula can be used as a consistency check in that usa_ofs +
- * (usa_count * 2) has to be less than or equal to 510.
- */
-typedef struct {
-       NTFS_RECORD_TYPE magic; /* A four-byte magic identifying the record
-                                  type and/or status. */
-       le16 usa_ofs;           /* Offset to the Update Sequence Array (usa)
-                                  from the start of the ntfs record. */
-       le16 usa_count;         /* Number of le16 sized entries in the usa
-                                  including the Update Sequence Number (usn),
-                                  thus the number of fixups is the usa_count
-                                  minus 1. */
-} __attribute__ ((__packed__)) NTFS_RECORD;
-
-/*
- * System files mft record numbers. All these files are always marked as used
- * in the bitmap attribute of the mft; presumably in order to avoid accidental
- * allocation for random other mft records. Also, the sequence number for each
- * of the system files is always equal to their mft record number and it is
- * never modified.
- */
-typedef enum {
-       FILE_MFT       = 0,     /* Master file table (mft). Data attribute
-                                  contains the entries and bitmap attribute
-                                  records which ones are in use (bit==1). */
-       FILE_MFTMirr   = 1,     /* Mft mirror: copy of first four mft records
-                                  in data attribute. If cluster size > 4kiB,
-                                  copy of first N mft records, with
-                                       N = cluster_size / mft_record_size. */
-       FILE_LogFile   = 2,     /* Journalling log in data attribute. */
-       FILE_Volume    = 3,     /* Volume name attribute and volume information
-                                  attribute (flags and ntfs version). Windows
-                                  refers to this file as volume DASD (Direct
-                                  Access Storage Device). */
-       FILE_AttrDef   = 4,     /* Array of attribute definitions in data
-                                  attribute. */
-       FILE_root      = 5,     /* Root directory. */
-       FILE_Bitmap    = 6,     /* Allocation bitmap of all clusters (lcns) in
-                                  data attribute. */
-       FILE_Boot      = 7,     /* Boot sector (always at cluster 0) in data
-                                  attribute. */
-       FILE_BadClus   = 8,     /* Contains all bad clusters in the non-resident
-                                  data attribute. */
-       FILE_Secure    = 9,     /* Shared security descriptors in data attribute
-                                  and two indexes into the descriptors.
-                                  Appeared in Windows 2000. Before that, this
-                                  file was named $Quota but was unused. */
-       FILE_UpCase    = 10,    /* Uppercase equivalents of all 65536 Unicode
-                                  characters in data attribute. */
-       FILE_Extend    = 11,    /* Directory containing other system files (eg.
-                                  $ObjId, $Quota, $Reparse and $UsnJrnl). This
-                                  is new to NTFS3.0. */
-       FILE_reserved12 = 12,   /* Reserved for future use (records 12-15). */
-       FILE_reserved13 = 13,
-       FILE_reserved14 = 14,
-       FILE_reserved15 = 15,
-       FILE_first_user = 16,   /* First user file, used as test limit for
-                                  whether to allow opening a file or not. */
-} NTFS_SYSTEM_FILES;
-
-/*
- * These are the so far known MFT_RECORD_* flags (16-bit) which contain
- * information about the mft record in which they are present.
- */
-enum {
-       MFT_RECORD_IN_USE       = cpu_to_le16(0x0001),
-       MFT_RECORD_IS_DIRECTORY = cpu_to_le16(0x0002),
-} __attribute__ ((__packed__));
-
-typedef le16 MFT_RECORD_FLAGS;
-
-/*
- * mft references (aka file references or file record segment references) are
- * used whenever a structure needs to refer to a record in the mft.
- *
- * A reference consists of a 48-bit index into the mft and a 16-bit sequence
- * number used to detect stale references.
- *
- * For error reporting purposes we treat the 48-bit index as a signed quantity.
- *
- * The sequence number is a circular counter (skipping 0) describing how many
- * times the referenced mft record has been (re)used. This has to match the
- * sequence number of the mft record being referenced, otherwise the reference
- * is considered stale and removed (FIXME: only ntfsck or the driver itself?).
- *
- * If the sequence number is zero it is assumed that no sequence number
- * consistency checking should be performed.
- *
- * FIXME: Since inodes are 32-bit as of now, the driver needs to always check
- * for high_part being 0 and if not either BUG(), cause a panic() or handle
- * the situation in some other way. This shouldn't be a problem as a volume has
- * to become HUGE in order to need more than 32-bits worth of mft records.
- * Assuming the standard mft record size of 1kb only the records (never mind
- * the non-resident attributes, etc.) would require 4Tb of space on their own
- * for the first 32 bits worth of records. This is only if some strange person
- * doesn't decide to foul play and make the mft sparse which would be a really
- * horrible thing to do as it would trash our current driver implementation. )-:
- * Do I hear screams "we want 64-bit inodes!" ?!? (-;
- *
- * FIXME: The mft zone is defined as the first 12% of the volume. This space is
- * reserved so that the mft can grow contiguously and hence doesn't become
- * fragmented. Volume free space includes the empty part of the mft zone and
- * when the volume's free 88% are used up, the mft zone is shrunk by a factor
- * of 2, thus making more space available for more files/data. This process is
- * repeated every time there is no more free space except for the mft zone until
- * there really is no more free space.
- */
-
-/*
- * Typedef the MFT_REF as a 64-bit value for easier handling.
- * Also define two unpacking macros to get to the reference (MREF) and
- * sequence number (MSEQNO) respectively.
- * The _LE versions are to be applied on little endian MFT_REFs.
- * Note: The _LE versions will return a CPU endian formatted value!
- */
-#define MFT_REF_MASK_CPU 0x0000ffffffffffffULL
-#define MFT_REF_MASK_LE cpu_to_le64(MFT_REF_MASK_CPU)
-
-typedef u64 MFT_REF;
-typedef le64 leMFT_REF;
-
-#define MK_MREF(m, s)  ((MFT_REF)(((MFT_REF)(s) << 48) |               \
-                                       ((MFT_REF)(m) & MFT_REF_MASK_CPU)))
-#define MK_LE_MREF(m, s) cpu_to_le64(MK_MREF(m, s))
-
-#define MREF(x)                ((unsigned long)((x) & MFT_REF_MASK_CPU))
-#define MSEQNO(x)      ((u16)(((x) >> 48) & 0xffff))
-#define MREF_LE(x)     ((unsigned long)(le64_to_cpu(x) & MFT_REF_MASK_CPU))
-#define MSEQNO_LE(x)   ((u16)((le64_to_cpu(x) >> 48) & 0xffff))
-
-#define IS_ERR_MREF(x) (((x) & 0x0000800000000000ULL) ? true : false)
-#define ERR_MREF(x)    ((u64)((s64)(x)))
-#define MREF_ERR(x)    ((int)((s64)(x)))
-
-/*
- * The mft record header present at the beginning of every record in the mft.
- * This is followed by a sequence of variable length attribute records which
- * is terminated by an attribute of type AT_END which is a truncated attribute
- * in that it only consists of the attribute type code AT_END and none of the
- * other members of the attribute structure are present.
- */
-typedef struct {
-/*Ofs*/
-/*  0  NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
-       NTFS_RECORD_TYPE magic; /* Usually the magic is "FILE". */
-       le16 usa_ofs;           /* See NTFS_RECORD definition above. */
-       le16 usa_count;         /* See NTFS_RECORD definition above. */
-
-/*  8*/        le64 lsn;               /* $LogFile sequence number for this record.
-                                  Changed every time the record is modified. */
-/* 16*/        le16 sequence_number;   /* Number of times this mft record has been
-                                  reused. (See description for MFT_REF
-                                  above.) NOTE: The increment (skipping zero)
-                                  is done when the file is deleted. NOTE: If
-                                  this is zero it is left zero. */
-/* 18*/        le16 link_count;        /* Number of hard links, i.e. the number of
-                                  directory entries referencing this record.
-                                  NOTE: Only used in mft base records.
-                                  NOTE: When deleting a directory entry we
-                                  check the link_count and if it is 1 we
-                                  delete the file. Otherwise we delete the
-                                  FILE_NAME_ATTR being referenced by the
-                                  directory entry from the mft record and
-                                  decrement the link_count.
-                                  FIXME: Careful with Win32 + DOS names! */
-/* 20*/        le16 attrs_offset;      /* Byte offset to the first attribute in this
-                                  mft record from the start of the mft record.
-                                  NOTE: Must be aligned to 8-byte boundary. */
-/* 22*/        MFT_RECORD_FLAGS flags; /* Bit array of MFT_RECORD_FLAGS. When a file
-                                  is deleted, the MFT_RECORD_IN_USE flag is
-                                  set to zero. */
-/* 24*/        le32 bytes_in_use;      /* Number of bytes used in this mft record.
-                                  NOTE: Must be aligned to 8-byte boundary. */
-/* 28*/        le32 bytes_allocated;   /* Number of bytes allocated for this mft
-                                  record. This should be equal to the mft
-                                  record size. */
-/* 32*/        leMFT_REF base_mft_record;/* This is zero for base mft records.
-                                  When it is not zero it is a mft reference
-                                  pointing to the base mft record to which
-                                  this record belongs (this is then used to
-                                  locate the attribute list attribute present
-                                  in the base record which describes this
-                                  extension record and hence might need
-                                  modification when the extension record
-                                  itself is modified, also locating the
-                                  attribute list also means finding the other
-                                  potential extents, belonging to the non-base
-                                  mft record). */
-/* 40*/        le16 next_attr_instance;/* The instance number that will be assigned to
-                                  the next attribute added to this mft record.
-                                  NOTE: Incremented each time after it is used.
-                                  NOTE: Every time the mft record is reused
-                                  this number is set to zero.  NOTE: The first
-                                  instance number is always 0. */
-/* The below fields are specific to NTFS 3.1+ (Windows XP and above): */
-/* 42*/ le16 reserved;         /* Reserved/alignment. */
-/* 44*/ le32 mft_record_number;        /* Number of this mft record. */
-/* sizeof() = 48 bytes */
-/*
- * When (re)using the mft record, we place the update sequence array at this
- * offset, i.e. before we start with the attributes.  This also makes sense,
- * otherwise we could run into problems with the update sequence array
- * containing in itself the last two bytes of a sector which would mean that
- * multi sector transfer protection wouldn't work.  As you can't protect data
- * by overwriting it since you then can't get it back...
- * When reading we obviously use the data from the ntfs record header.
- */
-} __attribute__ ((__packed__)) MFT_RECORD;
-
-/* This is the version without the NTFS 3.1+ specific fields. */
-typedef struct {
-/*Ofs*/
-/*  0  NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
-       NTFS_RECORD_TYPE magic; /* Usually the magic is "FILE". */
-       le16 usa_ofs;           /* See NTFS_RECORD definition above. */
-       le16 usa_count;         /* See NTFS_RECORD definition above. */
-
-/*  8*/        le64 lsn;               /* $LogFile sequence number for this record.
-                                  Changed every time the record is modified. */
-/* 16*/        le16 sequence_number;   /* Number of times this mft record has been
-                                  reused. (See description for MFT_REF
-                                  above.) NOTE: The increment (skipping zero)
-                                  is done when the file is deleted. NOTE: If
-                                  this is zero it is left zero. */
-/* 18*/        le16 link_count;        /* Number of hard links, i.e. the number of
-                                  directory entries referencing this record.
-                                  NOTE: Only used in mft base records.
-                                  NOTE: When deleting a directory entry we
-                                  check the link_count and if it is 1 we
-                                  delete the file. Otherwise we delete the
-                                  FILE_NAME_ATTR being referenced by the
-                                  directory entry from the mft record and
-                                  decrement the link_count.
-                                  FIXME: Careful with Win32 + DOS names! */
-/* 20*/        le16 attrs_offset;      /* Byte offset to the first attribute in this
-                                  mft record from the start of the mft record.
-                                  NOTE: Must be aligned to 8-byte boundary. */
-/* 22*/        MFT_RECORD_FLAGS flags; /* Bit array of MFT_RECORD_FLAGS. When a file
-                                  is deleted, the MFT_RECORD_IN_USE flag is
-                                  set to zero. */
-/* 24*/        le32 bytes_in_use;      /* Number of bytes used in this mft record.
-                                  NOTE: Must be aligned to 8-byte boundary. */
-/* 28*/        le32 bytes_allocated;   /* Number of bytes allocated for this mft
-                                  record. This should be equal to the mft
-                                  record size. */
-/* 32*/        leMFT_REF base_mft_record;/* This is zero for base mft records.
-                                  When it is not zero it is a mft reference
-                                  pointing to the base mft record to which
-                                  this record belongs (this is then used to
-                                  locate the attribute list attribute present
-                                  in the base record which describes this
-                                  extension record and hence might need
-                                  modification when the extension record
-                                  itself is modified, also locating the
-                                  attribute list also means finding the other
-                                  potential extents, belonging to the non-base
-                                  mft record). */
-/* 40*/        le16 next_attr_instance;/* The instance number that will be assigned to
-                                  the next attribute added to this mft record.
-                                  NOTE: Incremented each time after it is used.
-                                  NOTE: Every time the mft record is reused
-                                  this number is set to zero.  NOTE: The first
-                                  instance number is always 0. */
-/* sizeof() = 42 bytes */
-/*
- * When (re)using the mft record, we place the update sequence array at this
- * offset, i.e. before we start with the attributes.  This also makes sense,
- * otherwise we could run into problems with the update sequence array
- * containing in itself the last two bytes of a sector which would mean that
- * multi sector transfer protection wouldn't work.  As you can't protect data
- * by overwriting it since you then can't get it back...
- * When reading we obviously use the data from the ntfs record header.
- */
-} __attribute__ ((__packed__)) MFT_RECORD_OLD;
-
-/*
- * System defined attributes (32-bit).  Each attribute type has a corresponding
- * attribute name (Unicode string of maximum 64 character length) as described
- * by the attribute definitions present in the data attribute of the $AttrDef
- * system file.  On NTFS 3.0 volumes the names are just as the types are named
- * in the below defines exchanging AT_ for the dollar sign ($).  If that is not
- * a revealing choice of symbol I do not know what is... (-;
- */
-enum {
-       AT_UNUSED                       = cpu_to_le32(         0),
-       AT_STANDARD_INFORMATION         = cpu_to_le32(      0x10),
-       AT_ATTRIBUTE_LIST               = cpu_to_le32(      0x20),
-       AT_FILE_NAME                    = cpu_to_le32(      0x30),
-       AT_OBJECT_ID                    = cpu_to_le32(      0x40),
-       AT_SECURITY_DESCRIPTOR          = cpu_to_le32(      0x50),
-       AT_VOLUME_NAME                  = cpu_to_le32(      0x60),
-       AT_VOLUME_INFORMATION           = cpu_to_le32(      0x70),
-       AT_DATA                         = cpu_to_le32(      0x80),
-       AT_INDEX_ROOT                   = cpu_to_le32(      0x90),
-       AT_INDEX_ALLOCATION             = cpu_to_le32(      0xa0),
-       AT_BITMAP                       = cpu_to_le32(      0xb0),
-       AT_REPARSE_POINT                = cpu_to_le32(      0xc0),
-       AT_EA_INFORMATION               = cpu_to_le32(      0xd0),
-       AT_EA                           = cpu_to_le32(      0xe0),
-       AT_PROPERTY_SET                 = cpu_to_le32(      0xf0),
-       AT_LOGGED_UTILITY_STREAM        = cpu_to_le32(     0x100),
-       AT_FIRST_USER_DEFINED_ATTRIBUTE = cpu_to_le32(    0x1000),
-       AT_END                          = cpu_to_le32(0xffffffff)
-};
-
-typedef le32 ATTR_TYPE;
-
-/*
- * The collation rules for sorting views/indexes/etc (32-bit).
- *
- * COLLATION_BINARY - Collate by binary compare where the first byte is most
- *     significant.
- * COLLATION_UNICODE_STRING - Collate Unicode strings by comparing their binary
- *     Unicode values, except that when a character can be uppercased, the
- *     upper case value collates before the lower case one.
- * COLLATION_FILE_NAME - Collate file names as Unicode strings. The collation
- *     is done very much like COLLATION_UNICODE_STRING. In fact I have no idea
- *     what the difference is. Perhaps the difference is that file names
- *     would treat some special characters in an odd way (see
- *     unistr.c::ntfs_collate_names() and unistr.c::legal_ansi_char_array[]
- *     for what I mean but COLLATION_UNICODE_STRING would not give any special
- *     treatment to any characters at all, but this is speculation.
- * COLLATION_NTOFS_ULONG - Sorting is done according to ascending le32 key
- *     values. E.g. used for $SII index in FILE_Secure, which sorts by
- *     security_id (le32).
- * COLLATION_NTOFS_SID - Sorting is done according to ascending SID values.
- *     E.g. used for $O index in FILE_Extend/$Quota.
- * COLLATION_NTOFS_SECURITY_HASH - Sorting is done first by ascending hash
- *     values and second by ascending security_id values. E.g. used for $SDH
- *     index in FILE_Secure.
- * COLLATION_NTOFS_ULONGS - Sorting is done according to a sequence of ascending
- *     le32 key values. E.g. used for $O index in FILE_Extend/$ObjId, which
- *     sorts by object_id (16-byte), by splitting up the object_id in four
- *     le32 values and using them as individual keys. E.g. take the following
- *     two security_ids, stored as follows on disk:
- *             1st: a1 61 65 b7 65 7b d4 11 9e 3d 00 e0 81 10 42 59
- *             2nd: 38 14 37 d2 d2 f3 d4 11 a5 21 c8 6b 79 b1 97 45
- *     To compare them, they are split into four le32 values each, like so:
- *             1st: 0xb76561a1 0x11d47b65 0xe0003d9e 0x59421081
- *             2nd: 0xd2371438 0x11d4f3d2 0x6bc821a5 0x4597b179
- *     Now, it is apparent why the 2nd object_id collates after the 1st: the
- *     first le32 value of the 1st object_id is less than the first le32 of
- *     the 2nd object_id. If the first le32 values of both object_ids were
- *     equal then the second le32 values would be compared, etc.
- */
-enum {
-       COLLATION_BINARY                = cpu_to_le32(0x00),
-       COLLATION_FILE_NAME             = cpu_to_le32(0x01),
-       COLLATION_UNICODE_STRING        = cpu_to_le32(0x02),
-       COLLATION_NTOFS_ULONG           = cpu_to_le32(0x10),
-       COLLATION_NTOFS_SID             = cpu_to_le32(0x11),
-       COLLATION_NTOFS_SECURITY_HASH   = cpu_to_le32(0x12),
-       COLLATION_NTOFS_ULONGS          = cpu_to_le32(0x13),
-};
-
-typedef le32 COLLATION_RULE;
-
-/*
- * The flags (32-bit) describing attribute properties in the attribute
- * definition structure.  FIXME: This information is based on Regis's
- * information and, according to him, it is not certain and probably
- * incomplete.  The INDEXABLE flag is fairly certainly correct as only the file
- * name attribute has this flag set and this is the only attribute indexed in
- * NT4.
- */
-enum {
-       ATTR_DEF_INDEXABLE      = cpu_to_le32(0x02), /* Attribute can be
-                                       indexed. */
-       ATTR_DEF_MULTIPLE       = cpu_to_le32(0x04), /* Attribute type
-                                       can be present multiple times in the
-                                       mft records of an inode. */
-       ATTR_DEF_NOT_ZERO       = cpu_to_le32(0x08), /* Attribute value
-                                       must contain at least one non-zero
-                                       byte. */
-       ATTR_DEF_INDEXED_UNIQUE = cpu_to_le32(0x10), /* Attribute must be
-                                       indexed and the attribute value must be
-                                       unique for the attribute type in all of
-                                       the mft records of an inode. */
-       ATTR_DEF_NAMED_UNIQUE   = cpu_to_le32(0x20), /* Attribute must be
-                                       named and the name must be unique for
-                                       the attribute type in all of the mft
-                                       records of an inode. */
-       ATTR_DEF_RESIDENT       = cpu_to_le32(0x40), /* Attribute must be
-                                       resident. */
-       ATTR_DEF_ALWAYS_LOG     = cpu_to_le32(0x80), /* Always log
-                                       modifications to this attribute,
-                                       regardless of whether it is resident or
-                                       non-resident.  Without this, only log
-                                       modifications if the attribute is
-                                       resident. */
-};
-
-typedef le32 ATTR_DEF_FLAGS;
-
-/*
- * The data attribute of FILE_AttrDef contains a sequence of attribute
- * definitions for the NTFS volume. With this, it is supposed to be safe for an
- * older NTFS driver to mount a volume containing a newer NTFS version without
- * damaging it (that's the theory. In practice it's: not damaging it too much).
- * Entries are sorted by attribute type. The flags describe whether the
- * attribute can be resident/non-resident and possibly other things, but the
- * actual bits are unknown.
- */
-typedef struct {
-/*hex ofs*/
-/*  0*/        ntfschar name[0x40];            /* Unicode name of the attribute. Zero
-                                          terminated. */
-/* 80*/        ATTR_TYPE type;                 /* Type of the attribute. */
-/* 84*/        le32 display_rule;              /* Default display rule.
-                                          FIXME: What does it mean? (AIA) */
-/* 88*/ COLLATION_RULE collation_rule; /* Default collation rule. */
-/* 8c*/        ATTR_DEF_FLAGS flags;           /* Flags describing the attribute. */
-/* 90*/        sle64 min_size;                 /* Optional minimum attribute size. */
-/* 98*/        sle64 max_size;                 /* Maximum size of attribute. */
-/* sizeof() = 0xa0 or 160 bytes */
-} __attribute__ ((__packed__)) ATTR_DEF;
-
-/*
- * Attribute flags (16-bit).
- */
-enum {
-       ATTR_IS_COMPRESSED    = cpu_to_le16(0x0001),
-       ATTR_COMPRESSION_MASK = cpu_to_le16(0x00ff), /* Compression method
-                                                             mask.  Also, first
-                                                             illegal value. */
-       ATTR_IS_ENCRYPTED     = cpu_to_le16(0x4000),
-       ATTR_IS_SPARSE        = cpu_to_le16(0x8000),
-} __attribute__ ((__packed__));
-
-typedef le16 ATTR_FLAGS;
-
-/*
- * Attribute compression.
- *
- * Only the data attribute is ever compressed in the current ntfs driver in
- * Windows. Further, compression is only applied when the data attribute is
- * non-resident. Finally, to use compression, the maximum allowed cluster size
- * on a volume is 4kib.
- *
- * The compression method is based on independently compressing blocks of X
- * clusters, where X is determined from the compression_unit value found in the
- * non-resident attribute record header (more precisely: X = 2^compression_unit
- * clusters). On Windows NT/2k, X always is 16 clusters (compression_unit = 4).
- *
- * There are three different cases of how a compression block of X clusters
- * can be stored:
- *
- *   1) The data in the block is all zero (a sparse block):
- *       This is stored as a sparse block in the runlist, i.e. the runlist
- *       entry has length = X and lcn = -1. The mapping pairs array actually
- *       uses a delta_lcn value length of 0, i.e. delta_lcn is not present at
- *       all, which is then interpreted by the driver as lcn = -1.
- *       NOTE: Even uncompressed files can be sparse on NTFS 3.0 volumes, then
- *       the same principles apply as above, except that the length is not
- *       restricted to being any particular value.
- *
- *   2) The data in the block is not compressed:
- *       This happens when compression doesn't reduce the size of the block
- *       in clusters. I.e. if compression has a small effect so that the
- *       compressed data still occupies X clusters, then the uncompressed data
- *       is stored in the block.
- *       This case is recognised by the fact that the runlist entry has
- *       length = X and lcn >= 0. The mapping pairs array stores this as
- *       normal with a run length of X and some specific delta_lcn, i.e.
- *       delta_lcn has to be present.
- *
- *   3) The data in the block is compressed:
- *       The common case. This case is recognised by the fact that the run
- *       list entry has length L < X and lcn >= 0. The mapping pairs array
- *       stores this as normal with a run length of X and some specific
- *       delta_lcn, i.e. delta_lcn has to be present. This runlist entry is
- *       immediately followed by a sparse entry with length = X - L and
- *       lcn = -1. The latter entry is to make up the vcn counting to the
- *       full compression block size X.
- *
- * In fact, life is more complicated because adjacent entries of the same type
- * can be coalesced. This means that one has to keep track of the number of
- * clusters handled and work on a basis of X clusters at a time being one
- * block. An example: if length L > X this means that this particular runlist
- * entry contains a block of length X and part of one or more blocks of length
- * L - X. Another example: if length L < X, this does not necessarily mean that
- * the block is compressed as it might be that the lcn changes inside the block
- * and hence the following runlist entry describes the continuation of the
- * potentially compressed block. The block would be compressed if the
- * following runlist entry describes at least X - L sparse clusters, thus
- * making up the compression block length as described in point 3 above. (Of
- * course, there can be several runlist entries with small lengths so that the
- * sparse entry does not follow the first data containing entry with
- * length < X.)
- *
- * NOTE: At the end of the compressed attribute value, there most likely is not
- * just the right amount of data to make up a compression block, thus this data
- * is not even attempted to be compressed. It is just stored as is, unless
- * the number of clusters it occupies is reduced when compressed in which case
- * it is stored as a compressed compression block, complete with sparse
- * clusters at the end.
- */
-
-/*
- * Flags of resident attributes (8-bit).
- */
-enum {
-       RESIDENT_ATTR_IS_INDEXED = 0x01, /* Attribute is referenced in an index
-                                           (has implications for deleting and
-                                           modifying the attribute). */
-} __attribute__ ((__packed__));
-
-typedef u8 RESIDENT_ATTR_FLAGS;
-
-/*
- * Attribute record header. Always aligned to 8-byte boundary.
- */
-typedef struct {
-/*Ofs*/
-/*  0*/        ATTR_TYPE type;         /* The (32-bit) type of the attribute. */
-/*  4*/        le32 length;            /* Byte size of the resident part of the
-                                  attribute (aligned to 8-byte boundary).
-                                  Used to get to the next attribute. */
-/*  8*/        u8 non_resident;        /* If 0, attribute is resident.
-                                  If 1, attribute is non-resident. */
-/*  9*/        u8 name_length;         /* Unicode character size of name of attribute.
-                                  0 if unnamed. */
-/* 10*/        le16 name_offset;       /* If name_length != 0, the byte offset to the
-                                  beginning of the name from the attribute
-                                  record. Note that the name is stored as a
-                                  Unicode string. When creating, place offset
-                                  just at the end of the record header. Then,
-                                  follow with attribute value or mapping pairs
-                                  array, resident and non-resident attributes
-                                  respectively, aligning to an 8-byte
-                                  boundary. */
-/* 12*/        ATTR_FLAGS flags;       /* Flags describing the attribute. */
-/* 14*/        le16 instance;          /* The instance of this attribute record. This
-                                  number is unique within this mft record (see
-                                  MFT_RECORD/next_attribute_instance notes in
-                                  mft.h for more details). */
-/* 16*/        union {
-               /* Resident attributes. */
-               struct {
-/* 16 */               le32 value_length;/* Byte size of attribute value. */
-/* 20 */               le16 value_offset;/* Byte offset of the attribute
-                                            value from the start of the
-                                            attribute record. When creating,
-                                            align to 8-byte boundary if we
-                                            have a name present as this might
-                                            not have a length of a multiple
-                                            of 8-bytes. */
-/* 22 */               RESIDENT_ATTR_FLAGS flags; /* See above. */
-/* 23 */               s8 reserved;      /* Reserved/alignment to 8-byte
-                                            boundary. */
-               } __attribute__ ((__packed__)) resident;
-               /* Non-resident attributes. */
-               struct {
-/* 16*/                        leVCN lowest_vcn;/* Lowest valid virtual cluster number
-                               for this portion of the attribute value or
-                               0 if this is the only extent (usually the
-                               case). - Only when an attribute list is used
-                               does lowest_vcn != 0 ever occur. */
-/* 24*/                        leVCN highest_vcn;/* Highest valid vcn of this extent of
-                               the attribute value. - Usually there is only one
-                               portion, so this usually equals the attribute
-                               value size in clusters minus 1. Can be -1 for
-                               zero length files. Can be 0 for "single extent"
-                               attributes. */
-/* 32*/                        le16 mapping_pairs_offset; /* Byte offset from the
-                               beginning of the structure to the mapping pairs
-                               array which contains the mappings between the
-                               vcns and the logical cluster numbers (lcns).
-                               When creating, place this at the end of this
-                               record header aligned to 8-byte boundary. */
-/* 34*/                        u8 compression_unit; /* The compression unit expressed
-                               as the log to the base 2 of the number of
-                               clusters in a compression unit.  0 means not
-                               compressed.  (This effectively limits the
-                               compression unit size to be a power of two
-                               clusters.)  WinNT4 only uses a value of 4.
-                               Sparse files have this set to 0 on XPSP2. */
-/* 35*/                        u8 reserved[5];         /* Align to 8-byte boundary. */
-/* The sizes below are only used when lowest_vcn is zero, as otherwise it would
-   be difficult to keep them up-to-date.*/
-/* 40*/                        sle64 allocated_size;   /* Byte size of disk space
-                               allocated to hold the attribute value. Always
-                               is a multiple of the cluster size. When a file
-                               is compressed, this field is a multiple of the
-                               compression block size (2^compression_unit) and
-                               it represents the logically allocated space
-                               rather than the actual on disk usage. For this
-                               use the compressed_size (see below). */
-/* 48*/                        sle64 data_size;        /* Byte size of the attribute
-                               value. Can be larger than allocated_size if
-                               attribute value is compressed or sparse. */
-/* 56*/                        sle64 initialized_size; /* Byte size of initialized
-                               portion of the attribute value. Usually equals
-                               data_size. */
-/* sizeof(uncompressed attr) = 64*/
-/* 64*/                        sle64 compressed_size;  /* Byte size of the attribute
-                               value after compression.  Only present when
-                               compressed or sparse.  Always is a multiple of
-                               the cluster size.  Represents the actual amount
-                               of disk space being used on the disk. */
-/* sizeof(compressed attr) = 72*/
-               } __attribute__ ((__packed__)) non_resident;
-       } __attribute__ ((__packed__)) data;
-} __attribute__ ((__packed__)) ATTR_RECORD;
-
-typedef ATTR_RECORD ATTR_REC;
-
-/*
- * File attribute flags (32-bit) appearing in the file_attributes fields of the
- * STANDARD_INFORMATION attribute of MFT_RECORDs and the FILENAME_ATTR
- * attributes of MFT_RECORDs and directory index entries.
- *
- * All of the below flags appear in the directory index entries but only some
- * appear in the STANDARD_INFORMATION attribute whilst only some others appear
- * in the FILENAME_ATTR attribute of MFT_RECORDs.  Unless otherwise stated the
- * flags appear in all of the above.
- */
-enum {
-       FILE_ATTR_READONLY              = cpu_to_le32(0x00000001),
-       FILE_ATTR_HIDDEN                = cpu_to_le32(0x00000002),
-       FILE_ATTR_SYSTEM                = cpu_to_le32(0x00000004),
-       /* Old DOS volid. Unused in NT. = cpu_to_le32(0x00000008), */
-
-       FILE_ATTR_DIRECTORY             = cpu_to_le32(0x00000010),
-       /* Note, FILE_ATTR_DIRECTORY is not considered valid in NT.  It is
-          reserved for the DOS SUBDIRECTORY flag. */
-       FILE_ATTR_ARCHIVE               = cpu_to_le32(0x00000020),
-       FILE_ATTR_DEVICE                = cpu_to_le32(0x00000040),
-       FILE_ATTR_NORMAL                = cpu_to_le32(0x00000080),
-
-       FILE_ATTR_TEMPORARY             = cpu_to_le32(0x00000100),
-       FILE_ATTR_SPARSE_FILE           = cpu_to_le32(0x00000200),
-       FILE_ATTR_REPARSE_POINT         = cpu_to_le32(0x00000400),
-       FILE_ATTR_COMPRESSED            = cpu_to_le32(0x00000800),
-
-       FILE_ATTR_OFFLINE               = cpu_to_le32(0x00001000),
-       FILE_ATTR_NOT_CONTENT_INDEXED   = cpu_to_le32(0x00002000),
-       FILE_ATTR_ENCRYPTED             = cpu_to_le32(0x00004000),
-
-       FILE_ATTR_VALID_FLAGS           = cpu_to_le32(0x00007fb7),
-       /* Note, FILE_ATTR_VALID_FLAGS masks out the old DOS VolId and the
-          FILE_ATTR_DEVICE and preserves everything else.  This mask is used
-          to obtain all flags that are valid for reading. */
-       FILE_ATTR_VALID_SET_FLAGS       = cpu_to_le32(0x000031a7),
-       /* Note, FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the
-          F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT,
-          F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest.  This mask
-          is used to obtain all flags that are valid for setting. */
-       /*
-        * The flag FILE_ATTR_DUP_FILENAME_INDEX_PRESENT is present in all
-        * FILENAME_ATTR attributes but not in the STANDARD_INFORMATION
-        * attribute of an mft record.
-        */
-       FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT   = cpu_to_le32(0x10000000),
-       /* Note, this is a copy of the corresponding bit from the mft record,
-          telling us whether this is a directory or not, i.e. whether it has
-          an index root attribute or not. */
-       FILE_ATTR_DUP_VIEW_INDEX_PRESENT        = cpu_to_le32(0x20000000),
-       /* Note, this is a copy of the corresponding bit from the mft record,
-          telling us whether this file has a view index present (eg. object id
-          index, quota index, one of the security indexes or the encrypting
-          filesystem related indexes). */
-};
-
-typedef le32 FILE_ATTR_FLAGS;
-
-/*
- * NOTE on times in NTFS: All times are in MS standard time format, i.e. they
- * are the number of 100-nanosecond intervals since 1st January 1601, 00:00:00
- * universal coordinated time (UTC). (In Linux time starts 1st January 1970,
- * 00:00:00 UTC and is stored as the number of 1-second intervals since then.)
- */
-
-/*
- * Attribute: Standard information (0x10).
- *
- * NOTE: Always resident.
- * NOTE: Present in all base file records on a volume.
- * NOTE: There is conflicting information about the meaning of each of the time
- *      fields but the meaning as defined below has been verified to be
- *      correct by practical experimentation on Windows NT4 SP6a and is hence
- *      assumed to be the one and only correct interpretation.
- */
-typedef struct {
-/*Ofs*/
-/*  0*/        sle64 creation_time;            /* Time file was created. Updated when
-                                          a filename is changed(?). */
-/*  8*/        sle64 last_data_change_time;    /* Time the data attribute was last
-                                          modified. */
-/* 16*/        sle64 last_mft_change_time;     /* Time this mft record was last
-                                          modified. */
-/* 24*/        sle64 last_access_time;         /* Approximate time when the file was
-                                          last accessed (obviously this is not
-                                          updated on read-only volumes). In
-                                          Windows this is only updated when
-                                          accessed if some time delta has
-                                          passed since the last update. Also,
-                                          last access time updates can be
-                                          disabled altogether for speed. */
-/* 32*/        FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
-/* 36*/        union {
-       /* NTFS 1.2 */
-               struct {
-               /* 36*/ u8 reserved12[12];      /* Reserved/alignment to 8-byte
-                                                  boundary. */
-               } __attribute__ ((__packed__)) v1;
-       /* sizeof() = 48 bytes */
-       /* NTFS 3.x */
-               struct {
-/*
- * If a volume has been upgraded from a previous NTFS version, then these
- * fields are present only if the file has been accessed since the upgrade.
- * Recognize the difference by comparing the length of the resident attribute
- * value. If it is 48, then the following fields are missing. If it is 72 then
- * the fields are present. Maybe just check like this:
- *     if (resident.ValueLength < sizeof(STANDARD_INFORMATION)) {
- *             Assume NTFS 1.2- format.
- *             If (volume version is 3.x)
- *                     Upgrade attribute to NTFS 3.x format.
- *             else
- *                     Use NTFS 1.2- format for access.
- *     } else
- *             Use NTFS 3.x format for access.
- * Only problem is that it might be legal to set the length of the value to
- * arbitrarily large values thus spoiling this check. - But chkdsk probably
- * views that as a corruption, assuming that it behaves like this for all
- * attributes.
- */
-               /* 36*/ le32 maximum_versions;  /* Maximum allowed versions for
-                               file. Zero if version numbering is disabled. */
-               /* 40*/ le32 version_number;    /* This file's version (if any).
-                               Set to zero if maximum_versions is zero. */
-               /* 44*/ le32 class_id;          /* Class id from bidirectional
-                               class id index (?). */
-               /* 48*/ le32 owner_id;          /* Owner_id of the user owning
-                               the file. Translate via $Q index in FILE_Extend
-                               /$Quota to the quota control entry for the user
-                               owning the file. Zero if quotas are disabled. */
-               /* 52*/ le32 security_id;       /* Security_id for the file.
-                               Translate via $SII index and $SDS data stream
-                               in FILE_Secure to the security descriptor. */
-               /* 56*/ le64 quota_charged;     /* Byte size of the charge to
-                               the quota for all streams of the file. Note: Is
-                               zero if quotas are disabled. */
-               /* 64*/ leUSN usn;              /* Last update sequence number
-                               of the file.  This is a direct index into the
-                               transaction log file ($UsnJrnl).  It is zero if
-                               the usn journal is disabled or this file has
-                               not been subject to logging yet.  See usnjrnl.h
-                               for details. */
-               } __attribute__ ((__packed__)) v3;
-       /* sizeof() = 72 bytes (NTFS 3.x) */
-       } __attribute__ ((__packed__)) ver;
-} __attribute__ ((__packed__)) STANDARD_INFORMATION;
-
-/*
- * Attribute: Attribute list (0x20).
- *
- * - Can be either resident or non-resident.
- * - Value consists of a sequence of variable length, 8-byte aligned,
- * ATTR_LIST_ENTRY records.
- * - The list is not terminated by anything at all! The only way to know when
- * the end is reached is to keep track of the current offset and compare it to
- * the attribute value size.
- * - The attribute list attribute contains one entry for each attribute of
- * the file in which the list is located, except for the list attribute
- * itself. The list is sorted: first by attribute type, second by attribute
- * name (if present), third by instance number. The extents of one
- * non-resident attribute (if present) immediately follow after the initial
- * extent. They are ordered by lowest_vcn and have their instace set to zero.
- * It is not allowed to have two attributes with all sorting keys equal.
- * - Further restrictions:
- *     - If not resident, the vcn to lcn mapping array has to fit inside the
- *       base mft record.
- *     - The attribute list attribute value has a maximum size of 256kb. This
- *       is imposed by the Windows cache manager.
- * - Attribute lists are only used when the attributes of mft record do not
- * fit inside the mft record despite all attributes (that can be made
- * non-resident) having been made non-resident. This can happen e.g. when:
- *     - File has a large number of hard links (lots of file name
- *       attributes present).
- *     - The mapping pairs array of some non-resident attribute becomes so
- *       large due to fragmentation that it overflows the mft record.
- *     - The security descriptor is very complex (not applicable to
- *       NTFS 3.0 volumes).
- *     - There are many named streams.
- */
-typedef struct {
-/*Ofs*/
-/*  0*/        ATTR_TYPE type;         /* Type of referenced attribute. */
-/*  4*/        le16 length;            /* Byte size of this entry (8-byte aligned). */
-/*  6*/        u8 name_length;         /* Size in Unicode chars of the name of the
-                                  attribute or 0 if unnamed. */
-/*  7*/        u8 name_offset;         /* Byte offset to beginning of attribute name
-                                  (always set this to where the name would
-                                  start even if unnamed). */
-/*  8*/        leVCN lowest_vcn;       /* Lowest virtual cluster number of this portion
-                                  of the attribute value. This is usually 0. It
-                                  is non-zero for the case where one attribute
-                                  does not fit into one mft record and thus
-                                  several mft records are allocated to hold
-                                  this attribute. In the latter case, each mft
-                                  record holds one extent of the attribute and
-                                  there is one attribute list entry for each
-                                  extent. NOTE: This is DEFINITELY a signed
-                                  value! The windows driver uses cmp, followed
-                                  by jg when comparing this, thus it treats it
-                                  as signed. */
-/* 16*/        leMFT_REF mft_reference;/* The reference of the mft record holding
-                                  the ATTR_RECORD for this portion of the
-                                  attribute value. */
-/* 24*/        le16 instance;          /* If lowest_vcn = 0, the instance of the
-                                  attribute being referenced; otherwise 0. */
-/* 26*/        ntfschar name[0];       /* Use when creating only. When reading use
-                                  name_offset to determine the location of the
-                                  name. */
-/* sizeof() = 26 + (attribute_name_length * 2) bytes */
-} __attribute__ ((__packed__)) ATTR_LIST_ENTRY;
-
-/*
- * The maximum allowed length for a file name.
- */
-#define MAXIMUM_FILE_NAME_LENGTH       255
-
-/*
- * Possible namespaces for filenames in ntfs (8-bit).
- */
-enum {
-       FILE_NAME_POSIX         = 0x00,
-       /* This is the largest namespace. It is case sensitive and allows all
-          Unicode characters except for: '\0' and '/'.  Beware that in
-          WinNT/2k/2003 by default files which eg have the same name except
-          for their case will not be distinguished by the standard utilities
-          and thus a "del filename" will delete both "filename" and "fileName"
-          without warning.  However if for example Services For Unix (SFU) are
-          installed and the case sensitive option was enabled at installation
-          time, then you can create/access/delete such files.
-          Note that even SFU places restrictions on the filenames beyond the
-          '\0' and '/' and in particular the following set of characters is
-          not allowed: '"', '/', '<', '>', '\'.  All other characters,
-          including the ones no allowed in WIN32 namespace are allowed.
-          Tested with SFU 3.5 (this is now free) running on Windows XP. */
-       FILE_NAME_WIN32         = 0x01,
-       /* The standard WinNT/2k NTFS long filenames. Case insensitive.  All
-          Unicode chars except: '\0', '"', '*', '/', ':', '<', '>', '?', '\',
-          and '|'.  Further, names cannot end with a '.' or a space. */
-       FILE_NAME_DOS           = 0x02,
-       /* The standard DOS filenames (8.3 format). Uppercase only.  All 8-bit
-          characters greater space, except: '"', '*', '+', ',', '/', ':', ';',
-          '<', '=', '>', '?', and '\'. */
-       FILE_NAME_WIN32_AND_DOS = 0x03,
-       /* 3 means that both the Win32 and the DOS filenames are identical and
-          hence have been saved in this single filename record. */
-} __attribute__ ((__packed__));
-
-typedef u8 FILE_NAME_TYPE_FLAGS;
-
-/*
- * Attribute: Filename (0x30).
- *
- * NOTE: Always resident.
- * NOTE: All fields, except the parent_directory, are only updated when the
- *      filename is changed. Until then, they just become out of sync with
- *      reality and the more up to date values are present in the standard
- *      information attribute.
- * NOTE: There is conflicting information about the meaning of each of the time
- *      fields but the meaning as defined below has been verified to be
- *      correct by practical experimentation on Windows NT4 SP6a and is hence
- *      assumed to be the one and only correct interpretation.
- */
-typedef struct {
-/*hex ofs*/
-/*  0*/        leMFT_REF parent_directory;     /* Directory this filename is
-                                          referenced from. */
-/*  8*/        sle64 creation_time;            /* Time file was created. */
-/* 10*/        sle64 last_data_change_time;    /* Time the data attribute was last
-                                          modified. */
-/* 18*/        sle64 last_mft_change_time;     /* Time this mft record was last
-                                          modified. */
-/* 20*/        sle64 last_access_time;         /* Time this mft record was last
-                                          accessed. */
-/* 28*/        sle64 allocated_size;           /* Byte size of on-disk allocated space
-                                          for the unnamed data attribute.  So
-                                          for normal $DATA, this is the
-                                          allocated_size from the unnamed
-                                          $DATA attribute and for compressed
-                                          and/or sparse $DATA, this is the
-                                          compressed_size from the unnamed
-                                          $DATA attribute.  For a directory or
-                                          other inode without an unnamed $DATA
-                                          attribute, this is always 0.  NOTE:
-                                          This is a multiple of the cluster
-                                          size. */
-/* 30*/        sle64 data_size;                /* Byte size of actual data in unnamed
-                                          data attribute.  For a directory or
-                                          other inode without an unnamed $DATA
-                                          attribute, this is always 0. */
-/* 38*/        FILE_ATTR_FLAGS file_attributes;        /* Flags describing the file. */
-/* 3c*/        union {
-       /* 3c*/ struct {
-               /* 3c*/ le16 packed_ea_size;    /* Size of the buffer needed to
-                                                  pack the extended attributes
-                                                  (EAs), if such are present.*/
-               /* 3e*/ le16 reserved;          /* Reserved for alignment. */
-               } __attribute__ ((__packed__)) ea;
-       /* 3c*/ struct {
-               /* 3c*/ le32 reparse_point_tag; /* Type of reparse point,
-                                                  present only in reparse
-                                                  points and only if there are
-                                                  no EAs. */
-               } __attribute__ ((__packed__)) rp;
-       } __attribute__ ((__packed__)) type;
-/* 40*/        u8 file_name_length;                    /* Length of file name in
-                                                  (Unicode) characters. */
-/* 41*/        FILE_NAME_TYPE_FLAGS file_name_type;    /* Namespace of the file name.*/
-/* 42*/        ntfschar file_name[0];                  /* File name in Unicode. */
-} __attribute__ ((__packed__)) FILE_NAME_ATTR;
-
-/*
- * GUID structures store globally unique identifiers (GUID). A GUID is a
- * 128-bit value consisting of one group of eight hexadecimal digits, followed
- * by three groups of four hexadecimal digits each, followed by one group of
- * twelve hexadecimal digits. GUIDs are Microsoft's implementation of the
- * distributed computing environment (DCE) universally unique identifier (UUID).
- * Example of a GUID:
- *     1F010768-5A73-BC91-0010A52216A7
- */
-typedef struct {
-       le32 data1;     /* The first eight hexadecimal digits of the GUID. */
-       le16 data2;     /* The first group of four hexadecimal digits. */
-       le16 data3;     /* The second group of four hexadecimal digits. */
-       u8 data4[8];    /* The first two bytes are the third group of four
-                          hexadecimal digits. The remaining six bytes are the
-                          final 12 hexadecimal digits. */
-} __attribute__ ((__packed__)) GUID;
-
-/*
- * FILE_Extend/$ObjId contains an index named $O. This index contains all
- * object_ids present on the volume as the index keys and the corresponding
- * mft_record numbers as the index entry data parts. The data part (defined
- * below) also contains three other object_ids:
- *     birth_volume_id - object_id of FILE_Volume on which the file was first
- *                       created. Optional (i.e. can be zero).
- *     birth_object_id - object_id of file when it was first created. Usually
- *                       equals the object_id. Optional (i.e. can be zero).
- *     domain_id       - Reserved (always zero).
- */
-typedef struct {
-       leMFT_REF mft_reference;/* Mft record containing the object_id in
-                                  the index entry key. */
-       union {
-               struct {
-                       GUID birth_volume_id;
-                       GUID birth_object_id;
-                       GUID domain_id;
-               } __attribute__ ((__packed__)) origin;
-               u8 extended_info[48];
-       } __attribute__ ((__packed__)) opt;
-} __attribute__ ((__packed__)) OBJ_ID_INDEX_DATA;
-
-/*
- * Attribute: Object id (NTFS 3.0+) (0x40).
- *
- * NOTE: Always resident.
- */
-typedef struct {
-       GUID object_id;                         /* Unique id assigned to the
-                                                  file.*/
-       /* The following fields are optional. The attribute value size is 16
-          bytes, i.e. sizeof(GUID), if these are not present at all. Note,
-          the entries can be present but one or more (or all) can be zero
-          meaning that that particular value(s) is(are) not defined. */
-       union {
-               struct {
-                       GUID birth_volume_id;   /* Unique id of volume on which
-                                                  the file was first created.*/
-                       GUID birth_object_id;   /* Unique id of file when it was
-                                                  first created. */
-                       GUID domain_id;         /* Reserved, zero. */
-               } __attribute__ ((__packed__)) origin;
-               u8 extended_info[48];
-       } __attribute__ ((__packed__)) opt;
-} __attribute__ ((__packed__)) OBJECT_ID_ATTR;
-
-/*
- * The pre-defined IDENTIFIER_AUTHORITIES used as SID_IDENTIFIER_AUTHORITY in
- * the SID structure (see below).
- */
-//typedef enum {                                       /* SID string prefix. */
-//     SECURITY_NULL_SID_AUTHORITY     = {0, 0, 0, 0, 0, 0},   /* S-1-0 */
-//     SECURITY_WORLD_SID_AUTHORITY    = {0, 0, 0, 0, 0, 1},   /* S-1-1 */
-//     SECURITY_LOCAL_SID_AUTHORITY    = {0, 0, 0, 0, 0, 2},   /* S-1-2 */
-//     SECURITY_CREATOR_SID_AUTHORITY  = {0, 0, 0, 0, 0, 3},   /* S-1-3 */
-//     SECURITY_NON_UNIQUE_AUTHORITY   = {0, 0, 0, 0, 0, 4},   /* S-1-4 */
-//     SECURITY_NT_SID_AUTHORITY       = {0, 0, 0, 0, 0, 5},   /* S-1-5 */
-//} IDENTIFIER_AUTHORITIES;
-
-/*
- * These relative identifiers (RIDs) are used with the above identifier
- * authorities to make up universal well-known SIDs.
- *
- * Note: The relative identifier (RID) refers to the portion of a SID, which
- * identifies a user or group in relation to the authority that issued the SID.
- * For example, the universal well-known SID Creator Owner ID (S-1-3-0) is
- * made up of the identifier authority SECURITY_CREATOR_SID_AUTHORITY (3) and
- * the relative identifier SECURITY_CREATOR_OWNER_RID (0).
- */
-typedef enum {                                 /* Identifier authority. */
-       SECURITY_NULL_RID                 = 0,  /* S-1-0 */
-       SECURITY_WORLD_RID                = 0,  /* S-1-1 */
-       SECURITY_LOCAL_RID                = 0,  /* S-1-2 */
-
-       SECURITY_CREATOR_OWNER_RID        = 0,  /* S-1-3 */
-       SECURITY_CREATOR_GROUP_RID        = 1,  /* S-1-3 */
-
-       SECURITY_CREATOR_OWNER_SERVER_RID = 2,  /* S-1-3 */
-       SECURITY_CREATOR_GROUP_SERVER_RID = 3,  /* S-1-3 */
-
-       SECURITY_DIALUP_RID               = 1,
-       SECURITY_NETWORK_RID              = 2,
-       SECURITY_BATCH_RID                = 3,
-       SECURITY_INTERACTIVE_RID          = 4,
-       SECURITY_SERVICE_RID              = 6,
-       SECURITY_ANONYMOUS_LOGON_RID      = 7,
-       SECURITY_PROXY_RID                = 8,
-       SECURITY_ENTERPRISE_CONTROLLERS_RID=9,
-       SECURITY_SERVER_LOGON_RID         = 9,
-       SECURITY_PRINCIPAL_SELF_RID       = 0xa,
-       SECURITY_AUTHENTICATED_USER_RID   = 0xb,
-       SECURITY_RESTRICTED_CODE_RID      = 0xc,
-       SECURITY_TERMINAL_SERVER_RID      = 0xd,
-
-       SECURITY_LOGON_IDS_RID            = 5,
-       SECURITY_LOGON_IDS_RID_COUNT      = 3,
-
-       SECURITY_LOCAL_SYSTEM_RID         = 0x12,
-
-       SECURITY_NT_NON_UNIQUE            = 0x15,
-
-       SECURITY_BUILTIN_DOMAIN_RID       = 0x20,
-
-       /*
-        * Well-known domain relative sub-authority values (RIDs).
-        */
-
-       /* Users. */
-       DOMAIN_USER_RID_ADMIN             = 0x1f4,
-       DOMAIN_USER_RID_GUEST             = 0x1f5,
-       DOMAIN_USER_RID_KRBTGT            = 0x1f6,
-
-       /* Groups. */
-       DOMAIN_GROUP_RID_ADMINS           = 0x200,
-       DOMAIN_GROUP_RID_USERS            = 0x201,
-       DOMAIN_GROUP_RID_GUESTS           = 0x202,
-       DOMAIN_GROUP_RID_COMPUTERS        = 0x203,
-       DOMAIN_GROUP_RID_CONTROLLERS      = 0x204,
-       DOMAIN_GROUP_RID_CERT_ADMINS      = 0x205,
-       DOMAIN_GROUP_RID_SCHEMA_ADMINS    = 0x206,
-       DOMAIN_GROUP_RID_ENTERPRISE_ADMINS= 0x207,
-       DOMAIN_GROUP_RID_POLICY_ADMINS    = 0x208,
-
-       /* Aliases. */
-       DOMAIN_ALIAS_RID_ADMINS           = 0x220,
-       DOMAIN_ALIAS_RID_USERS            = 0x221,
-       DOMAIN_ALIAS_RID_GUESTS           = 0x222,
-       DOMAIN_ALIAS_RID_POWER_USERS      = 0x223,
-
-       DOMAIN_ALIAS_RID_ACCOUNT_OPS      = 0x224,
-       DOMAIN_ALIAS_RID_SYSTEM_OPS       = 0x225,
-       DOMAIN_ALIAS_RID_PRINT_OPS        = 0x226,
-       DOMAIN_ALIAS_RID_BACKUP_OPS       = 0x227,
-
-       DOMAIN_ALIAS_RID_REPLICATOR       = 0x228,
-       DOMAIN_ALIAS_RID_RAS_SERVERS      = 0x229,
-       DOMAIN_ALIAS_RID_PREW2KCOMPACCESS = 0x22a,
-} RELATIVE_IDENTIFIERS;
-
-/*
- * The universal well-known SIDs:
- *
- *     NULL_SID                        S-1-0-0
- *     WORLD_SID                       S-1-1-0
- *     LOCAL_SID                       S-1-2-0
- *     CREATOR_OWNER_SID               S-1-3-0
- *     CREATOR_GROUP_SID               S-1-3-1
- *     CREATOR_OWNER_SERVER_SID        S-1-3-2
- *     CREATOR_GROUP_SERVER_SID        S-1-3-3
- *
- *     (Non-unique IDs)                S-1-4
- *
- * NT well-known SIDs:
- *
- *     NT_AUTHORITY_SID        S-1-5
- *     DIALUP_SID              S-1-5-1
- *
- *     NETWORD_SID             S-1-5-2
- *     BATCH_SID               S-1-5-3
- *     INTERACTIVE_SID         S-1-5-4
- *     SERVICE_SID             S-1-5-6
- *     ANONYMOUS_LOGON_SID     S-1-5-7         (aka null logon session)
- *     PROXY_SID               S-1-5-8
- *     SERVER_LOGON_SID        S-1-5-9         (aka domain controller account)
- *     SELF_SID                S-1-5-10        (self RID)
- *     AUTHENTICATED_USER_SID  S-1-5-11
- *     RESTRICTED_CODE_SID     S-1-5-12        (running restricted code)
- *     TERMINAL_SERVER_SID     S-1-5-13        (running on terminal server)
- *
- *     (Logon IDs)             S-1-5-5-X-Y
- *
- *     (NT non-unique IDs)     S-1-5-0x15-...
- *
- *     (Built-in domain)       S-1-5-0x20
- */
-
-/*
- * The SID_IDENTIFIER_AUTHORITY is a 48-bit value used in the SID structure.
- *
- * NOTE: This is stored as a big endian number, hence the high_part comes
- * before the low_part.
- */
-typedef union {
-       struct {
-               u16 high_part;  /* High 16-bits. */
-               u32 low_part;   /* Low 32-bits. */
-       } __attribute__ ((__packed__)) parts;
-       u8 value[6];            /* Value as individual bytes. */
-} __attribute__ ((__packed__)) SID_IDENTIFIER_AUTHORITY;
-
-/*
- * The SID structure is a variable-length structure used to uniquely identify
- * users or groups. SID stands for security identifier.
- *
- * The standard textual representation of the SID is of the form:
- *     S-R-I-S-S...
- * Where:
- *    - The first "S" is the literal character 'S' identifying the following
- *     digits as a SID.
- *    - R is the revision level of the SID expressed as a sequence of digits
- *     either in decimal or hexadecimal (if the later, prefixed by "0x").
- *    - I is the 48-bit identifier_authority, expressed as digits as R above.
- *    - S... is one or more sub_authority values, expressed as digits as above.
- *
- * Example SID; the domain-relative SID of the local Administrators group on
- * Windows NT/2k:
- *     S-1-5-32-544
- * This translates to a SID with:
- *     revision = 1,
- *     sub_authority_count = 2,
- *     identifier_authority = {0,0,0,0,0,5},   // SECURITY_NT_AUTHORITY
- *     sub_authority[0] = 32,                  // SECURITY_BUILTIN_DOMAIN_RID
- *     sub_authority[1] = 544                  // DOMAIN_ALIAS_RID_ADMINS
- */
-typedef struct {
-       u8 revision;
-       u8 sub_authority_count;
-       SID_IDENTIFIER_AUTHORITY identifier_authority;
-       le32 sub_authority[1];          /* At least one sub_authority. */
-} __attribute__ ((__packed__)) SID;
-
-/*
- * Current constants for SIDs.
- */
-typedef enum {
-       SID_REVISION                    =  1,   /* Current revision level. */
-       SID_MAX_SUB_AUTHORITIES         = 15,   /* Maximum number of those. */
-       SID_RECOMMENDED_SUB_AUTHORITIES =  1,   /* Will change to around 6 in
-                                                  a future revision. */
-} SID_CONSTANTS;
-
-/*
- * The predefined ACE types (8-bit, see below).
- */
-enum {
-       ACCESS_MIN_MS_ACE_TYPE          = 0,
-       ACCESS_ALLOWED_ACE_TYPE         = 0,
-       ACCESS_DENIED_ACE_TYPE          = 1,
-       SYSTEM_AUDIT_ACE_TYPE           = 2,
-       SYSTEM_ALARM_ACE_TYPE           = 3, /* Not implemented as of Win2k. */
-       ACCESS_MAX_MS_V2_ACE_TYPE       = 3,
-
-       ACCESS_ALLOWED_COMPOUND_ACE_TYPE= 4,
-       ACCESS_MAX_MS_V3_ACE_TYPE       = 4,
-
-       /* The following are Win2k only. */
-       ACCESS_MIN_MS_OBJECT_ACE_TYPE   = 5,
-       ACCESS_ALLOWED_OBJECT_ACE_TYPE  = 5,
-       ACCESS_DENIED_OBJECT_ACE_TYPE   = 6,
-       SYSTEM_AUDIT_OBJECT_ACE_TYPE    = 7,
-       SYSTEM_ALARM_OBJECT_ACE_TYPE    = 8,
-       ACCESS_MAX_MS_OBJECT_ACE_TYPE   = 8,
-
-       ACCESS_MAX_MS_V4_ACE_TYPE       = 8,
-
-       /* This one is for WinNT/2k. */
-       ACCESS_MAX_MS_ACE_TYPE          = 8,
-} __attribute__ ((__packed__));
-
-typedef u8 ACE_TYPES;
-
-/*
- * The ACE flags (8-bit) for audit and inheritance (see below).
- *
- * SUCCESSFUL_ACCESS_ACE_FLAG is only used with system audit and alarm ACE
- * types to indicate that a message is generated (in Windows!) for successful
- * accesses.
- *
- * FAILED_ACCESS_ACE_FLAG is only used with system audit and alarm ACE types
- * to indicate that a message is generated (in Windows!) for failed accesses.
- */
-enum {
-       /* The inheritance flags. */
-       OBJECT_INHERIT_ACE              = 0x01,
-       CONTAINER_INHERIT_ACE           = 0x02,
-       NO_PROPAGATE_INHERIT_ACE        = 0x04,
-       INHERIT_ONLY_ACE                = 0x08,
-       INHERITED_ACE                   = 0x10, /* Win2k only. */
-       VALID_INHERIT_FLAGS             = 0x1f,
-
-       /* The audit flags. */
-       SUCCESSFUL_ACCESS_ACE_FLAG      = 0x40,
-       FAILED_ACCESS_ACE_FLAG          = 0x80,
-} __attribute__ ((__packed__));
-
-typedef u8 ACE_FLAGS;
-
-/*
- * An ACE is an access-control entry in an access-control list (ACL).
- * An ACE defines access to an object for a specific user or group or defines
- * the types of access that generate system-administration messages or alarms
- * for a specific user or group. The user or group is identified by a security
- * identifier (SID).
- *
- * Each ACE starts with an ACE_HEADER structure (aligned on 4-byte boundary),
- * which specifies the type and size of the ACE. The format of the subsequent
- * data depends on the ACE type.
- */
-typedef struct {
-/*Ofs*/
-/*  0*/        ACE_TYPES type;         /* Type of the ACE. */
-/*  1*/        ACE_FLAGS flags;        /* Flags describing the ACE. */
-/*  2*/        le16 size;              /* Size in bytes of the ACE. */
-} __attribute__ ((__packed__)) ACE_HEADER;
-
-/*
- * The access mask (32-bit). Defines the access rights.
- *
- * The specific rights (bits 0 to 15).  These depend on the type of the object
- * being secured by the ACE.
- */
-enum {
-       /* Specific rights for files and directories are as follows: */
-
-       /* Right to read data from the file. (FILE) */
-       FILE_READ_DATA                  = cpu_to_le32(0x00000001),
-       /* Right to list contents of a directory. (DIRECTORY) */
-       FILE_LIST_DIRECTORY             = cpu_to_le32(0x00000001),
-
-       /* Right to write data to the file. (FILE) */
-       FILE_WRITE_DATA                 = cpu_to_le32(0x00000002),
-       /* Right to create a file in the directory. (DIRECTORY) */
-       FILE_ADD_FILE                   = cpu_to_le32(0x00000002),
-
-       /* Right to append data to the file. (FILE) */
-       FILE_APPEND_DATA                = cpu_to_le32(0x00000004),
-       /* Right to create a subdirectory. (DIRECTORY) */
-       FILE_ADD_SUBDIRECTORY           = cpu_to_le32(0x00000004),
-
-       /* Right to read extended attributes. (FILE/DIRECTORY) */
-       FILE_READ_EA                    = cpu_to_le32(0x00000008),
-
-       /* Right to write extended attributes. (FILE/DIRECTORY) */
-       FILE_WRITE_EA                   = cpu_to_le32(0x00000010),
-
-       /* Right to execute a file. (FILE) */
-       FILE_EXECUTE                    = cpu_to_le32(0x00000020),
-       /* Right to traverse the directory. (DIRECTORY) */
-       FILE_TRAVERSE                   = cpu_to_le32(0x00000020),
-
-       /*
-        * Right to delete a directory and all the files it contains (its
-        * children), even if the files are read-only. (DIRECTORY)
-        */
-       FILE_DELETE_CHILD               = cpu_to_le32(0x00000040),
-
-       /* Right to read file attributes. (FILE/DIRECTORY) */
-       FILE_READ_ATTRIBUTES            = cpu_to_le32(0x00000080),
-
-       /* Right to change file attributes. (FILE/DIRECTORY) */
-       FILE_WRITE_ATTRIBUTES           = cpu_to_le32(0x00000100),
-
-       /*
-        * The standard rights (bits 16 to 23).  These are independent of the
-        * type of object being secured.
-        */
-
-       /* Right to delete the object. */
-       DELETE                          = cpu_to_le32(0x00010000),
-
-       /*
-        * Right to read the information in the object's security descriptor,
-        * not including the information in the SACL, i.e. right to read the
-        * security descriptor and owner.
-        */
-       READ_CONTROL                    = cpu_to_le32(0x00020000),
-
-       /* Right to modify the DACL in the object's security descriptor. */
-       WRITE_DAC                       = cpu_to_le32(0x00040000),
-
-       /* Right to change the owner in the object's security descriptor. */
-       WRITE_OWNER                     = cpu_to_le32(0x00080000),
-
-       /*
-        * Right to use the object for synchronization.  Enables a process to
-        * wait until the object is in the signalled state.  Some object types
-        * do not support this access right.
-        */
-       SYNCHRONIZE                     = cpu_to_le32(0x00100000),
-
-       /*
-        * The following STANDARD_RIGHTS_* are combinations of the above for
-        * convenience and are defined by the Win32 API.
-        */
-
-       /* These are currently defined to READ_CONTROL. */
-       STANDARD_RIGHTS_READ            = cpu_to_le32(0x00020000),
-       STANDARD_RIGHTS_WRITE           = cpu_to_le32(0x00020000),
-       STANDARD_RIGHTS_EXECUTE         = cpu_to_le32(0x00020000),
-
-       /* Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access. */
-       STANDARD_RIGHTS_REQUIRED        = cpu_to_le32(0x000f0000),
-
-       /*
-        * Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and
-        * SYNCHRONIZE access.
-        */
-       STANDARD_RIGHTS_ALL             = cpu_to_le32(0x001f0000),
-
-       /*
-        * The access system ACL and maximum allowed access types (bits 24 to
-        * 25, bits 26 to 27 are reserved).
-        */
-       ACCESS_SYSTEM_SECURITY          = cpu_to_le32(0x01000000),
-       MAXIMUM_ALLOWED                 = cpu_to_le32(0x02000000),
-
-       /*
-        * The generic rights (bits 28 to 31).  These map onto the standard and
-        * specific rights.
-        */
-
-       /* Read, write, and execute access. */
-       GENERIC_ALL                     = cpu_to_le32(0x10000000),
-
-       /* Execute access. */
-       GENERIC_EXECUTE                 = cpu_to_le32(0x20000000),
-
-       /*
-        * Write access.  For files, this maps onto:
-        *      FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA |
-        *      FILE_WRITE_EA | STANDARD_RIGHTS_WRITE | SYNCHRONIZE
-        * For directories, the mapping has the same numerical value.  See
-        * above for the descriptions of the rights granted.
-        */
-       GENERIC_WRITE                   = cpu_to_le32(0x40000000),
-
-       /*
-        * Read access.  For files, this maps onto:
-        *      FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_READ_EA |
-        *      STANDARD_RIGHTS_READ | SYNCHRONIZE
-        * For directories, the mapping has the same numberical value.  See
-        * above for the descriptions of the rights granted.
-        */
-       GENERIC_READ                    = cpu_to_le32(0x80000000),
-};
-
-typedef le32 ACCESS_MASK;
-
-/*
- * The generic mapping array. Used to denote the mapping of each generic
- * access right to a specific access mask.
- *
- * FIXME: What exactly is this and what is it for? (AIA)
- */
-typedef struct {
-       ACCESS_MASK generic_read;
-       ACCESS_MASK generic_write;
-       ACCESS_MASK generic_execute;
-       ACCESS_MASK generic_all;
-} __attribute__ ((__packed__)) GENERIC_MAPPING;
-
-/*
- * The predefined ACE type structures are as defined below.
- */
-
-/*
- * ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE
- */
-typedef struct {
-/*  0  ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
-       ACE_TYPES type;         /* Type of the ACE. */
-       ACE_FLAGS flags;        /* Flags describing the ACE. */
-       le16 size;              /* Size in bytes of the ACE. */
-/*  4*/        ACCESS_MASK mask;       /* Access mask associated with the ACE. */
-
-/*  8*/        SID sid;                /* The SID associated with the ACE. */
-} __attribute__ ((__packed__)) ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE,
-                              SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE;
-
-/*
- * The object ACE flags (32-bit).
- */
-enum {
-       ACE_OBJECT_TYPE_PRESENT                 = cpu_to_le32(1),
-       ACE_INHERITED_OBJECT_TYPE_PRESENT       = cpu_to_le32(2),
-};
-
-typedef le32 OBJECT_ACE_FLAGS;
-
-typedef struct {
-/*  0  ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
-       ACE_TYPES type;         /* Type of the ACE. */
-       ACE_FLAGS flags;        /* Flags describing the ACE. */
-       le16 size;              /* Size in bytes of the ACE. */
-/*  4*/        ACCESS_MASK mask;       /* Access mask associated with the ACE. */
-
-/*  8*/        OBJECT_ACE_FLAGS object_flags;  /* Flags describing the object ACE. */
-/* 12*/        GUID object_type;
-/* 28*/        GUID inherited_object_type;
-
-/* 44*/        SID sid;                /* The SID associated with the ACE. */
-} __attribute__ ((__packed__)) ACCESS_ALLOWED_OBJECT_ACE,
-                              ACCESS_DENIED_OBJECT_ACE,
-                              SYSTEM_AUDIT_OBJECT_ACE,
-                              SYSTEM_ALARM_OBJECT_ACE;
-
-/*
- * An ACL is an access-control list (ACL).
- * An ACL starts with an ACL header structure, which specifies the size of
- * the ACL and the number of ACEs it contains. The ACL header is followed by
- * zero or more access control entries (ACEs). The ACL as well as each ACE
- * are aligned on 4-byte boundaries.
- */
-typedef struct {
-       u8 revision;    /* Revision of this ACL. */
-       u8 alignment1;
-       le16 size;      /* Allocated space in bytes for ACL. Includes this
-                          header, the ACEs and the remaining free space. */
-       le16 ace_count; /* Number of ACEs in the ACL. */
-       le16 alignment2;
-/* sizeof() = 8 bytes */
-} __attribute__ ((__packed__)) ACL;
-
-/*
- * Current constants for ACLs.
- */
-typedef enum {
-       /* Current revision. */
-       ACL_REVISION            = 2,
-       ACL_REVISION_DS         = 4,
-
-       /* History of revisions. */
-       ACL_REVISION1           = 1,
-       MIN_ACL_REVISION        = 2,
-       ACL_REVISION2           = 2,
-       ACL_REVISION3           = 3,
-       ACL_REVISION4           = 4,
-       MAX_ACL_REVISION        = 4,
-} ACL_CONSTANTS;
-
-/*
- * The security descriptor control flags (16-bit).
- *
- * SE_OWNER_DEFAULTED - This boolean flag, when set, indicates that the SID
- *     pointed to by the Owner field was provided by a defaulting mechanism
- *     rather than explicitly provided by the original provider of the
- *     security descriptor.  This may affect the treatment of the SID with
- *     respect to inheritance of an owner.
- *
- * SE_GROUP_DEFAULTED - This boolean flag, when set, indicates that the SID in
- *     the Group field was provided by a defaulting mechanism rather than
- *     explicitly provided by the original provider of the security
- *     descriptor.  This may affect the treatment of the SID with respect to
- *     inheritance of a primary group.
- *
- * SE_DACL_PRESENT - This boolean flag, when set, indicates that the security
- *     descriptor contains a discretionary ACL.  If this flag is set and the
- *     Dacl field of the SECURITY_DESCRIPTOR is null, then a null ACL is
- *     explicitly being specified.
- *
- * SE_DACL_DEFAULTED - This boolean flag, when set, indicates that the ACL
- *     pointed to by the Dacl field was provided by a defaulting mechanism
- *     rather than explicitly provided by the original provider of the
- *     security descriptor.  This may affect the treatment of the ACL with
- *     respect to inheritance of an ACL.  This flag is ignored if the
- *     DaclPresent flag is not set.
- *
- * SE_SACL_PRESENT - This boolean flag, when set,  indicates that the security
- *     descriptor contains a system ACL pointed to by the Sacl field.  If this
- *     flag is set and the Sacl field of the SECURITY_DESCRIPTOR is null, then
- *     an empty (but present) ACL is being specified.
- *
- * SE_SACL_DEFAULTED - This boolean flag, when set, indicates that the ACL
- *     pointed to by the Sacl field was provided by a defaulting mechanism
- *     rather than explicitly provided by the original provider of the
- *     security descriptor.  This may affect the treatment of the ACL with
- *     respect to inheritance of an ACL.  This flag is ignored if the
- *     SaclPresent flag is not set.
- *
- * SE_SELF_RELATIVE - This boolean flag, when set, indicates that the security
- *     descriptor is in self-relative form.  In this form, all fields of the
- *     security descriptor are contiguous in memory and all pointer fields are
- *     expressed as offsets from the beginning of the security descriptor.
- */
-enum {
-       SE_OWNER_DEFAULTED              = cpu_to_le16(0x0001),
-       SE_GROUP_DEFAULTED              = cpu_to_le16(0x0002),
-       SE_DACL_PRESENT                 = cpu_to_le16(0x0004),
-       SE_DACL_DEFAULTED               = cpu_to_le16(0x0008),
-
-       SE_SACL_PRESENT                 = cpu_to_le16(0x0010),
-       SE_SACL_DEFAULTED               = cpu_to_le16(0x0020),
-
-       SE_DACL_AUTO_INHERIT_REQ        = cpu_to_le16(0x0100),
-       SE_SACL_AUTO_INHERIT_REQ        = cpu_to_le16(0x0200),
-       SE_DACL_AUTO_INHERITED          = cpu_to_le16(0x0400),
-       SE_SACL_AUTO_INHERITED          = cpu_to_le16(0x0800),
-
-       SE_DACL_PROTECTED               = cpu_to_le16(0x1000),
-       SE_SACL_PROTECTED               = cpu_to_le16(0x2000),
-       SE_RM_CONTROL_VALID             = cpu_to_le16(0x4000),
-       SE_SELF_RELATIVE                = cpu_to_le16(0x8000)
-} __attribute__ ((__packed__));
-
-typedef le16 SECURITY_DESCRIPTOR_CONTROL;
-
-/*
- * Self-relative security descriptor. Contains the owner and group SIDs as well
- * as the sacl and dacl ACLs inside the security descriptor itself.
- */
-typedef struct {
-       u8 revision;    /* Revision level of the security descriptor. */
-       u8 alignment;
-       SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
-                          the descriptor as well as the following fields. */
-       le32 owner;     /* Byte offset to a SID representing an object's
-                          owner. If this is NULL, no owner SID is present in
-                          the descriptor. */
-       le32 group;     /* Byte offset to a SID representing an object's
-                          primary group. If this is NULL, no primary group
-                          SID is present in the descriptor. */
-       le32 sacl;      /* Byte offset to a system ACL. Only valid, if
-                          SE_SACL_PRESENT is set in the control field. If
-                          SE_SACL_PRESENT is set but sacl is NULL, a NULL ACL
-                          is specified. */
-       le32 dacl;      /* Byte offset to a discretionary ACL. Only valid, if
-                          SE_DACL_PRESENT is set in the control field. If
-                          SE_DACL_PRESENT is set but dacl is NULL, a NULL ACL
-                          (unconditionally granting access) is specified. */
-/* sizeof() = 0x14 bytes */
-} __attribute__ ((__packed__)) SECURITY_DESCRIPTOR_RELATIVE;
-
-/*
- * Absolute security descriptor. Does not contain the owner and group SIDs, nor
- * the sacl and dacl ACLs inside the security descriptor. Instead, it contains
- * pointers to these structures in memory. Obviously, absolute security
- * descriptors are only useful for in memory representations of security
- * descriptors. On disk, a self-relative security descriptor is used.
- */
-typedef struct {
-       u8 revision;    /* Revision level of the security descriptor. */
-       u8 alignment;
-       SECURITY_DESCRIPTOR_CONTROL control;    /* Flags qualifying the type of
-                          the descriptor as well as the following fields. */
-       SID *owner;     /* Points to a SID representing an object's owner. If
-                          this is NULL, no owner SID is present in the
-                          descriptor. */
-       SID *group;     /* Points to a SID representing an object's primary
-                          group. If this is NULL, no primary group SID is
-                          present in the descriptor. */
-       ACL *sacl;      /* Points to a system ACL. Only valid, if
-                          SE_SACL_PRESENT is set in the control field. If
-                          SE_SACL_PRESENT is set but sacl is NULL, a NULL ACL
-                          is specified. */
-       ACL *dacl;      /* Points to a discretionary ACL. Only valid, if
-                          SE_DACL_PRESENT is set in the control field. If
-                          SE_DACL_PRESENT is set but dacl is NULL, a NULL ACL
-                          (unconditionally granting access) is specified. */
-} __attribute__ ((__packed__)) SECURITY_DESCRIPTOR;
-
-/*
- * Current constants for security descriptors.
- */
-typedef enum {
-       /* Current revision. */
-       SECURITY_DESCRIPTOR_REVISION    = 1,
-       SECURITY_DESCRIPTOR_REVISION1   = 1,
-
-       /* The sizes of both the absolute and relative security descriptors is
-          the same as pointers, at least on ia32 architecture are 32-bit. */
-       SECURITY_DESCRIPTOR_MIN_LENGTH  = sizeof(SECURITY_DESCRIPTOR),
-} SECURITY_DESCRIPTOR_CONSTANTS;
-
-/*
- * Attribute: Security descriptor (0x50). A standard self-relative security
- * descriptor.
- *
- * NOTE: Can be resident or non-resident.
- * NOTE: Not used in NTFS 3.0+, as security descriptors are stored centrally
- * in FILE_Secure and the correct descriptor is found using the security_id
- * from the standard information attribute.
- */
-typedef SECURITY_DESCRIPTOR_RELATIVE SECURITY_DESCRIPTOR_ATTR;
-
-/*
- * On NTFS 3.0+, all security descriptors are stored in FILE_Secure. Only one
- * referenced instance of each unique security descriptor is stored.
- *
- * FILE_Secure contains no unnamed data attribute, i.e. it has zero length. It
- * does, however, contain two indexes ($SDH and $SII) as well as a named data
- * stream ($SDS).
- *
- * Every unique security descriptor is assigned a unique security identifier
- * (security_id, not to be confused with a SID). The security_id is unique for
- * the NTFS volume and is used as an index into the $SII index, which maps
- * security_ids to the security descriptor's storage location within the $SDS
- * data attribute. The $SII index is sorted by ascending security_id.
- *
- * A simple hash is computed from each security descriptor. This hash is used
- * as an index into the $SDH index, which maps security descriptor hashes to
- * the security descriptor's storage location within the $SDS data attribute.
- * The $SDH index is sorted by security descriptor hash and is stored in a B+
- * tree. When searching $SDH (with the intent of determining whether or not a
- * new security descriptor is already present in the $SDS data stream), if a
- * matching hash is found, but the security descriptors do not match, the
- * search in the $SDH index is continued, searching for a next matching hash.
- *
- * When a precise match is found, the security_id coresponding to the security
- * descriptor in the $SDS attribute is read from the found $SDH index entry and
- * is stored in the $STANDARD_INFORMATION attribute of the file/directory to
- * which the security descriptor is being applied. The $STANDARD_INFORMATION
- * attribute is present in all base mft records (i.e. in all files and
- * directories).
- *
- * If a match is not found, the security descriptor is assigned a new unique
- * security_id and is added to the $SDS data attribute. Then, entries
- * referencing the this security descriptor in the $SDS data attribute are
- * added to the $SDH and $SII indexes.
- *
- * Note: Entries are never deleted from FILE_Secure, even if nothing
- * references an entry any more.
- */
-
-/*
- * This header precedes each security descriptor in the $SDS data stream.
- * This is also the index entry data part of both the $SII and $SDH indexes.
- */
-typedef struct {
-       le32 hash;        /* Hash of the security descriptor. */
-       le32 security_id; /* The security_id assigned to the descriptor. */
-       le64 offset;      /* Byte offset of this entry in the $SDS stream. */
-       le32 length;      /* Size in bytes of this entry in $SDS stream. */
-} __attribute__ ((__packed__)) SECURITY_DESCRIPTOR_HEADER;
-
-/*
- * The $SDS data stream contains the security descriptors, aligned on 16-byte
- * boundaries, sorted by security_id in a B+ tree. Security descriptors cannot
- * cross 256kib boundaries (this restriction is imposed by the Windows cache
- * manager). Each security descriptor is contained in a SDS_ENTRY structure.
- * Also, each security descriptor is stored twice in the $SDS stream with a
- * fixed offset of 0x40000 bytes (256kib, the Windows cache manager's max size)
- * between them; i.e. if a SDS_ENTRY specifies an offset of 0x51d0, then the
- * first copy of the security descriptor will be at offset 0x51d0 in the
- * $SDS data stream and the second copy will be at offset 0x451d0.
- */
-typedef struct {
-/*Ofs*/
-/*  0  SECURITY_DESCRIPTOR_HEADER; -- Unfolded here as gcc doesn't like
-                                      unnamed structs. */
-       le32 hash;        /* Hash of the security descriptor. */
-       le32 security_id; /* The security_id assigned to the descriptor. */
-       le64 offset;      /* Byte offset of this entry in the $SDS stream. */
-       le32 length;      /* Size in bytes of this entry in $SDS stream. */
-/* 20*/        SECURITY_DESCRIPTOR_RELATIVE sid; /* The self-relative security
-                                            descriptor. */
-} __attribute__ ((__packed__)) SDS_ENTRY;
-
-/*
- * The index entry key used in the $SII index. The collation type is
- * COLLATION_NTOFS_ULONG.
- */
-typedef struct {
-       le32 security_id; /* The security_id assigned to the descriptor. */
-} __attribute__ ((__packed__)) SII_INDEX_KEY;
-
-/*
- * The index entry key used in the $SDH index. The keys are sorted first by
- * hash and then by security_id. The collation rule is
- * COLLATION_NTOFS_SECURITY_HASH.
- */
-typedef struct {
-       le32 hash;        /* Hash of the security descriptor. */
-       le32 security_id; /* The security_id assigned to the descriptor. */
-} __attribute__ ((__packed__)) SDH_INDEX_KEY;
-
-/*
- * Attribute: Volume name (0x60).
- *
- * NOTE: Always resident.
- * NOTE: Present only in FILE_Volume.
- */
-typedef struct {
-       ntfschar name[0];       /* The name of the volume in Unicode. */
-} __attribute__ ((__packed__)) VOLUME_NAME;
-
-/*
- * Possible flags for the volume (16-bit).
- */
-enum {
-       VOLUME_IS_DIRTY                 = cpu_to_le16(0x0001),
-       VOLUME_RESIZE_LOG_FILE          = cpu_to_le16(0x0002),
-       VOLUME_UPGRADE_ON_MOUNT         = cpu_to_le16(0x0004),
-       VOLUME_MOUNTED_ON_NT4           = cpu_to_le16(0x0008),
-
-       VOLUME_DELETE_USN_UNDERWAY      = cpu_to_le16(0x0010),
-       VOLUME_REPAIR_OBJECT_ID         = cpu_to_le16(0x0020),
-
-       VOLUME_CHKDSK_UNDERWAY          = cpu_to_le16(0x4000),
-       VOLUME_MODIFIED_BY_CHKDSK       = cpu_to_le16(0x8000),
-
-       VOLUME_FLAGS_MASK               = cpu_to_le16(0xc03f),
-
-       /* To make our life easier when checking if we must mount read-only. */
-       VOLUME_MUST_MOUNT_RO_MASK       = cpu_to_le16(0xc027),
-} __attribute__ ((__packed__));
-
-typedef le16 VOLUME_FLAGS;
-
-/*
- * Attribute: Volume information (0x70).
- *
- * NOTE: Always resident.
- * NOTE: Present only in FILE_Volume.
- * NOTE: Windows 2000 uses NTFS 3.0 while Windows NT4 service pack 6a uses
- *      NTFS 1.2. I haven't personally seen other values yet.
- */
-typedef struct {
-       le64 reserved;          /* Not used (yet?). */
-       u8 major_ver;           /* Major version of the ntfs format. */
-       u8 minor_ver;           /* Minor version of the ntfs format. */
-       VOLUME_FLAGS flags;     /* Bit array of VOLUME_* flags. */
-} __attribute__ ((__packed__)) VOLUME_INFORMATION;
-
-/*
- * Attribute: Data attribute (0x80).
- *
- * NOTE: Can be resident or non-resident.
- *
- * Data contents of a file (i.e. the unnamed stream) or of a named stream.
- */
-typedef struct {
-       u8 data[0];             /* The file's data contents. */
-} __attribute__ ((__packed__)) DATA_ATTR;
-
-/*
- * Index header flags (8-bit).
- */
-enum {
-       /*
-        * When index header is in an index root attribute:
-        */
-       SMALL_INDEX = 0, /* The index is small enough to fit inside the index
-                           root attribute and there is no index allocation
-                           attribute present. */
-       LARGE_INDEX = 1, /* The index is too large to fit in the index root
-                           attribute and/or an index allocation attribute is
-                           present. */
-       /*
-        * When index header is in an index block, i.e. is part of index
-        * allocation attribute:
-        */
-       LEAF_NODE  = 0, /* This is a leaf node, i.e. there are no more nodes
-                          branching off it. */
-       INDEX_NODE = 1, /* This node indexes other nodes, i.e. it is not a leaf
-                          node. */
-       NODE_MASK  = 1, /* Mask for accessing the *_NODE bits. */
-} __attribute__ ((__packed__));
-
-typedef u8 INDEX_HEADER_FLAGS;
-
-/*
- * This is the header for indexes, describing the INDEX_ENTRY records, which
- * follow the INDEX_HEADER. Together the index header and the index entries
- * make up a complete index.
- *
- * IMPORTANT NOTE: The offset, length and size structure members are counted
- * relative to the start of the index header structure and not relative to the
- * start of the index root or index allocation structures themselves.
- */
-typedef struct {
-       le32 entries_offset;            /* Byte offset to first INDEX_ENTRY
-                                          aligned to 8-byte boundary. */
-       le32 index_length;              /* Data size of the index in bytes,
-                                          i.e. bytes used from allocated
-                                          size, aligned to 8-byte boundary. */
-       le32 allocated_size;            /* Byte size of this index (block),
-                                          multiple of 8 bytes. */
-       /* NOTE: For the index root attribute, the above two numbers are always
-          equal, as the attribute is resident and it is resized as needed. In
-          the case of the index allocation attribute the attribute is not
-          resident and hence the allocated_size is a fixed value and must
-          equal the index_block_size specified by the INDEX_ROOT attribute
-          corresponding to the INDEX_ALLOCATION attribute this INDEX_BLOCK
-          belongs to. */
-       INDEX_HEADER_FLAGS flags;       /* Bit field of INDEX_HEADER_FLAGS. */
-       u8 reserved[3];                 /* Reserved/align to 8-byte boundary. */
-} __attribute__ ((__packed__)) INDEX_HEADER;
-
-/*
- * Attribute: Index root (0x90).
- *
- * NOTE: Always resident.
- *
- * This is followed by a sequence of index entries (INDEX_ENTRY structures)
- * as described by the index header.
- *
- * When a directory is small enough to fit inside the index root then this
- * is the only attribute describing the directory. When the directory is too
- * large to fit in the index root, on the other hand, two additional attributes
- * are present: an index allocation attribute, containing sub-nodes of the B+
- * directory tree (see below), and a bitmap attribute, describing which virtual
- * cluster numbers (vcns) in the index allocation attribute are in use by an
- * index block.
- *
- * NOTE: The root directory (FILE_root) contains an entry for itself. Other
- * directories do not contain entries for themselves, though.
- */
-typedef struct {
-       ATTR_TYPE type;                 /* Type of the indexed attribute. Is
-                                          $FILE_NAME for directories, zero
-                                          for view indexes. No other values
-                                          allowed. */
-       COLLATION_RULE collation_rule;  /* Collation rule used to sort the
-                                          index entries. If type is $FILE_NAME,
-                                          this must be COLLATION_FILE_NAME. */
-       le32 index_block_size;          /* Size of each index block in bytes (in
-                                          the index allocation attribute). */
-       u8 clusters_per_index_block;    /* Cluster size of each index block (in
-                                          the index allocation attribute), when
-                                          an index block is >= than a cluster,
-                                          otherwise this will be the log of
-                                          the size (like how the encoding of
-                                          the mft record size and the index
-                                          record size found in the boot sector
-                                          work). Has to be a power of 2. */
-       u8 reserved[3];                 /* Reserved/align to 8-byte boundary. */
-       INDEX_HEADER index;             /* Index header describing the
-                                          following index entries. */
-} __attribute__ ((__packed__)) INDEX_ROOT;
-
-/*
- * Attribute: Index allocation (0xa0).
- *
- * NOTE: Always non-resident (doesn't make sense to be resident anyway!).
- *
- * This is an array of index blocks. Each index block starts with an
- * INDEX_BLOCK structure containing an index header, followed by a sequence of
- * index entries (INDEX_ENTRY structures), as described by the INDEX_HEADER.
- */
-typedef struct {
-/*  0  NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
-       NTFS_RECORD_TYPE magic; /* Magic is "INDX". */
-       le16 usa_ofs;           /* See NTFS_RECORD definition. */
-       le16 usa_count;         /* See NTFS_RECORD definition. */
-
-/*  8*/        sle64 lsn;              /* $LogFile sequence number of the last
-                                  modification of this index block. */
-/* 16*/        leVCN index_block_vcn;  /* Virtual cluster number of the index block.
-                                  If the cluster_size on the volume is <= the
-                                  index_block_size of the directory,
-                                  index_block_vcn counts in units of clusters,
-                                  and in units of sectors otherwise. */
-/* 24*/        INDEX_HEADER index;     /* Describes the following index entries. */
-/* sizeof()= 40 (0x28) bytes */
-/*
- * When creating the index block, we place the update sequence array at this
- * offset, i.e. before we start with the index entries. This also makes sense,
- * otherwise we could run into problems with the update sequence array
- * containing in itself the last two bytes of a sector which would mean that
- * multi sector transfer protection wouldn't work. As you can't protect data
- * by overwriting it since you then can't get it back...
- * When reading use the data from the ntfs record header.
- */
-} __attribute__ ((__packed__)) INDEX_BLOCK;
-
-typedef INDEX_BLOCK INDEX_ALLOCATION;
-
-/*
- * The system file FILE_Extend/$Reparse contains an index named $R listing
- * all reparse points on the volume. The index entry keys are as defined
- * below. Note, that there is no index data associated with the index entries.
- *
- * The index entries are sorted by the index key file_id. The collation rule is
- * COLLATION_NTOFS_ULONGS. FIXME: Verify whether the reparse_tag is not the
- * primary key / is not a key at all. (AIA)
- */
-typedef struct {
-       le32 reparse_tag;       /* Reparse point type (inc. flags). */
-       leMFT_REF file_id;      /* Mft record of the file containing the
-                                  reparse point attribute. */
-} __attribute__ ((__packed__)) REPARSE_INDEX_KEY;
-
-/*
- * Quota flags (32-bit).
- *
- * The user quota flags.  Names explain meaning.
- */
-enum {
-       QUOTA_FLAG_DEFAULT_LIMITS       = cpu_to_le32(0x00000001),
-       QUOTA_FLAG_LIMIT_REACHED        = cpu_to_le32(0x00000002),
-       QUOTA_FLAG_ID_DELETED           = cpu_to_le32(0x00000004),
-
-       QUOTA_FLAG_USER_MASK            = cpu_to_le32(0x00000007),
-       /* This is a bit mask for the user quota flags. */
-
-       /*
-        * These flags are only present in the quota defaults index entry, i.e.
-        * in the entry where owner_id = QUOTA_DEFAULTS_ID.
-        */
-       QUOTA_FLAG_TRACKING_ENABLED     = cpu_to_le32(0x00000010),
-       QUOTA_FLAG_ENFORCEMENT_ENABLED  = cpu_to_le32(0x00000020),
-       QUOTA_FLAG_TRACKING_REQUESTED   = cpu_to_le32(0x00000040),
-       QUOTA_FLAG_LOG_THRESHOLD        = cpu_to_le32(0x00000080),
-
-       QUOTA_FLAG_LOG_LIMIT            = cpu_to_le32(0x00000100),
-       QUOTA_FLAG_OUT_OF_DATE          = cpu_to_le32(0x00000200),
-       QUOTA_FLAG_CORRUPT              = cpu_to_le32(0x00000400),
-       QUOTA_FLAG_PENDING_DELETES      = cpu_to_le32(0x00000800),
-};
-
-typedef le32 QUOTA_FLAGS;
-
-/*
- * The system file FILE_Extend/$Quota contains two indexes $O and $Q. Quotas
- * are on a per volume and per user basis.
- *
- * The $Q index contains one entry for each existing user_id on the volume. The
- * index key is the user_id of the user/group owning this quota control entry,
- * i.e. the key is the owner_id. The user_id of the owner of a file, i.e. the
- * owner_id, is found in the standard information attribute. The collation rule
- * for $Q is COLLATION_NTOFS_ULONG.
- *
- * The $O index contains one entry for each user/group who has been assigned
- * a quota on that volume. The index key holds the SID of the user_id the
- * entry belongs to, i.e. the owner_id. The collation rule for $O is
- * COLLATION_NTOFS_SID.
- *
- * The $O index entry data is the user_id of the user corresponding to the SID.
- * This user_id is used as an index into $Q to find the quota control entry
- * associated with the SID.
- *
- * The $Q index entry data is the quota control entry and is defined below.
- */
-typedef struct {
-       le32 version;           /* Currently equals 2. */
-       QUOTA_FLAGS flags;      /* Flags describing this quota entry. */
-       le64 bytes_used;        /* How many bytes of the quota are in use. */
-       sle64 change_time;      /* Last time this quota entry was changed. */
-       sle64 threshold;        /* Soft quota (-1 if not limited). */
-       sle64 limit;            /* Hard quota (-1 if not limited). */
-       sle64 exceeded_time;    /* How long the soft quota has been exceeded. */
-       SID sid;                /* The SID of the user/object associated with
-                                  this quota entry.  Equals zero for the quota
-                                  defaults entry (and in fact on a WinXP
-                                  volume, it is not present at all). */
-} __attribute__ ((__packed__)) QUOTA_CONTROL_ENTRY;
-
-/*
- * Predefined owner_id values (32-bit).
- */
-enum {
-       QUOTA_INVALID_ID        = cpu_to_le32(0x00000000),
-       QUOTA_DEFAULTS_ID       = cpu_to_le32(0x00000001),
-       QUOTA_FIRST_USER_ID     = cpu_to_le32(0x00000100),
-};
-
-/*
- * Current constants for quota control entries.
- */
-typedef enum {
-       /* Current version. */
-       QUOTA_VERSION   = 2,
-} QUOTA_CONTROL_ENTRY_CONSTANTS;
-
-/*
- * Index entry flags (16-bit).
- */
-enum {
-       INDEX_ENTRY_NODE = cpu_to_le16(1), /* This entry contains a
-                       sub-node, i.e. a reference to an index block in form of
-                       a virtual cluster number (see below). */
-       INDEX_ENTRY_END  = cpu_to_le16(2), /* This signifies the last
-                       entry in an index block.  The index entry does not
-                       represent a file but it can point to a sub-node. */
-
-       INDEX_ENTRY_SPACE_FILLER = cpu_to_le16(0xffff), /* gcc: Force
-                       enum bit width to 16-bit. */
-} __attribute__ ((__packed__));
-
-typedef le16 INDEX_ENTRY_FLAGS;
-
-/*
- * This the index entry header (see below).
- */
-typedef struct {
-/*  0*/        union {
-               struct { /* Only valid when INDEX_ENTRY_END is not set. */
-                       leMFT_REF indexed_file; /* The mft reference of the file
-                                                  described by this index
-                                                  entry. Used for directory
-                                                  indexes. */
-               } __attribute__ ((__packed__)) dir;
-               struct { /* Used for views/indexes to find the entry's data. */
-                       le16 data_offset;       /* Data byte offset from this
-                                                  INDEX_ENTRY. Follows the
-                                                  index key. */
-                       le16 data_length;       /* Data length in bytes. */
-                       le32 reservedV;         /* Reserved (zero). */
-               } __attribute__ ((__packed__)) vi;
-       } __attribute__ ((__packed__)) data;
-/*  8*/        le16 length;             /* Byte size of this index entry, multiple of
-                                   8-bytes. */
-/* 10*/        le16 key_length;         /* Byte size of the key value, which is in the
-                                   index entry. It follows field reserved. Not
-                                   multiple of 8-bytes. */
-/* 12*/        INDEX_ENTRY_FLAGS flags; /* Bit field of INDEX_ENTRY_* flags. */
-/* 14*/        le16 reserved;           /* Reserved/align to 8-byte boundary. */
-/* sizeof() = 16 bytes */
-} __attribute__ ((__packed__)) INDEX_ENTRY_HEADER;
-
-/*
- * This is an index entry. A sequence of such entries follows each INDEX_HEADER
- * structure. Together they make up a complete index. The index follows either
- * an index root attribute or an index allocation attribute.
- *
- * NOTE: Before NTFS 3.0 only filename attributes were indexed.
- */
-typedef struct {
-/*Ofs*/
-/*  0  INDEX_ENTRY_HEADER; -- Unfolded here as gcc dislikes unnamed structs. */
-       union {
-               struct { /* Only valid when INDEX_ENTRY_END is not set. */
-                       leMFT_REF indexed_file; /* The mft reference of the file
-                                                  described by this index
-                                                  entry. Used for directory
-                                                  indexes. */
-               } __attribute__ ((__packed__)) dir;
-               struct { /* Used for views/indexes to find the entry's data. */
-                       le16 data_offset;       /* Data byte offset from this
-                                                  INDEX_ENTRY. Follows the
-                                                  index key. */
-                       le16 data_length;       /* Data length in bytes. */
-                       le32 reservedV;         /* Reserved (zero). */
-               } __attribute__ ((__packed__)) vi;
-       } __attribute__ ((__packed__)) data;
-       le16 length;             /* Byte size of this index entry, multiple of
-                                   8-bytes. */
-       le16 key_length;         /* Byte size of the key value, which is in the
-                                   index entry. It follows field reserved. Not
-                                   multiple of 8-bytes. */
-       INDEX_ENTRY_FLAGS flags; /* Bit field of INDEX_ENTRY_* flags. */
-       le16 reserved;           /* Reserved/align to 8-byte boundary. */
-
-/* 16*/        union {         /* The key of the indexed attribute. NOTE: Only present
-                          if INDEX_ENTRY_END bit in flags is not set. NOTE: On
-                          NTFS versions before 3.0 the only valid key is the
-                          FILE_NAME_ATTR. On NTFS 3.0+ the following
-                          additional index keys are defined: */
-               FILE_NAME_ATTR file_name;/* $I30 index in directories. */
-               SII_INDEX_KEY sii;      /* $SII index in $Secure. */
-               SDH_INDEX_KEY sdh;      /* $SDH index in $Secure. */
-               GUID object_id;         /* $O index in FILE_Extend/$ObjId: The
-                                          object_id of the mft record found in
-                                          the data part of the index. */
-               REPARSE_INDEX_KEY reparse;      /* $R index in
-                                                  FILE_Extend/$Reparse. */
-               SID sid;                /* $O index in FILE_Extend/$Quota:
-                                          SID of the owner of the user_id. */
-               le32 owner_id;          /* $Q index in FILE_Extend/$Quota:
-                                          user_id of the owner of the quota
-                                          control entry in the data part of
-                                          the index. */
-       } __attribute__ ((__packed__)) key;
-       /* The (optional) index data is inserted here when creating. */
-       // leVCN vcn;   /* If INDEX_ENTRY_NODE bit in flags is set, the last
-       //                 eight bytes of this index entry contain the virtual
-       //                 cluster number of the index block that holds the
-       //                 entries immediately preceding the current entry (the
-       //                 vcn references the corresponding cluster in the data
-       //                 of the non-resident index allocation attribute). If
-       //                 the key_length is zero, then the vcn immediately
-       //                 follows the INDEX_ENTRY_HEADER. Regardless of
-       //                 key_length, the address of the 8-byte boundary
-       //                 aligned vcn of INDEX_ENTRY{_HEADER} *ie is given by
-       //                 (char*)ie + le16_to_cpu(ie*)->length) - sizeof(VCN),
-       //                 where sizeof(VCN) can be hardcoded as 8 if wanted. */
-} __attribute__ ((__packed__)) INDEX_ENTRY;
-
-/*
- * Attribute: Bitmap (0xb0).
- *
- * Contains an array of bits (aka a bitfield).
- *
- * When used in conjunction with the index allocation attribute, each bit
- * corresponds to one index block within the index allocation attribute. Thus
- * the number of bits in the bitmap * index block size / cluster size is the
- * number of clusters in the index allocation attribute.
- */
-typedef struct {
-       u8 bitmap[0];                   /* Array of bits. */
-} __attribute__ ((__packed__)) BITMAP_ATTR;
-
-/*
- * The reparse point tag defines the type of the reparse point. It also
- * includes several flags, which further describe the reparse point.
- *
- * The reparse point tag is an unsigned 32-bit value divided in three parts:
- *
- * 1. The least significant 16 bits (i.e. bits 0 to 15) specifiy the type of
- *    the reparse point.
- * 2. The 13 bits after this (i.e. bits 16 to 28) are reserved for future use.
- * 3. The most significant three bits are flags describing the reparse point.
- *    They are defined as follows:
- *     bit 29: Name surrogate bit. If set, the filename is an alias for
- *             another object in the system.
- *     bit 30: High-latency bit. If set, accessing the first byte of data will
- *             be slow. (E.g. the data is stored on a tape drive.)
- *     bit 31: Microsoft bit. If set, the tag is owned by Microsoft. User
- *             defined tags have to use zero here.
- *
- * These are the predefined reparse point tags:
- */
-enum {
-       IO_REPARSE_TAG_IS_ALIAS         = cpu_to_le32(0x20000000),
-       IO_REPARSE_TAG_IS_HIGH_LATENCY  = cpu_to_le32(0x40000000),
-       IO_REPARSE_TAG_IS_MICROSOFT     = cpu_to_le32(0x80000000),
-
-       IO_REPARSE_TAG_RESERVED_ZERO    = cpu_to_le32(0x00000000),
-       IO_REPARSE_TAG_RESERVED_ONE     = cpu_to_le32(0x00000001),
-       IO_REPARSE_TAG_RESERVED_RANGE   = cpu_to_le32(0x00000001),
-
-       IO_REPARSE_TAG_NSS              = cpu_to_le32(0x68000005),
-       IO_REPARSE_TAG_NSS_RECOVER      = cpu_to_le32(0x68000006),
-       IO_REPARSE_TAG_SIS              = cpu_to_le32(0x68000007),
-       IO_REPARSE_TAG_DFS              = cpu_to_le32(0x68000008),
-
-       IO_REPARSE_TAG_MOUNT_POINT      = cpu_to_le32(0x88000003),
-
-       IO_REPARSE_TAG_HSM              = cpu_to_le32(0xa8000004),
-
-       IO_REPARSE_TAG_SYMBOLIC_LINK    = cpu_to_le32(0xe8000000),
-
-       IO_REPARSE_TAG_VALID_VALUES     = cpu_to_le32(0xe000ffff),
-};
-
-/*
- * Attribute: Reparse point (0xc0).
- *
- * NOTE: Can be resident or non-resident.
- */
-typedef struct {
-       le32 reparse_tag;               /* Reparse point type (inc. flags). */
-       le16 reparse_data_length;       /* Byte size of reparse data. */
-       le16 reserved;                  /* Align to 8-byte boundary. */
-       u8 reparse_data[0];             /* Meaning depends on reparse_tag. */
-} __attribute__ ((__packed__)) REPARSE_POINT;
-
-/*
- * Attribute: Extended attribute (EA) information (0xd0).
- *
- * NOTE: Always resident. (Is this true???)
- */
-typedef struct {
-       le16 ea_length;         /* Byte size of the packed extended
-                                  attributes. */
-       le16 need_ea_count;     /* The number of extended attributes which have
-                                  the NEED_EA bit set. */
-       le32 ea_query_length;   /* Byte size of the buffer required to query
-                                  the extended attributes when calling
-                                  ZwQueryEaFile() in Windows NT/2k. I.e. the
-                                  byte size of the unpacked extended
-                                  attributes. */
-} __attribute__ ((__packed__)) EA_INFORMATION;
-
-/*
- * Extended attribute flags (8-bit).
- */
-enum {
-       NEED_EA = 0x80          /* If set the file to which the EA belongs
-                                  cannot be interpreted without understanding
-                                  the associates extended attributes. */
-} __attribute__ ((__packed__));
-
-typedef u8 EA_FLAGS;
-
-/*
- * Attribute: Extended attribute (EA) (0xe0).
- *
- * NOTE: Can be resident or non-resident.
- *
- * Like the attribute list and the index buffer list, the EA attribute value is
- * a sequence of EA_ATTR variable length records.
- */
-typedef struct {
-       le32 next_entry_offset; /* Offset to the next EA_ATTR. */
-       EA_FLAGS flags;         /* Flags describing the EA. */
-       u8 ea_name_length;      /* Length of the name of the EA in bytes
-                                  excluding the '\0' byte terminator. */
-       le16 ea_value_length;   /* Byte size of the EA's value. */
-       u8 ea_name[0];          /* Name of the EA.  Note this is ASCII, not
-                                  Unicode and it is zero terminated. */
-       u8 ea_value[0];         /* The value of the EA.  Immediately follows
-                                  the name. */
-} __attribute__ ((__packed__)) EA_ATTR;
-
-/*
- * Attribute: Property set (0xf0).
- *
- * Intended to support Native Structure Storage (NSS) - a feature removed from
- * NTFS 3.0 during beta testing.
- */
-typedef struct {
-       /* Irrelevant as feature unused. */
-} __attribute__ ((__packed__)) PROPERTY_SET;
-
-/*
- * Attribute: Logged utility stream (0x100).
- *
- * NOTE: Can be resident or non-resident.
- *
- * Operations on this attribute are logged to the journal ($LogFile) like
- * normal metadata changes.
- *
- * Used by the Encrypting File System (EFS). All encrypted files have this
- * attribute with the name $EFS.
- */
-typedef struct {
-       /* Can be anything the creator chooses. */
-       /* EFS uses it as follows: */
-       // FIXME: Type this info, verifying it along the way. (AIA)
-} __attribute__ ((__packed__)) LOGGED_UTILITY_STREAM, EFS_ATTR;
-
-#endif /* _LINUX_NTFS_LAYOUT_H */
diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c
deleted file mode 100644 (file)
index eda9972..0000000
+++ /dev/null
@@ -1,1000 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * lcnalloc.c - Cluster (de)allocation code.  Part of the Linux-NTFS project.
- *
- * Copyright (c) 2004-2005 Anton Altaparmakov
- */
-
-#ifdef NTFS_RW
-
-#include <linux/pagemap.h>
-
-#include "lcnalloc.h"
-#include "debug.h"
-#include "bitmap.h"
-#include "inode.h"
-#include "volume.h"
-#include "attrib.h"
-#include "malloc.h"
-#include "aops.h"
-#include "ntfs.h"
-
-/**
- * ntfs_cluster_free_from_rl_nolock - free clusters from runlist
- * @vol:       mounted ntfs volume on which to free the clusters
- * @rl:                runlist describing the clusters to free
- *
- * Free all the clusters described by the runlist @rl on the volume @vol.  In
- * the case of an error being returned, at least some of the clusters were not
- * freed.
- *
- * Return 0 on success and -errno on error.
- *
- * Locking: - The volume lcn bitmap must be locked for writing on entry and is
- *           left locked on return.
- */
-int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
-               const runlist_element *rl)
-{
-       struct inode *lcnbmp_vi = vol->lcnbmp_ino;
-       int ret = 0;
-
-       ntfs_debug("Entering.");
-       if (!rl)
-               return 0;
-       for (; rl->length; rl++) {
-               int err;
-
-               if (rl->lcn < 0)
-                       continue;
-               err = ntfs_bitmap_clear_run(lcnbmp_vi, rl->lcn, rl->length);
-               if (unlikely(err && (!ret || ret == -ENOMEM) && ret != err))
-                       ret = err;
-       }
-       ntfs_debug("Done.");
-       return ret;
-}
-
-/**
- * ntfs_cluster_alloc - allocate clusters on an ntfs volume
- * @vol:       mounted ntfs volume on which to allocate the clusters
- * @start_vcn: vcn to use for the first allocated cluster
- * @count:     number of clusters to allocate
- * @start_lcn: starting lcn at which to allocate the clusters (or -1 if none)
- * @zone:      zone from which to allocate the clusters
- * @is_extension:      if 'true', this is an attribute extension
- *
- * Allocate @count clusters preferably starting at cluster @start_lcn or at the
- * current allocator position if @start_lcn is -1, on the mounted ntfs volume
- * @vol. @zone is either DATA_ZONE for allocation of normal clusters or
- * MFT_ZONE for allocation of clusters for the master file table, i.e. the
- * $MFT/$DATA attribute.
- *
- * @start_vcn specifies the vcn of the first allocated cluster.  This makes
- * merging the resulting runlist with the old runlist easier.
- *
- * If @is_extension is 'true', the caller is allocating clusters to extend an
- * attribute and if it is 'false', the caller is allocating clusters to fill a
- * hole in an attribute.  Practically the difference is that if @is_extension
- * is 'true' the returned runlist will be terminated with LCN_ENOENT and if
- * @is_extension is 'false' the runlist will be terminated with
- * LCN_RL_NOT_MAPPED.
- *
- * You need to check the return value with IS_ERR().  If this is false, the
- * function was successful and the return value is a runlist describing the
- * allocated cluster(s).  If IS_ERR() is true, the function failed and
- * PTR_ERR() gives you the error code.
- *
- * Notes on the allocation algorithm
- * =================================
- *
- * There are two data zones.  First is the area between the end of the mft zone
- * and the end of the volume, and second is the area between the start of the
- * volume and the start of the mft zone.  On unmodified/standard NTFS 1.x
- * volumes, the second data zone does not exist due to the mft zone being
- * expanded to cover the start of the volume in order to reserve space for the
- * mft bitmap attribute.
- *
- * This is not the prettiest function but the complexity stems from the need of
- * implementing the mft vs data zoned approach and from the fact that we have
- * access to the lcn bitmap in portions of up to 8192 bytes at a time, so we
- * need to cope with crossing over boundaries of two buffers.  Further, the
- * fact that the allocator allows for caller supplied hints as to the location
- * of where allocation should begin and the fact that the allocator keeps track
- * of where in the data zones the next natural allocation should occur,
- * contribute to the complexity of the function.  But it should all be
- * worthwhile, because this allocator should: 1) be a full implementation of
- * the MFT zone approach used by Windows NT, 2) cause reduction in
- * fragmentation, and 3) be speedy in allocations (the code is not optimized
- * for speed, but the algorithm is, so further speed improvements are probably
- * possible).
- *
- * FIXME: We should be monitoring cluster allocation and increment the MFT zone
- * size dynamically but this is something for the future.  We will just cause
- * heavier fragmentation by not doing it and I am not even sure Windows would
- * grow the MFT zone dynamically, so it might even be correct not to do this.
- * The overhead in doing dynamic MFT zone expansion would be very large and
- * unlikely worth the effort. (AIA)
- *
- * TODO: I have added in double the required zone position pointer wrap around
- * logic which can be optimized to having only one of the two logic sets.
- * However, having the double logic will work fine, but if we have only one of
- * the sets and we get it wrong somewhere, then we get into trouble, so
- * removing the duplicate logic requires _very_ careful consideration of _all_
- * possible code paths.  So at least for now, I am leaving the double logic -
- * better safe than sorry... (AIA)
- *
- * Locking: - The volume lcn bitmap must be unlocked on entry and is unlocked
- *           on return.
- *         - This function takes the volume lcn bitmap lock for writing and
- *           modifies the bitmap contents.
- */
-runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
-               const s64 count, const LCN start_lcn,
-               const NTFS_CLUSTER_ALLOCATION_ZONES zone,
-               const bool is_extension)
-{
-       LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn;
-       LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size;
-       s64 clusters;
-       loff_t i_size;
-       struct inode *lcnbmp_vi;
-       runlist_element *rl = NULL;
-       struct address_space *mapping;
-       struct page *page = NULL;
-       u8 *buf, *byte;
-       int err = 0, rlpos, rlsize, buf_size;
-       u8 pass, done_zones, search_zone, need_writeback = 0, bit;
-
-       ntfs_debug("Entering for start_vcn 0x%llx, count 0x%llx, start_lcn "
-                       "0x%llx, zone %s_ZONE.", (unsigned long long)start_vcn,
-                       (unsigned long long)count,
-                       (unsigned long long)start_lcn,
-                       zone == MFT_ZONE ? "MFT" : "DATA");
-       BUG_ON(!vol);
-       lcnbmp_vi = vol->lcnbmp_ino;
-       BUG_ON(!lcnbmp_vi);
-       BUG_ON(start_vcn < 0);
-       BUG_ON(count < 0);
-       BUG_ON(start_lcn < -1);
-       BUG_ON(zone < FIRST_ZONE);
-       BUG_ON(zone > LAST_ZONE);
-
-       /* Return NULL if @count is zero. */
-       if (!count)
-               return NULL;
-       /* Take the lcnbmp lock for writing. */
-       down_write(&vol->lcnbmp_lock);
-       /*
-        * If no specific @start_lcn was requested, use the current data zone
-        * position, otherwise use the requested @start_lcn but make sure it
-        * lies outside the mft zone.  Also set done_zones to 0 (no zones done)
-        * and pass depending on whether we are starting inside a zone (1) or
-        * at the beginning of a zone (2).  If requesting from the MFT_ZONE,
-        * we either start at the current position within the mft zone or at
-        * the specified position.  If the latter is out of bounds then we start
-        * at the beginning of the MFT_ZONE.
-        */
-       done_zones = 0;
-       pass = 1;
-       /*
-        * zone_start and zone_end are the current search range.  search_zone
-        * is 1 for mft zone, 2 for data zone 1 (end of mft zone till end of
-        * volume) and 4 for data zone 2 (start of volume till start of mft
-        * zone).
-        */
-       zone_start = start_lcn;
-       if (zone_start < 0) {
-               if (zone == DATA_ZONE)
-                       zone_start = vol->data1_zone_pos;
-               else
-                       zone_start = vol->mft_zone_pos;
-               if (!zone_start) {
-                       /*
-                        * Zone starts at beginning of volume which means a
-                        * single pass is sufficient.
-                        */
-                       pass = 2;
-               }
-       } else if (zone == DATA_ZONE && zone_start >= vol->mft_zone_start &&
-                       zone_start < vol->mft_zone_end) {
-               zone_start = vol->mft_zone_end;
-               /*
-                * Starting at beginning of data1_zone which means a single
-                * pass in this zone is sufficient.
-                */
-               pass = 2;
-       } else if (zone == MFT_ZONE && (zone_start < vol->mft_zone_start ||
-                       zone_start >= vol->mft_zone_end)) {
-               zone_start = vol->mft_lcn;
-               if (!vol->mft_zone_end)
-                       zone_start = 0;
-               /*
-                * Starting at beginning of volume which means a single pass
-                * is sufficient.
-                */
-               pass = 2;
-       }
-       if (zone == MFT_ZONE) {
-               zone_end = vol->mft_zone_end;
-               search_zone = 1;
-       } else /* if (zone == DATA_ZONE) */ {
-               /* Skip searching the mft zone. */
-               done_zones |= 1;
-               if (zone_start >= vol->mft_zone_end) {
-                       zone_end = vol->nr_clusters;
-                       search_zone = 2;
-               } else {
-                       zone_end = vol->mft_zone_start;
-                       search_zone = 4;
-               }
-       }
-       /*
-        * bmp_pos is the current bit position inside the bitmap.  We use
-        * bmp_initial_pos to determine whether or not to do a zone switch.
-        */
-       bmp_pos = bmp_initial_pos = zone_start;
-
-       /* Loop until all clusters are allocated, i.e. clusters == 0. */
-       clusters = count;
-       rlpos = rlsize = 0;
-       mapping = lcnbmp_vi->i_mapping;
-       i_size = i_size_read(lcnbmp_vi);
-       while (1) {
-               ntfs_debug("Start of outer while loop: done_zones 0x%x, "
-                               "search_zone %i, pass %i, zone_start 0x%llx, "
-                               "zone_end 0x%llx, bmp_initial_pos 0x%llx, "
-                               "bmp_pos 0x%llx, rlpos %i, rlsize %i.",
-                               done_zones, search_zone, pass,
-                               (unsigned long long)zone_start,
-                               (unsigned long long)zone_end,
-                               (unsigned long long)bmp_initial_pos,
-                               (unsigned long long)bmp_pos, rlpos, rlsize);
-               /* Loop until we run out of free clusters. */
-               last_read_pos = bmp_pos >> 3;
-               ntfs_debug("last_read_pos 0x%llx.",
-                               (unsigned long long)last_read_pos);
-               if (last_read_pos > i_size) {
-                       ntfs_debug("End of attribute reached.  "
-                                       "Skipping to zone_pass_done.");
-                       goto zone_pass_done;
-               }
-               if (likely(page)) {
-                       if (need_writeback) {
-                               ntfs_debug("Marking page dirty.");
-                               flush_dcache_page(page);
-                               set_page_dirty(page);
-                               need_writeback = 0;
-                       }
-                       ntfs_unmap_page(page);
-               }
-               page = ntfs_map_page(mapping, last_read_pos >>
-                               PAGE_SHIFT);
-               if (IS_ERR(page)) {
-                       err = PTR_ERR(page);
-                       ntfs_error(vol->sb, "Failed to map page.");
-                       goto out;
-               }
-               buf_size = last_read_pos & ~PAGE_MASK;
-               buf = page_address(page) + buf_size;
-               buf_size = PAGE_SIZE - buf_size;
-               if (unlikely(last_read_pos + buf_size > i_size))
-                       buf_size = i_size - last_read_pos;
-               buf_size <<= 3;
-               lcn = bmp_pos & 7;
-               bmp_pos &= ~(LCN)7;
-               ntfs_debug("Before inner while loop: buf_size %i, lcn 0x%llx, "
-                               "bmp_pos 0x%llx, need_writeback %i.", buf_size,
-                               (unsigned long long)lcn,
-                               (unsigned long long)bmp_pos, need_writeback);
-               while (lcn < buf_size && lcn + bmp_pos < zone_end) {
-                       byte = buf + (lcn >> 3);
-                       ntfs_debug("In inner while loop: buf_size %i, "
-                                       "lcn 0x%llx, bmp_pos 0x%llx, "
-                                       "need_writeback %i, byte ofs 0x%x, "
-                                       "*byte 0x%x.", buf_size,
-                                       (unsigned long long)lcn,
-                                       (unsigned long long)bmp_pos,
-                                       need_writeback,
-                                       (unsigned int)(lcn >> 3),
-                                       (unsigned int)*byte);
-                       /* Skip full bytes. */
-                       if (*byte == 0xff) {
-                               lcn = (lcn + 8) & ~(LCN)7;
-                               ntfs_debug("Continuing while loop 1.");
-                               continue;
-                       }
-                       bit = 1 << (lcn & 7);
-                       ntfs_debug("bit 0x%x.", bit);
-                       /* If the bit is already set, go onto the next one. */
-                       if (*byte & bit) {
-                               lcn++;
-                               ntfs_debug("Continuing while loop 2.");
-                               continue;
-                       }
-                       /*
-                        * Allocate more memory if needed, including space for
-                        * the terminator element.
-                        * ntfs_malloc_nofs() operates on whole pages only.
-                        */
-                       if ((rlpos + 2) * sizeof(*rl) > rlsize) {
-                               runlist_element *rl2;
-
-                               ntfs_debug("Reallocating memory.");
-                               if (!rl)
-                                       ntfs_debug("First free bit is at LCN "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       (lcn + bmp_pos));
-                               rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE);
-                               if (unlikely(!rl2)) {
-                                       err = -ENOMEM;
-                                       ntfs_error(vol->sb, "Failed to "
-                                                       "allocate memory.");
-                                       goto out;
-                               }
-                               memcpy(rl2, rl, rlsize);
-                               ntfs_free(rl);
-                               rl = rl2;
-                               rlsize += PAGE_SIZE;
-                               ntfs_debug("Reallocated memory, rlsize 0x%x.",
-                                               rlsize);
-                       }
-                       /* Allocate the bitmap bit. */
-                       *byte |= bit;
-                       /* We need to write this bitmap page to disk. */
-                       need_writeback = 1;
-                       ntfs_debug("*byte 0x%x, need_writeback is set.",
-                                       (unsigned int)*byte);
-                       /*
-                        * Coalesce with previous run if adjacent LCNs.
-                        * Otherwise, append a new run.
-                        */
-                       ntfs_debug("Adding run (lcn 0x%llx, len 0x%llx), "
-                                       "prev_lcn 0x%llx, lcn 0x%llx, "
-                                       "bmp_pos 0x%llx, prev_run_len 0x%llx, "
-                                       "rlpos %i.",
-                                       (unsigned long long)(lcn + bmp_pos),
-                                       1ULL, (unsigned long long)prev_lcn,
-                                       (unsigned long long)lcn,
-                                       (unsigned long long)bmp_pos,
-                                       (unsigned long long)prev_run_len,
-                                       rlpos);
-                       if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) {
-                               ntfs_debug("Coalescing to run (lcn 0x%llx, "
-                                               "len 0x%llx).",
-                                               (unsigned long long)
-                                               rl[rlpos - 1].lcn,
-                                               (unsigned long long)
-                                               rl[rlpos - 1].length);
-                               rl[rlpos - 1].length = ++prev_run_len;
-                               ntfs_debug("Run now (lcn 0x%llx, len 0x%llx), "
-                                               "prev_run_len 0x%llx.",
-                                               (unsigned long long)
-                                               rl[rlpos - 1].lcn,
-                                               (unsigned long long)
-                                               rl[rlpos - 1].length,
-                                               (unsigned long long)
-                                               prev_run_len);
-                       } else {
-                               if (likely(rlpos)) {
-                                       ntfs_debug("Adding new run, (previous "
-                                                       "run lcn 0x%llx, "
-                                                       "len 0x%llx).",
-                                                       (unsigned long long)
-                                                       rl[rlpos - 1].lcn,
-                                                       (unsigned long long)
-                                                       rl[rlpos - 1].length);
-                                       rl[rlpos].vcn = rl[rlpos - 1].vcn +
-                                                       prev_run_len;
-                               } else {
-                                       ntfs_debug("Adding new run, is first "
-                                                       "run.");
-                                       rl[rlpos].vcn = start_vcn;
-                               }
-                               rl[rlpos].lcn = prev_lcn = lcn + bmp_pos;
-                               rl[rlpos].length = prev_run_len = 1;
-                               rlpos++;
-                       }
-                       /* Done? */
-                       if (!--clusters) {
-                               LCN tc;
-                               /*
-                                * Update the current zone position.  Positions
-                                * of already scanned zones have been updated
-                                * during the respective zone switches.
-                                */
-                               tc = lcn + bmp_pos + 1;
-                               ntfs_debug("Done. Updating current zone "
-                                               "position, tc 0x%llx, "
-                                               "search_zone %i.",
-                                               (unsigned long long)tc,
-                                               search_zone);
-                               switch (search_zone) {
-                               case 1:
-                                       ntfs_debug("Before checks, "
-                                                       "vol->mft_zone_pos "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       vol->mft_zone_pos);
-                                       if (tc >= vol->mft_zone_end) {
-                                               vol->mft_zone_pos =
-                                                               vol->mft_lcn;
-                                               if (!vol->mft_zone_end)
-                                                       vol->mft_zone_pos = 0;
-                                       } else if ((bmp_initial_pos >=
-                                                       vol->mft_zone_pos ||
-                                                       tc > vol->mft_zone_pos)
-                                                       && tc >= vol->mft_lcn)
-                                               vol->mft_zone_pos = tc;
-                                       ntfs_debug("After checks, "
-                                                       "vol->mft_zone_pos "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       vol->mft_zone_pos);
-                                       break;
-                               case 2:
-                                       ntfs_debug("Before checks, "
-                                                       "vol->data1_zone_pos "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       vol->data1_zone_pos);
-                                       if (tc >= vol->nr_clusters)
-                                               vol->data1_zone_pos =
-                                                            vol->mft_zone_end;
-                                       else if ((bmp_initial_pos >=
-                                                   vol->data1_zone_pos ||
-                                                   tc > vol->data1_zone_pos)
-                                                   && tc >= vol->mft_zone_end)
-                                               vol->data1_zone_pos = tc;
-                                       ntfs_debug("After checks, "
-                                                       "vol->data1_zone_pos "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       vol->data1_zone_pos);
-                                       break;
-                               case 4:
-                                       ntfs_debug("Before checks, "
-                                                       "vol->data2_zone_pos "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       vol->data2_zone_pos);
-                                       if (tc >= vol->mft_zone_start)
-                                               vol->data2_zone_pos = 0;
-                                       else if (bmp_initial_pos >=
-                                                     vol->data2_zone_pos ||
-                                                     tc > vol->data2_zone_pos)
-                                               vol->data2_zone_pos = tc;
-                                       ntfs_debug("After checks, "
-                                                       "vol->data2_zone_pos "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       vol->data2_zone_pos);
-                                       break;
-                               default:
-                                       BUG();
-                               }
-                               ntfs_debug("Finished.  Going to out.");
-                               goto out;
-                       }
-                       lcn++;
-               }
-               bmp_pos += buf_size;
-               ntfs_debug("After inner while loop: buf_size 0x%x, lcn "
-                               "0x%llx, bmp_pos 0x%llx, need_writeback %i.",
-                               buf_size, (unsigned long long)lcn,
-                               (unsigned long long)bmp_pos, need_writeback);
-               if (bmp_pos < zone_end) {
-                       ntfs_debug("Continuing outer while loop, "
-                                       "bmp_pos 0x%llx, zone_end 0x%llx.",
-                                       (unsigned long long)bmp_pos,
-                                       (unsigned long long)zone_end);
-                       continue;
-               }
-zone_pass_done:        /* Finished with the current zone pass. */
-               ntfs_debug("At zone_pass_done, pass %i.", pass);
-               if (pass == 1) {
-                       /*
-                        * Now do pass 2, scanning the first part of the zone
-                        * we omitted in pass 1.
-                        */
-                       pass = 2;
-                       zone_end = zone_start;
-                       switch (search_zone) {
-                       case 1: /* mft_zone */
-                               zone_start = vol->mft_zone_start;
-                               break;
-                       case 2: /* data1_zone */
-                               zone_start = vol->mft_zone_end;
-                               break;
-                       case 4: /* data2_zone */
-                               zone_start = 0;
-                               break;
-                       default:
-                               BUG();
-                       }
-                       /* Sanity check. */
-                       if (zone_end < zone_start)
-                               zone_end = zone_start;
-                       bmp_pos = zone_start;
-                       ntfs_debug("Continuing outer while loop, pass 2, "
-                                       "zone_start 0x%llx, zone_end 0x%llx, "
-                                       "bmp_pos 0x%llx.",
-                                       (unsigned long long)zone_start,
-                                       (unsigned long long)zone_end,
-                                       (unsigned long long)bmp_pos);
-                       continue;
-               } /* pass == 2 */
-done_zones_check:
-               ntfs_debug("At done_zones_check, search_zone %i, done_zones "
-                               "before 0x%x, done_zones after 0x%x.",
-                               search_zone, done_zones,
-                               done_zones | search_zone);
-               done_zones |= search_zone;
-               if (done_zones < 7) {
-                       ntfs_debug("Switching zone.");
-                       /* Now switch to the next zone we haven't done yet. */
-                       pass = 1;
-                       switch (search_zone) {
-                       case 1:
-                               ntfs_debug("Switching from mft zone to data1 "
-                                               "zone.");
-                               /* Update mft zone position. */
-                               if (rlpos) {
-                                       LCN tc;
-
-                                       ntfs_debug("Before checks, "
-                                                       "vol->mft_zone_pos "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       vol->mft_zone_pos);
-                                       tc = rl[rlpos - 1].lcn +
-                                                       rl[rlpos - 1].length;
-                                       if (tc >= vol->mft_zone_end) {
-                                               vol->mft_zone_pos =
-                                                               vol->mft_lcn;
-                                               if (!vol->mft_zone_end)
-                                                       vol->mft_zone_pos = 0;
-                                       } else if ((bmp_initial_pos >=
-                                                       vol->mft_zone_pos ||
-                                                       tc > vol->mft_zone_pos)
-                                                       && tc >= vol->mft_lcn)
-                                               vol->mft_zone_pos = tc;
-                                       ntfs_debug("After checks, "
-                                                       "vol->mft_zone_pos "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       vol->mft_zone_pos);
-                               }
-                               /* Switch from mft zone to data1 zone. */
-switch_to_data1_zone:          search_zone = 2;
-                               zone_start = bmp_initial_pos =
-                                               vol->data1_zone_pos;
-                               zone_end = vol->nr_clusters;
-                               if (zone_start == vol->mft_zone_end)
-                                       pass = 2;
-                               if (zone_start >= zone_end) {
-                                       vol->data1_zone_pos = zone_start =
-                                                       vol->mft_zone_end;
-                                       pass = 2;
-                               }
-                               break;
-                       case 2:
-                               ntfs_debug("Switching from data1 zone to "
-                                               "data2 zone.");
-                               /* Update data1 zone position. */
-                               if (rlpos) {
-                                       LCN tc;
-
-                                       ntfs_debug("Before checks, "
-                                                       "vol->data1_zone_pos "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       vol->data1_zone_pos);
-                                       tc = rl[rlpos - 1].lcn +
-                                                       rl[rlpos - 1].length;
-                                       if (tc >= vol->nr_clusters)
-                                               vol->data1_zone_pos =
-                                                            vol->mft_zone_end;
-                                       else if ((bmp_initial_pos >=
-                                                   vol->data1_zone_pos ||
-                                                   tc > vol->data1_zone_pos)
-                                                   && tc >= vol->mft_zone_end)
-                                               vol->data1_zone_pos = tc;
-                                       ntfs_debug("After checks, "
-                                                       "vol->data1_zone_pos "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       vol->data1_zone_pos);
-                               }
-                               /* Switch from data1 zone to data2 zone. */
-                               search_zone = 4;
-                               zone_start = bmp_initial_pos =
-                                               vol->data2_zone_pos;
-                               zone_end = vol->mft_zone_start;
-                               if (!zone_start)
-                                       pass = 2;
-                               if (zone_start >= zone_end) {
-                                       vol->data2_zone_pos = zone_start =
-                                                       bmp_initial_pos = 0;
-                                       pass = 2;
-                               }
-                               break;
-                       case 4:
-                               ntfs_debug("Switching from data2 zone to "
-                                               "data1 zone.");
-                               /* Update data2 zone position. */
-                               if (rlpos) {
-                                       LCN tc;
-
-                                       ntfs_debug("Before checks, "
-                                                       "vol->data2_zone_pos "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       vol->data2_zone_pos);
-                                       tc = rl[rlpos - 1].lcn +
-                                                       rl[rlpos - 1].length;
-                                       if (tc >= vol->mft_zone_start)
-                                               vol->data2_zone_pos = 0;
-                                       else if (bmp_initial_pos >=
-                                                     vol->data2_zone_pos ||
-                                                     tc > vol->data2_zone_pos)
-                                               vol->data2_zone_pos = tc;
-                                       ntfs_debug("After checks, "
-                                                       "vol->data2_zone_pos "
-                                                       "0x%llx.",
-                                                       (unsigned long long)
-                                                       vol->data2_zone_pos);
-                               }
-                               /* Switch from data2 zone to data1 zone. */
-                               goto switch_to_data1_zone;
-                       default:
-                               BUG();
-                       }
-                       ntfs_debug("After zone switch, search_zone %i, "
-                                       "pass %i, bmp_initial_pos 0x%llx, "
-                                       "zone_start 0x%llx, zone_end 0x%llx.",
-                                       search_zone, pass,
-                                       (unsigned long long)bmp_initial_pos,
-                                       (unsigned long long)zone_start,
-                                       (unsigned long long)zone_end);
-                       bmp_pos = zone_start;
-                       if (zone_start == zone_end) {
-                               ntfs_debug("Empty zone, going to "
-                                               "done_zones_check.");
-                               /* Empty zone. Don't bother searching it. */
-                               goto done_zones_check;
-                       }
-                       ntfs_debug("Continuing outer while loop.");
-                       continue;
-               } /* done_zones == 7 */
-               ntfs_debug("All zones are finished.");
-               /*
-                * All zones are finished!  If DATA_ZONE, shrink mft zone.  If
-                * MFT_ZONE, we have really run out of space.
-                */
-               mft_zone_size = vol->mft_zone_end - vol->mft_zone_start;
-               ntfs_debug("vol->mft_zone_start 0x%llx, vol->mft_zone_end "
-                               "0x%llx, mft_zone_size 0x%llx.",
-                               (unsigned long long)vol->mft_zone_start,
-                               (unsigned long long)vol->mft_zone_end,
-                               (unsigned long long)mft_zone_size);
-               if (zone == MFT_ZONE || mft_zone_size <= 0) {
-                       ntfs_debug("No free clusters left, going to out.");
-                       /* Really no more space left on device. */
-                       err = -ENOSPC;
-                       goto out;
-               } /* zone == DATA_ZONE && mft_zone_size > 0 */
-               ntfs_debug("Shrinking mft zone.");
-               zone_end = vol->mft_zone_end;
-               mft_zone_size >>= 1;
-               if (mft_zone_size > 0)
-                       vol->mft_zone_end = vol->mft_zone_start + mft_zone_size;
-               else /* mft zone and data2 zone no longer exist. */
-                       vol->data2_zone_pos = vol->mft_zone_start =
-                                       vol->mft_zone_end = 0;
-               if (vol->mft_zone_pos >= vol->mft_zone_end) {
-                       vol->mft_zone_pos = vol->mft_lcn;
-                       if (!vol->mft_zone_end)
-                               vol->mft_zone_pos = 0;
-               }
-               bmp_pos = zone_start = bmp_initial_pos =
-                               vol->data1_zone_pos = vol->mft_zone_end;
-               search_zone = 2;
-               pass = 2;
-               done_zones &= ~2;
-               ntfs_debug("After shrinking mft zone, mft_zone_size 0x%llx, "
-                               "vol->mft_zone_start 0x%llx, "
-                               "vol->mft_zone_end 0x%llx, "
-                               "vol->mft_zone_pos 0x%llx, search_zone 2, "
-                               "pass 2, dones_zones 0x%x, zone_start 0x%llx, "
-                               "zone_end 0x%llx, vol->data1_zone_pos 0x%llx, "
-                               "continuing outer while loop.",
-                               (unsigned long long)mft_zone_size,
-                               (unsigned long long)vol->mft_zone_start,
-                               (unsigned long long)vol->mft_zone_end,
-                               (unsigned long long)vol->mft_zone_pos,
-                               done_zones, (unsigned long long)zone_start,
-                               (unsigned long long)zone_end,
-                               (unsigned long long)vol->data1_zone_pos);
-       }
-       ntfs_debug("After outer while loop.");
-out:
-       ntfs_debug("At out.");
-       /* Add runlist terminator element. */
-       if (likely(rl)) {
-               rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
-               rl[rlpos].lcn = is_extension ? LCN_ENOENT : LCN_RL_NOT_MAPPED;
-               rl[rlpos].length = 0;
-       }
-       if (likely(page && !IS_ERR(page))) {
-               if (need_writeback) {
-                       ntfs_debug("Marking page dirty.");
-                       flush_dcache_page(page);
-                       set_page_dirty(page);
-                       need_writeback = 0;
-               }
-               ntfs_unmap_page(page);
-       }
-       if (likely(!err)) {
-               up_write(&vol->lcnbmp_lock);
-               ntfs_debug("Done.");
-               return rl;
-       }
-       ntfs_error(vol->sb, "Failed to allocate clusters, aborting "
-                       "(error %i).", err);
-       if (rl) {
-               int err2;
-
-               if (err == -ENOSPC)
-                       ntfs_debug("Not enough space to complete allocation, "
-                                       "err -ENOSPC, first free lcn 0x%llx, "
-                                       "could allocate up to 0x%llx "
-                                       "clusters.",
-                                       (unsigned long long)rl[0].lcn,
-                                       (unsigned long long)(count - clusters));
-               /* Deallocate all allocated clusters. */
-               ntfs_debug("Attempting rollback...");
-               err2 = ntfs_cluster_free_from_rl_nolock(vol, rl);
-               if (err2) {
-                       ntfs_error(vol->sb, "Failed to rollback (error %i).  "
-                                       "Leaving inconsistent metadata!  "
-                                       "Unmount and run chkdsk.", err2);
-                       NVolSetErrors(vol);
-               }
-               /* Free the runlist. */
-               ntfs_free(rl);
-       } else if (err == -ENOSPC)
-               ntfs_debug("No space left at all, err = -ENOSPC, first free "
-                               "lcn = 0x%llx.",
-                               (long long)vol->data1_zone_pos);
-       up_write(&vol->lcnbmp_lock);
-       return ERR_PTR(err);
-}
-
-/**
- * __ntfs_cluster_free - free clusters on an ntfs volume
- * @ni:                ntfs inode whose runlist describes the clusters to free
- * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters
- * @count:     number of clusters to free or -1 for all clusters
- * @ctx:       active attribute search context if present or NULL if not
- * @is_rollback:       true if this is a rollback operation
- *
- * Free @count clusters starting at the cluster @start_vcn in the runlist
- * described by the vfs inode @ni.
- *
- * If @count is -1, all clusters from @start_vcn to the end of the runlist are
- * deallocated.  Thus, to completely free all clusters in a runlist, use
- * @start_vcn = 0 and @count = -1.
- *
- * If @ctx is specified, it is an active search context of @ni and its base mft
- * record.  This is needed when __ntfs_cluster_free() encounters unmapped
- * runlist fragments and allows their mapping.  If you do not have the mft
- * record mapped, you can specify @ctx as NULL and __ntfs_cluster_free() will
- * perform the necessary mapping and unmapping.
- *
- * Note, __ntfs_cluster_free() saves the state of @ctx on entry and restores it
- * before returning.  Thus, @ctx will be left pointing to the same attribute on
- * return as on entry.  However, the actual pointers in @ctx may point to
- * different memory locations on return, so you must remember to reset any
- * cached pointers from the @ctx, i.e. after the call to __ntfs_cluster_free(),
- * you will probably want to do:
- *     m = ctx->mrec;
- *     a = ctx->attr;
- * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that
- * you cache ctx->mrec in a variable @m of type MFT_RECORD *.
- *
- * @is_rollback should always be 'false', it is for internal use to rollback
- * errors.  You probably want to use ntfs_cluster_free() instead.
- *
- * Note, __ntfs_cluster_free() does not modify the runlist, so you have to
- * remove from the runlist or mark sparse the freed runs later.
- *
- * Return the number of deallocated clusters (not counting sparse ones) on
- * success and -errno on error.
- *
- * WARNING: If @ctx is supplied, regardless of whether success or failure is
- *         returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
- *         is no longer valid, i.e. you need to either call
- *         ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
- *         In that case PTR_ERR(@ctx->mrec) will give you the error code for
- *         why the mapping of the old inode failed.
- *
- * Locking: - The runlist described by @ni must be locked for writing on entry
- *           and is locked on return.  Note the runlist may be modified when
- *           needed runlist fragments need to be mapped.
- *         - The volume lcn bitmap must be unlocked on entry and is unlocked
- *           on return.
- *         - This function takes the volume lcn bitmap lock for writing and
- *           modifies the bitmap contents.
- *         - If @ctx is NULL, the base mft record of @ni must not be mapped on
- *           entry and it will be left unmapped on return.
- *         - If @ctx is not NULL, the base mft record must be mapped on entry
- *           and it will be left mapped on return.
- */
-s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count,
-               ntfs_attr_search_ctx *ctx, const bool is_rollback)
-{
-       s64 delta, to_free, total_freed, real_freed;
-       ntfs_volume *vol;
-       struct inode *lcnbmp_vi;
-       runlist_element *rl;
-       int err;
-
-       BUG_ON(!ni);
-       ntfs_debug("Entering for i_ino 0x%lx, start_vcn 0x%llx, count "
-                       "0x%llx.%s", ni->mft_no, (unsigned long long)start_vcn,
-                       (unsigned long long)count,
-                       is_rollback ? " (rollback)" : "");
-       vol = ni->vol;
-       lcnbmp_vi = vol->lcnbmp_ino;
-       BUG_ON(!lcnbmp_vi);
-       BUG_ON(start_vcn < 0);
-       BUG_ON(count < -1);
-       /*
-        * Lock the lcn bitmap for writing but only if not rolling back.  We
-        * must hold the lock all the way including through rollback otherwise
-        * rollback is not possible because once we have cleared a bit and
-        * dropped the lock, anyone could have set the bit again, thus
-        * allocating the cluster for another use.
-        */
-       if (likely(!is_rollback))
-               down_write(&vol->lcnbmp_lock);
-
-       total_freed = real_freed = 0;
-
-       rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, ctx);
-       if (IS_ERR(rl)) {
-               if (!is_rollback)
-                       ntfs_error(vol->sb, "Failed to find first runlist "
-                                       "element (error %li), aborting.",
-                                       PTR_ERR(rl));
-               err = PTR_ERR(rl);
-               goto err_out;
-       }
-       if (unlikely(rl->lcn < LCN_HOLE)) {
-               if (!is_rollback)
-                       ntfs_error(vol->sb, "First runlist element has "
-                                       "invalid lcn, aborting.");
-               err = -EIO;
-               goto err_out;
-       }
-       /* Find the starting cluster inside the run that needs freeing. */
-       delta = start_vcn - rl->vcn;
-
-       /* The number of clusters in this run that need freeing. */
-       to_free = rl->length - delta;
-       if (count >= 0 && to_free > count)
-               to_free = count;
-
-       if (likely(rl->lcn >= 0)) {
-               /* Do the actual freeing of the clusters in this run. */
-               err = ntfs_bitmap_set_bits_in_run(lcnbmp_vi, rl->lcn + delta,
-                               to_free, likely(!is_rollback) ? 0 : 1);
-               if (unlikely(err)) {
-                       if (!is_rollback)
-                               ntfs_error(vol->sb, "Failed to clear first run "
-                                               "(error %i), aborting.", err);
-                       goto err_out;
-               }
-               /* We have freed @to_free real clusters. */
-               real_freed = to_free;
-       };
-       /* Go to the next run and adjust the number of clusters left to free. */
-       ++rl;
-       if (count >= 0)
-               count -= to_free;
-
-       /* Keep track of the total "freed" clusters, including sparse ones. */
-       total_freed = to_free;
-       /*
-        * Loop over the remaining runs, using @count as a capping value, and
-        * free them.
-        */
-       for (; rl->length && count != 0; ++rl) {
-               if (unlikely(rl->lcn < LCN_HOLE)) {
-                       VCN vcn;
-
-                       /* Attempt to map runlist. */
-                       vcn = rl->vcn;
-                       rl = ntfs_attr_find_vcn_nolock(ni, vcn, ctx);
-                       if (IS_ERR(rl)) {
-                               err = PTR_ERR(rl);
-                               if (!is_rollback)
-                                       ntfs_error(vol->sb, "Failed to map "
-                                                       "runlist fragment or "
-                                                       "failed to find "
-                                                       "subsequent runlist "
-                                                       "element.");
-                               goto err_out;
-                       }
-                       if (unlikely(rl->lcn < LCN_HOLE)) {
-                               if (!is_rollback)
-                                       ntfs_error(vol->sb, "Runlist element "
-                                                       "has invalid lcn "
-                                                       "(0x%llx).",
-                                                       (unsigned long long)
-                                                       rl->lcn);
-                               err = -EIO;
-                               goto err_out;
-                       }
-               }
-               /* The number of clusters in this run that need freeing. */
-               to_free = rl->length;
-               if (count >= 0 && to_free > count)
-                       to_free = count;
-
-               if (likely(rl->lcn >= 0)) {
-                       /* Do the actual freeing of the clusters in the run. */
-                       err = ntfs_bitmap_set_bits_in_run(lcnbmp_vi, rl->lcn,
-                                       to_free, likely(!is_rollback) ? 0 : 1);
-                       if (unlikely(err)) {
-                               if (!is_rollback)
-                                       ntfs_error(vol->sb, "Failed to clear "
-                                                       "subsequent run.");
-                               goto err_out;
-                       }
-                       /* We have freed @to_free real clusters. */
-                       real_freed += to_free;
-               }
-               /* Adjust the number of clusters left to free. */
-               if (count >= 0)
-                       count -= to_free;
-       
-               /* Update the total done clusters. */
-               total_freed += to_free;
-       }
-       if (likely(!is_rollback))
-               up_write(&vol->lcnbmp_lock);
-
-       BUG_ON(count > 0);
-
-       /* We are done.  Return the number of actually freed clusters. */
-       ntfs_debug("Done.");
-       return real_freed;
-err_out:
-       if (is_rollback)
-               return err;
-       /* If no real clusters were freed, no need to rollback. */
-       if (!real_freed) {
-               up_write(&vol->lcnbmp_lock);
-               return err;
-       }
-       /*
-        * Attempt to rollback and if that succeeds just return the error code.
-        * If rollback fails, set the volume errors flag, emit an error
-        * message, and return the error code.
-        */
-       delta = __ntfs_cluster_free(ni, start_vcn, total_freed, ctx, true);
-       if (delta < 0) {
-               ntfs_error(vol->sb, "Failed to rollback (error %i).  Leaving "
-                               "inconsistent metadata!  Unmount and run "
-                               "chkdsk.", (int)delta);
-               NVolSetErrors(vol);
-       }
-       up_write(&vol->lcnbmp_lock);
-       ntfs_error(vol->sb, "Aborting (error %i).", err);
-       return err;
-}
-
-#endif /* NTFS_RW */
diff --git a/fs/ntfs/lcnalloc.h b/fs/ntfs/lcnalloc.h
deleted file mode 100644 (file)
index 1589a6d..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * lcnalloc.h - Exports for NTFS kernel cluster (de)allocation.  Part of the
- *             Linux-NTFS project.
- *
- * Copyright (c) 2004-2005 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_LCNALLOC_H
-#define _LINUX_NTFS_LCNALLOC_H
-
-#ifdef NTFS_RW
-
-#include <linux/fs.h>
-
-#include "attrib.h"
-#include "types.h"
-#include "inode.h"
-#include "runlist.h"
-#include "volume.h"
-
-typedef enum {
-       FIRST_ZONE      = 0,    /* For sanity checking. */
-       MFT_ZONE        = 0,    /* Allocate from $MFT zone. */
-       DATA_ZONE       = 1,    /* Allocate from $DATA zone. */
-       LAST_ZONE       = 1,    /* For sanity checking. */
-} NTFS_CLUSTER_ALLOCATION_ZONES;
-
-extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol,
-               const VCN start_vcn, const s64 count, const LCN start_lcn,
-               const NTFS_CLUSTER_ALLOCATION_ZONES zone,
-               const bool is_extension);
-
-extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
-               s64 count, ntfs_attr_search_ctx *ctx, const bool is_rollback);
-
-/**
- * ntfs_cluster_free - free clusters on an ntfs volume
- * @ni:                ntfs inode whose runlist describes the clusters to free
- * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters
- * @count:     number of clusters to free or -1 for all clusters
- * @ctx:       active attribute search context if present or NULL if not
- *
- * Free @count clusters starting at the cluster @start_vcn in the runlist
- * described by the ntfs inode @ni.
- *
- * If @count is -1, all clusters from @start_vcn to the end of the runlist are
- * deallocated.  Thus, to completely free all clusters in a runlist, use
- * @start_vcn = 0 and @count = -1.
- *
- * If @ctx is specified, it is an active search context of @ni and its base mft
- * record.  This is needed when ntfs_cluster_free() encounters unmapped runlist
- * fragments and allows their mapping.  If you do not have the mft record
- * mapped, you can specify @ctx as NULL and ntfs_cluster_free() will perform
- * the necessary mapping and unmapping.
- *
- * Note, ntfs_cluster_free() saves the state of @ctx on entry and restores it
- * before returning.  Thus, @ctx will be left pointing to the same attribute on
- * return as on entry.  However, the actual pointers in @ctx may point to
- * different memory locations on return, so you must remember to reset any
- * cached pointers from the @ctx, i.e. after the call to ntfs_cluster_free(),
- * you will probably want to do:
- *     m = ctx->mrec;
- *     a = ctx->attr;
- * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that
- * you cache ctx->mrec in a variable @m of type MFT_RECORD *.
- *
- * Note, ntfs_cluster_free() does not modify the runlist, so you have to remove
- * from the runlist or mark sparse the freed runs later.
- *
- * Return the number of deallocated clusters (not counting sparse ones) on
- * success and -errno on error.
- *
- * WARNING: If @ctx is supplied, regardless of whether success or failure is
- *         returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
- *         is no longer valid, i.e. you need to either call
- *         ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
- *         In that case PTR_ERR(@ctx->mrec) will give you the error code for
- *         why the mapping of the old inode failed.
- *
- * Locking: - The runlist described by @ni must be locked for writing on entry
- *           and is locked on return.  Note the runlist may be modified when
- *           needed runlist fragments need to be mapped.
- *         - The volume lcn bitmap must be unlocked on entry and is unlocked
- *           on return.
- *         - This function takes the volume lcn bitmap lock for writing and
- *           modifies the bitmap contents.
- *         - If @ctx is NULL, the base mft record of @ni must not be mapped on
- *           entry and it will be left unmapped on return.
- *         - If @ctx is not NULL, the base mft record must be mapped on entry
- *           and it will be left mapped on return.
- */
-static inline s64 ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
-               s64 count, ntfs_attr_search_ctx *ctx)
-{
-       return __ntfs_cluster_free(ni, start_vcn, count, ctx, false);
-}
-
-extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
-               const runlist_element *rl);
-
-/**
- * ntfs_cluster_free_from_rl - free clusters from runlist
- * @vol:       mounted ntfs volume on which to free the clusters
- * @rl:                runlist describing the clusters to free
- *
- * Free all the clusters described by the runlist @rl on the volume @vol.  In
- * the case of an error being returned, at least some of the clusters were not
- * freed.
- *
- * Return 0 on success and -errno on error.
- *
- * Locking: - This function takes the volume lcn bitmap lock for writing and
- *           modifies the bitmap contents.
- *         - The caller must have locked the runlist @rl for reading or
- *           writing.
- */
-static inline int ntfs_cluster_free_from_rl(ntfs_volume *vol,
-               const runlist_element *rl)
-{
-       int ret;
-
-       down_write(&vol->lcnbmp_lock);
-       ret = ntfs_cluster_free_from_rl_nolock(vol, rl);
-       up_write(&vol->lcnbmp_lock);
-       return ret;
-}
-
-#endif /* NTFS_RW */
-
-#endif /* defined _LINUX_NTFS_LCNALLOC_H */
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c
deleted file mode 100644 (file)
index 6ce60ff..0000000
+++ /dev/null
@@ -1,849 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2002-2007 Anton Altaparmakov
- */
-
-#ifdef NTFS_RW
-
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/highmem.h>
-#include <linux/buffer_head.h>
-#include <linux/bitops.h>
-#include <linux/log2.h>
-#include <linux/bio.h>
-
-#include "attrib.h"
-#include "aops.h"
-#include "debug.h"
-#include "logfile.h"
-#include "malloc.h"
-#include "volume.h"
-#include "ntfs.h"
-
-/**
- * ntfs_check_restart_page_header - check the page header for consistency
- * @vi:                $LogFile inode to which the restart page header belongs
- * @rp:                restart page header to check
- * @pos:       position in @vi at which the restart page header resides
- *
- * Check the restart page header @rp for consistency and return 'true' if it is
- * consistent and 'false' otherwise.
- *
- * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
- * require the full restart page.
- */
-static bool ntfs_check_restart_page_header(struct inode *vi,
-               RESTART_PAGE_HEADER *rp, s64 pos)
-{
-       u32 logfile_system_page_size, logfile_log_page_size;
-       u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
-       bool have_usa = true;
-
-       ntfs_debug("Entering.");
-       /*
-        * If the system or log page sizes are smaller than the ntfs block size
-        * or either is not a power of 2 we cannot handle this log file.
-        */
-       logfile_system_page_size = le32_to_cpu(rp->system_page_size);
-       logfile_log_page_size = le32_to_cpu(rp->log_page_size);
-       if (logfile_system_page_size < NTFS_BLOCK_SIZE ||
-                       logfile_log_page_size < NTFS_BLOCK_SIZE ||
-                       logfile_system_page_size &
-                       (logfile_system_page_size - 1) ||
-                       !is_power_of_2(logfile_log_page_size)) {
-               ntfs_error(vi->i_sb, "$LogFile uses unsupported page size.");
-               return false;
-       }
-       /*
-        * We must be either at !pos (1st restart page) or at pos = system page
-        * size (2nd restart page).
-        */
-       if (pos && pos != logfile_system_page_size) {
-               ntfs_error(vi->i_sb, "Found restart area in incorrect "
-                               "position in $LogFile.");
-               return false;
-       }
-       /* We only know how to handle version 1.1. */
-       if (sle16_to_cpu(rp->major_ver) != 1 ||
-                       sle16_to_cpu(rp->minor_ver) != 1) {
-               ntfs_error(vi->i_sb, "$LogFile version %i.%i is not "
-                               "supported.  (This driver supports version "
-                               "1.1 only.)", (int)sle16_to_cpu(rp->major_ver),
-                               (int)sle16_to_cpu(rp->minor_ver));
-               return false;
-       }
-       /*
-        * If chkdsk has been run the restart page may not be protected by an
-        * update sequence array.
-        */
-       if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
-               have_usa = false;
-               goto skip_usa_checks;
-       }
-       /* Verify the size of the update sequence array. */
-       usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS);
-       if (usa_count != le16_to_cpu(rp->usa_count)) {
-               ntfs_error(vi->i_sb, "$LogFile restart page specifies "
-                               "inconsistent update sequence array count.");
-               return false;
-       }
-       /* Verify the position of the update sequence array. */
-       usa_ofs = le16_to_cpu(rp->usa_ofs);
-       usa_end = usa_ofs + usa_count * sizeof(u16);
-       if (usa_ofs < sizeof(RESTART_PAGE_HEADER) ||
-                       usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
-               ntfs_error(vi->i_sb, "$LogFile restart page specifies "
-                               "inconsistent update sequence array offset.");
-               return false;
-       }
-skip_usa_checks:
-       /*
-        * Verify the position of the restart area.  It must be:
-        *      - aligned to 8-byte boundary,
-        *      - after the update sequence array, and
-        *      - within the system page size.
-        */
-       ra_ofs = le16_to_cpu(rp->restart_area_offset);
-       if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
-                       ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
-                       ra_ofs > logfile_system_page_size) {
-               ntfs_error(vi->i_sb, "$LogFile restart page specifies "
-                               "inconsistent restart area offset.");
-               return false;
-       }
-       /*
-        * Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
-        * set.
-        */
-       if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
-               ntfs_error(vi->i_sb, "$LogFile restart page is not modified "
-                               "by chkdsk but a chkdsk LSN is specified.");
-               return false;
-       }
-       ntfs_debug("Done.");
-       return true;
-}
-
-/**
- * ntfs_check_restart_area - check the restart area for consistency
- * @vi:                $LogFile inode to which the restart page belongs
- * @rp:                restart page whose restart area to check
- *
- * Check the restart area of the restart page @rp for consistency and return
- * 'true' if it is consistent and 'false' otherwise.
- *
- * This function assumes that the restart page header has already been
- * consistency checked.
- *
- * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
- * require the full restart page.
- */
-static bool ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
-{
-       u64 file_size;
-       RESTART_AREA *ra;
-       u16 ra_ofs, ra_len, ca_ofs;
-       u8 fs_bits;
-
-       ntfs_debug("Entering.");
-       ra_ofs = le16_to_cpu(rp->restart_area_offset);
-       ra = (RESTART_AREA*)((u8*)rp + ra_ofs);
-       /*
-        * Everything before ra->file_size must be before the first word
-        * protected by an update sequence number.  This ensures that it is
-        * safe to access ra->client_array_offset.
-        */
-       if (ra_ofs + offsetof(RESTART_AREA, file_size) >
-                       NTFS_BLOCK_SIZE - sizeof(u16)) {
-               ntfs_error(vi->i_sb, "$LogFile restart area specifies "
-                               "inconsistent file offset.");
-               return false;
-       }
-       /*
-        * Now that we can access ra->client_array_offset, make sure everything
-        * up to the log client array is before the first word protected by an
-        * update sequence number.  This ensures we can access all of the
-        * restart area elements safely.  Also, the client array offset must be
-        * aligned to an 8-byte boundary.
-        */
-       ca_ofs = le16_to_cpu(ra->client_array_offset);
-       if (((ca_ofs + 7) & ~7) != ca_ofs ||
-                       ra_ofs + ca_ofs > NTFS_BLOCK_SIZE - sizeof(u16)) {
-               ntfs_error(vi->i_sb, "$LogFile restart area specifies "
-                               "inconsistent client array offset.");
-               return false;
-       }
-       /*
-        * The restart area must end within the system page size both when
-        * calculated manually and as specified by ra->restart_area_length.
-        * Also, the calculated length must not exceed the specified length.
-        */
-       ra_len = ca_ofs + le16_to_cpu(ra->log_clients) *
-                       sizeof(LOG_CLIENT_RECORD);
-       if (ra_ofs + ra_len > le32_to_cpu(rp->system_page_size) ||
-                       ra_ofs + le16_to_cpu(ra->restart_area_length) >
-                       le32_to_cpu(rp->system_page_size) ||
-                       ra_len > le16_to_cpu(ra->restart_area_length)) {
-               ntfs_error(vi->i_sb, "$LogFile restart area is out of bounds "
-                               "of the system page size specified by the "
-                               "restart page header and/or the specified "
-                               "restart area length is inconsistent.");
-               return false;
-       }
-       /*
-        * The ra->client_free_list and ra->client_in_use_list must be either
-        * LOGFILE_NO_CLIENT or less than ra->log_clients or they are
-        * overflowing the client array.
-        */
-       if ((ra->client_free_list != LOGFILE_NO_CLIENT &&
-                       le16_to_cpu(ra->client_free_list) >=
-                       le16_to_cpu(ra->log_clients)) ||
-                       (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
-                       le16_to_cpu(ra->client_in_use_list) >=
-                       le16_to_cpu(ra->log_clients))) {
-               ntfs_error(vi->i_sb, "$LogFile restart area specifies "
-                               "overflowing client free and/or in use lists.");
-               return false;
-       }
-       /*
-        * Check ra->seq_number_bits against ra->file_size for consistency.
-        * We cannot just use ffs() because the file size is not a power of 2.
-        */
-       file_size = (u64)sle64_to_cpu(ra->file_size);
-       fs_bits = 0;
-       while (file_size) {
-               file_size >>= 1;
-               fs_bits++;
-       }
-       if (le32_to_cpu(ra->seq_number_bits) != 67 - fs_bits) {
-               ntfs_error(vi->i_sb, "$LogFile restart area specifies "
-                               "inconsistent sequence number bits.");
-               return false;
-       }
-       /* The log record header length must be a multiple of 8. */
-       if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) !=
-                       le16_to_cpu(ra->log_record_header_length)) {
-               ntfs_error(vi->i_sb, "$LogFile restart area specifies "
-                               "inconsistent log record header length.");
-               return false;
-       }
-       /* Dito for the log page data offset. */
-       if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) !=
-                       le16_to_cpu(ra->log_page_data_offset)) {
-               ntfs_error(vi->i_sb, "$LogFile restart area specifies "
-                               "inconsistent log page data offset.");
-               return false;
-       }
-       ntfs_debug("Done.");
-       return true;
-}
-
-/**
- * ntfs_check_log_client_array - check the log client array for consistency
- * @vi:                $LogFile inode to which the restart page belongs
- * @rp:                restart page whose log client array to check
- *
- * Check the log client array of the restart page @rp for consistency and
- * return 'true' if it is consistent and 'false' otherwise.
- *
- * This function assumes that the restart page header and the restart area have
- * already been consistency checked.
- *
- * Unlike ntfs_check_restart_page_header() and ntfs_check_restart_area(), this
- * function needs @rp->system_page_size bytes in @rp, i.e. it requires the full
- * restart page and the page must be multi sector transfer deprotected.
- */
-static bool ntfs_check_log_client_array(struct inode *vi,
-               RESTART_PAGE_HEADER *rp)
-{
-       RESTART_AREA *ra;
-       LOG_CLIENT_RECORD *ca, *cr;
-       u16 nr_clients, idx;
-       bool in_free_list, idx_is_first;
-
-       ntfs_debug("Entering.");
-       ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
-       ca = (LOG_CLIENT_RECORD*)((u8*)ra +
-                       le16_to_cpu(ra->client_array_offset));
-       /*
-        * Check the ra->client_free_list first and then check the
-        * ra->client_in_use_list.  Check each of the log client records in
-        * each of the lists and check that the array does not overflow the
-        * ra->log_clients value.  Also keep track of the number of records
-        * visited as there cannot be more than ra->log_clients records and
-        * that way we detect eventual loops in within a list.
-        */
-       nr_clients = le16_to_cpu(ra->log_clients);
-       idx = le16_to_cpu(ra->client_free_list);
-       in_free_list = true;
-check_list:
-       for (idx_is_first = true; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
-                       idx = le16_to_cpu(cr->next_client)) {
-               if (!nr_clients || idx >= le16_to_cpu(ra->log_clients))
-                       goto err_out;
-               /* Set @cr to the current log client record. */
-               cr = ca + idx;
-               /* The first log client record must not have a prev_client. */
-               if (idx_is_first) {
-                       if (cr->prev_client != LOGFILE_NO_CLIENT)
-                               goto err_out;
-                       idx_is_first = false;
-               }
-       }
-       /* Switch to and check the in use list if we just did the free list. */
-       if (in_free_list) {
-               in_free_list = false;
-               idx = le16_to_cpu(ra->client_in_use_list);
-               goto check_list;
-       }
-       ntfs_debug("Done.");
-       return true;
-err_out:
-       ntfs_error(vi->i_sb, "$LogFile log client array is corrupt.");
-       return false;
-}
-
-/**
- * ntfs_check_and_load_restart_page - check the restart page for consistency
- * @vi:                $LogFile inode to which the restart page belongs
- * @rp:                restart page to check
- * @pos:       position in @vi at which the restart page resides
- * @wrp:       [OUT] copy of the multi sector transfer deprotected restart page
- * @lsn:       [OUT] set to the current logfile lsn on success
- *
- * Check the restart page @rp for consistency and return 0 if it is consistent
- * and -errno otherwise.  The restart page may have been modified by chkdsk in
- * which case its magic is CHKD instead of RSTR.
- *
- * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
- * require the full restart page.
- *
- * If @wrp is not NULL, on success, *@wrp will point to a buffer containing a
- * copy of the complete multi sector transfer deprotected page.  On failure,
- * *@wrp is undefined.
- *
- * Simillarly, if @lsn is not NULL, on success *@lsn will be set to the current
- * logfile lsn according to this restart page.  On failure, *@lsn is undefined.
- *
- * The following error codes are defined:
- *     -EINVAL - The restart page is inconsistent.
- *     -ENOMEM - Not enough memory to load the restart page.
- *     -EIO    - Failed to reading from $LogFile.
- */
-static int ntfs_check_and_load_restart_page(struct inode *vi,
-               RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp,
-               LSN *lsn)
-{
-       RESTART_AREA *ra;
-       RESTART_PAGE_HEADER *trp;
-       int size, err;
-
-       ntfs_debug("Entering.");
-       /* Check the restart page header for consistency. */
-       if (!ntfs_check_restart_page_header(vi, rp, pos)) {
-               /* Error output already done inside the function. */
-               return -EINVAL;
-       }
-       /* Check the restart area for consistency. */
-       if (!ntfs_check_restart_area(vi, rp)) {
-               /* Error output already done inside the function. */
-               return -EINVAL;
-       }
-       ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
-       /*
-        * Allocate a buffer to store the whole restart page so we can multi
-        * sector transfer deprotect it.
-        */
-       trp = ntfs_malloc_nofs(le32_to_cpu(rp->system_page_size));
-       if (!trp) {
-               ntfs_error(vi->i_sb, "Failed to allocate memory for $LogFile "
-                               "restart page buffer.");
-               return -ENOMEM;
-       }
-       /*
-        * Read the whole of the restart page into the buffer.  If it fits
-        * completely inside @rp, just copy it from there.  Otherwise map all
-        * the required pages and copy the data from them.
-        */
-       size = PAGE_SIZE - (pos & ~PAGE_MASK);
-       if (size >= le32_to_cpu(rp->system_page_size)) {
-               memcpy(trp, rp, le32_to_cpu(rp->system_page_size));
-       } else {
-               pgoff_t idx;
-               struct page *page;
-               int have_read, to_read;
-
-               /* First copy what we already have in @rp. */
-               memcpy(trp, rp, size);
-               /* Copy the remaining data one page at a time. */
-               have_read = size;
-               to_read = le32_to_cpu(rp->system_page_size) - size;
-               idx = (pos + size) >> PAGE_SHIFT;
-               BUG_ON((pos + size) & ~PAGE_MASK);
-               do {
-                       page = ntfs_map_page(vi->i_mapping, idx);
-                       if (IS_ERR(page)) {
-                               ntfs_error(vi->i_sb, "Error mapping $LogFile "
-                                               "page (index %lu).", idx);
-                               err = PTR_ERR(page);
-                               if (err != -EIO && err != -ENOMEM)
-                                       err = -EIO;
-                               goto err_out;
-                       }
-                       size = min_t(int, to_read, PAGE_SIZE);
-                       memcpy((u8*)trp + have_read, page_address(page), size);
-                       ntfs_unmap_page(page);
-                       have_read += size;
-                       to_read -= size;
-                       idx++;
-               } while (to_read > 0);
-       }
-       /*
-        * Perform the multi sector transfer deprotection on the buffer if the
-        * restart page is protected.
-        */
-       if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count))
-                       && post_read_mst_fixup((NTFS_RECORD*)trp,
-                       le32_to_cpu(rp->system_page_size))) {
-               /*
-                * A multi sector tranfer error was detected.  We only need to
-                * abort if the restart page contents exceed the multi sector
-                * transfer fixup of the first sector.
-                */
-               if (le16_to_cpu(rp->restart_area_offset) +
-                               le16_to_cpu(ra->restart_area_length) >
-                               NTFS_BLOCK_SIZE - sizeof(u16)) {
-                       ntfs_error(vi->i_sb, "Multi sector transfer error "
-                                       "detected in $LogFile restart page.");
-                       err = -EINVAL;
-                       goto err_out;
-               }
-       }
-       /*
-        * If the restart page is modified by chkdsk or there are no active
-        * logfile clients, the logfile is consistent.  Otherwise, need to
-        * check the log client records for consistency, too.
-        */
-       err = 0;
-       if (ntfs_is_rstr_record(rp->magic) &&
-                       ra->client_in_use_list != LOGFILE_NO_CLIENT) {
-               if (!ntfs_check_log_client_array(vi, trp)) {
-                       err = -EINVAL;
-                       goto err_out;
-               }
-       }
-       if (lsn) {
-               if (ntfs_is_rstr_record(rp->magic))
-                       *lsn = sle64_to_cpu(ra->current_lsn);
-               else /* if (ntfs_is_chkd_record(rp->magic)) */
-                       *lsn = sle64_to_cpu(rp->chkdsk_lsn);
-       }
-       ntfs_debug("Done.");
-       if (wrp)
-               *wrp = trp;
-       else {
-err_out:
-               ntfs_free(trp);
-       }
-       return err;
-}
-
-/**
- * ntfs_check_logfile - check the journal for consistency
- * @log_vi:    struct inode of loaded journal $LogFile to check
- * @rp:                [OUT] on success this is a copy of the current restart page
- *
- * Check the $LogFile journal for consistency and return 'true' if it is
- * consistent and 'false' if not.  On success, the current restart page is
- * returned in *@rp.  Caller must call ntfs_free(*@rp) when finished with it.
- *
- * At present we only check the two restart pages and ignore the log record
- * pages.
- *
- * Note that the MstProtected flag is not set on the $LogFile inode and hence
- * when reading pages they are not deprotected.  This is because we do not know
- * if the $LogFile was created on a system with a different page size to ours
- * yet and mst deprotection would fail if our page size is smaller.
- */
-bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
-{
-       s64 size, pos;
-       LSN rstr1_lsn, rstr2_lsn;
-       ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
-       struct address_space *mapping = log_vi->i_mapping;
-       struct page *page = NULL;
-       u8 *kaddr = NULL;
-       RESTART_PAGE_HEADER *rstr1_ph = NULL;
-       RESTART_PAGE_HEADER *rstr2_ph = NULL;
-       int log_page_size, err;
-       bool logfile_is_empty = true;
-       u8 log_page_bits;
-
-       ntfs_debug("Entering.");
-       /* An empty $LogFile must have been clean before it got emptied. */
-       if (NVolLogFileEmpty(vol))
-               goto is_empty;
-       size = i_size_read(log_vi);
-       /* Make sure the file doesn't exceed the maximum allowed size. */
-       if (size > MaxLogFileSize)
-               size = MaxLogFileSize;
-       /*
-        * Truncate size to a multiple of the page cache size or the default
-        * log page size if the page cache size is between the default log page
-        * log page size if the page cache size is between the default log page
-        * size and twice that.
-        */
-       if (PAGE_SIZE >= DefaultLogPageSize && PAGE_SIZE <=
-                       DefaultLogPageSize * 2)
-               log_page_size = DefaultLogPageSize;
-       else
-               log_page_size = PAGE_SIZE;
-       /*
-        * Use ntfs_ffs() instead of ffs() to enable the compiler to
-        * optimize log_page_size and log_page_bits into constants.
-        */
-       log_page_bits = ntfs_ffs(log_page_size) - 1;
-       size &= ~(s64)(log_page_size - 1);
-       /*
-        * Ensure the log file is big enough to store at least the two restart
-        * pages and the minimum number of log record pages.
-        */
-       if (size < log_page_size * 2 || (size - log_page_size * 2) >>
-                       log_page_bits < MinLogRecordPages) {
-               ntfs_error(vol->sb, "$LogFile is too small.");
-               return false;
-       }
-       /*
-        * Read through the file looking for a restart page.  Since the restart
-        * page header is at the beginning of a page we only need to search at
-        * what could be the beginning of a page (for each page size) rather
-        * than scanning the whole file byte by byte.  If all potential places
-        * contain empty and uninitialzed records, the log file can be assumed
-        * to be empty.
-        */
-       for (pos = 0; pos < size; pos <<= 1) {
-               pgoff_t idx = pos >> PAGE_SHIFT;
-               if (!page || page->index != idx) {
-                       if (page)
-                               ntfs_unmap_page(page);
-                       page = ntfs_map_page(mapping, idx);
-                       if (IS_ERR(page)) {
-                               ntfs_error(vol->sb, "Error mapping $LogFile "
-                                               "page (index %lu).", idx);
-                               goto err_out;
-                       }
-               }
-               kaddr = (u8*)page_address(page) + (pos & ~PAGE_MASK);
-               /*
-                * A non-empty block means the logfile is not empty while an
-                * empty block after a non-empty block has been encountered
-                * means we are done.
-                */
-               if (!ntfs_is_empty_recordp((le32*)kaddr))
-                       logfile_is_empty = false;
-               else if (!logfile_is_empty)
-                       break;
-               /*
-                * A log record page means there cannot be a restart page after
-                * this so no need to continue searching.
-                */
-               if (ntfs_is_rcrd_recordp((le32*)kaddr))
-                       break;
-               /* If not a (modified by chkdsk) restart page, continue. */
-               if (!ntfs_is_rstr_recordp((le32*)kaddr) &&
-                               !ntfs_is_chkd_recordp((le32*)kaddr)) {
-                       if (!pos)
-                               pos = NTFS_BLOCK_SIZE >> 1;
-                       continue;
-               }
-               /*
-                * Check the (modified by chkdsk) restart page for consistency
-                * and get a copy of the complete multi sector transfer
-                * deprotected restart page.
-                */
-               err = ntfs_check_and_load_restart_page(log_vi,
-                               (RESTART_PAGE_HEADER*)kaddr, pos,
-                               !rstr1_ph ? &rstr1_ph : &rstr2_ph,
-                               !rstr1_ph ? &rstr1_lsn : &rstr2_lsn);
-               if (!err) {
-                       /*
-                        * If we have now found the first (modified by chkdsk)
-                        * restart page, continue looking for the second one.
-                        */
-                       if (!pos) {
-                               pos = NTFS_BLOCK_SIZE >> 1;
-                               continue;
-                       }
-                       /*
-                        * We have now found the second (modified by chkdsk)
-                        * restart page, so we can stop looking.
-                        */
-                       break;
-               }
-               /*
-                * Error output already done inside the function.  Note, we do
-                * not abort if the restart page was invalid as we might still
-                * find a valid one further in the file.
-                */
-               if (err != -EINVAL) {
-                       ntfs_unmap_page(page);
-                       goto err_out;
-               }
-               /* Continue looking. */
-               if (!pos)
-                       pos = NTFS_BLOCK_SIZE >> 1;
-       }
-       if (page)
-               ntfs_unmap_page(page);
-       if (logfile_is_empty) {
-               NVolSetLogFileEmpty(vol);
-is_empty:
-               ntfs_debug("Done.  ($LogFile is empty.)");
-               return true;
-       }
-       if (!rstr1_ph) {
-               BUG_ON(rstr2_ph);
-               ntfs_error(vol->sb, "Did not find any restart pages in "
-                               "$LogFile and it was not empty.");
-               return false;
-       }
-       /* If both restart pages were found, use the more recent one. */
-       if (rstr2_ph) {
-               /*
-                * If the second restart area is more recent, switch to it.
-                * Otherwise just throw it away.
-                */
-               if (rstr2_lsn > rstr1_lsn) {
-                       ntfs_debug("Using second restart page as it is more "
-                                       "recent.");
-                       ntfs_free(rstr1_ph);
-                       rstr1_ph = rstr2_ph;
-                       /* rstr1_lsn = rstr2_lsn; */
-               } else {
-                       ntfs_debug("Using first restart page as it is more "
-                                       "recent.");
-                       ntfs_free(rstr2_ph);
-               }
-               rstr2_ph = NULL;
-       }
-       /* All consistency checks passed. */
-       if (rp)
-               *rp = rstr1_ph;
-       else
-               ntfs_free(rstr1_ph);
-       ntfs_debug("Done.");
-       return true;
-err_out:
-       if (rstr1_ph)
-               ntfs_free(rstr1_ph);
-       return false;
-}
-
-/**
- * ntfs_is_logfile_clean - check in the journal if the volume is clean
- * @log_vi:    struct inode of loaded journal $LogFile to check
- * @rp:                copy of the current restart page
- *
- * Analyze the $LogFile journal and return 'true' if it indicates the volume was
- * shutdown cleanly and 'false' if not.
- *
- * At present we only look at the two restart pages and ignore the log record
- * pages.  This is a little bit crude in that there will be a very small number
- * of cases where we think that a volume is dirty when in fact it is clean.
- * This should only affect volumes that have not been shutdown cleanly but did
- * not have any pending, non-check-pointed i/o, i.e. they were completely idle
- * at least for the five seconds preceding the unclean shutdown.
- *
- * This function assumes that the $LogFile journal has already been consistency
- * checked by a call to ntfs_check_logfile() and in particular if the $LogFile
- * is empty this function requires that NVolLogFileEmpty() is true otherwise an
- * empty volume will be reported as dirty.
- */
-bool ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
-{
-       ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
-       RESTART_AREA *ra;
-
-       ntfs_debug("Entering.");
-       /* An empty $LogFile must have been clean before it got emptied. */
-       if (NVolLogFileEmpty(vol)) {
-               ntfs_debug("Done.  ($LogFile is empty.)");
-               return true;
-       }
-       BUG_ON(!rp);
-       if (!ntfs_is_rstr_record(rp->magic) &&
-                       !ntfs_is_chkd_record(rp->magic)) {
-               ntfs_error(vol->sb, "Restart page buffer is invalid.  This is "
-                               "probably a bug in that the $LogFile should "
-                               "have been consistency checked before calling "
-                               "this function.");
-               return false;
-       }
-       ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
-       /*
-        * If the $LogFile has active clients, i.e. it is open, and we do not
-        * have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags,
-        * we assume there was an unclean shutdown.
-        */
-       if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
-                       !(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
-               ntfs_debug("Done.  $LogFile indicates a dirty shutdown.");
-               return false;
-       }
-       /* $LogFile indicates a clean shutdown. */
-       ntfs_debug("Done.  $LogFile indicates a clean shutdown.");
-       return true;
-}
-
-/**
- * ntfs_empty_logfile - empty the contents of the $LogFile journal
- * @log_vi:    struct inode of loaded journal $LogFile to empty
- *
- * Empty the contents of the $LogFile journal @log_vi and return 'true' on
- * success and 'false' on error.
- *
- * This function assumes that the $LogFile journal has already been consistency
- * checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean()
- * has been used to ensure that the $LogFile is clean.
- */
-bool ntfs_empty_logfile(struct inode *log_vi)
-{
-       VCN vcn, end_vcn;
-       ntfs_inode *log_ni = NTFS_I(log_vi);
-       ntfs_volume *vol = log_ni->vol;
-       struct super_block *sb = vol->sb;
-       runlist_element *rl;
-       unsigned long flags;
-       unsigned block_size, block_size_bits;
-       int err;
-       bool should_wait = true;
-
-       ntfs_debug("Entering.");
-       if (NVolLogFileEmpty(vol)) {
-               ntfs_debug("Done.");
-               return true;
-       }
-       /*
-        * We cannot use ntfs_attr_set() because we may be still in the middle
-        * of a mount operation.  Thus we do the emptying by hand by first
-        * zapping the page cache pages for the $LogFile/$DATA attribute and
-        * then emptying each of the buffers in each of the clusters specified
-        * by the runlist by hand.
-        */
-       block_size = sb->s_blocksize;
-       block_size_bits = sb->s_blocksize_bits;
-       vcn = 0;
-       read_lock_irqsave(&log_ni->size_lock, flags);
-       end_vcn = (log_ni->initialized_size + vol->cluster_size_mask) >>
-                       vol->cluster_size_bits;
-       read_unlock_irqrestore(&log_ni->size_lock, flags);
-       truncate_inode_pages(log_vi->i_mapping, 0);
-       down_write(&log_ni->runlist.lock);
-       rl = log_ni->runlist.rl;
-       if (unlikely(!rl || vcn < rl->vcn || !rl->length)) {
-map_vcn:
-               err = ntfs_map_runlist_nolock(log_ni, vcn, NULL);
-               if (err) {
-                       ntfs_error(sb, "Failed to map runlist fragment (error "
-                                       "%d).", -err);
-                       goto err;
-               }
-               rl = log_ni->runlist.rl;
-               BUG_ON(!rl || vcn < rl->vcn || !rl->length);
-       }
-       /* Seek to the runlist element containing @vcn. */
-       while (rl->length && vcn >= rl[1].vcn)
-               rl++;
-       do {
-               LCN lcn;
-               sector_t block, end_block;
-               s64 len;
-
-               /*
-                * If this run is not mapped map it now and start again as the
-                * runlist will have been updated.
-                */
-               lcn = rl->lcn;
-               if (unlikely(lcn == LCN_RL_NOT_MAPPED)) {
-                       vcn = rl->vcn;
-                       goto map_vcn;
-               }
-               /* If this run is not valid abort with an error. */
-               if (unlikely(!rl->length || lcn < LCN_HOLE))
-                       goto rl_err;
-               /* Skip holes. */
-               if (lcn == LCN_HOLE)
-                       continue;
-               block = lcn << vol->cluster_size_bits >> block_size_bits;
-               len = rl->length;
-               if (rl[1].vcn > end_vcn)
-                       len = end_vcn - rl->vcn;
-               end_block = (lcn + len) << vol->cluster_size_bits >>
-                               block_size_bits;
-               /* Iterate over the blocks in the run and empty them. */
-               do {
-                       struct buffer_head *bh;
-
-                       /* Obtain the buffer, possibly not uptodate. */
-                       bh = sb_getblk(sb, block);
-                       BUG_ON(!bh);
-                       /* Setup buffer i/o submission. */
-                       lock_buffer(bh);
-                       bh->b_end_io = end_buffer_write_sync;
-                       get_bh(bh);
-                       /* Set the entire contents of the buffer to 0xff. */
-                       memset(bh->b_data, -1, block_size);
-                       if (!buffer_uptodate(bh))
-                               set_buffer_uptodate(bh);
-                       if (buffer_dirty(bh))
-                               clear_buffer_dirty(bh);
-                       /*
-                        * Submit the buffer and wait for i/o to complete but
-                        * only for the first buffer so we do not miss really
-                        * serious i/o errors.  Once the first buffer has
-                        * completed ignore errors afterwards as we can assume
-                        * that if one buffer worked all of them will work.
-                        */
-                       submit_bh(REQ_OP_WRITE, bh);
-                       if (should_wait) {
-                               should_wait = false;
-                               wait_on_buffer(bh);
-                               if (unlikely(!buffer_uptodate(bh)))
-                                       goto io_err;
-                       }
-                       brelse(bh);
-               } while (++block < end_block);
-       } while ((++rl)->vcn < end_vcn);
-       up_write(&log_ni->runlist.lock);
-       /*
-        * Zap the pages again just in case any got instantiated whilst we were
-        * emptying the blocks by hand.  FIXME: We may not have completed
-        * writing to all the buffer heads yet so this may happen too early.
-        * We really should use a kernel thread to do the emptying
-        * asynchronously and then we can also set the volume dirty and output
-        * an error message if emptying should fail.
-        */
-       truncate_inode_pages(log_vi->i_mapping, 0);
-       /* Set the flag so we do not have to do it again on remount. */
-       NVolSetLogFileEmpty(vol);
-       ntfs_debug("Done.");
-       return true;
-io_err:
-       ntfs_error(sb, "Failed to write buffer.  Unmount and run chkdsk.");
-       goto dirty_err;
-rl_err:
-       ntfs_error(sb, "Runlist is corrupt.  Unmount and run chkdsk.");
-dirty_err:
-       NVolSetErrors(vol);
-       err = -EIO;
-err:
-       up_write(&log_ni->runlist.lock);
-       ntfs_error(sb, "Failed to fill $LogFile with 0xff bytes (error %d).",
-                       -err);
-       return false;
-}
-
-#endif /* NTFS_RW */
diff --git a/fs/ntfs/logfile.h b/fs/ntfs/logfile.h
deleted file mode 100644 (file)
index 429d490..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * logfile.h - Defines for NTFS kernel journal ($LogFile) handling.  Part of
- *            the Linux-NTFS project.
- *
- * Copyright (c) 2000-2005 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_LOGFILE_H
-#define _LINUX_NTFS_LOGFILE_H
-
-#ifdef NTFS_RW
-
-#include <linux/fs.h>
-
-#include "types.h"
-#include "endian.h"
-#include "layout.h"
-
-/*
- * Journal ($LogFile) organization:
- *
- * Two restart areas present in the first two pages (restart pages, one restart
- * area in each page).  When the volume is dismounted they should be identical,
- * except for the update sequence array which usually has a different update
- * sequence number.
- *
- * These are followed by log records organized in pages headed by a log record
- * header going up to log file size.  Not all pages contain log records when a
- * volume is first formatted, but as the volume ages, all records will be used.
- * When the log file fills up, the records at the beginning are purged (by
- * modifying the oldest_lsn to a higher value presumably) and writing begins
- * at the beginning of the file.  Effectively, the log file is viewed as a
- * circular entity.
- *
- * NOTE: Windows NT, 2000, and XP all use log file version 1.1 but they accept
- * versions <= 1.x, including 0.-1.  (Yes, that is a minus one in there!)  We
- * probably only want to support 1.1 as this seems to be the current version
- * and we don't know how that differs from the older versions.  The only
- * exception is if the journal is clean as marked by the two restart pages
- * then it doesn't matter whether we are on an earlier version.  We can just
- * reinitialize the logfile and start again with version 1.1.
- */
-
-/* Some $LogFile related constants. */
-#define MaxLogFileSize         0x100000000ULL
-#define DefaultLogPageSize     4096
-#define MinLogRecordPages      48
-
-/*
- * Log file restart page header (begins the restart area).
- */
-typedef struct {
-/*Ofs*/
-/*  0  NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
-/*  0*/        NTFS_RECORD_TYPE magic; /* The magic is "RSTR". */
-/*  4*/        le16 usa_ofs;           /* See NTFS_RECORD definition in layout.h.
-                                  When creating, set this to be immediately
-                                  after this header structure (without any
-                                  alignment). */
-/*  6*/        le16 usa_count;         /* See NTFS_RECORD definition in layout.h. */
-
-/*  8*/        leLSN chkdsk_lsn;       /* The last log file sequence number found by
-                                  chkdsk.  Only used when the magic is changed
-                                  to "CHKD".  Otherwise this is zero. */
-/* 16*/        le32 system_page_size;  /* Byte size of system pages when the log file
-                                  was created, has to be >= 512 and a power of
-                                  2.  Use this to calculate the required size
-                                  of the usa (usa_count) and add it to usa_ofs.
-                                  Then verify that the result is less than the
-                                  value of the restart_area_offset. */
-/* 20*/        le32 log_page_size;     /* Byte size of log file pages, has to be >=
-                                  512 and a power of 2.  The default is 4096
-                                  and is used when the system page size is
-                                  between 4096 and 8192.  Otherwise this is
-                                  set to the system page size instead. */
-/* 24*/        le16 restart_area_offset;/* Byte offset from the start of this header to
-                                  the RESTART_AREA.  Value has to be aligned
-                                  to 8-byte boundary.  When creating, set this
-                                  to be after the usa. */
-/* 26*/        sle16 minor_ver;        /* Log file minor version.  Only check if major
-                                  version is 1. */
-/* 28*/        sle16 major_ver;        /* Log file major version.  We only support
-                                  version 1.1. */
-/* sizeof() = 30 (0x1e) bytes */
-} __attribute__ ((__packed__)) RESTART_PAGE_HEADER;
-
-/*
- * Constant for the log client indices meaning that there are no client records
- * in this particular client array.  Also inside the client records themselves,
- * this means that there are no client records preceding or following this one.
- */
-#define LOGFILE_NO_CLIENT      cpu_to_le16(0xffff)
-#define LOGFILE_NO_CLIENT_CPU  0xffff
-
-/*
- * These are the so far known RESTART_AREA_* flags (16-bit) which contain
- * information about the log file in which they are present.
- */
-enum {
-       RESTART_VOLUME_IS_CLEAN = cpu_to_le16(0x0002),
-       RESTART_SPACE_FILLER    = cpu_to_le16(0xffff), /* gcc: Force enum bit width to 16. */
-} __attribute__ ((__packed__));
-
-typedef le16 RESTART_AREA_FLAGS;
-
-/*
- * Log file restart area record.  The offset of this record is found by adding
- * the offset of the RESTART_PAGE_HEADER to the restart_area_offset value found
- * in it.  See notes at restart_area_offset above.
- */
-typedef struct {
-/*Ofs*/
-/*  0*/        leLSN current_lsn;      /* The current, i.e. last LSN inside the log
-                                  when the restart area was last written.
-                                  This happens often but what is the interval?
-                                  Is it just fixed time or is it every time a
-                                  check point is written or somethine else?
-                                  On create set to 0. */
-/*  8*/        le16 log_clients;       /* Number of log client records in the array of
-                                  log client records which follows this
-                                  restart area.  Must be 1.  */
-/* 10*/        le16 client_free_list;  /* The index of the first free log client record
-                                  in the array of log client records.
-                                  LOGFILE_NO_CLIENT means that there are no
-                                  free log client records in the array.
-                                  If != LOGFILE_NO_CLIENT, check that
-                                  log_clients > client_free_list.  On Win2k
-                                  and presumably earlier, on a clean volume
-                                  this is != LOGFILE_NO_CLIENT, and it should
-                                  be 0, i.e. the first (and only) client
-                                  record is free and thus the logfile is
-                                  closed and hence clean.  A dirty volume
-                                  would have left the logfile open and hence
-                                  this would be LOGFILE_NO_CLIENT.  On WinXP
-                                  and presumably later, the logfile is always
-                                  open, even on clean shutdown so this should
-                                  always be LOGFILE_NO_CLIENT. */
-/* 12*/        le16 client_in_use_list;/* The index of the first in-use log client
-                                  record in the array of log client records.
-                                  LOGFILE_NO_CLIENT means that there are no
-                                  in-use log client records in the array.  If
-                                  != LOGFILE_NO_CLIENT check that log_clients
-                                  > client_in_use_list.  On Win2k and
-                                  presumably earlier, on a clean volume this
-                                  is LOGFILE_NO_CLIENT, i.e. there are no
-                                  client records in use and thus the logfile
-                                  is closed and hence clean.  A dirty volume
-                                  would have left the logfile open and hence
-                                  this would be != LOGFILE_NO_CLIENT, and it
-                                  should be 0, i.e. the first (and only)
-                                  client record is in use.  On WinXP and
-                                  presumably later, the logfile is always
-                                  open, even on clean shutdown so this should
-                                  always be 0. */
-/* 14*/        RESTART_AREA_FLAGS flags;/* Flags modifying LFS behaviour.  On Win2k
-                                  and presumably earlier this is always 0.  On
-                                  WinXP and presumably later, if the logfile
-                                  was shutdown cleanly, the second bit,
-                                  RESTART_VOLUME_IS_CLEAN, is set.  This bit
-                                  is cleared when the volume is mounted by
-                                  WinXP and set when the volume is dismounted,
-                                  thus if the logfile is dirty, this bit is
-                                  clear.  Thus we don't need to check the
-                                  Windows version to determine if the logfile
-                                  is clean.  Instead if the logfile is closed,
-                                  we know it must be clean.  If it is open and
-                                  this bit is set, we also know it must be
-                                  clean.  If on the other hand the logfile is
-                                  open and this bit is clear, we can be almost
-                                  certain that the logfile is dirty. */
-/* 16*/        le32 seq_number_bits;   /* How many bits to use for the sequence
-                                  number.  This is calculated as 67 - the
-                                  number of bits required to store the logfile
-                                  size in bytes and this can be used in with
-                                  the specified file_size as a consistency
-                                  check. */
-/* 20*/        le16 restart_area_length;/* Length of the restart area including the
-                                  client array.  Following checks required if
-                                  version matches.  Otherwise, skip them.
-                                  restart_area_offset + restart_area_length
-                                  has to be <= system_page_size.  Also,
-                                  restart_area_length has to be >=
-                                  client_array_offset + (log_clients *
-                                  sizeof(log client record)). */
-/* 22*/        le16 client_array_offset;/* Offset from the start of this record to
-                                  the first log client record if versions are
-                                  matched.  When creating, set this to be
-                                  after this restart area structure, aligned
-                                  to 8-bytes boundary.  If the versions do not
-                                  match, this is ignored and the offset is
-                                  assumed to be (sizeof(RESTART_AREA) + 7) &
-                                  ~7, i.e. rounded up to first 8-byte
-                                  boundary.  Either way, client_array_offset
-                                  has to be aligned to an 8-byte boundary.
-                                  Also, restart_area_offset +
-                                  client_array_offset has to be <= 510.
-                                  Finally, client_array_offset + (log_clients
-                                  * sizeof(log client record)) has to be <=
-                                  system_page_size.  On Win2k and presumably
-                                  earlier, this is 0x30, i.e. immediately
-                                  following this record.  On WinXP and
-                                  presumably later, this is 0x40, i.e. there
-                                  are 16 extra bytes between this record and
-                                  the client array.  This probably means that
-                                  the RESTART_AREA record is actually bigger
-                                  in WinXP and later. */
-/* 24*/        sle64 file_size;        /* Usable byte size of the log file.  If the
-                                  restart_area_offset + the offset of the
-                                  file_size are > 510 then corruption has
-                                  occurred.  This is the very first check when
-                                  starting with the restart_area as if it
-                                  fails it means that some of the above values
-                                  will be corrupted by the multi sector
-                                  transfer protection.  The file_size has to
-                                  be rounded down to be a multiple of the
-                                  log_page_size in the RESTART_PAGE_HEADER and
-                                  then it has to be at least big enough to
-                                  store the two restart pages and 48 (0x30)
-                                  log record pages. */
-/* 32*/        le32 last_lsn_data_length;/* Length of data of last LSN, not including
-                                  the log record header.  On create set to
-                                  0. */
-/* 36*/        le16 log_record_header_length;/* Byte size of the log record header.
-                                  If the version matches then check that the
-                                  value of log_record_header_length is a
-                                  multiple of 8, i.e.
-                                  (log_record_header_length + 7) & ~7 ==
-                                  log_record_header_length.  When creating set
-                                  it to sizeof(LOG_RECORD_HEADER), aligned to
-                                  8 bytes. */
-/* 38*/        le16 log_page_data_offset;/* Offset to the start of data in a log record
-                                  page.  Must be a multiple of 8.  On create
-                                  set it to immediately after the update
-                                  sequence array of the log record page. */
-/* 40*/        le32 restart_log_open_count;/* A counter that gets incremented every
-                                  time the logfile is restarted which happens
-                                  at mount time when the logfile is opened.
-                                  When creating set to a random value.  Win2k
-                                  sets it to the low 32 bits of the current
-                                  system time in NTFS format (see time.h). */
-/* 44*/        le32 reserved;          /* Reserved/alignment to 8-byte boundary. */
-/* sizeof() = 48 (0x30) bytes */
-} __attribute__ ((__packed__)) RESTART_AREA;
-
-/*
- * Log client record.  The offset of this record is found by adding the offset
- * of the RESTART_AREA to the client_array_offset value found in it.
- */
-typedef struct {
-/*Ofs*/
-/*  0*/        leLSN oldest_lsn;       /* Oldest LSN needed by this client.  On create
-                                  set to 0. */
-/*  8*/        leLSN client_restart_lsn;/* LSN at which this client needs to restart
-                                  the volume, i.e. the current position within
-                                  the log file.  At present, if clean this
-                                  should = current_lsn in restart area but it
-                                  probably also = current_lsn when dirty most
-                                  of the time.  At create set to 0. */
-/* 16*/        le16 prev_client;       /* The offset to the previous log client record
-                                  in the array of log client records.
-                                  LOGFILE_NO_CLIENT means there is no previous
-                                  client record, i.e. this is the first one.
-                                  This is always LOGFILE_NO_CLIENT. */
-/* 18*/        le16 next_client;       /* The offset to the next log client record in
-                                  the array of log client records.
-                                  LOGFILE_NO_CLIENT means there are no next
-                                  client records, i.e. this is the last one.
-                                  This is always LOGFILE_NO_CLIENT. */
-/* 20*/        le16 seq_number;        /* On Win2k and presumably earlier, this is set
-                                  to zero every time the logfile is restarted
-                                  and it is incremented when the logfile is
-                                  closed at dismount time.  Thus it is 0 when
-                                  dirty and 1 when clean.  On WinXP and
-                                  presumably later, this is always 0. */
-/* 22*/        u8 reserved[6];         /* Reserved/alignment. */
-/* 28*/        le32 client_name_length;/* Length of client name in bytes.  Should
-                                  always be 8. */
-/* 32*/        ntfschar client_name[64];/* Name of the client in Unicode.  Should
-                                  always be "NTFS" with the remaining bytes
-                                  set to 0. */
-/* sizeof() = 160 (0xa0) bytes */
-} __attribute__ ((__packed__)) LOG_CLIENT_RECORD;
-
-extern bool ntfs_check_logfile(struct inode *log_vi,
-               RESTART_PAGE_HEADER **rp);
-
-extern bool ntfs_is_logfile_clean(struct inode *log_vi,
-               const RESTART_PAGE_HEADER *rp);
-
-extern bool ntfs_empty_logfile(struct inode *log_vi);
-
-#endif /* NTFS_RW */
-
-#endif /* _LINUX_NTFS_LOGFILE_H */
diff --git a/fs/ntfs/malloc.h b/fs/ntfs/malloc.h
deleted file mode 100644 (file)
index 7068425..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * malloc.h - NTFS kernel memory handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2005 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_MALLOC_H
-#define _LINUX_NTFS_MALLOC_H
-
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/highmem.h>
-
-/**
- * __ntfs_malloc - allocate memory in multiples of pages
- * @size:      number of bytes to allocate
- * @gfp_mask:  extra flags for the allocator
- *
- * Internal function.  You probably want ntfs_malloc_nofs()...
- *
- * Allocates @size bytes of memory, rounded up to multiples of PAGE_SIZE and
- * returns a pointer to the allocated memory.
- *
- * If there was insufficient memory to complete the request, return NULL.
- * Depending on @gfp_mask the allocation may be guaranteed to succeed.
- */
-static inline void *__ntfs_malloc(unsigned long size, gfp_t gfp_mask)
-{
-       if (likely(size <= PAGE_SIZE)) {
-               BUG_ON(!size);
-               /* kmalloc() has per-CPU caches so is faster for now. */
-               return kmalloc(PAGE_SIZE, gfp_mask & ~__GFP_HIGHMEM);
-               /* return (void *)__get_free_page(gfp_mask); */
-       }
-       if (likely((size >> PAGE_SHIFT) < totalram_pages()))
-               return __vmalloc(size, gfp_mask);
-       return NULL;
-}
-
-/**
- * ntfs_malloc_nofs - allocate memory in multiples of pages
- * @size:      number of bytes to allocate
- *
- * Allocates @size bytes of memory, rounded up to multiples of PAGE_SIZE and
- * returns a pointer to the allocated memory.
- *
- * If there was insufficient memory to complete the request, return NULL.
- */
-static inline void *ntfs_malloc_nofs(unsigned long size)
-{
-       return __ntfs_malloc(size, GFP_NOFS | __GFP_HIGHMEM);
-}
-
-/**
- * ntfs_malloc_nofs_nofail - allocate memory in multiples of pages
- * @size:      number of bytes to allocate
- *
- * Allocates @size bytes of memory, rounded up to multiples of PAGE_SIZE and
- * returns a pointer to the allocated memory.
- *
- * This function guarantees that the allocation will succeed.  It will sleep
- * for as long as it takes to complete the allocation.
- *
- * If there was insufficient memory to complete the request, return NULL.
- */
-static inline void *ntfs_malloc_nofs_nofail(unsigned long size)
-{
-       return __ntfs_malloc(size, GFP_NOFS | __GFP_HIGHMEM | __GFP_NOFAIL);
-}
-
-static inline void ntfs_free(void *addr)
-{
-       kvfree(addr);
-}
-
-#endif /* _LINUX_NTFS_MALLOC_H */
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
deleted file mode 100644 (file)
index 6fd1dc4..0000000
+++ /dev/null
@@ -1,2907 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2012 Anton Altaparmakov and Tuxera Inc.
- * Copyright (c) 2002 Richard Russon
- */
-
-#include <linux/buffer_head.h>
-#include <linux/slab.h>
-#include <linux/swap.h>
-#include <linux/bio.h>
-
-#include "attrib.h"
-#include "aops.h"
-#include "bitmap.h"
-#include "debug.h"
-#include "dir.h"
-#include "lcnalloc.h"
-#include "malloc.h"
-#include "mft.h"
-#include "ntfs.h"
-
-#define MAX_BHS        (PAGE_SIZE / NTFS_BLOCK_SIZE)
-
-/**
- * map_mft_record_page - map the page in which a specific mft record resides
- * @ni:                ntfs inode whose mft record page to map
- *
- * This maps the page in which the mft record of the ntfs inode @ni is situated
- * and returns a pointer to the mft record within the mapped page.
- *
- * Return value needs to be checked with IS_ERR() and if that is true PTR_ERR()
- * contains the negative error code returned.
- */
-static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
-{
-       loff_t i_size;
-       ntfs_volume *vol = ni->vol;
-       struct inode *mft_vi = vol->mft_ino;
-       struct page *page;
-       unsigned long index, end_index;
-       unsigned ofs;
-
-       BUG_ON(ni->page);
-       /*
-        * The index into the page cache and the offset within the page cache
-        * page of the wanted mft record. FIXME: We need to check for
-        * overflowing the unsigned long, but I don't think we would ever get
-        * here if the volume was that big...
-        */
-       index = (u64)ni->mft_no << vol->mft_record_size_bits >>
-                       PAGE_SHIFT;
-       ofs = (ni->mft_no << vol->mft_record_size_bits) & ~PAGE_MASK;
-
-       i_size = i_size_read(mft_vi);
-       /* The maximum valid index into the page cache for $MFT's data. */
-       end_index = i_size >> PAGE_SHIFT;
-
-       /* If the wanted index is out of bounds the mft record doesn't exist. */
-       if (unlikely(index >= end_index)) {
-               if (index > end_index || (i_size & ~PAGE_MASK) < ofs +
-                               vol->mft_record_size) {
-                       page = ERR_PTR(-ENOENT);
-                       ntfs_error(vol->sb, "Attempt to read mft record 0x%lx, "
-                                       "which is beyond the end of the mft.  "
-                                       "This is probably a bug in the ntfs "
-                                       "driver.", ni->mft_no);
-                       goto err_out;
-               }
-       }
-       /* Read, map, and pin the page. */
-       page = ntfs_map_page(mft_vi->i_mapping, index);
-       if (!IS_ERR(page)) {
-               /* Catch multi sector transfer fixup errors. */
-               if (likely(ntfs_is_mft_recordp((le32*)(page_address(page) +
-                               ofs)))) {
-                       ni->page = page;
-                       ni->page_ofs = ofs;
-                       return page_address(page) + ofs;
-               }
-               ntfs_error(vol->sb, "Mft record 0x%lx is corrupt.  "
-                               "Run chkdsk.", ni->mft_no);
-               ntfs_unmap_page(page);
-               page = ERR_PTR(-EIO);
-               NVolSetErrors(vol);
-       }
-err_out:
-       ni->page = NULL;
-       ni->page_ofs = 0;
-       return (void*)page;
-}
-
-/**
- * map_mft_record - map, pin and lock an mft record
- * @ni:                ntfs inode whose MFT record to map
- *
- * First, take the mrec_lock mutex.  We might now be sleeping, while waiting
- * for the mutex if it was already locked by someone else.
- *
- * The page of the record is mapped using map_mft_record_page() before being
- * returned to the caller.
- *
- * This in turn uses ntfs_map_page() to get the page containing the wanted mft
- * record (it in turn calls read_cache_page() which reads it in from disk if
- * necessary, increments the use count on the page so that it cannot disappear
- * under us and returns a reference to the page cache page).
- *
- * If read_cache_page() invokes ntfs_readpage() to load the page from disk, it
- * sets PG_locked and clears PG_uptodate on the page. Once I/O has completed
- * and the post-read mst fixups on each mft record in the page have been
- * performed, the page gets PG_uptodate set and PG_locked cleared (this is done
- * in our asynchronous I/O completion handler end_buffer_read_mft_async()).
- * ntfs_map_page() waits for PG_locked to become clear and checks if
- * PG_uptodate is set and returns an error code if not. This provides
- * sufficient protection against races when reading/using the page.
- *
- * However there is the write mapping to think about. Doing the above described
- * checking here will be fine, because when initiating the write we will set
- * PG_locked and clear PG_uptodate making sure nobody is touching the page
- * contents. Doing the locking this way means that the commit to disk code in
- * the page cache code paths is automatically sufficiently locked with us as
- * we will not touch a page that has been locked or is not uptodate. The only
- * locking problem then is them locking the page while we are accessing it.
- *
- * So that code will end up having to own the mrec_lock of all mft
- * records/inodes present in the page before I/O can proceed. In that case we
- * wouldn't need to bother with PG_locked and PG_uptodate as nobody will be
- * accessing anything without owning the mrec_lock mutex.  But we do need to
- * use them because of the read_cache_page() invocation and the code becomes so
- * much simpler this way that it is well worth it.
- *
- * The mft record is now ours and we return a pointer to it. You need to check
- * the returned pointer with IS_ERR() and if that is true, PTR_ERR() will return
- * the error code.
- *
- * NOTE: Caller is responsible for setting the mft record dirty before calling
- * unmap_mft_record(). This is obviously only necessary if the caller really
- * modified the mft record...
- * Q: Do we want to recycle one of the VFS inode state bits instead?
- * A: No, the inode ones mean we want to change the mft record, not we want to
- * write it out.
- */
-MFT_RECORD *map_mft_record(ntfs_inode *ni)
-{
-       MFT_RECORD *m;
-
-       ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);
-
-       /* Make sure the ntfs inode doesn't go away. */
-       atomic_inc(&ni->count);
-
-       /* Serialize access to this mft record. */
-       mutex_lock(&ni->mrec_lock);
-
-       m = map_mft_record_page(ni);
-       if (!IS_ERR(m))
-               return m;
-
-       mutex_unlock(&ni->mrec_lock);
-       atomic_dec(&ni->count);
-       ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
-       return m;
-}
-
-/**
- * unmap_mft_record_page - unmap the page in which a specific mft record resides
- * @ni:                ntfs inode whose mft record page to unmap
- *
- * This unmaps the page in which the mft record of the ntfs inode @ni is
- * situated and returns. This is a NOOP if highmem is not configured.
- *
- * The unmap happens via ntfs_unmap_page() which in turn decrements the use
- * count on the page thus releasing it from the pinned state.
- *
- * We do not actually unmap the page from memory of course, as that will be
- * done by the page cache code itself when memory pressure increases or
- * whatever.
- */
-static inline void unmap_mft_record_page(ntfs_inode *ni)
-{
-       BUG_ON(!ni->page);
-
-       // TODO: If dirty, blah...
-       ntfs_unmap_page(ni->page);
-       ni->page = NULL;
-       ni->page_ofs = 0;
-       return;
-}
-
-/**
- * unmap_mft_record - release a mapped mft record
- * @ni:                ntfs inode whose MFT record to unmap
- *
- * We release the page mapping and the mrec_lock mutex which unmaps the mft
- * record and releases it for others to get hold of. We also release the ntfs
- * inode by decrementing the ntfs inode reference count.
- *
- * NOTE: If caller has modified the mft record, it is imperative to set the mft
- * record dirty BEFORE calling unmap_mft_record().
- */
-void unmap_mft_record(ntfs_inode *ni)
-{
-       struct page *page = ni->page;
-
-       BUG_ON(!page);
-
-       ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);
-
-       unmap_mft_record_page(ni);
-       mutex_unlock(&ni->mrec_lock);
-       atomic_dec(&ni->count);
-       /*
-        * If pure ntfs_inode, i.e. no vfs inode attached, we leave it to
-        * ntfs_clear_extent_inode() in the extent inode case, and to the
-        * caller in the non-extent, yet pure ntfs inode case, to do the actual
-        * tear down of all structures and freeing of all allocated memory.
-        */
-       return;
-}
-
-/**
- * map_extent_mft_record - load an extent inode and attach it to its base
- * @base_ni:   base ntfs inode
- * @mref:      mft reference of the extent inode to load
- * @ntfs_ino:  on successful return, pointer to the ntfs_inode structure
- *
- * Load the extent mft record @mref and attach it to its base inode @base_ni.
- * Return the mapped extent mft record if IS_ERR(result) is false.  Otherwise
- * PTR_ERR(result) gives the negative error code.
- *
- * On successful return, @ntfs_ino contains a pointer to the ntfs_inode
- * structure of the mapped extent inode.
- */
-MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
-               ntfs_inode **ntfs_ino)
-{
-       MFT_RECORD *m;
-       ntfs_inode *ni = NULL;
-       ntfs_inode **extent_nis = NULL;
-       int i;
-       unsigned long mft_no = MREF(mref);
-       u16 seq_no = MSEQNO(mref);
-       bool destroy_ni = false;
-
-       ntfs_debug("Mapping extent mft record 0x%lx (base mft record 0x%lx).",
-                       mft_no, base_ni->mft_no);
-       /* Make sure the base ntfs inode doesn't go away. */
-       atomic_inc(&base_ni->count);
-       /*
-        * Check if this extent inode has already been added to the base inode,
-        * in which case just return it. If not found, add it to the base
-        * inode before returning it.
-        */
-       mutex_lock(&base_ni->extent_lock);
-       if (base_ni->nr_extents > 0) {
-               extent_nis = base_ni->ext.extent_ntfs_inos;
-               for (i = 0; i < base_ni->nr_extents; i++) {
-                       if (mft_no != extent_nis[i]->mft_no)
-                               continue;
-                       ni = extent_nis[i];
-                       /* Make sure the ntfs inode doesn't go away. */
-                       atomic_inc(&ni->count);
-                       break;
-               }
-       }
-       if (likely(ni != NULL)) {
-               mutex_unlock(&base_ni->extent_lock);
-               atomic_dec(&base_ni->count);
-               /* We found the record; just have to map and return it. */
-               m = map_mft_record(ni);
-               /* map_mft_record() has incremented this on success. */
-               atomic_dec(&ni->count);
-               if (!IS_ERR(m)) {
-                       /* Verify the sequence number. */
-                       if (likely(le16_to_cpu(m->sequence_number) == seq_no)) {
-                               ntfs_debug("Done 1.");
-                               *ntfs_ino = ni;
-                               return m;
-                       }
-                       unmap_mft_record(ni);
-                       ntfs_error(base_ni->vol->sb, "Found stale extent mft "
-                                       "reference! Corrupt filesystem. "
-                                       "Run chkdsk.");
-                       return ERR_PTR(-EIO);
-               }
-map_err_out:
-               ntfs_error(base_ni->vol->sb, "Failed to map extent "
-                               "mft record, error code %ld.", -PTR_ERR(m));
-               return m;
-       }
-       /* Record wasn't there. Get a new ntfs inode and initialize it. */
-       ni = ntfs_new_extent_inode(base_ni->vol->sb, mft_no);
-       if (unlikely(!ni)) {
-               mutex_unlock(&base_ni->extent_lock);
-               atomic_dec(&base_ni->count);
-               return ERR_PTR(-ENOMEM);
-       }
-       ni->vol = base_ni->vol;
-       ni->seq_no = seq_no;
-       ni->nr_extents = -1;
-       ni->ext.base_ntfs_ino = base_ni;
-       /* Now map the record. */
-       m = map_mft_record(ni);
-       if (IS_ERR(m)) {
-               mutex_unlock(&base_ni->extent_lock);
-               atomic_dec(&base_ni->count);
-               ntfs_clear_extent_inode(ni);
-               goto map_err_out;
-       }
-       /* Verify the sequence number if it is present. */
-       if (seq_no && (le16_to_cpu(m->sequence_number) != seq_no)) {
-               ntfs_error(base_ni->vol->sb, "Found stale extent mft "
-                               "reference! Corrupt filesystem. Run chkdsk.");
-               destroy_ni = true;
-               m = ERR_PTR(-EIO);
-               goto unm_err_out;
-       }
-       /* Attach extent inode to base inode, reallocating memory if needed. */
-       if (!(base_ni->nr_extents & 3)) {
-               ntfs_inode **tmp;
-               int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *);
-
-               tmp = kmalloc(new_size, GFP_NOFS);
-               if (unlikely(!tmp)) {
-                       ntfs_error(base_ni->vol->sb, "Failed to allocate "
-                                       "internal buffer.");
-                       destroy_ni = true;
-                       m = ERR_PTR(-ENOMEM);
-                       goto unm_err_out;
-               }
-               if (base_ni->nr_extents) {
-                       BUG_ON(!base_ni->ext.extent_ntfs_inos);
-                       memcpy(tmp, base_ni->ext.extent_ntfs_inos, new_size -
-                                       4 * sizeof(ntfs_inode *));
-                       kfree(base_ni->ext.extent_ntfs_inos);
-               }
-               base_ni->ext.extent_ntfs_inos = tmp;
-       }
-       base_ni->ext.extent_ntfs_inos[base_ni->nr_extents++] = ni;
-       mutex_unlock(&base_ni->extent_lock);
-       atomic_dec(&base_ni->count);
-       ntfs_debug("Done 2.");
-       *ntfs_ino = ni;
-       return m;
-unm_err_out:
-       unmap_mft_record(ni);
-       mutex_unlock(&base_ni->extent_lock);
-       atomic_dec(&base_ni->count);
-       /*
-        * If the extent inode was not attached to the base inode we need to
-        * release it or we will leak memory.
-        */
-       if (destroy_ni)
-               ntfs_clear_extent_inode(ni);
-       return m;
-}
-
-#ifdef NTFS_RW
-
-/**
- * __mark_mft_record_dirty - set the mft record and the page containing it dirty
- * @ni:                ntfs inode describing the mapped mft record
- *
- * Internal function.  Users should call mark_mft_record_dirty() instead.
- *
- * Set the mapped (extent) mft record of the (base or extent) ntfs inode @ni,
- * as well as the page containing the mft record, dirty.  Also, mark the base
- * vfs inode dirty.  This ensures that any changes to the mft record are
- * written out to disk.
- *
- * NOTE:  We only set I_DIRTY_DATASYNC (and not I_DIRTY_PAGES)
- * on the base vfs inode, because even though file data may have been modified,
- * it is dirty in the inode meta data rather than the data page cache of the
- * inode, and thus there are no data pages that need writing out.  Therefore, a
- * full mark_inode_dirty() is overkill.  A mark_inode_dirty_sync(), on the
- * other hand, is not sufficient, because ->write_inode needs to be called even
- * in case of fdatasync. This needs to happen or the file data would not
- * necessarily hit the device synchronously, even though the vfs inode has the
- * O_SYNC flag set.  Also, I_DIRTY_DATASYNC simply "feels" better than just
- * I_DIRTY_SYNC, since the file data has not actually hit the block device yet,
- * which is not what I_DIRTY_SYNC on its own would suggest.
- */
-void __mark_mft_record_dirty(ntfs_inode *ni)
-{
-       ntfs_inode *base_ni;
-
-       ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
-       BUG_ON(NInoAttr(ni));
-       mark_ntfs_record_dirty(ni->page, ni->page_ofs);
-       /* Determine the base vfs inode and mark it dirty, too. */
-       mutex_lock(&ni->extent_lock);
-       if (likely(ni->nr_extents >= 0))
-               base_ni = ni;
-       else
-               base_ni = ni->ext.base_ntfs_ino;
-       mutex_unlock(&ni->extent_lock);
-       __mark_inode_dirty(VFS_I(base_ni), I_DIRTY_DATASYNC);
-}
-
-static const char *ntfs_please_email = "Please email "
-               "linux-ntfs-dev@lists.sourceforge.net and say that you saw "
-               "this message.  Thank you.";
-
-/**
- * ntfs_sync_mft_mirror_umount - synchronise an mft record to the mft mirror
- * @vol:       ntfs volume on which the mft record to synchronize resides
- * @mft_no:    mft record number of mft record to synchronize
- * @m:         mapped, mst protected (extent) mft record to synchronize
- *
- * Write the mapped, mst protected (extent) mft record @m with mft record
- * number @mft_no to the mft mirror ($MFTMirr) of the ntfs volume @vol,
- * bypassing the page cache and the $MFTMirr inode itself.
- *
- * This function is only for use at umount time when the mft mirror inode has
- * already been disposed off.  We BUG() if we are called while the mft mirror
- * inode is still attached to the volume.
- *
- * On success return 0.  On error return -errno.
- *
- * NOTE:  This function is not implemented yet as I am not convinced it can
- * actually be triggered considering the sequence of commits we do in super.c::
- * ntfs_put_super().  But just in case we provide this place holder as the
- * alternative would be either to BUG() or to get a NULL pointer dereference
- * and Oops.
- */
-static int ntfs_sync_mft_mirror_umount(ntfs_volume *vol,
-               const unsigned long mft_no, MFT_RECORD *m)
-{
-       BUG_ON(vol->mftmirr_ino);
-       ntfs_error(vol->sb, "Umount time mft mirror syncing is not "
-                       "implemented yet.  %s", ntfs_please_email);
-       return -EOPNOTSUPP;
-}
-
-/**
- * ntfs_sync_mft_mirror - synchronize an mft record to the mft mirror
- * @vol:       ntfs volume on which the mft record to synchronize resides
- * @mft_no:    mft record number of mft record to synchronize
- * @m:         mapped, mst protected (extent) mft record to synchronize
- * @sync:      if true, wait for i/o completion
- *
- * Write the mapped, mst protected (extent) mft record @m with mft record
- * number @mft_no to the mft mirror ($MFTMirr) of the ntfs volume @vol.
- *
- * On success return 0.  On error return -errno and set the volume errors flag
- * in the ntfs volume @vol.
- *
- * NOTE:  We always perform synchronous i/o and ignore the @sync parameter.
- *
- * TODO:  If @sync is false, want to do truly asynchronous i/o, i.e. just
- * schedule i/o via ->writepage or do it via kntfsd or whatever.
- */
-int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no,
-               MFT_RECORD *m, int sync)
-{
-       struct page *page;
-       unsigned int blocksize = vol->sb->s_blocksize;
-       int max_bhs = vol->mft_record_size / blocksize;
-       struct buffer_head *bhs[MAX_BHS];
-       struct buffer_head *bh, *head;
-       u8 *kmirr;
-       runlist_element *rl;
-       unsigned int block_start, block_end, m_start, m_end, page_ofs;
-       int i_bhs, nr_bhs, err = 0;
-       unsigned char blocksize_bits = vol->sb->s_blocksize_bits;
-
-       ntfs_debug("Entering for inode 0x%lx.", mft_no);
-       BUG_ON(!max_bhs);
-       if (WARN_ON(max_bhs > MAX_BHS))
-               return -EINVAL;
-       if (unlikely(!vol->mftmirr_ino)) {
-               /* This could happen during umount... */
-               err = ntfs_sync_mft_mirror_umount(vol, mft_no, m);
-               if (likely(!err))
-                       return err;
-               goto err_out;
-       }
-       /* Get the page containing the mirror copy of the mft record @m. */
-       page = ntfs_map_page(vol->mftmirr_ino->i_mapping, mft_no >>
-                       (PAGE_SHIFT - vol->mft_record_size_bits));
-       if (IS_ERR(page)) {
-               ntfs_error(vol->sb, "Failed to map mft mirror page.");
-               err = PTR_ERR(page);
-               goto err_out;
-       }
-       lock_page(page);
-       BUG_ON(!PageUptodate(page));
-       ClearPageUptodate(page);
-       /* Offset of the mft mirror record inside the page. */
-       page_ofs = (mft_no << vol->mft_record_size_bits) & ~PAGE_MASK;
-       /* The address in the page of the mirror copy of the mft record @m. */
-       kmirr = page_address(page) + page_ofs;
-       /* Copy the mst protected mft record to the mirror. */
-       memcpy(kmirr, m, vol->mft_record_size);
-       /* Create uptodate buffers if not present. */
-       if (unlikely(!page_has_buffers(page))) {
-               struct buffer_head *tail;
-
-               bh = head = alloc_page_buffers(page, blocksize, true);
-               do {
-                       set_buffer_uptodate(bh);
-                       tail = bh;
-                       bh = bh->b_this_page;
-               } while (bh);
-               tail->b_this_page = head;
-               attach_page_private(page, head);
-       }
-       bh = head = page_buffers(page);
-       BUG_ON(!bh);
-       rl = NULL;
-       nr_bhs = 0;
-       block_start = 0;
-       m_start = kmirr - (u8*)page_address(page);
-       m_end = m_start + vol->mft_record_size;
-       do {
-               block_end = block_start + blocksize;
-               /* If the buffer is outside the mft record, skip it. */
-               if (block_end <= m_start)
-                       continue;
-               if (unlikely(block_start >= m_end))
-                       break;
-               /* Need to map the buffer if it is not mapped already. */
-               if (unlikely(!buffer_mapped(bh))) {
-                       VCN vcn;
-                       LCN lcn;
-                       unsigned int vcn_ofs;
-
-                       bh->b_bdev = vol->sb->s_bdev;
-                       /* Obtain the vcn and offset of the current block. */
-                       vcn = ((VCN)mft_no << vol->mft_record_size_bits) +
-                                       (block_start - m_start);
-                       vcn_ofs = vcn & vol->cluster_size_mask;
-                       vcn >>= vol->cluster_size_bits;
-                       if (!rl) {
-                               down_read(&NTFS_I(vol->mftmirr_ino)->
-                                               runlist.lock);
-                               rl = NTFS_I(vol->mftmirr_ino)->runlist.rl;
-                               /*
-                                * $MFTMirr always has the whole of its runlist
-                                * in memory.
-                                */
-                               BUG_ON(!rl);
-                       }
-                       /* Seek to element containing target vcn. */
-                       while (rl->length && rl[1].vcn <= vcn)
-                               rl++;
-                       lcn = ntfs_rl_vcn_to_lcn(rl, vcn);
-                       /* For $MFTMirr, only lcn >= 0 is a successful remap. */
-                       if (likely(lcn >= 0)) {
-                               /* Setup buffer head to correct block. */
-                               bh->b_blocknr = ((lcn <<
-                                               vol->cluster_size_bits) +
-                                               vcn_ofs) >> blocksize_bits;
-                               set_buffer_mapped(bh);
-                       } else {
-                               bh->b_blocknr = -1;
-                               ntfs_error(vol->sb, "Cannot write mft mirror "
-                                               "record 0x%lx because its "
-                                               "location on disk could not "
-                                               "be determined (error code "
-                                               "%lli).", mft_no,
-                                               (long long)lcn);
-                               err = -EIO;
-                       }
-               }
-               BUG_ON(!buffer_uptodate(bh));
-               BUG_ON(!nr_bhs && (m_start != block_start));
-               BUG_ON(nr_bhs >= max_bhs);
-               bhs[nr_bhs++] = bh;
-               BUG_ON((nr_bhs >= max_bhs) && (m_end != block_end));
-       } while (block_start = block_end, (bh = bh->b_this_page) != head);
-       if (unlikely(rl))
-               up_read(&NTFS_I(vol->mftmirr_ino)->runlist.lock);
-       if (likely(!err)) {
-               /* Lock buffers and start synchronous write i/o on them. */
-               for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) {
-                       struct buffer_head *tbh = bhs[i_bhs];
-
-                       if (!trylock_buffer(tbh))
-                               BUG();
-                       BUG_ON(!buffer_uptodate(tbh));
-                       clear_buffer_dirty(tbh);
-                       get_bh(tbh);
-                       tbh->b_end_io = end_buffer_write_sync;
-                       submit_bh(REQ_OP_WRITE, tbh);
-               }
-               /* Wait on i/o completion of buffers. */
-               for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) {
-                       struct buffer_head *tbh = bhs[i_bhs];
-
-                       wait_on_buffer(tbh);
-                       if (unlikely(!buffer_uptodate(tbh))) {
-                               err = -EIO;
-                               /*
-                                * Set the buffer uptodate so the page and
-                                * buffer states do not become out of sync.
-                                */
-                               set_buffer_uptodate(tbh);
-                       }
-               }
-       } else /* if (unlikely(err)) */ {
-               /* Clean the buffers. */
-               for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++)
-                       clear_buffer_dirty(bhs[i_bhs]);
-       }
-       /* Current state: all buffers are clean, unlocked, and uptodate. */
-       /* Remove the mst protection fixups again. */
-       post_write_mst_fixup((NTFS_RECORD*)kmirr);
-       flush_dcache_page(page);
-       SetPageUptodate(page);
-       unlock_page(page);
-       ntfs_unmap_page(page);
-       if (likely(!err)) {
-               ntfs_debug("Done.");
-       } else {
-               ntfs_error(vol->sb, "I/O error while writing mft mirror "
-                               "record 0x%lx!", mft_no);
-err_out:
-               ntfs_error(vol->sb, "Failed to synchronize $MFTMirr (error "
-                               "code %i).  Volume will be left marked dirty "
-                               "on umount.  Run ntfsfix on the partition "
-                               "after umounting to correct this.", -err);
-               NVolSetErrors(vol);
-       }
-       return err;
-}
-
-/**
- * write_mft_record_nolock - write out a mapped (extent) mft record
- * @ni:                ntfs inode describing the mapped (extent) mft record
- * @m:         mapped (extent) mft record to write
- * @sync:      if true, wait for i/o completion
- *
- * Write the mapped (extent) mft record @m described by the (regular or extent)
- * ntfs inode @ni to backing store.  If the mft record @m has a counterpart in
- * the mft mirror, that is also updated.
- *
- * We only write the mft record if the ntfs inode @ni is dirty and the first
- * buffer belonging to its mft record is dirty, too.  We ignore the dirty state
- * of subsequent buffers because we could have raced with
- * fs/ntfs/aops.c::mark_ntfs_record_dirty().
- *
- * On success, clean the mft record and return 0.  On error, leave the mft
- * record dirty and return -errno.
- *
- * NOTE:  We always perform synchronous i/o and ignore the @sync parameter.
- * However, if the mft record has a counterpart in the mft mirror and @sync is
- * true, we write the mft record, wait for i/o completion, and only then write
- * the mft mirror copy.  This ensures that if the system crashes either the mft
- * or the mft mirror will contain a self-consistent mft record @m.  If @sync is
- * false on the other hand, we start i/o on both and then wait for completion
- * on them.  This provides a speedup but no longer guarantees that you will end
- * up with a self-consistent mft record in the case of a crash but if you asked
- * for asynchronous writing you probably do not care about that anyway.
- *
- * TODO:  If @sync is false, want to do truly asynchronous i/o, i.e. just
- * schedule i/o via ->writepage or do it via kntfsd or whatever.
- */
-int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync)
-{
-       ntfs_volume *vol = ni->vol;
-       struct page *page = ni->page;
-       unsigned int blocksize = vol->sb->s_blocksize;
-       unsigned char blocksize_bits = vol->sb->s_blocksize_bits;
-       int max_bhs = vol->mft_record_size / blocksize;
-       struct buffer_head *bhs[MAX_BHS];
-       struct buffer_head *bh, *head;
-       runlist_element *rl;
-       unsigned int block_start, block_end, m_start, m_end;
-       int i_bhs, nr_bhs, err = 0;
-
-       ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
-       BUG_ON(NInoAttr(ni));
-       BUG_ON(!max_bhs);
-       BUG_ON(!PageLocked(page));
-       if (WARN_ON(max_bhs > MAX_BHS)) {
-               err = -EINVAL;
-               goto err_out;
-       }
-       /*
-        * If the ntfs_inode is clean no need to do anything.  If it is dirty,
-        * mark it as clean now so that it can be redirtied later on if needed.
-        * There is no danger of races since the caller is holding the locks
-        * for the mft record @m and the page it is in.
-        */
-       if (!NInoTestClearDirty(ni))
-               goto done;
-       bh = head = page_buffers(page);
-       BUG_ON(!bh);
-       rl = NULL;
-       nr_bhs = 0;
-       block_start = 0;
-       m_start = ni->page_ofs;
-       m_end = m_start + vol->mft_record_size;
-       do {
-               block_end = block_start + blocksize;
-               /* If the buffer is outside the mft record, skip it. */
-               if (block_end <= m_start)
-                       continue;
-               if (unlikely(block_start >= m_end))
-                       break;
-               /*
-                * If this block is not the first one in the record, we ignore
-                * the buffer's dirty state because we could have raced with a
-                * parallel mark_ntfs_record_dirty().
-                */
-               if (block_start == m_start) {
-                       /* This block is the first one in the record. */
-                       if (!buffer_dirty(bh)) {
-                               BUG_ON(nr_bhs);
-                               /* Clean records are not written out. */
-                               break;
-                       }
-               }
-               /* Need to map the buffer if it is not mapped already. */
-               if (unlikely(!buffer_mapped(bh))) {
-                       VCN vcn;
-                       LCN lcn;
-                       unsigned int vcn_ofs;
-
-                       bh->b_bdev = vol->sb->s_bdev;
-                       /* Obtain the vcn and offset of the current block. */
-                       vcn = ((VCN)ni->mft_no << vol->mft_record_size_bits) +
-                                       (block_start - m_start);
-                       vcn_ofs = vcn & vol->cluster_size_mask;
-                       vcn >>= vol->cluster_size_bits;
-                       if (!rl) {
-                               down_read(&NTFS_I(vol->mft_ino)->runlist.lock);
-                               rl = NTFS_I(vol->mft_ino)->runlist.rl;
-                               BUG_ON(!rl);
-                       }
-                       /* Seek to element containing target vcn. */
-                       while (rl->length && rl[1].vcn <= vcn)
-                               rl++;
-                       lcn = ntfs_rl_vcn_to_lcn(rl, vcn);
-                       /* For $MFT, only lcn >= 0 is a successful remap. */
-                       if (likely(lcn >= 0)) {
-                               /* Setup buffer head to correct block. */
-                               bh->b_blocknr = ((lcn <<
-                                               vol->cluster_size_bits) +
-                                               vcn_ofs) >> blocksize_bits;
-                               set_buffer_mapped(bh);
-                       } else {
-                               bh->b_blocknr = -1;
-                               ntfs_error(vol->sb, "Cannot write mft record "
-                                               "0x%lx because its location "
-                                               "on disk could not be "
-                                               "determined (error code %lli).",
-                                               ni->mft_no, (long long)lcn);
-                               err = -EIO;
-                       }
-               }
-               BUG_ON(!buffer_uptodate(bh));
-               BUG_ON(!nr_bhs && (m_start != block_start));
-               BUG_ON(nr_bhs >= max_bhs);
-               bhs[nr_bhs++] = bh;
-               BUG_ON((nr_bhs >= max_bhs) && (m_end != block_end));
-       } while (block_start = block_end, (bh = bh->b_this_page) != head);
-       if (unlikely(rl))
-               up_read(&NTFS_I(vol->mft_ino)->runlist.lock);
-       if (!nr_bhs)
-               goto done;
-       if (unlikely(err))
-               goto cleanup_out;
-       /* Apply the mst protection fixups. */
-       err = pre_write_mst_fixup((NTFS_RECORD*)m, vol->mft_record_size);
-       if (err) {
-               ntfs_error(vol->sb, "Failed to apply mst fixups!");
-               goto cleanup_out;
-       }
-       flush_dcache_mft_record_page(ni);
-       /* Lock buffers and start synchronous write i/o on them. */
-       for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) {
-               struct buffer_head *tbh = bhs[i_bhs];
-
-               if (!trylock_buffer(tbh))
-                       BUG();
-               BUG_ON(!buffer_uptodate(tbh));
-               clear_buffer_dirty(tbh);
-               get_bh(tbh);
-               tbh->b_end_io = end_buffer_write_sync;
-               submit_bh(REQ_OP_WRITE, tbh);
-       }
-       /* Synchronize the mft mirror now if not @sync. */
-       if (!sync && ni->mft_no < vol->mftmirr_size)
-               ntfs_sync_mft_mirror(vol, ni->mft_no, m, sync);
-       /* Wait on i/o completion of buffers. */
-       for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) {
-               struct buffer_head *tbh = bhs[i_bhs];
-
-               wait_on_buffer(tbh);
-               if (unlikely(!buffer_uptodate(tbh))) {
-                       err = -EIO;
-                       /*
-                        * Set the buffer uptodate so the page and buffer
-                        * states do not become out of sync.
-                        */
-                       if (PageUptodate(page))
-                               set_buffer_uptodate(tbh);
-               }
-       }
-       /* If @sync, now synchronize the mft mirror. */
-       if (sync && ni->mft_no < vol->mftmirr_size)
-               ntfs_sync_mft_mirror(vol, ni->mft_no, m, sync);
-       /* Remove the mst protection fixups again. */
-       post_write_mst_fixup((NTFS_RECORD*)m);
-       flush_dcache_mft_record_page(ni);
-       if (unlikely(err)) {
-               /* I/O error during writing.  This is really bad! */
-               ntfs_error(vol->sb, "I/O error while writing mft record "
-                               "0x%lx!  Marking base inode as bad.  You "
-                               "should unmount the volume and run chkdsk.",
-                               ni->mft_no);
-               goto err_out;
-       }
-done:
-       ntfs_debug("Done.");
-       return 0;
-cleanup_out:
-       /* Clean the buffers. */
-       for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++)
-               clear_buffer_dirty(bhs[i_bhs]);
-err_out:
-       /*
-        * Current state: all buffers are clean, unlocked, and uptodate.
-        * The caller should mark the base inode as bad so that no more i/o
-        * happens.  ->clear_inode() will still be invoked so all extent inodes
-        * and other allocated memory will be freed.
-        */
-       if (err == -ENOMEM) {
-               ntfs_error(vol->sb, "Not enough memory to write mft record.  "
-                               "Redirtying so the write is retried later.");
-               mark_mft_record_dirty(ni);
-               err = 0;
-       } else
-               NVolSetErrors(vol);
-       return err;
-}
-
-/**
- * ntfs_may_write_mft_record - check if an mft record may be written out
- * @vol:       [IN]  ntfs volume on which the mft record to check resides
- * @mft_no:    [IN]  mft record number of the mft record to check
- * @m:         [IN]  mapped mft record to check
- * @locked_ni: [OUT] caller has to unlock this ntfs inode if one is returned
- *
- * Check if the mapped (base or extent) mft record @m with mft record number
- * @mft_no belonging to the ntfs volume @vol may be written out.  If necessary
- * and possible the ntfs inode of the mft record is locked and the base vfs
- * inode is pinned.  The locked ntfs inode is then returned in @locked_ni.  The
- * caller is responsible for unlocking the ntfs inode and unpinning the base
- * vfs inode.
- *
- * Return 'true' if the mft record may be written out and 'false' if not.
- *
- * The caller has locked the page and cleared the uptodate flag on it which
- * means that we can safely write out any dirty mft records that do not have
- * their inodes in icache as determined by ilookup5() as anyone
- * opening/creating such an inode would block when attempting to map the mft
- * record in read_cache_page() until we are finished with the write out.
- *
- * Here is a description of the tests we perform:
- *
- * If the inode is found in icache we know the mft record must be a base mft
- * record.  If it is dirty, we do not write it and return 'false' as the vfs
- * inode write paths will result in the access times being updated which would
- * cause the base mft record to be redirtied and written out again.  (We know
- * the access time update will modify the base mft record because Windows
- * chkdsk complains if the standard information attribute is not in the base
- * mft record.)
- *
- * If the inode is in icache and not dirty, we attempt to lock the mft record
- * and if we find the lock was already taken, it is not safe to write the mft
- * record and we return 'false'.
- *
- * If we manage to obtain the lock we have exclusive access to the mft record,
- * which also allows us safe writeout of the mft record.  We then set
- * @locked_ni to the locked ntfs inode and return 'true'.
- *
- * Note we cannot just lock the mft record and sleep while waiting for the lock
- * because this would deadlock due to lock reversal (normally the mft record is
- * locked before the page is locked but we already have the page locked here
- * when we try to lock the mft record).
- *
- * If the inode is not in icache we need to perform further checks.
- *
- * If the mft record is not a FILE record or it is a base mft record, we can
- * safely write it and return 'true'.
- *
- * We now know the mft record is an extent mft record.  We check if the inode
- * corresponding to its base mft record is in icache and obtain a reference to
- * it if it is.  If it is not, we can safely write it and return 'true'.
- *
- * We now have the base inode for the extent mft record.  We check if it has an
- * ntfs inode for the extent mft record attached and if not it is safe to write
- * the extent mft record and we return 'true'.
- *
- * The ntfs inode for the extent mft record is attached to the base inode so we
- * attempt to lock the extent mft record and if we find the lock was already
- * taken, it is not safe to write the extent mft record and we return 'false'.
- *
- * If we manage to obtain the lock we have exclusive access to the extent mft
- * record, which also allows us safe writeout of the extent mft record.  We
- * set the ntfs inode of the extent mft record clean and then set @locked_ni to
- * the now locked ntfs inode and return 'true'.
- *
- * Note, the reason for actually writing dirty mft records here and not just
- * relying on the vfs inode dirty code paths is that we can have mft records
- * modified without them ever having actual inodes in memory.  Also we can have
- * dirty mft records with clean ntfs inodes in memory.  None of the described
- * cases would result in the dirty mft records being written out if we only
- * relied on the vfs inode dirty code paths.  And these cases can really occur
- * during allocation of new mft records and in particular when the
- * initialized_size of the $MFT/$DATA attribute is extended and the new space
- * is initialized using ntfs_mft_record_format().  The clean inode can then
- * appear if the mft record is reused for a new inode before it got written
- * out.
- */
-bool ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
-               const MFT_RECORD *m, ntfs_inode **locked_ni)
-{
-       struct super_block *sb = vol->sb;
-       struct inode *mft_vi = vol->mft_ino;
-       struct inode *vi;
-       ntfs_inode *ni, *eni, **extent_nis;
-       int i;
-       ntfs_attr na;
-
-       ntfs_debug("Entering for inode 0x%lx.", mft_no);
-       /*
-        * Normally we do not return a locked inode so set @locked_ni to NULL.
-        */
-       BUG_ON(!locked_ni);
-       *locked_ni = NULL;
-       /*
-        * Check if the inode corresponding to this mft record is in the VFS
-        * inode cache and obtain a reference to it if it is.
-        */
-       ntfs_debug("Looking for inode 0x%lx in icache.", mft_no);
-       na.mft_no = mft_no;
-       na.name = NULL;
-       na.name_len = 0;
-       na.type = AT_UNUSED;
-       /*
-        * Optimize inode 0, i.e. $MFT itself, since we have it in memory and
-        * we get here for it rather often.
-        */
-       if (!mft_no) {
-               /* Balance the below iput(). */
-               vi = igrab(mft_vi);
-               BUG_ON(vi != mft_vi);
-       } else {
-               /*
-                * Have to use ilookup5_nowait() since ilookup5() waits for the
-                * inode lock which causes ntfs to deadlock when a concurrent
-                * inode write via the inode dirty code paths and the page
-                * dirty code path of the inode dirty code path when writing
-                * $MFT occurs.
-                */
-               vi = ilookup5_nowait(sb, mft_no, ntfs_test_inode, &na);
-       }
-       if (vi) {
-               ntfs_debug("Base inode 0x%lx is in icache.", mft_no);
-               /* The inode is in icache. */
-               ni = NTFS_I(vi);
-               /* Take a reference to the ntfs inode. */
-               atomic_inc(&ni->count);
-               /* If the inode is dirty, do not write this record. */
-               if (NInoDirty(ni)) {
-                       ntfs_debug("Inode 0x%lx is dirty, do not write it.",
-                                       mft_no);
-                       atomic_dec(&ni->count);
-                       iput(vi);
-                       return false;
-               }
-               ntfs_debug("Inode 0x%lx is not dirty.", mft_no);
-               /* The inode is not dirty, try to take the mft record lock. */
-               if (unlikely(!mutex_trylock(&ni->mrec_lock))) {
-                       ntfs_debug("Mft record 0x%lx is already locked, do "
-                                       "not write it.", mft_no);
-                       atomic_dec(&ni->count);
-                       iput(vi);
-                       return false;
-               }
-               ntfs_debug("Managed to lock mft record 0x%lx, write it.",
-                               mft_no);
-               /*
-                * The write has to occur while we hold the mft record lock so
-                * return the locked ntfs inode.
-                */
-               *locked_ni = ni;
-               return true;
-       }
-       ntfs_debug("Inode 0x%lx is not in icache.", mft_no);
-       /* The inode is not in icache. */
-       /* Write the record if it is not a mft record (type "FILE"). */
-       if (!ntfs_is_mft_record(m->magic)) {
-               ntfs_debug("Mft record 0x%lx is not a FILE record, write it.",
-                               mft_no);
-               return true;
-       }
-       /* Write the mft record if it is a base inode. */
-       if (!m->base_mft_record) {
-               ntfs_debug("Mft record 0x%lx is a base record, write it.",
-                               mft_no);
-               return true;
-       }
-       /*
-        * This is an extent mft record.  Check if the inode corresponding to
-        * its base mft record is in icache and obtain a reference to it if it
-        * is.
-        */
-       na.mft_no = MREF_LE(m->base_mft_record);
-       ntfs_debug("Mft record 0x%lx is an extent record.  Looking for base "
-                       "inode 0x%lx in icache.", mft_no, na.mft_no);
-       if (!na.mft_no) {
-               /* Balance the below iput(). */
-               vi = igrab(mft_vi);
-               BUG_ON(vi != mft_vi);
-       } else
-               vi = ilookup5_nowait(sb, na.mft_no, ntfs_test_inode,
-                               &na);
-       if (!vi) {
-               /*
-                * The base inode is not in icache, write this extent mft
-                * record.
-                */
-               ntfs_debug("Base inode 0x%lx is not in icache, write the "
-                               "extent record.", na.mft_no);
-               return true;
-       }
-       ntfs_debug("Base inode 0x%lx is in icache.", na.mft_no);
-       /*
-        * The base inode is in icache.  Check if it has the extent inode
-        * corresponding to this extent mft record attached.
-        */
-       ni = NTFS_I(vi);
-       mutex_lock(&ni->extent_lock);
-       if (ni->nr_extents <= 0) {
-               /*
-                * The base inode has no attached extent inodes, write this
-                * extent mft record.
-                */
-               mutex_unlock(&ni->extent_lock);
-               iput(vi);
-               ntfs_debug("Base inode 0x%lx has no attached extent inodes, "
-                               "write the extent record.", na.mft_no);
-               return true;
-       }
-       /* Iterate over the attached extent inodes. */
-       extent_nis = ni->ext.extent_ntfs_inos;
-       for (eni = NULL, i = 0; i < ni->nr_extents; ++i) {
-               if (mft_no == extent_nis[i]->mft_no) {
-                       /*
-                        * Found the extent inode corresponding to this extent
-                        * mft record.
-                        */
-                       eni = extent_nis[i];
-                       break;
-               }
-       }
-       /*
-        * If the extent inode was not attached to the base inode, write this
-        * extent mft record.
-        */
-       if (!eni) {
-               mutex_unlock(&ni->extent_lock);
-               iput(vi);
-               ntfs_debug("Extent inode 0x%lx is not attached to its base "
-                               "inode 0x%lx, write the extent record.",
-                               mft_no, na.mft_no);
-               return true;
-       }
-       ntfs_debug("Extent inode 0x%lx is attached to its base inode 0x%lx.",
-                       mft_no, na.mft_no);
-       /* Take a reference to the extent ntfs inode. */
-       atomic_inc(&eni->count);
-       mutex_unlock(&ni->extent_lock);
-       /*
-        * Found the extent inode coresponding to this extent mft record.
-        * Try to take the mft record lock.
-        */
-       if (unlikely(!mutex_trylock(&eni->mrec_lock))) {
-               atomic_dec(&eni->count);
-               iput(vi);
-               ntfs_debug("Extent mft record 0x%lx is already locked, do "
-                               "not write it.", mft_no);
-               return false;
-       }
-       ntfs_debug("Managed to lock extent mft record 0x%lx, write it.",
-                       mft_no);
-       if (NInoTestClearDirty(eni))
-               ntfs_debug("Extent inode 0x%lx is dirty, marking it clean.",
-                               mft_no);
-       /*
-        * The write has to occur while we hold the mft record lock so return
-        * the locked extent ntfs inode.
-        */
-       *locked_ni = eni;
-       return true;
-}
-
-static const char *es = "  Leaving inconsistent metadata.  Unmount and run "
-               "chkdsk.";
-
-/**
- * ntfs_mft_bitmap_find_and_alloc_free_rec_nolock - see name
- * @vol:       volume on which to search for a free mft record
- * @base_ni:   open base inode if allocating an extent mft record or NULL
- *
- * Search for a free mft record in the mft bitmap attribute on the ntfs volume
- * @vol.
- *
- * If @base_ni is NULL start the search at the default allocator position.
- *
- * If @base_ni is not NULL start the search at the mft record after the base
- * mft record @base_ni.
- *
- * Return the free mft record on success and -errno on error.  An error code of
- * -ENOSPC means that there are no free mft records in the currently
- * initialized mft bitmap.
- *
- * Locking: Caller must hold vol->mftbmp_lock for writing.
- */
-static int ntfs_mft_bitmap_find_and_alloc_free_rec_nolock(ntfs_volume *vol,
-               ntfs_inode *base_ni)
-{
-       s64 pass_end, ll, data_pos, pass_start, ofs, bit;
-       unsigned long flags;
-       struct address_space *mftbmp_mapping;
-       u8 *buf, *byte;
-       struct page *page;
-       unsigned int page_ofs, size;
-       u8 pass, b;
-
-       ntfs_debug("Searching for free mft record in the currently "
-                       "initialized mft bitmap.");
-       mftbmp_mapping = vol->mftbmp_ino->i_mapping;
-       /*
-        * Set the end of the pass making sure we do not overflow the mft
-        * bitmap.
-        */
-       read_lock_irqsave(&NTFS_I(vol->mft_ino)->size_lock, flags);
-       pass_end = NTFS_I(vol->mft_ino)->allocated_size >>
-                       vol->mft_record_size_bits;
-       read_unlock_irqrestore(&NTFS_I(vol->mft_ino)->size_lock, flags);
-       read_lock_irqsave(&NTFS_I(vol->mftbmp_ino)->size_lock, flags);
-       ll = NTFS_I(vol->mftbmp_ino)->initialized_size << 3;
-       read_unlock_irqrestore(&NTFS_I(vol->mftbmp_ino)->size_lock, flags);
-       if (pass_end > ll)
-               pass_end = ll;
-       pass = 1;
-       if (!base_ni)
-               data_pos = vol->mft_data_pos;
-       else
-               data_pos = base_ni->mft_no + 1;
-       if (data_pos < 24)
-               data_pos = 24;
-       if (data_pos >= pass_end) {
-               data_pos = 24;
-               pass = 2;
-               /* This happens on a freshly formatted volume. */
-               if (data_pos >= pass_end)
-                       return -ENOSPC;
-       }
-       pass_start = data_pos;
-       ntfs_debug("Starting bitmap search: pass %u, pass_start 0x%llx, "
-                       "pass_end 0x%llx, data_pos 0x%llx.", pass,
-                       (long long)pass_start, (long long)pass_end,
-                       (long long)data_pos);
-       /* Loop until a free mft record is found. */
-       for (; pass <= 2;) {
-               /* Cap size to pass_end. */
-               ofs = data_pos >> 3;
-               page_ofs = ofs & ~PAGE_MASK;
-               size = PAGE_SIZE - page_ofs;
-               ll = ((pass_end + 7) >> 3) - ofs;
-               if (size > ll)
-                       size = ll;
-               size <<= 3;
-               /*
-                * If we are still within the active pass, search the next page
-                * for a zero bit.
-                */
-               if (size) {
-                       page = ntfs_map_page(mftbmp_mapping,
-                                       ofs >> PAGE_SHIFT);
-                       if (IS_ERR(page)) {
-                               ntfs_error(vol->sb, "Failed to read mft "
-                                               "bitmap, aborting.");
-                               return PTR_ERR(page);
-                       }
-                       buf = (u8*)page_address(page) + page_ofs;
-                       bit = data_pos & 7;
-                       data_pos &= ~7ull;
-                       ntfs_debug("Before inner for loop: size 0x%x, "
-                                       "data_pos 0x%llx, bit 0x%llx", size,
-                                       (long long)data_pos, (long long)bit);
-                       for (; bit < size && data_pos + bit < pass_end;
-                                       bit &= ~7ull, bit += 8) {
-                               byte = buf + (bit >> 3);
-                               if (*byte == 0xff)
-                                       continue;
-                               b = ffz((unsigned long)*byte);
-                               if (b < 8 && b >= (bit & 7)) {
-                                       ll = data_pos + (bit & ~7ull) + b;
-                                       if (unlikely(ll > (1ll << 32))) {
-                                               ntfs_unmap_page(page);
-                                               return -ENOSPC;
-                                       }
-                                       *byte |= 1 << b;
-                                       flush_dcache_page(page);
-                                       set_page_dirty(page);
-                                       ntfs_unmap_page(page);
-                                       ntfs_debug("Done.  (Found and "
-                                                       "allocated mft record "
-                                                       "0x%llx.)",
-                                                       (long long)ll);
-                                       return ll;
-                               }
-                       }
-                       ntfs_debug("After inner for loop: size 0x%x, "
-                                       "data_pos 0x%llx, bit 0x%llx", size,
-                                       (long long)data_pos, (long long)bit);
-                       data_pos += size;
-                       ntfs_unmap_page(page);
-                       /*
-                        * If the end of the pass has not been reached yet,
-                        * continue searching the mft bitmap for a zero bit.
-                        */
-                       if (data_pos < pass_end)
-                               continue;
-               }
-               /* Do the next pass. */
-               if (++pass == 2) {
-                       /*
-                        * Starting the second pass, in which we scan the first
-                        * part of the zone which we omitted earlier.
-                        */
-                       pass_end = pass_start;
-                       data_pos = pass_start = 24;
-                       ntfs_debug("pass %i, pass_start 0x%llx, pass_end "
-                                       "0x%llx.", pass, (long long)pass_start,
-                                       (long long)pass_end);
-                       if (data_pos >= pass_end)
-                               break;
-               }
-       }
-       /* No free mft records in currently initialized mft bitmap. */
-       ntfs_debug("Done.  (No free mft records left in currently initialized "
-                       "mft bitmap.)");
-       return -ENOSPC;
-}
-
-/**
- * ntfs_mft_bitmap_extend_allocation_nolock - extend mft bitmap by a cluster
- * @vol:       volume on which to extend the mft bitmap attribute
- *
- * Extend the mft bitmap attribute on the ntfs volume @vol by one cluster.
- *
- * Note: Only changes allocated_size, i.e. does not touch initialized_size or
- * data_size.
- *
- * Return 0 on success and -errno on error.
- *
- * Locking: - Caller must hold vol->mftbmp_lock for writing.
- *         - This function takes NTFS_I(vol->mftbmp_ino)->runlist.lock for
- *           writing and releases it before returning.
- *         - This function takes vol->lcnbmp_lock for writing and releases it
- *           before returning.
- */
-static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol)
-{
-       LCN lcn;
-       s64 ll;
-       unsigned long flags;
-       struct page *page;
-       ntfs_inode *mft_ni, *mftbmp_ni;
-       runlist_element *rl, *rl2 = NULL;
-       ntfs_attr_search_ctx *ctx = NULL;
-       MFT_RECORD *mrec;
-       ATTR_RECORD *a = NULL;
-       int ret, mp_size;
-       u32 old_alen = 0;
-       u8 *b, tb;
-       struct {
-               u8 added_cluster:1;
-               u8 added_run:1;
-               u8 mp_rebuilt:1;
-       } status = { 0, 0, 0 };
-
-       ntfs_debug("Extending mft bitmap allocation.");
-       mft_ni = NTFS_I(vol->mft_ino);
-       mftbmp_ni = NTFS_I(vol->mftbmp_ino);
-       /*
-        * Determine the last lcn of the mft bitmap.  The allocated size of the
-        * mft bitmap cannot be zero so we are ok to do this.
-        */
-       down_write(&mftbmp_ni->runlist.lock);
-       read_lock_irqsave(&mftbmp_ni->size_lock, flags);
-       ll = mftbmp_ni->allocated_size;
-       read_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
-       rl = ntfs_attr_find_vcn_nolock(mftbmp_ni,
-                       (ll - 1) >> vol->cluster_size_bits, NULL);
-       if (IS_ERR(rl) || unlikely(!rl->length || rl->lcn < 0)) {
-               up_write(&mftbmp_ni->runlist.lock);
-               ntfs_error(vol->sb, "Failed to determine last allocated "
-                               "cluster of mft bitmap attribute.");
-               if (!IS_ERR(rl))
-                       ret = -EIO;
-               else
-                       ret = PTR_ERR(rl);
-               return ret;
-       }
-       lcn = rl->lcn + rl->length;
-       ntfs_debug("Last lcn of mft bitmap attribute is 0x%llx.",
-                       (long long)lcn);
-       /*
-        * Attempt to get the cluster following the last allocated cluster by
-        * hand as it may be in the MFT zone so the allocator would not give it
-        * to us.
-        */
-       ll = lcn >> 3;
-       page = ntfs_map_page(vol->lcnbmp_ino->i_mapping,
-                       ll >> PAGE_SHIFT);
-       if (IS_ERR(page)) {
-               up_write(&mftbmp_ni->runlist.lock);
-               ntfs_error(vol->sb, "Failed to read from lcn bitmap.");
-               return PTR_ERR(page);
-       }
-       b = (u8*)page_address(page) + (ll & ~PAGE_MASK);
-       tb = 1 << (lcn & 7ull);
-       down_write(&vol->lcnbmp_lock);
-       if (*b != 0xff && !(*b & tb)) {
-               /* Next cluster is free, allocate it. */
-               *b |= tb;
-               flush_dcache_page(page);
-               set_page_dirty(page);
-               up_write(&vol->lcnbmp_lock);
-               ntfs_unmap_page(page);
-               /* Update the mft bitmap runlist. */
-               rl->length++;
-               rl[1].vcn++;
-               status.added_cluster = 1;
-               ntfs_debug("Appending one cluster to mft bitmap.");
-       } else {
-               up_write(&vol->lcnbmp_lock);
-               ntfs_unmap_page(page);
-               /* Allocate a cluster from the DATA_ZONE. */
-               rl2 = ntfs_cluster_alloc(vol, rl[1].vcn, 1, lcn, DATA_ZONE,
-                               true);
-               if (IS_ERR(rl2)) {
-                       up_write(&mftbmp_ni->runlist.lock);
-                       ntfs_error(vol->sb, "Failed to allocate a cluster for "
-                                       "the mft bitmap.");
-                       return PTR_ERR(rl2);
-               }
-               rl = ntfs_runlists_merge(mftbmp_ni->runlist.rl, rl2);
-               if (IS_ERR(rl)) {
-                       up_write(&mftbmp_ni->runlist.lock);
-                       ntfs_error(vol->sb, "Failed to merge runlists for mft "
-                                       "bitmap.");
-                       if (ntfs_cluster_free_from_rl(vol, rl2)) {
-                               ntfs_error(vol->sb, "Failed to deallocate "
-                                               "allocated cluster.%s", es);
-                               NVolSetErrors(vol);
-                       }
-                       ntfs_free(rl2);
-                       return PTR_ERR(rl);
-               }
-               mftbmp_ni->runlist.rl = rl;
-               status.added_run = 1;
-               ntfs_debug("Adding one run to mft bitmap.");
-               /* Find the last run in the new runlist. */
-               for (; rl[1].length; rl++)
-                       ;
-       }
-       /*
-        * Update the attribute record as well.  Note: @rl is the last
-        * (non-terminator) runlist element of mft bitmap.
-        */
-       mrec = map_mft_record(mft_ni);
-       if (IS_ERR(mrec)) {
-               ntfs_error(vol->sb, "Failed to map mft record.");
-               ret = PTR_ERR(mrec);
-               goto undo_alloc;
-       }
-       ctx = ntfs_attr_get_search_ctx(mft_ni, mrec);
-       if (unlikely(!ctx)) {
-               ntfs_error(vol->sb, "Failed to get search context.");
-               ret = -ENOMEM;
-               goto undo_alloc;
-       }
-       ret = ntfs_attr_lookup(mftbmp_ni->type, mftbmp_ni->name,
-                       mftbmp_ni->name_len, CASE_SENSITIVE, rl[1].vcn, NULL,
-                       0, ctx);
-       if (unlikely(ret)) {
-               ntfs_error(vol->sb, "Failed to find last attribute extent of "
-                               "mft bitmap attribute.");
-               if (ret == -ENOENT)
-                       ret = -EIO;
-               goto undo_alloc;
-       }
-       a = ctx->attr;
-       ll = sle64_to_cpu(a->data.non_resident.lowest_vcn);
-       /* Search back for the previous last allocated cluster of mft bitmap. */
-       for (rl2 = rl; rl2 > mftbmp_ni->runlist.rl; rl2--) {
-               if (ll >= rl2->vcn)
-                       break;
-       }
-       BUG_ON(ll < rl2->vcn);
-       BUG_ON(ll >= rl2->vcn + rl2->length);
-       /* Get the size for the new mapping pairs array for this extent. */
-       mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1);
-       if (unlikely(mp_size <= 0)) {
-               ntfs_error(vol->sb, "Get size for mapping pairs failed for "
-                               "mft bitmap attribute extent.");
-               ret = mp_size;
-               if (!ret)
-                       ret = -EIO;
-               goto undo_alloc;
-       }
-       /* Expand the attribute record if necessary. */
-       old_alen = le32_to_cpu(a->length);
-       ret = ntfs_attr_record_resize(ctx->mrec, a, mp_size +
-                       le16_to_cpu(a->data.non_resident.mapping_pairs_offset));
-       if (unlikely(ret)) {
-               if (ret != -ENOSPC) {
-                       ntfs_error(vol->sb, "Failed to resize attribute "
-                                       "record for mft bitmap attribute.");
-                       goto undo_alloc;
-               }
-               // TODO: Deal with this by moving this extent to a new mft
-               // record or by starting a new extent in a new mft record or by
-               // moving other attributes out of this mft record.
-               // Note: It will need to be a special mft record and if none of
-               // those are available it gets rather complicated...
-               ntfs_error(vol->sb, "Not enough space in this mft record to "
-                               "accommodate extended mft bitmap attribute "
-                               "extent.  Cannot handle this yet.");
-               ret = -EOPNOTSUPP;
-               goto undo_alloc;
-       }
-       status.mp_rebuilt = 1;
-       /* Generate the mapping pairs array directly into the attr record. */
-       ret = ntfs_mapping_pairs_build(vol, (u8*)a +
-                       le16_to_cpu(a->data.non_resident.mapping_pairs_offset),
-                       mp_size, rl2, ll, -1, NULL);
-       if (unlikely(ret)) {
-               ntfs_error(vol->sb, "Failed to build mapping pairs array for "
-                               "mft bitmap attribute.");
-               goto undo_alloc;
-       }
-       /* Update the highest_vcn. */
-       a->data.non_resident.highest_vcn = cpu_to_sle64(rl[1].vcn - 1);
-       /*
-        * We now have extended the mft bitmap allocated_size by one cluster.
-        * Reflect this in the ntfs_inode structure and the attribute record.
-        */
-       if (a->data.non_resident.lowest_vcn) {
-               /*
-                * We are not in the first attribute extent, switch to it, but
-                * first ensure the changes will make it to disk later.
-                */
-               flush_dcache_mft_record_page(ctx->ntfs_ino);
-               mark_mft_record_dirty(ctx->ntfs_ino);
-               ntfs_attr_reinit_search_ctx(ctx);
-               ret = ntfs_attr_lookup(mftbmp_ni->type, mftbmp_ni->name,
-                               mftbmp_ni->name_len, CASE_SENSITIVE, 0, NULL,
-                               0, ctx);
-               if (unlikely(ret)) {
-                       ntfs_error(vol->sb, "Failed to find first attribute "
-                                       "extent of mft bitmap attribute.");
-                       goto restore_undo_alloc;
-               }
-               a = ctx->attr;
-       }
-       write_lock_irqsave(&mftbmp_ni->size_lock, flags);
-       mftbmp_ni->allocated_size += vol->cluster_size;
-       a->data.non_resident.allocated_size =
-                       cpu_to_sle64(mftbmp_ni->allocated_size);
-       write_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
-       /* Ensure the changes make it to disk. */
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(mft_ni);
-       up_write(&mftbmp_ni->runlist.lock);
-       ntfs_debug("Done.");
-       return 0;
-restore_undo_alloc:
-       ntfs_attr_reinit_search_ctx(ctx);
-       if (ntfs_attr_lookup(mftbmp_ni->type, mftbmp_ni->name,
-                       mftbmp_ni->name_len, CASE_SENSITIVE, rl[1].vcn, NULL,
-                       0, ctx)) {
-               ntfs_error(vol->sb, "Failed to find last attribute extent of "
-                               "mft bitmap attribute.%s", es);
-               write_lock_irqsave(&mftbmp_ni->size_lock, flags);
-               mftbmp_ni->allocated_size += vol->cluster_size;
-               write_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
-               ntfs_attr_put_search_ctx(ctx);
-               unmap_mft_record(mft_ni);
-               up_write(&mftbmp_ni->runlist.lock);
-               /*
-                * The only thing that is now wrong is ->allocated_size of the
-                * base attribute extent which chkdsk should be able to fix.
-                */
-               NVolSetErrors(vol);
-               return ret;
-       }
-       a = ctx->attr;
-       a->data.non_resident.highest_vcn = cpu_to_sle64(rl[1].vcn - 2);
-undo_alloc:
-       if (status.added_cluster) {
-               /* Truncate the last run in the runlist by one cluster. */
-               rl->length--;
-               rl[1].vcn--;
-       } else if (status.added_run) {
-               lcn = rl->lcn;
-               /* Remove the last run from the runlist. */
-               rl->lcn = rl[1].lcn;
-               rl->length = 0;
-       }
-       /* Deallocate the cluster. */
-       down_write(&vol->lcnbmp_lock);
-       if (ntfs_bitmap_clear_bit(vol->lcnbmp_ino, lcn)) {
-               ntfs_error(vol->sb, "Failed to free allocated cluster.%s", es);
-               NVolSetErrors(vol);
-       }
-       up_write(&vol->lcnbmp_lock);
-       if (status.mp_rebuilt) {
-               if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(
-                               a->data.non_resident.mapping_pairs_offset),
-                               old_alen - le16_to_cpu(
-                               a->data.non_resident.mapping_pairs_offset),
-                               rl2, ll, -1, NULL)) {
-                       ntfs_error(vol->sb, "Failed to restore mapping pairs "
-                                       "array.%s", es);
-                       NVolSetErrors(vol);
-               }
-               if (ntfs_attr_record_resize(ctx->mrec, a, old_alen)) {
-                       ntfs_error(vol->sb, "Failed to restore attribute "
-                                       "record.%s", es);
-                       NVolSetErrors(vol);
-               }
-               flush_dcache_mft_record_page(ctx->ntfs_ino);
-               mark_mft_record_dirty(ctx->ntfs_ino);
-       }
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (!IS_ERR(mrec))
-               unmap_mft_record(mft_ni);
-       up_write(&mftbmp_ni->runlist.lock);
-       return ret;
-}
-
-/**
- * ntfs_mft_bitmap_extend_initialized_nolock - extend mftbmp initialized data
- * @vol:       volume on which to extend the mft bitmap attribute
- *
- * Extend the initialized portion of the mft bitmap attribute on the ntfs
- * volume @vol by 8 bytes.
- *
- * Note:  Only changes initialized_size and data_size, i.e. requires that
- * allocated_size is big enough to fit the new initialized_size.
- *
- * Return 0 on success and -error on error.
- *
- * Locking: Caller must hold vol->mftbmp_lock for writing.
- */
-static int ntfs_mft_bitmap_extend_initialized_nolock(ntfs_volume *vol)
-{
-       s64 old_data_size, old_initialized_size;
-       unsigned long flags;
-       struct inode *mftbmp_vi;
-       ntfs_inode *mft_ni, *mftbmp_ni;
-       ntfs_attr_search_ctx *ctx;
-       MFT_RECORD *mrec;
-       ATTR_RECORD *a;
-       int ret;
-
-       ntfs_debug("Extending mft bitmap initiailized (and data) size.");
-       mft_ni = NTFS_I(vol->mft_ino);
-       mftbmp_vi = vol->mftbmp_ino;
-       mftbmp_ni = NTFS_I(mftbmp_vi);
-       /* Get the attribute record. */
-       mrec = map_mft_record(mft_ni);
-       if (IS_ERR(mrec)) {
-               ntfs_error(vol->sb, "Failed to map mft record.");
-               return PTR_ERR(mrec);
-       }
-       ctx = ntfs_attr_get_search_ctx(mft_ni, mrec);
-       if (unlikely(!ctx)) {
-               ntfs_error(vol->sb, "Failed to get search context.");
-               ret = -ENOMEM;
-               goto unm_err_out;
-       }
-       ret = ntfs_attr_lookup(mftbmp_ni->type, mftbmp_ni->name,
-                       mftbmp_ni->name_len, CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(ret)) {
-               ntfs_error(vol->sb, "Failed to find first attribute extent of "
-                               "mft bitmap attribute.");
-               if (ret == -ENOENT)
-                       ret = -EIO;
-               goto put_err_out;
-       }
-       a = ctx->attr;
-       write_lock_irqsave(&mftbmp_ni->size_lock, flags);
-       old_data_size = i_size_read(mftbmp_vi);
-       old_initialized_size = mftbmp_ni->initialized_size;
-       /*
-        * We can simply update the initialized_size before filling the space
-        * with zeroes because the caller is holding the mft bitmap lock for
-        * writing which ensures that no one else is trying to access the data.
-        */
-       mftbmp_ni->initialized_size += 8;
-       a->data.non_resident.initialized_size =
-                       cpu_to_sle64(mftbmp_ni->initialized_size);
-       if (mftbmp_ni->initialized_size > old_data_size) {
-               i_size_write(mftbmp_vi, mftbmp_ni->initialized_size);
-               a->data.non_resident.data_size =
-                               cpu_to_sle64(mftbmp_ni->initialized_size);
-       }
-       write_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
-       /* Ensure the changes make it to disk. */
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(mft_ni);
-       /* Initialize the mft bitmap attribute value with zeroes. */
-       ret = ntfs_attr_set(mftbmp_ni, old_initialized_size, 8, 0);
-       if (likely(!ret)) {
-               ntfs_debug("Done.  (Wrote eight initialized bytes to mft "
-                               "bitmap.");
-               return 0;
-       }
-       ntfs_error(vol->sb, "Failed to write to mft bitmap.");
-       /* Try to recover from the error. */
-       mrec = map_mft_record(mft_ni);
-       if (IS_ERR(mrec)) {
-               ntfs_error(vol->sb, "Failed to map mft record.%s", es);
-               NVolSetErrors(vol);
-               return ret;
-       }
-       ctx = ntfs_attr_get_search_ctx(mft_ni, mrec);
-       if (unlikely(!ctx)) {
-               ntfs_error(vol->sb, "Failed to get search context.%s", es);
-               NVolSetErrors(vol);
-               goto unm_err_out;
-       }
-       if (ntfs_attr_lookup(mftbmp_ni->type, mftbmp_ni->name,
-                       mftbmp_ni->name_len, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
-               ntfs_error(vol->sb, "Failed to find first attribute extent of "
-                               "mft bitmap attribute.%s", es);
-               NVolSetErrors(vol);
-put_err_out:
-               ntfs_attr_put_search_ctx(ctx);
-unm_err_out:
-               unmap_mft_record(mft_ni);
-               goto err_out;
-       }
-       a = ctx->attr;
-       write_lock_irqsave(&mftbmp_ni->size_lock, flags);
-       mftbmp_ni->initialized_size = old_initialized_size;
-       a->data.non_resident.initialized_size =
-                       cpu_to_sle64(old_initialized_size);
-       if (i_size_read(mftbmp_vi) != old_data_size) {
-               i_size_write(mftbmp_vi, old_data_size);
-               a->data.non_resident.data_size = cpu_to_sle64(old_data_size);
-       }
-       write_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(mft_ni);
-#ifdef DEBUG
-       read_lock_irqsave(&mftbmp_ni->size_lock, flags);
-       ntfs_debug("Restored status of mftbmp: allocated_size 0x%llx, "
-                       "data_size 0x%llx, initialized_size 0x%llx.",
-                       (long long)mftbmp_ni->allocated_size,
-                       (long long)i_size_read(mftbmp_vi),
-                       (long long)mftbmp_ni->initialized_size);
-       read_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
-#endif /* DEBUG */
-err_out:
-       return ret;
-}
-
-/**
- * ntfs_mft_data_extend_allocation_nolock - extend mft data attribute
- * @vol:       volume on which to extend the mft data attribute
- *
- * Extend the mft data attribute on the ntfs volume @vol by 16 mft records
- * worth of clusters or if not enough space for this by one mft record worth
- * of clusters.
- *
- * Note:  Only changes allocated_size, i.e. does not touch initialized_size or
- * data_size.
- *
- * Return 0 on success and -errno on error.
- *
- * Locking: - Caller must hold vol->mftbmp_lock for writing.
- *         - This function takes NTFS_I(vol->mft_ino)->runlist.lock for
- *           writing and releases it before returning.
- *         - This function calls functions which take vol->lcnbmp_lock for
- *           writing and release it before returning.
- */
-static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol)
-{
-       LCN lcn;
-       VCN old_last_vcn;
-       s64 min_nr, nr, ll;
-       unsigned long flags;
-       ntfs_inode *mft_ni;
-       runlist_element *rl, *rl2;
-       ntfs_attr_search_ctx *ctx = NULL;
-       MFT_RECORD *mrec;
-       ATTR_RECORD *a = NULL;
-       int ret, mp_size;
-       u32 old_alen = 0;
-       bool mp_rebuilt = false;
-
-       ntfs_debug("Extending mft data allocation.");
-       mft_ni = NTFS_I(vol->mft_ino);
-       /*
-        * Determine the preferred allocation location, i.e. the last lcn of
-        * the mft data attribute.  The allocated size of the mft data
-        * attribute cannot be zero so we are ok to do this.
-        */
-       down_write(&mft_ni->runlist.lock);
-       read_lock_irqsave(&mft_ni->size_lock, flags);
-       ll = mft_ni->allocated_size;
-       read_unlock_irqrestore(&mft_ni->size_lock, flags);
-       rl = ntfs_attr_find_vcn_nolock(mft_ni,
-                       (ll - 1) >> vol->cluster_size_bits, NULL);
-       if (IS_ERR(rl) || unlikely(!rl->length || rl->lcn < 0)) {
-               up_write(&mft_ni->runlist.lock);
-               ntfs_error(vol->sb, "Failed to determine last allocated "
-                               "cluster of mft data attribute.");
-               if (!IS_ERR(rl))
-                       ret = -EIO;
-               else
-                       ret = PTR_ERR(rl);
-               return ret;
-       }
-       lcn = rl->lcn + rl->length;
-       ntfs_debug("Last lcn of mft data attribute is 0x%llx.", (long long)lcn);
-       /* Minimum allocation is one mft record worth of clusters. */
-       min_nr = vol->mft_record_size >> vol->cluster_size_bits;
-       if (!min_nr)
-               min_nr = 1;
-       /* Want to allocate 16 mft records worth of clusters. */
-       nr = vol->mft_record_size << 4 >> vol->cluster_size_bits;
-       if (!nr)
-               nr = min_nr;
-       /* Ensure we do not go above 2^32-1 mft records. */
-       read_lock_irqsave(&mft_ni->size_lock, flags);
-       ll = mft_ni->allocated_size;
-       read_unlock_irqrestore(&mft_ni->size_lock, flags);
-       if (unlikely((ll + (nr << vol->cluster_size_bits)) >>
-                       vol->mft_record_size_bits >= (1ll << 32))) {
-               nr = min_nr;
-               if (unlikely((ll + (nr << vol->cluster_size_bits)) >>
-                               vol->mft_record_size_bits >= (1ll << 32))) {
-                       ntfs_warning(vol->sb, "Cannot allocate mft record "
-                                       "because the maximum number of inodes "
-                                       "(2^32) has already been reached.");
-                       up_write(&mft_ni->runlist.lock);
-                       return -ENOSPC;
-               }
-       }
-       ntfs_debug("Trying mft data allocation with %s cluster count %lli.",
-                       nr > min_nr ? "default" : "minimal", (long long)nr);
-       old_last_vcn = rl[1].vcn;
-       do {
-               rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE,
-                               true);
-               if (!IS_ERR(rl2))
-                       break;
-               if (PTR_ERR(rl2) != -ENOSPC || nr == min_nr) {
-                       ntfs_error(vol->sb, "Failed to allocate the minimal "
-                                       "number of clusters (%lli) for the "
-                                       "mft data attribute.", (long long)nr);
-                       up_write(&mft_ni->runlist.lock);
-                       return PTR_ERR(rl2);
-               }
-               /*
-                * There is not enough space to do the allocation, but there
-                * might be enough space to do a minimal allocation so try that
-                * before failing.
-                */
-               nr = min_nr;
-               ntfs_debug("Retrying mft data allocation with minimal cluster "
-                               "count %lli.", (long long)nr);
-       } while (1);
-       rl = ntfs_runlists_merge(mft_ni->runlist.rl, rl2);
-       if (IS_ERR(rl)) {
-               up_write(&mft_ni->runlist.lock);
-               ntfs_error(vol->sb, "Failed to merge runlists for mft data "
-                               "attribute.");
-               if (ntfs_cluster_free_from_rl(vol, rl2)) {
-                       ntfs_error(vol->sb, "Failed to deallocate clusters "
-                                       "from the mft data attribute.%s", es);
-                       NVolSetErrors(vol);
-               }
-               ntfs_free(rl2);
-               return PTR_ERR(rl);
-       }
-       mft_ni->runlist.rl = rl;
-       ntfs_debug("Allocated %lli clusters.", (long long)nr);
-       /* Find the last run in the new runlist. */
-       for (; rl[1].length; rl++)
-               ;
-       /* Update the attribute record as well. */
-       mrec = map_mft_record(mft_ni);
-       if (IS_ERR(mrec)) {
-               ntfs_error(vol->sb, "Failed to map mft record.");
-               ret = PTR_ERR(mrec);
-               goto undo_alloc;
-       }
-       ctx = ntfs_attr_get_search_ctx(mft_ni, mrec);
-       if (unlikely(!ctx)) {
-               ntfs_error(vol->sb, "Failed to get search context.");
-               ret = -ENOMEM;
-               goto undo_alloc;
-       }
-       ret = ntfs_attr_lookup(mft_ni->type, mft_ni->name, mft_ni->name_len,
-                       CASE_SENSITIVE, rl[1].vcn, NULL, 0, ctx);
-       if (unlikely(ret)) {
-               ntfs_error(vol->sb, "Failed to find last attribute extent of "
-                               "mft data attribute.");
-               if (ret == -ENOENT)
-                       ret = -EIO;
-               goto undo_alloc;
-       }
-       a = ctx->attr;
-       ll = sle64_to_cpu(a->data.non_resident.lowest_vcn);
-       /* Search back for the previous last allocated cluster of mft bitmap. */
-       for (rl2 = rl; rl2 > mft_ni->runlist.rl; rl2--) {
-               if (ll >= rl2->vcn)
-                       break;
-       }
-       BUG_ON(ll < rl2->vcn);
-       BUG_ON(ll >= rl2->vcn + rl2->length);
-       /* Get the size for the new mapping pairs array for this extent. */
-       mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1);
-       if (unlikely(mp_size <= 0)) {
-               ntfs_error(vol->sb, "Get size for mapping pairs failed for "
-                               "mft data attribute extent.");
-               ret = mp_size;
-               if (!ret)
-                       ret = -EIO;
-               goto undo_alloc;
-       }
-       /* Expand the attribute record if necessary. */
-       old_alen = le32_to_cpu(a->length);
-       ret = ntfs_attr_record_resize(ctx->mrec, a, mp_size +
-                       le16_to_cpu(a->data.non_resident.mapping_pairs_offset));
-       if (unlikely(ret)) {
-               if (ret != -ENOSPC) {
-                       ntfs_error(vol->sb, "Failed to resize attribute "
-                                       "record for mft data attribute.");
-                       goto undo_alloc;
-               }
-               // TODO: Deal with this by moving this extent to a new mft
-               // record or by starting a new extent in a new mft record or by
-               // moving other attributes out of this mft record.
-               // Note: Use the special reserved mft records and ensure that
-               // this extent is not required to find the mft record in
-               // question.  If no free special records left we would need to
-               // move an existing record away, insert ours in its place, and
-               // then place the moved record into the newly allocated space
-               // and we would then need to update all references to this mft
-               // record appropriately.  This is rather complicated...
-               ntfs_error(vol->sb, "Not enough space in this mft record to "
-                               "accommodate extended mft data attribute "
-                               "extent.  Cannot handle this yet.");
-               ret = -EOPNOTSUPP;
-               goto undo_alloc;
-       }
-       mp_rebuilt = true;
-       /* Generate the mapping pairs array directly into the attr record. */
-       ret = ntfs_mapping_pairs_build(vol, (u8*)a +
-                       le16_to_cpu(a->data.non_resident.mapping_pairs_offset),
-                       mp_size, rl2, ll, -1, NULL);
-       if (unlikely(ret)) {
-               ntfs_error(vol->sb, "Failed to build mapping pairs array of "
-                               "mft data attribute.");
-               goto undo_alloc;
-       }
-       /* Update the highest_vcn. */
-       a->data.non_resident.highest_vcn = cpu_to_sle64(rl[1].vcn - 1);
-       /*
-        * We now have extended the mft data allocated_size by nr clusters.
-        * Reflect this in the ntfs_inode structure and the attribute record.
-        * @rl is the last (non-terminator) runlist element of mft data
-        * attribute.
-        */
-       if (a->data.non_resident.lowest_vcn) {
-               /*
-                * We are not in the first attribute extent, switch to it, but
-                * first ensure the changes will make it to disk later.
-                */
-               flush_dcache_mft_record_page(ctx->ntfs_ino);
-               mark_mft_record_dirty(ctx->ntfs_ino);
-               ntfs_attr_reinit_search_ctx(ctx);
-               ret = ntfs_attr_lookup(mft_ni->type, mft_ni->name,
-                               mft_ni->name_len, CASE_SENSITIVE, 0, NULL, 0,
-                               ctx);
-               if (unlikely(ret)) {
-                       ntfs_error(vol->sb, "Failed to find first attribute "
-                                       "extent of mft data attribute.");
-                       goto restore_undo_alloc;
-               }
-               a = ctx->attr;
-       }
-       write_lock_irqsave(&mft_ni->size_lock, flags);
-       mft_ni->allocated_size += nr << vol->cluster_size_bits;
-       a->data.non_resident.allocated_size =
-                       cpu_to_sle64(mft_ni->allocated_size);
-       write_unlock_irqrestore(&mft_ni->size_lock, flags);
-       /* Ensure the changes make it to disk. */
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(mft_ni);
-       up_write(&mft_ni->runlist.lock);
-       ntfs_debug("Done.");
-       return 0;
-restore_undo_alloc:
-       ntfs_attr_reinit_search_ctx(ctx);
-       if (ntfs_attr_lookup(mft_ni->type, mft_ni->name, mft_ni->name_len,
-                       CASE_SENSITIVE, rl[1].vcn, NULL, 0, ctx)) {
-               ntfs_error(vol->sb, "Failed to find last attribute extent of "
-                               "mft data attribute.%s", es);
-               write_lock_irqsave(&mft_ni->size_lock, flags);
-               mft_ni->allocated_size += nr << vol->cluster_size_bits;
-               write_unlock_irqrestore(&mft_ni->size_lock, flags);
-               ntfs_attr_put_search_ctx(ctx);
-               unmap_mft_record(mft_ni);
-               up_write(&mft_ni->runlist.lock);
-               /*
-                * The only thing that is now wrong is ->allocated_size of the
-                * base attribute extent which chkdsk should be able to fix.
-                */
-               NVolSetErrors(vol);
-               return ret;
-       }
-       ctx->attr->data.non_resident.highest_vcn =
-                       cpu_to_sle64(old_last_vcn - 1);
-undo_alloc:
-       if (ntfs_cluster_free(mft_ni, old_last_vcn, -1, ctx) < 0) {
-               ntfs_error(vol->sb, "Failed to free clusters from mft data "
-                               "attribute.%s", es);
-               NVolSetErrors(vol);
-       }
-
-       if (ntfs_rl_truncate_nolock(vol, &mft_ni->runlist, old_last_vcn)) {
-               ntfs_error(vol->sb, "Failed to truncate mft data attribute "
-                               "runlist.%s", es);
-               NVolSetErrors(vol);
-       }
-       if (ctx) {
-               a = ctx->attr;
-               if (mp_rebuilt && !IS_ERR(ctx->mrec)) {
-                       if (ntfs_mapping_pairs_build(vol, (u8 *)a + le16_to_cpu(
-                               a->data.non_resident.mapping_pairs_offset),
-                               old_alen - le16_to_cpu(
-                                       a->data.non_resident.mapping_pairs_offset),
-                               rl2, ll, -1, NULL)) {
-                               ntfs_error(vol->sb, "Failed to restore mapping pairs "
-                                       "array.%s", es);
-                               NVolSetErrors(vol);
-                       }
-                       if (ntfs_attr_record_resize(ctx->mrec, a, old_alen)) {
-                               ntfs_error(vol->sb, "Failed to restore attribute "
-                                       "record.%s", es);
-                               NVolSetErrors(vol);
-                       }
-                       flush_dcache_mft_record_page(ctx->ntfs_ino);
-                       mark_mft_record_dirty(ctx->ntfs_ino);
-               } else if (IS_ERR(ctx->mrec)) {
-                       ntfs_error(vol->sb, "Failed to restore attribute search "
-                               "context.%s", es);
-                       NVolSetErrors(vol);
-               }
-               ntfs_attr_put_search_ctx(ctx);
-       }
-       if (!IS_ERR(mrec))
-               unmap_mft_record(mft_ni);
-       up_write(&mft_ni->runlist.lock);
-       return ret;
-}
-
-/**
- * ntfs_mft_record_layout - layout an mft record into a memory buffer
- * @vol:       volume to which the mft record will belong
- * @mft_no:    mft reference specifying the mft record number
- * @m:         destination buffer of size >= @vol->mft_record_size bytes
- *
- * Layout an empty, unused mft record with the mft record number @mft_no into
- * the buffer @m.  The volume @vol is needed because the mft record structure
- * was modified in NTFS 3.1 so we need to know which volume version this mft
- * record will be used on.
- *
- * Return 0 on success and -errno on error.
- */
-static int ntfs_mft_record_layout(const ntfs_volume *vol, const s64 mft_no,
-               MFT_RECORD *m)
-{
-       ATTR_RECORD *a;
-
-       ntfs_debug("Entering for mft record 0x%llx.", (long long)mft_no);
-       if (mft_no >= (1ll << 32)) {
-               ntfs_error(vol->sb, "Mft record number 0x%llx exceeds "
-                               "maximum of 2^32.", (long long)mft_no);
-               return -ERANGE;
-       }
-       /* Start by clearing the whole mft record to gives us a clean slate. */
-       memset(m, 0, vol->mft_record_size);
-       /* Aligned to 2-byte boundary. */
-       if (vol->major_ver < 3 || (vol->major_ver == 3 && !vol->minor_ver))
-               m->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD_OLD) + 1) & ~1);
-       else {
-               m->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD) + 1) & ~1);
-               /*
-                * Set the NTFS 3.1+ specific fields while we know that the
-                * volume version is 3.1+.
-                */
-               m->reserved = 0;
-               m->mft_record_number = cpu_to_le32((u32)mft_no);
-       }
-       m->magic = magic_FILE;
-       if (vol->mft_record_size >= NTFS_BLOCK_SIZE)
-               m->usa_count = cpu_to_le16(vol->mft_record_size /
-                               NTFS_BLOCK_SIZE + 1);
-       else {
-               m->usa_count = cpu_to_le16(1);
-               ntfs_warning(vol->sb, "Sector size is bigger than mft record "
-                               "size.  Setting usa_count to 1.  If chkdsk "
-                               "reports this as corruption, please email "
-                               "linux-ntfs-dev@lists.sourceforge.net stating "
-                               "that you saw this message and that the "
-                               "modified filesystem created was corrupt.  "
-                               "Thank you.");
-       }
-       /* Set the update sequence number to 1. */
-       *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs)) = cpu_to_le16(1);
-       m->lsn = 0;
-       m->sequence_number = cpu_to_le16(1);
-       m->link_count = 0;
-       /*
-        * Place the attributes straight after the update sequence array,
-        * aligned to 8-byte boundary.
-        */
-       m->attrs_offset = cpu_to_le16((le16_to_cpu(m->usa_ofs) +
-                       (le16_to_cpu(m->usa_count) << 1) + 7) & ~7);
-       m->flags = 0;
-       /*
-        * Using attrs_offset plus eight bytes (for the termination attribute).
-        * attrs_offset is already aligned to 8-byte boundary, so no need to
-        * align again.
-        */
-       m->bytes_in_use = cpu_to_le32(le16_to_cpu(m->attrs_offset) + 8);
-       m->bytes_allocated = cpu_to_le32(vol->mft_record_size);
-       m->base_mft_record = 0;
-       m->next_attr_instance = 0;
-       /* Add the termination attribute. */
-       a = (ATTR_RECORD*)((u8*)m + le16_to_cpu(m->attrs_offset));
-       a->type = AT_END;
-       a->length = 0;
-       ntfs_debug("Done.");
-       return 0;
-}
-
-/**
- * ntfs_mft_record_format - format an mft record on an ntfs volume
- * @vol:       volume on which to format the mft record
- * @mft_no:    mft record number to format
- *
- * Format the mft record @mft_no in $MFT/$DATA, i.e. lay out an empty, unused
- * mft record into the appropriate place of the mft data attribute.  This is
- * used when extending the mft data attribute.
- *
- * Return 0 on success and -errno on error.
- */
-static int ntfs_mft_record_format(const ntfs_volume *vol, const s64 mft_no)
-{
-       loff_t i_size;
-       struct inode *mft_vi = vol->mft_ino;
-       struct page *page;
-       MFT_RECORD *m;
-       pgoff_t index, end_index;
-       unsigned int ofs;
-       int err;
-
-       ntfs_debug("Entering for mft record 0x%llx.", (long long)mft_no);
-       /*
-        * The index into the page cache and the offset within the page cache
-        * page of the wanted mft record.
-        */
-       index = mft_no << vol->mft_record_size_bits >> PAGE_SHIFT;
-       ofs = (mft_no << vol->mft_record_size_bits) & ~PAGE_MASK;
-       /* The maximum valid index into the page cache for $MFT's data. */
-       i_size = i_size_read(mft_vi);
-       end_index = i_size >> PAGE_SHIFT;
-       if (unlikely(index >= end_index)) {
-               if (unlikely(index > end_index || ofs + vol->mft_record_size >=
-                               (i_size & ~PAGE_MASK))) {
-                       ntfs_error(vol->sb, "Tried to format non-existing mft "
-                                       "record 0x%llx.", (long long)mft_no);
-                       return -ENOENT;
-               }
-       }
-       /* Read, map, and pin the page containing the mft record. */
-       page = ntfs_map_page(mft_vi->i_mapping, index);
-       if (IS_ERR(page)) {
-               ntfs_error(vol->sb, "Failed to map page containing mft record "
-                               "to format 0x%llx.", (long long)mft_no);
-               return PTR_ERR(page);
-       }
-       lock_page(page);
-       BUG_ON(!PageUptodate(page));
-       ClearPageUptodate(page);
-       m = (MFT_RECORD*)((u8*)page_address(page) + ofs);
-       err = ntfs_mft_record_layout(vol, mft_no, m);
-       if (unlikely(err)) {
-               ntfs_error(vol->sb, "Failed to layout mft record 0x%llx.",
-                               (long long)mft_no);
-               SetPageUptodate(page);
-               unlock_page(page);
-               ntfs_unmap_page(page);
-               return err;
-       }
-       flush_dcache_page(page);
-       SetPageUptodate(page);
-       unlock_page(page);
-       /*
-        * Make sure the mft record is written out to disk.  We could use
-        * ilookup5() to check if an inode is in icache and so on but this is
-        * unnecessary as ntfs_writepage() will write the dirty record anyway.
-        */
-       mark_ntfs_record_dirty(page, ofs);
-       ntfs_unmap_page(page);
-       ntfs_debug("Done.");
-       return 0;
-}
-
-/**
- * ntfs_mft_record_alloc - allocate an mft record on an ntfs volume
- * @vol:       [IN]  volume on which to allocate the mft record
- * @mode:      [IN]  mode if want a file or directory, i.e. base inode or 0
- * @base_ni:   [IN]  open base inode if allocating an extent mft record or NULL
- * @mrec:      [OUT] on successful return this is the mapped mft record
- *
- * Allocate an mft record in $MFT/$DATA of an open ntfs volume @vol.
- *
- * If @base_ni is NULL make the mft record a base mft record, i.e. a file or
- * direvctory inode, and allocate it at the default allocator position.  In
- * this case @mode is the file mode as given to us by the caller.  We in
- * particular use @mode to distinguish whether a file or a directory is being
- * created (S_IFDIR(mode) and S_IFREG(mode), respectively).
- *
- * If @base_ni is not NULL make the allocated mft record an extent record,
- * allocate it starting at the mft record after the base mft record and attach
- * the allocated and opened ntfs inode to the base inode @base_ni.  In this
- * case @mode must be 0 as it is meaningless for extent inodes.
- *
- * You need to check the return value with IS_ERR().  If false, the function
- * was successful and the return value is the now opened ntfs inode of the
- * allocated mft record.  *@mrec is then set to the allocated, mapped, pinned,
- * and locked mft record.  If IS_ERR() is true, the function failed and the
- * error code is obtained from PTR_ERR(return value).  *@mrec is undefined in
- * this case.
- *
- * Allocation strategy:
- *
- * To find a free mft record, we scan the mft bitmap for a zero bit.  To
- * optimize this we start scanning at the place specified by @base_ni or if
- * @base_ni is NULL we start where we last stopped and we perform wrap around
- * when we reach the end.  Note, we do not try to allocate mft records below
- * number 24 because numbers 0 to 15 are the defined system files anyway and 16
- * to 24 are special in that they are used for storing extension mft records
- * for the $DATA attribute of $MFT.  This is required to avoid the possibility
- * of creating a runlist with a circular dependency which once written to disk
- * can never be read in again.  Windows will only use records 16 to 24 for
- * normal files if the volume is completely out of space.  We never use them
- * which means that when the volume is really out of space we cannot create any
- * more files while Windows can still create up to 8 small files.  We can start
- * doing this at some later time, it does not matter much for now.
- *
- * When scanning the mft bitmap, we only search up to the last allocated mft
- * record.  If there are no free records left in the range 24 to number of
- * allocated mft records, then we extend the $MFT/$DATA attribute in order to
- * create free mft records.  We extend the allocated size of $MFT/$DATA by 16
- * records at a time or one cluster, if cluster size is above 16kiB.  If there
- * is not sufficient space to do this, we try to extend by a single mft record
- * or one cluster, if cluster size is above the mft record size.
- *
- * No matter how many mft records we allocate, we initialize only the first
- * allocated mft record, incrementing mft data size and initialized size
- * accordingly, open an ntfs_inode for it and return it to the caller, unless
- * there are less than 24 mft records, in which case we allocate and initialize
- * mft records until we reach record 24 which we consider as the first free mft
- * record for use by normal files.
- *
- * If during any stage we overflow the initialized data in the mft bitmap, we
- * extend the initialized size (and data size) by 8 bytes, allocating another
- * cluster if required.  The bitmap data size has to be at least equal to the
- * number of mft records in the mft, but it can be bigger, in which case the
- * superflous bits are padded with zeroes.
- *
- * Thus, when we return successfully (IS_ERR() is false), we will have:
- *     - initialized / extended the mft bitmap if necessary,
- *     - initialized / extended the mft data if necessary,
- *     - set the bit corresponding to the mft record being allocated in the
- *       mft bitmap,
- *     - opened an ntfs_inode for the allocated mft record, and we will have
- *     - returned the ntfs_inode as well as the allocated mapped, pinned, and
- *       locked mft record.
- *
- * On error, the volume will be left in a consistent state and no record will
- * be allocated.  If rolling back a partial operation fails, we may leave some
- * inconsistent metadata in which case we set NVolErrors() so the volume is
- * left dirty when unmounted.
- *
- * Note, this function cannot make use of most of the normal functions, like
- * for example for attribute resizing, etc, because when the run list overflows
- * the base mft record and an attribute list is used, it is very important that
- * the extension mft records used to store the $DATA attribute of $MFT can be
- * reached without having to read the information contained inside them, as
- * this would make it impossible to find them in the first place after the
- * volume is unmounted.  $MFT/$BITMAP probably does not need to follow this
- * rule because the bitmap is not essential for finding the mft records, but on
- * the other hand, handling the bitmap in this special way would make life
- * easier because otherwise there might be circular invocations of functions
- * when reading the bitmap.
- */
-ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, const int mode,
-               ntfs_inode *base_ni, MFT_RECORD **mrec)
-{
-       s64 ll, bit, old_data_initialized, old_data_size;
-       unsigned long flags;
-       struct inode *vi;
-       struct page *page;
-       ntfs_inode *mft_ni, *mftbmp_ni, *ni;
-       ntfs_attr_search_ctx *ctx;
-       MFT_RECORD *m;
-       ATTR_RECORD *a;
-       pgoff_t index;
-       unsigned int ofs;
-       int err;
-       le16 seq_no, usn;
-       bool record_formatted = false;
-
-       if (base_ni) {
-               ntfs_debug("Entering (allocating an extent mft record for "
-                               "base mft record 0x%llx).",
-                               (long long)base_ni->mft_no);
-               /* @mode and @base_ni are mutually exclusive. */
-               BUG_ON(mode);
-       } else
-               ntfs_debug("Entering (allocating a base mft record).");
-       if (mode) {
-               /* @mode and @base_ni are mutually exclusive. */
-               BUG_ON(base_ni);
-               /* We only support creation of normal files and directories. */
-               if (!S_ISREG(mode) && !S_ISDIR(mode))
-                       return ERR_PTR(-EOPNOTSUPP);
-       }
-       BUG_ON(!mrec);
-       mft_ni = NTFS_I(vol->mft_ino);
-       mftbmp_ni = NTFS_I(vol->mftbmp_ino);
-       down_write(&vol->mftbmp_lock);
-       bit = ntfs_mft_bitmap_find_and_alloc_free_rec_nolock(vol, base_ni);
-       if (bit >= 0) {
-               ntfs_debug("Found and allocated free record (#1), bit 0x%llx.",
-                               (long long)bit);
-               goto have_alloc_rec;
-       }
-       if (bit != -ENOSPC) {
-               up_write(&vol->mftbmp_lock);
-               return ERR_PTR(bit);
-       }
-       /*
-        * No free mft records left.  If the mft bitmap already covers more
-        * than the currently used mft records, the next records are all free,
-        * so we can simply allocate the first unused mft record.
-        * Note: We also have to make sure that the mft bitmap at least covers
-        * the first 24 mft records as they are special and whilst they may not
-        * be in use, we do not allocate from them.
-        */
-       read_lock_irqsave(&mft_ni->size_lock, flags);
-       ll = mft_ni->initialized_size >> vol->mft_record_size_bits;
-       read_unlock_irqrestore(&mft_ni->size_lock, flags);
-       read_lock_irqsave(&mftbmp_ni->size_lock, flags);
-       old_data_initialized = mftbmp_ni->initialized_size;
-       read_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
-       if (old_data_initialized << 3 > ll && old_data_initialized > 3) {
-               bit = ll;
-               if (bit < 24)
-                       bit = 24;
-               if (unlikely(bit >= (1ll << 32)))
-                       goto max_err_out;
-               ntfs_debug("Found free record (#2), bit 0x%llx.",
-                               (long long)bit);
-               goto found_free_rec;
-       }
-       /*
-        * The mft bitmap needs to be expanded until it covers the first unused
-        * mft record that we can allocate.
-        * Note: The smallest mft record we allocate is mft record 24.
-        */
-       bit = old_data_initialized << 3;
-       if (unlikely(bit >= (1ll << 32)))
-               goto max_err_out;
-       read_lock_irqsave(&mftbmp_ni->size_lock, flags);
-       old_data_size = mftbmp_ni->allocated_size;
-       ntfs_debug("Status of mftbmp before extension: allocated_size 0x%llx, "
-                       "data_size 0x%llx, initialized_size 0x%llx.",
-                       (long long)old_data_size,
-                       (long long)i_size_read(vol->mftbmp_ino),
-                       (long long)old_data_initialized);
-       read_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
-       if (old_data_initialized + 8 > old_data_size) {
-               /* Need to extend bitmap by one more cluster. */
-               ntfs_debug("mftbmp: initialized_size + 8 > allocated_size.");
-               err = ntfs_mft_bitmap_extend_allocation_nolock(vol);
-               if (unlikely(err)) {
-                       up_write(&vol->mftbmp_lock);
-                       goto err_out;
-               }
-#ifdef DEBUG
-               read_lock_irqsave(&mftbmp_ni->size_lock, flags);
-               ntfs_debug("Status of mftbmp after allocation extension: "
-                               "allocated_size 0x%llx, data_size 0x%llx, "
-                               "initialized_size 0x%llx.",
-                               (long long)mftbmp_ni->allocated_size,
-                               (long long)i_size_read(vol->mftbmp_ino),
-                               (long long)mftbmp_ni->initialized_size);
-               read_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
-#endif /* DEBUG */
-       }
-       /*
-        * We now have sufficient allocated space, extend the initialized_size
-        * as well as the data_size if necessary and fill the new space with
-        * zeroes.
-        */
-       err = ntfs_mft_bitmap_extend_initialized_nolock(vol);
-       if (unlikely(err)) {
-               up_write(&vol->mftbmp_lock);
-               goto err_out;
-       }
-#ifdef DEBUG
-       read_lock_irqsave(&mftbmp_ni->size_lock, flags);
-       ntfs_debug("Status of mftbmp after initialized extension: "
-                       "allocated_size 0x%llx, data_size 0x%llx, "
-                       "initialized_size 0x%llx.",
-                       (long long)mftbmp_ni->allocated_size,
-                       (long long)i_size_read(vol->mftbmp_ino),
-                       (long long)mftbmp_ni->initialized_size);
-       read_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
-#endif /* DEBUG */
-       ntfs_debug("Found free record (#3), bit 0x%llx.", (long long)bit);
-found_free_rec:
-       /* @bit is the found free mft record, allocate it in the mft bitmap. */
-       ntfs_debug("At found_free_rec.");
-       err = ntfs_bitmap_set_bit(vol->mftbmp_ino, bit);
-       if (unlikely(err)) {
-               ntfs_error(vol->sb, "Failed to allocate bit in mft bitmap.");
-               up_write(&vol->mftbmp_lock);
-               goto err_out;
-       }
-       ntfs_debug("Set bit 0x%llx in mft bitmap.", (long long)bit);
-have_alloc_rec:
-       /*
-        * The mft bitmap is now uptodate.  Deal with mft data attribute now.
-        * Note, we keep hold of the mft bitmap lock for writing until all
-        * modifications to the mft data attribute are complete, too, as they
-        * will impact decisions for mft bitmap and mft record allocation done
-        * by a parallel allocation and if the lock is not maintained a
-        * parallel allocation could allocate the same mft record as this one.
-        */
-       ll = (bit + 1) << vol->mft_record_size_bits;
-       read_lock_irqsave(&mft_ni->size_lock, flags);
-       old_data_initialized = mft_ni->initialized_size;
-       read_unlock_irqrestore(&mft_ni->size_lock, flags);
-       if (ll <= old_data_initialized) {
-               ntfs_debug("Allocated mft record already initialized.");
-               goto mft_rec_already_initialized;
-       }
-       ntfs_debug("Initializing allocated mft record.");
-       /*
-        * The mft record is outside the initialized data.  Extend the mft data
-        * attribute until it covers the allocated record.  The loop is only
-        * actually traversed more than once when a freshly formatted volume is
-        * first written to so it optimizes away nicely in the common case.
-        */
-       read_lock_irqsave(&mft_ni->size_lock, flags);
-       ntfs_debug("Status of mft data before extension: "
-                       "allocated_size 0x%llx, data_size 0x%llx, "
-                       "initialized_size 0x%llx.",
-                       (long long)mft_ni->allocated_size,
-                       (long long)i_size_read(vol->mft_ino),
-                       (long long)mft_ni->initialized_size);
-       while (ll > mft_ni->allocated_size) {
-               read_unlock_irqrestore(&mft_ni->size_lock, flags);
-               err = ntfs_mft_data_extend_allocation_nolock(vol);
-               if (unlikely(err)) {
-                       ntfs_error(vol->sb, "Failed to extend mft data "
-                                       "allocation.");
-                       goto undo_mftbmp_alloc_nolock;
-               }
-               read_lock_irqsave(&mft_ni->size_lock, flags);
-               ntfs_debug("Status of mft data after allocation extension: "
-                               "allocated_size 0x%llx, data_size 0x%llx, "
-                               "initialized_size 0x%llx.",
-                               (long long)mft_ni->allocated_size,
-                               (long long)i_size_read(vol->mft_ino),
-                               (long long)mft_ni->initialized_size);
-       }
-       read_unlock_irqrestore(&mft_ni->size_lock, flags);
-       /*
-        * Extend mft data initialized size (and data size of course) to reach
-        * the allocated mft record, formatting the mft records allong the way.
-        * Note: We only modify the ntfs_inode structure as that is all that is
-        * needed by ntfs_mft_record_format().  We will update the attribute
-        * record itself in one fell swoop later on.
-        */
-       write_lock_irqsave(&mft_ni->size_lock, flags);
-       old_data_initialized = mft_ni->initialized_size;
-       old_data_size = vol->mft_ino->i_size;
-       while (ll > mft_ni->initialized_size) {
-               s64 new_initialized_size, mft_no;
-               
-               new_initialized_size = mft_ni->initialized_size +
-                               vol->mft_record_size;
-               mft_no = mft_ni->initialized_size >> vol->mft_record_size_bits;
-               if (new_initialized_size > i_size_read(vol->mft_ino))
-                       i_size_write(vol->mft_ino, new_initialized_size);
-               write_unlock_irqrestore(&mft_ni->size_lock, flags);
-               ntfs_debug("Initializing mft record 0x%llx.",
-                               (long long)mft_no);
-               err = ntfs_mft_record_format(vol, mft_no);
-               if (unlikely(err)) {
-                       ntfs_error(vol->sb, "Failed to format mft record.");
-                       goto undo_data_init;
-               }
-               write_lock_irqsave(&mft_ni->size_lock, flags);
-               mft_ni->initialized_size = new_initialized_size;
-       }
-       write_unlock_irqrestore(&mft_ni->size_lock, flags);
-       record_formatted = true;
-       /* Update the mft data attribute record to reflect the new sizes. */
-       m = map_mft_record(mft_ni);
-       if (IS_ERR(m)) {
-               ntfs_error(vol->sb, "Failed to map mft record.");
-               err = PTR_ERR(m);
-               goto undo_data_init;
-       }
-       ctx = ntfs_attr_get_search_ctx(mft_ni, m);
-       if (unlikely(!ctx)) {
-               ntfs_error(vol->sb, "Failed to get search context.");
-               err = -ENOMEM;
-               unmap_mft_record(mft_ni);
-               goto undo_data_init;
-       }
-       err = ntfs_attr_lookup(mft_ni->type, mft_ni->name, mft_ni->name_len,
-                       CASE_SENSITIVE, 0, NULL, 0, ctx);
-       if (unlikely(err)) {
-               ntfs_error(vol->sb, "Failed to find first attribute extent of "
-                               "mft data attribute.");
-               ntfs_attr_put_search_ctx(ctx);
-               unmap_mft_record(mft_ni);
-               goto undo_data_init;
-       }
-       a = ctx->attr;
-       read_lock_irqsave(&mft_ni->size_lock, flags);
-       a->data.non_resident.initialized_size =
-                       cpu_to_sle64(mft_ni->initialized_size);
-       a->data.non_resident.data_size =
-                       cpu_to_sle64(i_size_read(vol->mft_ino));
-       read_unlock_irqrestore(&mft_ni->size_lock, flags);
-       /* Ensure the changes make it to disk. */
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(mft_ni);
-       read_lock_irqsave(&mft_ni->size_lock, flags);
-       ntfs_debug("Status of mft data after mft record initialization: "
-                       "allocated_size 0x%llx, data_size 0x%llx, "
-                       "initialized_size 0x%llx.",
-                       (long long)mft_ni->allocated_size,
-                       (long long)i_size_read(vol->mft_ino),
-                       (long long)mft_ni->initialized_size);
-       BUG_ON(i_size_read(vol->mft_ino) > mft_ni->allocated_size);
-       BUG_ON(mft_ni->initialized_size > i_size_read(vol->mft_ino));
-       read_unlock_irqrestore(&mft_ni->size_lock, flags);
-mft_rec_already_initialized:
-       /*
-        * We can finally drop the mft bitmap lock as the mft data attribute
-        * has been fully updated.  The only disparity left is that the
-        * allocated mft record still needs to be marked as in use to match the
-        * set bit in the mft bitmap but this is actually not a problem since
-        * this mft record is not referenced from anywhere yet and the fact
-        * that it is allocated in the mft bitmap means that no-one will try to
-        * allocate it either.
-        */
-       up_write(&vol->mftbmp_lock);
-       /*
-        * We now have allocated and initialized the mft record.  Calculate the
-        * index of and the offset within the page cache page the record is in.
-        */
-       index = bit << vol->mft_record_size_bits >> PAGE_SHIFT;
-       ofs = (bit << vol->mft_record_size_bits) & ~PAGE_MASK;
-       /* Read, map, and pin the page containing the mft record. */
-       page = ntfs_map_page(vol->mft_ino->i_mapping, index);
-       if (IS_ERR(page)) {
-               ntfs_error(vol->sb, "Failed to map page containing allocated "
-                               "mft record 0x%llx.", (long long)bit);
-               err = PTR_ERR(page);
-               goto undo_mftbmp_alloc;
-       }
-       lock_page(page);
-       BUG_ON(!PageUptodate(page));
-       ClearPageUptodate(page);
-       m = (MFT_RECORD*)((u8*)page_address(page) + ofs);
-       /* If we just formatted the mft record no need to do it again. */
-       if (!record_formatted) {
-               /* Sanity check that the mft record is really not in use. */
-               if (ntfs_is_file_record(m->magic) &&
-                               (m->flags & MFT_RECORD_IN_USE)) {
-                       ntfs_error(vol->sb, "Mft record 0x%llx was marked "
-                                       "free in mft bitmap but is marked "
-                                       "used itself.  Corrupt filesystem.  "
-                                       "Unmount and run chkdsk.",
-                                       (long long)bit);
-                       err = -EIO;
-                       SetPageUptodate(page);
-                       unlock_page(page);
-                       ntfs_unmap_page(page);
-                       NVolSetErrors(vol);
-                       goto undo_mftbmp_alloc;
-               }
-               /*
-                * We need to (re-)format the mft record, preserving the
-                * sequence number if it is not zero as well as the update
-                * sequence number if it is not zero or -1 (0xffff).  This
-                * means we do not need to care whether or not something went
-                * wrong with the previous mft record.
-                */
-               seq_no = m->sequence_number;
-               usn = *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs));
-               err = ntfs_mft_record_layout(vol, bit, m);
-               if (unlikely(err)) {
-                       ntfs_error(vol->sb, "Failed to layout allocated mft "
-                                       "record 0x%llx.", (long long)bit);
-                       SetPageUptodate(page);
-                       unlock_page(page);
-                       ntfs_unmap_page(page);
-                       goto undo_mftbmp_alloc;
-               }
-               if (seq_no)
-                       m->sequence_number = seq_no;
-               if (usn && le16_to_cpu(usn) != 0xffff)
-                       *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs)) = usn;
-       }
-       /* Set the mft record itself in use. */
-       m->flags |= MFT_RECORD_IN_USE;
-       if (S_ISDIR(mode))
-               m->flags |= MFT_RECORD_IS_DIRECTORY;
-       flush_dcache_page(page);
-       SetPageUptodate(page);
-       if (base_ni) {
-               MFT_RECORD *m_tmp;
-
-               /*
-                * Setup the base mft record in the extent mft record.  This
-                * completes initialization of the allocated extent mft record
-                * and we can simply use it with map_extent_mft_record().
-                */
-               m->base_mft_record = MK_LE_MREF(base_ni->mft_no,
-                               base_ni->seq_no);
-               /*
-                * Allocate an extent inode structure for the new mft record,
-                * attach it to the base inode @base_ni and map, pin, and lock
-                * its, i.e. the allocated, mft record.
-                */
-               m_tmp = map_extent_mft_record(base_ni, bit, &ni);
-               if (IS_ERR(m_tmp)) {
-                       ntfs_error(vol->sb, "Failed to map allocated extent "
-                                       "mft record 0x%llx.", (long long)bit);
-                       err = PTR_ERR(m_tmp);
-                       /* Set the mft record itself not in use. */
-                       m->flags &= cpu_to_le16(
-                                       ~le16_to_cpu(MFT_RECORD_IN_USE));
-                       flush_dcache_page(page);
-                       /* Make sure the mft record is written out to disk. */
-                       mark_ntfs_record_dirty(page, ofs);
-                       unlock_page(page);
-                       ntfs_unmap_page(page);
-                       goto undo_mftbmp_alloc;
-               }
-               BUG_ON(m != m_tmp);
-               /*
-                * Make sure the allocated mft record is written out to disk.
-                * No need to set the inode dirty because the caller is going
-                * to do that anyway after finishing with the new extent mft
-                * record (e.g. at a minimum a new attribute will be added to
-                * the mft record.
-                */
-               mark_ntfs_record_dirty(page, ofs);
-               unlock_page(page);
-               /*
-                * Need to unmap the page since map_extent_mft_record() mapped
-                * it as well so we have it mapped twice at the moment.
-                */
-               ntfs_unmap_page(page);
-       } else {
-               /*
-                * Allocate a new VFS inode and set it up.  NOTE: @vi->i_nlink
-                * is set to 1 but the mft record->link_count is 0.  The caller
-                * needs to bear this in mind.
-                */
-               vi = new_inode(vol->sb);
-               if (unlikely(!vi)) {
-                       err = -ENOMEM;
-                       /* Set the mft record itself not in use. */
-                       m->flags &= cpu_to_le16(
-                                       ~le16_to_cpu(MFT_RECORD_IN_USE));
-                       flush_dcache_page(page);
-                       /* Make sure the mft record is written out to disk. */
-                       mark_ntfs_record_dirty(page, ofs);
-                       unlock_page(page);
-                       ntfs_unmap_page(page);
-                       goto undo_mftbmp_alloc;
-               }
-               vi->i_ino = bit;
-
-               /* The owner and group come from the ntfs volume. */
-               vi->i_uid = vol->uid;
-               vi->i_gid = vol->gid;
-
-               /* Initialize the ntfs specific part of @vi. */
-               ntfs_init_big_inode(vi);
-               ni = NTFS_I(vi);
-               /*
-                * Set the appropriate mode, attribute type, and name.  For
-                * directories, also setup the index values to the defaults.
-                */
-               if (S_ISDIR(mode)) {
-                       vi->i_mode = S_IFDIR | S_IRWXUGO;
-                       vi->i_mode &= ~vol->dmask;
-
-                       NInoSetMstProtected(ni);
-                       ni->type = AT_INDEX_ALLOCATION;
-                       ni->name = I30;
-                       ni->name_len = 4;
-
-                       ni->itype.index.block_size = 4096;
-                       ni->itype.index.block_size_bits = ntfs_ffs(4096) - 1;
-                       ni->itype.index.collation_rule = COLLATION_FILE_NAME;
-                       if (vol->cluster_size <= ni->itype.index.block_size) {
-                               ni->itype.index.vcn_size = vol->cluster_size;
-                               ni->itype.index.vcn_size_bits =
-                                               vol->cluster_size_bits;
-                       } else {
-                               ni->itype.index.vcn_size = vol->sector_size;
-                               ni->itype.index.vcn_size_bits =
-                                               vol->sector_size_bits;
-                       }
-               } else {
-                       vi->i_mode = S_IFREG | S_IRWXUGO;
-                       vi->i_mode &= ~vol->fmask;
-
-                       ni->type = AT_DATA;
-                       ni->name = NULL;
-                       ni->name_len = 0;
-               }
-               if (IS_RDONLY(vi))
-                       vi->i_mode &= ~S_IWUGO;
-
-               /* Set the inode times to the current time. */
-               simple_inode_init_ts(vi);
-               /*
-                * Set the file size to 0, the ntfs inode sizes are set to 0 by
-                * the call to ntfs_init_big_inode() below.
-                */
-               vi->i_size = 0;
-               vi->i_blocks = 0;
-
-               /* Set the sequence number. */
-               vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
-               /*
-                * Manually map, pin, and lock the mft record as we already
-                * have its page mapped and it is very easy to do.
-                */
-               atomic_inc(&ni->count);
-               mutex_lock(&ni->mrec_lock);
-               ni->page = page;
-               ni->page_ofs = ofs;
-               /*
-                * Make sure the allocated mft record is written out to disk.
-                * NOTE: We do not set the ntfs inode dirty because this would
-                * fail in ntfs_write_inode() because the inode does not have a
-                * standard information attribute yet.  Also, there is no need
-                * to set the inode dirty because the caller is going to do
-                * that anyway after finishing with the new mft record (e.g. at
-                * a minimum some new attributes will be added to the mft
-                * record.
-                */
-               mark_ntfs_record_dirty(page, ofs);
-               unlock_page(page);
-
-               /* Add the inode to the inode hash for the superblock. */
-               insert_inode_hash(vi);
-
-               /* Update the default mft allocation position. */
-               vol->mft_data_pos = bit + 1;
-       }
-       /*
-        * Return the opened, allocated inode of the allocated mft record as
-        * well as the mapped, pinned, and locked mft record.
-        */
-       ntfs_debug("Returning opened, allocated %sinode 0x%llx.",
-                       base_ni ? "extent " : "", (long long)bit);
-       *mrec = m;
-       return ni;
-undo_data_init:
-       write_lock_irqsave(&mft_ni->size_lock, flags);
-       mft_ni->initialized_size = old_data_initialized;
-       i_size_write(vol->mft_ino, old_data_size);
-       write_unlock_irqrestore(&mft_ni->size_lock, flags);
-       goto undo_mftbmp_alloc_nolock;
-undo_mftbmp_alloc:
-       down_write(&vol->mftbmp_lock);
-undo_mftbmp_alloc_nolock:
-       if (ntfs_bitmap_clear_bit(vol->mftbmp_ino, bit)) {
-               ntfs_error(vol->sb, "Failed to clear bit in mft bitmap.%s", es);
-               NVolSetErrors(vol);
-       }
-       up_write(&vol->mftbmp_lock);
-err_out:
-       return ERR_PTR(err);
-max_err_out:
-       ntfs_warning(vol->sb, "Cannot allocate mft record because the maximum "
-                       "number of inodes (2^32) has already been reached.");
-       up_write(&vol->mftbmp_lock);
-       return ERR_PTR(-ENOSPC);
-}
-
-/**
- * ntfs_extent_mft_record_free - free an extent mft record on an ntfs volume
- * @ni:                ntfs inode of the mapped extent mft record to free
- * @m:         mapped extent mft record of the ntfs inode @ni
- *
- * Free the mapped extent mft record @m of the extent ntfs inode @ni.
- *
- * Note that this function unmaps the mft record and closes and destroys @ni
- * internally and hence you cannot use either @ni nor @m any more after this
- * function returns success.
- *
- * On success return 0 and on error return -errno.  @ni and @m are still valid
- * in this case and have not been freed.
- *
- * For some errors an error message is displayed and the success code 0 is
- * returned and the volume is then left dirty on umount.  This makes sense in
- * case we could not rollback the changes that were already done since the
- * caller no longer wants to reference this mft record so it does not matter to
- * the caller if something is wrong with it as long as it is properly detached
- * from the base inode.
- */
-int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
-{
-       unsigned long mft_no = ni->mft_no;
-       ntfs_volume *vol = ni->vol;
-       ntfs_inode *base_ni;
-       ntfs_inode **extent_nis;
-       int i, err;
-       le16 old_seq_no;
-       u16 seq_no;
-       
-       BUG_ON(NInoAttr(ni));
-       BUG_ON(ni->nr_extents != -1);
-
-       mutex_lock(&ni->extent_lock);
-       base_ni = ni->ext.base_ntfs_ino;
-       mutex_unlock(&ni->extent_lock);
-
-       BUG_ON(base_ni->nr_extents <= 0);
-
-       ntfs_debug("Entering for extent inode 0x%lx, base inode 0x%lx.\n",
-                       mft_no, base_ni->mft_no);
-
-       mutex_lock(&base_ni->extent_lock);
-
-       /* Make sure we are holding the only reference to the extent inode. */
-       if (atomic_read(&ni->count) > 2) {
-               ntfs_error(vol->sb, "Tried to free busy extent inode 0x%lx, "
-                               "not freeing.", base_ni->mft_no);
-               mutex_unlock(&base_ni->extent_lock);
-               return -EBUSY;
-       }
-
-       /* Dissociate the ntfs inode from the base inode. */
-       extent_nis = base_ni->ext.extent_ntfs_inos;
-       err = -ENOENT;
-       for (i = 0; i < base_ni->nr_extents; i++) {
-               if (ni != extent_nis[i])
-                       continue;
-               extent_nis += i;
-               base_ni->nr_extents--;
-               memmove(extent_nis, extent_nis + 1, (base_ni->nr_extents - i) *
-                               sizeof(ntfs_inode*));
-               err = 0;
-               break;
-       }
-
-       mutex_unlock(&base_ni->extent_lock);
-
-       if (unlikely(err)) {
-               ntfs_error(vol->sb, "Extent inode 0x%lx is not attached to "
-                               "its base inode 0x%lx.", mft_no,
-                               base_ni->mft_no);
-               BUG();
-       }
-
-       /*
-        * The extent inode is no longer attached to the base inode so no one
-        * can get a reference to it any more.
-        */
-
-       /* Mark the mft record as not in use. */
-       m->flags &= ~MFT_RECORD_IN_USE;
-
-       /* Increment the sequence number, skipping zero, if it is not zero. */
-       old_seq_no = m->sequence_number;
-       seq_no = le16_to_cpu(old_seq_no);
-       if (seq_no == 0xffff)
-               seq_no = 1;
-       else if (seq_no)
-               seq_no++;
-       m->sequence_number = cpu_to_le16(seq_no);
-
-       /*
-        * Set the ntfs inode dirty and write it out.  We do not need to worry
-        * about the base inode here since whatever caused the extent mft
-        * record to be freed is guaranteed to do it already.
-        */
-       NInoSetDirty(ni);
-       err = write_mft_record(ni, m, 0);
-       if (unlikely(err)) {
-               ntfs_error(vol->sb, "Failed to write mft record 0x%lx, not "
-                               "freeing.", mft_no);
-               goto rollback;
-       }
-rollback_error:
-       /* Unmap and throw away the now freed extent inode. */
-       unmap_extent_mft_record(ni);
-       ntfs_clear_extent_inode(ni);
-
-       /* Clear the bit in the $MFT/$BITMAP corresponding to this record. */
-       down_write(&vol->mftbmp_lock);
-       err = ntfs_bitmap_clear_bit(vol->mftbmp_ino, mft_no);
-       up_write(&vol->mftbmp_lock);
-       if (unlikely(err)) {
-               /*
-                * The extent inode is gone but we failed to deallocate it in
-                * the mft bitmap.  Just emit a warning and leave the volume
-                * dirty on umount.
-                */
-               ntfs_error(vol->sb, "Failed to clear bit in mft bitmap.%s", es);
-               NVolSetErrors(vol);
-       }
-       return 0;
-rollback:
-       /* Rollback what we did... */
-       mutex_lock(&base_ni->extent_lock);
-       extent_nis = base_ni->ext.extent_ntfs_inos;
-       if (!(base_ni->nr_extents & 3)) {
-               int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode*);
-
-               extent_nis = kmalloc(new_size, GFP_NOFS);
-               if (unlikely(!extent_nis)) {
-                       ntfs_error(vol->sb, "Failed to allocate internal "
-                                       "buffer during rollback.%s", es);
-                       mutex_unlock(&base_ni->extent_lock);
-                       NVolSetErrors(vol);
-                       goto rollback_error;
-               }
-               if (base_ni->nr_extents) {
-                       BUG_ON(!base_ni->ext.extent_ntfs_inos);
-                       memcpy(extent_nis, base_ni->ext.extent_ntfs_inos,
-                                       new_size - 4 * sizeof(ntfs_inode*));
-                       kfree(base_ni->ext.extent_ntfs_inos);
-               }
-               base_ni->ext.extent_ntfs_inos = extent_nis;
-       }
-       m->flags |= MFT_RECORD_IN_USE;
-       m->sequence_number = old_seq_no;
-       extent_nis[base_ni->nr_extents++] = ni;
-       mutex_unlock(&base_ni->extent_lock);
-       mark_mft_record_dirty(ni);
-       return err;
-}
-#endif /* NTFS_RW */
diff --git a/fs/ntfs/mft.h b/fs/ntfs/mft.h
deleted file mode 100644 (file)
index 49c001a..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * mft.h - Defines for mft record handling in NTFS Linux kernel driver.
- *        Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2004 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_MFT_H
-#define _LINUX_NTFS_MFT_H
-
-#include <linux/fs.h>
-#include <linux/highmem.h>
-#include <linux/pagemap.h>
-
-#include "inode.h"
-
-extern MFT_RECORD *map_mft_record(ntfs_inode *ni);
-extern void unmap_mft_record(ntfs_inode *ni);
-
-extern MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
-               ntfs_inode **ntfs_ino);
-
-static inline void unmap_extent_mft_record(ntfs_inode *ni)
-{
-       unmap_mft_record(ni);
-       return;
-}
-
-#ifdef NTFS_RW
-
-/**
- * flush_dcache_mft_record_page - flush_dcache_page() for mft records
- * @ni:                ntfs inode structure of mft record
- *
- * Call flush_dcache_page() for the page in which an mft record resides.
- *
- * This must be called every time an mft record is modified, just after the
- * modification.
- */
-static inline void flush_dcache_mft_record_page(ntfs_inode *ni)
-{
-       flush_dcache_page(ni->page);
-}
-
-extern void __mark_mft_record_dirty(ntfs_inode *ni);
-
-/**
- * mark_mft_record_dirty - set the mft record and the page containing it dirty
- * @ni:                ntfs inode describing the mapped mft record
- *
- * Set the mapped (extent) mft record of the (base or extent) ntfs inode @ni,
- * as well as the page containing the mft record, dirty.  Also, mark the base
- * vfs inode dirty.  This ensures that any changes to the mft record are
- * written out to disk.
- *
- * NOTE:  Do not do anything if the mft record is already marked dirty.
- */
-static inline void mark_mft_record_dirty(ntfs_inode *ni)
-{
-       if (!NInoTestSetDirty(ni))
-               __mark_mft_record_dirty(ni);
-}
-
-extern int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no,
-               MFT_RECORD *m, int sync);
-
-extern int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync);
-
-/**
- * write_mft_record - write out a mapped (extent) mft record
- * @ni:                ntfs inode describing the mapped (extent) mft record
- * @m:         mapped (extent) mft record to write
- * @sync:      if true, wait for i/o completion
- *
- * This is just a wrapper for write_mft_record_nolock() (see mft.c), which
- * locks the page for the duration of the write.  This ensures that there are
- * no race conditions between writing the mft record via the dirty inode code
- * paths and via the page cache write back code paths or between writing
- * neighbouring mft records residing in the same page.
- *
- * Locking the page also serializes us against ->read_folio() if the page is not
- * uptodate.
- *
- * On success, clean the mft record and return 0.  On error, leave the mft
- * record dirty and return -errno.
- */
-static inline int write_mft_record(ntfs_inode *ni, MFT_RECORD *m, int sync)
-{
-       struct page *page = ni->page;
-       int err;
-
-       BUG_ON(!page);
-       lock_page(page);
-       err = write_mft_record_nolock(ni, m, sync);
-       unlock_page(page);
-       return err;
-}
-
-extern bool ntfs_may_write_mft_record(ntfs_volume *vol,
-               const unsigned long mft_no, const MFT_RECORD *m,
-               ntfs_inode **locked_ni);
-
-extern ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, const int mode,
-               ntfs_inode *base_ni, MFT_RECORD **mrec);
-extern int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m);
-
-#endif /* NTFS_RW */
-
-#endif /* _LINUX_NTFS_MFT_H */
diff --git a/fs/ntfs/mst.c b/fs/ntfs/mst.c
deleted file mode 100644 (file)
index 16b3c88..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * mst.c - NTFS multi sector transfer protection handling code. Part of the
- *        Linux-NTFS project.
- *
- * Copyright (c) 2001-2004 Anton Altaparmakov
- */
-
-#include "ntfs.h"
-
-/**
- * post_read_mst_fixup - deprotect multi sector transfer protected data
- * @b:         pointer to the data to deprotect
- * @size:      size in bytes of @b
- *
- * Perform the necessary post read multi sector transfer fixup and detect the
- * presence of incomplete multi sector transfers. - In that case, overwrite the
- * magic of the ntfs record header being processed with "BAAD" (in memory only!)
- * and abort processing.
- *
- * Return 0 on success and -EINVAL on error ("BAAD" magic will be present).
- *
- * NOTE: We consider the absence / invalidity of an update sequence array to
- * mean that the structure is not protected at all and hence doesn't need to
- * be fixed up. Thus, we return success and not failure in this case. This is
- * in contrast to pre_write_mst_fixup(), see below.
- */
-int post_read_mst_fixup(NTFS_RECORD *b, const u32 size)
-{
-       u16 usa_ofs, usa_count, usn;
-       u16 *usa_pos, *data_pos;
-
-       /* Setup the variables. */
-       usa_ofs = le16_to_cpu(b->usa_ofs);
-       /* Decrement usa_count to get number of fixups. */
-       usa_count = le16_to_cpu(b->usa_count) - 1;
-       /* Size and alignment checks. */
-       if ( size & (NTFS_BLOCK_SIZE - 1)       ||
-            usa_ofs & 1                        ||
-            usa_ofs + (usa_count * 2) > size   ||
-            (size >> NTFS_BLOCK_SIZE_BITS) != usa_count)
-               return 0;
-       /* Position of usn in update sequence array. */
-       usa_pos = (u16*)b + usa_ofs/sizeof(u16);
-       /*
-        * The update sequence number which has to be equal to each of the
-        * u16 values before they are fixed up. Note no need to care for
-        * endianness since we are comparing and moving data for on disk
-        * structures which means the data is consistent. - If it is
-        * consistenty the wrong endianness it doesn't make any difference.
-        */
-       usn = *usa_pos;
-       /*
-        * Position in protected data of first u16 that needs fixing up.
-        */
-       data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
-       /*
-        * Check for incomplete multi sector transfer(s).
-        */
-       while (usa_count--) {
-               if (*data_pos != usn) {
-                       /*
-                        * Incomplete multi sector transfer detected! )-:
-                        * Set the magic to "BAAD" and return failure.
-                        * Note that magic_BAAD is already converted to le32.
-                        */
-                       b->magic = magic_BAAD;
-                       return -EINVAL;
-               }
-               data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
-       }
-       /* Re-setup the variables. */
-       usa_count = le16_to_cpu(b->usa_count) - 1;
-       data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
-       /* Fixup all sectors. */
-       while (usa_count--) {
-               /*
-                * Increment position in usa and restore original data from
-                * the usa into the data buffer.
-                */
-               *data_pos = *(++usa_pos);
-               /* Increment position in data as well. */
-               data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
-       }
-       return 0;
-}
-
-/**
- * pre_write_mst_fixup - apply multi sector transfer protection
- * @b:         pointer to the data to protect
- * @size:      size in bytes of @b
- *
- * Perform the necessary pre write multi sector transfer fixup on the data
- * pointer to by @b of @size.
- *
- * Return 0 if fixup applied (success) or -EINVAL if no fixup was performed
- * (assumed not needed). This is in contrast to post_read_mst_fixup() above.
- *
- * NOTE: We consider the absence / invalidity of an update sequence array to
- * mean that the structure is not subject to protection and hence doesn't need
- * to be fixed up. This means that you have to create a valid update sequence
- * array header in the ntfs record before calling this function, otherwise it
- * will fail (the header needs to contain the position of the update sequence
- * array together with the number of elements in the array). You also need to
- * initialise the update sequence number before calling this function
- * otherwise a random word will be used (whatever was in the record at that
- * position at that time).
- */
-int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size)
-{
-       le16 *usa_pos, *data_pos;
-       u16 usa_ofs, usa_count, usn;
-       le16 le_usn;
-
-       /* Sanity check + only fixup if it makes sense. */
-       if (!b || ntfs_is_baad_record(b->magic) ||
-                       ntfs_is_hole_record(b->magic))
-               return -EINVAL;
-       /* Setup the variables. */
-       usa_ofs = le16_to_cpu(b->usa_ofs);
-       /* Decrement usa_count to get number of fixups. */
-       usa_count = le16_to_cpu(b->usa_count) - 1;
-       /* Size and alignment checks. */
-       if ( size & (NTFS_BLOCK_SIZE - 1)       ||
-            usa_ofs & 1                        ||
-            usa_ofs + (usa_count * 2) > size   ||
-            (size >> NTFS_BLOCK_SIZE_BITS) != usa_count)
-               return -EINVAL;
-       /* Position of usn in update sequence array. */
-       usa_pos = (le16*)((u8*)b + usa_ofs);
-       /*
-        * Cyclically increment the update sequence number
-        * (skipping 0 and -1, i.e. 0xffff).
-        */
-       usn = le16_to_cpup(usa_pos) + 1;
-       if (usn == 0xffff || !usn)
-               usn = 1;
-       le_usn = cpu_to_le16(usn);
-       *usa_pos = le_usn;
-       /* Position in data of first u16 that needs fixing up. */
-       data_pos = (le16*)b + NTFS_BLOCK_SIZE/sizeof(le16) - 1;
-       /* Fixup all sectors. */
-       while (usa_count--) {
-               /*
-                * Increment the position in the usa and save the
-                * original data from the data buffer into the usa.
-                */
-               *(++usa_pos) = *data_pos;
-               /* Apply fixup to data. */
-               *data_pos = le_usn;
-               /* Increment position in data as well. */
-               data_pos += NTFS_BLOCK_SIZE/sizeof(le16);
-       }
-       return 0;
-}
-
-/**
- * post_write_mst_fixup - fast deprotect multi sector transfer protected data
- * @b:         pointer to the data to deprotect
- *
- * Perform the necessary post write multi sector transfer fixup, not checking
- * for any errors, because we assume we have just used pre_write_mst_fixup(),
- * thus the data will be fine or we would never have gotten here.
- */
-void post_write_mst_fixup(NTFS_RECORD *b)
-{
-       le16 *usa_pos, *data_pos;
-
-       u16 usa_ofs = le16_to_cpu(b->usa_ofs);
-       u16 usa_count = le16_to_cpu(b->usa_count) - 1;
-
-       /* Position of usn in update sequence array. */
-       usa_pos = (le16*)b + usa_ofs/sizeof(le16);
-
-       /* Position in protected data of first u16 that needs fixing up. */
-       data_pos = (le16*)b + NTFS_BLOCK_SIZE/sizeof(le16) - 1;
-
-       /* Fixup all sectors. */
-       while (usa_count--) {
-               /*
-                * Increment position in usa and restore original data from
-                * the usa into the data buffer.
-                */
-               *data_pos = *(++usa_pos);
-
-               /* Increment position in data as well. */
-               data_pos += NTFS_BLOCK_SIZE/sizeof(le16);
-       }
-}
diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c
deleted file mode 100644 (file)
index d7498dd..0000000
+++ /dev/null
@@ -1,392 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS
- *          project.
- *
- * Copyright (c) 2001-2006 Anton Altaparmakov
- */
-
-#include <linux/dcache.h>
-#include <linux/exportfs.h>
-#include <linux/security.h>
-#include <linux/slab.h>
-
-#include "attrib.h"
-#include "debug.h"
-#include "dir.h"
-#include "mft.h"
-#include "ntfs.h"
-
-/**
- * ntfs_lookup - find the inode represented by a dentry in a directory inode
- * @dir_ino:   directory inode in which to look for the inode
- * @dent:      dentry representing the inode to look for
- * @flags:     lookup flags
- *
- * In short, ntfs_lookup() looks for the inode represented by the dentry @dent
- * in the directory inode @dir_ino and if found attaches the inode to the
- * dentry @dent.
- *
- * In more detail, the dentry @dent specifies which inode to look for by
- * supplying the name of the inode in @dent->d_name.name. ntfs_lookup()
- * converts the name to Unicode and walks the contents of the directory inode
- * @dir_ino looking for the converted Unicode name. If the name is found in the
- * directory, the corresponding inode is loaded by calling ntfs_iget() on its
- * inode number and the inode is associated with the dentry @dent via a call to
- * d_splice_alias().
- *
- * If the name is not found in the directory, a NULL inode is inserted into the
- * dentry @dent via a call to d_add(). The dentry is then termed a negative
- * dentry.
- *
- * Only if an actual error occurs, do we return an error via ERR_PTR().
- *
- * In order to handle the case insensitivity issues of NTFS with regards to the
- * dcache and the dcache requiring only one dentry per directory, we deal with
- * dentry aliases that only differ in case in ->ntfs_lookup() while maintaining
- * a case sensitive dcache. This means that we get the full benefit of dcache
- * speed when the file/directory is looked up with the same case as returned by
- * ->ntfs_readdir() but that a lookup for any other case (or for the short file
- * name) will not find anything in dcache and will enter ->ntfs_lookup()
- * instead, where we search the directory for a fully matching file name
- * (including case) and if that is not found, we search for a file name that
- * matches with different case and if that has non-POSIX semantics we return
- * that. We actually do only one search (case sensitive) and keep tabs on
- * whether we have found a case insensitive match in the process.
- *
- * To simplify matters for us, we do not treat the short vs long filenames as
- * two hard links but instead if the lookup matches a short filename, we
- * return the dentry for the corresponding long filename instead.
- *
- * There are three cases we need to distinguish here:
- *
- * 1) @dent perfectly matches (i.e. including case) a directory entry with a
- *    file name in the WIN32 or POSIX namespaces. In this case
- *    ntfs_lookup_inode_by_name() will return with name set to NULL and we
- *    just d_splice_alias() @dent.
- * 2) @dent matches (not including case) a directory entry with a file name in
- *    the WIN32 namespace. In this case ntfs_lookup_inode_by_name() will return
- *    with name set to point to a kmalloc()ed ntfs_name structure containing
- *    the properly cased little endian Unicode name. We convert the name to the
- *    current NLS code page, search if a dentry with this name already exists
- *    and if so return that instead of @dent.  At this point things are
- *    complicated by the possibility of 'disconnected' dentries due to NFS
- *    which we deal with appropriately (see the code comments).  The VFS will
- *    then destroy the old @dent and use the one we returned.  If a dentry is
- *    not found, we allocate a new one, d_splice_alias() it, and return it as
- *    above.
- * 3) @dent matches either perfectly or not (i.e. we don't care about case) a
- *    directory entry with a file name in the DOS namespace. In this case
- *    ntfs_lookup_inode_by_name() will return with name set to point to a
- *    kmalloc()ed ntfs_name structure containing the mft reference (cpu endian)
- *    of the inode. We use the mft reference to read the inode and to find the
- *    file name in the WIN32 namespace corresponding to the matched short file
- *    name. We then convert the name to the current NLS code page, and proceed
- *    searching for a dentry with this name, etc, as in case 2), above.
- *
- * Locking: Caller must hold i_mutex on the directory.
- */
-static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
-               unsigned int flags)
-{
-       ntfs_volume *vol = NTFS_SB(dir_ino->i_sb);
-       struct inode *dent_inode;
-       ntfschar *uname;
-       ntfs_name *name = NULL;
-       MFT_REF mref;
-       unsigned long dent_ino;
-       int uname_len;
-
-       ntfs_debug("Looking up %pd in directory inode 0x%lx.",
-                       dent, dir_ino->i_ino);
-       /* Convert the name of the dentry to Unicode. */
-       uname_len = ntfs_nlstoucs(vol, dent->d_name.name, dent->d_name.len,
-                       &uname);
-       if (uname_len < 0) {
-               if (uname_len != -ENAMETOOLONG)
-                       ntfs_error(vol->sb, "Failed to convert name to "
-                                       "Unicode.");
-               return ERR_PTR(uname_len);
-       }
-       mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len,
-                       &name);
-       kmem_cache_free(ntfs_name_cache, uname);
-       if (!IS_ERR_MREF(mref)) {
-               dent_ino = MREF(mref);
-               ntfs_debug("Found inode 0x%lx. Calling ntfs_iget.", dent_ino);
-               dent_inode = ntfs_iget(vol->sb, dent_ino);
-               if (!IS_ERR(dent_inode)) {
-                       /* Consistency check. */
-                       if (is_bad_inode(dent_inode) || MSEQNO(mref) ==
-                                       NTFS_I(dent_inode)->seq_no ||
-                                       dent_ino == FILE_MFT) {
-                               /* Perfect WIN32/POSIX match. -- Case 1. */
-                               if (!name) {
-                                       ntfs_debug("Done.  (Case 1.)");
-                                       return d_splice_alias(dent_inode, dent);
-                               }
-                               /*
-                                * We are too indented.  Handle imperfect
-                                * matches and short file names further below.
-                                */
-                               goto handle_name;
-                       }
-                       ntfs_error(vol->sb, "Found stale reference to inode "
-                                       "0x%lx (reference sequence number = "
-                                       "0x%x, inode sequence number = 0x%x), "
-                                       "returning -EIO. Run chkdsk.",
-                                       dent_ino, MSEQNO(mref),
-                                       NTFS_I(dent_inode)->seq_no);
-                       iput(dent_inode);
-                       dent_inode = ERR_PTR(-EIO);
-               } else
-                       ntfs_error(vol->sb, "ntfs_iget(0x%lx) failed with "
-                                       "error code %li.", dent_ino,
-                                       PTR_ERR(dent_inode));
-               kfree(name);
-               /* Return the error code. */
-               return ERR_CAST(dent_inode);
-       }
-       /* It is guaranteed that @name is no longer allocated at this point. */
-       if (MREF_ERR(mref) == -ENOENT) {
-               ntfs_debug("Entry was not found, adding negative dentry.");
-               /* The dcache will handle negative entries. */
-               d_add(dent, NULL);
-               ntfs_debug("Done.");
-               return NULL;
-       }
-       ntfs_error(vol->sb, "ntfs_lookup_ino_by_name() failed with error "
-                       "code %i.", -MREF_ERR(mref));
-       return ERR_PTR(MREF_ERR(mref));
-       // TODO: Consider moving this lot to a separate function! (AIA)
-handle_name:
-   {
-       MFT_RECORD *m;
-       ntfs_attr_search_ctx *ctx;
-       ntfs_inode *ni = NTFS_I(dent_inode);
-       int err;
-       struct qstr nls_name;
-
-       nls_name.name = NULL;
-       if (name->type != FILE_NAME_DOS) {                      /* Case 2. */
-               ntfs_debug("Case 2.");
-               nls_name.len = (unsigned)ntfs_ucstonls(vol,
-                               (ntfschar*)&name->name, name->len,
-                               (unsigned char**)&nls_name.name, 0);
-               kfree(name);
-       } else /* if (name->type == FILE_NAME_DOS) */ {         /* Case 3. */
-               FILE_NAME_ATTR *fn;
-
-               ntfs_debug("Case 3.");
-               kfree(name);
-
-               /* Find the WIN32 name corresponding to the matched DOS name. */
-               ni = NTFS_I(dent_inode);
-               m = map_mft_record(ni);
-               if (IS_ERR(m)) {
-                       err = PTR_ERR(m);
-                       m = NULL;
-                       ctx = NULL;
-                       goto err_out;
-               }
-               ctx = ntfs_attr_get_search_ctx(ni, m);
-               if (unlikely(!ctx)) {
-                       err = -ENOMEM;
-                       goto err_out;
-               }
-               do {
-                       ATTR_RECORD *a;
-                       u32 val_len;
-
-                       err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0,
-                                       NULL, 0, ctx);
-                       if (unlikely(err)) {
-                               ntfs_error(vol->sb, "Inode corrupt: No WIN32 "
-                                               "namespace counterpart to DOS "
-                                               "file name. Run chkdsk.");
-                               if (err == -ENOENT)
-                                       err = -EIO;
-                               goto err_out;
-                       }
-                       /* Consistency checks. */
-                       a = ctx->attr;
-                       if (a->non_resident || a->flags)
-                               goto eio_err_out;
-                       val_len = le32_to_cpu(a->data.resident.value_length);
-                       if (le16_to_cpu(a->data.resident.value_offset) +
-                                       val_len > le32_to_cpu(a->length))
-                               goto eio_err_out;
-                       fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu(
-                                       ctx->attr->data.resident.value_offset));
-                       if ((u32)(fn->file_name_length * sizeof(ntfschar) +
-                                       sizeof(FILE_NAME_ATTR)) > val_len)
-                               goto eio_err_out;
-               } while (fn->file_name_type != FILE_NAME_WIN32);
-
-               /* Convert the found WIN32 name to current NLS code page. */
-               nls_name.len = (unsigned)ntfs_ucstonls(vol,
-                               (ntfschar*)&fn->file_name, fn->file_name_length,
-                               (unsigned char**)&nls_name.name, 0);
-
-               ntfs_attr_put_search_ctx(ctx);
-               unmap_mft_record(ni);
-       }
-       m = NULL;
-       ctx = NULL;
-
-       /* Check if a conversion error occurred. */
-       if ((signed)nls_name.len < 0) {
-               err = (signed)nls_name.len;
-               goto err_out;
-       }
-       nls_name.hash = full_name_hash(dent, nls_name.name, nls_name.len);
-
-       dent = d_add_ci(dent, dent_inode, &nls_name);
-       kfree(nls_name.name);
-       return dent;
-
-eio_err_out:
-       ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
-       err = -EIO;
-err_out:
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       if (m)
-               unmap_mft_record(ni);
-       iput(dent_inode);
-       ntfs_error(vol->sb, "Failed, returning error code %i.", err);
-       return ERR_PTR(err);
-   }
-}
-
-/*
- * Inode operations for directories.
- */
-const struct inode_operations ntfs_dir_inode_ops = {
-       .lookup = ntfs_lookup,  /* VFS: Lookup directory. */
-};
-
-/**
- * ntfs_get_parent - find the dentry of the parent of a given directory dentry
- * @child_dent:                dentry of the directory whose parent directory to find
- *
- * Find the dentry for the parent directory of the directory specified by the
- * dentry @child_dent.  This function is called from
- * fs/exportfs/expfs.c::find_exported_dentry() which in turn is called from the
- * default ->decode_fh() which is export_decode_fh() in the same file.
- *
- * The code is based on the ext3 ->get_parent() implementation found in
- * fs/ext3/namei.c::ext3_get_parent().
- *
- * Note: ntfs_get_parent() is called with @d_inode(child_dent)->i_mutex down.
- *
- * Return the dentry of the parent directory on success or the error code on
- * error (IS_ERR() is true).
- */
-static struct dentry *ntfs_get_parent(struct dentry *child_dent)
-{
-       struct inode *vi = d_inode(child_dent);
-       ntfs_inode *ni = NTFS_I(vi);
-       MFT_RECORD *mrec;
-       ntfs_attr_search_ctx *ctx;
-       ATTR_RECORD *attr;
-       FILE_NAME_ATTR *fn;
-       unsigned long parent_ino;
-       int err;
-
-       ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
-       /* Get the mft record of the inode belonging to the child dentry. */
-       mrec = map_mft_record(ni);
-       if (IS_ERR(mrec))
-               return ERR_CAST(mrec);
-       /* Find the first file name attribute in the mft record. */
-       ctx = ntfs_attr_get_search_ctx(ni, mrec);
-       if (unlikely(!ctx)) {
-               unmap_mft_record(ni);
-               return ERR_PTR(-ENOMEM);
-       }
-try_next:
-       err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL,
-                       0, ctx);
-       if (unlikely(err)) {
-               ntfs_attr_put_search_ctx(ctx);
-               unmap_mft_record(ni);
-               if (err == -ENOENT)
-                       ntfs_error(vi->i_sb, "Inode 0x%lx does not have a "
-                                       "file name attribute.  Run chkdsk.",
-                                       vi->i_ino);
-               return ERR_PTR(err);
-       }
-       attr = ctx->attr;
-       if (unlikely(attr->non_resident))
-               goto try_next;
-       fn = (FILE_NAME_ATTR *)((u8 *)attr +
-                       le16_to_cpu(attr->data.resident.value_offset));
-       if (unlikely((u8 *)fn + le32_to_cpu(attr->data.resident.value_length) >
-                       (u8*)attr + le32_to_cpu(attr->length)))
-               goto try_next;
-       /* Get the inode number of the parent directory. */
-       parent_ino = MREF_LE(fn->parent_directory);
-       /* Release the search context and the mft record of the child. */
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(ni);
-
-       return d_obtain_alias(ntfs_iget(vi->i_sb, parent_ino));
-}
-
-static struct inode *ntfs_nfs_get_inode(struct super_block *sb,
-               u64 ino, u32 generation)
-{
-       struct inode *inode;
-
-       inode = ntfs_iget(sb, ino);
-       if (!IS_ERR(inode)) {
-               if (is_bad_inode(inode) || inode->i_generation != generation) {
-                       iput(inode);
-                       inode = ERR_PTR(-ESTALE);
-               }
-       }
-
-       return inode;
-}
-
-static struct dentry *ntfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
-               int fh_len, int fh_type)
-{
-       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
-                                   ntfs_nfs_get_inode);
-}
-
-static struct dentry *ntfs_fh_to_parent(struct super_block *sb, struct fid *fid,
-               int fh_len, int fh_type)
-{
-       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
-                                   ntfs_nfs_get_inode);
-}
-
-/*
- * Export operations allowing NFS exporting of mounted NTFS partitions.
- *
- * We use the default ->encode_fh() for now.  Note that they
- * use 32 bits to store the inode number which is an unsigned long so on 64-bit
- * architectures is usually 64 bits so it would all fail horribly on huge
- * volumes.  I guess we need to define our own encode and decode fh functions
- * that store 64-bit inode numbers at some point but for now we will ignore the
- * problem...
- *
- * We also use the default ->get_name() helper (used by ->decode_fh() via
- * fs/exportfs/expfs.c::find_exported_dentry()) as that is completely fs
- * independent.
- *
- * The default ->get_parent() just returns -EACCES so we have to provide our
- * own and the default ->get_dentry() is incompatible with NTFS due to not
- * allowing the inode number 0 which is used in NTFS for the system file $MFT
- * and due to using iget() whereas NTFS needs ntfs_iget().
- */
-const struct export_operations ntfs_export_ops = {
-       .encode_fh      = generic_encode_ino32_fh,
-       .get_parent     = ntfs_get_parent,      /* Find the parent of a given
-                                                  directory. */
-       .fh_to_dentry   = ntfs_fh_to_dentry,
-       .fh_to_parent   = ntfs_fh_to_parent,
-};
diff --git a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
deleted file mode 100644 (file)
index e81376e..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * ntfs.h - Defines for NTFS Linux kernel driver.
- *
- * Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc.
- * Copyright (C) 2002 Richard Russon
- */
-
-#ifndef _LINUX_NTFS_H
-#define _LINUX_NTFS_H
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/compiler.h>
-#include <linux/fs.h>
-#include <linux/nls.h>
-#include <linux/smp.h>
-#include <linux/pagemap.h>
-
-#include "types.h"
-#include "volume.h"
-#include "layout.h"
-
-typedef enum {
-       NTFS_BLOCK_SIZE         = 512,
-       NTFS_BLOCK_SIZE_BITS    = 9,
-       NTFS_SB_MAGIC           = 0x5346544e,   /* 'NTFS' */
-       NTFS_MAX_NAME_LEN       = 255,
-       NTFS_MAX_ATTR_NAME_LEN  = 255,
-       NTFS_MAX_CLUSTER_SIZE   = 64 * 1024,    /* 64kiB */
-       NTFS_MAX_PAGES_PER_CLUSTER = NTFS_MAX_CLUSTER_SIZE / PAGE_SIZE,
-} NTFS_CONSTANTS;
-
-/* Global variables. */
-
-/* Slab caches (from super.c). */
-extern struct kmem_cache *ntfs_name_cache;
-extern struct kmem_cache *ntfs_inode_cache;
-extern struct kmem_cache *ntfs_big_inode_cache;
-extern struct kmem_cache *ntfs_attr_ctx_cache;
-extern struct kmem_cache *ntfs_index_ctx_cache;
-
-/* The various operations structs defined throughout the driver files. */
-extern const struct address_space_operations ntfs_normal_aops;
-extern const struct address_space_operations ntfs_compressed_aops;
-extern const struct address_space_operations ntfs_mst_aops;
-
-extern const struct  file_operations ntfs_file_ops;
-extern const struct inode_operations ntfs_file_inode_ops;
-
-extern const struct  file_operations ntfs_dir_ops;
-extern const struct inode_operations ntfs_dir_inode_ops;
-
-extern const struct  file_operations ntfs_empty_file_ops;
-extern const struct inode_operations ntfs_empty_inode_ops;
-
-extern const struct export_operations ntfs_export_ops;
-
-/**
- * NTFS_SB - return the ntfs volume given a vfs super block
- * @sb:                VFS super block
- *
- * NTFS_SB() returns the ntfs volume associated with the VFS super block @sb.
- */
-static inline ntfs_volume *NTFS_SB(struct super_block *sb)
-{
-       return sb->s_fs_info;
-}
-
-/* Declarations of functions and global variables. */
-
-/* From fs/ntfs/compress.c */
-extern int ntfs_read_compressed_block(struct page *page);
-extern int allocate_compression_buffers(void);
-extern void free_compression_buffers(void);
-
-/* From fs/ntfs/super.c */
-#define default_upcase_len 0x10000
-extern struct mutex ntfs_lock;
-
-typedef struct {
-       int val;
-       char *str;
-} option_t;
-extern const option_t on_errors_arr[];
-
-/* From fs/ntfs/mst.c */
-extern int post_read_mst_fixup(NTFS_RECORD *b, const u32 size);
-extern int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size);
-extern void post_write_mst_fixup(NTFS_RECORD *b);
-
-/* From fs/ntfs/unistr.c */
-extern bool ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
-               const ntfschar *s2, size_t s2_len,
-               const IGNORE_CASE_BOOL ic,
-               const ntfschar *upcase, const u32 upcase_size);
-extern int ntfs_collate_names(const ntfschar *name1, const u32 name1_len,
-               const ntfschar *name2, const u32 name2_len,
-               const int err_val, const IGNORE_CASE_BOOL ic,
-               const ntfschar *upcase, const u32 upcase_len);
-extern int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n);
-extern int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
-               const ntfschar *upcase, const u32 upcase_size);
-extern void ntfs_upcase_name(ntfschar *name, u32 name_len,
-               const ntfschar *upcase, const u32 upcase_len);
-extern void ntfs_file_upcase_value(FILE_NAME_ATTR *file_name_attr,
-               const ntfschar *upcase, const u32 upcase_len);
-extern int ntfs_file_compare_values(FILE_NAME_ATTR *file_name_attr1,
-               FILE_NAME_ATTR *file_name_attr2,
-               const int err_val, const IGNORE_CASE_BOOL ic,
-               const ntfschar *upcase, const u32 upcase_len);
-extern int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
-               const int ins_len, ntfschar **outs);
-extern int ntfs_ucstonls(const ntfs_volume *vol, const ntfschar *ins,
-               const int ins_len, unsigned char **outs, int outs_len);
-
-/* From fs/ntfs/upcase.c */
-extern ntfschar *generate_default_upcase(void);
-
-static inline int ntfs_ffs(int x)
-{
-       int r = 1;
-
-       if (!x)
-               return 0;
-       if (!(x & 0xffff)) {
-               x >>= 16;
-               r += 16;
-       }
-       if (!(x & 0xff)) {
-               x >>= 8;
-               r += 8;
-       }
-       if (!(x & 0xf)) {
-               x >>= 4;
-               r += 4;
-       }
-       if (!(x & 3)) {
-               x >>= 2;
-               r += 2;
-       }
-       if (!(x & 1)) {
-               x >>= 1;
-               r += 1;
-       }
-       return r;
-}
-
-#endif /* _LINUX_NTFS_H */
diff --git a/fs/ntfs/quota.c b/fs/ntfs/quota.c
deleted file mode 100644 (file)
index 9160480..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * quota.c - NTFS kernel quota ($Quota) handling.  Part of the Linux-NTFS
- *          project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- */
-
-#ifdef NTFS_RW
-
-#include "index.h"
-#include "quota.h"
-#include "debug.h"
-#include "ntfs.h"
-
-/**
- * ntfs_mark_quotas_out_of_date - mark the quotas out of date on an ntfs volume
- * @vol:       ntfs volume on which to mark the quotas out of date
- *
- * Mark the quotas out of date on the ntfs volume @vol and return 'true' on
- * success and 'false' on error.
- */
-bool ntfs_mark_quotas_out_of_date(ntfs_volume *vol)
-{
-       ntfs_index_context *ictx;
-       QUOTA_CONTROL_ENTRY *qce;
-       const le32 qid = QUOTA_DEFAULTS_ID;
-       int err;
-
-       ntfs_debug("Entering.");
-       if (NVolQuotaOutOfDate(vol))
-               goto done;
-       if (!vol->quota_ino || !vol->quota_q_ino) {
-               ntfs_error(vol->sb, "Quota inodes are not open.");
-               return false;
-       }
-       inode_lock(vol->quota_q_ino);
-       ictx = ntfs_index_ctx_get(NTFS_I(vol->quota_q_ino));
-       if (!ictx) {
-               ntfs_error(vol->sb, "Failed to get index context.");
-               goto err_out;
-       }
-       err = ntfs_index_lookup(&qid, sizeof(qid), ictx);
-       if (err) {
-               if (err == -ENOENT)
-                       ntfs_error(vol->sb, "Quota defaults entry is not "
-                                       "present.");
-               else
-                       ntfs_error(vol->sb, "Lookup of quota defaults entry "
-                                       "failed.");
-               goto err_out;
-       }
-       if (ictx->data_len < offsetof(QUOTA_CONTROL_ENTRY, sid)) {
-               ntfs_error(vol->sb, "Quota defaults entry size is invalid.  "
-                               "Run chkdsk.");
-               goto err_out;
-       }
-       qce = (QUOTA_CONTROL_ENTRY*)ictx->data;
-       if (le32_to_cpu(qce->version) != QUOTA_VERSION) {
-               ntfs_error(vol->sb, "Quota defaults entry version 0x%x is not "
-                               "supported.", le32_to_cpu(qce->version));
-               goto err_out;
-       }
-       ntfs_debug("Quota defaults flags = 0x%x.", le32_to_cpu(qce->flags));
-       /* If quotas are already marked out of date, no need to do anything. */
-       if (qce->flags & QUOTA_FLAG_OUT_OF_DATE)
-               goto set_done;
-       /*
-        * If quota tracking is neither requested, nor enabled and there are no
-        * pending deletes, no need to mark the quotas out of date.
-        */
-       if (!(qce->flags & (QUOTA_FLAG_TRACKING_ENABLED |
-                       QUOTA_FLAG_TRACKING_REQUESTED |
-                       QUOTA_FLAG_PENDING_DELETES)))
-               goto set_done;
-       /*
-        * Set the QUOTA_FLAG_OUT_OF_DATE bit thus marking quotas out of date.
-        * This is verified on WinXP to be sufficient to cause windows to
-        * rescan the volume on boot and update all quota entries.
-        */
-       qce->flags |= QUOTA_FLAG_OUT_OF_DATE;
-       /* Ensure the modified flags are written to disk. */
-       ntfs_index_entry_flush_dcache_page(ictx);
-       ntfs_index_entry_mark_dirty(ictx);
-set_done:
-       ntfs_index_ctx_put(ictx);
-       inode_unlock(vol->quota_q_ino);
-       /*
-        * We set the flag so we do not try to mark the quotas out of date
-        * again on remount.
-        */
-       NVolSetQuotaOutOfDate(vol);
-done:
-       ntfs_debug("Done.");
-       return true;
-err_out:
-       if (ictx)
-               ntfs_index_ctx_put(ictx);
-       inode_unlock(vol->quota_q_ino);
-       return false;
-}
-
-#endif /* NTFS_RW */
diff --git a/fs/ntfs/quota.h b/fs/ntfs/quota.h
deleted file mode 100644 (file)
index fe3132a..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * quota.h - Defines for NTFS kernel quota ($Quota) handling.  Part of the
- *          Linux-NTFS project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_QUOTA_H
-#define _LINUX_NTFS_QUOTA_H
-
-#ifdef NTFS_RW
-
-#include "types.h"
-#include "volume.h"
-
-extern bool ntfs_mark_quotas_out_of_date(ntfs_volume *vol);
-
-#endif /* NTFS_RW */
-
-#endif /* _LINUX_NTFS_QUOTA_H */
diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c
deleted file mode 100644 (file)
index 0d448e9..0000000
+++ /dev/null
@@ -1,1893 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * runlist.c - NTFS runlist handling code.  Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2007 Anton Altaparmakov
- * Copyright (c) 2002-2005 Richard Russon
- */
-
-#include "debug.h"
-#include "dir.h"
-#include "endian.h"
-#include "malloc.h"
-#include "ntfs.h"
-
-/**
- * ntfs_rl_mm - runlist memmove
- *
- * It is up to the caller to serialize access to the runlist @base.
- */
-static inline void ntfs_rl_mm(runlist_element *base, int dst, int src,
-               int size)
-{
-       if (likely((dst != src) && (size > 0)))
-               memmove(base + dst, base + src, size * sizeof(*base));
-}
-
-/**
- * ntfs_rl_mc - runlist memory copy
- *
- * It is up to the caller to serialize access to the runlists @dstbase and
- * @srcbase.
- */
-static inline void ntfs_rl_mc(runlist_element *dstbase, int dst,
-               runlist_element *srcbase, int src, int size)
-{
-       if (likely(size > 0))
-               memcpy(dstbase + dst, srcbase + src, size * sizeof(*dstbase));
-}
-
-/**
- * ntfs_rl_realloc - Reallocate memory for runlists
- * @rl:                original runlist
- * @old_size:  number of runlist elements in the original runlist @rl
- * @new_size:  number of runlist elements we need space for
- *
- * As the runlists grow, more memory will be required.  To prevent the
- * kernel having to allocate and reallocate large numbers of small bits of
- * memory, this function returns an entire page of memory.
- *
- * It is up to the caller to serialize access to the runlist @rl.
- *
- * N.B.  If the new allocation doesn't require a different number of pages in
- *       memory, the function will return the original pointer.
- *
- * On success, return a pointer to the newly allocated, or recycled, memory.
- * On error, return -errno. The following error codes are defined:
- *     -ENOMEM - Not enough memory to allocate runlist array.
- *     -EINVAL - Invalid parameters were passed in.
- */
-static inline runlist_element *ntfs_rl_realloc(runlist_element *rl,
-               int old_size, int new_size)
-{
-       runlist_element *new_rl;
-
-       old_size = PAGE_ALIGN(old_size * sizeof(*rl));
-       new_size = PAGE_ALIGN(new_size * sizeof(*rl));
-       if (old_size == new_size)
-               return rl;
-
-       new_rl = ntfs_malloc_nofs(new_size);
-       if (unlikely(!new_rl))
-               return ERR_PTR(-ENOMEM);
-
-       if (likely(rl != NULL)) {
-               if (unlikely(old_size > new_size))
-                       old_size = new_size;
-               memcpy(new_rl, rl, old_size);
-               ntfs_free(rl);
-       }
-       return new_rl;
-}
-
-/**
- * ntfs_rl_realloc_nofail - Reallocate memory for runlists
- * @rl:                original runlist
- * @old_size:  number of runlist elements in the original runlist @rl
- * @new_size:  number of runlist elements we need space for
- *
- * As the runlists grow, more memory will be required.  To prevent the
- * kernel having to allocate and reallocate large numbers of small bits of
- * memory, this function returns an entire page of memory.
- *
- * This function guarantees that the allocation will succeed.  It will sleep
- * for as long as it takes to complete the allocation.
- *
- * It is up to the caller to serialize access to the runlist @rl.
- *
- * N.B.  If the new allocation doesn't require a different number of pages in
- *       memory, the function will return the original pointer.
- *
- * On success, return a pointer to the newly allocated, or recycled, memory.
- * On error, return -errno. The following error codes are defined:
- *     -ENOMEM - Not enough memory to allocate runlist array.
- *     -EINVAL - Invalid parameters were passed in.
- */
-static inline runlist_element *ntfs_rl_realloc_nofail(runlist_element *rl,
-               int old_size, int new_size)
-{
-       runlist_element *new_rl;
-
-       old_size = PAGE_ALIGN(old_size * sizeof(*rl));
-       new_size = PAGE_ALIGN(new_size * sizeof(*rl));
-       if (old_size == new_size)
-               return rl;
-
-       new_rl = ntfs_malloc_nofs_nofail(new_size);
-       BUG_ON(!new_rl);
-
-       if (likely(rl != NULL)) {
-               if (unlikely(old_size > new_size))
-                       old_size = new_size;
-               memcpy(new_rl, rl, old_size);
-               ntfs_free(rl);
-       }
-       return new_rl;
-}
-
-/**
- * ntfs_are_rl_mergeable - test if two runlists can be joined together
- * @dst:       original runlist
- * @src:       new runlist to test for mergeability with @dst
- *
- * Test if two runlists can be joined together. For this, their VCNs and LCNs
- * must be adjacent.
- *
- * It is up to the caller to serialize access to the runlists @dst and @src.
- *
- * Return: true   Success, the runlists can be merged.
- *        false  Failure, the runlists cannot be merged.
- */
-static inline bool ntfs_are_rl_mergeable(runlist_element *dst,
-               runlist_element *src)
-{
-       BUG_ON(!dst);
-       BUG_ON(!src);
-
-       /* We can merge unmapped regions even if they are misaligned. */
-       if ((dst->lcn == LCN_RL_NOT_MAPPED) && (src->lcn == LCN_RL_NOT_MAPPED))
-               return true;
-       /* If the runs are misaligned, we cannot merge them. */
-       if ((dst->vcn + dst->length) != src->vcn)
-               return false;
-       /* If both runs are non-sparse and contiguous, we can merge them. */
-       if ((dst->lcn >= 0) && (src->lcn >= 0) &&
-                       ((dst->lcn + dst->length) == src->lcn))
-               return true;
-       /* If we are merging two holes, we can merge them. */
-       if ((dst->lcn == LCN_HOLE) && (src->lcn == LCN_HOLE))
-               return true;
-       /* Cannot merge. */
-       return false;
-}
-
-/**
- * __ntfs_rl_merge - merge two runlists without testing if they can be merged
- * @dst:       original, destination runlist
- * @src:       new runlist to merge with @dst
- *
- * Merge the two runlists, writing into the destination runlist @dst. The
- * caller must make sure the runlists can be merged or this will corrupt the
- * destination runlist.
- *
- * It is up to the caller to serialize access to the runlists @dst and @src.
- */
-static inline void __ntfs_rl_merge(runlist_element *dst, runlist_element *src)
-{
-       dst->length += src->length;
-}
-
-/**
- * ntfs_rl_append - append a runlist after a given element
- * @dst:       original runlist to be worked on
- * @dsize:     number of elements in @dst (including end marker)
- * @src:       runlist to be inserted into @dst
- * @ssize:     number of elements in @src (excluding end marker)
- * @loc:       append the new runlist @src after this element in @dst
- *
- * Append the runlist @src after element @loc in @dst.  Merge the right end of
- * the new runlist, if necessary. Adjust the size of the hole before the
- * appended runlist.
- *
- * It is up to the caller to serialize access to the runlists @dst and @src.
- *
- * On success, return a pointer to the new, combined, runlist. Note, both
- * runlists @dst and @src are deallocated before returning so you cannot use
- * the pointers for anything any more. (Strictly speaking the returned runlist
- * may be the same as @dst but this is irrelevant.)
- *
- * On error, return -errno. Both runlists are left unmodified. The following
- * error codes are defined:
- *     -ENOMEM - Not enough memory to allocate runlist array.
- *     -EINVAL - Invalid parameters were passed in.
- */
-static inline runlist_element *ntfs_rl_append(runlist_element *dst,
-               int dsize, runlist_element *src, int ssize, int loc)
-{
-       bool right = false;     /* Right end of @src needs merging. */
-       int marker;             /* End of the inserted runs. */
-
-       BUG_ON(!dst);
-       BUG_ON(!src);
-
-       /* First, check if the right hand end needs merging. */
-       if ((loc + 1) < dsize)
-               right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
-
-       /* Space required: @dst size + @src size, less one if we merged. */
-       dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right);
-       if (IS_ERR(dst))
-               return dst;
-       /*
-        * We are guaranteed to succeed from here so can start modifying the
-        * original runlists.
-        */
-
-       /* First, merge the right hand end, if necessary. */
-       if (right)
-               __ntfs_rl_merge(src + ssize - 1, dst + loc + 1);
-
-       /* First run after the @src runs that have been inserted. */
-       marker = loc + ssize + 1;
-
-       /* Move the tail of @dst out of the way, then copy in @src. */
-       ntfs_rl_mm(dst, marker, loc + 1 + right, dsize - (loc + 1 + right));
-       ntfs_rl_mc(dst, loc + 1, src, 0, ssize);
-
-       /* Adjust the size of the preceding hole. */
-       dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn;
-
-       /* We may have changed the length of the file, so fix the end marker */
-       if (dst[marker].lcn == LCN_ENOENT)
-               dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length;
-
-       return dst;
-}
-
-/**
- * ntfs_rl_insert - insert a runlist into another
- * @dst:       original runlist to be worked on
- * @dsize:     number of elements in @dst (including end marker)
- * @src:       new runlist to be inserted
- * @ssize:     number of elements in @src (excluding end marker)
- * @loc:       insert the new runlist @src before this element in @dst
- *
- * Insert the runlist @src before element @loc in the runlist @dst. Merge the
- * left end of the new runlist, if necessary. Adjust the size of the hole
- * after the inserted runlist.
- *
- * It is up to the caller to serialize access to the runlists @dst and @src.
- *
- * On success, return a pointer to the new, combined, runlist. Note, both
- * runlists @dst and @src are deallocated before returning so you cannot use
- * the pointers for anything any more. (Strictly speaking the returned runlist
- * may be the same as @dst but this is irrelevant.)
- *
- * On error, return -errno. Both runlists are left unmodified. The following
- * error codes are defined:
- *     -ENOMEM - Not enough memory to allocate runlist array.
- *     -EINVAL - Invalid parameters were passed in.
- */
-static inline runlist_element *ntfs_rl_insert(runlist_element *dst,
-               int dsize, runlist_element *src, int ssize, int loc)
-{
-       bool left = false;      /* Left end of @src needs merging. */
-       bool disc = false;      /* Discontinuity between @dst and @src. */
-       int marker;             /* End of the inserted runs. */
-
-       BUG_ON(!dst);
-       BUG_ON(!src);
-
-       /*
-        * disc => Discontinuity between the end of @dst and the start of @src.
-        *         This means we might need to insert a "not mapped" run.
-        */
-       if (loc == 0)
-               disc = (src[0].vcn > 0);
-       else {
-               s64 merged_length;
-
-               left = ntfs_are_rl_mergeable(dst + loc - 1, src);
-
-               merged_length = dst[loc - 1].length;
-               if (left)
-                       merged_length += src->length;
-
-               disc = (src[0].vcn > dst[loc - 1].vcn + merged_length);
-       }
-       /*
-        * Space required: @dst size + @src size, less one if we merged, plus
-        * one if there was a discontinuity.
-        */
-       dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc);
-       if (IS_ERR(dst))
-               return dst;
-       /*
-        * We are guaranteed to succeed from here so can start modifying the
-        * original runlist.
-        */
-       if (left)
-               __ntfs_rl_merge(dst + loc - 1, src);
-       /*
-        * First run after the @src runs that have been inserted.
-        * Nominally,  @marker equals @loc + @ssize, i.e. location + number of
-        * runs in @src.  However, if @left, then the first run in @src has
-        * been merged with one in @dst.  And if @disc, then @dst and @src do
-        * not meet and we need an extra run to fill the gap.
-        */
-       marker = loc + ssize - left + disc;
-
-       /* Move the tail of @dst out of the way, then copy in @src. */
-       ntfs_rl_mm(dst, marker, loc, dsize - loc);
-       ntfs_rl_mc(dst, loc + disc, src, left, ssize - left);
-
-       /* Adjust the VCN of the first run after the insertion... */
-       dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length;
-       /* ... and the length. */
-       if (dst[marker].lcn == LCN_HOLE || dst[marker].lcn == LCN_RL_NOT_MAPPED)
-               dst[marker].length = dst[marker + 1].vcn - dst[marker].vcn;
-
-       /* Writing beyond the end of the file and there is a discontinuity. */
-       if (disc) {
-               if (loc > 0) {
-                       dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length;
-                       dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn;
-               } else {
-                       dst[loc].vcn = 0;
-                       dst[loc].length = dst[loc + 1].vcn;
-               }
-               dst[loc].lcn = LCN_RL_NOT_MAPPED;
-       }
-       return dst;
-}
-
-/**
- * ntfs_rl_replace - overwrite a runlist element with another runlist
- * @dst:       original runlist to be worked on
- * @dsize:     number of elements in @dst (including end marker)
- * @src:       new runlist to be inserted
- * @ssize:     number of elements in @src (excluding end marker)
- * @loc:       index in runlist @dst to overwrite with @src
- *
- * Replace the runlist element @dst at @loc with @src. Merge the left and
- * right ends of the inserted runlist, if necessary.
- *
- * It is up to the caller to serialize access to the runlists @dst and @src.
- *
- * On success, return a pointer to the new, combined, runlist. Note, both
- * runlists @dst and @src are deallocated before returning so you cannot use
- * the pointers for anything any more. (Strictly speaking the returned runlist
- * may be the same as @dst but this is irrelevant.)
- *
- * On error, return -errno. Both runlists are left unmodified. The following
- * error codes are defined:
- *     -ENOMEM - Not enough memory to allocate runlist array.
- *     -EINVAL - Invalid parameters were passed in.
- */
-static inline runlist_element *ntfs_rl_replace(runlist_element *dst,
-               int dsize, runlist_element *src, int ssize, int loc)
-{
-       signed delta;
-       bool left = false;      /* Left end of @src needs merging. */
-       bool right = false;     /* Right end of @src needs merging. */
-       int tail;               /* Start of tail of @dst. */
-       int marker;             /* End of the inserted runs. */
-
-       BUG_ON(!dst);
-       BUG_ON(!src);
-
-       /* First, see if the left and right ends need merging. */
-       if ((loc + 1) < dsize)
-               right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
-       if (loc > 0)
-               left = ntfs_are_rl_mergeable(dst + loc - 1, src);
-       /*
-        * Allocate some space.  We will need less if the left, right, or both
-        * ends get merged.  The -1 accounts for the run being replaced.
-        */
-       delta = ssize - 1 - left - right;
-       if (delta > 0) {
-               dst = ntfs_rl_realloc(dst, dsize, dsize + delta);
-               if (IS_ERR(dst))
-                       return dst;
-       }
-       /*
-        * We are guaranteed to succeed from here so can start modifying the
-        * original runlists.
-        */
-
-       /* First, merge the left and right ends, if necessary. */
-       if (right)
-               __ntfs_rl_merge(src + ssize - 1, dst + loc + 1);
-       if (left)
-               __ntfs_rl_merge(dst + loc - 1, src);
-       /*
-        * Offset of the tail of @dst.  This needs to be moved out of the way
-        * to make space for the runs to be copied from @src, i.e. the first
-        * run of the tail of @dst.
-        * Nominally, @tail equals @loc + 1, i.e. location, skipping the
-        * replaced run.  However, if @right, then one of @dst's runs is
-        * already merged into @src.
-        */
-       tail = loc + right + 1;
-       /*
-        * First run after the @src runs that have been inserted, i.e. where
-        * the tail of @dst needs to be moved to.
-        * Nominally, @marker equals @loc + @ssize, i.e. location + number of
-        * runs in @src.  However, if @left, then the first run in @src has
-        * been merged with one in @dst.
-        */
-       marker = loc + ssize - left;
-
-       /* Move the tail of @dst out of the way, then copy in @src. */
-       ntfs_rl_mm(dst, marker, tail, dsize - tail);
-       ntfs_rl_mc(dst, loc, src, left, ssize - left);
-
-       /* We may have changed the length of the file, so fix the end marker. */
-       if (dsize - tail > 0 && dst[marker].lcn == LCN_ENOENT)
-               dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length;
-       return dst;
-}
-
-/**
- * ntfs_rl_split - insert a runlist into the centre of a hole
- * @dst:       original runlist to be worked on
- * @dsize:     number of elements in @dst (including end marker)
- * @src:       new runlist to be inserted
- * @ssize:     number of elements in @src (excluding end marker)
- * @loc:       index in runlist @dst at which to split and insert @src
- *
- * Split the runlist @dst at @loc into two and insert @new in between the two
- * fragments. No merging of runlists is necessary. Adjust the size of the
- * holes either side.
- *
- * It is up to the caller to serialize access to the runlists @dst and @src.
- *
- * On success, return a pointer to the new, combined, runlist. Note, both
- * runlists @dst and @src are deallocated before returning so you cannot use
- * the pointers for anything any more. (Strictly speaking the returned runlist
- * may be the same as @dst but this is irrelevant.)
- *
- * On error, return -errno. Both runlists are left unmodified. The following
- * error codes are defined:
- *     -ENOMEM - Not enough memory to allocate runlist array.
- *     -EINVAL - Invalid parameters were passed in.
- */
-static inline runlist_element *ntfs_rl_split(runlist_element *dst, int dsize,
-               runlist_element *src, int ssize, int loc)
-{
-       BUG_ON(!dst);
-       BUG_ON(!src);
-
-       /* Space required: @dst size + @src size + one new hole. */
-       dst = ntfs_rl_realloc(dst, dsize, dsize + ssize + 1);
-       if (IS_ERR(dst))
-               return dst;
-       /*
-        * We are guaranteed to succeed from here so can start modifying the
-        * original runlists.
-        */
-
-       /* Move the tail of @dst out of the way, then copy in @src. */
-       ntfs_rl_mm(dst, loc + 1 + ssize, loc, dsize - loc);
-       ntfs_rl_mc(dst, loc + 1, src, 0, ssize);
-
-       /* Adjust the size of the holes either size of @src. */
-       dst[loc].length         = dst[loc+1].vcn       - dst[loc].vcn;
-       dst[loc+ssize+1].vcn    = dst[loc+ssize].vcn   + dst[loc+ssize].length;
-       dst[loc+ssize+1].length = dst[loc+ssize+2].vcn - dst[loc+ssize+1].vcn;
-
-       return dst;
-}
-
-/**
- * ntfs_runlists_merge - merge two runlists into one
- * @drl:       original runlist to be worked on
- * @srl:       new runlist to be merged into @drl
- *
- * First we sanity check the two runlists @srl and @drl to make sure that they
- * are sensible and can be merged. The runlist @srl must be either after the
- * runlist @drl or completely within a hole (or unmapped region) in @drl.
- *
- * It is up to the caller to serialize access to the runlists @drl and @srl.
- *
- * Merging of runlists is necessary in two cases:
- *   1. When attribute lists are used and a further extent is being mapped.
- *   2. When new clusters are allocated to fill a hole or extend a file.
- *
- * There are four possible ways @srl can be merged. It can:
- *     - be inserted at the beginning of a hole,
- *     - split the hole in two and be inserted between the two fragments,
- *     - be appended at the end of a hole, or it can
- *     - replace the whole hole.
- * It can also be appended to the end of the runlist, which is just a variant
- * of the insert case.
- *
- * On success, return a pointer to the new, combined, runlist. Note, both
- * runlists @drl and @srl are deallocated before returning so you cannot use
- * the pointers for anything any more. (Strictly speaking the returned runlist
- * may be the same as @dst but this is irrelevant.)
- *
- * On error, return -errno. Both runlists are left unmodified. The following
- * error codes are defined:
- *     -ENOMEM - Not enough memory to allocate runlist array.
- *     -EINVAL - Invalid parameters were passed in.
- *     -ERANGE - The runlists overlap and cannot be merged.
- */
-runlist_element *ntfs_runlists_merge(runlist_element *drl,
-               runlist_element *srl)
-{
-       int di, si;             /* Current index into @[ds]rl. */
-       int sstart;             /* First index with lcn > LCN_RL_NOT_MAPPED. */
-       int dins;               /* Index into @drl at which to insert @srl. */
-       int dend, send;         /* Last index into @[ds]rl. */
-       int dfinal, sfinal;     /* The last index into @[ds]rl with
-                                  lcn >= LCN_HOLE. */
-       int marker = 0;
-       VCN marker_vcn = 0;
-
-#ifdef DEBUG
-       ntfs_debug("dst:");
-       ntfs_debug_dump_runlist(drl);
-       ntfs_debug("src:");
-       ntfs_debug_dump_runlist(srl);
-#endif
-
-       /* Check for silly calling... */
-       if (unlikely(!srl))
-               return drl;
-       if (IS_ERR(srl) || IS_ERR(drl))
-               return ERR_PTR(-EINVAL);
-
-       /* Check for the case where the first mapping is being done now. */
-       if (unlikely(!drl)) {
-               drl = srl;
-               /* Complete the source runlist if necessary. */
-               if (unlikely(drl[0].vcn)) {
-                       /* Scan to the end of the source runlist. */
-                       for (dend = 0; likely(drl[dend].length); dend++)
-                               ;
-                       dend++;
-                       drl = ntfs_rl_realloc(drl, dend, dend + 1);
-                       if (IS_ERR(drl))
-                               return drl;
-                       /* Insert start element at the front of the runlist. */
-                       ntfs_rl_mm(drl, 1, 0, dend);
-                       drl[0].vcn = 0;
-                       drl[0].lcn = LCN_RL_NOT_MAPPED;
-                       drl[0].length = drl[1].vcn;
-               }
-               goto finished;
-       }
-
-       si = di = 0;
-
-       /* Skip any unmapped start element(s) in the source runlist. */
-       while (srl[si].length && srl[si].lcn < LCN_HOLE)
-               si++;
-
-       /* Can't have an entirely unmapped source runlist. */
-       BUG_ON(!srl[si].length);
-
-       /* Record the starting points. */
-       sstart = si;
-
-       /*
-        * Skip forward in @drl until we reach the position where @srl needs to
-        * be inserted. If we reach the end of @drl, @srl just needs to be
-        * appended to @drl.
-        */
-       for (; drl[di].length; di++) {
-               if (drl[di].vcn + drl[di].length > srl[sstart].vcn)
-                       break;
-       }
-       dins = di;
-
-       /* Sanity check for illegal overlaps. */
-       if ((drl[di].vcn == srl[si].vcn) && (drl[di].lcn >= 0) &&
-                       (srl[si].lcn >= 0)) {
-               ntfs_error(NULL, "Run lists overlap. Cannot merge!");
-               return ERR_PTR(-ERANGE);
-       }
-
-       /* Scan to the end of both runlists in order to know their sizes. */
-       for (send = si; srl[send].length; send++)
-               ;
-       for (dend = di; drl[dend].length; dend++)
-               ;
-
-       if (srl[send].lcn == LCN_ENOENT)
-               marker_vcn = srl[marker = send].vcn;
-
-       /* Scan to the last element with lcn >= LCN_HOLE. */
-       for (sfinal = send; sfinal >= 0 && srl[sfinal].lcn < LCN_HOLE; sfinal--)
-               ;
-       for (dfinal = dend; dfinal >= 0 && drl[dfinal].lcn < LCN_HOLE; dfinal--)
-               ;
-
-       {
-       bool start;
-       bool finish;
-       int ds = dend + 1;              /* Number of elements in drl & srl */
-       int ss = sfinal - sstart + 1;
-
-       start  = ((drl[dins].lcn <  LCN_RL_NOT_MAPPED) ||    /* End of file   */
-                 (drl[dins].vcn == srl[sstart].vcn));       /* Start of hole */
-       finish = ((drl[dins].lcn >= LCN_RL_NOT_MAPPED) &&    /* End of file   */
-                ((drl[dins].vcn + drl[dins].length) <=      /* End of hole   */
-                 (srl[send - 1].vcn + srl[send - 1].length)));
-
-       /* Or we will lose an end marker. */
-       if (finish && !drl[dins].length)
-               ss++;
-       if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn))
-               finish = false;
-#if 0
-       ntfs_debug("dfinal = %i, dend = %i", dfinal, dend);
-       ntfs_debug("sstart = %i, sfinal = %i, send = %i", sstart, sfinal, send);
-       ntfs_debug("start = %i, finish = %i", start, finish);
-       ntfs_debug("ds = %i, ss = %i, dins = %i", ds, ss, dins);
-#endif
-       if (start) {
-               if (finish)
-                       drl = ntfs_rl_replace(drl, ds, srl + sstart, ss, dins);
-               else
-                       drl = ntfs_rl_insert(drl, ds, srl + sstart, ss, dins);
-       } else {
-               if (finish)
-                       drl = ntfs_rl_append(drl, ds, srl + sstart, ss, dins);
-               else
-                       drl = ntfs_rl_split(drl, ds, srl + sstart, ss, dins);
-       }
-       if (IS_ERR(drl)) {
-               ntfs_error(NULL, "Merge failed.");
-               return drl;
-       }
-       ntfs_free(srl);
-       if (marker) {
-               ntfs_debug("Triggering marker code.");
-               for (ds = dend; drl[ds].length; ds++)
-                       ;
-               /* We only need to care if @srl ended after @drl. */
-               if (drl[ds].vcn <= marker_vcn) {
-                       int slots = 0;
-
-                       if (drl[ds].vcn == marker_vcn) {
-                               ntfs_debug("Old marker = 0x%llx, replacing "
-                                               "with LCN_ENOENT.",
-                                               (unsigned long long)
-                                               drl[ds].lcn);
-                               drl[ds].lcn = LCN_ENOENT;
-                               goto finished;
-                       }
-                       /*
-                        * We need to create an unmapped runlist element in
-                        * @drl or extend an existing one before adding the
-                        * ENOENT terminator.
-                        */
-                       if (drl[ds].lcn == LCN_ENOENT) {
-                               ds--;
-                               slots = 1;
-                       }
-                       if (drl[ds].lcn != LCN_RL_NOT_MAPPED) {
-                               /* Add an unmapped runlist element. */
-                               if (!slots) {
-                                       drl = ntfs_rl_realloc_nofail(drl, ds,
-                                                       ds + 2);
-                                       slots = 2;
-                               }
-                               ds++;
-                               /* Need to set vcn if it isn't set already. */
-                               if (slots != 1)
-                                       drl[ds].vcn = drl[ds - 1].vcn +
-                                                       drl[ds - 1].length;
-                               drl[ds].lcn = LCN_RL_NOT_MAPPED;
-                               /* We now used up a slot. */
-                               slots--;
-                       }
-                       drl[ds].length = marker_vcn - drl[ds].vcn;
-                       /* Finally add the ENOENT terminator. */
-                       ds++;
-                       if (!slots)
-                               drl = ntfs_rl_realloc_nofail(drl, ds, ds + 1);
-                       drl[ds].vcn = marker_vcn;
-                       drl[ds].lcn = LCN_ENOENT;
-                       drl[ds].length = (s64)0;
-               }
-       }
-       }
-
-finished:
-       /* The merge was completed successfully. */
-       ntfs_debug("Merged runlist:");
-       ntfs_debug_dump_runlist(drl);
-       return drl;
-}
-
-/**
- * ntfs_mapping_pairs_decompress - convert mapping pairs array to runlist
- * @vol:       ntfs volume on which the attribute resides
- * @attr:      attribute record whose mapping pairs array to decompress
- * @old_rl:    optional runlist in which to insert @attr's runlist
- *
- * It is up to the caller to serialize access to the runlist @old_rl.
- *
- * Decompress the attribute @attr's mapping pairs array into a runlist. On
- * success, return the decompressed runlist.
- *
- * If @old_rl is not NULL, decompressed runlist is inserted into the
- * appropriate place in @old_rl and the resultant, combined runlist is
- * returned. The original @old_rl is deallocated.
- *
- * On error, return -errno. @old_rl is left unmodified in that case.
- *
- * The following error codes are defined:
- *     -ENOMEM - Not enough memory to allocate runlist array.
- *     -EIO    - Corrupt runlist.
- *     -EINVAL - Invalid parameters were passed in.
- *     -ERANGE - The two runlists overlap.
- *
- * FIXME: For now we take the conceptionally simplest approach of creating the
- * new runlist disregarding the already existing one and then splicing the
- * two into one, if that is possible (we check for overlap and discard the new
- * runlist if overlap present before returning ERR_PTR(-ERANGE)).
- */
-runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol,
-               const ATTR_RECORD *attr, runlist_element *old_rl)
-{
-       VCN vcn;                /* Current vcn. */
-       LCN lcn;                /* Current lcn. */
-       s64 deltaxcn;           /* Change in [vl]cn. */
-       runlist_element *rl;    /* The output runlist. */
-       u8 *buf;                /* Current position in mapping pairs array. */
-       u8 *attr_end;           /* End of attribute. */
-       int rlsize;             /* Size of runlist buffer. */
-       u16 rlpos;              /* Current runlist position in units of
-                                  runlist_elements. */
-       u8 b;                   /* Current byte offset in buf. */
-
-#ifdef DEBUG
-       /* Make sure attr exists and is non-resident. */
-       if (!attr || !attr->non_resident || sle64_to_cpu(
-                       attr->data.non_resident.lowest_vcn) < (VCN)0) {
-               ntfs_error(vol->sb, "Invalid arguments.");
-               return ERR_PTR(-EINVAL);
-       }
-#endif
-       /* Start at vcn = lowest_vcn and lcn 0. */
-       vcn = sle64_to_cpu(attr->data.non_resident.lowest_vcn);
-       lcn = 0;
-       /* Get start of the mapping pairs array. */
-       buf = (u8*)attr + le16_to_cpu(
-                       attr->data.non_resident.mapping_pairs_offset);
-       attr_end = (u8*)attr + le32_to_cpu(attr->length);
-       if (unlikely(buf < (u8*)attr || buf > attr_end)) {
-               ntfs_error(vol->sb, "Corrupt attribute.");
-               return ERR_PTR(-EIO);
-       }
-       /* If the mapping pairs array is valid but empty, nothing to do. */
-       if (!vcn && !*buf)
-               return old_rl;
-       /* Current position in runlist array. */
-       rlpos = 0;
-       /* Allocate first page and set current runlist size to one page. */
-       rl = ntfs_malloc_nofs(rlsize = PAGE_SIZE);
-       if (unlikely(!rl))
-               return ERR_PTR(-ENOMEM);
-       /* Insert unmapped starting element if necessary. */
-       if (vcn) {
-               rl->vcn = 0;
-               rl->lcn = LCN_RL_NOT_MAPPED;
-               rl->length = vcn;
-               rlpos++;
-       }
-       while (buf < attr_end && *buf) {
-               /*
-                * Allocate more memory if needed, including space for the
-                * not-mapped and terminator elements. ntfs_malloc_nofs()
-                * operates on whole pages only.
-                */
-               if (((rlpos + 3) * sizeof(*old_rl)) > rlsize) {
-                       runlist_element *rl2;
-
-                       rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE);
-                       if (unlikely(!rl2)) {
-                               ntfs_free(rl);
-                               return ERR_PTR(-ENOMEM);
-                       }
-                       memcpy(rl2, rl, rlsize);
-                       ntfs_free(rl);
-                       rl = rl2;
-                       rlsize += PAGE_SIZE;
-               }
-               /* Enter the current vcn into the current runlist element. */
-               rl[rlpos].vcn = vcn;
-               /*
-                * Get the change in vcn, i.e. the run length in clusters.
-                * Doing it this way ensures that we signextend negative values.
-                * A negative run length doesn't make any sense, but hey, I
-                * didn't make up the NTFS specs and Windows NT4 treats the run
-                * length as a signed value so that's how it is...
-                */
-               b = *buf & 0xf;
-               if (b) {
-                       if (unlikely(buf + b > attr_end))
-                               goto io_error;
-                       for (deltaxcn = (s8)buf[b--]; b; b--)
-                               deltaxcn = (deltaxcn << 8) + buf[b];
-               } else { /* The length entry is compulsory. */
-                       ntfs_error(vol->sb, "Missing length entry in mapping "
-                                       "pairs array.");
-                       deltaxcn = (s64)-1;
-               }
-               /*
-                * Assume a negative length to indicate data corruption and
-                * hence clean-up and return NULL.
-                */
-               if (unlikely(deltaxcn < 0)) {
-                       ntfs_error(vol->sb, "Invalid length in mapping pairs "
-                                       "array.");
-                       goto err_out;
-               }
-               /*
-                * Enter the current run length into the current runlist
-                * element.
-                */
-               rl[rlpos].length = deltaxcn;
-               /* Increment the current vcn by the current run length. */
-               vcn += deltaxcn;
-               /*
-                * There might be no lcn change at all, as is the case for
-                * sparse clusters on NTFS 3.0+, in which case we set the lcn
-                * to LCN_HOLE.
-                */
-               if (!(*buf & 0xf0))
-                       rl[rlpos].lcn = LCN_HOLE;
-               else {
-                       /* Get the lcn change which really can be negative. */
-                       u8 b2 = *buf & 0xf;
-                       b = b2 + ((*buf >> 4) & 0xf);
-                       if (buf + b > attr_end)
-                               goto io_error;
-                       for (deltaxcn = (s8)buf[b--]; b > b2; b--)
-                               deltaxcn = (deltaxcn << 8) + buf[b];
-                       /* Change the current lcn to its new value. */
-                       lcn += deltaxcn;
-#ifdef DEBUG
-                       /*
-                        * On NTFS 1.2-, apparently can have lcn == -1 to
-                        * indicate a hole. But we haven't verified ourselves
-                        * whether it is really the lcn or the deltaxcn that is
-                        * -1. So if either is found give us a message so we
-                        * can investigate it further!
-                        */
-                       if (vol->major_ver < 3) {
-                               if (unlikely(deltaxcn == (LCN)-1))
-                                       ntfs_error(vol->sb, "lcn delta == -1");
-                               if (unlikely(lcn == (LCN)-1))
-                                       ntfs_error(vol->sb, "lcn == -1");
-                       }
-#endif
-                       /* Check lcn is not below -1. */
-                       if (unlikely(lcn < (LCN)-1)) {
-                               ntfs_error(vol->sb, "Invalid LCN < -1 in "
-                                               "mapping pairs array.");
-                               goto err_out;
-                       }
-                       /* Enter the current lcn into the runlist element. */
-                       rl[rlpos].lcn = lcn;
-               }
-               /* Get to the next runlist element. */
-               rlpos++;
-               /* Increment the buffer position to the next mapping pair. */
-               buf += (*buf & 0xf) + ((*buf >> 4) & 0xf) + 1;
-       }
-       if (unlikely(buf >= attr_end))
-               goto io_error;
-       /*
-        * If there is a highest_vcn specified, it must be equal to the final
-        * vcn in the runlist - 1, or something has gone badly wrong.
-        */
-       deltaxcn = sle64_to_cpu(attr->data.non_resident.highest_vcn);
-       if (unlikely(deltaxcn && vcn - 1 != deltaxcn)) {
-mpa_err:
-               ntfs_error(vol->sb, "Corrupt mapping pairs array in "
-                               "non-resident attribute.");
-               goto err_out;
-       }
-       /* Setup not mapped runlist element if this is the base extent. */
-       if (!attr->data.non_resident.lowest_vcn) {
-               VCN max_cluster;
-
-               max_cluster = ((sle64_to_cpu(
-                               attr->data.non_resident.allocated_size) +
-                               vol->cluster_size - 1) >>
-                               vol->cluster_size_bits) - 1;
-               /*
-                * A highest_vcn of zero means this is a single extent
-                * attribute so simply terminate the runlist with LCN_ENOENT).
-                */
-               if (deltaxcn) {
-                       /*
-                        * If there is a difference between the highest_vcn and
-                        * the highest cluster, the runlist is either corrupt
-                        * or, more likely, there are more extents following
-                        * this one.
-                        */
-                       if (deltaxcn < max_cluster) {
-                               ntfs_debug("More extents to follow; deltaxcn "
-                                               "= 0x%llx, max_cluster = "
-                                               "0x%llx",
-                                               (unsigned long long)deltaxcn,
-                                               (unsigned long long)
-                                               max_cluster);
-                               rl[rlpos].vcn = vcn;
-                               vcn += rl[rlpos].length = max_cluster -
-                                               deltaxcn;
-                               rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
-                               rlpos++;
-                       } else if (unlikely(deltaxcn > max_cluster)) {
-                               ntfs_error(vol->sb, "Corrupt attribute.  "
-                                               "deltaxcn = 0x%llx, "
-                                               "max_cluster = 0x%llx",
-                                               (unsigned long long)deltaxcn,
-                                               (unsigned long long)
-                                               max_cluster);
-                               goto mpa_err;
-                       }
-               }
-               rl[rlpos].lcn = LCN_ENOENT;
-       } else /* Not the base extent. There may be more extents to follow. */
-               rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
-
-       /* Setup terminating runlist element. */
-       rl[rlpos].vcn = vcn;
-       rl[rlpos].length = (s64)0;
-       /* If no existing runlist was specified, we are done. */
-       if (!old_rl) {
-               ntfs_debug("Mapping pairs array successfully decompressed:");
-               ntfs_debug_dump_runlist(rl);
-               return rl;
-       }
-       /* Now combine the new and old runlists checking for overlaps. */
-       old_rl = ntfs_runlists_merge(old_rl, rl);
-       if (!IS_ERR(old_rl))
-               return old_rl;
-       ntfs_free(rl);
-       ntfs_error(vol->sb, "Failed to merge runlists.");
-       return old_rl;
-io_error:
-       ntfs_error(vol->sb, "Corrupt attribute.");
-err_out:
-       ntfs_free(rl);
-       return ERR_PTR(-EIO);
-}
-
-/**
- * ntfs_rl_vcn_to_lcn - convert a vcn into a lcn given a runlist
- * @rl:                runlist to use for conversion
- * @vcn:       vcn to convert
- *
- * Convert the virtual cluster number @vcn of an attribute into a logical
- * cluster number (lcn) of a device using the runlist @rl to map vcns to their
- * corresponding lcns.
- *
- * It is up to the caller to serialize access to the runlist @rl.
- *
- * Since lcns must be >= 0, we use negative return codes with special meaning:
- *
- * Return code         Meaning / Description
- * ==================================================
- *  LCN_HOLE           Hole / not allocated on disk.
- *  LCN_RL_NOT_MAPPED  This is part of the runlist which has not been
- *                     inserted into the runlist yet.
- *  LCN_ENOENT         There is no such vcn in the attribute.
- *
- * Locking: - The caller must have locked the runlist (for reading or writing).
- *         - This function does not touch the lock, nor does it modify the
- *           runlist.
- */
-LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn)
-{
-       int i;
-
-       BUG_ON(vcn < 0);
-       /*
-        * If rl is NULL, assume that we have found an unmapped runlist. The
-        * caller can then attempt to map it and fail appropriately if
-        * necessary.
-        */
-       if (unlikely(!rl))
-               return LCN_RL_NOT_MAPPED;
-
-       /* Catch out of lower bounds vcn. */
-       if (unlikely(vcn < rl[0].vcn))
-               return LCN_ENOENT;
-
-       for (i = 0; likely(rl[i].length); i++) {
-               if (unlikely(vcn < rl[i+1].vcn)) {
-                       if (likely(rl[i].lcn >= (LCN)0))
-                               return rl[i].lcn + (vcn - rl[i].vcn);
-                       return rl[i].lcn;
-               }
-       }
-       /*
-        * The terminator element is setup to the correct value, i.e. one of
-        * LCN_HOLE, LCN_RL_NOT_MAPPED, or LCN_ENOENT.
-        */
-       if (likely(rl[i].lcn < (LCN)0))
-               return rl[i].lcn;
-       /* Just in case... We could replace this with BUG() some day. */
-       return LCN_ENOENT;
-}
-
-#ifdef NTFS_RW
-
-/**
- * ntfs_rl_find_vcn_nolock - find a vcn in a runlist
- * @rl:                runlist to search
- * @vcn:       vcn to find
- *
- * Find the virtual cluster number @vcn in the runlist @rl and return the
- * address of the runlist element containing the @vcn on success.
- *
- * Return NULL if @rl is NULL or @vcn is in an unmapped part/out of bounds of
- * the runlist.
- *
- * Locking: The runlist must be locked on entry.
- */
-runlist_element *ntfs_rl_find_vcn_nolock(runlist_element *rl, const VCN vcn)
-{
-       BUG_ON(vcn < 0);
-       if (unlikely(!rl || vcn < rl[0].vcn))
-               return NULL;
-       while (likely(rl->length)) {
-               if (unlikely(vcn < rl[1].vcn)) {
-                       if (likely(rl->lcn >= LCN_HOLE))
-                               return rl;
-                       return NULL;
-               }
-               rl++;
-       }
-       if (likely(rl->lcn == LCN_ENOENT))
-               return rl;
-       return NULL;
-}
-
-/**
- * ntfs_get_nr_significant_bytes - get number of bytes needed to store a number
- * @n:         number for which to get the number of bytes for
- *
- * Return the number of bytes required to store @n unambiguously as
- * a signed number.
- *
- * This is used in the context of the mapping pairs array to determine how
- * many bytes will be needed in the array to store a given logical cluster
- * number (lcn) or a specific run length.
- *
- * Return the number of bytes written.  This function cannot fail.
- */
-static inline int ntfs_get_nr_significant_bytes(const s64 n)
-{
-       s64 l = n;
-       int i;
-       s8 j;
-
-       i = 0;
-       do {
-               l >>= 8;
-               i++;
-       } while (l != 0 && l != -1);
-       j = (n >> 8 * (i - 1)) & 0xff;
-       /* If the sign bit is wrong, we need an extra byte. */
-       if ((n < 0 && j >= 0) || (n > 0 && j < 0))
-               i++;
-       return i;
-}
-
-/**
- * ntfs_get_size_for_mapping_pairs - get bytes needed for mapping pairs array
- * @vol:       ntfs volume (needed for the ntfs version)
- * @rl:                locked runlist to determine the size of the mapping pairs of
- * @first_vcn: first vcn which to include in the mapping pairs array
- * @last_vcn:  last vcn which to include in the mapping pairs array
- *
- * Walk the locked runlist @rl and calculate the size in bytes of the mapping
- * pairs array corresponding to the runlist @rl, starting at vcn @first_vcn and
- * finishing with vcn @last_vcn.
- *
- * A @last_vcn of -1 means end of runlist and in that case the size of the
- * mapping pairs array corresponding to the runlist starting at vcn @first_vcn
- * and finishing at the end of the runlist is determined.
- *
- * This for example allows us to allocate a buffer of the right size when
- * building the mapping pairs array.
- *
- * If @rl is NULL, just return 1 (for the single terminator byte).
- *
- * Return the calculated size in bytes on success.  On error, return -errno.
- * The following error codes are defined:
- *     -EINVAL - Run list contains unmapped elements.  Make sure to only pass
- *               fully mapped runlists to this function.
- *     -EIO    - The runlist is corrupt.
- *
- * Locking: @rl must be locked on entry (either for reading or writing), it
- *         remains locked throughout, and is left locked upon return.
- */
-int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
-               const runlist_element *rl, const VCN first_vcn,
-               const VCN last_vcn)
-{
-       LCN prev_lcn;
-       int rls;
-       bool the_end = false;
-
-       BUG_ON(first_vcn < 0);
-       BUG_ON(last_vcn < -1);
-       BUG_ON(last_vcn >= 0 && first_vcn > last_vcn);
-       if (!rl) {
-               BUG_ON(first_vcn);
-               BUG_ON(last_vcn > 0);
-               return 1;
-       }
-       /* Skip to runlist element containing @first_vcn. */
-       while (rl->length && first_vcn >= rl[1].vcn)
-               rl++;
-       if (unlikely((!rl->length && first_vcn > rl->vcn) ||
-                       first_vcn < rl->vcn))
-               return -EINVAL;
-       prev_lcn = 0;
-       /* Always need the termining zero byte. */
-       rls = 1;
-       /* Do the first partial run if present. */
-       if (first_vcn > rl->vcn) {
-               s64 delta, length = rl->length;
-
-               /* We know rl->length != 0 already. */
-               if (unlikely(length < 0 || rl->lcn < LCN_HOLE))
-                       goto err_out;
-               /*
-                * If @stop_vcn is given and finishes inside this run, cap the
-                * run length.
-                */
-               if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) {
-                       s64 s1 = last_vcn + 1;
-                       if (unlikely(rl[1].vcn > s1))
-                               length = s1 - rl->vcn;
-                       the_end = true;
-               }
-               delta = first_vcn - rl->vcn;
-               /* Header byte + length. */
-               rls += 1 + ntfs_get_nr_significant_bytes(length - delta);
-               /*
-                * If the logical cluster number (lcn) denotes a hole and we
-                * are on NTFS 3.0+, we don't store it at all, i.e. we need
-                * zero space.  On earlier NTFS versions we just store the lcn.
-                * Note: this assumes that on NTFS 1.2-, holes are stored with
-                * an lcn of -1 and not a delta_lcn of -1 (unless both are -1).
-                */
-               if (likely(rl->lcn >= 0 || vol->major_ver < 3)) {
-                       prev_lcn = rl->lcn;
-                       if (likely(rl->lcn >= 0))
-                               prev_lcn += delta;
-                       /* Change in lcn. */
-                       rls += ntfs_get_nr_significant_bytes(prev_lcn);
-               }
-               /* Go to next runlist element. */
-               rl++;
-       }
-       /* Do the full runs. */
-       for (; rl->length && !the_end; rl++) {
-               s64 length = rl->length;
-
-               if (unlikely(length < 0 || rl->lcn < LCN_HOLE))
-                       goto err_out;
-               /*
-                * If @stop_vcn is given and finishes inside this run, cap the
-                * run length.
-                */
-               if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) {
-                       s64 s1 = last_vcn + 1;
-                       if (unlikely(rl[1].vcn > s1))
-                               length = s1 - rl->vcn;
-                       the_end = true;
-               }
-               /* Header byte + length. */
-               rls += 1 + ntfs_get_nr_significant_bytes(length);
-               /*
-                * If the logical cluster number (lcn) denotes a hole and we
-                * are on NTFS 3.0+, we don't store it at all, i.e. we need
-                * zero space.  On earlier NTFS versions we just store the lcn.
-                * Note: this assumes that on NTFS 1.2-, holes are stored with
-                * an lcn of -1 and not a delta_lcn of -1 (unless both are -1).
-                */
-               if (likely(rl->lcn >= 0 || vol->major_ver < 3)) {
-                       /* Change in lcn. */
-                       rls += ntfs_get_nr_significant_bytes(rl->lcn -
-                                       prev_lcn);
-                       prev_lcn = rl->lcn;
-               }
-       }
-       return rls;
-err_out:
-       if (rl->lcn == LCN_RL_NOT_MAPPED)
-               rls = -EINVAL;
-       else
-               rls = -EIO;
-       return rls;
-}
-
-/**
- * ntfs_write_significant_bytes - write the significant bytes of a number
- * @dst:       destination buffer to write to
- * @dst_max:   pointer to last byte of destination buffer for bounds checking
- * @n:         number whose significant bytes to write
- *
- * Store in @dst, the minimum bytes of the number @n which are required to
- * identify @n unambiguously as a signed number, taking care not to exceed
- * @dest_max, the maximum position within @dst to which we are allowed to
- * write.
- *
- * This is used when building the mapping pairs array of a runlist to compress
- * a given logical cluster number (lcn) or a specific run length to the minimum
- * size possible.
- *
- * Return the number of bytes written on success.  On error, i.e. the
- * destination buffer @dst is too small, return -ENOSPC.
- */
-static inline int ntfs_write_significant_bytes(s8 *dst, const s8 *dst_max,
-               const s64 n)
-{
-       s64 l = n;
-       int i;
-       s8 j;
-
-       i = 0;
-       do {
-               if (unlikely(dst > dst_max))
-                       goto err_out;
-               *dst++ = l & 0xffll;
-               l >>= 8;
-               i++;
-       } while (l != 0 && l != -1);
-       j = (n >> 8 * (i - 1)) & 0xff;
-       /* If the sign bit is wrong, we need an extra byte. */
-       if (n < 0 && j >= 0) {
-               if (unlikely(dst > dst_max))
-                       goto err_out;
-               i++;
-               *dst = (s8)-1;
-       } else if (n > 0 && j < 0) {
-               if (unlikely(dst > dst_max))
-                       goto err_out;
-               i++;
-               *dst = (s8)0;
-       }
-       return i;
-err_out:
-       return -ENOSPC;
-}
-
-/**
- * ntfs_mapping_pairs_build - build the mapping pairs array from a runlist
- * @vol:       ntfs volume (needed for the ntfs version)
- * @dst:       destination buffer to which to write the mapping pairs array
- * @dst_len:   size of destination buffer @dst in bytes
- * @rl:                locked runlist for which to build the mapping pairs array
- * @first_vcn: first vcn which to include in the mapping pairs array
- * @last_vcn:  last vcn which to include in the mapping pairs array
- * @stop_vcn:  first vcn outside destination buffer on success or -ENOSPC
- *
- * Create the mapping pairs array from the locked runlist @rl, starting at vcn
- * @first_vcn and finishing with vcn @last_vcn and save the array in @dst.
- * @dst_len is the size of @dst in bytes and it should be at least equal to the
- * value obtained by calling ntfs_get_size_for_mapping_pairs().
- *
- * A @last_vcn of -1 means end of runlist and in that case the mapping pairs
- * array corresponding to the runlist starting at vcn @first_vcn and finishing
- * at the end of the runlist is created.
- *
- * If @rl is NULL, just write a single terminator byte to @dst.
- *
- * On success or -ENOSPC error, if @stop_vcn is not NULL, *@stop_vcn is set to
- * the first vcn outside the destination buffer.  Note that on error, @dst has
- * been filled with all the mapping pairs that will fit, thus it can be treated
- * as partial success, in that a new attribute extent needs to be created or
- * the next extent has to be used and the mapping pairs build has to be
- * continued with @first_vcn set to *@stop_vcn.
- *
- * Return 0 on success and -errno on error.  The following error codes are
- * defined:
- *     -EINVAL - Run list contains unmapped elements.  Make sure to only pass
- *               fully mapped runlists to this function.
- *     -EIO    - The runlist is corrupt.
- *     -ENOSPC - The destination buffer is too small.
- *
- * Locking: @rl must be locked on entry (either for reading or writing), it
- *         remains locked throughout, and is left locked upon return.
- */
-int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst,
-               const int dst_len, const runlist_element *rl,
-               const VCN first_vcn, const VCN last_vcn, VCN *const stop_vcn)
-{
-       LCN prev_lcn;
-       s8 *dst_max, *dst_next;
-       int err = -ENOSPC;
-       bool the_end = false;
-       s8 len_len, lcn_len;
-
-       BUG_ON(first_vcn < 0);
-       BUG_ON(last_vcn < -1);
-       BUG_ON(last_vcn >= 0 && first_vcn > last_vcn);
-       BUG_ON(dst_len < 1);
-       if (!rl) {
-               BUG_ON(first_vcn);
-               BUG_ON(last_vcn > 0);
-               if (stop_vcn)
-                       *stop_vcn = 0;
-               /* Terminator byte. */
-               *dst = 0;
-               return 0;
-       }
-       /* Skip to runlist element containing @first_vcn. */
-       while (rl->length && first_vcn >= rl[1].vcn)
-               rl++;
-       if (unlikely((!rl->length && first_vcn > rl->vcn) ||
-                       first_vcn < rl->vcn))
-               return -EINVAL;
-       /*
-        * @dst_max is used for bounds checking in
-        * ntfs_write_significant_bytes().
-        */
-       dst_max = dst + dst_len - 1;
-       prev_lcn = 0;
-       /* Do the first partial run if present. */
-       if (first_vcn > rl->vcn) {
-               s64 delta, length = rl->length;
-
-               /* We know rl->length != 0 already. */
-               if (unlikely(length < 0 || rl->lcn < LCN_HOLE))
-                       goto err_out;
-               /*
-                * If @stop_vcn is given and finishes inside this run, cap the
-                * run length.
-                */
-               if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) {
-                       s64 s1 = last_vcn + 1;
-                       if (unlikely(rl[1].vcn > s1))
-                               length = s1 - rl->vcn;
-                       the_end = true;
-               }
-               delta = first_vcn - rl->vcn;
-               /* Write length. */
-               len_len = ntfs_write_significant_bytes(dst + 1, dst_max,
-                               length - delta);
-               if (unlikely(len_len < 0))
-                       goto size_err;
-               /*
-                * If the logical cluster number (lcn) denotes a hole and we
-                * are on NTFS 3.0+, we don't store it at all, i.e. we need
-                * zero space.  On earlier NTFS versions we just write the lcn
-                * change.  FIXME: Do we need to write the lcn change or just
-                * the lcn in that case?  Not sure as I have never seen this
-                * case on NT4. - We assume that we just need to write the lcn
-                * change until someone tells us otherwise... (AIA)
-                */
-               if (likely(rl->lcn >= 0 || vol->major_ver < 3)) {
-                       prev_lcn = rl->lcn;
-                       if (likely(rl->lcn >= 0))
-                               prev_lcn += delta;
-                       /* Write change in lcn. */
-                       lcn_len = ntfs_write_significant_bytes(dst + 1 +
-                                       len_len, dst_max, prev_lcn);
-                       if (unlikely(lcn_len < 0))
-                               goto size_err;
-               } else
-                       lcn_len = 0;
-               dst_next = dst + len_len + lcn_len + 1;
-               if (unlikely(dst_next > dst_max))
-                       goto size_err;
-               /* Update header byte. */
-               *dst = lcn_len << 4 | len_len;
-               /* Position at next mapping pairs array element. */
-               dst = dst_next;
-               /* Go to next runlist element. */
-               rl++;
-       }
-       /* Do the full runs. */
-       for (; rl->length && !the_end; rl++) {
-               s64 length = rl->length;
-
-               if (unlikely(length < 0 || rl->lcn < LCN_HOLE))
-                       goto err_out;
-               /*
-                * If @stop_vcn is given and finishes inside this run, cap the
-                * run length.
-                */
-               if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) {
-                       s64 s1 = last_vcn + 1;
-                       if (unlikely(rl[1].vcn > s1))
-                               length = s1 - rl->vcn;
-                       the_end = true;
-               }
-               /* Write length. */
-               len_len = ntfs_write_significant_bytes(dst + 1, dst_max,
-                               length);
-               if (unlikely(len_len < 0))
-                       goto size_err;
-               /*
-                * If the logical cluster number (lcn) denotes a hole and we
-                * are on NTFS 3.0+, we don't store it at all, i.e. we need
-                * zero space.  On earlier NTFS versions we just write the lcn
-                * change.  FIXME: Do we need to write the lcn change or just
-                * the lcn in that case?  Not sure as I have never seen this
-                * case on NT4. - We assume that we just need to write the lcn
-                * change until someone tells us otherwise... (AIA)
-                */
-               if (likely(rl->lcn >= 0 || vol->major_ver < 3)) {
-                       /* Write change in lcn. */
-                       lcn_len = ntfs_write_significant_bytes(dst + 1 +
-                                       len_len, dst_max, rl->lcn - prev_lcn);
-                       if (unlikely(lcn_len < 0))
-                               goto size_err;
-                       prev_lcn = rl->lcn;
-               } else
-                       lcn_len = 0;
-               dst_next = dst + len_len + lcn_len + 1;
-               if (unlikely(dst_next > dst_max))
-                       goto size_err;
-               /* Update header byte. */
-               *dst = lcn_len << 4 | len_len;
-               /* Position at next mapping pairs array element. */
-               dst = dst_next;
-       }
-       /* Success. */
-       err = 0;
-size_err:
-       /* Set stop vcn. */
-       if (stop_vcn)
-               *stop_vcn = rl->vcn;
-       /* Add terminator byte. */
-       *dst = 0;
-       return err;
-err_out:
-       if (rl->lcn == LCN_RL_NOT_MAPPED)
-               err = -EINVAL;
-       else
-               err = -EIO;
-       return err;
-}
-
-/**
- * ntfs_rl_truncate_nolock - truncate a runlist starting at a specified vcn
- * @vol:       ntfs volume (needed for error output)
- * @runlist:   runlist to truncate
- * @new_length:        the new length of the runlist in VCNs
- *
- * Truncate the runlist described by @runlist as well as the memory buffer
- * holding the runlist elements to a length of @new_length VCNs.
- *
- * If @new_length lies within the runlist, the runlist elements with VCNs of
- * @new_length and above are discarded.  As a special case if @new_length is
- * zero, the runlist is discarded and set to NULL.
- *
- * If @new_length lies beyond the runlist, a sparse runlist element is added to
- * the end of the runlist @runlist or if the last runlist element is a sparse
- * one already, this is extended.
- *
- * Note, no checking is done for unmapped runlist elements.  It is assumed that
- * the caller has mapped any elements that need to be mapped already.
- *
- * Return 0 on success and -errno on error.
- *
- * Locking: The caller must hold @runlist->lock for writing.
- */
-int ntfs_rl_truncate_nolock(const ntfs_volume *vol, runlist *const runlist,
-               const s64 new_length)
-{
-       runlist_element *rl;
-       int old_size;
-
-       ntfs_debug("Entering for new_length 0x%llx.", (long long)new_length);
-       BUG_ON(!runlist);
-       BUG_ON(new_length < 0);
-       rl = runlist->rl;
-       if (!new_length) {
-               ntfs_debug("Freeing runlist.");
-               runlist->rl = NULL;
-               if (rl)
-                       ntfs_free(rl);
-               return 0;
-       }
-       if (unlikely(!rl)) {
-               /*
-                * Create a runlist consisting of a sparse runlist element of
-                * length @new_length followed by a terminator runlist element.
-                */
-               rl = ntfs_malloc_nofs(PAGE_SIZE);
-               if (unlikely(!rl)) {
-                       ntfs_error(vol->sb, "Not enough memory to allocate "
-                                       "runlist element buffer.");
-                       return -ENOMEM;
-               }
-               runlist->rl = rl;
-               rl[1].length = rl->vcn = 0;
-               rl->lcn = LCN_HOLE;
-               rl[1].vcn = rl->length = new_length;
-               rl[1].lcn = LCN_ENOENT;
-               return 0;
-       }
-       BUG_ON(new_length < rl->vcn);
-       /* Find @new_length in the runlist. */
-       while (likely(rl->length && new_length >= rl[1].vcn))
-               rl++;
-       /*
-        * If not at the end of the runlist we need to shrink it.
-        * If at the end of the runlist we need to expand it.
-        */
-       if (rl->length) {
-               runlist_element *trl;
-               bool is_end;
-
-               ntfs_debug("Shrinking runlist.");
-               /* Determine the runlist size. */
-               trl = rl + 1;
-               while (likely(trl->length))
-                       trl++;
-               old_size = trl - runlist->rl + 1;
-               /* Truncate the run. */
-               rl->length = new_length - rl->vcn;
-               /*
-                * If a run was partially truncated, make the following runlist
-                * element a terminator.
-                */
-               is_end = false;
-               if (rl->length) {
-                       rl++;
-                       if (!rl->length)
-                               is_end = true;
-                       rl->vcn = new_length;
-                       rl->length = 0;
-               }
-               rl->lcn = LCN_ENOENT;
-               /* Reallocate memory if necessary. */
-               if (!is_end) {
-                       int new_size = rl - runlist->rl + 1;
-                       rl = ntfs_rl_realloc(runlist->rl, old_size, new_size);
-                       if (IS_ERR(rl))
-                               ntfs_warning(vol->sb, "Failed to shrink "
-                                               "runlist buffer.  This just "
-                                               "wastes a bit of memory "
-                                               "temporarily so we ignore it "
-                                               "and return success.");
-                       else
-                               runlist->rl = rl;
-               }
-       } else if (likely(/* !rl->length && */ new_length > rl->vcn)) {
-               ntfs_debug("Expanding runlist.");
-               /*
-                * If there is a previous runlist element and it is a sparse
-                * one, extend it.  Otherwise need to add a new, sparse runlist
-                * element.
-                */
-               if ((rl > runlist->rl) && ((rl - 1)->lcn == LCN_HOLE))
-                       (rl - 1)->length = new_length - (rl - 1)->vcn;
-               else {
-                       /* Determine the runlist size. */
-                       old_size = rl - runlist->rl + 1;
-                       /* Reallocate memory if necessary. */
-                       rl = ntfs_rl_realloc(runlist->rl, old_size,
-                                       old_size + 1);
-                       if (IS_ERR(rl)) {
-                               ntfs_error(vol->sb, "Failed to expand runlist "
-                                               "buffer, aborting.");
-                               return PTR_ERR(rl);
-                       }
-                       runlist->rl = rl;
-                       /*
-                        * Set @rl to the same runlist element in the new
-                        * runlist as before in the old runlist.
-                        */
-                       rl += old_size - 1;
-                       /* Add a new, sparse runlist element. */
-                       rl->lcn = LCN_HOLE;
-                       rl->length = new_length - rl->vcn;
-                       /* Add a new terminator runlist element. */
-                       rl++;
-                       rl->length = 0;
-               }
-               rl->vcn = new_length;
-               rl->lcn = LCN_ENOENT;
-       } else /* if (unlikely(!rl->length && new_length == rl->vcn)) */ {
-               /* Runlist already has same size as requested. */
-               rl->lcn = LCN_ENOENT;
-       }
-       ntfs_debug("Done.");
-       return 0;
-}
-
-/**
- * ntfs_rl_punch_nolock - punch a hole into a runlist
- * @vol:       ntfs volume (needed for error output)
- * @runlist:   runlist to punch a hole into
- * @start:     starting VCN of the hole to be created
- * @length:    size of the hole to be created in units of clusters
- *
- * Punch a hole into the runlist @runlist starting at VCN @start and of size
- * @length clusters.
- *
- * Return 0 on success and -errno on error, in which case @runlist has not been
- * modified.
- *
- * If @start and/or @start + @length are outside the runlist return error code
- * -ENOENT.
- *
- * If the runlist contains unmapped or error elements between @start and @start
- * + @length return error code -EINVAL.
- *
- * Locking: The caller must hold @runlist->lock for writing.
- */
-int ntfs_rl_punch_nolock(const ntfs_volume *vol, runlist *const runlist,
-               const VCN start, const s64 length)
-{
-       const VCN end = start + length;
-       s64 delta;
-       runlist_element *rl, *rl_end, *rl_real_end, *trl;
-       int old_size;
-       bool lcn_fixup = false;
-
-       ntfs_debug("Entering for start 0x%llx, length 0x%llx.",
-                       (long long)start, (long long)length);
-       BUG_ON(!runlist);
-       BUG_ON(start < 0);
-       BUG_ON(length < 0);
-       BUG_ON(end < 0);
-       rl = runlist->rl;
-       if (unlikely(!rl)) {
-               if (likely(!start && !length))
-                       return 0;
-               return -ENOENT;
-       }
-       /* Find @start in the runlist. */
-       while (likely(rl->length && start >= rl[1].vcn))
-               rl++;
-       rl_end = rl;
-       /* Find @end in the runlist. */
-       while (likely(rl_end->length && end >= rl_end[1].vcn)) {
-               /* Verify there are no unmapped or error elements. */
-               if (unlikely(rl_end->lcn < LCN_HOLE))
-                       return -EINVAL;
-               rl_end++;
-       }
-       /* Check the last element. */
-       if (unlikely(rl_end->length && rl_end->lcn < LCN_HOLE))
-               return -EINVAL;
-       /* This covers @start being out of bounds, too. */
-       if (!rl_end->length && end > rl_end->vcn)
-               return -ENOENT;
-       if (!length)
-               return 0;
-       if (!rl->length)
-               return -ENOENT;
-       rl_real_end = rl_end;
-       /* Determine the runlist size. */
-       while (likely(rl_real_end->length))
-               rl_real_end++;
-       old_size = rl_real_end - runlist->rl + 1;
-       /* If @start is in a hole simply extend the hole. */
-       if (rl->lcn == LCN_HOLE) {
-               /*
-                * If both @start and @end are in the same sparse run, we are
-                * done.
-                */
-               if (end <= rl[1].vcn) {
-                       ntfs_debug("Done (requested hole is already sparse).");
-                       return 0;
-               }
-extend_hole:
-               /* Extend the hole. */
-               rl->length = end - rl->vcn;
-               /* If @end is in a hole, merge it with the current one. */
-               if (rl_end->lcn == LCN_HOLE) {
-                       rl_end++;
-                       rl->length = rl_end->vcn - rl->vcn;
-               }
-               /* We have done the hole.  Now deal with the remaining tail. */
-               rl++;
-               /* Cut out all runlist elements up to @end. */
-               if (rl < rl_end)
-                       memmove(rl, rl_end, (rl_real_end - rl_end + 1) *
-                                       sizeof(*rl));
-               /* Adjust the beginning of the tail if necessary. */
-               if (end > rl->vcn) {
-                       delta = end - rl->vcn;
-                       rl->vcn = end;
-                       rl->length -= delta;
-                       /* Only adjust the lcn if it is real. */
-                       if (rl->lcn >= 0)
-                               rl->lcn += delta;
-               }
-shrink_allocation:
-               /* Reallocate memory if the allocation changed. */
-               if (rl < rl_end) {
-                       rl = ntfs_rl_realloc(runlist->rl, old_size,
-                                       old_size - (rl_end - rl));
-                       if (IS_ERR(rl))
-                               ntfs_warning(vol->sb, "Failed to shrink "
-                                               "runlist buffer.  This just "
-                                               "wastes a bit of memory "
-                                               "temporarily so we ignore it "
-                                               "and return success.");
-                       else
-                               runlist->rl = rl;
-               }
-               ntfs_debug("Done (extend hole).");
-               return 0;
-       }
-       /*
-        * If @start is at the beginning of a run things are easier as there is
-        * no need to split the first run.
-        */
-       if (start == rl->vcn) {
-               /*
-                * @start is at the beginning of a run.
-                *
-                * If the previous run is sparse, extend its hole.
-                *
-                * If @end is not in the same run, switch the run to be sparse
-                * and extend the newly created hole.
-                *
-                * Thus both of these cases reduce the problem to the above
-                * case of "@start is in a hole".
-                */
-               if (rl > runlist->rl && (rl - 1)->lcn == LCN_HOLE) {
-                       rl--;
-                       goto extend_hole;
-               }
-               if (end >= rl[1].vcn) {
-                       rl->lcn = LCN_HOLE;
-                       goto extend_hole;
-               }
-               /*
-                * The final case is when @end is in the same run as @start.
-                * For this need to split the run into two.  One run for the
-                * sparse region between the beginning of the old run, i.e.
-                * @start, and @end and one for the remaining non-sparse
-                * region, i.e. between @end and the end of the old run.
-                */
-               trl = ntfs_rl_realloc(runlist->rl, old_size, old_size + 1);
-               if (IS_ERR(trl))
-                       goto enomem_out;
-               old_size++;
-               if (runlist->rl != trl) {
-                       rl = trl + (rl - runlist->rl);
-                       rl_end = trl + (rl_end - runlist->rl);
-                       rl_real_end = trl + (rl_real_end - runlist->rl);
-                       runlist->rl = trl;
-               }
-split_end:
-               /* Shift all the runs up by one. */
-               memmove(rl + 1, rl, (rl_real_end - rl + 1) * sizeof(*rl));
-               /* Finally, setup the two split runs. */
-               rl->lcn = LCN_HOLE;
-               rl->length = length;
-               rl++;
-               rl->vcn += length;
-               /* Only adjust the lcn if it is real. */
-               if (rl->lcn >= 0 || lcn_fixup)
-                       rl->lcn += length;
-               rl->length -= length;
-               ntfs_debug("Done (split one).");
-               return 0;
-       }
-       /*
-        * @start is neither in a hole nor at the beginning of a run.
-        *
-        * If @end is in a hole, things are easier as simply truncating the run
-        * @start is in to end at @start - 1, deleting all runs after that up
-        * to @end, and finally extending the beginning of the run @end is in
-        * to be @start is all that is needed.
-        */
-       if (rl_end->lcn == LCN_HOLE) {
-               /* Truncate the run containing @start. */
-               rl->length = start - rl->vcn;
-               rl++;
-               /* Cut out all runlist elements up to @end. */
-               if (rl < rl_end)
-                       memmove(rl, rl_end, (rl_real_end - rl_end + 1) *
-                                       sizeof(*rl));
-               /* Extend the beginning of the run @end is in to be @start. */
-               rl->vcn = start;
-               rl->length = rl[1].vcn - start;
-               goto shrink_allocation;
-       }
-       /* 
-        * If @end is not in a hole there are still two cases to distinguish.
-        * Either @end is or is not in the same run as @start.
-        *
-        * The second case is easier as it can be reduced to an already solved
-        * problem by truncating the run @start is in to end at @start - 1.
-        * Then, if @end is in the next run need to split the run into a sparse
-        * run followed by a non-sparse run (already covered above) and if @end
-        * is not in the next run switching it to be sparse, again reduces the
-        * problem to the already covered case of "@start is in a hole".
-        */
-       if (end >= rl[1].vcn) {
-               /*
-                * If @end is not in the next run, reduce the problem to the
-                * case of "@start is in a hole".
-                */
-               if (rl[1].length && end >= rl[2].vcn) {
-                       /* Truncate the run containing @start. */
-                       rl->length = start - rl->vcn;
-                       rl++;
-                       rl->vcn = start;
-                       rl->lcn = LCN_HOLE;
-                       goto extend_hole;
-               }
-               trl = ntfs_rl_realloc(runlist->rl, old_size, old_size + 1);
-               if (IS_ERR(trl))
-                       goto enomem_out;
-               old_size++;
-               if (runlist->rl != trl) {
-                       rl = trl + (rl - runlist->rl);
-                       rl_end = trl + (rl_end - runlist->rl);
-                       rl_real_end = trl + (rl_real_end - runlist->rl);
-                       runlist->rl = trl;
-               }
-               /* Truncate the run containing @start. */
-               rl->length = start - rl->vcn;
-               rl++;
-               /*
-                * @end is in the next run, reduce the problem to the case
-                * where "@start is at the beginning of a run and @end is in
-                * the same run as @start".
-                */
-               delta = rl->vcn - start;
-               rl->vcn = start;
-               if (rl->lcn >= 0) {
-                       rl->lcn -= delta;
-                       /* Need this in case the lcn just became negative. */
-                       lcn_fixup = true;
-               }
-               rl->length += delta;
-               goto split_end;
-       }
-       /*
-        * The first case from above, i.e. @end is in the same run as @start.
-        * We need to split the run into three.  One run for the non-sparse
-        * region between the beginning of the old run and @start, one for the
-        * sparse region between @start and @end, and one for the remaining
-        * non-sparse region, i.e. between @end and the end of the old run.
-        */
-       trl = ntfs_rl_realloc(runlist->rl, old_size, old_size + 2);
-       if (IS_ERR(trl))
-               goto enomem_out;
-       old_size += 2;
-       if (runlist->rl != trl) {
-               rl = trl + (rl - runlist->rl);
-               rl_end = trl + (rl_end - runlist->rl);
-               rl_real_end = trl + (rl_real_end - runlist->rl);
-               runlist->rl = trl;
-       }
-       /* Shift all the runs up by two. */
-       memmove(rl + 2, rl, (rl_real_end - rl + 1) * sizeof(*rl));
-       /* Finally, setup the three split runs. */
-       rl->length = start - rl->vcn;
-       rl++;
-       rl->vcn = start;
-       rl->lcn = LCN_HOLE;
-       rl->length = length;
-       rl++;
-       delta = end - rl->vcn;
-       rl->vcn = end;
-       rl->lcn += delta;
-       rl->length -= delta;
-       ntfs_debug("Done (split both).");
-       return 0;
-enomem_out:
-       ntfs_error(vol->sb, "Not enough memory to extend runlist buffer.");
-       return -ENOMEM;
-}
-
-#endif /* NTFS_RW */
diff --git a/fs/ntfs/runlist.h b/fs/ntfs/runlist.h
deleted file mode 100644 (file)
index 38de0a3..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * runlist.h - Defines for runlist handling in NTFS Linux kernel driver.
- *            Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2005 Anton Altaparmakov
- * Copyright (c) 2002 Richard Russon
- */
-
-#ifndef _LINUX_NTFS_RUNLIST_H
-#define _LINUX_NTFS_RUNLIST_H
-
-#include "types.h"
-#include "layout.h"
-#include "volume.h"
-
-/**
- * runlist_element - in memory vcn to lcn mapping array element
- * @vcn:       starting vcn of the current array element
- * @lcn:       starting lcn of the current array element
- * @length:    length in clusters of the current array element
- *
- * The last vcn (in fact the last vcn + 1) is reached when length == 0.
- *
- * When lcn == -1 this means that the count vcns starting at vcn are not
- * physically allocated (i.e. this is a hole / data is sparse).
- */
-typedef struct {       /* In memory vcn to lcn mapping structure element. */
-       VCN vcn;        /* vcn = Starting virtual cluster number. */
-       LCN lcn;        /* lcn = Starting logical cluster number. */
-       s64 length;     /* Run length in clusters. */
-} runlist_element;
-
-/**
- * runlist - in memory vcn to lcn mapping array including a read/write lock
- * @rl:                pointer to an array of runlist elements
- * @lock:      read/write spinlock for serializing access to @rl
- *
- */
-typedef struct {
-       runlist_element *rl;
-       struct rw_semaphore lock;
-} runlist;
-
-static inline void ntfs_init_runlist(runlist *rl)
-{
-       rl->rl = NULL;
-       init_rwsem(&rl->lock);
-}
-
-typedef enum {
-       LCN_HOLE                = -1,   /* Keep this as highest value or die! */
-       LCN_RL_NOT_MAPPED       = -2,
-       LCN_ENOENT              = -3,
-       LCN_ENOMEM              = -4,
-       LCN_EIO                 = -5,
-} LCN_SPECIAL_VALUES;
-
-extern runlist_element *ntfs_runlists_merge(runlist_element *drl,
-               runlist_element *srl);
-
-extern runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol,
-               const ATTR_RECORD *attr, runlist_element *old_rl);
-
-extern LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn);
-
-#ifdef NTFS_RW
-
-extern runlist_element *ntfs_rl_find_vcn_nolock(runlist_element *rl,
-               const VCN vcn);
-
-extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
-               const runlist_element *rl, const VCN first_vcn,
-               const VCN last_vcn);
-
-extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst,
-               const int dst_len, const runlist_element *rl,
-               const VCN first_vcn, const VCN last_vcn, VCN *const stop_vcn);
-
-extern int ntfs_rl_truncate_nolock(const ntfs_volume *vol,
-               runlist *const runlist, const s64 new_length);
-
-int ntfs_rl_punch_nolock(const ntfs_volume *vol, runlist *const runlist,
-               const VCN start, const s64 length);
-
-#endif /* NTFS_RW */
-
-#endif /* _LINUX_NTFS_RUNLIST_H */
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
deleted file mode 100644 (file)
index 56a7d5b..0000000
+++ /dev/null
@@ -1,3202 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * super.c - NTFS kernel super block handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2012 Anton Altaparmakov and Tuxera Inc.
- * Copyright (c) 2001,2002 Richard Russon
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/blkdev.h>      /* For bdev_logical_block_size(). */
-#include <linux/backing-dev.h>
-#include <linux/buffer_head.h>
-#include <linux/vfs.h>
-#include <linux/moduleparam.h>
-#include <linux/bitmap.h>
-
-#include "sysctl.h"
-#include "logfile.h"
-#include "quota.h"
-#include "usnjrnl.h"
-#include "dir.h"
-#include "debug.h"
-#include "index.h"
-#include "inode.h"
-#include "aops.h"
-#include "layout.h"
-#include "malloc.h"
-#include "ntfs.h"
-
-/* Number of mounted filesystems which have compression enabled. */
-static unsigned long ntfs_nr_compression_users;
-
-/* A global default upcase table and a corresponding reference count. */
-static ntfschar *default_upcase;
-static unsigned long ntfs_nr_upcase_users;
-
-/* Error constants/strings used in inode.c::ntfs_show_options(). */
-typedef enum {
-       /* One of these must be present, default is ON_ERRORS_CONTINUE. */
-       ON_ERRORS_PANIC                 = 0x01,
-       ON_ERRORS_REMOUNT_RO            = 0x02,
-       ON_ERRORS_CONTINUE              = 0x04,
-       /* Optional, can be combined with any of the above. */
-       ON_ERRORS_RECOVER               = 0x10,
-} ON_ERRORS_ACTIONS;
-
-const option_t on_errors_arr[] = {
-       { ON_ERRORS_PANIC,      "panic" },
-       { ON_ERRORS_REMOUNT_RO, "remount-ro", },
-       { ON_ERRORS_CONTINUE,   "continue", },
-       { ON_ERRORS_RECOVER,    "recover" },
-       { 0,                    NULL }
-};
-
-/**
- * simple_getbool - convert input string to a boolean value
- * @s: input string to convert
- * @setval: where to store the output boolean value
- *
- * Copied from old ntfs driver (which copied from vfat driver).
- *
- * "1", "yes", "true", or an empty string are converted to %true.
- * "0", "no", and "false" are converted to %false.
- *
- * Return: %1 if the string is converted or was empty and *setval contains it;
- *        %0 if the string was not valid.
- */
-static int simple_getbool(char *s, bool *setval)
-{
-       if (s) {
-               if (!strcmp(s, "1") || !strcmp(s, "yes") || !strcmp(s, "true"))
-                       *setval = true;
-               else if (!strcmp(s, "0") || !strcmp(s, "no") ||
-                                                       !strcmp(s, "false"))
-                       *setval = false;
-               else
-                       return 0;
-       } else
-               *setval = true;
-       return 1;
-}
-
-/**
- * parse_options - parse the (re)mount options
- * @vol:       ntfs volume
- * @opt:       string containing the (re)mount options
- *
- * Parse the recognized options in @opt for the ntfs volume described by @vol.
- */
-static bool parse_options(ntfs_volume *vol, char *opt)
-{
-       char *p, *v, *ov;
-       static char *utf8 = "utf8";
-       int errors = 0, sloppy = 0;
-       kuid_t uid = INVALID_UID;
-       kgid_t gid = INVALID_GID;
-       umode_t fmask = (umode_t)-1, dmask = (umode_t)-1;
-       int mft_zone_multiplier = -1, on_errors = -1;
-       int show_sys_files = -1, case_sensitive = -1, disable_sparse = -1;
-       struct nls_table *nls_map = NULL, *old_nls;
-
-       /* I am lazy... (-8 */
-#define NTFS_GETOPT_WITH_DEFAULT(option, variable, default_value)      \
-       if (!strcmp(p, option)) {                                       \
-               if (!v || !*v)                                          \
-                       variable = default_value;                       \
-               else {                                                  \
-                       variable = simple_strtoul(ov = v, &v, 0);       \
-                       if (*v)                                         \
-                               goto needs_val;                         \
-               }                                                       \
-       }
-#define NTFS_GETOPT(option, variable)                                  \
-       if (!strcmp(p, option)) {                                       \
-               if (!v || !*v)                                          \
-                       goto needs_arg;                                 \
-               variable = simple_strtoul(ov = v, &v, 0);               \
-               if (*v)                                                 \
-                       goto needs_val;                                 \
-       }
-#define NTFS_GETOPT_UID(option, variable)                              \
-       if (!strcmp(p, option)) {                                       \
-               uid_t uid_value;                                        \
-               if (!v || !*v)                                          \
-                       goto needs_arg;                                 \
-               uid_value = simple_strtoul(ov = v, &v, 0);              \
-               if (*v)                                                 \
-                       goto needs_val;                                 \
-               variable = make_kuid(current_user_ns(), uid_value);     \
-               if (!uid_valid(variable))                               \
-                       goto needs_val;                                 \
-       }
-#define NTFS_GETOPT_GID(option, variable)                              \
-       if (!strcmp(p, option)) {                                       \
-               gid_t gid_value;                                        \
-               if (!v || !*v)                                          \
-                       goto needs_arg;                                 \
-               gid_value = simple_strtoul(ov = v, &v, 0);              \
-               if (*v)                                                 \
-                       goto needs_val;                                 \
-               variable = make_kgid(current_user_ns(), gid_value);     \
-               if (!gid_valid(variable))                               \
-                       goto needs_val;                                 \
-       }
-#define NTFS_GETOPT_OCTAL(option, variable)                            \
-       if (!strcmp(p, option)) {                                       \
-               if (!v || !*v)                                          \
-                       goto needs_arg;                                 \
-               variable = simple_strtoul(ov = v, &v, 8);               \
-               if (*v)                                                 \
-                       goto needs_val;                                 \
-       }
-#define NTFS_GETOPT_BOOL(option, variable)                             \
-       if (!strcmp(p, option)) {                                       \
-               bool val;                                               \
-               if (!simple_getbool(v, &val))                           \
-                       goto needs_bool;                                \
-               variable = val;                                         \
-       }
-#define NTFS_GETOPT_OPTIONS_ARRAY(option, variable, opt_array)         \
-       if (!strcmp(p, option)) {                                       \
-               int _i;                                                 \
-               if (!v || !*v)                                          \
-                       goto needs_arg;                                 \
-               ov = v;                                                 \
-               if (variable == -1)                                     \
-                       variable = 0;                                   \
-               for (_i = 0; opt_array[_i].str && *opt_array[_i].str; _i++) \
-                       if (!strcmp(opt_array[_i].str, v)) {            \
-                               variable |= opt_array[_i].val;          \
-                               break;                                  \
-                       }                                               \
-               if (!opt_array[_i].str || !*opt_array[_i].str)          \
-                       goto needs_val;                                 \
-       }
-       if (!opt || !*opt)
-               goto no_mount_options;
-       ntfs_debug("Entering with mount options string: %s", opt);
-       while ((p = strsep(&opt, ","))) {
-               if ((v = strchr(p, '=')))
-                       *v++ = 0;
-               NTFS_GETOPT_UID("uid", uid)
-               else NTFS_GETOPT_GID("gid", gid)
-               else NTFS_GETOPT_OCTAL("umask", fmask = dmask)
-               else NTFS_GETOPT_OCTAL("fmask", fmask)
-               else NTFS_GETOPT_OCTAL("dmask", dmask)
-               else NTFS_GETOPT("mft_zone_multiplier", mft_zone_multiplier)
-               else NTFS_GETOPT_WITH_DEFAULT("sloppy", sloppy, true)
-               else NTFS_GETOPT_BOOL("show_sys_files", show_sys_files)
-               else NTFS_GETOPT_BOOL("case_sensitive", case_sensitive)
-               else NTFS_GETOPT_BOOL("disable_sparse", disable_sparse)
-               else NTFS_GETOPT_OPTIONS_ARRAY("errors", on_errors,
-                               on_errors_arr)
-               else if (!strcmp(p, "posix") || !strcmp(p, "show_inodes"))
-                       ntfs_warning(vol->sb, "Ignoring obsolete option %s.",
-                                       p);
-               else if (!strcmp(p, "nls") || !strcmp(p, "iocharset")) {
-                       if (!strcmp(p, "iocharset"))
-                               ntfs_warning(vol->sb, "Option iocharset is "
-                                               "deprecated. Please use "
-                                               "option nls=<charsetname> in "
-                                               "the future.");
-                       if (!v || !*v)
-                               goto needs_arg;
-use_utf8:
-                       old_nls = nls_map;
-                       nls_map = load_nls(v);
-                       if (!nls_map) {
-                               if (!old_nls) {
-                                       ntfs_error(vol->sb, "NLS character set "
-                                                       "%s not found.", v);
-                                       return false;
-                               }
-                               ntfs_error(vol->sb, "NLS character set %s not "
-                                               "found. Using previous one %s.",
-                                               v, old_nls->charset);
-                               nls_map = old_nls;
-                       } else /* nls_map */ {
-                               unload_nls(old_nls);
-                       }
-               } else if (!strcmp(p, "utf8")) {
-                       bool val = false;
-                       ntfs_warning(vol->sb, "Option utf8 is no longer "
-                                  "supported, using option nls=utf8. Please "
-                                  "use option nls=utf8 in the future and "
-                                  "make sure utf8 is compiled either as a "
-                                  "module or into the kernel.");
-                       if (!v || !*v)
-                               val = true;
-                       else if (!simple_getbool(v, &val))
-                               goto needs_bool;
-                       if (val) {
-                               v = utf8;
-                               goto use_utf8;
-                       }
-               } else {
-                       ntfs_error(vol->sb, "Unrecognized mount option %s.", p);
-                       if (errors < INT_MAX)
-                               errors++;
-               }
-#undef NTFS_GETOPT_OPTIONS_ARRAY
-#undef NTFS_GETOPT_BOOL
-#undef NTFS_GETOPT
-#undef NTFS_GETOPT_WITH_DEFAULT
-       }
-no_mount_options:
-       if (errors && !sloppy)
-               return false;
-       if (sloppy)
-               ntfs_warning(vol->sb, "Sloppy option given. Ignoring "
-                               "unrecognized mount option(s) and continuing.");
-       /* Keep this first! */
-       if (on_errors != -1) {
-               if (!on_errors) {
-                       ntfs_error(vol->sb, "Invalid errors option argument "
-                                       "or bug in options parser.");
-                       return false;
-               }
-       }
-       if (nls_map) {
-               if (vol->nls_map && vol->nls_map != nls_map) {
-                       ntfs_error(vol->sb, "Cannot change NLS character set "
-                                       "on remount.");
-                       return false;
-               } /* else (!vol->nls_map) */
-               ntfs_debug("Using NLS character set %s.", nls_map->charset);
-               vol->nls_map = nls_map;
-       } else /* (!nls_map) */ {
-               if (!vol->nls_map) {
-                       vol->nls_map = load_nls_default();
-                       if (!vol->nls_map) {
-                               ntfs_error(vol->sb, "Failed to load default "
-                                               "NLS character set.");
-                               return false;
-                       }
-                       ntfs_debug("Using default NLS character set (%s).",
-                                       vol->nls_map->charset);
-               }
-       }
-       if (mft_zone_multiplier != -1) {
-               if (vol->mft_zone_multiplier && vol->mft_zone_multiplier !=
-                               mft_zone_multiplier) {
-                       ntfs_error(vol->sb, "Cannot change mft_zone_multiplier "
-                                       "on remount.");
-                       return false;
-               }
-               if (mft_zone_multiplier < 1 || mft_zone_multiplier > 4) {
-                       ntfs_error(vol->sb, "Invalid mft_zone_multiplier. "
-                                       "Using default value, i.e. 1.");
-                       mft_zone_multiplier = 1;
-               }
-               vol->mft_zone_multiplier = mft_zone_multiplier;
-       }
-       if (!vol->mft_zone_multiplier)
-               vol->mft_zone_multiplier = 1;
-       if (on_errors != -1)
-               vol->on_errors = on_errors;
-       if (!vol->on_errors || vol->on_errors == ON_ERRORS_RECOVER)
-               vol->on_errors |= ON_ERRORS_CONTINUE;
-       if (uid_valid(uid))
-               vol->uid = uid;
-       if (gid_valid(gid))
-               vol->gid = gid;
-       if (fmask != (umode_t)-1)
-               vol->fmask = fmask;
-       if (dmask != (umode_t)-1)
-               vol->dmask = dmask;
-       if (show_sys_files != -1) {
-               if (show_sys_files)
-                       NVolSetShowSystemFiles(vol);
-               else
-                       NVolClearShowSystemFiles(vol);
-       }
-       if (case_sensitive != -1) {
-               if (case_sensitive)
-                       NVolSetCaseSensitive(vol);
-               else
-                       NVolClearCaseSensitive(vol);
-       }
-       if (disable_sparse != -1) {
-               if (disable_sparse)
-                       NVolClearSparseEnabled(vol);
-               else {
-                       if (!NVolSparseEnabled(vol) &&
-                                       vol->major_ver && vol->major_ver < 3)
-                               ntfs_warning(vol->sb, "Not enabling sparse "
-                                               "support due to NTFS volume "
-                                               "version %i.%i (need at least "
-                                               "version 3.0).", vol->major_ver,
-                                               vol->minor_ver);
-                       else
-                               NVolSetSparseEnabled(vol);
-               }
-       }
-       return true;
-needs_arg:
-       ntfs_error(vol->sb, "The %s option requires an argument.", p);
-       return false;
-needs_bool:
-       ntfs_error(vol->sb, "The %s option requires a boolean argument.", p);
-       return false;
-needs_val:
-       ntfs_error(vol->sb, "Invalid %s option argument: %s", p, ov);
-       return false;
-}
-
-#ifdef NTFS_RW
-
-/**
- * ntfs_write_volume_flags - write new flags to the volume information flags
- * @vol:       ntfs volume on which to modify the flags
- * @flags:     new flags value for the volume information flags
- *
- * Internal function.  You probably want to use ntfs_{set,clear}_volume_flags()
- * instead (see below).
- *
- * Replace the volume information flags on the volume @vol with the value
- * supplied in @flags.  Note, this overwrites the volume information flags, so
- * make sure to combine the flags you want to modify with the old flags and use
- * the result when calling ntfs_write_volume_flags().
- *
- * Return 0 on success and -errno on error.
- */
-static int ntfs_write_volume_flags(ntfs_volume *vol, const VOLUME_FLAGS flags)
-{
-       ntfs_inode *ni = NTFS_I(vol->vol_ino);
-       MFT_RECORD *m;
-       VOLUME_INFORMATION *vi;
-       ntfs_attr_search_ctx *ctx;
-       int err;
-
-       ntfs_debug("Entering, old flags = 0x%x, new flags = 0x%x.",
-                       le16_to_cpu(vol->vol_flags), le16_to_cpu(flags));
-       if (vol->vol_flags == flags)
-               goto done;
-       BUG_ON(!ni);
-       m = map_mft_record(ni);
-       if (IS_ERR(m)) {
-               err = PTR_ERR(m);
-               goto err_out;
-       }
-       ctx = ntfs_attr_get_search_ctx(ni, m);
-       if (!ctx) {
-               err = -ENOMEM;
-               goto put_unm_err_out;
-       }
-       err = ntfs_attr_lookup(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0,
-                       ctx);
-       if (err)
-               goto put_unm_err_out;
-       vi = (VOLUME_INFORMATION*)((u8*)ctx->attr +
-                       le16_to_cpu(ctx->attr->data.resident.value_offset));
-       vol->vol_flags = vi->flags = flags;
-       flush_dcache_mft_record_page(ctx->ntfs_ino);
-       mark_mft_record_dirty(ctx->ntfs_ino);
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(ni);
-done:
-       ntfs_debug("Done.");
-       return 0;
-put_unm_err_out:
-       if (ctx)
-               ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(ni);
-err_out:
-       ntfs_error(vol->sb, "Failed with error code %i.", -err);
-       return err;
-}
-
-/**
- * ntfs_set_volume_flags - set bits in the volume information flags
- * @vol:       ntfs volume on which to modify the flags
- * @flags:     flags to set on the volume
- *
- * Set the bits in @flags in the volume information flags on the volume @vol.
- *
- * Return 0 on success and -errno on error.
- */
-static inline int ntfs_set_volume_flags(ntfs_volume *vol, VOLUME_FLAGS flags)
-{
-       flags &= VOLUME_FLAGS_MASK;
-       return ntfs_write_volume_flags(vol, vol->vol_flags | flags);
-}
-
-/**
- * ntfs_clear_volume_flags - clear bits in the volume information flags
- * @vol:       ntfs volume on which to modify the flags
- * @flags:     flags to clear on the volume
- *
- * Clear the bits in @flags in the volume information flags on the volume @vol.
- *
- * Return 0 on success and -errno on error.
- */
-static inline int ntfs_clear_volume_flags(ntfs_volume *vol, VOLUME_FLAGS flags)
-{
-       flags &= VOLUME_FLAGS_MASK;
-       flags = vol->vol_flags & cpu_to_le16(~le16_to_cpu(flags));
-       return ntfs_write_volume_flags(vol, flags);
-}
-
-#endif /* NTFS_RW */
-
-/**
- * ntfs_remount - change the mount options of a mounted ntfs filesystem
- * @sb:                superblock of mounted ntfs filesystem
- * @flags:     remount flags
- * @opt:       remount options string
- *
- * Change the mount options of an already mounted ntfs filesystem.
- *
- * NOTE:  The VFS sets the @sb->s_flags remount flags to @flags after
- * ntfs_remount() returns successfully (i.e. returns 0).  Otherwise,
- * @sb->s_flags are not changed.
- */
-static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
-{
-       ntfs_volume *vol = NTFS_SB(sb);
-
-       ntfs_debug("Entering with remount options string: %s", opt);
-
-       sync_filesystem(sb);
-
-#ifndef NTFS_RW
-       /* For read-only compiled driver, enforce read-only flag. */
-       *flags |= SB_RDONLY;
-#else /* NTFS_RW */
-       /*
-        * For the read-write compiled driver, if we are remounting read-write,
-        * make sure there are no volume errors and that no unsupported volume
-        * flags are set.  Also, empty the logfile journal as it would become
-        * stale as soon as something is written to the volume and mark the
-        * volume dirty so that chkdsk is run if the volume is not umounted
-        * cleanly.  Finally, mark the quotas out of date so Windows rescans
-        * the volume on boot and updates them.
-        *
-        * When remounting read-only, mark the volume clean if no volume errors
-        * have occurred.
-        */
-       if (sb_rdonly(sb) && !(*flags & SB_RDONLY)) {
-               static const char *es = ".  Cannot remount read-write.";
-
-               /* Remounting read-write. */
-               if (NVolErrors(vol)) {
-                       ntfs_error(sb, "Volume has errors and is read-only%s",
-                                       es);
-                       return -EROFS;
-               }
-               if (vol->vol_flags & VOLUME_IS_DIRTY) {
-                       ntfs_error(sb, "Volume is dirty and read-only%s", es);
-                       return -EROFS;
-               }
-               if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) {
-                       ntfs_error(sb, "Volume has been modified by chkdsk "
-                                       "and is read-only%s", es);
-                       return -EROFS;
-               }
-               if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) {
-                       ntfs_error(sb, "Volume has unsupported flags set "
-                                       "(0x%x) and is read-only%s",
-                                       (unsigned)le16_to_cpu(vol->vol_flags),
-                                       es);
-                       return -EROFS;
-               }
-               if (ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) {
-                       ntfs_error(sb, "Failed to set dirty bit in volume "
-                                       "information flags%s", es);
-                       return -EROFS;
-               }
-#if 0
-               // TODO: Enable this code once we start modifying anything that
-               //       is different between NTFS 1.2 and 3.x...
-               /* Set NT4 compatibility flag on newer NTFS version volumes. */
-               if ((vol->major_ver > 1)) {
-                       if (ntfs_set_volume_flags(vol, VOLUME_MOUNTED_ON_NT4)) {
-                               ntfs_error(sb, "Failed to set NT4 "
-                                               "compatibility flag%s", es);
-                               NVolSetErrors(vol);
-                               return -EROFS;
-                       }
-               }
-#endif
-               if (!ntfs_empty_logfile(vol->logfile_ino)) {
-                       ntfs_error(sb, "Failed to empty journal $LogFile%s",
-                                       es);
-                       NVolSetErrors(vol);
-                       return -EROFS;
-               }
-               if (!ntfs_mark_quotas_out_of_date(vol)) {
-                       ntfs_error(sb, "Failed to mark quotas out of date%s",
-                                       es);
-                       NVolSetErrors(vol);
-                       return -EROFS;
-               }
-               if (!ntfs_stamp_usnjrnl(vol)) {
-                       ntfs_error(sb, "Failed to stamp transaction log "
-                                       "($UsnJrnl)%s", es);
-                       NVolSetErrors(vol);
-                       return -EROFS;
-               }
-       } else if (!sb_rdonly(sb) && (*flags & SB_RDONLY)) {
-               /* Remounting read-only. */
-               if (!NVolErrors(vol)) {
-                       if (ntfs_clear_volume_flags(vol, VOLUME_IS_DIRTY))
-                               ntfs_warning(sb, "Failed to clear dirty bit "
-                                               "in volume information "
-                                               "flags.  Run chkdsk.");
-               }
-       }
-#endif /* NTFS_RW */
-
-       // TODO: Deal with *flags.
-
-       if (!parse_options(vol, opt))
-               return -EINVAL;
-
-       ntfs_debug("Done.");
-       return 0;
-}
-
-/**
- * is_boot_sector_ntfs - check whether a boot sector is a valid NTFS boot sector
- * @sb:                Super block of the device to which @b belongs.
- * @b:         Boot sector of device @sb to check.
- * @silent:    If 'true', all output will be silenced.
- *
- * is_boot_sector_ntfs() checks whether the boot sector @b is a valid NTFS boot
- * sector. Returns 'true' if it is valid and 'false' if not.
- *
- * @sb is only needed for warning/error output, i.e. it can be NULL when silent
- * is 'true'.
- */
-static bool is_boot_sector_ntfs(const struct super_block *sb,
-               const NTFS_BOOT_SECTOR *b, const bool silent)
-{
-       /*
-        * Check that checksum == sum of u32 values from b to the checksum
-        * field.  If checksum is zero, no checking is done.  We will work when
-        * the checksum test fails, since some utilities update the boot sector
-        * ignoring the checksum which leaves the checksum out-of-date.  We
-        * report a warning if this is the case.
-        */
-       if ((void*)b < (void*)&b->checksum && b->checksum && !silent) {
-               le32 *u;
-               u32 i;
-
-               for (i = 0, u = (le32*)b; u < (le32*)(&b->checksum); ++u)
-                       i += le32_to_cpup(u);
-               if (le32_to_cpu(b->checksum) != i)
-                       ntfs_warning(sb, "Invalid boot sector checksum.");
-       }
-       /* Check OEMidentifier is "NTFS    " */
-       if (b->oem_id != magicNTFS)
-               goto not_ntfs;
-       /* Check bytes per sector value is between 256 and 4096. */
-       if (le16_to_cpu(b->bpb.bytes_per_sector) < 0x100 ||
-                       le16_to_cpu(b->bpb.bytes_per_sector) > 0x1000)
-               goto not_ntfs;
-       /* Check sectors per cluster value is valid. */
-       switch (b->bpb.sectors_per_cluster) {
-       case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
-               break;
-       default:
-               goto not_ntfs;
-       }
-       /* Check the cluster size is not above the maximum (64kiB). */
-       if ((u32)le16_to_cpu(b->bpb.bytes_per_sector) *
-                       b->bpb.sectors_per_cluster > NTFS_MAX_CLUSTER_SIZE)
-               goto not_ntfs;
-       /* Check reserved/unused fields are really zero. */
-       if (le16_to_cpu(b->bpb.reserved_sectors) ||
-                       le16_to_cpu(b->bpb.root_entries) ||
-                       le16_to_cpu(b->bpb.sectors) ||
-                       le16_to_cpu(b->bpb.sectors_per_fat) ||
-                       le32_to_cpu(b->bpb.large_sectors) || b->bpb.fats)
-               goto not_ntfs;
-       /* Check clusters per file mft record value is valid. */
-       if ((u8)b->clusters_per_mft_record < 0xe1 ||
-                       (u8)b->clusters_per_mft_record > 0xf7)
-               switch (b->clusters_per_mft_record) {
-               case 1: case 2: case 4: case 8: case 16: case 32: case 64:
-                       break;
-               default:
-                       goto not_ntfs;
-               }
-       /* Check clusters per index block value is valid. */
-       if ((u8)b->clusters_per_index_record < 0xe1 ||
-                       (u8)b->clusters_per_index_record > 0xf7)
-               switch (b->clusters_per_index_record) {
-               case 1: case 2: case 4: case 8: case 16: case 32: case 64:
-                       break;
-               default:
-                       goto not_ntfs;
-               }
-       /*
-        * Check for valid end of sector marker. We will work without it, but
-        * many BIOSes will refuse to boot from a bootsector if the magic is
-        * incorrect, so we emit a warning.
-        */
-       if (!silent && b->end_of_sector_marker != cpu_to_le16(0xaa55))
-               ntfs_warning(sb, "Invalid end of sector marker.");
-       return true;
-not_ntfs:
-       return false;
-}
-
-/**
- * read_ntfs_boot_sector - read the NTFS boot sector of a device
- * @sb:                super block of device to read the boot sector from
- * @silent:    if true, suppress all output
- *
- * Reads the boot sector from the device and validates it. If that fails, tries
- * to read the backup boot sector, first from the end of the device a-la NT4 and
- * later and then from the middle of the device a-la NT3.51 and before.
- *
- * If a valid boot sector is found but it is not the primary boot sector, we
- * repair the primary boot sector silently (unless the device is read-only or
- * the primary boot sector is not accessible).
- *
- * NOTE: To call this function, @sb must have the fields s_dev, the ntfs super
- * block (u.ntfs_sb), nr_blocks and the device flags (s_flags) initialized
- * to their respective values.
- *
- * Return the unlocked buffer head containing the boot sector or NULL on error.
- */
-static struct buffer_head *read_ntfs_boot_sector(struct super_block *sb,
-               const int silent)
-{
-       const char *read_err_str = "Unable to read %s boot sector.";
-       struct buffer_head *bh_primary, *bh_backup;
-       sector_t nr_blocks = NTFS_SB(sb)->nr_blocks;
-
-       /* Try to read primary boot sector. */
-       if ((bh_primary = sb_bread(sb, 0))) {
-               if (is_boot_sector_ntfs(sb, (NTFS_BOOT_SECTOR*)
-                               bh_primary->b_data, silent))
-                       return bh_primary;
-               if (!silent)
-                       ntfs_error(sb, "Primary boot sector is invalid.");
-       } else if (!silent)
-               ntfs_error(sb, read_err_str, "primary");
-       if (!(NTFS_SB(sb)->on_errors & ON_ERRORS_RECOVER)) {
-               if (bh_primary)
-                       brelse(bh_primary);
-               if (!silent)
-                       ntfs_error(sb, "Mount option errors=recover not used. "
-                                       "Aborting without trying to recover.");
-               return NULL;
-       }
-       /* Try to read NT4+ backup boot sector. */
-       if ((bh_backup = sb_bread(sb, nr_blocks - 1))) {
-               if (is_boot_sector_ntfs(sb, (NTFS_BOOT_SECTOR*)
-                               bh_backup->b_data, silent))
-                       goto hotfix_primary_boot_sector;
-               brelse(bh_backup);
-       } else if (!silent)
-               ntfs_error(sb, read_err_str, "backup");
-       /* Try to read NT3.51- backup boot sector. */
-       if ((bh_backup = sb_bread(sb, nr_blocks >> 1))) {
-               if (is_boot_sector_ntfs(sb, (NTFS_BOOT_SECTOR*)
-                               bh_backup->b_data, silent))
-                       goto hotfix_primary_boot_sector;
-               if (!silent)
-                       ntfs_error(sb, "Could not find a valid backup boot "
-                                       "sector.");
-               brelse(bh_backup);
-       } else if (!silent)
-               ntfs_error(sb, read_err_str, "backup");
-       /* We failed. Cleanup and return. */
-       if (bh_primary)
-               brelse(bh_primary);
-       return NULL;
-hotfix_primary_boot_sector:
-       if (bh_primary) {
-               /*
-                * If we managed to read sector zero and the volume is not
-                * read-only, copy the found, valid backup boot sector to the
-                * primary boot sector.  Note we only copy the actual boot
-                * sector structure, not the actual whole device sector as that
-                * may be bigger and would potentially damage the $Boot system
-                * file (FIXME: Would be nice to know if the backup boot sector
-                * on a large sector device contains the whole boot loader or
-                * just the first 512 bytes).
-                */
-               if (!sb_rdonly(sb)) {
-                       ntfs_warning(sb, "Hot-fix: Recovering invalid primary "
-                                       "boot sector from backup copy.");
-                       memcpy(bh_primary->b_data, bh_backup->b_data,
-                                       NTFS_BLOCK_SIZE);
-                       mark_buffer_dirty(bh_primary);
-                       sync_dirty_buffer(bh_primary);
-                       if (buffer_uptodate(bh_primary)) {
-                               brelse(bh_backup);
-                               return bh_primary;
-                       }
-                       ntfs_error(sb, "Hot-fix: Device write error while "
-                                       "recovering primary boot sector.");
-               } else {
-                       ntfs_warning(sb, "Hot-fix: Recovery of primary boot "
-                                       "sector failed: Read-only mount.");
-               }
-               brelse(bh_primary);
-       }
-       ntfs_warning(sb, "Using backup boot sector.");
-       return bh_backup;
-}
-
-/**
- * parse_ntfs_boot_sector - parse the boot sector and store the data in @vol
- * @vol:       volume structure to initialise with data from boot sector
- * @b:         boot sector to parse
- *
- * Parse the ntfs boot sector @b and store all imporant information therein in
- * the ntfs super block @vol.  Return 'true' on success and 'false' on error.
- */
-static bool parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
-{
-       unsigned int sectors_per_cluster_bits, nr_hidden_sects;
-       int clusters_per_mft_record, clusters_per_index_record;
-       s64 ll;
-
-       vol->sector_size = le16_to_cpu(b->bpb.bytes_per_sector);
-       vol->sector_size_bits = ffs(vol->sector_size) - 1;
-       ntfs_debug("vol->sector_size = %i (0x%x)", vol->sector_size,
-                       vol->sector_size);
-       ntfs_debug("vol->sector_size_bits = %i (0x%x)", vol->sector_size_bits,
-                       vol->sector_size_bits);
-       if (vol->sector_size < vol->sb->s_blocksize) {
-               ntfs_error(vol->sb, "Sector size (%i) is smaller than the "
-                               "device block size (%lu).  This is not "
-                               "supported.  Sorry.", vol->sector_size,
-                               vol->sb->s_blocksize);
-               return false;
-       }
-       ntfs_debug("sectors_per_cluster = 0x%x", b->bpb.sectors_per_cluster);
-       sectors_per_cluster_bits = ffs(b->bpb.sectors_per_cluster) - 1;
-       ntfs_debug("sectors_per_cluster_bits = 0x%x",
-                       sectors_per_cluster_bits);
-       nr_hidden_sects = le32_to_cpu(b->bpb.hidden_sectors);
-       ntfs_debug("number of hidden sectors = 0x%x", nr_hidden_sects);
-       vol->cluster_size = vol->sector_size << sectors_per_cluster_bits;
-       vol->cluster_size_mask = vol->cluster_size - 1;
-       vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
-       ntfs_debug("vol->cluster_size = %i (0x%x)", vol->cluster_size,
-                       vol->cluster_size);
-       ntfs_debug("vol->cluster_size_mask = 0x%x", vol->cluster_size_mask);
-       ntfs_debug("vol->cluster_size_bits = %i", vol->cluster_size_bits);
-       if (vol->cluster_size < vol->sector_size) {
-               ntfs_error(vol->sb, "Cluster size (%i) is smaller than the "
-                               "sector size (%i).  This is not supported.  "
-                               "Sorry.", vol->cluster_size, vol->sector_size);
-               return false;
-       }
-       clusters_per_mft_record = b->clusters_per_mft_record;
-       ntfs_debug("clusters_per_mft_record = %i (0x%x)",
-                       clusters_per_mft_record, clusters_per_mft_record);
-       if (clusters_per_mft_record > 0)
-               vol->mft_record_size = vol->cluster_size <<
-                               (ffs(clusters_per_mft_record) - 1);
-       else
-               /*
-                * When mft_record_size < cluster_size, clusters_per_mft_record
-                * = -log2(mft_record_size) bytes. mft_record_size normaly is
-                * 1024 bytes, which is encoded as 0xF6 (-10 in decimal).
-                */
-               vol->mft_record_size = 1 << -clusters_per_mft_record;
-       vol->mft_record_size_mask = vol->mft_record_size - 1;
-       vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
-       ntfs_debug("vol->mft_record_size = %i (0x%x)", vol->mft_record_size,
-                       vol->mft_record_size);
-       ntfs_debug("vol->mft_record_size_mask = 0x%x",
-                       vol->mft_record_size_mask);
-       ntfs_debug("vol->mft_record_size_bits = %i (0x%x)",
-                       vol->mft_record_size_bits, vol->mft_record_size_bits);
-       /*
-        * We cannot support mft record sizes above the PAGE_SIZE since
-        * we store $MFT/$DATA, the table of mft records in the page cache.
-        */
-       if (vol->mft_record_size > PAGE_SIZE) {
-               ntfs_error(vol->sb, "Mft record size (%i) exceeds the "
-                               "PAGE_SIZE on your system (%lu).  "
-                               "This is not supported.  Sorry.",
-                               vol->mft_record_size, PAGE_SIZE);
-               return false;
-       }
-       /* We cannot support mft record sizes below the sector size. */
-       if (vol->mft_record_size < vol->sector_size) {
-               ntfs_error(vol->sb, "Mft record size (%i) is smaller than the "
-                               "sector size (%i).  This is not supported.  "
-                               "Sorry.", vol->mft_record_size,
-                               vol->sector_size);
-               return false;
-       }
-       clusters_per_index_record = b->clusters_per_index_record;
-       ntfs_debug("clusters_per_index_record = %i (0x%x)",
-                       clusters_per_index_record, clusters_per_index_record);
-       if (clusters_per_index_record > 0)
-               vol->index_record_size = vol->cluster_size <<
-                               (ffs(clusters_per_index_record) - 1);
-       else
-               /*
-                * When index_record_size < cluster_size,
-                * clusters_per_index_record = -log2(index_record_size) bytes.
-                * index_record_size normaly equals 4096 bytes, which is
-                * encoded as 0xF4 (-12 in decimal).
-                */
-               vol->index_record_size = 1 << -clusters_per_index_record;
-       vol->index_record_size_mask = vol->index_record_size - 1;
-       vol->index_record_size_bits = ffs(vol->index_record_size) - 1;
-       ntfs_debug("vol->index_record_size = %i (0x%x)",
-                       vol->index_record_size, vol->index_record_size);
-       ntfs_debug("vol->index_record_size_mask = 0x%x",
-                       vol->index_record_size_mask);
-       ntfs_debug("vol->index_record_size_bits = %i (0x%x)",
-                       vol->index_record_size_bits,
-                       vol->index_record_size_bits);
-       /* We cannot support index record sizes below the sector size. */
-       if (vol->index_record_size < vol->sector_size) {
-               ntfs_error(vol->sb, "Index record size (%i) is smaller than "
-                               "the sector size (%i).  This is not "
-                               "supported.  Sorry.", vol->index_record_size,
-                               vol->sector_size);
-               return false;
-       }
-       /*
-        * Get the size of the volume in clusters and check for 64-bit-ness.
-        * Windows currently only uses 32 bits to save the clusters so we do
-        * the same as it is much faster on 32-bit CPUs.
-        */
-       ll = sle64_to_cpu(b->number_of_sectors) >> sectors_per_cluster_bits;
-       if ((u64)ll >= 1ULL << 32) {
-               ntfs_error(vol->sb, "Cannot handle 64-bit clusters.  Sorry.");
-               return false;
-       }
-       vol->nr_clusters = ll;
-       ntfs_debug("vol->nr_clusters = 0x%llx", (long long)vol->nr_clusters);
-       /*
-        * On an architecture where unsigned long is 32-bits, we restrict the
-        * volume size to 2TiB (2^41). On a 64-bit architecture, the compiler
-        * will hopefully optimize the whole check away.
-        */
-       if (sizeof(unsigned long) < 8) {
-               if ((ll << vol->cluster_size_bits) >= (1ULL << 41)) {
-                       ntfs_error(vol->sb, "Volume size (%lluTiB) is too "
-                                       "large for this architecture.  "
-                                       "Maximum supported is 2TiB.  Sorry.",
-                                       (unsigned long long)ll >> (40 -
-                                       vol->cluster_size_bits));
-                       return false;
-               }
-       }
-       ll = sle64_to_cpu(b->mft_lcn);
-       if (ll >= vol->nr_clusters) {
-               ntfs_error(vol->sb, "MFT LCN (%lli, 0x%llx) is beyond end of "
-                               "volume.  Weird.", (unsigned long long)ll,
-                               (unsigned long long)ll);
-               return false;
-       }
-       vol->mft_lcn = ll;
-       ntfs_debug("vol->mft_lcn = 0x%llx", (long long)vol->mft_lcn);
-       ll = sle64_to_cpu(b->mftmirr_lcn);
-       if (ll >= vol->nr_clusters) {
-               ntfs_error(vol->sb, "MFTMirr LCN (%lli, 0x%llx) is beyond end "
-                               "of volume.  Weird.", (unsigned long long)ll,
-                               (unsigned long long)ll);
-               return false;
-       }
-       vol->mftmirr_lcn = ll;
-       ntfs_debug("vol->mftmirr_lcn = 0x%llx", (long long)vol->mftmirr_lcn);
-#ifdef NTFS_RW
-       /*
-        * Work out the size of the mft mirror in number of mft records. If the
-        * cluster size is less than or equal to the size taken by four mft
-        * records, the mft mirror stores the first four mft records. If the
-        * cluster size is bigger than the size taken by four mft records, the
-        * mft mirror contains as many mft records as will fit into one
-        * cluster.
-        */
-       if (vol->cluster_size <= (4 << vol->mft_record_size_bits))
-               vol->mftmirr_size = 4;
-       else
-               vol->mftmirr_size = vol->cluster_size >>
-                               vol->mft_record_size_bits;
-       ntfs_debug("vol->mftmirr_size = %i", vol->mftmirr_size);
-#endif /* NTFS_RW */
-       vol->serial_no = le64_to_cpu(b->volume_serial_number);
-       ntfs_debug("vol->serial_no = 0x%llx",
-                       (unsigned long long)vol->serial_no);
-       return true;
-}
-
-/**
- * ntfs_setup_allocators - initialize the cluster and mft allocators
- * @vol:       volume structure for which to setup the allocators
- *
- * Setup the cluster (lcn) and mft allocators to the starting values.
- */
-static void ntfs_setup_allocators(ntfs_volume *vol)
-{
-#ifdef NTFS_RW
-       LCN mft_zone_size, mft_lcn;
-#endif /* NTFS_RW */
-
-       ntfs_debug("vol->mft_zone_multiplier = 0x%x",
-                       vol->mft_zone_multiplier);
-#ifdef NTFS_RW
-       /* Determine the size of the MFT zone. */
-       mft_zone_size = vol->nr_clusters;
-       switch (vol->mft_zone_multiplier) {  /* % of volume size in clusters */
-       case 4:
-               mft_zone_size >>= 1;                    /* 50%   */
-               break;
-       case 3:
-               mft_zone_size = (mft_zone_size +
-                               (mft_zone_size >> 1)) >> 2;     /* 37.5% */
-               break;
-       case 2:
-               mft_zone_size >>= 2;                    /* 25%   */
-               break;
-       /* case 1: */
-       default:
-               mft_zone_size >>= 3;                    /* 12.5% */
-               break;
-       }
-       /* Setup the mft zone. */
-       vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn;
-       ntfs_debug("vol->mft_zone_pos = 0x%llx",
-                       (unsigned long long)vol->mft_zone_pos);
-       /*
-        * Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs
-        * source) and if the actual mft_lcn is in the expected place or even
-        * further to the front of the volume, extend the mft_zone to cover the
-        * beginning of the volume as well.  This is in order to protect the
-        * area reserved for the mft bitmap as well within the mft_zone itself.
-        * On non-standard volumes we do not protect it as the overhead would
-        * be higher than the speed increase we would get by doing it.
-        */
-       mft_lcn = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size;
-       if (mft_lcn * vol->cluster_size < 16 * 1024)
-               mft_lcn = (16 * 1024 + vol->cluster_size - 1) /
-                               vol->cluster_size;
-       if (vol->mft_zone_start <= mft_lcn)
-               vol->mft_zone_start = 0;
-       ntfs_debug("vol->mft_zone_start = 0x%llx",
-                       (unsigned long long)vol->mft_zone_start);
-       /*
-        * Need to cap the mft zone on non-standard volumes so that it does
-        * not point outside the boundaries of the volume.  We do this by
-        * halving the zone size until we are inside the volume.
-        */
-       vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
-       while (vol->mft_zone_end >= vol->nr_clusters) {
-               mft_zone_size >>= 1;
-               vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
-       }
-       ntfs_debug("vol->mft_zone_end = 0x%llx",
-                       (unsigned long long)vol->mft_zone_end);
-       /*
-        * Set the current position within each data zone to the start of the
-        * respective zone.
-        */
-       vol->data1_zone_pos = vol->mft_zone_end;
-       ntfs_debug("vol->data1_zone_pos = 0x%llx",
-                       (unsigned long long)vol->data1_zone_pos);
-       vol->data2_zone_pos = 0;
-       ntfs_debug("vol->data2_zone_pos = 0x%llx",
-                       (unsigned long long)vol->data2_zone_pos);
-
-       /* Set the mft data allocation position to mft record 24. */
-       vol->mft_data_pos = 24;
-       ntfs_debug("vol->mft_data_pos = 0x%llx",
-                       (unsigned long long)vol->mft_data_pos);
-#endif /* NTFS_RW */
-}
-
-#ifdef NTFS_RW
-
-/**
- * load_and_init_mft_mirror - load and setup the mft mirror inode for a volume
- * @vol:       ntfs super block describing device whose mft mirror to load
- *
- * Return 'true' on success or 'false' on error.
- */
-static bool load_and_init_mft_mirror(ntfs_volume *vol)
-{
-       struct inode *tmp_ino;
-       ntfs_inode *tmp_ni;
-
-       ntfs_debug("Entering.");
-       /* Get mft mirror inode. */
-       tmp_ino = ntfs_iget(vol->sb, FILE_MFTMirr);
-       if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
-               if (!IS_ERR(tmp_ino))
-                       iput(tmp_ino);
-               /* Caller will display error message. */
-               return false;
-       }
-       /*
-        * Re-initialize some specifics about $MFTMirr's inode as
-        * ntfs_read_inode() will have set up the default ones.
-        */
-       /* Set uid and gid to root. */
-       tmp_ino->i_uid = GLOBAL_ROOT_UID;
-       tmp_ino->i_gid = GLOBAL_ROOT_GID;
-       /* Regular file.  No access for anyone. */
-       tmp_ino->i_mode = S_IFREG;
-       /* No VFS initiated operations allowed for $MFTMirr. */
-       tmp_ino->i_op = &ntfs_empty_inode_ops;
-       tmp_ino->i_fop = &ntfs_empty_file_ops;
-       /* Put in our special address space operations. */
-       tmp_ino->i_mapping->a_ops = &ntfs_mst_aops;
-       tmp_ni = NTFS_I(tmp_ino);
-       /* The $MFTMirr, like the $MFT is multi sector transfer protected. */
-       NInoSetMstProtected(tmp_ni);
-       NInoSetSparseDisabled(tmp_ni);
-       /*
-        * Set up our little cheat allowing us to reuse the async read io
-        * completion handler for directories.
-        */
-       tmp_ni->itype.index.block_size = vol->mft_record_size;
-       tmp_ni->itype.index.block_size_bits = vol->mft_record_size_bits;
-       vol->mftmirr_ino = tmp_ino;
-       ntfs_debug("Done.");
-       return true;
-}
-
-/**
- * check_mft_mirror - compare contents of the mft mirror with the mft
- * @vol:       ntfs super block describing device whose mft mirror to check
- *
- * Return 'true' on success or 'false' on error.
- *
- * Note, this function also results in the mft mirror runlist being completely
- * mapped into memory.  The mft mirror write code requires this and will BUG()
- * should it find an unmapped runlist element.
- */
-static bool check_mft_mirror(ntfs_volume *vol)
-{
-       struct super_block *sb = vol->sb;
-       ntfs_inode *mirr_ni;
-       struct page *mft_page, *mirr_page;
-       u8 *kmft, *kmirr;
-       runlist_element *rl, rl2[2];
-       pgoff_t index;
-       int mrecs_per_page, i;
-
-       ntfs_debug("Entering.");
-       /* Compare contents of $MFT and $MFTMirr. */
-       mrecs_per_page = PAGE_SIZE / vol->mft_record_size;
-       BUG_ON(!mrecs_per_page);
-       BUG_ON(!vol->mftmirr_size);
-       mft_page = mirr_page = NULL;
-       kmft = kmirr = NULL;
-       index = i = 0;
-       do {
-               u32 bytes;
-
-               /* Switch pages if necessary. */
-               if (!(i % mrecs_per_page)) {
-                       if (index) {
-                               ntfs_unmap_page(mft_page);
-                               ntfs_unmap_page(mirr_page);
-                       }
-                       /* Get the $MFT page. */
-                       mft_page = ntfs_map_page(vol->mft_ino->i_mapping,
-                                       index);
-                       if (IS_ERR(mft_page)) {
-                               ntfs_error(sb, "Failed to read $MFT.");
-                               return false;
-                       }
-                       kmft = page_address(mft_page);
-                       /* Get the $MFTMirr page. */
-                       mirr_page = ntfs_map_page(vol->mftmirr_ino->i_mapping,
-                                       index);
-                       if (IS_ERR(mirr_page)) {
-                               ntfs_error(sb, "Failed to read $MFTMirr.");
-                               goto mft_unmap_out;
-                       }
-                       kmirr = page_address(mirr_page);
-                       ++index;
-               }
-               /* Do not check the record if it is not in use. */
-               if (((MFT_RECORD*)kmft)->flags & MFT_RECORD_IN_USE) {
-                       /* Make sure the record is ok. */
-                       if (ntfs_is_baad_recordp((le32*)kmft)) {
-                               ntfs_error(sb, "Incomplete multi sector "
-                                               "transfer detected in mft "
-                                               "record %i.", i);
-mm_unmap_out:
-                               ntfs_unmap_page(mirr_page);
-mft_unmap_out:
-                               ntfs_unmap_page(mft_page);
-                               return false;
-                       }
-               }
-               /* Do not check the mirror record if it is not in use. */
-               if (((MFT_RECORD*)kmirr)->flags & MFT_RECORD_IN_USE) {
-                       if (ntfs_is_baad_recordp((le32*)kmirr)) {
-                               ntfs_error(sb, "Incomplete multi sector "
-                                               "transfer detected in mft "
-                                               "mirror record %i.", i);
-                               goto mm_unmap_out;
-                       }
-               }
-               /* Get the amount of data in the current record. */
-               bytes = le32_to_cpu(((MFT_RECORD*)kmft)->bytes_in_use);
-               if (bytes < sizeof(MFT_RECORD_OLD) ||
-                               bytes > vol->mft_record_size ||
-                               ntfs_is_baad_recordp((le32*)kmft)) {
-                       bytes = le32_to_cpu(((MFT_RECORD*)kmirr)->bytes_in_use);
-                       if (bytes < sizeof(MFT_RECORD_OLD) ||
-                                       bytes > vol->mft_record_size ||
-                                       ntfs_is_baad_recordp((le32*)kmirr))
-                               bytes = vol->mft_record_size;
-               }
-               /* Compare the two records. */
-               if (memcmp(kmft, kmirr, bytes)) {
-                       ntfs_error(sb, "$MFT and $MFTMirr (record %i) do not "
-                                       "match.  Run ntfsfix or chkdsk.", i);
-                       goto mm_unmap_out;
-               }
-               kmft += vol->mft_record_size;
-               kmirr += vol->mft_record_size;
-       } while (++i < vol->mftmirr_size);
-       /* Release the last pages. */
-       ntfs_unmap_page(mft_page);
-       ntfs_unmap_page(mirr_page);
-
-       /* Construct the mft mirror runlist by hand. */
-       rl2[0].vcn = 0;
-       rl2[0].lcn = vol->mftmirr_lcn;
-       rl2[0].length = (vol->mftmirr_size * vol->mft_record_size +
-                       vol->cluster_size - 1) / vol->cluster_size;
-       rl2[1].vcn = rl2[0].length;
-       rl2[1].lcn = LCN_ENOENT;
-       rl2[1].length = 0;
-       /*
-        * Because we have just read all of the mft mirror, we know we have
-        * mapped the full runlist for it.
-        */
-       mirr_ni = NTFS_I(vol->mftmirr_ino);
-       down_read(&mirr_ni->runlist.lock);
-       rl = mirr_ni->runlist.rl;
-       /* Compare the two runlists.  They must be identical. */
-       i = 0;
-       do {
-               if (rl2[i].vcn != rl[i].vcn || rl2[i].lcn != rl[i].lcn ||
-                               rl2[i].length != rl[i].length) {
-                       ntfs_error(sb, "$MFTMirr location mismatch.  "
-                                       "Run chkdsk.");
-                       up_read(&mirr_ni->runlist.lock);
-                       return false;
-               }
-       } while (rl2[i++].length);
-       up_read(&mirr_ni->runlist.lock);
-       ntfs_debug("Done.");
-       return true;
-}
-
-/**
- * load_and_check_logfile - load and check the logfile inode for a volume
- * @vol:       ntfs super block describing device whose logfile to load
- *
- * Return 'true' on success or 'false' on error.
- */
-static bool load_and_check_logfile(ntfs_volume *vol,
-               RESTART_PAGE_HEADER **rp)
-{
-       struct inode *tmp_ino;
-
-       ntfs_debug("Entering.");
-       tmp_ino = ntfs_iget(vol->sb, FILE_LogFile);
-       if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
-               if (!IS_ERR(tmp_ino))
-                       iput(tmp_ino);
-               /* Caller will display error message. */
-               return false;
-       }
-       if (!ntfs_check_logfile(tmp_ino, rp)) {
-               iput(tmp_ino);
-               /* ntfs_check_logfile() will have displayed error output. */
-               return false;
-       }
-       NInoSetSparseDisabled(NTFS_I(tmp_ino));
-       vol->logfile_ino = tmp_ino;
-       ntfs_debug("Done.");
-       return true;
-}
-
-#define NTFS_HIBERFIL_HEADER_SIZE      4096
-
-/**
- * check_windows_hibernation_status - check if Windows is suspended on a volume
- * @vol:       ntfs super block of device to check
- *
- * Check if Windows is hibernated on the ntfs volume @vol.  This is done by
- * looking for the file hiberfil.sys in the root directory of the volume.  If
- * the file is not present Windows is definitely not suspended.
- *
- * If hiberfil.sys exists and is less than 4kiB in size it means Windows is
- * definitely suspended (this volume is not the system volume).  Caveat:  on a
- * system with many volumes it is possible that the < 4kiB check is bogus but
- * for now this should do fine.
- *
- * If hiberfil.sys exists and is larger than 4kiB in size, we need to read the
- * hiberfil header (which is the first 4kiB).  If this begins with "hibr",
- * Windows is definitely suspended.  If it is completely full of zeroes,
- * Windows is definitely not hibernated.  Any other case is treated as if
- * Windows is suspended.  This caters for the above mentioned caveat of a
- * system with many volumes where no "hibr" magic would be present and there is
- * no zero header.
- *
- * Return 0 if Windows is not hibernated on the volume, >0 if Windows is
- * hibernated on the volume, and -errno on error.
- */
-static int check_windows_hibernation_status(ntfs_volume *vol)
-{
-       MFT_REF mref;
-       struct inode *vi;
-       struct page *page;
-       u32 *kaddr, *kend;
-       ntfs_name *name = NULL;
-       int ret = 1;
-       static const ntfschar hiberfil[13] = { cpu_to_le16('h'),
-                       cpu_to_le16('i'), cpu_to_le16('b'),
-                       cpu_to_le16('e'), cpu_to_le16('r'),
-                       cpu_to_le16('f'), cpu_to_le16('i'),
-                       cpu_to_le16('l'), cpu_to_le16('.'),
-                       cpu_to_le16('s'), cpu_to_le16('y'),
-                       cpu_to_le16('s'), 0 };
-
-       ntfs_debug("Entering.");
-       /*
-        * Find the inode number for the hibernation file by looking up the
-        * filename hiberfil.sys in the root directory.
-        */
-       inode_lock(vol->root_ino);
-       mref = ntfs_lookup_inode_by_name(NTFS_I(vol->root_ino), hiberfil, 12,
-                       &name);
-       inode_unlock(vol->root_ino);
-       if (IS_ERR_MREF(mref)) {
-               ret = MREF_ERR(mref);
-               /* If the file does not exist, Windows is not hibernated. */
-               if (ret == -ENOENT) {
-                       ntfs_debug("hiberfil.sys not present.  Windows is not "
-                                       "hibernated on the volume.");
-                       return 0;
-               }
-               /* A real error occurred. */
-               ntfs_error(vol->sb, "Failed to find inode number for "
-                               "hiberfil.sys.");
-               return ret;
-       }
-       /* We do not care for the type of match that was found. */
-       kfree(name);
-       /* Get the inode. */
-       vi = ntfs_iget(vol->sb, MREF(mref));
-       if (IS_ERR(vi) || is_bad_inode(vi)) {
-               if (!IS_ERR(vi))
-                       iput(vi);
-               ntfs_error(vol->sb, "Failed to load hiberfil.sys.");
-               return IS_ERR(vi) ? PTR_ERR(vi) : -EIO;
-       }
-       if (unlikely(i_size_read(vi) < NTFS_HIBERFIL_HEADER_SIZE)) {
-               ntfs_debug("hiberfil.sys is smaller than 4kiB (0x%llx).  "
-                               "Windows is hibernated on the volume.  This "
-                               "is not the system volume.", i_size_read(vi));
-               goto iput_out;
-       }
-       page = ntfs_map_page(vi->i_mapping, 0);
-       if (IS_ERR(page)) {
-               ntfs_error(vol->sb, "Failed to read from hiberfil.sys.");
-               ret = PTR_ERR(page);
-               goto iput_out;
-       }
-       kaddr = (u32*)page_address(page);
-       if (*(le32*)kaddr == cpu_to_le32(0x72626968)/*'hibr'*/) {
-               ntfs_debug("Magic \"hibr\" found in hiberfil.sys.  Windows is "
-                               "hibernated on the volume.  This is the "
-                               "system volume.");
-               goto unm_iput_out;
-       }
-       kend = kaddr + NTFS_HIBERFIL_HEADER_SIZE/sizeof(*kaddr);
-       do {
-               if (unlikely(*kaddr)) {
-                       ntfs_debug("hiberfil.sys is larger than 4kiB "
-                                       "(0x%llx), does not contain the "
-                                       "\"hibr\" magic, and does not have a "
-                                       "zero header.  Windows is hibernated "
-                                       "on the volume.  This is not the "
-                                       "system volume.", i_size_read(vi));
-                       goto unm_iput_out;
-               }
-       } while (++kaddr < kend);
-       ntfs_debug("hiberfil.sys contains a zero header.  Windows is not "
-                       "hibernated on the volume.  This is the system "
-                       "volume.");
-       ret = 0;
-unm_iput_out:
-       ntfs_unmap_page(page);
-iput_out:
-       iput(vi);
-       return ret;
-}
-
-/**
- * load_and_init_quota - load and setup the quota file for a volume if present
- * @vol:       ntfs super block describing device whose quota file to load
- *
- * Return 'true' on success or 'false' on error.  If $Quota is not present, we
- * leave vol->quota_ino as NULL and return success.
- */
-static bool load_and_init_quota(ntfs_volume *vol)
-{
-       MFT_REF mref;
-       struct inode *tmp_ino;
-       ntfs_name *name = NULL;
-       static const ntfschar Quota[7] = { cpu_to_le16('$'),
-                       cpu_to_le16('Q'), cpu_to_le16('u'),
-                       cpu_to_le16('o'), cpu_to_le16('t'),
-                       cpu_to_le16('a'), 0 };
-       static ntfschar Q[3] = { cpu_to_le16('$'),
-                       cpu_to_le16('Q'), 0 };
-
-       ntfs_debug("Entering.");
-       /*
-        * Find the inode number for the quota file by looking up the filename
-        * $Quota in the extended system files directory $Extend.
-        */
-       inode_lock(vol->extend_ino);
-       mref = ntfs_lookup_inode_by_name(NTFS_I(vol->extend_ino), Quota, 6,
-                       &name);
-       inode_unlock(vol->extend_ino);
-       if (IS_ERR_MREF(mref)) {
-               /*
-                * If the file does not exist, quotas are disabled and have
-                * never been enabled on this volume, just return success.
-                */
-               if (MREF_ERR(mref) == -ENOENT) {
-                       ntfs_debug("$Quota not present.  Volume does not have "
-                                       "quotas enabled.");
-                       /*
-                        * No need to try to set quotas out of date if they are
-                        * not enabled.
-                        */
-                       NVolSetQuotaOutOfDate(vol);
-                       return true;
-               }
-               /* A real error occurred. */
-               ntfs_error(vol->sb, "Failed to find inode number for $Quota.");
-               return false;
-       }
-       /* We do not care for the type of match that was found. */
-       kfree(name);
-       /* Get the inode. */
-       tmp_ino = ntfs_iget(vol->sb, MREF(mref));
-       if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
-               if (!IS_ERR(tmp_ino))
-                       iput(tmp_ino);
-               ntfs_error(vol->sb, "Failed to load $Quota.");
-               return false;
-       }
-       vol->quota_ino = tmp_ino;
-       /* Get the $Q index allocation attribute. */
-       tmp_ino = ntfs_index_iget(vol->quota_ino, Q, 2);
-       if (IS_ERR(tmp_ino)) {
-               ntfs_error(vol->sb, "Failed to load $Quota/$Q index.");
-               return false;
-       }
-       vol->quota_q_ino = tmp_ino;
-       ntfs_debug("Done.");
-       return true;
-}
-
-/**
- * load_and_init_usnjrnl - load and setup the transaction log if present
- * @vol:       ntfs super block describing device whose usnjrnl file to load
- *
- * Return 'true' on success or 'false' on error.
- *
- * If $UsnJrnl is not present or in the process of being disabled, we set
- * NVolUsnJrnlStamped() and return success.
- *
- * If the $UsnJrnl $DATA/$J attribute has a size equal to the lowest valid usn,
- * i.e. transaction logging has only just been enabled or the journal has been
- * stamped and nothing has been logged since, we also set NVolUsnJrnlStamped()
- * and return success.
- */
-static bool load_and_init_usnjrnl(ntfs_volume *vol)
-{
-       MFT_REF mref;
-       struct inode *tmp_ino;
-       ntfs_inode *tmp_ni;
-       struct page *page;
-       ntfs_name *name = NULL;
-       USN_HEADER *uh;
-       static const ntfschar UsnJrnl[9] = { cpu_to_le16('$'),
-                       cpu_to_le16('U'), cpu_to_le16('s'),
-                       cpu_to_le16('n'), cpu_to_le16('J'),
-                       cpu_to_le16('r'), cpu_to_le16('n'),
-                       cpu_to_le16('l'), 0 };
-       static ntfschar Max[5] = { cpu_to_le16('$'),
-                       cpu_to_le16('M'), cpu_to_le16('a'),
-                       cpu_to_le16('x'), 0 };
-       static ntfschar J[3] = { cpu_to_le16('$'),
-                       cpu_to_le16('J'), 0 };
-
-       ntfs_debug("Entering.");
-       /*
-        * Find the inode number for the transaction log file by looking up the
-        * filename $UsnJrnl in the extended system files directory $Extend.
-        */
-       inode_lock(vol->extend_ino);
-       mref = ntfs_lookup_inode_by_name(NTFS_I(vol->extend_ino), UsnJrnl, 8,
-                       &name);
-       inode_unlock(vol->extend_ino);
-       if (IS_ERR_MREF(mref)) {
-               /*
-                * If the file does not exist, transaction logging is disabled,
-                * just return success.
-                */
-               if (MREF_ERR(mref) == -ENOENT) {
-                       ntfs_debug("$UsnJrnl not present.  Volume does not "
-                                       "have transaction logging enabled.");
-not_enabled:
-                       /*
-                        * No need to try to stamp the transaction log if
-                        * transaction logging is not enabled.
-                        */
-                       NVolSetUsnJrnlStamped(vol);
-                       return true;
-               }
-               /* A real error occurred. */
-               ntfs_error(vol->sb, "Failed to find inode number for "
-                               "$UsnJrnl.");
-               return false;
-       }
-       /* We do not care for the type of match that was found. */
-       kfree(name);
-       /* Get the inode. */
-       tmp_ino = ntfs_iget(vol->sb, MREF(mref));
-       if (IS_ERR(tmp_ino) || unlikely(is_bad_inode(tmp_ino))) {
-               if (!IS_ERR(tmp_ino))
-                       iput(tmp_ino);
-               ntfs_error(vol->sb, "Failed to load $UsnJrnl.");
-               return false;
-       }
-       vol->usnjrnl_ino = tmp_ino;
-       /*
-        * If the transaction log is in the process of being deleted, we can
-        * ignore it.
-        */
-       if (unlikely(vol->vol_flags & VOLUME_DELETE_USN_UNDERWAY)) {
-               ntfs_debug("$UsnJrnl in the process of being disabled.  "
-                               "Volume does not have transaction logging "
-                               "enabled.");
-               goto not_enabled;
-       }
-       /* Get the $DATA/$Max attribute. */
-       tmp_ino = ntfs_attr_iget(vol->usnjrnl_ino, AT_DATA, Max, 4);
-       if (IS_ERR(tmp_ino)) {
-               ntfs_error(vol->sb, "Failed to load $UsnJrnl/$DATA/$Max "
-                               "attribute.");
-               return false;
-       }
-       vol->usnjrnl_max_ino = tmp_ino;
-       if (unlikely(i_size_read(tmp_ino) < sizeof(USN_HEADER))) {
-               ntfs_error(vol->sb, "Found corrupt $UsnJrnl/$DATA/$Max "
-                               "attribute (size is 0x%llx but should be at "
-                               "least 0x%zx bytes).", i_size_read(tmp_ino),
-                               sizeof(USN_HEADER));
-               return false;
-       }
-       /* Get the $DATA/$J attribute. */
-       tmp_ino = ntfs_attr_iget(vol->usnjrnl_ino, AT_DATA, J, 2);
-       if (IS_ERR(tmp_ino)) {
-               ntfs_error(vol->sb, "Failed to load $UsnJrnl/$DATA/$J "
-                               "attribute.");
-               return false;
-       }
-       vol->usnjrnl_j_ino = tmp_ino;
-       /* Verify $J is non-resident and sparse. */
-       tmp_ni = NTFS_I(vol->usnjrnl_j_ino);
-       if (unlikely(!NInoNonResident(tmp_ni) || !NInoSparse(tmp_ni))) {
-               ntfs_error(vol->sb, "$UsnJrnl/$DATA/$J attribute is resident "
-                               "and/or not sparse.");
-               return false;
-       }
-       /* Read the USN_HEADER from $DATA/$Max. */
-       page = ntfs_map_page(vol->usnjrnl_max_ino->i_mapping, 0);
-       if (IS_ERR(page)) {
-               ntfs_error(vol->sb, "Failed to read from $UsnJrnl/$DATA/$Max "
-                               "attribute.");
-               return false;
-       }
-       uh = (USN_HEADER*)page_address(page);
-       /* Sanity check the $Max. */
-       if (unlikely(sle64_to_cpu(uh->allocation_delta) >
-                       sle64_to_cpu(uh->maximum_size))) {
-               ntfs_error(vol->sb, "Allocation delta (0x%llx) exceeds "
-                               "maximum size (0x%llx).  $UsnJrnl is corrupt.",
-                               (long long)sle64_to_cpu(uh->allocation_delta),
-                               (long long)sle64_to_cpu(uh->maximum_size));
-               ntfs_unmap_page(page);
-               return false;
-       }
-       /*
-        * If the transaction log has been stamped and nothing has been written
-        * to it since, we do not need to stamp it.
-        */
-       if (unlikely(sle64_to_cpu(uh->lowest_valid_usn) >=
-                       i_size_read(vol->usnjrnl_j_ino))) {
-               if (likely(sle64_to_cpu(uh->lowest_valid_usn) ==
-                               i_size_read(vol->usnjrnl_j_ino))) {
-                       ntfs_unmap_page(page);
-                       ntfs_debug("$UsnJrnl is enabled but nothing has been "
-                                       "logged since it was last stamped.  "
-                                       "Treating this as if the volume does "
-                                       "not have transaction logging "
-                                       "enabled.");
-                       goto not_enabled;
-               }
-               ntfs_error(vol->sb, "$UsnJrnl has lowest valid usn (0x%llx) "
-                               "which is out of bounds (0x%llx).  $UsnJrnl "
-                               "is corrupt.",
-                               (long long)sle64_to_cpu(uh->lowest_valid_usn),
-                               i_size_read(vol->usnjrnl_j_ino));
-               ntfs_unmap_page(page);
-               return false;
-       }
-       ntfs_unmap_page(page);
-       ntfs_debug("Done.");
-       return true;
-}
-
-/**
- * load_and_init_attrdef - load the attribute definitions table for a volume
- * @vol:       ntfs super block describing device whose attrdef to load
- *
- * Return 'true' on success or 'false' on error.
- */
-static bool load_and_init_attrdef(ntfs_volume *vol)
-{
-       loff_t i_size;
-       struct super_block *sb = vol->sb;
-       struct inode *ino;
-       struct page *page;
-       pgoff_t index, max_index;
-       unsigned int size;
-
-       ntfs_debug("Entering.");
-       /* Read attrdef table and setup vol->attrdef and vol->attrdef_size. */
-       ino = ntfs_iget(sb, FILE_AttrDef);
-       if (IS_ERR(ino) || is_bad_inode(ino)) {
-               if (!IS_ERR(ino))
-                       iput(ino);
-               goto failed;
-       }
-       NInoSetSparseDisabled(NTFS_I(ino));
-       /* The size of FILE_AttrDef must be above 0 and fit inside 31 bits. */
-       i_size = i_size_read(ino);
-       if (i_size <= 0 || i_size > 0x7fffffff)
-               goto iput_failed;
-       vol->attrdef = (ATTR_DEF*)ntfs_malloc_nofs(i_size);
-       if (!vol->attrdef)
-               goto iput_failed;
-       index = 0;
-       max_index = i_size >> PAGE_SHIFT;
-       size = PAGE_SIZE;
-       while (index < max_index) {
-               /* Read the attrdef table and copy it into the linear buffer. */
-read_partial_attrdef_page:
-               page = ntfs_map_page(ino->i_mapping, index);
-               if (IS_ERR(page))
-                       goto free_iput_failed;
-               memcpy((u8*)vol->attrdef + (index++ << PAGE_SHIFT),
-                               page_address(page), size);
-               ntfs_unmap_page(page);
-       }
-       if (size == PAGE_SIZE) {
-               size = i_size & ~PAGE_MASK;
-               if (size)
-                       goto read_partial_attrdef_page;
-       }
-       vol->attrdef_size = i_size;
-       ntfs_debug("Read %llu bytes from $AttrDef.", i_size);
-       iput(ino);
-       return true;
-free_iput_failed:
-       ntfs_free(vol->attrdef);
-       vol->attrdef = NULL;
-iput_failed:
-       iput(ino);
-failed:
-       ntfs_error(sb, "Failed to initialize attribute definition table.");
-       return false;
-}
-
-#endif /* NTFS_RW */
-
-/**
- * load_and_init_upcase - load the upcase table for an ntfs volume
- * @vol:       ntfs super block describing device whose upcase to load
- *
- * Return 'true' on success or 'false' on error.
- */
-static bool load_and_init_upcase(ntfs_volume *vol)
-{
-       loff_t i_size;
-       struct super_block *sb = vol->sb;
-       struct inode *ino;
-       struct page *page;
-       pgoff_t index, max_index;
-       unsigned int size;
-       int i, max;
-
-       ntfs_debug("Entering.");
-       /* Read upcase table and setup vol->upcase and vol->upcase_len. */
-       ino = ntfs_iget(sb, FILE_UpCase);
-       if (IS_ERR(ino) || is_bad_inode(ino)) {
-               if (!IS_ERR(ino))
-                       iput(ino);
-               goto upcase_failed;
-       }
-       /*
-        * The upcase size must not be above 64k Unicode characters, must not
-        * be zero and must be a multiple of sizeof(ntfschar).
-        */
-       i_size = i_size_read(ino);
-       if (!i_size || i_size & (sizeof(ntfschar) - 1) ||
-                       i_size > 64ULL * 1024 * sizeof(ntfschar))
-               goto iput_upcase_failed;
-       vol->upcase = (ntfschar*)ntfs_malloc_nofs(i_size);
-       if (!vol->upcase)
-               goto iput_upcase_failed;
-       index = 0;
-       max_index = i_size >> PAGE_SHIFT;
-       size = PAGE_SIZE;
-       while (index < max_index) {
-               /* Read the upcase table and copy it into the linear buffer. */
-read_partial_upcase_page:
-               page = ntfs_map_page(ino->i_mapping, index);
-               if (IS_ERR(page))
-                       goto iput_upcase_failed;
-               memcpy((char*)vol->upcase + (index++ << PAGE_SHIFT),
-                               page_address(page), size);
-               ntfs_unmap_page(page);
-       }
-       if (size == PAGE_SIZE) {
-               size = i_size & ~PAGE_MASK;
-               if (size)
-                       goto read_partial_upcase_page;
-       }
-       vol->upcase_len = i_size >> UCHAR_T_SIZE_BITS;
-       ntfs_debug("Read %llu bytes from $UpCase (expected %zu bytes).",
-                       i_size, 64 * 1024 * sizeof(ntfschar));
-       iput(ino);
-       mutex_lock(&ntfs_lock);
-       if (!default_upcase) {
-               ntfs_debug("Using volume specified $UpCase since default is "
-                               "not present.");
-               mutex_unlock(&ntfs_lock);
-               return true;
-       }
-       max = default_upcase_len;
-       if (max > vol->upcase_len)
-               max = vol->upcase_len;
-       for (i = 0; i < max; i++)
-               if (vol->upcase[i] != default_upcase[i])
-                       break;
-       if (i == max) {
-               ntfs_free(vol->upcase);
-               vol->upcase = default_upcase;
-               vol->upcase_len = max;
-               ntfs_nr_upcase_users++;
-               mutex_unlock(&ntfs_lock);
-               ntfs_debug("Volume specified $UpCase matches default. Using "
-                               "default.");
-               return true;
-       }
-       mutex_unlock(&ntfs_lock);
-       ntfs_debug("Using volume specified $UpCase since it does not match "
-                       "the default.");
-       return true;
-iput_upcase_failed:
-       iput(ino);
-       ntfs_free(vol->upcase);
-       vol->upcase = NULL;
-upcase_failed:
-       mutex_lock(&ntfs_lock);
-       if (default_upcase) {
-               vol->upcase = default_upcase;
-               vol->upcase_len = default_upcase_len;
-               ntfs_nr_upcase_users++;
-               mutex_unlock(&ntfs_lock);
-               ntfs_error(sb, "Failed to load $UpCase from the volume. Using "
-                               "default.");
-               return true;
-       }
-       mutex_unlock(&ntfs_lock);
-       ntfs_error(sb, "Failed to initialize upcase table.");
-       return false;
-}
-
-/*
- * The lcn and mft bitmap inodes are NTFS-internal inodes with
- * their own special locking rules:
- */
-static struct lock_class_key
-       lcnbmp_runlist_lock_key, lcnbmp_mrec_lock_key,
-       mftbmp_runlist_lock_key, mftbmp_mrec_lock_key;
-
-/**
- * load_system_files - open the system files using normal functions
- * @vol:       ntfs super block describing device whose system files to load
- *
- * Open the system files with normal access functions and complete setting up
- * the ntfs super block @vol.
- *
- * Return 'true' on success or 'false' on error.
- */
-static bool load_system_files(ntfs_volume *vol)
-{
-       struct super_block *sb = vol->sb;
-       MFT_RECORD *m;
-       VOLUME_INFORMATION *vi;
-       ntfs_attr_search_ctx *ctx;
-#ifdef NTFS_RW
-       RESTART_PAGE_HEADER *rp;
-       int err;
-#endif /* NTFS_RW */
-
-       ntfs_debug("Entering.");
-#ifdef NTFS_RW
-       /* Get mft mirror inode compare the contents of $MFT and $MFTMirr. */
-       if (!load_and_init_mft_mirror(vol) || !check_mft_mirror(vol)) {
-               static const char *es1 = "Failed to load $MFTMirr";
-               static const char *es2 = "$MFTMirr does not match $MFT";
-               static const char *es3 = ".  Run ntfsfix and/or chkdsk.";
-
-               /* If a read-write mount, convert it to a read-only mount. */
-               if (!sb_rdonly(sb)) {
-                       if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
-                                       ON_ERRORS_CONTINUE))) {
-                               ntfs_error(sb, "%s and neither on_errors="
-                                               "continue nor on_errors="
-                                               "remount-ro was specified%s",
-                                               !vol->mftmirr_ino ? es1 : es2,
-                                               es3);
-                               goto iput_mirr_err_out;
-                       }
-                       sb->s_flags |= SB_RDONLY;
-                       ntfs_error(sb, "%s.  Mounting read-only%s",
-                                       !vol->mftmirr_ino ? es1 : es2, es3);
-               } else
-                       ntfs_warning(sb, "%s.  Will not be able to remount "
-                                       "read-write%s",
-                                       !vol->mftmirr_ino ? es1 : es2, es3);
-               /* This will prevent a read-write remount. */
-               NVolSetErrors(vol);
-       }
-#endif /* NTFS_RW */
-       /* Get mft bitmap attribute inode. */
-       vol->mftbmp_ino = ntfs_attr_iget(vol->mft_ino, AT_BITMAP, NULL, 0);
-       if (IS_ERR(vol->mftbmp_ino)) {
-               ntfs_error(sb, "Failed to load $MFT/$BITMAP attribute.");
-               goto iput_mirr_err_out;
-       }
-       lockdep_set_class(&NTFS_I(vol->mftbmp_ino)->runlist.lock,
-                          &mftbmp_runlist_lock_key);
-       lockdep_set_class(&NTFS_I(vol->mftbmp_ino)->mrec_lock,
-                          &mftbmp_mrec_lock_key);
-       /* Read upcase table and setup @vol->upcase and @vol->upcase_len. */
-       if (!load_and_init_upcase(vol))
-               goto iput_mftbmp_err_out;
-#ifdef NTFS_RW
-       /*
-        * Read attribute definitions table and setup @vol->attrdef and
-        * @vol->attrdef_size.
-        */
-       if (!load_and_init_attrdef(vol))
-               goto iput_upcase_err_out;
-#endif /* NTFS_RW */
-       /*
-        * Get the cluster allocation bitmap inode and verify the size, no
-        * need for any locking at this stage as we are already running
-        * exclusively as we are mount in progress task.
-        */
-       vol->lcnbmp_ino = ntfs_iget(sb, FILE_Bitmap);
-       if (IS_ERR(vol->lcnbmp_ino) || is_bad_inode(vol->lcnbmp_ino)) {
-               if (!IS_ERR(vol->lcnbmp_ino))
-                       iput(vol->lcnbmp_ino);
-               goto bitmap_failed;
-       }
-       lockdep_set_class(&NTFS_I(vol->lcnbmp_ino)->runlist.lock,
-                          &lcnbmp_runlist_lock_key);
-       lockdep_set_class(&NTFS_I(vol->lcnbmp_ino)->mrec_lock,
-                          &lcnbmp_mrec_lock_key);
-
-       NInoSetSparseDisabled(NTFS_I(vol->lcnbmp_ino));
-       if ((vol->nr_clusters + 7) >> 3 > i_size_read(vol->lcnbmp_ino)) {
-               iput(vol->lcnbmp_ino);
-bitmap_failed:
-               ntfs_error(sb, "Failed to load $Bitmap.");
-               goto iput_attrdef_err_out;
-       }
-       /*
-        * Get the volume inode and setup our cache of the volume flags and
-        * version.
-        */
-       vol->vol_ino = ntfs_iget(sb, FILE_Volume);
-       if (IS_ERR(vol->vol_ino) || is_bad_inode(vol->vol_ino)) {
-               if (!IS_ERR(vol->vol_ino))
-                       iput(vol->vol_ino);
-volume_failed:
-               ntfs_error(sb, "Failed to load $Volume.");
-               goto iput_lcnbmp_err_out;
-       }
-       m = map_mft_record(NTFS_I(vol->vol_ino));
-       if (IS_ERR(m)) {
-iput_volume_failed:
-               iput(vol->vol_ino);
-               goto volume_failed;
-       }
-       if (!(ctx = ntfs_attr_get_search_ctx(NTFS_I(vol->vol_ino), m))) {
-               ntfs_error(sb, "Failed to get attribute search context.");
-               goto get_ctx_vol_failed;
-       }
-       if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0,
-                       ctx) || ctx->attr->non_resident || ctx->attr->flags) {
-err_put_vol:
-               ntfs_attr_put_search_ctx(ctx);
-get_ctx_vol_failed:
-               unmap_mft_record(NTFS_I(vol->vol_ino));
-               goto iput_volume_failed;
-       }
-       vi = (VOLUME_INFORMATION*)((char*)ctx->attr +
-                       le16_to_cpu(ctx->attr->data.resident.value_offset));
-       /* Some bounds checks. */
-       if ((u8*)vi < (u8*)ctx->attr || (u8*)vi +
-                       le32_to_cpu(ctx->attr->data.resident.value_length) >
-                       (u8*)ctx->attr + le32_to_cpu(ctx->attr->length))
-               goto err_put_vol;
-       /* Copy the volume flags and version to the ntfs_volume structure. */
-       vol->vol_flags = vi->flags;
-       vol->major_ver = vi->major_ver;
-       vol->minor_ver = vi->minor_ver;
-       ntfs_attr_put_search_ctx(ctx);
-       unmap_mft_record(NTFS_I(vol->vol_ino));
-       pr_info("volume version %i.%i.\n", vol->major_ver,
-                       vol->minor_ver);
-       if (vol->major_ver < 3 && NVolSparseEnabled(vol)) {
-               ntfs_warning(vol->sb, "Disabling sparse support due to NTFS "
-                               "volume version %i.%i (need at least version "
-                               "3.0).", vol->major_ver, vol->minor_ver);
-               NVolClearSparseEnabled(vol);
-       }
-#ifdef NTFS_RW
-       /* Make sure that no unsupported volume flags are set. */
-       if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) {
-               static const char *es1a = "Volume is dirty";
-               static const char *es1b = "Volume has been modified by chkdsk";
-               static const char *es1c = "Volume has unsupported flags set";
-               static const char *es2a = ".  Run chkdsk and mount in Windows.";
-               static const char *es2b = ".  Mount in Windows.";
-               const char *es1, *es2;
-
-               es2 = es2a;
-               if (vol->vol_flags & VOLUME_IS_DIRTY)
-                       es1 = es1a;
-               else if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) {
-                       es1 = es1b;
-                       es2 = es2b;
-               } else {
-                       es1 = es1c;
-                       ntfs_warning(sb, "Unsupported volume flags 0x%x "
-                                       "encountered.",
-                                       (unsigned)le16_to_cpu(vol->vol_flags));
-               }
-               /* If a read-write mount, convert it to a read-only mount. */
-               if (!sb_rdonly(sb)) {
-                       if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
-                                       ON_ERRORS_CONTINUE))) {
-                               ntfs_error(sb, "%s and neither on_errors="
-                                               "continue nor on_errors="
-                                               "remount-ro was specified%s",
-                                               es1, es2);
-                               goto iput_vol_err_out;
-                       }
-                       sb->s_flags |= SB_RDONLY;
-                       ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-               } else
-                       ntfs_warning(sb, "%s.  Will not be able to remount "
-                                       "read-write%s", es1, es2);
-               /*
-                * Do not set NVolErrors() because ntfs_remount() re-checks the
-                * flags which we need to do in case any flags have changed.
-                */
-       }
-       /*
-        * Get the inode for the logfile, check it and determine if the volume
-        * was shutdown cleanly.
-        */
-       rp = NULL;
-       if (!load_and_check_logfile(vol, &rp) ||
-                       !ntfs_is_logfile_clean(vol->logfile_ino, rp)) {
-               static const char *es1a = "Failed to load $LogFile";
-               static const char *es1b = "$LogFile is not clean";
-               static const char *es2 = ".  Mount in Windows.";
-               const char *es1;
-
-               es1 = !vol->logfile_ino ? es1a : es1b;
-               /* If a read-write mount, convert it to a read-only mount. */
-               if (!sb_rdonly(sb)) {
-                       if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
-                                       ON_ERRORS_CONTINUE))) {
-                               ntfs_error(sb, "%s and neither on_errors="
-                                               "continue nor on_errors="
-                                               "remount-ro was specified%s",
-                                               es1, es2);
-                               if (vol->logfile_ino) {
-                                       BUG_ON(!rp);
-                                       ntfs_free(rp);
-                               }
-                               goto iput_logfile_err_out;
-                       }
-                       sb->s_flags |= SB_RDONLY;
-                       ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-               } else
-                       ntfs_warning(sb, "%s.  Will not be able to remount "
-                                       "read-write%s", es1, es2);
-               /* This will prevent a read-write remount. */
-               NVolSetErrors(vol);
-       }
-       ntfs_free(rp);
-#endif /* NTFS_RW */
-       /* Get the root directory inode so we can do path lookups. */
-       vol->root_ino = ntfs_iget(sb, FILE_root);
-       if (IS_ERR(vol->root_ino) || is_bad_inode(vol->root_ino)) {
-               if (!IS_ERR(vol->root_ino))
-                       iput(vol->root_ino);
-               ntfs_error(sb, "Failed to load root directory.");
-               goto iput_logfile_err_out;
-       }
-#ifdef NTFS_RW
-       /*
-        * Check if Windows is suspended to disk on the target volume.  If it
-        * is hibernated, we must not write *anything* to the disk so set
-        * NVolErrors() without setting the dirty volume flag and mount
-        * read-only.  This will prevent read-write remounting and it will also
-        * prevent all writes.
-        */
-       err = check_windows_hibernation_status(vol);
-       if (unlikely(err)) {
-               static const char *es1a = "Failed to determine if Windows is "
-                               "hibernated";
-               static const char *es1b = "Windows is hibernated";
-               static const char *es2 = ".  Run chkdsk.";
-               const char *es1;
-
-               es1 = err < 0 ? es1a : es1b;
-               /* If a read-write mount, convert it to a read-only mount. */
-               if (!sb_rdonly(sb)) {
-                       if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
-                                       ON_ERRORS_CONTINUE))) {
-                               ntfs_error(sb, "%s and neither on_errors="
-                                               "continue nor on_errors="
-                                               "remount-ro was specified%s",
-                                               es1, es2);
-                               goto iput_root_err_out;
-                       }
-                       sb->s_flags |= SB_RDONLY;
-                       ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-               } else
-                       ntfs_warning(sb, "%s.  Will not be able to remount "
-                                       "read-write%s", es1, es2);
-               /* This will prevent a read-write remount. */
-               NVolSetErrors(vol);
-       }
-       /* If (still) a read-write mount, mark the volume dirty. */
-       if (!sb_rdonly(sb) && ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) {
-               static const char *es1 = "Failed to set dirty bit in volume "
-                               "information flags";
-               static const char *es2 = ".  Run chkdsk.";
-
-               /* Convert to a read-only mount. */
-               if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
-                               ON_ERRORS_CONTINUE))) {
-                       ntfs_error(sb, "%s and neither on_errors=continue nor "
-                                       "on_errors=remount-ro was specified%s",
-                                       es1, es2);
-                       goto iput_root_err_out;
-               }
-               ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-               sb->s_flags |= SB_RDONLY;
-               /*
-                * Do not set NVolErrors() because ntfs_remount() might manage
-                * to set the dirty flag in which case all would be well.
-                */
-       }
-#if 0
-       // TODO: Enable this code once we start modifying anything that is
-       //       different between NTFS 1.2 and 3.x...
-       /*
-        * If (still) a read-write mount, set the NT4 compatibility flag on
-        * newer NTFS version volumes.
-        */
-       if (!(sb->s_flags & SB_RDONLY) && (vol->major_ver > 1) &&
-                       ntfs_set_volume_flags(vol, VOLUME_MOUNTED_ON_NT4)) {
-               static const char *es1 = "Failed to set NT4 compatibility flag";
-               static const char *es2 = ".  Run chkdsk.";
-
-               /* Convert to a read-only mount. */
-               if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
-                               ON_ERRORS_CONTINUE))) {
-                       ntfs_error(sb, "%s and neither on_errors=continue nor "
-                                       "on_errors=remount-ro was specified%s",
-                                       es1, es2);
-                       goto iput_root_err_out;
-               }
-               ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-               sb->s_flags |= SB_RDONLY;
-               NVolSetErrors(vol);
-       }
-#endif
-       /* If (still) a read-write mount, empty the logfile. */
-       if (!sb_rdonly(sb) && !ntfs_empty_logfile(vol->logfile_ino)) {
-               static const char *es1 = "Failed to empty $LogFile";
-               static const char *es2 = ".  Mount in Windows.";
-
-               /* Convert to a read-only mount. */
-               if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
-                               ON_ERRORS_CONTINUE))) {
-                       ntfs_error(sb, "%s and neither on_errors=continue nor "
-                                       "on_errors=remount-ro was specified%s",
-                                       es1, es2);
-                       goto iput_root_err_out;
-               }
-               ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-               sb->s_flags |= SB_RDONLY;
-               NVolSetErrors(vol);
-       }
-#endif /* NTFS_RW */
-       /* If on NTFS versions before 3.0, we are done. */
-       if (unlikely(vol->major_ver < 3))
-               return true;
-       /* NTFS 3.0+ specific initialization. */
-       /* Get the security descriptors inode. */
-       vol->secure_ino = ntfs_iget(sb, FILE_Secure);
-       if (IS_ERR(vol->secure_ino) || is_bad_inode(vol->secure_ino)) {
-               if (!IS_ERR(vol->secure_ino))
-                       iput(vol->secure_ino);
-               ntfs_error(sb, "Failed to load $Secure.");
-               goto iput_root_err_out;
-       }
-       // TODO: Initialize security.
-       /* Get the extended system files' directory inode. */
-       vol->extend_ino = ntfs_iget(sb, FILE_Extend);
-       if (IS_ERR(vol->extend_ino) || is_bad_inode(vol->extend_ino) ||
-           !S_ISDIR(vol->extend_ino->i_mode)) {
-               if (!IS_ERR(vol->extend_ino))
-                       iput(vol->extend_ino);
-               ntfs_error(sb, "Failed to load $Extend.");
-               goto iput_sec_err_out;
-       }
-#ifdef NTFS_RW
-       /* Find the quota file, load it if present, and set it up. */
-       if (!load_and_init_quota(vol)) {
-               static const char *es1 = "Failed to load $Quota";
-               static const char *es2 = ".  Run chkdsk.";
-
-               /* If a read-write mount, convert it to a read-only mount. */
-               if (!sb_rdonly(sb)) {
-                       if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
-                                       ON_ERRORS_CONTINUE))) {
-                               ntfs_error(sb, "%s and neither on_errors="
-                                               "continue nor on_errors="
-                                               "remount-ro was specified%s",
-                                               es1, es2);
-                               goto iput_quota_err_out;
-                       }
-                       sb->s_flags |= SB_RDONLY;
-                       ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-               } else
-                       ntfs_warning(sb, "%s.  Will not be able to remount "
-                                       "read-write%s", es1, es2);
-               /* This will prevent a read-write remount. */
-               NVolSetErrors(vol);
-       }
-       /* If (still) a read-write mount, mark the quotas out of date. */
-       if (!sb_rdonly(sb) && !ntfs_mark_quotas_out_of_date(vol)) {
-               static const char *es1 = "Failed to mark quotas out of date";
-               static const char *es2 = ".  Run chkdsk.";
-
-               /* Convert to a read-only mount. */
-               if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
-                               ON_ERRORS_CONTINUE))) {
-                       ntfs_error(sb, "%s and neither on_errors=continue nor "
-                                       "on_errors=remount-ro was specified%s",
-                                       es1, es2);
-                       goto iput_quota_err_out;
-               }
-               ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-               sb->s_flags |= SB_RDONLY;
-               NVolSetErrors(vol);
-       }
-       /*
-        * Find the transaction log file ($UsnJrnl), load it if present, check
-        * it, and set it up.
-        */
-       if (!load_and_init_usnjrnl(vol)) {
-               static const char *es1 = "Failed to load $UsnJrnl";
-               static const char *es2 = ".  Run chkdsk.";
-
-               /* If a read-write mount, convert it to a read-only mount. */
-               if (!sb_rdonly(sb)) {
-                       if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
-                                       ON_ERRORS_CONTINUE))) {
-                               ntfs_error(sb, "%s and neither on_errors="
-                                               "continue nor on_errors="
-                                               "remount-ro was specified%s",
-                                               es1, es2);
-                               goto iput_usnjrnl_err_out;
-                       }
-                       sb->s_flags |= SB_RDONLY;
-                       ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-               } else
-                       ntfs_warning(sb, "%s.  Will not be able to remount "
-                                       "read-write%s", es1, es2);
-               /* This will prevent a read-write remount. */
-               NVolSetErrors(vol);
-       }
-       /* If (still) a read-write mount, stamp the transaction log. */
-       if (!sb_rdonly(sb) && !ntfs_stamp_usnjrnl(vol)) {
-               static const char *es1 = "Failed to stamp transaction log "
-                               "($UsnJrnl)";
-               static const char *es2 = ".  Run chkdsk.";
-
-               /* Convert to a read-only mount. */
-               if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
-                               ON_ERRORS_CONTINUE))) {
-                       ntfs_error(sb, "%s and neither on_errors=continue nor "
-                                       "on_errors=remount-ro was specified%s",
-                                       es1, es2);
-                       goto iput_usnjrnl_err_out;
-               }
-               ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-               sb->s_flags |= SB_RDONLY;
-               NVolSetErrors(vol);
-       }
-#endif /* NTFS_RW */
-       return true;
-#ifdef NTFS_RW
-iput_usnjrnl_err_out:
-       iput(vol->usnjrnl_j_ino);
-       iput(vol->usnjrnl_max_ino);
-       iput(vol->usnjrnl_ino);
-iput_quota_err_out:
-       iput(vol->quota_q_ino);
-       iput(vol->quota_ino);
-       iput(vol->extend_ino);
-#endif /* NTFS_RW */
-iput_sec_err_out:
-       iput(vol->secure_ino);
-iput_root_err_out:
-       iput(vol->root_ino);
-iput_logfile_err_out:
-#ifdef NTFS_RW
-       iput(vol->logfile_ino);
-iput_vol_err_out:
-#endif /* NTFS_RW */
-       iput(vol->vol_ino);
-iput_lcnbmp_err_out:
-       iput(vol->lcnbmp_ino);
-iput_attrdef_err_out:
-       vol->attrdef_size = 0;
-       if (vol->attrdef) {
-               ntfs_free(vol->attrdef);
-               vol->attrdef = NULL;
-       }
-#ifdef NTFS_RW
-iput_upcase_err_out:
-#endif /* NTFS_RW */
-       vol->upcase_len = 0;
-       mutex_lock(&ntfs_lock);
-       if (vol->upcase == default_upcase) {
-               ntfs_nr_upcase_users--;
-               vol->upcase = NULL;
-       }
-       mutex_unlock(&ntfs_lock);
-       if (vol->upcase) {
-               ntfs_free(vol->upcase);
-               vol->upcase = NULL;
-       }
-iput_mftbmp_err_out:
-       iput(vol->mftbmp_ino);
-iput_mirr_err_out:
-#ifdef NTFS_RW
-       iput(vol->mftmirr_ino);
-#endif /* NTFS_RW */
-       return false;
-}
-
-/**
- * ntfs_put_super - called by the vfs to unmount a volume
- * @sb:                vfs superblock of volume to unmount
- *
- * ntfs_put_super() is called by the VFS (from fs/super.c::do_umount()) when
- * the volume is being unmounted (umount system call has been invoked) and it
- * releases all inodes and memory belonging to the NTFS specific part of the
- * super block.
- */
-static void ntfs_put_super(struct super_block *sb)
-{
-       ntfs_volume *vol = NTFS_SB(sb);
-
-       ntfs_debug("Entering.");
-
-#ifdef NTFS_RW
-       /*
-        * Commit all inodes while they are still open in case some of them
-        * cause others to be dirtied.
-        */
-       ntfs_commit_inode(vol->vol_ino);
-
-       /* NTFS 3.0+ specific. */
-       if (vol->major_ver >= 3) {
-               if (vol->usnjrnl_j_ino)
-                       ntfs_commit_inode(vol->usnjrnl_j_ino);
-               if (vol->usnjrnl_max_ino)
-                       ntfs_commit_inode(vol->usnjrnl_max_ino);
-               if (vol->usnjrnl_ino)
-                       ntfs_commit_inode(vol->usnjrnl_ino);
-               if (vol->quota_q_ino)
-                       ntfs_commit_inode(vol->quota_q_ino);
-               if (vol->quota_ino)
-                       ntfs_commit_inode(vol->quota_ino);
-               if (vol->extend_ino)
-                       ntfs_commit_inode(vol->extend_ino);
-               if (vol->secure_ino)
-                       ntfs_commit_inode(vol->secure_ino);
-       }
-
-       ntfs_commit_inode(vol->root_ino);
-
-       down_write(&vol->lcnbmp_lock);
-       ntfs_commit_inode(vol->lcnbmp_ino);
-       up_write(&vol->lcnbmp_lock);
-
-       down_write(&vol->mftbmp_lock);
-       ntfs_commit_inode(vol->mftbmp_ino);
-       up_write(&vol->mftbmp_lock);
-
-       if (vol->logfile_ino)
-               ntfs_commit_inode(vol->logfile_ino);
-
-       if (vol->mftmirr_ino)
-               ntfs_commit_inode(vol->mftmirr_ino);
-       ntfs_commit_inode(vol->mft_ino);
-
-       /*
-        * If a read-write mount and no volume errors have occurred, mark the
-        * volume clean.  Also, re-commit all affected inodes.
-        */
-       if (!sb_rdonly(sb)) {
-               if (!NVolErrors(vol)) {
-                       if (ntfs_clear_volume_flags(vol, VOLUME_IS_DIRTY))
-                               ntfs_warning(sb, "Failed to clear dirty bit "
-                                               "in volume information "
-                                               "flags.  Run chkdsk.");
-                       ntfs_commit_inode(vol->vol_ino);
-                       ntfs_commit_inode(vol->root_ino);
-                       if (vol->mftmirr_ino)
-                               ntfs_commit_inode(vol->mftmirr_ino);
-                       ntfs_commit_inode(vol->mft_ino);
-               } else {
-                       ntfs_warning(sb, "Volume has errors.  Leaving volume "
-                                       "marked dirty.  Run chkdsk.");
-               }
-       }
-#endif /* NTFS_RW */
-
-       iput(vol->vol_ino);
-       vol->vol_ino = NULL;
-
-       /* NTFS 3.0+ specific clean up. */
-       if (vol->major_ver >= 3) {
-#ifdef NTFS_RW
-               if (vol->usnjrnl_j_ino) {
-                       iput(vol->usnjrnl_j_ino);
-                       vol->usnjrnl_j_ino = NULL;
-               }
-               if (vol->usnjrnl_max_ino) {
-                       iput(vol->usnjrnl_max_ino);
-                       vol->usnjrnl_max_ino = NULL;
-               }
-               if (vol->usnjrnl_ino) {
-                       iput(vol->usnjrnl_ino);
-                       vol->usnjrnl_ino = NULL;
-               }
-               if (vol->quota_q_ino) {
-                       iput(vol->quota_q_ino);
-                       vol->quota_q_ino = NULL;
-               }
-               if (vol->quota_ino) {
-                       iput(vol->quota_ino);
-                       vol->quota_ino = NULL;
-               }
-#endif /* NTFS_RW */
-               if (vol->extend_ino) {
-                       iput(vol->extend_ino);
-                       vol->extend_ino = NULL;
-               }
-               if (vol->secure_ino) {
-                       iput(vol->secure_ino);
-                       vol->secure_ino = NULL;
-               }
-       }
-
-       iput(vol->root_ino);
-       vol->root_ino = NULL;
-
-       down_write(&vol->lcnbmp_lock);
-       iput(vol->lcnbmp_ino);
-       vol->lcnbmp_ino = NULL;
-       up_write(&vol->lcnbmp_lock);
-
-       down_write(&vol->mftbmp_lock);
-       iput(vol->mftbmp_ino);
-       vol->mftbmp_ino = NULL;
-       up_write(&vol->mftbmp_lock);
-
-#ifdef NTFS_RW
-       if (vol->logfile_ino) {
-               iput(vol->logfile_ino);
-               vol->logfile_ino = NULL;
-       }
-       if (vol->mftmirr_ino) {
-               /* Re-commit the mft mirror and mft just in case. */
-               ntfs_commit_inode(vol->mftmirr_ino);
-               ntfs_commit_inode(vol->mft_ino);
-               iput(vol->mftmirr_ino);
-               vol->mftmirr_ino = NULL;
-       }
-       /*
-        * We should have no dirty inodes left, due to
-        * mft.c::ntfs_mft_writepage() cleaning all the dirty pages as
-        * the underlying mft records are written out and cleaned.
-        */
-       ntfs_commit_inode(vol->mft_ino);
-       write_inode_now(vol->mft_ino, 1);
-#endif /* NTFS_RW */
-
-       iput(vol->mft_ino);
-       vol->mft_ino = NULL;
-
-       /* Throw away the table of attribute definitions. */
-       vol->attrdef_size = 0;
-       if (vol->attrdef) {
-               ntfs_free(vol->attrdef);
-               vol->attrdef = NULL;
-       }
-       vol->upcase_len = 0;
-       /*
-        * Destroy the global default upcase table if necessary.  Also decrease
-        * the number of upcase users if we are a user.
-        */
-       mutex_lock(&ntfs_lock);
-       if (vol->upcase == default_upcase) {
-               ntfs_nr_upcase_users--;
-               vol->upcase = NULL;
-       }
-       if (!ntfs_nr_upcase_users && default_upcase) {
-               ntfs_free(default_upcase);
-               default_upcase = NULL;
-       }
-       if (vol->cluster_size <= 4096 && !--ntfs_nr_compression_users)
-               free_compression_buffers();
-       mutex_unlock(&ntfs_lock);
-       if (vol->upcase) {
-               ntfs_free(vol->upcase);
-               vol->upcase = NULL;
-       }
-
-       unload_nls(vol->nls_map);
-
-       sb->s_fs_info = NULL;
-       kfree(vol);
-}
-
-/**
- * get_nr_free_clusters - return the number of free clusters on a volume
- * @vol:       ntfs volume for which to obtain free cluster count
- *
- * Calculate the number of free clusters on the mounted NTFS volume @vol. We
- * actually calculate the number of clusters in use instead because this
- * allows us to not care about partial pages as these will be just zero filled
- * and hence not be counted as allocated clusters.
- *
- * The only particularity is that clusters beyond the end of the logical ntfs
- * volume will be marked as allocated to prevent errors which means we have to
- * discount those at the end. This is important as the cluster bitmap always
- * has a size in multiples of 8 bytes, i.e. up to 63 clusters could be outside
- * the logical volume and marked in use when they are not as they do not exist.
- *
- * If any pages cannot be read we assume all clusters in the erroring pages are
- * in use. This means we return an underestimate on errors which is better than
- * an overestimate.
- */
-static s64 get_nr_free_clusters(ntfs_volume *vol)
-{
-       s64 nr_free = vol->nr_clusters;
-       struct address_space *mapping = vol->lcnbmp_ino->i_mapping;
-       struct page *page;
-       pgoff_t index, max_index;
-
-       ntfs_debug("Entering.");
-       /* Serialize accesses to the cluster bitmap. */
-       down_read(&vol->lcnbmp_lock);
-       /*
-        * Convert the number of bits into bytes rounded up, then convert into
-        * multiples of PAGE_SIZE, rounding up so that if we have one
-        * full and one partial page max_index = 2.
-        */
-       max_index = (((vol->nr_clusters + 7) >> 3) + PAGE_SIZE - 1) >>
-                       PAGE_SHIFT;
-       /* Use multiples of 4 bytes, thus max_size is PAGE_SIZE / 4. */
-       ntfs_debug("Reading $Bitmap, max_index = 0x%lx, max_size = 0x%lx.",
-                       max_index, PAGE_SIZE / 4);
-       for (index = 0; index < max_index; index++) {
-               unsigned long *kaddr;
-
-               /*
-                * Read the page from page cache, getting it from backing store
-                * if necessary, and increment the use count.
-                */
-               page = read_mapping_page(mapping, index, NULL);
-               /* Ignore pages which errored synchronously. */
-               if (IS_ERR(page)) {
-                       ntfs_debug("read_mapping_page() error. Skipping "
-                                       "page (index 0x%lx).", index);
-                       nr_free -= PAGE_SIZE * 8;
-                       continue;
-               }
-               kaddr = kmap_atomic(page);
-               /*
-                * Subtract the number of set bits. If this
-                * is the last page and it is partial we don't really care as
-                * it just means we do a little extra work but it won't affect
-                * the result as all out of range bytes are set to zero by
-                * ntfs_readpage().
-                */
-               nr_free -= bitmap_weight(kaddr,
-                                       PAGE_SIZE * BITS_PER_BYTE);
-               kunmap_atomic(kaddr);
-               put_page(page);
-       }
-       ntfs_debug("Finished reading $Bitmap, last index = 0x%lx.", index - 1);
-       /*
-        * Fixup for eventual bits outside logical ntfs volume (see function
-        * description above).
-        */
-       if (vol->nr_clusters & 63)
-               nr_free += 64 - (vol->nr_clusters & 63);
-       up_read(&vol->lcnbmp_lock);
-       /* If errors occurred we may well have gone below zero, fix this. */
-       if (nr_free < 0)
-               nr_free = 0;
-       ntfs_debug("Exiting.");
-       return nr_free;
-}
-
-/**
- * __get_nr_free_mft_records - return the number of free inodes on a volume
- * @vol:       ntfs volume for which to obtain free inode count
- * @nr_free:   number of mft records in filesystem
- * @max_index: maximum number of pages containing set bits
- *
- * Calculate the number of free mft records (inodes) on the mounted NTFS
- * volume @vol. We actually calculate the number of mft records in use instead
- * because this allows us to not care about partial pages as these will be just
- * zero filled and hence not be counted as allocated mft record.
- *
- * If any pages cannot be read we assume all mft records in the erroring pages
- * are in use. This means we return an underestimate on errors which is better
- * than an overestimate.
- *
- * NOTE: Caller must hold mftbmp_lock rw_semaphore for reading or writing.
- */
-static unsigned long __get_nr_free_mft_records(ntfs_volume *vol,
-               s64 nr_free, const pgoff_t max_index)
-{
-       struct address_space *mapping = vol->mftbmp_ino->i_mapping;
-       struct page *page;
-       pgoff_t index;
-
-       ntfs_debug("Entering.");
-       /* Use multiples of 4 bytes, thus max_size is PAGE_SIZE / 4. */
-       ntfs_debug("Reading $MFT/$BITMAP, max_index = 0x%lx, max_size = "
-                       "0x%lx.", max_index, PAGE_SIZE / 4);
-       for (index = 0; index < max_index; index++) {
-               unsigned long *kaddr;
-
-               /*
-                * Read the page from page cache, getting it from backing store
-                * if necessary, and increment the use count.
-                */
-               page = read_mapping_page(mapping, index, NULL);
-               /* Ignore pages which errored synchronously. */
-               if (IS_ERR(page)) {
-                       ntfs_debug("read_mapping_page() error. Skipping "
-                                       "page (index 0x%lx).", index);
-                       nr_free -= PAGE_SIZE * 8;
-                       continue;
-               }
-               kaddr = kmap_atomic(page);
-               /*
-                * Subtract the number of set bits. If this
-                * is the last page and it is partial we don't really care as
-                * it just means we do a little extra work but it won't affect
-                * the result as all out of range bytes are set to zero by
-                * ntfs_readpage().
-                */
-               nr_free -= bitmap_weight(kaddr,
-                                       PAGE_SIZE * BITS_PER_BYTE);
-               kunmap_atomic(kaddr);
-               put_page(page);
-       }
-       ntfs_debug("Finished reading $MFT/$BITMAP, last index = 0x%lx.",
-                       index - 1);
-       /* If errors occurred we may well have gone below zero, fix this. */
-       if (nr_free < 0)
-               nr_free = 0;
-       ntfs_debug("Exiting.");
-       return nr_free;
-}
-
-/**
- * ntfs_statfs - return information about mounted NTFS volume
- * @dentry:    dentry from mounted volume
- * @sfs:       statfs structure in which to return the information
- *
- * Return information about the mounted NTFS volume @dentry in the statfs structure
- * pointed to by @sfs (this is initialized with zeros before ntfs_statfs is
- * called). We interpret the values to be correct of the moment in time at
- * which we are called. Most values are variable otherwise and this isn't just
- * the free values but the totals as well. For example we can increase the
- * total number of file nodes if we run out and we can keep doing this until
- * there is no more space on the volume left at all.
- *
- * Called from vfs_statfs which is used to handle the statfs, fstatfs, and
- * ustat system calls.
- *
- * Return 0 on success or -errno on error.
- */
-static int ntfs_statfs(struct dentry *dentry, struct kstatfs *sfs)
-{
-       struct super_block *sb = dentry->d_sb;
-       s64 size;
-       ntfs_volume *vol = NTFS_SB(sb);
-       ntfs_inode *mft_ni = NTFS_I(vol->mft_ino);
-       pgoff_t max_index;
-       unsigned long flags;
-
-       ntfs_debug("Entering.");
-       /* Type of filesystem. */
-       sfs->f_type   = NTFS_SB_MAGIC;
-       /* Optimal transfer block size. */
-       sfs->f_bsize  = PAGE_SIZE;
-       /*
-        * Total data blocks in filesystem in units of f_bsize and since
-        * inodes are also stored in data blocs ($MFT is a file) this is just
-        * the total clusters.
-        */
-       sfs->f_blocks = vol->nr_clusters << vol->cluster_size_bits >>
-                               PAGE_SHIFT;
-       /* Free data blocks in filesystem in units of f_bsize. */
-       size          = get_nr_free_clusters(vol) << vol->cluster_size_bits >>
-                               PAGE_SHIFT;
-       if (size < 0LL)
-               size = 0LL;
-       /* Free blocks avail to non-superuser, same as above on NTFS. */
-       sfs->f_bavail = sfs->f_bfree = size;
-       /* Serialize accesses to the inode bitmap. */
-       down_read(&vol->mftbmp_lock);
-       read_lock_irqsave(&mft_ni->size_lock, flags);
-       size = i_size_read(vol->mft_ino) >> vol->mft_record_size_bits;
-       /*
-        * Convert the maximum number of set bits into bytes rounded up, then
-        * convert into multiples of PAGE_SIZE, rounding up so that if we
-        * have one full and one partial page max_index = 2.
-        */
-       max_index = ((((mft_ni->initialized_size >> vol->mft_record_size_bits)
-                       + 7) >> 3) + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       read_unlock_irqrestore(&mft_ni->size_lock, flags);
-       /* Number of inodes in filesystem (at this point in time). */
-       sfs->f_files = size;
-       /* Free inodes in fs (based on current total count). */
-       sfs->f_ffree = __get_nr_free_mft_records(vol, size, max_index);
-       up_read(&vol->mftbmp_lock);
-       /*
-        * File system id. This is extremely *nix flavour dependent and even
-        * within Linux itself all fs do their own thing. I interpret this to
-        * mean a unique id associated with the mounted fs and not the id
-        * associated with the filesystem driver, the latter is already given
-        * by the filesystem type in sfs->f_type. Thus we use the 64-bit
-        * volume serial number splitting it into two 32-bit parts. We enter
-        * the least significant 32-bits in f_fsid[0] and the most significant
-        * 32-bits in f_fsid[1].
-        */
-       sfs->f_fsid = u64_to_fsid(vol->serial_no);
-       /* Maximum length of filenames. */
-       sfs->f_namelen     = NTFS_MAX_NAME_LEN;
-       return 0;
-}
-
-#ifdef NTFS_RW
-static int ntfs_write_inode(struct inode *vi, struct writeback_control *wbc)
-{
-       return __ntfs_write_inode(vi, wbc->sync_mode == WB_SYNC_ALL);
-}
-#endif
-
-/*
- * The complete super operations.
- */
-static const struct super_operations ntfs_sops = {
-       .alloc_inode    = ntfs_alloc_big_inode,   /* VFS: Allocate new inode. */
-       .free_inode     = ntfs_free_big_inode, /* VFS: Deallocate inode. */
-#ifdef NTFS_RW
-       .write_inode    = ntfs_write_inode,     /* VFS: Write dirty inode to
-                                                  disk. */
-#endif /* NTFS_RW */
-       .put_super      = ntfs_put_super,       /* Syscall: umount. */
-       .statfs         = ntfs_statfs,          /* Syscall: statfs */
-       .remount_fs     = ntfs_remount,         /* Syscall: mount -o remount. */
-       .evict_inode    = ntfs_evict_big_inode, /* VFS: Called when an inode is
-                                                  removed from memory. */
-       .show_options   = ntfs_show_options,    /* Show mount options in
-                                                  proc. */
-};
-
-/**
- * ntfs_fill_super - mount an ntfs filesystem
- * @sb:                super block of ntfs filesystem to mount
- * @opt:       string containing the mount options
- * @silent:    silence error output
- *
- * ntfs_fill_super() is called by the VFS to mount the device described by @sb
- * with the mount otions in @data with the NTFS filesystem.
- *
- * If @silent is true, remain silent even if errors are detected. This is used
- * during bootup, when the kernel tries to mount the root filesystem with all
- * registered filesystems one after the other until one succeeds. This implies
- * that all filesystems except the correct one will quite correctly and
- * expectedly return an error, but nobody wants to see error messages when in
- * fact this is what is supposed to happen.
- *
- * NOTE: @sb->s_flags contains the mount options flags.
- */
-static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
-{
-       ntfs_volume *vol;
-       struct buffer_head *bh;
-       struct inode *tmp_ino;
-       int blocksize, result;
-
-       /*
-        * We do a pretty difficult piece of bootstrap by reading the
-        * MFT (and other metadata) from disk into memory. We'll only
-        * release this metadata during umount, so the locking patterns
-        * observed during bootstrap do not count. So turn off the
-        * observation of locking patterns (strictly for this context
-        * only) while mounting NTFS. [The validator is still active
-        * otherwise, even for this context: it will for example record
-        * lock class registrations.]
-        */
-       lockdep_off();
-       ntfs_debug("Entering.");
-#ifndef NTFS_RW
-       sb->s_flags |= SB_RDONLY;
-#endif /* ! NTFS_RW */
-       /* Allocate a new ntfs_volume and place it in sb->s_fs_info. */
-       sb->s_fs_info = kmalloc(sizeof(ntfs_volume), GFP_NOFS);
-       vol = NTFS_SB(sb);
-       if (!vol) {
-               if (!silent)
-                       ntfs_error(sb, "Allocation of NTFS volume structure "
-                                       "failed. Aborting mount...");
-               lockdep_on();
-               return -ENOMEM;
-       }
-       /* Initialize ntfs_volume structure. */
-       *vol = (ntfs_volume) {
-               .sb = sb,
-               /*
-                * Default is group and other don't have any access to files or
-                * directories while owner has full access. Further, files by
-                * default are not executable but directories are of course
-                * browseable.
-                */
-               .fmask = 0177,
-               .dmask = 0077,
-       };
-       init_rwsem(&vol->mftbmp_lock);
-       init_rwsem(&vol->lcnbmp_lock);
-
-       /* By default, enable sparse support. */
-       NVolSetSparseEnabled(vol);
-
-       /* Important to get the mount options dealt with now. */
-       if (!parse_options(vol, (char*)opt))
-               goto err_out_now;
-
-       /* We support sector sizes up to the PAGE_SIZE. */
-       if (bdev_logical_block_size(sb->s_bdev) > PAGE_SIZE) {
-               if (!silent)
-                       ntfs_error(sb, "Device has unsupported sector size "
-                                       "(%i).  The maximum supported sector "
-                                       "size on this architecture is %lu "
-                                       "bytes.",
-                                       bdev_logical_block_size(sb->s_bdev),
-                                       PAGE_SIZE);
-               goto err_out_now;
-       }
-       /*
-        * Setup the device access block size to NTFS_BLOCK_SIZE or the hard
-        * sector size, whichever is bigger.
-        */
-       blocksize = sb_min_blocksize(sb, NTFS_BLOCK_SIZE);
-       if (blocksize < NTFS_BLOCK_SIZE) {
-               if (!silent)
-                       ntfs_error(sb, "Unable to set device block size.");
-               goto err_out_now;
-       }
-       BUG_ON(blocksize != sb->s_blocksize);
-       ntfs_debug("Set device block size to %i bytes (block size bits %i).",
-                       blocksize, sb->s_blocksize_bits);
-       /* Determine the size of the device in units of block_size bytes. */
-       vol->nr_blocks = sb_bdev_nr_blocks(sb);
-       if (!vol->nr_blocks) {
-               if (!silent)
-                       ntfs_error(sb, "Unable to determine device size.");
-               goto err_out_now;
-       }
-       /* Read the boot sector and return unlocked buffer head to it. */
-       if (!(bh = read_ntfs_boot_sector(sb, silent))) {
-               if (!silent)
-                       ntfs_error(sb, "Not an NTFS volume.");
-               goto err_out_now;
-       }
-       /*
-        * Extract the data from the boot sector and setup the ntfs volume
-        * using it.
-        */
-       result = parse_ntfs_boot_sector(vol, (NTFS_BOOT_SECTOR*)bh->b_data);
-       brelse(bh);
-       if (!result) {
-               if (!silent)
-                       ntfs_error(sb, "Unsupported NTFS filesystem.");
-               goto err_out_now;
-       }
-       /*
-        * If the boot sector indicates a sector size bigger than the current
-        * device block size, switch the device block size to the sector size.
-        * TODO: It may be possible to support this case even when the set
-        * below fails, we would just be breaking up the i/o for each sector
-        * into multiple blocks for i/o purposes but otherwise it should just
-        * work.  However it is safer to leave disabled until someone hits this
-        * error message and then we can get them to try it without the setting
-        * so we know for sure that it works.
-        */
-       if (vol->sector_size > blocksize) {
-               blocksize = sb_set_blocksize(sb, vol->sector_size);
-               if (blocksize != vol->sector_size) {
-                       if (!silent)
-                               ntfs_error(sb, "Unable to set device block "
-                                               "size to sector size (%i).",
-                                               vol->sector_size);
-                       goto err_out_now;
-               }
-               BUG_ON(blocksize != sb->s_blocksize);
-               vol->nr_blocks = sb_bdev_nr_blocks(sb);
-               ntfs_debug("Changed device block size to %i bytes (block size "
-                               "bits %i) to match volume sector size.",
-                               blocksize, sb->s_blocksize_bits);
-       }
-       /* Initialize the cluster and mft allocators. */
-       ntfs_setup_allocators(vol);
-       /* Setup remaining fields in the super block. */
-       sb->s_magic = NTFS_SB_MAGIC;
-       /*
-        * Ntfs allows 63 bits for the file size, i.e. correct would be:
-        *      sb->s_maxbytes = ~0ULL >> 1;
-        * But the kernel uses a long as the page cache page index which on
-        * 32-bit architectures is only 32-bits. MAX_LFS_FILESIZE is kernel
-        * defined to the maximum the page cache page index can cope with
-        * without overflowing the index or to 2^63 - 1, whichever is smaller.
-        */
-       sb->s_maxbytes = MAX_LFS_FILESIZE;
-       /* Ntfs measures time in 100ns intervals. */
-       sb->s_time_gran = 100;
-       /*
-        * Now load the metadata required for the page cache and our address
-        * space operations to function. We do this by setting up a specialised
-        * read_inode method and then just calling the normal iget() to obtain
-        * the inode for $MFT which is sufficient to allow our normal inode
-        * operations and associated address space operations to function.
-        */
-       sb->s_op = &ntfs_sops;
-       tmp_ino = new_inode(sb);
-       if (!tmp_ino) {
-               if (!silent)
-                       ntfs_error(sb, "Failed to load essential metadata.");
-               goto err_out_now;
-       }
-       tmp_ino->i_ino = FILE_MFT;
-       insert_inode_hash(tmp_ino);
-       if (ntfs_read_inode_mount(tmp_ino) < 0) {
-               if (!silent)
-                       ntfs_error(sb, "Failed to load essential metadata.");
-               goto iput_tmp_ino_err_out_now;
-       }
-       mutex_lock(&ntfs_lock);
-       /*
-        * The current mount is a compression user if the cluster size is
-        * less than or equal 4kiB.
-        */
-       if (vol->cluster_size <= 4096 && !ntfs_nr_compression_users++) {
-               result = allocate_compression_buffers();
-               if (result) {
-                       ntfs_error(NULL, "Failed to allocate buffers "
-                                       "for compression engine.");
-                       ntfs_nr_compression_users--;
-                       mutex_unlock(&ntfs_lock);
-                       goto iput_tmp_ino_err_out_now;
-               }
-       }
-       /*
-        * Generate the global default upcase table if necessary.  Also
-        * temporarily increment the number of upcase users to avoid race
-        * conditions with concurrent (u)mounts.
-        */
-       if (!default_upcase)
-               default_upcase = generate_default_upcase();
-       ntfs_nr_upcase_users++;
-       mutex_unlock(&ntfs_lock);
-       /*
-        * From now on, ignore @silent parameter. If we fail below this line,
-        * it will be due to a corrupt fs or a system error, so we report it.
-        */
-       /*
-        * Open the system files with normal access functions and complete
-        * setting up the ntfs super block.
-        */
-       if (!load_system_files(vol)) {
-               ntfs_error(sb, "Failed to load system files.");
-               goto unl_upcase_iput_tmp_ino_err_out_now;
-       }
-
-       /* We grab a reference, simulating an ntfs_iget(). */
-       ihold(vol->root_ino);
-       if ((sb->s_root = d_make_root(vol->root_ino))) {
-               ntfs_debug("Exiting, status successful.");
-               /* Release the default upcase if it has no users. */
-               mutex_lock(&ntfs_lock);
-               if (!--ntfs_nr_upcase_users && default_upcase) {
-                       ntfs_free(default_upcase);
-                       default_upcase = NULL;
-               }
-               mutex_unlock(&ntfs_lock);
-               sb->s_export_op = &ntfs_export_ops;
-               lockdep_on();
-               return 0;
-       }
-       ntfs_error(sb, "Failed to allocate root directory.");
-       /* Clean up after the successful load_system_files() call from above. */
-       // TODO: Use ntfs_put_super() instead of repeating all this code...
-       // FIXME: Should mark the volume clean as the error is most likely
-       //        -ENOMEM.
-       iput(vol->vol_ino);
-       vol->vol_ino = NULL;
-       /* NTFS 3.0+ specific clean up. */
-       if (vol->major_ver >= 3) {
-#ifdef NTFS_RW
-               if (vol->usnjrnl_j_ino) {
-                       iput(vol->usnjrnl_j_ino);
-                       vol->usnjrnl_j_ino = NULL;
-               }
-               if (vol->usnjrnl_max_ino) {
-                       iput(vol->usnjrnl_max_ino);
-                       vol->usnjrnl_max_ino = NULL;
-               }
-               if (vol->usnjrnl_ino) {
-                       iput(vol->usnjrnl_ino);
-                       vol->usnjrnl_ino = NULL;
-               }
-               if (vol->quota_q_ino) {
-                       iput(vol->quota_q_ino);
-                       vol->quota_q_ino = NULL;
-               }
-               if (vol->quota_ino) {
-                       iput(vol->quota_ino);
-                       vol->quota_ino = NULL;
-               }
-#endif /* NTFS_RW */
-               if (vol->extend_ino) {
-                       iput(vol->extend_ino);
-                       vol->extend_ino = NULL;
-               }
-               if (vol->secure_ino) {
-                       iput(vol->secure_ino);
-                       vol->secure_ino = NULL;
-               }
-       }
-       iput(vol->root_ino);
-       vol->root_ino = NULL;
-       iput(vol->lcnbmp_ino);
-       vol->lcnbmp_ino = NULL;
-       iput(vol->mftbmp_ino);
-       vol->mftbmp_ino = NULL;
-#ifdef NTFS_RW
-       if (vol->logfile_ino) {
-               iput(vol->logfile_ino);
-               vol->logfile_ino = NULL;
-       }
-       if (vol->mftmirr_ino) {
-               iput(vol->mftmirr_ino);
-               vol->mftmirr_ino = NULL;
-       }
-#endif /* NTFS_RW */
-       /* Throw away the table of attribute definitions. */
-       vol->attrdef_size = 0;
-       if (vol->attrdef) {
-               ntfs_free(vol->attrdef);
-               vol->attrdef = NULL;
-       }
-       vol->upcase_len = 0;
-       mutex_lock(&ntfs_lock);
-       if (vol->upcase == default_upcase) {
-               ntfs_nr_upcase_users--;
-               vol->upcase = NULL;
-       }
-       mutex_unlock(&ntfs_lock);
-       if (vol->upcase) {
-               ntfs_free(vol->upcase);
-               vol->upcase = NULL;
-       }
-       if (vol->nls_map) {
-               unload_nls(vol->nls_map);
-               vol->nls_map = NULL;
-       }
-       /* Error exit code path. */
-unl_upcase_iput_tmp_ino_err_out_now:
-       /*
-        * Decrease the number of upcase users and destroy the global default
-        * upcase table if necessary.
-        */
-       mutex_lock(&ntfs_lock);
-       if (!--ntfs_nr_upcase_users && default_upcase) {
-               ntfs_free(default_upcase);
-               default_upcase = NULL;
-       }
-       if (vol->cluster_size <= 4096 && !--ntfs_nr_compression_users)
-               free_compression_buffers();
-       mutex_unlock(&ntfs_lock);
-iput_tmp_ino_err_out_now:
-       iput(tmp_ino);
-       if (vol->mft_ino && vol->mft_ino != tmp_ino)
-               iput(vol->mft_ino);
-       vol->mft_ino = NULL;
-       /* Errors at this stage are irrelevant. */
-err_out_now:
-       sb->s_fs_info = NULL;
-       kfree(vol);
-       ntfs_debug("Failed, returning -EINVAL.");
-       lockdep_on();
-       return -EINVAL;
-}
-
-/*
- * This is a slab cache to optimize allocations and deallocations of Unicode
- * strings of the maximum length allowed by NTFS, which is NTFS_MAX_NAME_LEN
- * (255) Unicode characters + a terminating NULL Unicode character.
- */
-struct kmem_cache *ntfs_name_cache;
-
-/* Slab caches for efficient allocation/deallocation of inodes. */
-struct kmem_cache *ntfs_inode_cache;
-struct kmem_cache *ntfs_big_inode_cache;
-
-/* Init once constructor for the inode slab cache. */
-static void ntfs_big_inode_init_once(void *foo)
-{
-       ntfs_inode *ni = (ntfs_inode *)foo;
-
-       inode_init_once(VFS_I(ni));
-}
-
-/*
- * Slab caches to optimize allocations and deallocations of attribute search
- * contexts and index contexts, respectively.
- */
-struct kmem_cache *ntfs_attr_ctx_cache;
-struct kmem_cache *ntfs_index_ctx_cache;
-
-/* Driver wide mutex. */
-DEFINE_MUTEX(ntfs_lock);
-
-static struct dentry *ntfs_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
-{
-       return mount_bdev(fs_type, flags, dev_name, data, ntfs_fill_super);
-}
-
-static struct file_system_type ntfs_fs_type = {
-       .owner          = THIS_MODULE,
-       .name           = "ntfs",
-       .mount          = ntfs_mount,
-       .kill_sb        = kill_block_super,
-       .fs_flags       = FS_REQUIRES_DEV,
-};
-MODULE_ALIAS_FS("ntfs");
-
-/* Stable names for the slab caches. */
-static const char ntfs_index_ctx_cache_name[] = "ntfs_index_ctx_cache";
-static const char ntfs_attr_ctx_cache_name[] = "ntfs_attr_ctx_cache";
-static const char ntfs_name_cache_name[] = "ntfs_name_cache";
-static const char ntfs_inode_cache_name[] = "ntfs_inode_cache";
-static const char ntfs_big_inode_cache_name[] = "ntfs_big_inode_cache";
-
-static int __init init_ntfs_fs(void)
-{
-       int err = 0;
-
-       /* This may be ugly but it results in pretty output so who cares. (-8 */
-       pr_info("driver " NTFS_VERSION " [Flags: R/"
-#ifdef NTFS_RW
-                       "W"
-#else
-                       "O"
-#endif
-#ifdef DEBUG
-                       " DEBUG"
-#endif
-#ifdef MODULE
-                       " MODULE"
-#endif
-                       "].\n");
-
-       ntfs_debug("Debug messages are enabled.");
-
-       ntfs_index_ctx_cache = kmem_cache_create(ntfs_index_ctx_cache_name,
-                       sizeof(ntfs_index_context), 0 /* offset */,
-                       SLAB_HWCACHE_ALIGN, NULL /* ctor */);
-       if (!ntfs_index_ctx_cache) {
-               pr_crit("Failed to create %s!\n", ntfs_index_ctx_cache_name);
-               goto ictx_err_out;
-       }
-       ntfs_attr_ctx_cache = kmem_cache_create(ntfs_attr_ctx_cache_name,
-                       sizeof(ntfs_attr_search_ctx), 0 /* offset */,
-                       SLAB_HWCACHE_ALIGN, NULL /* ctor */);
-       if (!ntfs_attr_ctx_cache) {
-               pr_crit("NTFS: Failed to create %s!\n",
-                       ntfs_attr_ctx_cache_name);
-               goto actx_err_out;
-       }
-
-       ntfs_name_cache = kmem_cache_create(ntfs_name_cache_name,
-                       (NTFS_MAX_NAME_LEN+1) * sizeof(ntfschar), 0,
-                       SLAB_HWCACHE_ALIGN, NULL);
-       if (!ntfs_name_cache) {
-               pr_crit("Failed to create %s!\n", ntfs_name_cache_name);
-               goto name_err_out;
-       }
-
-       ntfs_inode_cache = kmem_cache_create(ntfs_inode_cache_name,
-                       sizeof(ntfs_inode), 0,
-                       SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
-       if (!ntfs_inode_cache) {
-               pr_crit("Failed to create %s!\n", ntfs_inode_cache_name);
-               goto inode_err_out;
-       }
-
-       ntfs_big_inode_cache = kmem_cache_create(ntfs_big_inode_cache_name,
-                       sizeof(big_ntfs_inode), 0,
-                       SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|
-                       SLAB_ACCOUNT, ntfs_big_inode_init_once);
-       if (!ntfs_big_inode_cache) {
-               pr_crit("Failed to create %s!\n", ntfs_big_inode_cache_name);
-               goto big_inode_err_out;
-       }
-
-       /* Register the ntfs sysctls. */
-       err = ntfs_sysctl(1);
-       if (err) {
-               pr_crit("Failed to register NTFS sysctls!\n");
-               goto sysctl_err_out;
-       }
-
-       err = register_filesystem(&ntfs_fs_type);
-       if (!err) {
-               ntfs_debug("NTFS driver registered successfully.");
-               return 0; /* Success! */
-       }
-       pr_crit("Failed to register NTFS filesystem driver!\n");
-
-       /* Unregister the ntfs sysctls. */
-       ntfs_sysctl(0);
-sysctl_err_out:
-       kmem_cache_destroy(ntfs_big_inode_cache);
-big_inode_err_out:
-       kmem_cache_destroy(ntfs_inode_cache);
-inode_err_out:
-       kmem_cache_destroy(ntfs_name_cache);
-name_err_out:
-       kmem_cache_destroy(ntfs_attr_ctx_cache);
-actx_err_out:
-       kmem_cache_destroy(ntfs_index_ctx_cache);
-ictx_err_out:
-       if (!err) {
-               pr_crit("Aborting NTFS filesystem driver registration...\n");
-               err = -ENOMEM;
-       }
-       return err;
-}
-
-static void __exit exit_ntfs_fs(void)
-{
-       ntfs_debug("Unregistering NTFS driver.");
-
-       unregister_filesystem(&ntfs_fs_type);
-
-       /*
-        * Make sure all delayed rcu free inodes are flushed before we
-        * destroy cache.
-        */
-       rcu_barrier();
-       kmem_cache_destroy(ntfs_big_inode_cache);
-       kmem_cache_destroy(ntfs_inode_cache);
-       kmem_cache_destroy(ntfs_name_cache);
-       kmem_cache_destroy(ntfs_attr_ctx_cache);
-       kmem_cache_destroy(ntfs_index_ctx_cache);
-       /* Unregister the ntfs sysctls. */
-       ntfs_sysctl(0);
-}
-
-MODULE_AUTHOR("Anton Altaparmakov <anton@tuxera.com>");
-MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc.");
-MODULE_VERSION(NTFS_VERSION);
-MODULE_LICENSE("GPL");
-#ifdef DEBUG
-module_param(debug_msgs, bint, 0);
-MODULE_PARM_DESC(debug_msgs, "Enable debug messages.");
-#endif
-
-module_init(init_ntfs_fs)
-module_exit(exit_ntfs_fs)
diff --git a/fs/ntfs/sysctl.c b/fs/ntfs/sysctl.c
deleted file mode 100644 (file)
index 4e98017..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * sysctl.c - Code for sysctl handling in NTFS Linux kernel driver. Part of
- *           the Linux-NTFS project. Adapted from the old NTFS driver,
- *           Copyright (C) 1997 Martin von Löwis, Régis Duchesne
- *
- * Copyright (c) 2002-2005 Anton Altaparmakov
- */
-
-#ifdef DEBUG
-
-#include <linux/module.h>
-
-#ifdef CONFIG_SYSCTL
-
-#include <linux/proc_fs.h>
-#include <linux/sysctl.h>
-
-#include "sysctl.h"
-#include "debug.h"
-
-/* Definition of the ntfs sysctl. */
-static struct ctl_table ntfs_sysctls[] = {
-       {
-               .procname       = "ntfs-debug",
-               .data           = &debug_msgs,          /* Data pointer and size. */
-               .maxlen         = sizeof(debug_msgs),
-               .mode           = 0644,                 /* Mode, proc handler. */
-               .proc_handler   = proc_dointvec
-       },
-};
-
-/* Storage for the sysctls header. */
-static struct ctl_table_header *sysctls_root_table;
-
-/**
- * ntfs_sysctl - add or remove the debug sysctl
- * @add:       add (1) or remove (0) the sysctl
- *
- * Add or remove the debug sysctl. Return 0 on success or -errno on error.
- */
-int ntfs_sysctl(int add)
-{
-       if (add) {
-               BUG_ON(sysctls_root_table);
-               sysctls_root_table = register_sysctl("fs", ntfs_sysctls);
-               if (!sysctls_root_table)
-                       return -ENOMEM;
-       } else {
-               BUG_ON(!sysctls_root_table);
-               unregister_sysctl_table(sysctls_root_table);
-               sysctls_root_table = NULL;
-       }
-       return 0;
-}
-
-#endif /* CONFIG_SYSCTL */
-#endif /* DEBUG */
diff --git a/fs/ntfs/sysctl.h b/fs/ntfs/sysctl.h
deleted file mode 100644 (file)
index 96bb229..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * sysctl.h - Defines for sysctl handling in NTFS Linux kernel driver. Part of
- *           the Linux-NTFS project. Adapted from the old NTFS driver,
- *           Copyright (C) 1997 Martin von Löwis, Régis Duchesne
- *
- * Copyright (c) 2002-2004 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_SYSCTL_H
-#define _LINUX_NTFS_SYSCTL_H
-
-
-#if defined(DEBUG) && defined(CONFIG_SYSCTL)
-
-extern int ntfs_sysctl(int add);
-
-#else
-
-/* Just return success. */
-static inline int ntfs_sysctl(int add)
-{
-       return 0;
-}
-
-#endif /* DEBUG && CONFIG_SYSCTL */
-#endif /* _LINUX_NTFS_SYSCTL_H */
diff --git a/fs/ntfs/time.h b/fs/ntfs/time.h
deleted file mode 100644 (file)
index 6b63261..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * time.h - NTFS time conversion functions.  Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2005 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_TIME_H
-#define _LINUX_NTFS_TIME_H
-
-#include <linux/time.h>                /* For current_kernel_time(). */
-#include <asm/div64.h>         /* For do_div(). */
-
-#include "endian.h"
-
-#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
-
-/**
- * utc2ntfs - convert Linux UTC time to NTFS time
- * @ts:                Linux UTC time to convert to NTFS time
- *
- * Convert the Linux UTC time @ts to its corresponding NTFS time and return
- * that in little endian format.
- *
- * Linux stores time in a struct timespec64 consisting of a time64_t tv_sec
- * and a long tv_nsec where tv_sec is the number of 1-second intervals since
- * 1st January 1970, 00:00:00 UTC and tv_nsec is the number of 1-nano-second
- * intervals since the value of tv_sec.
- *
- * NTFS uses Microsoft's standard time format which is stored in a s64 and is
- * measured as the number of 100-nano-second intervals since 1st January 1601,
- * 00:00:00 UTC.
- */
-static inline sle64 utc2ntfs(const struct timespec64 ts)
-{
-       /*
-        * Convert the seconds to 100ns intervals, add the nano-seconds
-        * converted to 100ns intervals, and then add the NTFS time offset.
-        */
-       return cpu_to_sle64((s64)ts.tv_sec * 10000000 + ts.tv_nsec / 100 +
-                       NTFS_TIME_OFFSET);
-}
-
-/**
- * get_current_ntfs_time - get the current time in little endian NTFS format
- *
- * Get the current time from the Linux kernel, convert it to its corresponding
- * NTFS time and return that in little endian format.
- */
-static inline sle64 get_current_ntfs_time(void)
-{
-       struct timespec64 ts;
-
-       ktime_get_coarse_real_ts64(&ts);
-       return utc2ntfs(ts);
-}
-
-/**
- * ntfs2utc - convert NTFS time to Linux time
- * @time:      NTFS time (little endian) to convert to Linux UTC
- *
- * Convert the little endian NTFS time @time to its corresponding Linux UTC
- * time and return that in cpu format.
- *
- * Linux stores time in a struct timespec64 consisting of a time64_t tv_sec
- * and a long tv_nsec where tv_sec is the number of 1-second intervals since
- * 1st January 1970, 00:00:00 UTC and tv_nsec is the number of 1-nano-second
- * intervals since the value of tv_sec.
- *
- * NTFS uses Microsoft's standard time format which is stored in a s64 and is
- * measured as the number of 100 nano-second intervals since 1st January 1601,
- * 00:00:00 UTC.
- */
-static inline struct timespec64 ntfs2utc(const sle64 time)
-{
-       struct timespec64 ts;
-
-       /* Subtract the NTFS time offset. */
-       u64 t = (u64)(sle64_to_cpu(time) - NTFS_TIME_OFFSET);
-       /*
-        * Convert the time to 1-second intervals and the remainder to
-        * 1-nano-second intervals.
-        */
-       ts.tv_nsec = do_div(t, 10000000) * 100;
-       ts.tv_sec = t;
-       return ts;
-}
-
-#endif /* _LINUX_NTFS_TIME_H */
diff --git a/fs/ntfs/types.h b/fs/ntfs/types.h
deleted file mode 100644 (file)
index 9a47859..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * types.h - Defines for NTFS Linux kernel driver specific types.
- *          Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2005 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_TYPES_H
-#define _LINUX_NTFS_TYPES_H
-
-#include <linux/types.h>
-
-typedef __le16 le16;
-typedef __le32 le32;
-typedef __le64 le64;
-typedef __u16 __bitwise sle16;
-typedef __u32 __bitwise sle32;
-typedef __u64 __bitwise sle64;
-
-/* 2-byte Unicode character type. */
-typedef le16 ntfschar;
-#define UCHAR_T_SIZE_BITS 1
-
-/*
- * Clusters are signed 64-bit values on NTFS volumes. We define two types, LCN
- * and VCN, to allow for type checking and better code readability.
- */
-typedef s64 VCN;
-typedef sle64 leVCN;
-typedef s64 LCN;
-typedef sle64 leLCN;
-
-/*
- * The NTFS journal $LogFile uses log sequence numbers which are signed 64-bit
- * values.  We define our own type LSN, to allow for type checking and better
- * code readability.
- */
-typedef s64 LSN;
-typedef sle64 leLSN;
-
-/*
- * The NTFS transaction log $UsnJrnl uses usn which are signed 64-bit values.
- * We define our own type USN, to allow for type checking and better code
- * readability.
- */
-typedef s64 USN;
-typedef sle64 leUSN;
-
-typedef enum {
-       CASE_SENSITIVE = 0,
-       IGNORE_CASE = 1,
-} IGNORE_CASE_BOOL;
-
-#endif /* _LINUX_NTFS_TYPES_H */
diff --git a/fs/ntfs/unistr.c b/fs/ntfs/unistr.c
deleted file mode 100644 (file)
index a6b6c64..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2006 Anton Altaparmakov
- */
-
-#include <linux/slab.h>
-
-#include "types.h"
-#include "debug.h"
-#include "ntfs.h"
-
-/*
- * IMPORTANT
- * =========
- *
- * All these routines assume that the Unicode characters are in little endian
- * encoding inside the strings!!!
- */
-
-/*
- * This is used by the name collation functions to quickly determine what
- * characters are (in)valid.
- */
-static const u8 legal_ansi_char_array[0x40] = {
-       0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
-       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
-
-       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
-       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
-
-       0x17, 0x07, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17,
-       0x17, 0x17, 0x18, 0x16, 0x16, 0x17, 0x07, 0x00,
-
-       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
-       0x17, 0x17, 0x04, 0x16, 0x18, 0x16, 0x18, 0x18,
-};
-
-/**
- * ntfs_are_names_equal - compare two Unicode names for equality
- * @s1:                        name to compare to @s2
- * @s1_len:            length in Unicode characters of @s1
- * @s2:                        name to compare to @s1
- * @s2_len:            length in Unicode characters of @s2
- * @ic:                        ignore case bool
- * @upcase:            upcase table (only if @ic == IGNORE_CASE)
- * @upcase_size:       length in Unicode characters of @upcase (if present)
- *
- * Compare the names @s1 and @s2 and return 'true' (1) if the names are
- * identical, or 'false' (0) if they are not identical. If @ic is IGNORE_CASE,
- * the @upcase table is used to performa a case insensitive comparison.
- */
-bool ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
-               const ntfschar *s2, size_t s2_len, const IGNORE_CASE_BOOL ic,
-               const ntfschar *upcase, const u32 upcase_size)
-{
-       if (s1_len != s2_len)
-               return false;
-       if (ic == CASE_SENSITIVE)
-               return !ntfs_ucsncmp(s1, s2, s1_len);
-       return !ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size);
-}
-
-/**
- * ntfs_collate_names - collate two Unicode names
- * @name1:     first Unicode name to compare
- * @name2:     second Unicode name to compare
- * @err_val:   if @name1 contains an invalid character return this value
- * @ic:                either CASE_SENSITIVE or IGNORE_CASE
- * @upcase:    upcase table (ignored if @ic is CASE_SENSITIVE)
- * @upcase_len:        upcase table size (ignored if @ic is CASE_SENSITIVE)
- *
- * ntfs_collate_names collates two Unicode names and returns:
- *
- *  -1 if the first name collates before the second one,
- *   0 if the names match,
- *   1 if the second name collates before the first one, or
- * @err_val if an invalid character is found in @name1 during the comparison.
- *
- * The following characters are considered invalid: '"', '*', '<', '>' and '?'.
- */
-int ntfs_collate_names(const ntfschar *name1, const u32 name1_len,
-               const ntfschar *name2, const u32 name2_len,
-               const int err_val, const IGNORE_CASE_BOOL ic,
-               const ntfschar *upcase, const u32 upcase_len)
-{
-       u32 cnt, min_len;
-       u16 c1, c2;
-
-       min_len = name1_len;
-       if (name1_len > name2_len)
-               min_len = name2_len;
-       for (cnt = 0; cnt < min_len; ++cnt) {
-               c1 = le16_to_cpu(*name1++);
-               c2 = le16_to_cpu(*name2++);
-               if (ic) {
-                       if (c1 < upcase_len)
-                               c1 = le16_to_cpu(upcase[c1]);
-                       if (c2 < upcase_len)
-                               c2 = le16_to_cpu(upcase[c2]);
-               }
-               if (c1 < 64 && legal_ansi_char_array[c1] & 8)
-                       return err_val;
-               if (c1 < c2)
-                       return -1;
-               if (c1 > c2)
-                       return 1;
-       }
-       if (name1_len < name2_len)
-               return -1;
-       if (name1_len == name2_len)
-               return 0;
-       /* name1_len > name2_len */
-       c1 = le16_to_cpu(*name1);
-       if (c1 < 64 && legal_ansi_char_array[c1] & 8)
-               return err_val;
-       return 1;
-}
-
-/**
- * ntfs_ucsncmp - compare two little endian Unicode strings
- * @s1:                first string
- * @s2:                second string
- * @n:         maximum unicode characters to compare
- *
- * Compare the first @n characters of the Unicode strings @s1 and @s2,
- * The strings in little endian format and appropriate le16_to_cpu()
- * conversion is performed on non-little endian machines.
- *
- * The function returns an integer less than, equal to, or greater than zero
- * if @s1 (or the first @n Unicode characters thereof) is found, respectively,
- * to be less than, to match, or be greater than @s2.
- */
-int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
-{
-       u16 c1, c2;
-       size_t i;
-
-       for (i = 0; i < n; ++i) {
-               c1 = le16_to_cpu(s1[i]);
-               c2 = le16_to_cpu(s2[i]);
-               if (c1 < c2)
-                       return -1;
-               if (c1 > c2)
-                       return 1;
-               if (!c1)
-                       break;
-       }
-       return 0;
-}
-
-/**
- * ntfs_ucsncasecmp - compare two little endian Unicode strings, ignoring case
- * @s1:                        first string
- * @s2:                        second string
- * @n:                 maximum unicode characters to compare
- * @upcase:            upcase table
- * @upcase_size:       upcase table size in Unicode characters
- *
- * Compare the first @n characters of the Unicode strings @s1 and @s2,
- * ignoring case. The strings in little endian format and appropriate
- * le16_to_cpu() conversion is performed on non-little endian machines.
- *
- * Each character is uppercased using the @upcase table before the comparison.
- *
- * The function returns an integer less than, equal to, or greater than zero
- * if @s1 (or the first @n Unicode characters thereof) is found, respectively,
- * to be less than, to match, or be greater than @s2.
- */
-int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
-               const ntfschar *upcase, const u32 upcase_size)
-{
-       size_t i;
-       u16 c1, c2;
-
-       for (i = 0; i < n; ++i) {
-               if ((c1 = le16_to_cpu(s1[i])) < upcase_size)
-                       c1 = le16_to_cpu(upcase[c1]);
-               if ((c2 = le16_to_cpu(s2[i])) < upcase_size)
-                       c2 = le16_to_cpu(upcase[c2]);
-               if (c1 < c2)
-                       return -1;
-               if (c1 > c2)
-                       return 1;
-               if (!c1)
-                       break;
-       }
-       return 0;
-}
-
-void ntfs_upcase_name(ntfschar *name, u32 name_len, const ntfschar *upcase,
-               const u32 upcase_len)
-{
-       u32 i;
-       u16 u;
-
-       for (i = 0; i < name_len; i++)
-               if ((u = le16_to_cpu(name[i])) < upcase_len)
-                       name[i] = upcase[u];
-}
-
-void ntfs_file_upcase_value(FILE_NAME_ATTR *file_name_attr,
-               const ntfschar *upcase, const u32 upcase_len)
-{
-       ntfs_upcase_name((ntfschar*)&file_name_attr->file_name,
-                       file_name_attr->file_name_length, upcase, upcase_len);
-}
-
-int ntfs_file_compare_values(FILE_NAME_ATTR *file_name_attr1,
-               FILE_NAME_ATTR *file_name_attr2,
-               const int err_val, const IGNORE_CASE_BOOL ic,
-               const ntfschar *upcase, const u32 upcase_len)
-{
-       return ntfs_collate_names((ntfschar*)&file_name_attr1->file_name,
-                       file_name_attr1->file_name_length,
-                       (ntfschar*)&file_name_attr2->file_name,
-                       file_name_attr2->file_name_length,
-                       err_val, ic, upcase, upcase_len);
-}
-
-/**
- * ntfs_nlstoucs - convert NLS string to little endian Unicode string
- * @vol:       ntfs volume which we are working with
- * @ins:       input NLS string buffer
- * @ins_len:   length of input string in bytes
- * @outs:      on return contains the allocated output Unicode string buffer
- *
- * Convert the input string @ins, which is in whatever format the loaded NLS
- * map dictates, into a little endian, 2-byte Unicode string.
- *
- * This function allocates the string and the caller is responsible for
- * calling kmem_cache_free(ntfs_name_cache, *@outs); when finished with it.
- *
- * On success the function returns the number of Unicode characters written to
- * the output string *@outs (>= 0), not counting the terminating Unicode NULL
- * character. *@outs is set to the allocated output string buffer.
- *
- * On error, a negative number corresponding to the error code is returned. In
- * that case the output string is not allocated. Both *@outs and *@outs_len
- * are then undefined.
- *
- * This might look a bit odd due to fast path optimization...
- */
-int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
-               const int ins_len, ntfschar **outs)
-{
-       struct nls_table *nls = vol->nls_map;
-       ntfschar *ucs;
-       wchar_t wc;
-       int i, o, wc_len;
-
-       /* We do not trust outside sources. */
-       if (likely(ins)) {
-               ucs = kmem_cache_alloc(ntfs_name_cache, GFP_NOFS);
-               if (likely(ucs)) {
-                       for (i = o = 0; i < ins_len; i += wc_len) {
-                               wc_len = nls->char2uni(ins + i, ins_len - i,
-                                               &wc);
-                               if (likely(wc_len >= 0 &&
-                                               o < NTFS_MAX_NAME_LEN)) {
-                                       if (likely(wc)) {
-                                               ucs[o++] = cpu_to_le16(wc);
-                                               continue;
-                                       } /* else if (!wc) */
-                                       break;
-                               } /* else if (wc_len < 0 ||
-                                               o >= NTFS_MAX_NAME_LEN) */
-                               goto name_err;
-                       }
-                       ucs[o] = 0;
-                       *outs = ucs;
-                       return o;
-               } /* else if (!ucs) */
-               ntfs_error(vol->sb, "Failed to allocate buffer for converted "
-                               "name from ntfs_name_cache.");
-               return -ENOMEM;
-       } /* else if (!ins) */
-       ntfs_error(vol->sb, "Received NULL pointer.");
-       return -EINVAL;
-name_err:
-       kmem_cache_free(ntfs_name_cache, ucs);
-       if (wc_len < 0) {
-               ntfs_error(vol->sb, "Name using character set %s contains "
-                               "characters that cannot be converted to "
-                               "Unicode.", nls->charset);
-               i = -EILSEQ;
-       } else /* if (o >= NTFS_MAX_NAME_LEN) */ {
-               ntfs_error(vol->sb, "Name is too long (maximum length for a "
-                               "name on NTFS is %d Unicode characters.",
-                               NTFS_MAX_NAME_LEN);
-               i = -ENAMETOOLONG;
-       }
-       return i;
-}
-
-/**
- * ntfs_ucstonls - convert little endian Unicode string to NLS string
- * @vol:       ntfs volume which we are working with
- * @ins:       input Unicode string buffer
- * @ins_len:   length of input string in Unicode characters
- * @outs:      on return contains the (allocated) output NLS string buffer
- * @outs_len:  length of output string buffer in bytes
- *
- * Convert the input little endian, 2-byte Unicode string @ins, of length
- * @ins_len into the string format dictated by the loaded NLS.
- *
- * If *@outs is NULL, this function allocates the string and the caller is
- * responsible for calling kfree(*@outs); when finished with it. In this case
- * @outs_len is ignored and can be 0.
- *
- * On success the function returns the number of bytes written to the output
- * string *@outs (>= 0), not counting the terminating NULL byte. If the output
- * string buffer was allocated, *@outs is set to it.
- *
- * On error, a negative number corresponding to the error code is returned. In
- * that case the output string is not allocated. The contents of *@outs are
- * then undefined.
- *
- * This might look a bit odd due to fast path optimization...
- */
-int ntfs_ucstonls(const ntfs_volume *vol, const ntfschar *ins,
-               const int ins_len, unsigned char **outs, int outs_len)
-{
-       struct nls_table *nls = vol->nls_map;
-       unsigned char *ns;
-       int i, o, ns_len, wc;
-
-       /* We don't trust outside sources. */
-       if (ins) {
-               ns = *outs;
-               ns_len = outs_len;
-               if (ns && !ns_len) {
-                       wc = -ENAMETOOLONG;
-                       goto conversion_err;
-               }
-               if (!ns) {
-                       ns_len = ins_len * NLS_MAX_CHARSET_SIZE;
-                       ns = kmalloc(ns_len + 1, GFP_NOFS);
-                       if (!ns)
-                               goto mem_err_out;
-               }
-               for (i = o = 0; i < ins_len; i++) {
-retry:                 wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o,
-                                       ns_len - o);
-                       if (wc > 0) {
-                               o += wc;
-                               continue;
-                       } else if (!wc)
-                               break;
-                       else if (wc == -ENAMETOOLONG && ns != *outs) {
-                               unsigned char *tc;
-                               /* Grow in multiples of 64 bytes. */
-                               tc = kmalloc((ns_len + 64) &
-                                               ~63, GFP_NOFS);
-                               if (tc) {
-                                       memcpy(tc, ns, ns_len);
-                                       ns_len = ((ns_len + 64) & ~63) - 1;
-                                       kfree(ns);
-                                       ns = tc;
-                                       goto retry;
-                               } /* No memory so goto conversion_error; */
-                       } /* wc < 0, real error. */
-                       goto conversion_err;
-               }
-               ns[o] = 0;
-               *outs = ns;
-               return o;
-       } /* else (!ins) */
-       ntfs_error(vol->sb, "Received NULL pointer.");
-       return -EINVAL;
-conversion_err:
-       ntfs_error(vol->sb, "Unicode name contains characters that cannot be "
-                       "converted to character set %s.  You might want to "
-                       "try to use the mount option nls=utf8.", nls->charset);
-       if (ns != *outs)
-               kfree(ns);
-       if (wc != -ENAMETOOLONG)
-               wc = -EILSEQ;
-       return wc;
-mem_err_out:
-       ntfs_error(vol->sb, "Failed to allocate name!");
-       return -ENOMEM;
-}
diff --git a/fs/ntfs/upcase.c b/fs/ntfs/upcase.c
deleted file mode 100644 (file)
index 4ebe84a..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * upcase.c - Generate the full NTFS Unicode upcase table in little endian.
- *           Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001 Richard Russon <ntfs@flatcap.org>
- * Copyright (c) 2001-2006 Anton Altaparmakov
- */
-
-#include "malloc.h"
-#include "ntfs.h"
-
-ntfschar *generate_default_upcase(void)
-{
-       static const int uc_run_table[][3] = { /* Start, End, Add */
-       {0x0061, 0x007B,  -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72,  74},
-       {0x00E0, 0x00F7,  -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76,  86},
-       {0x00F8, 0x00FF,  -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100},
-       {0x0256, 0x0258, -205}, {0x1F00, 0x1F08,   8}, {0x1F78, 0x1F7A, 128},
-       {0x028A, 0x028C, -217}, {0x1F10, 0x1F16,   8}, {0x1F7A, 0x1F7C, 112},
-       {0x03AC, 0x03AD,  -38}, {0x1F20, 0x1F28,   8}, {0x1F7C, 0x1F7E, 126},
-       {0x03AD, 0x03B0,  -37}, {0x1F30, 0x1F38,   8}, {0x1FB0, 0x1FB2,   8},
-       {0x03B1, 0x03C2,  -32}, {0x1F40, 0x1F46,   8}, {0x1FD0, 0x1FD2,   8},
-       {0x03C2, 0x03C3,  -31}, {0x1F51, 0x1F52,   8}, {0x1FE0, 0x1FE2,   8},
-       {0x03C3, 0x03CC,  -32}, {0x1F53, 0x1F54,   8}, {0x1FE5, 0x1FE6,   7},
-       {0x03CC, 0x03CD,  -64}, {0x1F55, 0x1F56,   8}, {0x2170, 0x2180, -16},
-       {0x03CD, 0x03CF,  -63}, {0x1F57, 0x1F58,   8}, {0x24D0, 0x24EA, -26},
-       {0x0430, 0x0450,  -32}, {0x1F60, 0x1F68,   8}, {0xFF41, 0xFF5B, -32},
-       {0}
-       };
-
-       static const int uc_dup_table[][2] = { /* Start, End */
-       {0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC},
-       {0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB},
-       {0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5},
-       {0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9},
-       {0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95},
-       {0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9},
-       {0}
-       };
-
-       static const int uc_word_table[][2] = { /* Offset, Value */
-       {0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196},
-       {0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C},
-       {0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D},
-       {0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F},
-       {0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9},
-       {0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE},
-       {0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7},
-       {0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197},
-       {0}
-       };
-
-       int i, r;
-       ntfschar *uc;
-
-       uc = ntfs_malloc_nofs(default_upcase_len * sizeof(ntfschar));
-       if (!uc)
-               return uc;
-       memset(uc, 0, default_upcase_len * sizeof(ntfschar));
-       /* Generate the little endian Unicode upcase table used by ntfs. */
-       for (i = 0; i < default_upcase_len; i++)
-               uc[i] = cpu_to_le16(i);
-       for (r = 0; uc_run_table[r][0]; r++)
-               for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++)
-                       le16_add_cpu(&uc[i], uc_run_table[r][2]);
-       for (r = 0; uc_dup_table[r][0]; r++)
-               for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2)
-                       le16_add_cpu(&uc[i + 1], -1);
-       for (r = 0; uc_word_table[r][0]; r++)
-               uc[uc_word_table[r][0]] = cpu_to_le16(uc_word_table[r][1]);
-       return uc;
-}
diff --git a/fs/ntfs/usnjrnl.c b/fs/ntfs/usnjrnl.c
deleted file mode 100644 (file)
index 9097a0b..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * usnjrnl.h - NTFS kernel transaction log ($UsnJrnl) handling.  Part of the
- *            Linux-NTFS project.
- *
- * Copyright (c) 2005 Anton Altaparmakov
- */
-
-#ifdef NTFS_RW
-
-#include <linux/fs.h>
-#include <linux/highmem.h>
-#include <linux/mm.h>
-
-#include "aops.h"
-#include "debug.h"
-#include "endian.h"
-#include "time.h"
-#include "types.h"
-#include "usnjrnl.h"
-#include "volume.h"
-
-/**
- * ntfs_stamp_usnjrnl - stamp the transaction log ($UsnJrnl) on an ntfs volume
- * @vol:       ntfs volume on which to stamp the transaction log
- *
- * Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return
- * 'true' on success and 'false' on error.
- *
- * This function assumes that the transaction log has already been loaded and
- * consistency checked by a call to fs/ntfs/super.c::load_and_init_usnjrnl().
- */
-bool ntfs_stamp_usnjrnl(ntfs_volume *vol)
-{
-       ntfs_debug("Entering.");
-       if (likely(!NVolUsnJrnlStamped(vol))) {
-               sle64 stamp;
-               struct page *page;
-               USN_HEADER *uh;
-
-               page = ntfs_map_page(vol->usnjrnl_max_ino->i_mapping, 0);
-               if (IS_ERR(page)) {
-                       ntfs_error(vol->sb, "Failed to read from "
-                                       "$UsnJrnl/$DATA/$Max attribute.");
-                       return false;
-               }
-               uh = (USN_HEADER*)page_address(page);
-               stamp = get_current_ntfs_time();
-               ntfs_debug("Stamping transaction log ($UsnJrnl): old "
-                               "journal_id 0x%llx, old lowest_valid_usn "
-                               "0x%llx, new journal_id 0x%llx, new "
-                               "lowest_valid_usn 0x%llx.",
-                               (long long)sle64_to_cpu(uh->journal_id),
-                               (long long)sle64_to_cpu(uh->lowest_valid_usn),
-                               (long long)sle64_to_cpu(stamp),
-                               i_size_read(vol->usnjrnl_j_ino));
-               uh->lowest_valid_usn =
-                               cpu_to_sle64(i_size_read(vol->usnjrnl_j_ino));
-               uh->journal_id = stamp;
-               flush_dcache_page(page);
-               set_page_dirty(page);
-               ntfs_unmap_page(page);
-               /* Set the flag so we do not have to do it again on remount. */
-               NVolSetUsnJrnlStamped(vol);
-       }
-       ntfs_debug("Done.");
-       return true;
-}
-
-#endif /* NTFS_RW */
diff --git a/fs/ntfs/usnjrnl.h b/fs/ntfs/usnjrnl.h
deleted file mode 100644 (file)
index 85f531b..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * usnjrnl.h - Defines for NTFS kernel transaction log ($UsnJrnl) handling.
- *            Part of the Linux-NTFS project.
- *
- * Copyright (c) 2005 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_USNJRNL_H
-#define _LINUX_NTFS_USNJRNL_H
-
-#ifdef NTFS_RW
-
-#include "types.h"
-#include "endian.h"
-#include "layout.h"
-#include "volume.h"
-
-/*
- * Transaction log ($UsnJrnl) organization:
- *
- * The transaction log records whenever a file is modified in any way.  So for
- * example it will record that file "blah" was written to at a particular time
- * but not what was written.  If will record that a file was deleted or
- * created, that a file was truncated, etc.  See below for all the reason
- * codes used.
- *
- * The transaction log is in the $Extend directory which is in the root
- * directory of each volume.  If it is not present it means transaction
- * logging is disabled.  If it is present it means transaction logging is
- * either enabled or in the process of being disabled in which case we can
- * ignore it as it will go away as soon as Windows gets its hands on it.
- *
- * To determine whether the transaction logging is enabled or in the process
- * of being disabled, need to check the volume flags in the
- * $VOLUME_INFORMATION attribute in the $Volume system file (which is present
- * in the root directory and has a fixed mft record number, see layout.h).
- * If the flag VOLUME_DELETE_USN_UNDERWAY is set it means the transaction log
- * is in the process of being disabled and if this flag is clear it means the
- * transaction log is enabled.
- *
- * The transaction log consists of two parts; the $DATA/$Max attribute as well
- * as the $DATA/$J attribute.  $Max is a header describing the transaction
- * log whilst $J is the transaction log data itself as a sequence of variable
- * sized USN_RECORDs (see below for all the structures).
- *
- * We do not care about transaction logging at this point in time but we still
- * need to let windows know that the transaction log is out of date.  To do
- * this we need to stamp the transaction log.  This involves setting the
- * lowest_valid_usn field in the $DATA/$Max attribute to the usn to be used
- * for the next added USN_RECORD to the $DATA/$J attribute as well as
- * generating a new journal_id in $DATA/$Max.
- *
- * The journal_id is as of the current version (2.0) of the transaction log
- * simply the 64-bit timestamp of when the journal was either created or last
- * stamped.
- *
- * To determine the next usn there are two ways.  The first is to parse
- * $DATA/$J and to find the last USN_RECORD in it and to add its record_length
- * to its usn (which is the byte offset in the $DATA/$J attribute).  The
- * second is simply to take the data size of the attribute.  Since the usns
- * are simply byte offsets into $DATA/$J, this is exactly the next usn.  For
- * obvious reasons we use the second method as it is much simpler and faster.
- *
- * As an aside, note that to actually disable the transaction log, one would
- * need to set the VOLUME_DELETE_USN_UNDERWAY flag (see above), then go
- * through all the mft records on the volume and set the usn field in their
- * $STANDARD_INFORMATION attribute to zero.  Once that is done, one would need
- * to delete the transaction log file, i.e. \$Extent\$UsnJrnl, and finally,
- * one would need to clear the VOLUME_DELETE_USN_UNDERWAY flag.
- *
- * Note that if a volume is unmounted whilst the transaction log is being
- * disabled, the process will continue the next time the volume is mounted.
- * This is why we can safely mount read-write when we see a transaction log
- * in the process of being deleted.
- */
-
-/* Some $UsnJrnl related constants. */
-#define UsnJrnlMajorVer                2
-#define UsnJrnlMinorVer                0
-
-/*
- * $DATA/$Max attribute.  This is (always?) resident and has a fixed size of
- * 32 bytes.  It contains the header describing the transaction log.
- */
-typedef struct {
-/*Ofs*/
-/*   0*/sle64 maximum_size;    /* The maximum on-disk size of the $DATA/$J
-                                  attribute. */
-/*   8*/sle64 allocation_delta;        /* Number of bytes by which to increase the
-                                  size of the $DATA/$J attribute. */
-/*0x10*/sle64 journal_id;      /* Current id of the transaction log. */
-/*0x18*/leUSN lowest_valid_usn;        /* Lowest valid usn in $DATA/$J for the
-                                  current journal_id. */
-/* sizeof() = 32 (0x20) bytes */
-} __attribute__ ((__packed__)) USN_HEADER;
-
-/*
- * Reason flags (32-bit).  Cumulative flags describing the change(s) to the
- * file since it was last opened.  I think the names speak for themselves but
- * if you disagree check out the descriptions in the Linux NTFS project NTFS
- * documentation: http://www.linux-ntfs.org/
- */
-enum {
-       USN_REASON_DATA_OVERWRITE       = cpu_to_le32(0x00000001),
-       USN_REASON_DATA_EXTEND          = cpu_to_le32(0x00000002),
-       USN_REASON_DATA_TRUNCATION      = cpu_to_le32(0x00000004),
-       USN_REASON_NAMED_DATA_OVERWRITE = cpu_to_le32(0x00000010),
-       USN_REASON_NAMED_DATA_EXTEND    = cpu_to_le32(0x00000020),
-       USN_REASON_NAMED_DATA_TRUNCATION= cpu_to_le32(0x00000040),
-       USN_REASON_FILE_CREATE          = cpu_to_le32(0x00000100),
-       USN_REASON_FILE_DELETE          = cpu_to_le32(0x00000200),
-       USN_REASON_EA_CHANGE            = cpu_to_le32(0x00000400),
-       USN_REASON_SECURITY_CHANGE      = cpu_to_le32(0x00000800),
-       USN_REASON_RENAME_OLD_NAME      = cpu_to_le32(0x00001000),
-       USN_REASON_RENAME_NEW_NAME      = cpu_to_le32(0x00002000),
-       USN_REASON_INDEXABLE_CHANGE     = cpu_to_le32(0x00004000),
-       USN_REASON_BASIC_INFO_CHANGE    = cpu_to_le32(0x00008000),
-       USN_REASON_HARD_LINK_CHANGE     = cpu_to_le32(0x00010000),
-       USN_REASON_COMPRESSION_CHANGE   = cpu_to_le32(0x00020000),
-       USN_REASON_ENCRYPTION_CHANGE    = cpu_to_le32(0x00040000),
-       USN_REASON_OBJECT_ID_CHANGE     = cpu_to_le32(0x00080000),
-       USN_REASON_REPARSE_POINT_CHANGE = cpu_to_le32(0x00100000),
-       USN_REASON_STREAM_CHANGE        = cpu_to_le32(0x00200000),
-       USN_REASON_CLOSE                = cpu_to_le32(0x80000000),
-};
-
-typedef le32 USN_REASON_FLAGS;
-
-/*
- * Source info flags (32-bit).  Information about the source of the change(s)
- * to the file.  For detailed descriptions of what these mean, see the Linux
- * NTFS project NTFS documentation:
- *     http://www.linux-ntfs.org/
- */
-enum {
-       USN_SOURCE_DATA_MANAGEMENT        = cpu_to_le32(0x00000001),
-       USN_SOURCE_AUXILIARY_DATA         = cpu_to_le32(0x00000002),
-       USN_SOURCE_REPLICATION_MANAGEMENT = cpu_to_le32(0x00000004),
-};
-
-typedef le32 USN_SOURCE_INFO_FLAGS;
-
-/*
- * $DATA/$J attribute.  This is always non-resident, is marked as sparse, and
- * is of variabled size.  It consists of a sequence of variable size
- * USN_RECORDS.  The minimum allocated_size is allocation_delta as
- * specified in $DATA/$Max.  When the maximum_size specified in $DATA/$Max is
- * exceeded by more than allocation_delta bytes, allocation_delta bytes are
- * allocated and appended to the $DATA/$J attribute and an equal number of
- * bytes at the beginning of the attribute are freed and made sparse.  Note the
- * making sparse only happens at volume checkpoints and hence the actual
- * $DATA/$J size can exceed maximum_size + allocation_delta temporarily.
- */
-typedef struct {
-/*Ofs*/
-/*   0*/le32 length;           /* Byte size of this record (8-byte
-                                  aligned). */
-/*   4*/le16 major_ver;                /* Major version of the transaction log used
-                                  for this record. */
-/*   6*/le16 minor_ver;                /* Minor version of the transaction log used
-                                  for this record. */
-/*   8*/leMFT_REF mft_reference;/* The mft reference of the file (or
-                                  directory) described by this record. */
-/*0x10*/leMFT_REF parent_directory;/* The mft reference of the parent
-                                  directory of the file described by this
-                                  record. */
-/*0x18*/leUSN usn;             /* The usn of this record.  Equals the offset
-                                  within the $DATA/$J attribute. */
-/*0x20*/sle64 time;            /* Time when this record was created. */
-/*0x28*/USN_REASON_FLAGS reason;/* Reason flags (see above). */
-/*0x2c*/USN_SOURCE_INFO_FLAGS source_info;/* Source info flags (see above). */
-/*0x30*/le32 security_id;      /* File security_id copied from
-                                  $STANDARD_INFORMATION. */
-/*0x34*/FILE_ATTR_FLAGS file_attributes;       /* File attributes copied from
-                                  $STANDARD_INFORMATION or $FILE_NAME (not
-                                  sure which). */
-/*0x38*/le16 file_name_size;   /* Size of the file name in bytes. */
-/*0x3a*/le16 file_name_offset; /* Offset to the file name in bytes from the
-                                  start of this record. */
-/*0x3c*/ntfschar file_name[0]; /* Use when creating only.  When reading use
-                                  file_name_offset to determine the location
-                                  of the name. */
-/* sizeof() = 60 (0x3c) bytes */
-} __attribute__ ((__packed__)) USN_RECORD;
-
-extern bool ntfs_stamp_usnjrnl(ntfs_volume *vol);
-
-#endif /* NTFS_RW */
-
-#endif /* _LINUX_NTFS_USNJRNL_H */
diff --git a/fs/ntfs/volume.h b/fs/ntfs/volume.h
deleted file mode 100644 (file)
index 930a9ae..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * volume.h - Defines for volume structures in NTFS Linux kernel driver. Part
- *           of the Linux-NTFS project.
- *
- * Copyright (c) 2001-2006 Anton Altaparmakov
- * Copyright (c) 2002 Richard Russon
- */
-
-#ifndef _LINUX_NTFS_VOLUME_H
-#define _LINUX_NTFS_VOLUME_H
-
-#include <linux/rwsem.h>
-#include <linux/uidgid.h>
-
-#include "types.h"
-#include "layout.h"
-
-/*
- * The NTFS in memory super block structure.
- */
-typedef struct {
-       /*
-        * FIXME: Reorder to have commonly used together element within the
-        * same cache line, aiming at a cache line size of 32 bytes. Aim for
-        * 64 bytes for less commonly used together elements. Put most commonly
-        * used elements to front of structure. Obviously do this only when the
-        * structure has stabilized... (AIA)
-        */
-       /* Device specifics. */
-       struct super_block *sb;         /* Pointer back to the super_block. */
-       LCN nr_blocks;                  /* Number of sb->s_blocksize bytes
-                                          sized blocks on the device. */
-       /* Configuration provided by user at mount time. */
-       unsigned long flags;            /* Miscellaneous flags, see below. */
-       kuid_t uid;                     /* uid that files will be mounted as. */
-       kgid_t gid;                     /* gid that files will be mounted as. */
-       umode_t fmask;                  /* The mask for file permissions. */
-       umode_t dmask;                  /* The mask for directory
-                                          permissions. */
-       u8 mft_zone_multiplier;         /* Initial mft zone multiplier. */
-       u8 on_errors;                   /* What to do on filesystem errors. */
-       /* NTFS bootsector provided information. */
-       u16 sector_size;                /* in bytes */
-       u8 sector_size_bits;            /* log2(sector_size) */
-       u32 cluster_size;               /* in bytes */
-       u32 cluster_size_mask;          /* cluster_size - 1 */
-       u8 cluster_size_bits;           /* log2(cluster_size) */
-       u32 mft_record_size;            /* in bytes */
-       u32 mft_record_size_mask;       /* mft_record_size - 1 */
-       u8 mft_record_size_bits;        /* log2(mft_record_size) */
-       u32 index_record_size;          /* in bytes */
-       u32 index_record_size_mask;     /* index_record_size - 1 */
-       u8 index_record_size_bits;      /* log2(index_record_size) */
-       LCN nr_clusters;                /* Volume size in clusters == number of
-                                          bits in lcn bitmap. */
-       LCN mft_lcn;                    /* Cluster location of mft data. */
-       LCN mftmirr_lcn;                /* Cluster location of copy of mft. */
-       u64 serial_no;                  /* The volume serial number. */
-       /* Mount specific NTFS information. */
-       u32 upcase_len;                 /* Number of entries in upcase[]. */
-       ntfschar *upcase;               /* The upcase table. */
-
-       s32 attrdef_size;               /* Size of the attribute definition
-                                          table in bytes. */
-       ATTR_DEF *attrdef;              /* Table of attribute definitions.
-                                          Obtained from FILE_AttrDef. */
-
-#ifdef NTFS_RW
-       /* Variables used by the cluster and mft allocators. */
-       s64 mft_data_pos;               /* Mft record number at which to
-                                          allocate the next mft record. */
-       LCN mft_zone_start;             /* First cluster of the mft zone. */
-       LCN mft_zone_end;               /* First cluster beyond the mft zone. */
-       LCN mft_zone_pos;               /* Current position in the mft zone. */
-       LCN data1_zone_pos;             /* Current position in the first data
-                                          zone. */
-       LCN data2_zone_pos;             /* Current position in the second data
-                                          zone. */
-#endif /* NTFS_RW */
-
-       struct inode *mft_ino;          /* The VFS inode of $MFT. */
-
-       struct inode *mftbmp_ino;       /* Attribute inode for $MFT/$BITMAP. */
-       struct rw_semaphore mftbmp_lock; /* Lock for serializing accesses to the
-                                           mft record bitmap ($MFT/$BITMAP). */
-#ifdef NTFS_RW
-       struct inode *mftmirr_ino;      /* The VFS inode of $MFTMirr. */
-       int mftmirr_size;               /* Size of mft mirror in mft records. */
-
-       struct inode *logfile_ino;      /* The VFS inode of $LogFile. */
-#endif /* NTFS_RW */
-
-       struct inode *lcnbmp_ino;       /* The VFS inode of $Bitmap. */
-       struct rw_semaphore lcnbmp_lock; /* Lock for serializing accesses to the
-                                           cluster bitmap ($Bitmap/$DATA). */
-
-       struct inode *vol_ino;          /* The VFS inode of $Volume. */
-       VOLUME_FLAGS vol_flags;         /* Volume flags. */
-       u8 major_ver;                   /* Ntfs major version of volume. */
-       u8 minor_ver;                   /* Ntfs minor version of volume. */
-
-       struct inode *root_ino;         /* The VFS inode of the root
-                                          directory. */
-       struct inode *secure_ino;       /* The VFS inode of $Secure (NTFS3.0+
-                                          only, otherwise NULL). */
-       struct inode *extend_ino;       /* The VFS inode of $Extend (NTFS3.0+
-                                          only, otherwise NULL). */
-#ifdef NTFS_RW
-       /* $Quota stuff is NTFS3.0+ specific.  Unused/NULL otherwise. */
-       struct inode *quota_ino;        /* The VFS inode of $Quota. */
-       struct inode *quota_q_ino;      /* Attribute inode for $Quota/$Q. */
-       /* $UsnJrnl stuff is NTFS3.0+ specific.  Unused/NULL otherwise. */
-       struct inode *usnjrnl_ino;      /* The VFS inode of $UsnJrnl. */
-       struct inode *usnjrnl_max_ino;  /* Attribute inode for $UsnJrnl/$Max. */
-       struct inode *usnjrnl_j_ino;    /* Attribute inode for $UsnJrnl/$J. */
-#endif /* NTFS_RW */
-       struct nls_table *nls_map;
-} ntfs_volume;
-
-/*
- * Defined bits for the flags field in the ntfs_volume structure.
- */
-typedef enum {
-       NV_Errors,              /* 1: Volume has errors, prevent remount rw. */
-       NV_ShowSystemFiles,     /* 1: Return system files in ntfs_readdir(). */
-       NV_CaseSensitive,       /* 1: Treat file names as case sensitive and
-                                     create filenames in the POSIX namespace.
-                                     Otherwise be case insensitive but still
-                                     create file names in POSIX namespace. */
-       NV_LogFileEmpty,        /* 1: $LogFile journal is empty. */
-       NV_QuotaOutOfDate,      /* 1: $Quota is out of date. */
-       NV_UsnJrnlStamped,      /* 1: $UsnJrnl has been stamped. */
-       NV_SparseEnabled,       /* 1: May create sparse files. */
-} ntfs_volume_flags;
-
-/*
- * Macro tricks to expand the NVolFoo(), NVolSetFoo(), and NVolClearFoo()
- * functions.
- */
-#define DEFINE_NVOL_BIT_OPS(flag)                                      \
-static inline int NVol##flag(ntfs_volume *vol)         \
-{                                                      \
-       return test_bit(NV_##flag, &(vol)->flags);      \
-}                                                      \
-static inline void NVolSet##flag(ntfs_volume *vol)     \
-{                                                      \
-       set_bit(NV_##flag, &(vol)->flags);              \
-}                                                      \
-static inline void NVolClear##flag(ntfs_volume *vol)   \
-{                                                      \
-       clear_bit(NV_##flag, &(vol)->flags);            \
-}
-
-/* Emit the ntfs volume bitops functions. */
-DEFINE_NVOL_BIT_OPS(Errors)
-DEFINE_NVOL_BIT_OPS(ShowSystemFiles)
-DEFINE_NVOL_BIT_OPS(CaseSensitive)
-DEFINE_NVOL_BIT_OPS(LogFileEmpty)
-DEFINE_NVOL_BIT_OPS(QuotaOutOfDate)
-DEFINE_NVOL_BIT_OPS(UsnJrnlStamped)
-DEFINE_NVOL_BIT_OPS(SparseEnabled)
-
-#endif /* _LINUX_NTFS_VOLUME_H */
index 3b42938a9d3b229b0bbf1eef9a80f83da5111113..7f27382e0ce25bcb2c660fa799cf8295a9cf486b 100644 (file)
@@ -2457,7 +2457,6 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
        struct ATTR_LIST_ENTRY *le = NULL;
        struct runs_tree *run = &ni->file.run;
        u64 valid_size = ni->i_valid;
-       loff_t i_size = i_size_read(&ni->vfs_inode);
        u64 vbo_disk;
        size_t unc_size;
        u32 frame_size, i, npages_disk, ondisk_size;
@@ -2509,6 +2508,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
                err = -EOPNOTSUPP;
                goto out1;
 #else
+               loff_t i_size = i_size_read(&ni->vfs_inode);
                u32 frame_bits = ni_ext_compress_bits(ni);
                u64 frame64 = frame_vbo >> frame_bits;
                u64 frames, vbo_data;
index cae41db0aaa7d13e1fb4e0132b79261156a39306..084d19d78397c9b6108b36b9730c59a806a66534 100644 (file)
@@ -431,7 +431,7 @@ static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry,
         * fnd contains tree's path to insert to.
         * If fnd is not NULL then dir is locked.
         */
-       inode = ntfs_create_inode(mnt_idmap(file->f_path.mnt), dir, dentry, uni,
+       inode = ntfs_create_inode(file_mnt_idmap(file), dir, dentry, uni,
                                  mode, 0, NULL, 0, fnd);
        err = IS_ERR(inode) ? PTR_ERR(inode) :
                              finish_open(file, dentry, ntfs_file_open);
index 4d7efefa98c5ec3da43a554f1e9685e8e6b75e7e..1bde1281d5146d3d99e3b97c10cb7c6a3ad41b0f 100644 (file)
@@ -213,7 +213,7 @@ struct o2hb_region {
        unsigned int            hr_num_pages;
 
        struct page             **hr_slot_data;
-       struct bdev_handle      *hr_bdev_handle;
+       struct file             *hr_bdev_file;
        struct o2hb_disk_slot   *hr_slots;
 
        /* live node map of this region */
@@ -263,7 +263,7 @@ struct o2hb_region {
 
 static inline struct block_device *reg_bdev(struct o2hb_region *reg)
 {
-       return reg->hr_bdev_handle ? reg->hr_bdev_handle->bdev : NULL;
+       return reg->hr_bdev_file ? file_bdev(reg->hr_bdev_file) : NULL;
 }
 
 struct o2hb_bio_wait_ctxt {
@@ -1509,8 +1509,8 @@ static void o2hb_region_release(struct config_item *item)
                kfree(reg->hr_slot_data);
        }
 
-       if (reg->hr_bdev_handle)
-               bdev_release(reg->hr_bdev_handle);
+       if (reg->hr_bdev_file)
+               fput(reg->hr_bdev_file);
 
        kfree(reg->hr_slots);
 
@@ -1569,7 +1569,7 @@ static ssize_t o2hb_region_block_bytes_store(struct config_item *item,
        unsigned long block_bytes;
        unsigned int block_bits;
 
-       if (reg->hr_bdev_handle)
+       if (reg->hr_bdev_file)
                return -EINVAL;
 
        status = o2hb_read_block_input(reg, page, &block_bytes,
@@ -1598,7 +1598,7 @@ static ssize_t o2hb_region_start_block_store(struct config_item *item,
        char *p = (char *)page;
        ssize_t ret;
 
-       if (reg->hr_bdev_handle)
+       if (reg->hr_bdev_file)
                return -EINVAL;
 
        ret = kstrtoull(p, 0, &tmp);
@@ -1623,7 +1623,7 @@ static ssize_t o2hb_region_blocks_store(struct config_item *item,
        unsigned long tmp;
        char *p = (char *)page;
 
-       if (reg->hr_bdev_handle)
+       if (reg->hr_bdev_file)
                return -EINVAL;
 
        tmp = simple_strtoul(p, &p, 0);
@@ -1642,7 +1642,7 @@ static ssize_t o2hb_region_dev_show(struct config_item *item, char *page)
 {
        unsigned int ret = 0;
 
-       if (to_o2hb_region(item)->hr_bdev_handle)
+       if (to_o2hb_region(item)->hr_bdev_file)
                ret = sprintf(page, "%pg\n", reg_bdev(to_o2hb_region(item)));
 
        return ret;
@@ -1753,7 +1753,7 @@ out:
 }
 
 /*
- * this is acting as commit; we set up all of hr_bdev_handle and hr_task or
+ * this is acting as commit; we set up all of hr_bdev_file and hr_task or
  * nothing
  */
 static ssize_t o2hb_region_dev_store(struct config_item *item,
@@ -1769,7 +1769,7 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
        ssize_t ret = -EINVAL;
        int live_threshold;
 
-       if (reg->hr_bdev_handle)
+       if (reg->hr_bdev_file)
                goto out;
 
        /* We can't heartbeat without having had our node number
@@ -1795,11 +1795,11 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
        if (!S_ISBLK(f.file->f_mapping->host->i_mode))
                goto out2;
 
-       reg->hr_bdev_handle = bdev_open_by_dev(f.file->f_mapping->host->i_rdev,
+       reg->hr_bdev_file = bdev_file_open_by_dev(f.file->f_mapping->host->i_rdev,
                        BLK_OPEN_WRITE | BLK_OPEN_READ, NULL, NULL);
-       if (IS_ERR(reg->hr_bdev_handle)) {
-               ret = PTR_ERR(reg->hr_bdev_handle);
-               reg->hr_bdev_handle = NULL;
+       if (IS_ERR(reg->hr_bdev_file)) {
+               ret = PTR_ERR(reg->hr_bdev_file);
+               reg->hr_bdev_file = NULL;
                goto out2;
        }
 
@@ -1903,8 +1903,8 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
 
 out3:
        if (ret < 0) {
-               bdev_release(reg->hr_bdev_handle);
-               reg->hr_bdev_handle = NULL;
+               fput(reg->hr_bdev_file);
+               reg->hr_bdev_file = NULL;
        }
 out2:
        fdput(f);
index f37174e79fad4f377e76c04eec2a06c5f1f19f89..6de944818c569ceecc8b81a4acf49780dbb9b5b7 100644 (file)
@@ -27,7 +27,7 @@ static int ocfs2_do_flock(struct file *file, struct inode *inode,
        struct ocfs2_file_private *fp = file->private_data;
        struct ocfs2_lock_res *lockres = &fp->fp_flock;
 
-       if (fl->fl_type == F_WRLCK)
+       if (lock_is_write(fl))
                level = 1;
        if (!IS_SETLKW(cmd))
                trylock = 1;
@@ -53,8 +53,8 @@ static int ocfs2_do_flock(struct file *file, struct inode *inode,
                 */
 
                locks_init_lock(&request);
-               request.fl_type = F_UNLCK;
-               request.fl_flags = FL_FLOCK;
+               request.c.flc_type = F_UNLCK;
+               request.c.flc_flags = FL_FLOCK;
                locks_lock_file_wait(file, &request);
 
                ocfs2_file_unlock(file);
@@ -100,14 +100,14 @@ int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl)
        struct inode *inode = file->f_mapping->host;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
-       if (!(fl->fl_flags & FL_FLOCK))
+       if (!(fl->c.flc_flags & FL_FLOCK))
                return -ENOLCK;
 
        if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) ||
            ocfs2_mount_local(osb))
                return locks_lock_file_wait(file, fl);
 
-       if (fl->fl_type == F_UNLCK)
+       if (lock_is_unlock(fl))
                return ocfs2_do_funlock(file, cmd, fl);
        else
                return ocfs2_do_flock(file, inode, cmd, fl);
@@ -118,7 +118,7 @@ int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl)
        struct inode *inode = file->f_mapping->host;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
-       if (!(fl->fl_flags & FL_POSIX))
+       if (!(fl->c.flc_flags & FL_POSIX))
                return -ENOLCK;
 
        return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl);
index 9b76ee66aeb2f4f6c4d5f5728e2c303a8a440007..c11406cd87a88e5329d78a8bd252a180d810e361 100644 (file)
@@ -744,7 +744,7 @@ static int user_plock(struct ocfs2_cluster_connection *conn,
                return dlm_posix_cancel(conn->cc_lockspace, ino, file, fl);
        else if (IS_GETLK(cmd))
                return dlm_posix_get(conn->cc_lockspace, ino, file, fl);
-       else if (fl->fl_type == F_UNLCK)
+       else if (lock_is_unlock(fl))
                return dlm_posix_unlock(conn->cc_lockspace, ino, file, fl);
        else
                return dlm_posix_lock(conn->cc_lockspace, ino, file, cmd, fl);
index 6b906424902b46b9b17e1fb2102e916fcb89d1fc..a70aff17d4554af8478308dc6c2b5b5cd3122d23 100644 (file)
@@ -2027,8 +2027,8 @@ static int ocfs2_initialize_super(struct super_block *sb,
        cbits = le32_to_cpu(di->id2.i_super.s_clustersize_bits);
        bbits = le32_to_cpu(di->id2.i_super.s_blocksize_bits);
        sb->s_maxbytes = ocfs2_max_file_offset(bbits, cbits);
-       memcpy(&sb->s_uuid, di->id2.i_super.s_uuid,
-              sizeof(di->id2.i_super.s_uuid));
+       super_set_uuid(sb, di->id2.i_super.s_uuid,
+                      sizeof(di->id2.i_super.s_uuid));
 
        osb->osb_dx_mask = (1 << (cbits - bbits)) - 1;
 
index a84d21e55c391eebdf662c7fa8c9d5b2aef8efd2..a7d4bb2c725f1e9bdde176f769c3a52df0627ab9 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -154,49 +154,52 @@ COMPAT_SYSCALL_DEFINE2(truncate, const char __user *, path, compat_off_t, length
 }
 #endif
 
-long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
+long do_ftruncate(struct file *file, loff_t length, int small)
 {
        struct inode *inode;
        struct dentry *dentry;
-       struct fd f;
        int error;
 
-       error = -EINVAL;
-       if (length < 0)
-               goto out;
-       error = -EBADF;
-       f = fdget(fd);
-       if (!f.file)
-               goto out;
-
        /* explicitly opened as large or we are on 64-bit box */
-       if (f.file->f_flags & O_LARGEFILE)
+       if (file->f_flags & O_LARGEFILE)
                small = 0;
 
-       dentry = f.file->f_path.dentry;
+       dentry = file->f_path.dentry;
        inode = dentry->d_inode;
-       error = -EINVAL;
-       if (!S_ISREG(inode->i_mode) || !(f.file->f_mode & FMODE_WRITE))
-               goto out_putf;
+       if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
+               return -EINVAL;
 
-       error = -EINVAL;
        /* Cannot ftruncate over 2^31 bytes without large file support */
        if (small && length > MAX_NON_LFS)
-               goto out_putf;
+               return -EINVAL;
 
-       error = -EPERM;
        /* Check IS_APPEND on real upper inode */
-       if (IS_APPEND(file_inode(f.file)))
-               goto out_putf;
+       if (IS_APPEND(file_inode(file)))
+               return -EPERM;
        sb_start_write(inode->i_sb);
-       error = security_file_truncate(f.file);
+       error = security_file_truncate(file);
        if (!error)
-               error = do_truncate(file_mnt_idmap(f.file), dentry, length,
-                                   ATTR_MTIME | ATTR_CTIME, f.file);
+               error = do_truncate(file_mnt_idmap(file), dentry, length,
+                                   ATTR_MTIME | ATTR_CTIME, file);
        sb_end_write(inode->i_sb);
-out_putf:
+
+       return error;
+}
+
+long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
+{
+       struct fd f;
+       int error;
+
+       if (length < 0)
+               return -EINVAL;
+       f = fdget(fd);
+       if (!f.file)
+               return -EBADF;
+
+       error = do_ftruncate(f.file, length, small);
+
        fdput(f);
-out:
        return error;
 }
 
@@ -1364,7 +1367,7 @@ struct file *filp_open(const char *filename, int flags, umode_t mode)
 {
        struct filename *name = getname_kernel(filename);
        struct file *file = ERR_CAST(name);
-       
+
        if (!IS_ERR(name)) {
                file = file_open_name(name, flags, mode);
                putname(name);
index c4b65a6d41cc345c83e4729d3f9a76cad66391e3..4a0779e3ef792334904f18bfc5b5c791a7141768 100644 (file)
@@ -446,7 +446,7 @@ static int __init init_openprom_fs(void)
                                            sizeof(struct op_inode_info),
                                            0,
                                            (SLAB_RECLAIM_ACCOUNT |
-                                            SLAB_MEM_SPREAD | SLAB_ACCOUNT),
+                                            SLAB_ACCOUNT),
                                            op_inode_init_once);
        if (!op_inode_cachep)
                return -ENOMEM;
index b8e25ca51016d9df648ca58495baa9db553330ec..8586e2f5d24390c91263ea1ee48e7c3b22199cd2 100644 (file)
@@ -265,20 +265,18 @@ static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
        if (IS_ERR(old_file))
                return PTR_ERR(old_file);
 
+       /* Try to use clone_file_range to clone up within the same fs */
+       cloned = vfs_clone_file_range(old_file, 0, new_file, 0, len, 0);
+       if (cloned == len)
+               goto out_fput;
+
+       /* Couldn't clone, so now we try to copy the data */
        error = rw_verify_area(READ, old_file, &old_pos, len);
        if (!error)
                error = rw_verify_area(WRITE, new_file, &new_pos, len);
        if (error)
                goto out_fput;
 
-       /* Try to use clone_file_range to clone up within the same fs */
-       ovl_start_write(dentry);
-       cloned = do_clone_file_range(old_file, 0, new_file, 0, len, 0);
-       ovl_end_write(dentry);
-       if (cloned == len)
-               goto out_fput;
-       /* Couldn't clone, so now we try to copy the data */
-
        /* Check if lower fs supports seek operation */
        if (old_file->f_mode & FMODE_LSEEK)
                skip_hole = true;
index 112b4b12f8252affb5267cc4a908cb63d9bdd3c2..36dcc530ac286b0102e228acebdf03a5951fa57b 100644 (file)
@@ -280,12 +280,20 @@ static int ovl_mount_dir_check(struct fs_context *fc, const struct path *path,
 {
        struct ovl_fs_context *ctx = fc->fs_private;
 
-       if (ovl_dentry_weird(path->dentry))
-               return invalfc(fc, "filesystem on %s not supported", name);
-
        if (!d_is_dir(path->dentry))
                return invalfc(fc, "%s is not a directory", name);
 
+       /*
+        * Root dentries of case-insensitive capable filesystems might
+        * not have the dentry operations set, but still be incompatible
+        * with overlayfs.  Check explicitly to prevent post-mount
+        * failures.
+        */
+       if (sb_has_encoding(path->mnt->mnt_sb))
+               return invalfc(fc, "case-insensitive capable filesystem on %s not supported", name);
+
+       if (ovl_dentry_weird(path->dentry))
+               return invalfc(fc, "filesystem on %s not supported", name);
 
        /*
         * Check whether upper path is read-only here to report failures
index 2eef6c70b2aed54027b9ec2b1b544101ea32aefc..36d4b8b1f784462dffe665fb83f7a756eeba3262 100644 (file)
@@ -28,41 +28,38 @@ MODULE_LICENSE("GPL");
 
 struct ovl_dir_cache;
 
-static struct dentry *ovl_d_real(struct dentry *dentry,
-                                const struct inode *inode)
+static struct dentry *ovl_d_real(struct dentry *dentry, enum d_real_type type)
 {
-       struct dentry *real = NULL, *lower;
+       struct dentry *upper, *lower;
        int err;
 
-       /*
-        * vfs is only expected to call d_real() with NULL from d_real_inode()
-        * and with overlay inode from file_dentry() on an overlay file.
-        *
-        * TODO: remove @inode argument from d_real() API, remove code in this
-        * function that deals with non-NULL @inode and remove d_real() call
-        * from file_dentry().
-        */
-       if (inode && d_inode(dentry) == inode)
-               return dentry;
-       else if (inode)
+       switch (type) {
+       case D_REAL_DATA:
+       case D_REAL_METADATA:
+               break;
+       default:
                goto bug;
+       }
 
        if (!d_is_reg(dentry)) {
                /* d_real_inode() is only relevant for regular files */
                return dentry;
        }
 
-       real = ovl_dentry_upper(dentry);
-       if (real && (inode == d_inode(real)))
-               return real;
+       upper = ovl_dentry_upper(dentry);
+       if (upper && (type == D_REAL_METADATA ||
+                     ovl_has_upperdata(d_inode(dentry))))
+               return upper;
 
-       if (real && !inode && ovl_has_upperdata(d_inode(dentry)))
-               return real;
+       if (type == D_REAL_METADATA) {
+               lower = ovl_dentry_lower(dentry);
+               goto real_lower;
+       }
 
        /*
-        * Best effort lazy lookup of lowerdata for !inode case to return
+        * Best effort lazy lookup of lowerdata for D_REAL_DATA case to return
         * the real lowerdata dentry.  The only current caller of d_real() with
-        * NULL inode is d_real_inode() from trace_uprobe and this caller is
+        * D_REAL_DATA is d_real_inode() from trace_uprobe and this caller is
         * likely going to be followed reading from the file, before placing
         * uprobes on offset within the file, so lowerdata should be available
         * when setting the uprobe.
@@ -73,18 +70,13 @@ static struct dentry *ovl_d_real(struct dentry *dentry,
        lower = ovl_dentry_lowerdata(dentry);
        if (!lower)
                goto bug;
-       real = lower;
 
-       /* Handle recursion */
-       real = d_real(real, inode);
+real_lower:
+       /* Handle recursion into stacked lower fs */
+       return d_real(lower, type);
 
-       if (!inode || inode == d_inode(real))
-               return real;
 bug:
-       WARN(1, "%s(%pd4, %s:%lu): real dentry (%p/%lu) not found\n",
-            __func__, dentry, inode ? inode->i_sb->s_id : "NULL",
-            inode ? inode->i_ino : 0, real,
-            real && d_inode(real) ? d_inode(real)->i_ino : 0);
+       WARN(1, "%s(%pd4, %d): real dentry not found\n", __func__, dentry, type);
        return dentry;
 }
 
index a8e17f14d7a219aafada9e174ef50c6f67f56ff7..d285d1d7baaddedf6fc938ac8aaf8dc35e74d7d7 100644 (file)
@@ -774,13 +774,14 @@ bool ovl_init_uuid_xattr(struct super_block *sb, struct ovl_fs *ofs,
                         const struct path *upperpath)
 {
        bool set = false;
+       uuid_t uuid;
        int res;
 
        /* Try to load existing persistent uuid */
-       res = ovl_path_getxattr(ofs, upperpath, OVL_XATTR_UUID, sb->s_uuid.b,
+       res = ovl_path_getxattr(ofs, upperpath, OVL_XATTR_UUID, uuid.b,
                                UUID_SIZE);
        if (res == UUID_SIZE)
-               return true;
+               goto set_uuid;
 
        if (res != -ENODATA)
                goto fail;
@@ -808,17 +809,20 @@ bool ovl_init_uuid_xattr(struct super_block *sb, struct ovl_fs *ofs,
        }
 
        /* Generate overlay instance uuid */
-       uuid_gen(&sb->s_uuid);
+       uuid_gen(&uuid);
 
        /* Try to store persistent uuid */
        set = true;
-       res = ovl_setxattr(ofs, upperpath->dentry, OVL_XATTR_UUID, sb->s_uuid.b,
+       res = ovl_setxattr(ofs, upperpath->dentry, OVL_XATTR_UUID, uuid.b,
                           UUID_SIZE);
-       if (res == 0)
-               return true;
+       if (res)
+               goto fail;
+
+set_uuid:
+       super_set_uuid(sb, uuid.b, sizeof(uuid));
+       return true;
 
 fail:
-       memset(sb->s_uuid.b, 0, UUID_SIZE);
        ofs->config.uuid = OVL_UUID_NULL;
        pr_warn("failed to %s uuid (%pd2, err=%i); falling back to uuid=null.\n",
                set ? "set" : "get", upperpath->dentry, res);
diff --git a/fs/pidfs.c b/fs/pidfs.c
new file mode 100644 (file)
index 0000000..8fd71a0
--- /dev/null
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/anon_inodes.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/magic.h>
+#include <linux/mount.h>
+#include <linux/pid.h>
+#include <linux/pidfs.h>
+#include <linux/pid_namespace.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/proc_ns.h>
+#include <linux/pseudo_fs.h>
+#include <linux/seq_file.h>
+#include <uapi/linux/pidfd.h>
+
+#include "internal.h"
+
+static int pidfd_release(struct inode *inode, struct file *file)
+{
+#ifndef CONFIG_FS_PID
+       struct pid *pid = file->private_data;
+
+       file->private_data = NULL;
+       put_pid(pid);
+#endif
+       return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+/**
+ * pidfd_show_fdinfo - print information about a pidfd
+ * @m: proc fdinfo file
+ * @f: file referencing a pidfd
+ *
+ * Pid:
+ * This function will print the pid that a given pidfd refers to in the
+ * pid namespace of the procfs instance.
+ * If the pid namespace of the process is not a descendant of the pid
+ * namespace of the procfs instance 0 will be shown as its pid. This is
+ * similar to calling getppid() on a process whose parent is outside of
+ * its pid namespace.
+ *
+ * NSpid:
+ * If pid namespaces are supported then this function will also print
+ * the pid of a given pidfd refers to for all descendant pid namespaces
+ * starting from the current pid namespace of the instance, i.e. the
+ * Pid field and the first entry in the NSpid field will be identical.
+ * If the pid namespace of the process is not a descendant of the pid
+ * namespace of the procfs instance 0 will be shown as its first NSpid
+ * entry and no others will be shown.
+ * Note that this differs from the Pid and NSpid fields in
+ * /proc/<pid>/status where Pid and NSpid are always shown relative to
+ * the  pid namespace of the procfs instance. The difference becomes
+ * obvious when sending around a pidfd between pid namespaces from a
+ * different branch of the tree, i.e. where no ancestral relation is
+ * present between the pid namespaces:
+ * - create two new pid namespaces ns1 and ns2 in the initial pid
+ *   namespace (also take care to create new mount namespaces in the
+ *   new pid namespace and mount procfs)
+ * - create a process with a pidfd in ns1
+ * - send pidfd from ns1 to ns2
+ * - read /proc/self/fdinfo/<pidfd> and observe that both Pid and NSpid
+ *   have exactly one entry, which is 0
+ */
+static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
+{
+       struct pid *pid = pidfd_pid(f);
+       struct pid_namespace *ns;
+       pid_t nr = -1;
+
+       if (likely(pid_has_task(pid, PIDTYPE_PID))) {
+               ns = proc_pid_ns(file_inode(m->file)->i_sb);
+               nr = pid_nr_ns(pid, ns);
+       }
+
+       seq_put_decimal_ll(m, "Pid:\t", nr);
+
+#ifdef CONFIG_PID_NS
+       seq_put_decimal_ll(m, "\nNSpid:\t", nr);
+       if (nr > 0) {
+               int i;
+
+               /* If nr is non-zero it means that 'pid' is valid and that
+                * ns, i.e. the pid namespace associated with the procfs
+                * instance, is in the pid namespace hierarchy of pid.
+                * Start at one below the already printed level.
+                */
+               for (i = ns->level + 1; i <= pid->level; i++)
+                       seq_put_decimal_ll(m, "\t", pid->numbers[i].nr);
+       }
+#endif
+       seq_putc(m, '\n');
+}
+#endif
+
+/*
+ * Poll support for process exit notification.
+ */
+static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts)
+{
+       struct pid *pid = pidfd_pid(file);
+       bool thread = file->f_flags & PIDFD_THREAD;
+       struct task_struct *task;
+       __poll_t poll_flags = 0;
+
+       poll_wait(file, &pid->wait_pidfd, pts);
+       /*
+        * Depending on PIDFD_THREAD, inform pollers when the thread
+        * or the whole thread-group exits.
+        */
+       guard(rcu)();
+       task = pid_task(pid, PIDTYPE_PID);
+       if (!task)
+               poll_flags = EPOLLIN | EPOLLRDNORM | EPOLLHUP;
+       else if (task->exit_state && (thread || thread_group_empty(task)))
+               poll_flags = EPOLLIN | EPOLLRDNORM;
+
+       return poll_flags;
+}
+
+static const struct file_operations pidfs_file_operations = {
+       .release        = pidfd_release,
+       .poll           = pidfd_poll,
+#ifdef CONFIG_PROC_FS
+       .show_fdinfo    = pidfd_show_fdinfo,
+#endif
+};
+
+struct pid *pidfd_pid(const struct file *file)
+{
+       if (file->f_op != &pidfs_file_operations)
+               return ERR_PTR(-EBADF);
+#ifdef CONFIG_FS_PID
+       return file_inode(file)->i_private;
+#else
+       return file->private_data;
+#endif
+}
+
+#ifdef CONFIG_FS_PID
+static struct vfsmount *pidfs_mnt __ro_after_init;
+
+/*
+ * The vfs falls back to simple_setattr() if i_op->setattr() isn't
+ * implemented. Let's reject it completely until we have a clean
+ * permission concept for pidfds.
+ */
+static int pidfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+                        struct iattr *attr)
+{
+       return -EOPNOTSUPP;
+}
+
+static int pidfs_getattr(struct mnt_idmap *idmap, const struct path *path,
+                        struct kstat *stat, u32 request_mask,
+                        unsigned int query_flags)
+{
+       struct inode *inode = d_inode(path->dentry);
+
+       generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
+       return 0;
+}
+
+static const struct inode_operations pidfs_inode_operations = {
+       .getattr = pidfs_getattr,
+       .setattr = pidfs_setattr,
+};
+
+static void pidfs_evict_inode(struct inode *inode)
+{
+       struct pid *pid = inode->i_private;
+
+       clear_inode(inode);
+       put_pid(pid);
+}
+
+static const struct super_operations pidfs_sops = {
+       .drop_inode     = generic_delete_inode,
+       .evict_inode    = pidfs_evict_inode,
+       .statfs         = simple_statfs,
+};
+
+static char *pidfs_dname(struct dentry *dentry, char *buffer, int buflen)
+{
+       return dynamic_dname(buffer, buflen, "pidfd:[%lu]",
+                            d_inode(dentry)->i_ino);
+}
+
+static const struct dentry_operations pidfs_dentry_operations = {
+       .d_delete       = always_delete_dentry,
+       .d_dname        = pidfs_dname,
+       .d_prune        = stashed_dentry_prune,
+};
+
+static void pidfs_init_inode(struct inode *inode, void *data)
+{
+       inode->i_private = data;
+       inode->i_flags |= S_PRIVATE;
+       inode->i_mode |= S_IRWXU;
+       inode->i_op = &pidfs_inode_operations;
+       inode->i_fop = &pidfs_file_operations;
+}
+
+static void pidfs_put_data(void *data)
+{
+       struct pid *pid = data;
+       put_pid(pid);
+}
+
+static const struct stashed_operations pidfs_stashed_ops = {
+       .init_inode = pidfs_init_inode,
+       .put_data = pidfs_put_data,
+};
+
+static int pidfs_init_fs_context(struct fs_context *fc)
+{
+       struct pseudo_fs_context *ctx;
+
+       ctx = init_pseudo(fc, PID_FS_MAGIC);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->ops = &pidfs_sops;
+       ctx->dops = &pidfs_dentry_operations;
+       fc->s_fs_info = (void *)&pidfs_stashed_ops;
+       return 0;
+}
+
+static struct file_system_type pidfs_type = {
+       .name                   = "pidfs",
+       .init_fs_context        = pidfs_init_fs_context,
+       .kill_sb                = kill_anon_super,
+};
+
+struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags)
+{
+
+       struct file *pidfd_file;
+       struct path path;
+       int ret;
+
+       /*
+       * Inode numbering for pidfs start at RESERVED_PIDS + 1.
+       * This avoids collisions with the root inode which is 1
+       * for pseudo filesystems.
+        */
+       ret = path_from_stashed(&pid->stashed, pid->ino, pidfs_mnt,
+                               get_pid(pid), &path);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       pidfd_file = dentry_open(&path, flags, current_cred());
+       path_put(&path);
+       return pidfd_file;
+}
+
+void __init pidfs_init(void)
+{
+       pidfs_mnt = kern_mount(&pidfs_type);
+       if (IS_ERR(pidfs_mnt))
+               panic("Failed to mount pidfs pseudo filesystem");
+}
+
+bool is_pidfs_sb(const struct super_block *sb)
+{
+       return sb == pidfs_mnt->mnt_sb;
+}
+
+#else /* !CONFIG_FS_PID */
+
+struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags)
+{
+       struct file *pidfd_file;
+
+       pidfd_file = anon_inode_getfile("[pidfd]", &pidfs_file_operations, pid,
+                                       flags | O_RDWR);
+       if (IS_ERR(pidfd_file))
+               return pidfd_file;
+
+       get_pid(pid);
+       return pidfd_file;
+}
+
+void __init pidfs_init(void) { }
+bool is_pidfs_sb(const struct super_block *sb)
+{
+       return false;
+}
+#endif
index f1adbfe743d4a7cce8c6270963f5ba45357964cd..50c8a8596b5245f90f43701ab039e1daa851d009 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -76,18 +76,20 @@ static unsigned long pipe_user_pages_soft = PIPE_DEF_BUFFERS * INR_OPEN_CUR;
  * -- Manfred Spraul <manfred@colorfullife.com> 2002-05-09
  */
 
-static void pipe_lock_nested(struct pipe_inode_info *pipe, int subclass)
+#define cmp_int(l, r)          ((l > r) - (l < r))
+
+#ifdef CONFIG_PROVE_LOCKING
+static int pipe_lock_cmp_fn(const struct lockdep_map *a,
+                           const struct lockdep_map *b)
 {
-       if (pipe->files)
-               mutex_lock_nested(&pipe->mutex, subclass);
+       return cmp_int((unsigned long) a, (unsigned long) b);
 }
+#endif
 
 void pipe_lock(struct pipe_inode_info *pipe)
 {
-       /*
-        * pipe_lock() nests non-pipe inode locks (for writing to a file)
-        */
-       pipe_lock_nested(pipe, I_MUTEX_PARENT);
+       if (pipe->files)
+               mutex_lock(&pipe->mutex);
 }
 EXPORT_SYMBOL(pipe_lock);
 
@@ -98,28 +100,16 @@ void pipe_unlock(struct pipe_inode_info *pipe)
 }
 EXPORT_SYMBOL(pipe_unlock);
 
-static inline void __pipe_lock(struct pipe_inode_info *pipe)
-{
-       mutex_lock_nested(&pipe->mutex, I_MUTEX_PARENT);
-}
-
-static inline void __pipe_unlock(struct pipe_inode_info *pipe)
-{
-       mutex_unlock(&pipe->mutex);
-}
-
 void pipe_double_lock(struct pipe_inode_info *pipe1,
                      struct pipe_inode_info *pipe2)
 {
        BUG_ON(pipe1 == pipe2);
 
-       if (pipe1 < pipe2) {
-               pipe_lock_nested(pipe1, I_MUTEX_PARENT);
-               pipe_lock_nested(pipe2, I_MUTEX_CHILD);
-       } else {
-               pipe_lock_nested(pipe2, I_MUTEX_PARENT);
-               pipe_lock_nested(pipe1, I_MUTEX_CHILD);
-       }
+       if (pipe1 > pipe2)
+               swap(pipe1, pipe2);
+
+       pipe_lock(pipe1);
+       pipe_lock(pipe2);
 }
 
 static void anon_pipe_buf_release(struct pipe_inode_info *pipe,
@@ -271,7 +261,7 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
                return 0;
 
        ret = 0;
-       __pipe_lock(pipe);
+       mutex_lock(&pipe->mutex);
 
        /*
         * We only wake up writers if the pipe was full when we started
@@ -368,7 +358,7 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
                        ret = -EAGAIN;
                        break;
                }
-               __pipe_unlock(pipe);
+               mutex_unlock(&pipe->mutex);
 
                /*
                 * We only get here if we didn't actually read anything.
@@ -400,13 +390,13 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
                if (wait_event_interruptible_exclusive(pipe->rd_wait, pipe_readable(pipe)) < 0)
                        return -ERESTARTSYS;
 
-               __pipe_lock(pipe);
+               mutex_lock(&pipe->mutex);
                was_full = pipe_full(pipe->head, pipe->tail, pipe->max_usage);
                wake_next_reader = true;
        }
        if (pipe_empty(pipe->head, pipe->tail))
                wake_next_reader = false;
-       __pipe_unlock(pipe);
+       mutex_unlock(&pipe->mutex);
 
        if (was_full)
                wake_up_interruptible_sync_poll(&pipe->wr_wait, EPOLLOUT | EPOLLWRNORM);
@@ -462,7 +452,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
        if (unlikely(total_len == 0))
                return 0;
 
-       __pipe_lock(pipe);
+       mutex_lock(&pipe->mutex);
 
        if (!pipe->readers) {
                send_sig(SIGPIPE, current, 0);
@@ -582,19 +572,19 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
                 * after waiting we need to re-check whether the pipe
                 * become empty while we dropped the lock.
                 */
-               __pipe_unlock(pipe);
+               mutex_unlock(&pipe->mutex);
                if (was_empty)
                        wake_up_interruptible_sync_poll(&pipe->rd_wait, EPOLLIN | EPOLLRDNORM);
                kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
                wait_event_interruptible_exclusive(pipe->wr_wait, pipe_writable(pipe));
-               __pipe_lock(pipe);
+               mutex_lock(&pipe->mutex);
                was_empty = pipe_empty(pipe->head, pipe->tail);
                wake_next_writer = true;
        }
 out:
        if (pipe_full(pipe->head, pipe->tail, pipe->max_usage))
                wake_next_writer = false;
-       __pipe_unlock(pipe);
+       mutex_unlock(&pipe->mutex);
 
        /*
         * If we do do a wakeup event, we do a 'sync' wakeup, because we
@@ -629,7 +619,7 @@ static long pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 
        switch (cmd) {
        case FIONREAD:
-               __pipe_lock(pipe);
+               mutex_lock(&pipe->mutex);
                count = 0;
                head = pipe->head;
                tail = pipe->tail;
@@ -639,16 +629,16 @@ static long pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                        count += pipe->bufs[tail & mask].len;
                        tail++;
                }
-               __pipe_unlock(pipe);
+               mutex_unlock(&pipe->mutex);
 
                return put_user(count, (int __user *)arg);
 
 #ifdef CONFIG_WATCH_QUEUE
        case IOC_WATCH_QUEUE_SET_SIZE: {
                int ret;
-               __pipe_lock(pipe);
+               mutex_lock(&pipe->mutex);
                ret = watch_queue_set_size(pipe, arg);
-               __pipe_unlock(pipe);
+               mutex_unlock(&pipe->mutex);
                return ret;
        }
 
@@ -734,7 +724,7 @@ pipe_release(struct inode *inode, struct file *file)
 {
        struct pipe_inode_info *pipe = file->private_data;
 
-       __pipe_lock(pipe);
+       mutex_lock(&pipe->mutex);
        if (file->f_mode & FMODE_READ)
                pipe->readers--;
        if (file->f_mode & FMODE_WRITE)
@@ -747,7 +737,7 @@ pipe_release(struct inode *inode, struct file *file)
                kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
                kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
        }
-       __pipe_unlock(pipe);
+       mutex_unlock(&pipe->mutex);
 
        put_pipe_info(inode, pipe);
        return 0;
@@ -759,7 +749,7 @@ pipe_fasync(int fd, struct file *filp, int on)
        struct pipe_inode_info *pipe = filp->private_data;
        int retval = 0;
 
-       __pipe_lock(pipe);
+       mutex_lock(&pipe->mutex);
        if (filp->f_mode & FMODE_READ)
                retval = fasync_helper(fd, filp, on, &pipe->fasync_readers);
        if ((filp->f_mode & FMODE_WRITE) && retval >= 0) {
@@ -768,7 +758,7 @@ pipe_fasync(int fd, struct file *filp, int on)
                        /* this can happen only if on == T */
                        fasync_helper(-1, filp, 0, &pipe->fasync_readers);
        }
-       __pipe_unlock(pipe);
+       mutex_unlock(&pipe->mutex);
        return retval;
 }
 
@@ -834,6 +824,7 @@ struct pipe_inode_info *alloc_pipe_info(void)
                pipe->nr_accounted = pipe_bufs;
                pipe->user = user;
                mutex_init(&pipe->mutex);
+               lock_set_cmp_fn(&pipe->mutex, pipe_lock_cmp_fn, NULL);
                return pipe;
        }
 
@@ -1144,7 +1135,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
        filp->private_data = pipe;
        /* OK, we have a pipe and it's pinned down */
 
-       __pipe_lock(pipe);
+       mutex_lock(&pipe->mutex);
 
        /* We can only do regular read/write on fifos */
        stream_open(inode, filp);
@@ -1214,7 +1205,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
        }
 
        /* Ok! */
-       __pipe_unlock(pipe);
+       mutex_unlock(&pipe->mutex);
        return 0;
 
 err_rd:
@@ -1230,7 +1221,7 @@ err_wr:
        goto err;
 
 err:
-       __pipe_unlock(pipe);
+       mutex_unlock(&pipe->mutex);
 
        put_pipe_info(inode, pipe);
        return ret;
@@ -1411,7 +1402,7 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned int arg)
        if (!pipe)
                return -EBADF;
 
-       __pipe_lock(pipe);
+       mutex_lock(&pipe->mutex);
 
        switch (cmd) {
        case F_SETPIPE_SZ:
@@ -1425,7 +1416,7 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned int arg)
                break;
        }
 
-       __pipe_unlock(pipe);
+       mutex_unlock(&pipe->mutex);
        return ret;
 }
 
index e1af20893ebe1ed400acb7c7215377868f623bbf..6bf587d1a9b873ca708ac598a70b8e6fea6bc469 100644 (file)
@@ -786,12 +786,12 @@ struct posix_acl *posix_acl_from_xattr(struct user_namespace *userns,
                return ERR_PTR(count);
        if (count == 0)
                return NULL;
-       
+
        acl = posix_acl_alloc(count, GFP_NOFS);
        if (!acl)
                return ERR_PTR(-ENOMEM);
        acl_e = acl->a_entries;
-       
+
        for (end = entry + count; entry != end; acl_e++, entry++) {
                acl_e->e_tag  = le16_to_cpu(entry->e_tag);
                acl_e->e_perm = le16_to_cpu(entry->e_perm);
index 98a031ac26484544b8b07aec1ca72f40250ba2ca..18550c071d71c733204e3a94d274ac4d47c00119 100644 (file)
@@ -1878,8 +1878,6 @@ void proc_pid_evict_inode(struct proc_inode *ei)
                hlist_del_init_rcu(&ei->sibling_inodes);
                spin_unlock(&pid->lock);
        }
-
-       put_pid(pid);
 }
 
 struct inode *proc_pid_make_inode(struct super_block *sb,
index b33e490e3fd9f88f569e3453d603041e665cf6bf..dcd513dccf55cbfa50d5abe965b7a636dcff8353 100644 (file)
@@ -30,7 +30,6 @@
 
 static void proc_evict_inode(struct inode *inode)
 {
-       struct proc_dir_entry *de;
        struct ctl_table_header *head;
        struct proc_inode *ei = PROC_I(inode);
 
@@ -38,17 +37,8 @@ static void proc_evict_inode(struct inode *inode)
        clear_inode(inode);
 
        /* Stop tracking associated processes */
-       if (ei->pid) {
+       if (ei->pid)
                proc_pid_evict_inode(ei);
-               ei->pid = NULL;
-       }
-
-       /* Let go of any associated proc directory entry */
-       de = ei->pde;
-       if (de) {
-               pde_put(de);
-               ei->pde = NULL;
-       }
 
        head = ei->sysctl;
        if (head) {
@@ -80,6 +70,13 @@ static struct inode *proc_alloc_inode(struct super_block *sb)
 
 static void proc_free_inode(struct inode *inode)
 {
+       struct proc_inode *ei = PROC_I(inode);
+
+       if (ei->pid)
+               put_pid(ei->pid);
+       /* Let go of any associated proc directory entry */
+       if (ei->pde)
+               pde_put(ei->pde);
        kmem_cache_free(proc_inode_cachep, PROC_I(inode));
 }
 
@@ -95,7 +92,7 @@ void __init proc_init_kmemcache(void)
        proc_inode_cachep = kmem_cache_create("proc_inode_cache",
                                             sizeof(struct proc_inode),
                                             0, (SLAB_RECLAIM_ACCOUNT|
-                                               SLAB_MEM_SPREAD|SLAB_ACCOUNT|
+                                               SLAB_ACCOUNT|
                                                SLAB_PANIC),
                                             init_once);
        pde_opener_cache =
index b55dbc70287b492ae2e4ed43e2a3c04ee0818798..06a297a27ba3b31a5e2092fcd08d1ca9eebb5849 100644 (file)
@@ -271,7 +271,7 @@ static void proc_kill_sb(struct super_block *sb)
 
        kill_anon_super(sb);
        put_pid_ns(fs_info->pid_ns);
-       kfree(fs_info);
+       kfree_rcu(fs_info, rcu);
 }
 
 static struct file_system_type proc_fs_type = {
index 6eb9bb369b57ff1fdd9338b29a33d654c93cbda3..7b5711f76709cd27be1421809a082f0ec42e0a58 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/buffer_head.h>
 #include <linux/writeback.h>
 #include <linux/statfs.h>
+#include <linux/fs_context.h>
 #include "qnx4.h"
 
 #define QNX4_VERSION  4
@@ -30,28 +31,33 @@ static const struct super_operations qnx4_sops;
 
 static struct inode *qnx4_alloc_inode(struct super_block *sb);
 static void qnx4_free_inode(struct inode *inode);
-static int qnx4_remount(struct super_block *sb, int *flags, char *data);
 static int qnx4_statfs(struct dentry *, struct kstatfs *);
+static int qnx4_get_tree(struct fs_context *fc);
 
 static const struct super_operations qnx4_sops =
 {
        .alloc_inode    = qnx4_alloc_inode,
        .free_inode     = qnx4_free_inode,
        .statfs         = qnx4_statfs,
-       .remount_fs     = qnx4_remount,
 };
 
-static int qnx4_remount(struct super_block *sb, int *flags, char *data)
+static int qnx4_reconfigure(struct fs_context *fc)
 {
+       struct super_block *sb = fc->root->d_sb;
        struct qnx4_sb_info *qs;
 
        sync_filesystem(sb);
        qs = qnx4_sb(sb);
        qs->Version = QNX4_VERSION;
-       *flags |= SB_RDONLY;
+       fc->sb_flags |= SB_RDONLY;
        return 0;
 }
 
+static const struct fs_context_operations qnx4_context_opts = {
+       .get_tree       = qnx4_get_tree,
+       .reconfigure    = qnx4_reconfigure,
+};
+
 static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_head *bh, int create )
 {
        unsigned long phys;
@@ -183,12 +189,13 @@ static const char *qnx4_checkroot(struct super_block *sb,
        return "bitmap file not found.";
 }
 
-static int qnx4_fill_super(struct super_block *s, void *data, int silent)
+static int qnx4_fill_super(struct super_block *s, struct fs_context *fc)
 {
        struct buffer_head *bh;
        struct inode *root;
        const char *errmsg;
        struct qnx4_sb_info *qs;
+       int silent = fc->sb_flags & SB_SILENT;
 
        qs = kzalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL);
        if (!qs)
@@ -216,7 +223,7 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
        errmsg = qnx4_checkroot(s, (struct qnx4_super_block *) bh->b_data);
        brelse(bh);
        if (errmsg != NULL) {
-               if (!silent)
+               if (!silent)
                        printk(KERN_ERR "qnx4: %s\n", errmsg);
                return -EINVAL;
        }
@@ -235,6 +242,18 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
        return 0;
 }
 
+static int qnx4_get_tree(struct fs_context *fc)
+{
+       return get_tree_bdev(fc, qnx4_fill_super);
+}
+
+static int qnx4_init_fs_context(struct fs_context *fc)
+{
+       fc->ops = &qnx4_context_opts;
+
+       return 0;
+}
+
 static void qnx4_kill_sb(struct super_block *sb)
 {
        struct qnx4_sb_info *qs = qnx4_sb(sb);
@@ -376,18 +395,12 @@ static void destroy_inodecache(void)
        kmem_cache_destroy(qnx4_inode_cachep);
 }
 
-static struct dentry *qnx4_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
-{
-       return mount_bdev(fs_type, flags, dev_name, data, qnx4_fill_super);
-}
-
 static struct file_system_type qnx4_fs_type = {
-       .owner          = THIS_MODULE,
-       .name           = "qnx4",
-       .mount          = qnx4_mount,
-       .kill_sb        = qnx4_kill_sb,
-       .fs_flags       = FS_REQUIRES_DEV,
+       .owner                  = THIS_MODULE,
+       .name                   = "qnx4",
+       .kill_sb                = qnx4_kill_sb,
+       .fs_flags               = FS_REQUIRES_DEV,
+       .init_fs_context        = qnx4_init_fs_context,
 };
 MODULE_ALIAS_FS("qnx4");
 
index a286c545717f8991e3bae5808083f9ee5c2fd11b..405913f4faff99538beab737ee0887931a607b6b 100644 (file)
@@ -615,7 +615,7 @@ static int init_inodecache(void)
        qnx6_inode_cachep = kmem_cache_create("qnx6_inode_cache",
                                             sizeof(struct qnx6_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
-                                               SLAB_MEM_SPREAD|SLAB_ACCOUNT),
+                                               SLAB_ACCOUNT),
                                             init_once);
        if (!qnx6_inode_cachep)
                return -ENOMEM;
index 171c912af50f6f42bf96a9936f77fde70bbd8770..6474529c42530628fd3969573fb175283f4f51e8 100644 (file)
@@ -2386,7 +2386,7 @@ static int journal_read(struct super_block *sb)
 
        cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(sb);
        reiserfs_info(sb, "checking transaction log (%pg)\n",
-                     journal->j_bdev_handle->bdev);
+                     file_bdev(journal->j_bdev_file));
        start = ktime_get_seconds();
 
        /*
@@ -2447,7 +2447,7 @@ static int journal_read(struct super_block *sb)
                 * device and journal device to be the same
                 */
                d_bh =
-                   reiserfs_breada(journal->j_bdev_handle->bdev, cur_dblock,
+                   reiserfs_breada(file_bdev(journal->j_bdev_file), cur_dblock,
                                    sb->s_blocksize,
                                    SB_ONDISK_JOURNAL_1st_BLOCK(sb) +
                                    SB_ONDISK_JOURNAL_SIZE(sb));
@@ -2588,9 +2588,9 @@ static void journal_list_init(struct super_block *sb)
 
 static void release_journal_dev(struct reiserfs_journal *journal)
 {
-       if (journal->j_bdev_handle) {
-               bdev_release(journal->j_bdev_handle);
-               journal->j_bdev_handle = NULL;
+       if (journal->j_bdev_file) {
+               fput(journal->j_bdev_file);
+               journal->j_bdev_file = NULL;
        }
 }
 
@@ -2605,7 +2605,7 @@ static int journal_init_dev(struct super_block *super,
 
        result = 0;
 
-       journal->j_bdev_handle = NULL;
+       journal->j_bdev_file = NULL;
        jdev = SB_ONDISK_JOURNAL_DEVICE(super) ?
            new_decode_dev(SB_ONDISK_JOURNAL_DEVICE(super)) : super->s_dev;
 
@@ -2616,37 +2616,37 @@ static int journal_init_dev(struct super_block *super,
        if ((!jdev_name || !jdev_name[0])) {
                if (jdev == super->s_dev)
                        holder = NULL;
-               journal->j_bdev_handle = bdev_open_by_dev(jdev, blkdev_mode,
+               journal->j_bdev_file = bdev_file_open_by_dev(jdev, blkdev_mode,
                                                          holder, NULL);
-               if (IS_ERR(journal->j_bdev_handle)) {
-                       result = PTR_ERR(journal->j_bdev_handle);
-                       journal->j_bdev_handle = NULL;
+               if (IS_ERR(journal->j_bdev_file)) {
+                       result = PTR_ERR(journal->j_bdev_file);
+                       journal->j_bdev_file = NULL;
                        reiserfs_warning(super, "sh-458",
                                         "cannot init journal device unknown-block(%u,%u): %i",
                                         MAJOR(jdev), MINOR(jdev), result);
                        return result;
                } else if (jdev != super->s_dev)
-                       set_blocksize(journal->j_bdev_handle->bdev,
+                       set_blocksize(file_bdev(journal->j_bdev_file),
                                      super->s_blocksize);
 
                return 0;
        }
 
-       journal->j_bdev_handle = bdev_open_by_path(jdev_name, blkdev_mode,
+       journal->j_bdev_file = bdev_file_open_by_path(jdev_name, blkdev_mode,
                                                   holder, NULL);
-       if (IS_ERR(journal->j_bdev_handle)) {
-               result = PTR_ERR(journal->j_bdev_handle);
-               journal->j_bdev_handle = NULL;
+       if (IS_ERR(journal->j_bdev_file)) {
+               result = PTR_ERR(journal->j_bdev_file);
+               journal->j_bdev_file = NULL;
                reiserfs_warning(super, "sh-457",
                                 "journal_init_dev: Cannot open '%s': %i",
                                 jdev_name, result);
                return result;
        }
 
-       set_blocksize(journal->j_bdev_handle->bdev, super->s_blocksize);
+       set_blocksize(file_bdev(journal->j_bdev_file), super->s_blocksize);
        reiserfs_info(super,
                      "journal_init_dev: journal device: %pg\n",
-                     journal->j_bdev_handle->bdev);
+                     file_bdev(journal->j_bdev_file));
        return 0;
 }
 
@@ -2804,7 +2804,7 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
                                 "journal header magic %x (device %pg) does "
                                 "not match to magic found in super block %x",
                                 jh->jh_journal.jp_journal_magic,
-                                journal->j_bdev_handle->bdev,
+                                file_bdev(journal->j_bdev_file),
                                 sb_jp_journal_magic(rs));
                brelse(bhjh);
                goto free_and_return;
@@ -2828,7 +2828,7 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
        reiserfs_info(sb, "journal params: device %pg, size %u, "
                      "journal first block %u, max trans len %u, max batch %u, "
                      "max commit age %u, max trans age %u\n",
-                     journal->j_bdev_handle->bdev,
+                     file_bdev(journal->j_bdev_file),
                      SB_ONDISK_JOURNAL_SIZE(sb),
                      SB_ONDISK_JOURNAL_1st_BLOCK(sb),
                      journal->j_trans_max,
index 83cb9402e0f9c54dacd9fc64751b6e0ecca11421..5c68a4a52d78818eca7efbb61d3f9ab5787a408d 100644 (file)
@@ -354,7 +354,7 @@ static int show_journal(struct seq_file *m, void *unused)
                   "prepare: \t%12lu\n"
                   "prepare_retry: \t%12lu\n",
                   DJP(jp_journal_1st_block),
-                  SB_JOURNAL(sb)->j_bdev_handle->bdev,
+                  file_bdev(SB_JOURNAL(sb)->j_bdev_file),
                   DJP(jp_journal_dev),
                   DJP(jp_journal_size),
                   DJP(jp_journal_trans_max),
index 725667880e626a4577621c9137733340f0c53d30..0554903f42a90954620de4c6fca37be828d4f2fb 100644 (file)
@@ -299,7 +299,7 @@ struct reiserfs_journal {
        /* oldest journal block.  start here for traverse */
        struct reiserfs_journal_cnode *j_first;
 
-       struct bdev_handle *j_bdev_handle;
+       struct file *j_bdev_file;
 
        /* first block on s_dev of reserved area journal */
        int j_1st_reserved_block;
@@ -2810,10 +2810,10 @@ struct reiserfs_journal_header {
 
 /* We need these to make journal.c code more readable */
 #define journal_find_get_block(s, block) __find_get_block(\
-               SB_JOURNAL(s)->j_bdev_handle->bdev, block, s->s_blocksize)
-#define journal_getblk(s, block) __getblk(SB_JOURNAL(s)->j_bdev_handle->bdev,\
+               file_bdev(SB_JOURNAL(s)->j_bdev_file), block, s->s_blocksize)
+#define journal_getblk(s, block) __getblk(file_bdev(SB_JOURNAL(s)->j_bdev_file),\
                block, s->s_blocksize)
-#define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_bdev_handle->bdev,\
+#define journal_bread(s, block) __bread(file_bdev(SB_JOURNAL(s)->j_bdev_file),\
                block, s->s_blocksize)
 
 enum reiserfs_bh_state_bits {
index 67b5510beded2260b04c41bbd0247950784244dd..2cc469d481a290fa9978880229cc6995dc5b0a60 100644 (file)
@@ -670,7 +670,6 @@ static int __init init_inodecache(void)
                                                  sizeof(struct
                                                         reiserfs_inode_info),
                                                  0, (SLAB_RECLAIM_ACCOUNT|
-                                                     SLAB_MEM_SPREAD|
                                                      SLAB_ACCOUNT),
                                                  init_once);
        if (reiserfs_inode_cachep == NULL)
index f8c1120b8311f62324324b911b0aa4aebe4ccb04..de07f978ce3ebe16bf42bf5315996fd074de5aac 100644 (file)
@@ -373,9 +373,9 @@ int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
 }
 EXPORT_SYMBOL(generic_remap_file_range_prep);
 
-loff_t do_clone_file_range(struct file *file_in, loff_t pos_in,
-                          struct file *file_out, loff_t pos_out,
-                          loff_t len, unsigned int remap_flags)
+loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in,
+                           struct file *file_out, loff_t pos_out,
+                           loff_t len, unsigned int remap_flags)
 {
        loff_t ret;
 
@@ -391,23 +391,6 @@ loff_t do_clone_file_range(struct file *file_in, loff_t pos_in,
        if (!file_in->f_op->remap_file_range)
                return -EOPNOTSUPP;
 
-       ret = file_in->f_op->remap_file_range(file_in, pos_in,
-                       file_out, pos_out, len, remap_flags);
-       if (ret < 0)
-               return ret;
-
-       fsnotify_access(file_in);
-       fsnotify_modify(file_out);
-       return ret;
-}
-EXPORT_SYMBOL(do_clone_file_range);
-
-loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in,
-                           struct file *file_out, loff_t pos_out,
-                           loff_t len, unsigned int remap_flags)
-{
-       loff_t ret;
-
        ret = remap_verify_area(file_in, pos_in, len, false);
        if (ret)
                return ret;
@@ -417,10 +400,14 @@ loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in,
                return ret;
 
        file_start_write(file_out);
-       ret = do_clone_file_range(file_in, pos_in, file_out, pos_out, len,
-                                 remap_flags);
+       ret = file_in->f_op->remap_file_range(file_in, pos_in,
+                       file_out, pos_out, len, remap_flags);
        file_end_write(file_out);
+       if (ret < 0)
+               return ret;
 
+       fsnotify_access(file_in);
+       fsnotify_modify(file_out);
        return ret;
 }
 EXPORT_SYMBOL(vfs_clone_file_range);
index 545ad44f96b89148f1fc122d17f5a4b4e1a66deb..2be227532f399788de82a03e55970d33c67dc695 100644 (file)
@@ -594,7 +594,7 @@ static void romfs_kill_sb(struct super_block *sb)
 #ifdef CONFIG_ROMFS_ON_BLOCK
        if (sb->s_bdev) {
                sync_blockdev(sb->s_bdev);
-               bdev_release(sb->s_bdev_handle);
+               fput(sb->s_bdev_file);
        }
 #endif
 }
@@ -630,8 +630,8 @@ static int __init init_romfs_fs(void)
        romfs_inode_cachep =
                kmem_cache_create("romfs_i",
                                  sizeof(struct romfs_inode_info), 0,
-                                 SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD |
-                                 SLAB_ACCOUNT, romfs_i_init_once);
+                                 SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT,
+                                 romfs_i_init_once);
 
        if (!romfs_inode_cachep) {
                pr_err("Failed to initialise inode cache\n");
index 0ee55af1a55c29b14b118907b98e0329b8792376..9515c3fa1a03e8a8576f90f8a4dee46509dd1954 100644 (file)
@@ -476,7 +476,7 @@ static inline void wait_key_set(poll_table *wait, unsigned long in,
                wait->_key |= POLLOUT_SET;
 }
 
-static int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time)
+static noinline_for_stack int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time)
 {
        ktime_t expire, *to = NULL;
        struct poll_wqueues table;
@@ -839,7 +839,7 @@ SYSCALL_DEFINE1(old_select, struct sel_arg_struct __user *, arg)
 
 struct poll_list {
        struct poll_list *next;
-       int len;
+       unsigned int len;
        struct pollfd entries[];
 };
 
@@ -975,14 +975,15 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
                struct timespec64 *end_time)
 {
        struct poll_wqueues table;
-       int err = -EFAULT, fdcount, len;
+       int err = -EFAULT, fdcount;
        /* Allocate small arguments on the stack to save memory and be
           faster - use long to make sure the buffer is aligned properly
           on 64 bit archs to avoid unaligned access */
        long stack_pps[POLL_STACK_ALLOC/sizeof(long)];
        struct poll_list *const head = (struct poll_list *)stack_pps;
        struct poll_list *walk = head;
-       unsigned long todo = nfds;
+       unsigned int todo = nfds;
+       unsigned int len;
 
        if (nfds > rlimit(RLIMIT_NOFILE))
                return -EINVAL;
@@ -998,9 +999,9 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
                                        sizeof(struct pollfd) * walk->len))
                        goto out_fds;
 
-               todo -= walk->len;
-               if (!todo)
+               if (walk->len >= todo)
                        break;
+               todo -= walk->len;
 
                len = min(todo, POLLFD_PER_PAGE);
                walk = walk->next = kmalloc(struct_size(walk, entries, len),
@@ -1020,7 +1021,7 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
 
        for (walk = head; walk; walk = walk->next) {
                struct pollfd *fds = walk->entries;
-               int j;
+               unsigned int j;
 
                for (j = walk->len; j; fds++, ufds++, j--)
                        unsafe_put_user(fds->revents, &ufds->revents, Efault);
index 1daeb5714faad14c24c49a5efd5d118aaf04b54c..3de5047a7ff988c2049350e464771e912b12894e 100644 (file)
@@ -242,6 +242,7 @@ replay_again:
                .desired_access =  FILE_READ_DATA | FILE_READ_ATTRIBUTES,
                .disposition = FILE_OPEN,
                .fid = pfid,
+               .replay = !!(retries),
        };
 
        rc = SMB2_open_init(tcon, server,
index 2a4a4e3a8751f2ce8f0409ce79dc5024e02bb883..fb368b191eefd767a9f1f8b619580e3077827c46 100644 (file)
@@ -1085,7 +1085,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
 }
 
 static int
-cifs_setlease(struct file *file, int arg, struct file_lock **lease, void **priv)
+cifs_setlease(struct file *file, int arg, struct file_lease **lease, void **priv)
 {
        /*
         * Note that this is called by vfs setlease with i_lock held to
@@ -1094,9 +1094,6 @@ cifs_setlease(struct file *file, int arg, struct file_lock **lease, void **priv)
        struct inode *inode = file_inode(file);
        struct cifsFileInfo *cfile = file->private_data;
 
-       if (!(S_ISREG(inode->i_mode)))
-               return -EINVAL;
-
        /* Check if file is oplocked if this is request for new lease */
        if (arg == F_UNLCK ||
            ((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) ||
@@ -1172,6 +1169,9 @@ const char *cifs_get_link(struct dentry *dentry, struct inode *inode,
 {
        char *target_path;
 
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
        target_path = kmalloc(PATH_MAX, GFP_KERNEL);
        if (!target_path)
                return ERR_PTR(-ENOMEM);
index c86a72c9d9ecd4268481a4caa29e58004cb7d6b9..53c75cfb33ab9446740133e7f19da6229eeffd55 100644 (file)
@@ -1378,6 +1378,7 @@ struct cifs_open_parms {
        struct cifs_fid *fid;
        umode_t mode;
        bool reconnect:1;
+       bool replay:1; /* indicates that this open is for a replay */
 };
 
 struct cifs_fid {
index 01e89070df5ab2a38c1d041556e959419ec40fb4..5eb83bafc7fd2bfda2693e6b8f637a5c0292dbc0 100644 (file)
@@ -2066,20 +2066,20 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
                parm_data = (struct cifs_posix_lock *)
                        ((char *)&pSMBr->hdr.Protocol + data_offset);
                if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
-                       pLockData->fl_type = F_UNLCK;
+                       pLockData->c.flc_type = F_UNLCK;
                else {
                        if (parm_data->lock_type ==
                                        cpu_to_le16(CIFS_RDLCK))
-                               pLockData->fl_type = F_RDLCK;
+                               pLockData->c.flc_type = F_RDLCK;
                        else if (parm_data->lock_type ==
                                        cpu_to_le16(CIFS_WRLCK))
-                               pLockData->fl_type = F_WRLCK;
+                               pLockData->c.flc_type = F_WRLCK;
 
                        pLockData->fl_start = le64_to_cpu(parm_data->start);
                        pLockData->fl_end = pLockData->fl_start +
                                (le64_to_cpu(parm_data->length) ?
                                 le64_to_cpu(parm_data->length) - 1 : 0);
-                       pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
+                       pLockData->c.flc_pid = -le32_to_cpu(parm_data->pid);
                }
        }
 
index d03253f8f14552074dc79726a8d6521412eba6c4..ac9595504f4b11fa066a6516f034bff8bc09d56b 100644 (file)
@@ -3444,8 +3444,18 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
         * the user on mount
         */
        if ((cifs_sb->ctx->wsize == 0) ||
-           (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx)))
-               cifs_sb->ctx->wsize = server->ops->negotiate_wsize(tcon, ctx);
+           (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx))) {
+               cifs_sb->ctx->wsize =
+                       round_down(server->ops->negotiate_wsize(tcon, ctx), PAGE_SIZE);
+               /*
+                * in the very unlikely event that the server sent a max write size under PAGE_SIZE,
+                * (which would get rounded down to 0) then reset wsize to absolute minimum eg 4096
+                */
+               if (cifs_sb->ctx->wsize == 0) {
+                       cifs_sb->ctx->wsize = PAGE_SIZE;
+                       cifs_dbg(VFS, "wsize too small, reset to minimum ie PAGE_SIZE, usually 4096\n");
+               }
+       }
        if ((cifs_sb->ctx->rsize == 0) ||
            (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx)))
                cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx);
index f391c9b803d84f9549b50a57f860abdaf58e43b2..c3b8e7091a4d4d07c2825fbb839b31ec6d4223a1 100644 (file)
@@ -1315,20 +1315,20 @@ cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
        down_read(&cinode->lock_sem);
 
        exist = cifs_find_lock_conflict(cfile, offset, length, type,
-                                       flock->fl_flags, &conf_lock,
+                                       flock->c.flc_flags, &conf_lock,
                                        CIFS_LOCK_OP);
        if (exist) {
                flock->fl_start = conf_lock->offset;
                flock->fl_end = conf_lock->offset + conf_lock->length - 1;
-               flock->fl_pid = conf_lock->pid;
+               flock->c.flc_pid = conf_lock->pid;
                if (conf_lock->type & server->vals->shared_lock_type)
-                       flock->fl_type = F_RDLCK;
+                       flock->c.flc_type = F_RDLCK;
                else
-                       flock->fl_type = F_WRLCK;
+                       flock->c.flc_type = F_WRLCK;
        } else if (!cinode->can_cache_brlcks)
                rc = 1;
        else
-               flock->fl_type = F_UNLCK;
+               flock->c.flc_type = F_UNLCK;
 
        up_read(&cinode->lock_sem);
        return rc;
@@ -1404,16 +1404,16 @@ cifs_posix_lock_test(struct file *file, struct file_lock *flock)
 {
        int rc = 0;
        struct cifsInodeInfo *cinode = CIFS_I(file_inode(file));
-       unsigned char saved_type = flock->fl_type;
+       unsigned char saved_type = flock->c.flc_type;
 
-       if ((flock->fl_flags & FL_POSIX) == 0)
+       if ((flock->c.flc_flags & FL_POSIX) == 0)
                return 1;
 
        down_read(&cinode->lock_sem);
        posix_test_lock(file, flock);
 
-       if (flock->fl_type == F_UNLCK && !cinode->can_cache_brlcks) {
-               flock->fl_type = saved_type;
+       if (lock_is_unlock(flock) && !cinode->can_cache_brlcks) {
+               flock->c.flc_type = saved_type;
                rc = 1;
        }
 
@@ -1434,7 +1434,7 @@ cifs_posix_lock_set(struct file *file, struct file_lock *flock)
        struct cifsInodeInfo *cinode = CIFS_I(file_inode(file));
        int rc = FILE_LOCK_DEFERRED + 1;
 
-       if ((flock->fl_flags & FL_POSIX) == 0)
+       if ((flock->c.flc_flags & FL_POSIX) == 0)
                return rc;
 
        cifs_down_write(&cinode->lock_sem);
@@ -1584,7 +1584,9 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
 
        el = locks_to_send.next;
        spin_lock(&flctx->flc_lock);
-       list_for_each_entry(flock, &flctx->flc_posix, fl_list) {
+       for_each_file_lock(flock, &flctx->flc_posix) {
+               unsigned char ftype = flock->c.flc_type;
+
                if (el == &locks_to_send) {
                        /*
                         * The list ended. We don't have enough allocated
@@ -1594,12 +1596,12 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
                        break;
                }
                length = cifs_flock_len(flock);
-               if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK)
+               if (ftype == F_RDLCK || ftype == F_SHLCK)
                        type = CIFS_RDLCK;
                else
                        type = CIFS_WRLCK;
                lck = list_entry(el, struct lock_to_push, llist);
-               lck->pid = hash_lockowner(flock->fl_owner);
+               lck->pid = hash_lockowner(flock->c.flc_owner);
                lck->netfid = cfile->fid.netfid;
                lck->length = length;
                lck->type = type;
@@ -1666,42 +1668,43 @@ static void
 cifs_read_flock(struct file_lock *flock, __u32 *type, int *lock, int *unlock,
                bool *wait_flag, struct TCP_Server_Info *server)
 {
-       if (flock->fl_flags & FL_POSIX)
+       if (flock->c.flc_flags & FL_POSIX)
                cifs_dbg(FYI, "Posix\n");
-       if (flock->fl_flags & FL_FLOCK)
+       if (flock->c.flc_flags & FL_FLOCK)
                cifs_dbg(FYI, "Flock\n");
-       if (flock->fl_flags & FL_SLEEP) {
+       if (flock->c.flc_flags & FL_SLEEP) {
                cifs_dbg(FYI, "Blocking lock\n");
                *wait_flag = true;
        }
-       if (flock->fl_flags & FL_ACCESS)
+       if (flock->c.flc_flags & FL_ACCESS)
                cifs_dbg(FYI, "Process suspended by mandatory locking - not implemented yet\n");
-       if (flock->fl_flags & FL_LEASE)
+       if (flock->c.flc_flags & FL_LEASE)
                cifs_dbg(FYI, "Lease on file - not implemented yet\n");
-       if (flock->fl_flags &
+       if (flock->c.flc_flags &
            (~(FL_POSIX | FL_FLOCK | FL_SLEEP |
               FL_ACCESS | FL_LEASE | FL_CLOSE | FL_OFDLCK)))
-               cifs_dbg(FYI, "Unknown lock flags 0x%x\n", flock->fl_flags);
+               cifs_dbg(FYI, "Unknown lock flags 0x%x\n",
+                        flock->c.flc_flags);
 
        *type = server->vals->large_lock_type;
-       if (flock->fl_type == F_WRLCK) {
+       if (lock_is_write(flock)) {
                cifs_dbg(FYI, "F_WRLCK\n");
                *type |= server->vals->exclusive_lock_type;
                *lock = 1;
-       } else if (flock->fl_type == F_UNLCK) {
+       } else if (lock_is_unlock(flock)) {
                cifs_dbg(FYI, "F_UNLCK\n");
                *type |= server->vals->unlock_lock_type;
                *unlock = 1;
                /* Check if unlock includes more than one lock range */
-       } else if (flock->fl_type == F_RDLCK) {
+       } else if (lock_is_read(flock)) {
                cifs_dbg(FYI, "F_RDLCK\n");
                *type |= server->vals->shared_lock_type;
                *lock = 1;
-       } else if (flock->fl_type == F_EXLCK) {
+       } else if (flock->c.flc_type == F_EXLCK) {
                cifs_dbg(FYI, "F_EXLCK\n");
                *type |= server->vals->exclusive_lock_type;
                *lock = 1;
-       } else if (flock->fl_type == F_SHLCK) {
+       } else if (flock->c.flc_type == F_SHLCK) {
                cifs_dbg(FYI, "F_SHLCK\n");
                *type |= server->vals->shared_lock_type;
                *lock = 1;
@@ -1733,7 +1736,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
                else
                        posix_lock_type = CIFS_WRLCK;
                rc = CIFSSMBPosixLock(xid, tcon, netfid,
-                                     hash_lockowner(flock->fl_owner),
+                                     hash_lockowner(flock->c.flc_owner),
                                      flock->fl_start, length, flock,
                                      posix_lock_type, wait_flag);
                return rc;
@@ -1750,7 +1753,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
        if (rc == 0) {
                rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
                                            type, 0, 1, false);
-               flock->fl_type = F_UNLCK;
+               flock->c.flc_type = F_UNLCK;
                if (rc != 0)
                        cifs_dbg(VFS, "Error unlocking previously locked range %d during test of lock\n",
                                 rc);
@@ -1758,7 +1761,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
        }
 
        if (type & server->vals->shared_lock_type) {
-               flock->fl_type = F_WRLCK;
+               flock->c.flc_type = F_WRLCK;
                return 0;
        }
 
@@ -1770,12 +1773,12 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
        if (rc == 0) {
                rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
                        type | server->vals->shared_lock_type, 0, 1, false);
-               flock->fl_type = F_RDLCK;
+               flock->c.flc_type = F_RDLCK;
                if (rc != 0)
                        cifs_dbg(VFS, "Error unlocking previously locked range %d during test of lock\n",
                                 rc);
        } else
-               flock->fl_type = F_WRLCK;
+               flock->c.flc_type = F_WRLCK;
 
        return 0;
 }
@@ -1943,7 +1946,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
                        posix_lock_type = CIFS_UNLCK;
 
                rc = CIFSSMBPosixLock(xid, tcon, cfile->fid.netfid,
-                                     hash_lockowner(flock->fl_owner),
+                                     hash_lockowner(flock->c.flc_owner),
                                      flock->fl_start, length,
                                      NULL, posix_lock_type, wait_flag);
                goto out;
@@ -1953,7 +1956,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
                struct cifsLockInfo *lock;
 
                lock = cifs_lock_init(flock->fl_start, length, type,
-                                     flock->fl_flags);
+                                     flock->c.flc_flags);
                if (!lock)
                        return -ENOMEM;
 
@@ -1992,7 +1995,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
                rc = server->ops->mand_unlock_range(cfile, flock, xid);
 
 out:
-       if ((flock->fl_flags & FL_POSIX) || (flock->fl_flags & FL_FLOCK)) {
+       if ((flock->c.flc_flags & FL_POSIX) || (flock->c.flc_flags & FL_FLOCK)) {
                /*
                 * If this is a request to remove all locks because we
                 * are closing the file, it doesn't matter if the
@@ -2001,7 +2004,7 @@ out:
                 */
                if (rc) {
                        cifs_dbg(VFS, "%s failed rc=%d\n", __func__, rc);
-                       if (!(flock->fl_flags & FL_CLOSE))
+                       if (!(flock->c.flc_flags & FL_CLOSE))
                                return rc;
                }
                rc = locks_lock_file_wait(file, flock);
@@ -2022,7 +2025,7 @@ int cifs_flock(struct file *file, int cmd, struct file_lock *fl)
 
        xid = get_xid();
 
-       if (!(fl->fl_flags & FL_FLOCK)) {
+       if (!(fl->c.flc_flags & FL_FLOCK)) {
                rc = -ENOLCK;
                free_xid(xid);
                return rc;
@@ -2073,7 +2076,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
        xid = get_xid();
 
        cifs_dbg(FYI, "%s: %pD2 cmd=0x%x type=0x%x flags=0x%x r=%lld:%lld\n", __func__, file, cmd,
-                flock->fl_flags, flock->fl_type, (long long)flock->fl_start,
+                flock->c.flc_flags, flock->c.flc_type,
+                (long long)flock->fl_start,
                 (long long)flock->fl_end);
 
        cfile = (struct cifsFileInfo *)file->private_data;
@@ -2954,7 +2958,7 @@ skip_write:
                        continue;
                }
 
-               folio_batch_release(&fbatch);           
+               folio_batch_release(&fbatch);
                cond_resched();
        } while (wbc->nr_to_write > 0);
 
index aec8dbd1f9dbd2b685219850c65b0695ba657aba..4b2f5aa2ea0e1de026302b9e543e2e13429107f9 100644 (file)
@@ -1111,6 +1111,17 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
        case Opt_wsize:
                ctx->wsize = result.uint_32;
                ctx->got_wsize = true;
+               if (ctx->wsize % PAGE_SIZE != 0) {
+                       ctx->wsize = round_down(ctx->wsize, PAGE_SIZE);
+                       if (ctx->wsize == 0) {
+                               ctx->wsize = PAGE_SIZE;
+                               cifs_dbg(VFS, "wsize too small, reset to minimum %ld\n", PAGE_SIZE);
+                       } else {
+                               cifs_dbg(VFS,
+                                        "wsize rounded down to %d to multiple of PAGE_SIZE %ld\n",
+                                        ctx->wsize, PAGE_SIZE);
+                       }
+               }
                break;
        case Opt_acregmax:
                ctx->acregmax = HZ * result.uint_32;
index a6968573b775e7bdcab3df948908e9494f792027..4a517b280f2b79a2c1395a1c627b496def7392a7 100644 (file)
@@ -168,6 +168,21 @@ static char *automount_fullpath(struct dentry *dentry, void *page)
        return s;
 }
 
+static void fs_context_set_ids(struct smb3_fs_context *ctx)
+{
+       kuid_t uid = current_fsuid();
+       kgid_t gid = current_fsgid();
+
+       if (ctx->multiuser) {
+               if (!ctx->uid_specified)
+                       ctx->linux_uid = uid;
+               if (!ctx->gid_specified)
+                       ctx->linux_gid = gid;
+       }
+       if (!ctx->cruid_specified)
+               ctx->cred_uid = uid;
+}
+
 /*
  * Create a vfsmount that we can automount
  */
@@ -205,6 +220,7 @@ static struct vfsmount *cifs_do_automount(struct path *path)
        tmp.leaf_fullpath = NULL;
        tmp.UNC = tmp.prepath = NULL;
        tmp.dfs_root_ses = NULL;
+       fs_context_set_ids(&tmp);
 
        rc = smb3_fs_context_dup(ctx, &tmp);
        if (rc) {
index e0ee96d69d495216090d65817360c8fef6159419..c23478ab1cf851999e6578eed9d9f6b99cc08b30 100644 (file)
@@ -228,7 +228,7 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
                         * flock and OFD lock are associated with an open
                         * file description, not the process.
                         */
-                       if (!(flock->fl_flags & (FL_FLOCK | FL_OFDLCK)))
+                       if (!(flock->c.flc_flags & (FL_FLOCK | FL_OFDLCK)))
                                continue;
                if (cinode->can_cache_brlcks) {
                        /*
index 83c898afc8354bf04c7a86ee57e4343ad3618319..4695433fcf397f529754cc9ec266cb5ac1727512 100644 (file)
@@ -619,7 +619,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
                goto out;
        }
 
-       while (bytes_left >= sizeof(*p)) {
+       while (bytes_left >= (ssize_t)sizeof(*p)) {
                memset(&tmp_iface, 0, sizeof(tmp_iface));
                tmp_iface.speed = le64_to_cpu(p->LinkSpeed);
                tmp_iface.rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0;
@@ -1204,6 +1204,7 @@ replay_again:
                .disposition = FILE_OPEN,
                .create_options = cifs_create_options(cifs_sb, 0),
                .fid = &fid,
+               .replay = !!(retries),
        };
 
        rc = SMB2_open_init(tcon, server,
@@ -1569,6 +1570,7 @@ replay_again:
                .disposition = FILE_OPEN,
                .create_options = cifs_create_options(cifs_sb, create_options),
                .fid = &fid,
+               .replay = !!(retries),
        };
 
        if (qi.flags & PASSTHRU_FSCTL) {
@@ -2295,6 +2297,7 @@ replay_again:
                .disposition = FILE_OPEN,
                .create_options = cifs_create_options(cifs_sb, 0),
                .fid = fid,
+               .replay = !!(retries),
        };
 
        rc = SMB2_open_init(tcon, server,
@@ -2681,6 +2684,7 @@ replay_again:
                .disposition = FILE_OPEN,
                .create_options = cifs_create_options(cifs_sb, 0),
                .fid = &fid,
+               .replay = !!(retries),
        };
 
        rc = SMB2_open_init(tcon, server,
@@ -5213,7 +5217,7 @@ static int smb2_create_reparse_symlink(const unsigned int xid,
        struct inode *new;
        struct kvec iov;
        __le16 *path;
-       char *sym;
+       char *sym, sep = CIFS_DIR_SEP(cifs_sb);
        u16 len, plen;
        int rc = 0;
 
@@ -5227,7 +5231,8 @@ static int smb2_create_reparse_symlink(const unsigned int xid,
                .symlink_target = sym,
        };
 
-       path = cifs_convert_path_to_utf16(symname, cifs_sb);
+       convert_delimiter(sym, sep);
+       path = cifs_convert_path_to_utf16(sym, cifs_sb);
        if (!path) {
                rc = -ENOMEM;
                goto out;
@@ -5250,7 +5255,10 @@ static int smb2_create_reparse_symlink(const unsigned int xid,
        buf->PrintNameLength = cpu_to_le16(plen);
        memcpy(buf->PathBuffer, path, plen);
        buf->Flags = cpu_to_le32(*symname != '/' ? SYMLINK_FLAG_RELATIVE : 0);
+       if (*sym != sep)
+               buf->Flags = cpu_to_le32(SYMLINK_FLAG_RELATIVE);
 
+       convert_delimiter(sym, '/');
        iov.iov_base = buf;
        iov.iov_len = len;
        new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
index 4085ce27fd388c7eab9a8402e095e84551158cb1..608ee05491e262c5cf4555c6b51b364cdc60a03b 100644 (file)
@@ -2404,8 +2404,13 @@ create_durable_v2_buf(struct cifs_open_parms *oparms)
         */
        buf->dcontext.Timeout = cpu_to_le32(oparms->tcon->handle_timeout);
        buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
-       generate_random_uuid(buf->dcontext.CreateGuid);
-       memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
+
+       /* for replay, we should not overwrite the existing create guid */
+       if (!oparms->replay) {
+               generate_random_uuid(buf->dcontext.CreateGuid);
+               memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
+       } else
+               memcpy(buf->dcontext.CreateGuid, pfid->create_guid, 16);
 
        /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */
        buf->Name[0] = 'D';
@@ -3142,6 +3147,7 @@ replay_again:
        /* reinitialize for possible replay */
        flags = 0;
        server = cifs_pick_channel(ses);
+       oparms->replay = !!(retries);
 
        cifs_dbg(FYI, "create/open\n");
        if (!ses || !server)
index 0c97d3c860726a303081eb25927d38439bfaf4ea..089527a8b4ff42211c7bccdd4aa8adba9b984436 100644 (file)
@@ -6764,10 +6764,10 @@ struct file_lock *smb_flock_init(struct file *f)
 
        locks_init_lock(fl);
 
-       fl->fl_owner = f;
-       fl->fl_pid = current->tgid;
-       fl->fl_file = f;
-       fl->fl_flags = FL_POSIX;
+       fl->c.flc_owner = f;
+       fl->c.flc_pid = current->tgid;
+       fl->c.flc_file = f;
+       fl->c.flc_flags = FL_POSIX;
        fl->fl_ops = NULL;
        fl->fl_lmops = NULL;
 
@@ -6784,30 +6784,30 @@ static int smb2_set_flock_flags(struct file_lock *flock, int flags)
        case SMB2_LOCKFLAG_SHARED:
                ksmbd_debug(SMB, "received shared request\n");
                cmd = F_SETLKW;
-               flock->fl_type = F_RDLCK;
-               flock->fl_flags |= FL_SLEEP;
+               flock->c.flc_type = F_RDLCK;
+               flock->c.flc_flags |= FL_SLEEP;
                break;
        case SMB2_LOCKFLAG_EXCLUSIVE:
                ksmbd_debug(SMB, "received exclusive request\n");
                cmd = F_SETLKW;
-               flock->fl_type = F_WRLCK;
-               flock->fl_flags |= FL_SLEEP;
+               flock->c.flc_type = F_WRLCK;
+               flock->c.flc_flags |= FL_SLEEP;
                break;
        case SMB2_LOCKFLAG_SHARED | SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
                ksmbd_debug(SMB,
                            "received shared & fail immediately request\n");
                cmd = F_SETLK;
-               flock->fl_type = F_RDLCK;
+               flock->c.flc_type = F_RDLCK;
                break;
        case SMB2_LOCKFLAG_EXCLUSIVE | SMB2_LOCKFLAG_FAIL_IMMEDIATELY:
                ksmbd_debug(SMB,
                            "received exclusive & fail immediately request\n");
                cmd = F_SETLK;
-               flock->fl_type = F_WRLCK;
+               flock->c.flc_type = F_WRLCK;
                break;
        case SMB2_LOCKFLAG_UNLOCK:
                ksmbd_debug(SMB, "received unlock request\n");
-               flock->fl_type = F_UNLCK;
+               flock->c.flc_type = F_UNLCK;
                cmd = F_SETLK;
                break;
        }
@@ -6845,13 +6845,13 @@ static void smb2_remove_blocked_lock(void **argv)
        struct file_lock *flock = (struct file_lock *)argv[0];
 
        ksmbd_vfs_posix_lock_unblock(flock);
-       wake_up(&flock->fl_wait);
+       locks_wake_up(flock);
 }
 
 static inline bool lock_defer_pending(struct file_lock *fl)
 {
        /* check pending lock waiters */
-       return waitqueue_active(&fl->fl_wait);
+       return waitqueue_active(&fl->c.flc_wait);
 }
 
 /**
@@ -6942,8 +6942,8 @@ int smb2_lock(struct ksmbd_work *work)
                list_for_each_entry(cmp_lock, &lock_list, llist) {
                        if (cmp_lock->fl->fl_start <= flock->fl_start &&
                            cmp_lock->fl->fl_end >= flock->fl_end) {
-                               if (cmp_lock->fl->fl_type != F_UNLCK &&
-                                   flock->fl_type != F_UNLCK) {
+                               if (cmp_lock->fl->c.flc_type != F_UNLCK &&
+                                   flock->c.flc_type != F_UNLCK) {
                                        pr_err("conflict two locks in one request\n");
                                        err = -EINVAL;
                                        locks_free_lock(flock);
@@ -6991,12 +6991,12 @@ int smb2_lock(struct ksmbd_work *work)
                list_for_each_entry(conn, &conn_list, conns_list) {
                        spin_lock(&conn->llist_lock);
                        list_for_each_entry_safe(cmp_lock, tmp2, &conn->lock_list, clist) {
-                               if (file_inode(cmp_lock->fl->fl_file) !=
-                                   file_inode(smb_lock->fl->fl_file))
+                               if (file_inode(cmp_lock->fl->c.flc_file) !=
+                                   file_inode(smb_lock->fl->c.flc_file))
                                        continue;
 
-                               if (smb_lock->fl->fl_type == F_UNLCK) {
-                                       if (cmp_lock->fl->fl_file == smb_lock->fl->fl_file &&
+                               if (lock_is_unlock(smb_lock->fl)) {
+                                       if (cmp_lock->fl->c.flc_file == smb_lock->fl->c.flc_file &&
                                            cmp_lock->start == smb_lock->start &&
                                            cmp_lock->end == smb_lock->end &&
                                            !lock_defer_pending(cmp_lock->fl)) {
@@ -7013,7 +7013,7 @@ int smb2_lock(struct ksmbd_work *work)
                                        continue;
                                }
 
-                               if (cmp_lock->fl->fl_file == smb_lock->fl->fl_file) {
+                               if (cmp_lock->fl->c.flc_file == smb_lock->fl->c.flc_file) {
                                        if (smb_lock->flags & SMB2_LOCKFLAG_SHARED)
                                                continue;
                                } else {
@@ -7055,7 +7055,7 @@ int smb2_lock(struct ksmbd_work *work)
                }
                up_read(&conn_list_lock);
 out_check_cl:
-               if (smb_lock->fl->fl_type == F_UNLCK && nolock) {
+               if (lock_is_unlock(smb_lock->fl) && nolock) {
                        pr_err("Try to unlock nolocked range\n");
                        rsp->hdr.Status = STATUS_RANGE_NOT_LOCKED;
                        goto out;
@@ -7179,7 +7179,7 @@ out:
                struct file_lock *rlock = NULL;
 
                rlock = smb_flock_init(filp);
-               rlock->fl_type = F_UNLCK;
+               rlock->c.flc_type = F_UNLCK;
                rlock->fl_start = smb_lock->start;
                rlock->fl_end = smb_lock->end;
 
index a6961bfe3e139467296cf55798fe8f943aae9432..c487e834331aa61962b22d94c677289ec6e72067 100644 (file)
@@ -337,18 +337,18 @@ static int check_lock_range(struct file *filp, loff_t start, loff_t end,
                return 0;
 
        spin_lock(&ctx->flc_lock);
-       list_for_each_entry(flock, &ctx->flc_posix, fl_list) {
+       for_each_file_lock(flock, &ctx->flc_posix) {
                /* check conflict locks */
                if (flock->fl_end >= start && end >= flock->fl_start) {
-                       if (flock->fl_type == F_RDLCK) {
+                       if (lock_is_read(flock)) {
                                if (type == WRITE) {
                                        pr_err("not allow write by shared lock\n");
                                        error = 1;
                                        goto out;
                                }
-                       } else if (flock->fl_type == F_WRLCK) {
+                       } else if (lock_is_write(flock)) {
                                /* check owner in lock */
-                               if (flock->fl_file != filp) {
+                               if (flock->c.flc_file != filp) {
                                        error = 1;
                                        pr_err("not allow rw access by exclusive lock from other opens\n");
                                        goto out;
@@ -1837,13 +1837,13 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
 
 void ksmbd_vfs_posix_lock_wait(struct file_lock *flock)
 {
-       wait_event(flock->fl_wait, !flock->fl_blocker);
+       wait_event(flock->c.flc_wait, !flock->c.flc_blocker);
 }
 
 int ksmbd_vfs_posix_lock_wait_timeout(struct file_lock *flock, long timeout)
 {
-       return wait_event_interruptible_timeout(flock->fl_wait,
-                                               !flock->fl_blocker,
+       return wait_event_interruptible_timeout(flock->c.flc_wait,
+                                               !flock->c.flc_blocker,
                                                timeout);
 }
 
index d35e852954892dadcf1df6757c8b491904d2edbb..ee05ab6b37e769a16a3b1e40cd820c17e0b76d85 100644 (file)
@@ -274,9 +274,10 @@ static void destroy_super_work(struct work_struct *work)
 {
        struct super_block *s = container_of(work, struct super_block,
                                                        destroy_work);
-       int i;
-
-       for (i = 0; i < SB_FREEZE_LEVELS; i++)
+       security_sb_free(s);
+       put_user_ns(s->s_user_ns);
+       kfree(s->s_subtype);
+       for (int i = 0; i < SB_FREEZE_LEVELS; i++)
                percpu_free_rwsem(&s->s_writers.rw_sem[i]);
        kfree(s);
 }
@@ -296,9 +297,6 @@ static void destroy_unused_super(struct super_block *s)
        super_unlock_excl(s);
        list_lru_destroy(&s->s_dentry_lru);
        list_lru_destroy(&s->s_inode_lru);
-       security_sb_free(s);
-       put_user_ns(s->s_user_ns);
-       kfree(s->s_subtype);
        shrinker_free(s->s_shrink);
        /* no delays needed */
        destroy_super_work(&s->destroy_work);
@@ -409,9 +407,6 @@ static void __put_super(struct super_block *s)
                WARN_ON(s->s_dentry_lru.node);
                WARN_ON(s->s_inode_lru.node);
                WARN_ON(!list_empty(&s->s_mounts));
-               security_sb_free(s);
-               put_user_ns(s->s_user_ns);
-               kfree(s->s_subtype);
                call_rcu(&s->rcu, destroy_super_rcu);
        }
 }
@@ -1532,16 +1527,16 @@ int setup_bdev_super(struct super_block *sb, int sb_flags,
                struct fs_context *fc)
 {
        blk_mode_t mode = sb_open_mode(sb_flags);
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct block_device *bdev;
 
-       bdev_handle = bdev_open_by_dev(sb->s_dev, mode, sb, &fs_holder_ops);
-       if (IS_ERR(bdev_handle)) {
+       bdev_file = bdev_file_open_by_dev(sb->s_dev, mode, sb, &fs_holder_ops);
+       if (IS_ERR(bdev_file)) {
                if (fc)
                        errorf(fc, "%s: Can't open blockdev", fc->source);
-               return PTR_ERR(bdev_handle);
+               return PTR_ERR(bdev_file);
        }
-       bdev = bdev_handle->bdev;
+       bdev = file_bdev(bdev_file);
 
        /*
         * This really should be in blkdev_get_by_dev, but right now can't due
@@ -1549,7 +1544,7 @@ int setup_bdev_super(struct super_block *sb, int sb_flags,
         * writable from userspace even for a read-only block device.
         */
        if ((mode & BLK_OPEN_WRITE) && bdev_read_only(bdev)) {
-               bdev_release(bdev_handle);
+               fput(bdev_file);
                return -EACCES;
        }
 
@@ -1560,11 +1555,11 @@ int setup_bdev_super(struct super_block *sb, int sb_flags,
        if (atomic_read(&bdev->bd_fsfreeze_count) > 0) {
                if (fc)
                        warnf(fc, "%pg: Can't mount, blockdev is frozen", bdev);
-               bdev_release(bdev_handle);
+               fput(bdev_file);
                return -EBUSY;
        }
        spin_lock(&sb_lock);
-       sb->s_bdev_handle = bdev_handle;
+       sb->s_bdev_file = bdev_file;
        sb->s_bdev = bdev;
        sb->s_bdi = bdi_get(bdev->bd_disk->bdi);
        if (bdev_stable_writes(bdev))
@@ -1680,7 +1675,7 @@ void kill_block_super(struct super_block *sb)
        generic_shutdown_super(sb);
        if (bdev) {
                sync_blockdev(bdev);
-               bdev_release(sb->s_bdev_handle);
+               fput(sb->s_bdev_file);
        }
 }
 
index 5a915b2e68f5e48769bab76b315913303014d8b4..76bc2d5e75a960ae4610f1cb9f00b9ece914ce83 100644 (file)
@@ -336,7 +336,7 @@ int __init sysv_init_icache(void)
 {
        sysv_inode_cachep = kmem_cache_create("sysv_inode_cache",
                        sizeof(struct sysv_inode_info), 0,
-                       SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT,
+                       SLAB_RECLAIM_ACCOUNT|SLAB_ACCOUNT,
                        init_once);
        if (!sysv_inode_cachep)
                return -ENOMEM;
index 410ab2a44d2f604d22d7e805317cfa616ca5d191..19bcb51a220366631b9b89c0dfa0e86ddada208c 100644 (file)
@@ -83,9 +83,6 @@ static inline sysv_zone_t *block_end(struct buffer_head *bh)
        return (sysv_zone_t*)((char*)bh->b_data + bh->b_size);
 }
 
-/*
- * Requires read_lock(&pointers_lock) or write_lock(&pointers_lock)
- */
 static Indirect *get_branch(struct inode *inode,
                            int depth,
                            int offsets[],
@@ -105,15 +102,18 @@ static Indirect *get_branch(struct inode *inode,
                bh = sb_bread(sb, block);
                if (!bh)
                        goto failure;
+               read_lock(&pointers_lock);
                if (!verify_chain(chain, p))
                        goto changed;
                add_chain(++p, bh, (sysv_zone_t*)bh->b_data + *++offsets);
+               read_unlock(&pointers_lock);
                if (!p->key)
                        goto no_block;
        }
        return NULL;
 
 changed:
+       read_unlock(&pointers_lock);
        brelse(bh);
        *err = -EAGAIN;
        goto no_block;
@@ -219,9 +219,7 @@ static int get_block(struct inode *inode, sector_t iblock, struct buffer_head *b
                goto out;
 
 reread:
-       read_lock(&pointers_lock);
        partial = get_branch(inode, depth, offsets, chain, &err);
-       read_unlock(&pointers_lock);
 
        /* Simplest case - block found, no allocation needed */
        if (!partial) {
@@ -291,9 +289,9 @@ static Indirect *find_shared(struct inode *inode,
        *top = 0;
        for (k = depth; k > 1 && !offsets[k-1]; k--)
                ;
+       partial = get_branch(inode, k, offsets, chain, &err);
 
        write_lock(&pointers_lock);
-       partial = get_branch(inode, k, offsets, chain, &err);
        if (!partial)
                partial = chain + k-1;
        /*
index e413a9cf8ee38b9e0f9fad3d9234653626dbf1d7..551148de66cd86dbf76484d73c4c3acdc5969a1c 100644 (file)
@@ -205,7 +205,6 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
        dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino);
 
        err = fscrypt_prepare_lookup(dir, dentry, &nm);
-       generic_set_encrypted_ci_d_ops(dentry);
        if (err == -ENOENT)
                return d_splice_alias(NULL, dentry);
        if (err)
index 09e270d6ed0258923ccc7680025fad26d1cac5c6..d2881041b393c3fca36fb15e8aca78df3877e04d 100644 (file)
@@ -2239,13 +2239,14 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
                goto out_umount;
        }
 
+       generic_set_sb_d_ops(sb);
        sb->s_root = d_make_root(root);
        if (!sb->s_root) {
                err = -ENOMEM;
                goto out_umount;
        }
 
-       import_uuid(&sb->s_uuid, c->uuid);
+       super_set_uuid(sb, c->uuid, sizeof(c->uuid));
 
        mutex_unlock(&c->umount_mutex);
        return 0;
index 813f85156b0c3b9ed97a5d5740db2d20e3810e59..1698507d1ac73a0a4985322e00c52e61539d5317 100644 (file)
@@ -112,7 +112,7 @@ xfs_end_ioend(
         * longer dirty. If we don't remove delalloc blocks here, they become
         * stale and can corrupt free space accounting on unmount.
         */
-       error = blk_status_to_errno(ioend->io_bio->bi_status);
+       error = blk_status_to_errno(ioend->io_bio.bi_status);
        if (unlikely(error)) {
                if (ioend->io_flags & IOMAP_F_SHARED) {
                        xfs_reflink_cancel_cow_range(ip, offset, size, true);
@@ -179,7 +179,7 @@ STATIC void
 xfs_end_bio(
        struct bio              *bio)
 {
-       struct iomap_ioend      *ioend = bio->bi_private;
+       struct iomap_ioend      *ioend = iomap_ioend_from_bio(bio);
        struct xfs_inode        *ip = XFS_I(ioend->io_inode);
        unsigned long           flags;
 
@@ -276,7 +276,8 @@ static int
 xfs_map_blocks(
        struct iomap_writepage_ctx *wpc,
        struct inode            *inode,
-       loff_t                  offset)
+       loff_t                  offset,
+       unsigned int            len)
 {
        struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
@@ -444,7 +445,7 @@ xfs_prepare_ioend(
        /* send ioends that might require a transaction to the completion wq */
        if (xfs_ioend_is_append(ioend) || ioend->io_type == IOMAP_UNWRITTEN ||
            (ioend->io_flags & IOMAP_F_SHARED))
-               ioend->io_bio->bi_end_io = xfs_end_bio;
+               ioend->io_bio.bi_end_io = xfs_end_bio;
        return status;
 }
 
index 8e5bd50d29feb34b50a5a85dca9110648a6bf69e..01b41fabbe3c7ba89d2f59c6dad15e49dfe781c5 100644 (file)
@@ -1951,7 +1951,7 @@ xfs_free_buftarg(
        fs_put_dax(btp->bt_daxdev, btp->bt_mount);
        /* the main block device is closed by kill_block_super */
        if (btp->bt_bdev != btp->bt_mount->m_super->s_bdev)
-               bdev_release(btp->bt_bdev_handle);
+               fput(btp->bt_bdev_file);
 
        kmem_free(btp);
 }
@@ -1994,7 +1994,7 @@ xfs_setsize_buftarg_early(
 struct xfs_buftarg *
 xfs_alloc_buftarg(
        struct xfs_mount        *mp,
-       struct bdev_handle      *bdev_handle)
+       struct file             *bdev_file)
 {
        xfs_buftarg_t           *btp;
        const struct dax_holder_operations *ops = NULL;
@@ -2005,9 +2005,9 @@ xfs_alloc_buftarg(
        btp = kmem_zalloc(sizeof(*btp), KM_NOFS);
 
        btp->bt_mount = mp;
-       btp->bt_bdev_handle = bdev_handle;
-       btp->bt_dev = bdev_handle->bdev->bd_dev;
-       btp->bt_bdev = bdev_handle->bdev;
+       btp->bt_bdev_file = bdev_file;
+       btp->bt_bdev = file_bdev(bdev_file);
+       btp->bt_dev = btp->bt_bdev->bd_dev;
        btp->bt_daxdev = fs_dax_get_by_bdev(btp->bt_bdev, &btp->bt_dax_part_off,
                                            mp, ops);
 
index b470de08a46ca8e6e7c3b4dfe7e85110037f3949..304e858d04fb3cfca71d4378f2878293f7462d8b 100644 (file)
@@ -98,7 +98,7 @@ typedef unsigned int xfs_buf_flags_t;
  */
 typedef struct xfs_buftarg {
        dev_t                   bt_dev;
-       struct bdev_handle      *bt_bdev_handle;
+       struct file             *bt_bdev_file;
        struct block_device     *bt_bdev;
        struct dax_device       *bt_daxdev;
        u64                     bt_dax_part_off;
@@ -366,7 +366,7 @@ xfs_buf_update_cksum(struct xfs_buf *bp, unsigned long cksum_offset)
  *     Handling of buftargs.
  */
 struct xfs_buftarg *xfs_alloc_buftarg(struct xfs_mount *mp,
-               struct bdev_handle *bdev_handle);
+               struct file *bdev_file);
 extern void xfs_free_buftarg(struct xfs_buftarg *);
 extern void xfs_buftarg_wait(struct xfs_buftarg *);
 extern void xfs_buftarg_drain(struct xfs_buftarg *);
index aabb25dc3efab2ed57e8e1a99ec1aa0bfd503297..57fa21ad79124784d205f1313db461acda2546b1 100644 (file)
@@ -62,7 +62,7 @@ xfs_uuid_mount(
        int                     hole, i;
 
        /* Publish UUID in struct super_block */
-       uuid_copy(&mp->m_super->s_uuid, uuid);
+       super_set_uuid(mp->m_super, uuid->b, sizeof(*uuid));
 
        if (xfs_has_nouuid(mp))
                return 0;
@@ -706,6 +706,8 @@ xfs_mountfs(
        /* enable fail_at_unmount as default */
        mp->m_fail_unmount = true;
 
+       super_set_sysfs_name_id(mp->m_super);
+
        error = xfs_sysfs_init(&mp->m_kobj, &xfs_mp_ktype,
                               NULL, mp->m_super->s_id);
        if (error)
index 5a2512d20bd07473a872592911ede7246b8c11b7..00fbd5b6e582dffeeecec0e2a3f6f624d25304bd 100644 (file)
@@ -350,7 +350,6 @@ xfs_setup_dax_always(
                return -EINVAL;
        }
 
-       xfs_warn(mp, "DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
        return 0;
 
 disable_dax:
@@ -362,16 +361,16 @@ STATIC int
 xfs_blkdev_get(
        xfs_mount_t             *mp,
        const char              *name,
-       struct bdev_handle      **handlep)
+       struct file             **bdev_filep)
 {
        int                     error = 0;
 
-       *handlep = bdev_open_by_path(name,
+       *bdev_filep = bdev_file_open_by_path(name,
                BLK_OPEN_READ | BLK_OPEN_WRITE | BLK_OPEN_RESTRICT_WRITES,
                mp->m_super, &fs_holder_ops);
-       if (IS_ERR(*handlep)) {
-               error = PTR_ERR(*handlep);
-               *handlep = NULL;
+       if (IS_ERR(*bdev_filep)) {
+               error = PTR_ERR(*bdev_filep);
+               *bdev_filep = NULL;
                xfs_warn(mp, "Invalid device [%s], error=%d", name, error);
        }
 
@@ -436,26 +435,26 @@ xfs_open_devices(
 {
        struct super_block      *sb = mp->m_super;
        struct block_device     *ddev = sb->s_bdev;
-       struct bdev_handle      *logdev_handle = NULL, *rtdev_handle = NULL;
+       struct file             *logdev_file = NULL, *rtdev_file = NULL;
        int                     error;
 
        /*
         * Open real time and log devices - order is important.
         */
        if (mp->m_logname) {
-               error = xfs_blkdev_get(mp, mp->m_logname, &logdev_handle);
+               error = xfs_blkdev_get(mp, mp->m_logname, &logdev_file);
                if (error)
                        return error;
        }
 
        if (mp->m_rtname) {
-               error = xfs_blkdev_get(mp, mp->m_rtname, &rtdev_handle);
+               error = xfs_blkdev_get(mp, mp->m_rtname, &rtdev_file);
                if (error)
                        goto out_close_logdev;
 
-               if (rtdev_handle->bdev == ddev ||
-                   (logdev_handle &&
-                    rtdev_handle->bdev == logdev_handle->bdev)) {
+               if (file_bdev(rtdev_file) == ddev ||
+                   (logdev_file &&
+                    file_bdev(rtdev_file) == file_bdev(logdev_file))) {
                        xfs_warn(mp,
        "Cannot mount filesystem with identical rtdev and ddev/logdev.");
                        error = -EINVAL;
@@ -467,25 +466,25 @@ xfs_open_devices(
         * Setup xfs_mount buffer target pointers
         */
        error = -ENOMEM;
-       mp->m_ddev_targp = xfs_alloc_buftarg(mp, sb->s_bdev_handle);
+       mp->m_ddev_targp = xfs_alloc_buftarg(mp, sb->s_bdev_file);
        if (!mp->m_ddev_targp)
                goto out_close_rtdev;
 
-       if (rtdev_handle) {
-               mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev_handle);
+       if (rtdev_file) {
+               mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev_file);
                if (!mp->m_rtdev_targp)
                        goto out_free_ddev_targ;
        }
 
-       if (logdev_handle && logdev_handle->bdev != ddev) {
-               mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev_handle);
+       if (logdev_file && file_bdev(logdev_file) != ddev) {
+               mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev_file);
                if (!mp->m_logdev_targp)
                        goto out_free_rtdev_targ;
        } else {
                mp->m_logdev_targp = mp->m_ddev_targp;
                /* Handle won't be used, drop it */
-               if (logdev_handle)
-                       bdev_release(logdev_handle);
+               if (logdev_file)
+                       fput(logdev_file);
        }
 
        return 0;
@@ -496,11 +495,11 @@ xfs_open_devices(
  out_free_ddev_targ:
        xfs_free_buftarg(mp->m_ddev_targp);
  out_close_rtdev:
-        if (rtdev_handle)
-               bdev_release(rtdev_handle);
+        if (rtdev_file)
+               fput(rtdev_file);
  out_close_logdev:
-       if (logdev_handle)
-               bdev_release(logdev_handle);
+       if (logdev_file)
+               fput(logdev_file);
        return error;
 }
 
index 6ab2318a9c8e80271a3f17d2ad852dacad2f2fa1..3b103715acc90fe28a303d356f2a43d9b71f3eb6 100644 (file)
@@ -125,7 +125,8 @@ static void zonefs_readahead(struct readahead_control *rac)
  * which implies that the page range can only be within the fixed inode size.
  */
 static int zonefs_write_map_blocks(struct iomap_writepage_ctx *wpc,
-                                  struct inode *inode, loff_t offset)
+                                  struct inode *inode, loff_t offset,
+                                  unsigned int len)
 {
        struct zonefs_zone *z = zonefs_inode_zone(inode);
 
@@ -348,7 +349,12 @@ static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size,
        struct zonefs_inode_info *zi = ZONEFS_I(inode);
 
        if (error) {
-               zonefs_io_error(inode, true);
+               /*
+                * For Sync IOs, error recovery is called from
+                * zonefs_file_dio_write().
+                */
+               if (!is_sync_kiocb(iocb))
+                       zonefs_io_error(inode, true);
                return error;
        }
 
@@ -491,6 +497,14 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
                        ret = -EINVAL;
                        goto inode_unlock;
                }
+               /*
+                * Advance the zone write pointer offset. This assumes that the
+                * IO will succeed, which is OK to do because we do not allow
+                * partial writes (IOMAP_DIO_PARTIAL is not set) and if the IO
+                * fails, the error path will correct the write pointer offset.
+                */
+               z->z_wpoffset += count;
+               zonefs_inode_account_active(inode);
                mutex_unlock(&zi->i_truncate_mutex);
        }
 
@@ -504,20 +518,19 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
        if (ret == -ENOTBLK)
                ret = -EBUSY;
 
-       if (zonefs_zone_is_seq(z) &&
-           (ret > 0 || ret == -EIOCBQUEUED)) {
-               if (ret > 0)
-                       count = ret;
-
-               /*
-                * Update the zone write pointer offset assuming the write
-                * operation succeeded. If it did not, the error recovery path
-                * will correct it. Also do active seq file accounting.
-                */
-               mutex_lock(&zi->i_truncate_mutex);
-               z->z_wpoffset += count;
-               zonefs_inode_account_active(inode);
-               mutex_unlock(&zi->i_truncate_mutex);
+       /*
+        * For a failed IO or partial completion, trigger error recovery
+        * to update the zone write pointer offset to a correct value.
+        * For asynchronous IOs, zonefs_file_write_dio_end_io() may already
+        * have executed error recovery if the IO already completed when we
+        * reach here. However, we cannot know that and execute error recovery
+        * again (that will not change anything).
+        */
+       if (zonefs_zone_is_seq(z)) {
+               if (ret > 0 && ret != count)
+                       ret = -EIO;
+               if (ret < 0 && ret != -EIOCBQUEUED)
+                       zonefs_io_error(inode, true);
        }
 
 inode_unlock:
index ccf1ca4473e176b56fd446c37c2ab0de4d4e2652..236a6d88306f51bb9d34f7319e7078b618505dc3 100644 (file)
@@ -114,7 +114,7 @@ static int zonefs_zone_mgmt(struct super_block *sb,
 
        trace_zonefs_zone_mgmt(sb, z, op);
        ret = blkdev_zone_mgmt(sb->s_bdev, op, z->z_sector,
-                              z->z_size >> SECTOR_SHIFT, GFP_NOFS);
+                              z->z_size >> SECTOR_SHIFT);
        if (ret) {
                zonefs_err(sb,
                           "Zone management operation %s at %llu failed %d\n",
@@ -247,16 +247,18 @@ static void zonefs_inode_update_mode(struct inode *inode)
        z->z_mode = inode->i_mode;
 }
 
-struct zonefs_ioerr_data {
-       struct inode    *inode;
-       bool            write;
-};
-
 static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
                              void *data)
 {
-       struct zonefs_ioerr_data *err = data;
-       struct inode *inode = err->inode;
+       struct blk_zone *z = data;
+
+       *z = *zone;
+       return 0;
+}
+
+static void zonefs_handle_io_error(struct inode *inode, struct blk_zone *zone,
+                                  bool write)
+{
        struct zonefs_zone *z = zonefs_inode_zone(inode);
        struct super_block *sb = inode->i_sb;
        struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
@@ -271,8 +273,8 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
        data_size = zonefs_check_zone_condition(sb, z, zone);
        isize = i_size_read(inode);
        if (!(z->z_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE)) &&
-           !err->write && isize == data_size)
-               return 0;
+           !write && isize == data_size)
+               return;
 
        /*
         * At this point, we detected either a bad zone or an inconsistency
@@ -293,7 +295,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
         * In all cases, warn about inode size inconsistency and handle the
         * IO error according to the zone condition and to the mount options.
         */
-       if (zonefs_zone_is_seq(z) && isize != data_size)
+       if (isize != data_size)
                zonefs_warn(sb,
                            "inode %lu: invalid size %lld (should be %lld)\n",
                            inode->i_ino, isize, data_size);
@@ -353,8 +355,6 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
        zonefs_i_size_write(inode, data_size);
        z->z_wpoffset = data_size;
        zonefs_inode_account_active(inode);
-
-       return 0;
 }
 
 /*
@@ -368,23 +368,25 @@ void __zonefs_io_error(struct inode *inode, bool write)
 {
        struct zonefs_zone *z = zonefs_inode_zone(inode);
        struct super_block *sb = inode->i_sb;
-       struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
        unsigned int noio_flag;
-       unsigned int nr_zones = 1;
-       struct zonefs_ioerr_data err = {
-               .inode = inode,
-               .write = write,
-       };
+       struct blk_zone zone;
        int ret;
 
        /*
-        * The only files that have more than one zone are conventional zone
-        * files with aggregated conventional zones, for which the inode zone
-        * size is always larger than the device zone size.
+        * Conventional zone have no write pointer and cannot become read-only
+        * or offline. So simply fake a report for a single or aggregated zone
+        * and let zonefs_handle_io_error() correct the zone inode information
+        * according to the mount options.
         */
-       if (z->z_size > bdev_zone_sectors(sb->s_bdev))
-               nr_zones = z->z_size >>
-                       (sbi->s_zone_sectors_shift + SECTOR_SHIFT);
+       if (!zonefs_zone_is_seq(z)) {
+               zone.start = z->z_sector;
+               zone.len = z->z_size >> SECTOR_SHIFT;
+               zone.wp = zone.start + zone.len;
+               zone.type = BLK_ZONE_TYPE_CONVENTIONAL;
+               zone.cond = BLK_ZONE_COND_NOT_WP;
+               zone.capacity = zone.len;
+               goto handle_io_error;
+       }
 
        /*
         * Memory allocations in blkdev_report_zones() can trigger a memory
@@ -395,12 +397,20 @@ void __zonefs_io_error(struct inode *inode, bool write)
         * the GFP_NOIO context avoids both problems.
         */
        noio_flag = memalloc_noio_save();
-       ret = blkdev_report_zones(sb->s_bdev, z->z_sector, nr_zones,
-                                 zonefs_io_error_cb, &err);
-       if (ret != nr_zones)
+       ret = blkdev_report_zones(sb->s_bdev, z->z_sector, 1,
+                                 zonefs_io_error_cb, &zone);
+       memalloc_noio_restore(noio_flag);
+
+       if (ret != 1) {
                zonefs_err(sb, "Get inode %lu zone information failed %d\n",
                           inode->i_ino, ret);
-       memalloc_noio_restore(noio_flag);
+               zonefs_warn(sb, "remounting filesystem read-only\n");
+               sb->s_flags |= SB_RDONLY;
+               return;
+       }
+
+handle_io_error:
+       zonefs_handle_io_error(inode, &zone, write);
 }
 
 static struct kmem_cache *zonefs_inode_cachep;
index 961f4d88f9ef784c3c8fbafd6925579698a93d5f..0c0695763bea394aadf9ed26abd8fb3bedc714cf 100644 (file)
@@ -193,7 +193,6 @@ do {                                                                        \
 #ifndef smp_store_release
 #define smp_store_release(p, v)                                                \
 do {                                                                   \
-       compiletime_assert_atomic_type(*p);                             \
        barrier();                                                      \
        WRITE_ONCE(*p, v);                                              \
 } while (0)
@@ -203,7 +202,6 @@ do {                                                                        \
 #define smp_load_acquire(p)                                            \
 ({                                                                     \
        __unqual_scalar_typeof(*p) ___p1 = READ_ONCE(*p);               \
-       compiletime_assert_atomic_type(*p);                             \
        barrier();                                                      \
        (typeof(*p))___p1;                                              \
 })
index c4c423e97f069c325ba2ed41b6839adb160d95f6..4453906105ca183a8fe20be81468f5211666d01f 100644 (file)
@@ -9,6 +9,8 @@
 
 #include <drm/drm_connector.h>
 
+struct auxiliary_device;
+
 #if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE)
 int drm_aux_bridge_register(struct device *parent);
 #else
@@ -19,10 +21,23 @@ static inline int drm_aux_bridge_register(struct device *parent)
 #endif
 
 #if IS_ENABLED(CONFIG_DRM_AUX_HPD_BRIDGE)
+struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent, struct device_node *np);
+int devm_drm_dp_hpd_bridge_add(struct device *dev, struct auxiliary_device *adev);
 struct device *drm_dp_hpd_bridge_register(struct device *parent,
                                          struct device_node *np);
 void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status);
 #else
+static inline struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent,
+                                                                   struct device_node *np)
+{
+       return NULL;
+}
+
+static inline int devm_drm_dp_hpd_bridge_add(struct auxiliary_device *adev)
+{
+       return 0;
+}
+
 static inline struct device *drm_dp_hpd_bridge_register(struct device *parent,
                                                        struct device_node *np)
 {
index 51e0f6059410fa4a093fad04b21896842cae5c28..19ac7b36f608eafdf1b25bbabeea4296ddffe8d3 100644 (file)
 #define QCOM_ID_IPQ9510                        521
 #define QCOM_ID_QRB4210                        523
 #define QCOM_ID_QRB2210                        524
+#define QCOM_ID_SM8475                 530
+#define QCOM_ID_SM8475P                        531
 #define QCOM_ID_SA8775P                        534
 #define QCOM_ID_QRU1000                        539
+#define QCOM_ID_SM8475_2               540
 #define QCOM_ID_QDU1000                        545
 #define QCOM_ID_SM8650                 557
 #define QCOM_ID_SM4450                 568
 #define QCOM_ID_IPQ5322                        593
 #define QCOM_ID_IPQ5312                        594
 #define QCOM_ID_IPQ5302                        595
+#define QCOM_ID_QCS8550                        603
+#define QCOM_ID_QCM8550                        604
 #define QCOM_ID_IPQ5300                        624
 
 /*
index 3090e09c9a55cddb982e1aeafa02076212479940..bc15108aa3c2ab527c25d688c66121208b35eac9 100644 (file)
 #define CLK_GOUT_SSS_PCLK              12
 #define CLK_GOUT_GPIO_CORE_PCLK                13
 #define CLK_GOUT_SYSREG_CORE_PCLK      14
+#define CLK_GOUT_PDMA_CORE_ACLK                15
+#define CLK_GOUT_SPDMA_CORE_ACLK       16
 
 /* CMU_DPU */
 #define CLK_MOUT_DPU_USER              1
index 21adec22387c931ba00c03dfb51212c4896897d5..3dac3577788a70af3b5c80a0ea5b599559e53c59 100644 (file)
 #define CLK_GOUT_MISC_WDT_CLUSTER1_PCLK                        73
 #define CLK_GOUT_MISC_XIU_D_MISC_ACLK                  74
 
+/* CMU_PERIC0 */
+#define CLK_MOUT_PERIC0_BUS_USER                       1
+#define CLK_MOUT_PERIC0_I3C_USER                       2
+#define CLK_MOUT_PERIC0_USI0_UART_USER                 3
+#define CLK_MOUT_PERIC0_USI14_USI_USER                 4
+#define CLK_MOUT_PERIC0_USI1_USI_USER                  5
+#define CLK_MOUT_PERIC0_USI2_USI_USER                  6
+#define CLK_MOUT_PERIC0_USI3_USI_USER                  7
+#define CLK_MOUT_PERIC0_USI4_USI_USER                  8
+#define CLK_MOUT_PERIC0_USI5_USI_USER                  9
+#define CLK_MOUT_PERIC0_USI6_USI_USER                  10
+#define CLK_MOUT_PERIC0_USI7_USI_USER                  11
+#define CLK_MOUT_PERIC0_USI8_USI_USER                  12
+#define CLK_DOUT_PERIC0_I3C                            13
+#define CLK_DOUT_PERIC0_USI0_UART                      14
+#define CLK_DOUT_PERIC0_USI14_USI                      15
+#define CLK_DOUT_PERIC0_USI1_USI                       16
+#define CLK_DOUT_PERIC0_USI2_USI                       17
+#define CLK_DOUT_PERIC0_USI3_USI                       18
+#define CLK_DOUT_PERIC0_USI4_USI                       19
+#define CLK_DOUT_PERIC0_USI5_USI                       20
+#define CLK_DOUT_PERIC0_USI6_USI                       21
+#define CLK_DOUT_PERIC0_USI7_USI                       22
+#define CLK_DOUT_PERIC0_USI8_USI                       23
+#define CLK_GOUT_PERIC0_IP                             24
+#define CLK_GOUT_PERIC0_PERIC0_CMU_PERIC0_PCLK         25
+#define CLK_GOUT_PERIC0_CLK_PERIC0_OSCCLK_CLK          26
+#define CLK_GOUT_PERIC0_D_TZPC_PERIC0_PCLK             27
+#define CLK_GOUT_PERIC0_GPC_PERIC0_PCLK                        28
+#define CLK_GOUT_PERIC0_GPIO_PERIC0_PCLK               29
+#define CLK_GOUT_PERIC0_LHM_AXI_P_PERIC0_I_CLK         30
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_0            31
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_1            32
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_10           33
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_11           34
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_12           35
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_13           36
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_14           37
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_15           38
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_2            39
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_3            40
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_4            41
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_5            42
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_6            43
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_7            44
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_8            45
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_IPCLK_9            46
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_0             47
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_1             48
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_10            49
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_11            50
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_12            51
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_13            52
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_14            53
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_15            54
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_2             55
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_3             56
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_4             57
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_5             58
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_6             59
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_7             60
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_8             61
+#define CLK_GOUT_PERIC0_PERIC0_TOP0_PCLK_9             62
+#define CLK_GOUT_PERIC0_PERIC0_TOP1_IPCLK_0            63
+#define CLK_GOUT_PERIC0_PERIC0_TOP1_IPCLK_2            64
+#define CLK_GOUT_PERIC0_PERIC0_TOP1_PCLK_0             65
+#define CLK_GOUT_PERIC0_PERIC0_TOP1_PCLK_2             66
+#define CLK_GOUT_PERIC0_CLK_PERIC0_BUSP_CLK            67
+#define CLK_GOUT_PERIC0_CLK_PERIC0_I3C_CLK             68
+#define CLK_GOUT_PERIC0_CLK_PERIC0_USI0_UART_CLK       69
+#define CLK_GOUT_PERIC0_CLK_PERIC0_USI14_USI_CLK       70
+#define CLK_GOUT_PERIC0_CLK_PERIC0_USI1_USI_CLK                71
+#define CLK_GOUT_PERIC0_CLK_PERIC0_USI2_USI_CLK                72
+#define CLK_GOUT_PERIC0_CLK_PERIC0_USI3_USI_CLK                73
+#define CLK_GOUT_PERIC0_CLK_PERIC0_USI4_USI_CLK                74
+#define CLK_GOUT_PERIC0_CLK_PERIC0_USI5_USI_CLK                75
+#define CLK_GOUT_PERIC0_CLK_PERIC0_USI6_USI_CLK                76
+#define CLK_GOUT_PERIC0_CLK_PERIC0_USI7_USI_CLK                77
+#define CLK_GOUT_PERIC0_CLK_PERIC0_USI8_USI_CLK                78
+#define CLK_GOUT_PERIC0_SYSREG_PERIC0_PCLK             79
+
+/* CMU_PERIC1 */
+#define CLK_MOUT_PERIC1_BUS_USER                       1
+#define CLK_MOUT_PERIC1_I3C_USER                       2
+#define CLK_MOUT_PERIC1_USI0_USI_USER                  3
+#define CLK_MOUT_PERIC1_USI10_USI_USER                 4
+#define CLK_MOUT_PERIC1_USI11_USI_USER                 5
+#define CLK_MOUT_PERIC1_USI12_USI_USER                 6
+#define CLK_MOUT_PERIC1_USI13_USI_USER                 7
+#define CLK_MOUT_PERIC1_USI9_USI_USER                  8
+#define CLK_DOUT_PERIC1_I3C                            9
+#define CLK_DOUT_PERIC1_USI0_USI                       10
+#define CLK_DOUT_PERIC1_USI10_USI                      11
+#define CLK_DOUT_PERIC1_USI11_USI                      12
+#define CLK_DOUT_PERIC1_USI12_USI                      13
+#define CLK_DOUT_PERIC1_USI13_USI                      14
+#define CLK_DOUT_PERIC1_USI9_USI                       15
+#define CLK_GOUT_PERIC1_IP                             16
+#define CLK_GOUT_PERIC1_PCLK                           17
+#define CLK_GOUT_PERIC1_CLK_PERIC1_I3C_CLK             18
+#define CLK_GOUT_PERIC1_CLK_PERIC1_OSCCLK_CLK          19
+#define CLK_GOUT_PERIC1_D_TZPC_PERIC1_PCLK             20
+#define CLK_GOUT_PERIC1_GPC_PERIC1_PCLK                        21
+#define CLK_GOUT_PERIC1_GPIO_PERIC1_PCLK               22
+#define CLK_GOUT_PERIC1_LHM_AXI_P_PERIC1_I_CLK         23
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_IPCLK_1            24
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_IPCLK_2            25
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_IPCLK_3            26
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_IPCLK_4            27
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_IPCLK_5            28
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_IPCLK_6            29
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_IPCLK_8            30
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_PCLK_1             31
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_PCLK_15            32
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_PCLK_2             33
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_PCLK_3             34
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_PCLK_4             35
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_PCLK_5             36
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_PCLK_6             37
+#define CLK_GOUT_PERIC1_PERIC1_TOP0_PCLK_8             38
+#define CLK_GOUT_PERIC1_CLK_PERIC1_BUSP_CLK            39
+#define CLK_GOUT_PERIC1_CLK_PERIC1_USI0_USI_CLK                40
+#define CLK_GOUT_PERIC1_CLK_PERIC1_USI10_USI_CLK       41
+#define CLK_GOUT_PERIC1_CLK_PERIC1_USI11_USI_CLK       42
+#define CLK_GOUT_PERIC1_CLK_PERIC1_USI12_USI_CLK       43
+#define CLK_GOUT_PERIC1_CLK_PERIC1_USI13_USI_CLK       44
+#define CLK_GOUT_PERIC1_CLK_PERIC1_USI9_USI_CLK                45
+#define CLK_GOUT_PERIC1_SYSREG_PERIC1_PCLK             46
+
 #endif /* _DT_BINDINGS_CLOCK_GOOGLE_GS101_H */
index 783162da6148709e49b46e493786a489082fc7de..13b4a62877e5e35767386bbcacb581f657bb1072 100644 (file)
 #define GCC_USB3PHY_PHY_BCR                    3
 #define GCC_USB3_PHY_BCR                       4
 #define GCC_USB_30_BCR                         5
+#define GCC_MDSS_BCR                           6
+#define GCC_CRYPTO_BCR                         7
+#define GCC_SDCC1_BCR                          8
+#define GCC_SDCC2_BCR                          9
 
 /* GDSCs */
 #define CPP_GDSC                               0
index e893415ae13d0fdc7e8d99613ecbf6340b816f44..90c6e021a0356dce6d38cbdd8b199c04a8c29a8b 100644 (file)
 #define GCC_PCIE_3_CLKREF_CLK                                  236
 #define GCC_USB3_PRIM_CLKREF_CLK                               237
 #define GCC_USB3_SEC_CLKREF_CLK                                        238
+#define GCC_UFS_MEM_CLKREF_EN                                  239
+#define GCC_UFS_CARD_CLKREF_EN                                 240
 
 #define GCC_EMAC_BCR                                           0
 #define GCC_GPU_BCR                                            1
diff --git a/include/dt-bindings/clock/qcom,x1e80100-camcc.h b/include/dt-bindings/clock/qcom,x1e80100-camcc.h
new file mode 100644 (file)
index 0000000..d72fdfb
--- /dev/null
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_CAM_CC_X1E80100_H
+#define _DT_BINDINGS_CLK_QCOM_CAM_CC_X1E80100_H
+
+/* CAM_CC clocks */
+#define CAM_CC_BPS_AHB_CLK                                     0
+#define CAM_CC_BPS_CLK                                         1
+#define CAM_CC_BPS_CLK_SRC                                     2
+#define CAM_CC_BPS_FAST_AHB_CLK                                        3
+#define CAM_CC_CAMNOC_AXI_NRT_CLK                              4
+#define CAM_CC_CAMNOC_AXI_RT_CLK                               5
+#define CAM_CC_CAMNOC_AXI_RT_CLK_SRC                           6
+#define CAM_CC_CAMNOC_DCD_XO_CLK                               7
+#define CAM_CC_CAMNOC_XO_CLK                                   8
+#define CAM_CC_CCI_0_CLK                                       9
+#define CAM_CC_CCI_0_CLK_SRC                                   10
+#define CAM_CC_CCI_1_CLK                                       11
+#define CAM_CC_CCI_1_CLK_SRC                                   12
+#define CAM_CC_CORE_AHB_CLK                                    13
+#define CAM_CC_CPAS_AHB_CLK                                    14
+#define CAM_CC_CPAS_BPS_CLK                                    15
+#define CAM_CC_CPAS_FAST_AHB_CLK                               16
+#define CAM_CC_CPAS_IFE_0_CLK                                  17
+#define CAM_CC_CPAS_IFE_1_CLK                                  18
+#define CAM_CC_CPAS_IFE_LITE_CLK                               19
+#define CAM_CC_CPAS_IPE_NPS_CLK                                        20
+#define CAM_CC_CPAS_SFE_0_CLK                                  21
+#define CAM_CC_CPHY_RX_CLK_SRC                                 22
+#define CAM_CC_CSI0PHYTIMER_CLK                                        23
+#define CAM_CC_CSI0PHYTIMER_CLK_SRC                            24
+#define CAM_CC_CSI1PHYTIMER_CLK                                        25
+#define CAM_CC_CSI1PHYTIMER_CLK_SRC                            26
+#define CAM_CC_CSI2PHYTIMER_CLK                                        27
+#define CAM_CC_CSI2PHYTIMER_CLK_SRC                            28
+#define CAM_CC_CSI3PHYTIMER_CLK                                        29
+#define CAM_CC_CSI3PHYTIMER_CLK_SRC                            30
+#define CAM_CC_CSI4PHYTIMER_CLK                                        31
+#define CAM_CC_CSI4PHYTIMER_CLK_SRC                            32
+#define CAM_CC_CSI5PHYTIMER_CLK                                        33
+#define CAM_CC_CSI5PHYTIMER_CLK_SRC                            34
+#define CAM_CC_CSID_CLK                                                35
+#define CAM_CC_CSID_CLK_SRC                                    36
+#define CAM_CC_CSID_CSIPHY_RX_CLK                              37
+#define CAM_CC_CSIPHY0_CLK                                     38
+#define CAM_CC_CSIPHY1_CLK                                     39
+#define CAM_CC_CSIPHY2_CLK                                     40
+#define CAM_CC_CSIPHY3_CLK                                     41
+#define CAM_CC_CSIPHY4_CLK                                     42
+#define CAM_CC_CSIPHY5_CLK                                     43
+#define CAM_CC_FAST_AHB_CLK_SRC                                        44
+#define CAM_CC_GDSC_CLK                                                45
+#define CAM_CC_ICP_AHB_CLK                                     46
+#define CAM_CC_ICP_CLK                                         47
+#define CAM_CC_ICP_CLK_SRC                                     48
+#define CAM_CC_IFE_0_CLK                                       49
+#define CAM_CC_IFE_0_CLK_SRC                                   50
+#define CAM_CC_IFE_0_DSP_CLK                                   51
+#define CAM_CC_IFE_0_FAST_AHB_CLK                              52
+#define CAM_CC_IFE_1_CLK                                       53
+#define CAM_CC_IFE_1_CLK_SRC                                   54
+#define CAM_CC_IFE_1_DSP_CLK                                   55
+#define CAM_CC_IFE_1_FAST_AHB_CLK                              56
+#define CAM_CC_IFE_LITE_AHB_CLK                                        57
+#define CAM_CC_IFE_LITE_CLK                                    58
+#define CAM_CC_IFE_LITE_CLK_SRC                                        59
+#define CAM_CC_IFE_LITE_CPHY_RX_CLK                            60
+#define CAM_CC_IFE_LITE_CSID_CLK                               61
+#define CAM_CC_IFE_LITE_CSID_CLK_SRC                           62
+#define CAM_CC_IPE_NPS_AHB_CLK                                 63
+#define CAM_CC_IPE_NPS_CLK                                     64
+#define CAM_CC_IPE_NPS_CLK_SRC                                 65
+#define CAM_CC_IPE_NPS_FAST_AHB_CLK                            66
+#define CAM_CC_IPE_PPS_CLK                                     67
+#define CAM_CC_IPE_PPS_FAST_AHB_CLK                            68
+#define CAM_CC_JPEG_CLK                                                69
+#define CAM_CC_JPEG_CLK_SRC                                    70
+#define CAM_CC_MCLK0_CLK                                       71
+#define CAM_CC_MCLK0_CLK_SRC                                   72
+#define CAM_CC_MCLK1_CLK                                       73
+#define CAM_CC_MCLK1_CLK_SRC                                   74
+#define CAM_CC_MCLK2_CLK                                       75
+#define CAM_CC_MCLK2_CLK_SRC                                   76
+#define CAM_CC_MCLK3_CLK                                       77
+#define CAM_CC_MCLK3_CLK_SRC                                   78
+#define CAM_CC_MCLK4_CLK                                       79
+#define CAM_CC_MCLK4_CLK_SRC                                   80
+#define CAM_CC_MCLK5_CLK                                       81
+#define CAM_CC_MCLK5_CLK_SRC                                   82
+#define CAM_CC_MCLK6_CLK                                       83
+#define CAM_CC_MCLK6_CLK_SRC                                   84
+#define CAM_CC_MCLK7_CLK                                       85
+#define CAM_CC_MCLK7_CLK_SRC                                   86
+#define CAM_CC_PLL0                                            87
+#define CAM_CC_PLL0_OUT_EVEN                                   88
+#define CAM_CC_PLL0_OUT_ODD                                    89
+#define CAM_CC_PLL1                                            90
+#define CAM_CC_PLL1_OUT_EVEN                                   91
+#define CAM_CC_PLL2                                            92
+#define CAM_CC_PLL3                                            93
+#define CAM_CC_PLL3_OUT_EVEN                                   94
+#define CAM_CC_PLL4                                            95
+#define CAM_CC_PLL4_OUT_EVEN                                   96
+#define CAM_CC_PLL6                                            97
+#define CAM_CC_PLL6_OUT_EVEN                                   98
+#define CAM_CC_PLL8                                            99
+#define CAM_CC_PLL8_OUT_EVEN                                   100
+#define CAM_CC_SFE_0_CLK                                       101
+#define CAM_CC_SFE_0_CLK_SRC                                   102
+#define CAM_CC_SFE_0_FAST_AHB_CLK                              103
+#define CAM_CC_SLEEP_CLK                                       104
+#define CAM_CC_SLEEP_CLK_SRC                                   105
+#define CAM_CC_SLOW_AHB_CLK_SRC                                        106
+#define CAM_CC_XO_CLK_SRC                                      107
+
+/* CAM_CC power domains */
+#define CAM_CC_BPS_GDSC                                                0
+#define CAM_CC_IFE_0_GDSC                                      1
+#define CAM_CC_IFE_1_GDSC                                      2
+#define CAM_CC_IPE_0_GDSC                                      3
+#define CAM_CC_SFE_0_GDSC                                      4
+#define CAM_CC_TITAN_TOP_GDSC                                  5
+
+/* CAM_CC resets */
+#define CAM_CC_BPS_BCR                                         0
+#define CAM_CC_ICP_BCR                                         1
+#define CAM_CC_IFE_0_BCR                                       2
+#define CAM_CC_IFE_1_BCR                                       3
+#define CAM_CC_IPE_0_BCR                                       4
+#define CAM_CC_SFE_0_BCR                                       5
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,x1e80100-dispcc.h b/include/dt-bindings/clock/qcom,x1e80100-dispcc.h
new file mode 100644 (file)
index 0000000..d4a83e4
--- /dev/null
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_X1E80100_DISP_CC_H
+#define _DT_BINDINGS_CLK_QCOM_X1E80100_DISP_CC_H
+
+/* DISP_CC clocks */
+#define DISP_CC_MDSS_ACCU_CLK                                  0
+#define DISP_CC_MDSS_AHB1_CLK                                  1
+#define DISP_CC_MDSS_AHB_CLK                                   2
+#define DISP_CC_MDSS_AHB_CLK_SRC                               3
+#define DISP_CC_MDSS_BYTE0_CLK                                 4
+#define DISP_CC_MDSS_BYTE0_CLK_SRC                             5
+#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC                         6
+#define DISP_CC_MDSS_BYTE0_INTF_CLK                            7
+#define DISP_CC_MDSS_BYTE1_CLK                                 8
+#define DISP_CC_MDSS_BYTE1_CLK_SRC                             9
+#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC                         10
+#define DISP_CC_MDSS_BYTE1_INTF_CLK                            11
+#define DISP_CC_MDSS_DPTX0_AUX_CLK                             12
+#define DISP_CC_MDSS_DPTX0_AUX_CLK_SRC                         13
+#define DISP_CC_MDSS_DPTX0_LINK_CLK                            14
+#define DISP_CC_MDSS_DPTX0_LINK_CLK_SRC                                15
+#define DISP_CC_MDSS_DPTX0_LINK_DIV_CLK_SRC                    16
+#define DISP_CC_MDSS_DPTX0_LINK_INTF_CLK                       17
+#define DISP_CC_MDSS_DPTX0_PIXEL0_CLK                          18
+#define DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC                      19
+#define DISP_CC_MDSS_DPTX0_PIXEL1_CLK                          20
+#define DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC                      21
+#define DISP_CC_MDSS_DPTX0_USB_ROUTER_LINK_INTF_CLK            22
+#define DISP_CC_MDSS_DPTX1_AUX_CLK                             23
+#define DISP_CC_MDSS_DPTX1_AUX_CLK_SRC                         24
+#define DISP_CC_MDSS_DPTX1_LINK_CLK                            25
+#define DISP_CC_MDSS_DPTX1_LINK_CLK_SRC                                26
+#define DISP_CC_MDSS_DPTX1_LINK_DIV_CLK_SRC                    27
+#define DISP_CC_MDSS_DPTX1_LINK_INTF_CLK                       28
+#define DISP_CC_MDSS_DPTX1_PIXEL0_CLK                          29
+#define DISP_CC_MDSS_DPTX1_PIXEL0_CLK_SRC                      30
+#define DISP_CC_MDSS_DPTX1_PIXEL1_CLK                          31
+#define DISP_CC_MDSS_DPTX1_PIXEL1_CLK_SRC                      32
+#define DISP_CC_MDSS_DPTX1_USB_ROUTER_LINK_INTF_CLK            33
+#define DISP_CC_MDSS_DPTX2_AUX_CLK                             34
+#define DISP_CC_MDSS_DPTX2_AUX_CLK_SRC                         35
+#define DISP_CC_MDSS_DPTX2_LINK_CLK                            36
+#define DISP_CC_MDSS_DPTX2_LINK_CLK_SRC                                37
+#define DISP_CC_MDSS_DPTX2_LINK_DIV_CLK_SRC                    38
+#define DISP_CC_MDSS_DPTX2_LINK_INTF_CLK                       39
+#define DISP_CC_MDSS_DPTX2_PIXEL0_CLK                          40
+#define DISP_CC_MDSS_DPTX2_PIXEL0_CLK_SRC                      41
+#define DISP_CC_MDSS_DPTX2_PIXEL1_CLK                          42
+#define DISP_CC_MDSS_DPTX2_PIXEL1_CLK_SRC                      43
+#define DISP_CC_MDSS_DPTX2_USB_ROUTER_LINK_INTF_CLK            44
+#define DISP_CC_MDSS_DPTX3_AUX_CLK                             45
+#define DISP_CC_MDSS_DPTX3_AUX_CLK_SRC                         46
+#define DISP_CC_MDSS_DPTX3_LINK_CLK                            47
+#define DISP_CC_MDSS_DPTX3_LINK_CLK_SRC                                48
+#define DISP_CC_MDSS_DPTX3_LINK_DIV_CLK_SRC                    49
+#define DISP_CC_MDSS_DPTX3_LINK_INTF_CLK                       50
+#define DISP_CC_MDSS_DPTX3_PIXEL0_CLK                          51
+#define DISP_CC_MDSS_DPTX3_PIXEL0_CLK_SRC                      52
+#define DISP_CC_MDSS_ESC0_CLK                                  53
+#define DISP_CC_MDSS_ESC0_CLK_SRC                              54
+#define DISP_CC_MDSS_ESC1_CLK                                  55
+#define DISP_CC_MDSS_ESC1_CLK_SRC                              56
+#define DISP_CC_MDSS_MDP1_CLK                                  57
+#define DISP_CC_MDSS_MDP_CLK                                   58
+#define DISP_CC_MDSS_MDP_CLK_SRC                               59
+#define DISP_CC_MDSS_MDP_LUT1_CLK                              60
+#define DISP_CC_MDSS_MDP_LUT_CLK                               61
+#define DISP_CC_MDSS_NON_GDSC_AHB_CLK                          62
+#define DISP_CC_MDSS_PCLK0_CLK                                 63
+#define DISP_CC_MDSS_PCLK0_CLK_SRC                             64
+#define DISP_CC_MDSS_PCLK1_CLK                                 65
+#define DISP_CC_MDSS_PCLK1_CLK_SRC                             66
+#define DISP_CC_MDSS_RSCC_AHB_CLK                              67
+#define DISP_CC_MDSS_RSCC_VSYNC_CLK                            68
+#define DISP_CC_MDSS_VSYNC1_CLK                                        69
+#define DISP_CC_MDSS_VSYNC_CLK                                 70
+#define DISP_CC_MDSS_VSYNC_CLK_SRC                             71
+#define DISP_CC_PLL0                                           72
+#define DISP_CC_PLL1                                           73
+#define DISP_CC_SLEEP_CLK                                      74
+#define DISP_CC_SLEEP_CLK_SRC                                  75
+#define DISP_CC_XO_CLK                                         76
+#define DISP_CC_XO_CLK_SRC                                     77
+
+/* DISP_CC resets */
+#define DISP_CC_MDSS_CORE_BCR                                  0
+#define DISP_CC_MDSS_CORE_INT2_BCR                             1
+#define DISP_CC_MDSS_RSCC_BCR                                  2
+
+/* DISP_CC GDSCR */
+#define MDSS_GDSC                                              0
+#define MDSS_INT2_GDSC                                         1
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,x1e80100-gpucc.h b/include/dt-bindings/clock/qcom,x1e80100-gpucc.h
new file mode 100644 (file)
index 0000000..61a3a8f
--- /dev/null
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_X1E80100_GPU_CC_H
+#define _DT_BINDINGS_CLK_QCOM_X1E80100_GPU_CC_H
+
+/* GPU_CC clocks */
+#define GPU_CC_AHB_CLK                                         0
+#define GPU_CC_CB_CLK                                          1
+#define GPU_CC_CRC_AHB_CLK                                     2
+#define GPU_CC_CX_FF_CLK                                       3
+#define GPU_CC_CX_GMU_CLK                                      4
+#define GPU_CC_CXO_AON_CLK                                     5
+#define GPU_CC_CXO_CLK                                         6
+#define GPU_CC_DEMET_CLK                                       7
+#define GPU_CC_DEMET_DIV_CLK_SRC                               8
+#define GPU_CC_FF_CLK_SRC                                      9
+#define GPU_CC_FREQ_MEASURE_CLK                                        10
+#define GPU_CC_GMU_CLK_SRC                                     11
+#define GPU_CC_GX_GMU_CLK                                      12
+#define GPU_CC_GX_VSENSE_CLK                                   13
+#define GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK                         14
+#define GPU_CC_HUB_AON_CLK                                     15
+#define GPU_CC_HUB_CLK_SRC                                     16
+#define GPU_CC_HUB_CX_INT_CLK                                  17
+#define GPU_CC_MEMNOC_GFX_CLK                                  18
+#define GPU_CC_MND1X_0_GFX3D_CLK                               19
+#define GPU_CC_MND1X_1_GFX3D_CLK                               20
+#define GPU_CC_PLL0                                            21
+#define GPU_CC_PLL1                                            22
+#define GPU_CC_SLEEP_CLK                                       23
+#define GPU_CC_XO_CLK_SRC                                      24
+#define GPU_CC_XO_DIV_CLK_SRC                                  25
+
+/* GDSCs */
+#define GPU_CX_GDSC                                            0
+#define GPU_GX_GDSC                                            1
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,x1e80100-tcsr.h b/include/dt-bindings/clock/qcom,x1e80100-tcsr.h
new file mode 100644 (file)
index 0000000..bae2c46
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_X1E80100_TCSR_CC_H
+#define _DT_BINDINGS_CLK_QCOM_X1E80100_TCSR_CC_H
+
+/* TCSR CC clocks */
+#define TCSR_PCIE_2L_4_CLKREF_EN                               0
+#define TCSR_PCIE_2L_5_CLKREF_EN                               1
+#define TCSR_PCIE_8L_CLKREF_EN                                 2
+#define TCSR_USB3_MP0_CLKREF_EN                                        3
+#define TCSR_USB3_MP1_CLKREF_EN                                        4
+#define TCSR_USB2_1_CLKREF_EN                                  5
+#define TCSR_UFS_PHY_CLKREF_EN                                 6
+#define TCSR_USB4_1_CLKREF_EN                                  7
+#define TCSR_USB4_2_CLKREF_EN                                  8
+#define TCSR_USB2_2_CLKREF_EN                                  9
+#define TCSR_PCIE_4L_CLKREF_EN                                 10
+#define TCSR_EDP_CLKREF_EN                                     11
+
+#endif
diff --git a/include/dt-bindings/clock/renesas,r8a779h0-cpg-mssr.h b/include/dt-bindings/clock/renesas,r8a779h0-cpg-mssr.h
new file mode 100644 (file)
index 0000000..7ab6cfb
--- /dev/null
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2023 Renesas Electronics Corp.
+ */
+#ifndef __DT_BINDINGS_CLOCK_RENESAS_R8A779H0_CPG_MSSR_H__
+#define __DT_BINDINGS_CLOCK_RENESAS_R8A779H0_CPG_MSSR_H__
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+/* r8a779h0 CPG Core Clocks */
+
+#define R8A779H0_CLK_ZX                        0
+#define R8A779H0_CLK_ZD                        1
+#define R8A779H0_CLK_ZS                        2
+#define R8A779H0_CLK_ZT                        3
+#define R8A779H0_CLK_ZTR               4
+#define R8A779H0_CLK_S0D2              5
+#define R8A779H0_CLK_S0D3              6
+#define R8A779H0_CLK_S0D4              7
+#define R8A779H0_CLK_S0D1_VIO          8
+#define R8A779H0_CLK_S0D2_VIO          9
+#define R8A779H0_CLK_S0D4_VIO          10
+#define R8A779H0_CLK_S0D8_VIO          11
+#define R8A779H0_CLK_VIOBUSD1          12
+#define R8A779H0_CLK_VIOBUSD2          13
+#define R8A779H0_CLK_S0D1_VC           14
+#define R8A779H0_CLK_S0D2_VC           15
+#define R8A779H0_CLK_S0D4_VC           16
+#define R8A779H0_CLK_VCBUSD1           17
+#define R8A779H0_CLK_VCBUSD2           18
+#define R8A779H0_CLK_S0D2_MM           19
+#define R8A779H0_CLK_S0D4_MM           20
+#define R8A779H0_CLK_S0D2_U3DG         21
+#define R8A779H0_CLK_S0D4_U3DG         22
+#define R8A779H0_CLK_S0D2_RT           23
+#define R8A779H0_CLK_S0D3_RT           24
+#define R8A779H0_CLK_S0D4_RT           25
+#define R8A779H0_CLK_S0D6_RT           26
+#define R8A779H0_CLK_S0D2_PER          27
+#define R8A779H0_CLK_S0D3_PER          28
+#define R8A779H0_CLK_S0D4_PER          29
+#define R8A779H0_CLK_S0D6_PER          30
+#define R8A779H0_CLK_S0D12_PER         31
+#define R8A779H0_CLK_S0D24_PER         32
+#define R8A779H0_CLK_S0D1_HSC          33
+#define R8A779H0_CLK_S0D2_HSC          34
+#define R8A779H0_CLK_S0D4_HSC          35
+#define R8A779H0_CLK_S0D8_HSC          36
+#define R8A779H0_CLK_SVD1_IR           37
+#define R8A779H0_CLK_SVD2_IR           38
+#define R8A779H0_CLK_IMPAD1            39
+#define R8A779H0_CLK_IMPAD4            40
+#define R8A779H0_CLK_IMPB              41
+#define R8A779H0_CLK_SVD1_VIP          42
+#define R8A779H0_CLK_SVD2_VIP          43
+#define R8A779H0_CLK_CL                        44
+#define R8A779H0_CLK_CL16M             45
+#define R8A779H0_CLK_CL16M_MM          46
+#define R8A779H0_CLK_CL16M_RT          47
+#define R8A779H0_CLK_CL16M_PER         48
+#define R8A779H0_CLK_CL16M_HSC         49
+#define R8A779H0_CLK_ZC0               50
+#define R8A779H0_CLK_ZC1               51
+#define R8A779H0_CLK_ZC2               52
+#define R8A779H0_CLK_ZC3               53
+#define R8A779H0_CLK_ZB3               54
+#define R8A779H0_CLK_ZB3D2             55
+#define R8A779H0_CLK_ZB3D4             56
+#define R8A779H0_CLK_ZG                        57
+#define R8A779H0_CLK_SD0H              58
+#define R8A779H0_CLK_SD0               59
+#define R8A779H0_CLK_RPC               60
+#define R8A779H0_CLK_RPCD2             61
+#define R8A779H0_CLK_MSO               62
+#define R8A779H0_CLK_CANFD             63
+#define R8A779H0_CLK_CSI               64
+#define R8A779H0_CLK_FRAY              65
+#define R8A779H0_CLK_IPC               66
+#define R8A779H0_CLK_SASYNCRT          67
+#define R8A779H0_CLK_SASYNCPERD1       68
+#define R8A779H0_CLK_SASYNCPERD2       69
+#define R8A779H0_CLK_SASYNCPERD4       70
+#define R8A779H0_CLK_DSIEXT            71
+#define R8A779H0_CLK_DSIREF            72
+#define R8A779H0_CLK_ADGH              73
+#define R8A779H0_CLK_OSC               74
+#define R8A779H0_CLK_ZR0               75
+#define R8A779H0_CLK_ZR1               76
+#define R8A779H0_CLK_ZR2               77
+#define R8A779H0_CLK_RGMII             78
+#define R8A779H0_CLK_CPEX              79
+#define R8A779H0_CLK_CP                        80
+#define R8A779H0_CLK_CBFUSA            81
+#define R8A779H0_CLK_R                 82
+
+#endif /* __DT_BINDINGS_CLOCK_RENESAS_R8A779H0_CPG_MSSR_H__ */
index 5790b1391201d4574580075ba68bbe4eeeff95f9..0c7d3ca2d5bc0cde703b53cd68140c38b2c635d3 100644 (file)
 #define ACLK_AV1_PRE                   718
 #define PCLK_AV1_PRE                   719
 #define HCLK_SDIO_PRE                  720
-
-#define CLK_NR_CLKS                    (HCLK_SDIO_PRE + 1)
+#define PCLK_VO1GRF                    721
 
 /* scmi-clocks indices */
 
index 8d73a9c51e2b616ebdcc0692dfe80d466c3d826c..a4e4f92713954b634e18265fad33eb9acb4579e4 100644 (file)
 #define STM32F7_RCC_APB2_SAI1          22
 #define STM32F7_RCC_APB2_SAI2          23
 #define STM32F7_RCC_APB2_LTDC          26
+#define STM32F7_RCC_APB2_DSI           27
 
 #define STM32F7_APB2_RESET(bit)        (STM32F7_RCC_APB2_##bit + (0x24 * 8))
 #define STM32F7_APB2_CLOCK(bit)        (STM32F7_RCC_APB2_##bit + 0xA0)
diff --git a/include/dt-bindings/power/renesas,r8a779h0-sysc.h b/include/dt-bindings/power/renesas,r8a779h0-sysc.h
new file mode 100644 (file)
index 0000000..f27976f
--- /dev/null
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2023 Renesas Electronics Corp.
+ */
+#ifndef __DT_BINDINGS_POWER_RENESAS_R8A779H0_SYSC_H__
+#define __DT_BINDINGS_POWER_RENESAS_R8A779H0_SYSC_H__
+
+/*
+ * These power domain indices match the Power Domain Register Numbers (PDR)
+ */
+
+#define R8A779H0_PD_A1E0D0C0           0
+#define R8A779H0_PD_A1E0D0C1           1
+#define R8A779H0_PD_A1E0D0C2           2
+#define R8A779H0_PD_A1E0D0C3           3
+#define R8A779H0_PD_A2E0D0             16
+#define R8A779H0_PD_A3CR0              21
+#define R8A779H0_PD_A3CR1              22
+#define R8A779H0_PD_A3CR2              23
+#define R8A779H0_PD_A33DGA             24
+#define R8A779H0_PD_A23DGB             25
+#define R8A779H0_PD_C4                 31
+#define R8A779H0_PD_A1DSP0             33
+#define R8A779H0_PD_A2IMP01            34
+#define R8A779H0_PD_A2PSC              35
+#define R8A779H0_PD_A2CV0              36
+#define R8A779H0_PD_A2CV1              37
+#define R8A779H0_PD_A3IMR0             38
+#define R8A779H0_PD_A3IMR1             39
+#define R8A779H0_PD_A3VC               40
+#define R8A779H0_PD_A2CN0              42
+#define R8A779H0_PD_A1CN0              44
+#define R8A779H0_PD_A1DSP1             45
+#define R8A779H0_PD_A2DMA              47
+#define R8A779H0_PD_A2CV2              48
+#define R8A779H0_PD_A2CV3              49
+#define R8A779H0_PD_A3IMR2             50
+#define R8A779H0_PD_A3IMR3             51
+#define R8A779H0_PD_A3PCI              52
+#define R8A779H0_PD_A2PCIPHY           53
+#define R8A779H0_PD_A3VIP0             56
+#define R8A779H0_PD_A3VIP2             58
+#define R8A779H0_PD_A3ISP0             60
+#define R8A779H0_PD_A3DUL              62
+
+/* Always-on power area */
+#define R8A779H0_PD_ALWAYS_ON          64
+
+#endif /* __DT_BINDINGS_POWER_RENESAS_R8A779H0_SYSC_H__ */
diff --git a/include/dt-bindings/reset/qcom,x1e80100-gpucc.h b/include/dt-bindings/reset/qcom,x1e80100-gpucc.h
new file mode 100644 (file)
index 0000000..32b43e7
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_RESET_QCOM_X1E80100_GPU_CC_H
+#define _DT_BINDINGS_RESET_QCOM_X1E80100_GPU_CC_H
+
+#define GPUCC_GPU_CC_ACD_BCR                                   0
+#define GPUCC_GPU_CC_CB_BCR                                    1
+#define GPUCC_GPU_CC_CX_BCR                                    2
+#define GPUCC_GPU_CC_FAST_HUB_BCR                              3
+#define GPUCC_GPU_CC_FF_BCR                                    4
+#define GPUCC_GPU_CC_GFX3D_AON_BCR                             5
+#define GPUCC_GPU_CC_GMU_BCR                                   6
+#define GPUCC_GPU_CC_GX_BCR                                    7
+#define GPUCC_GPU_CC_XO_BCR                                    8
+
+#endif
index fcb4a4940ace74c98aacb1b18c62eee54a95ad4e..61637ef323026c8f87112af494eaca70fb963a17 100644 (file)
@@ -579,12 +579,12 @@ void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt,
 
 void __noreturn __kunit_abort(struct kunit *test);
 
-void __kunit_do_failed_assertion(struct kunit *test,
-                              const struct kunit_loc *loc,
-                              enum kunit_assert_type type,
-                              const struct kunit_assert *assert,
-                              assert_format_t assert_format,
-                              const char *fmt, ...);
+void __printf(6, 7) __kunit_do_failed_assertion(struct kunit *test,
+                                               const struct kunit_loc *loc,
+                                               enum kunit_assert_type type,
+                                               const struct kunit_assert *assert,
+                                               assert_format_t assert_format,
+                                               const char *fmt, ...);
 
 #define _KUNIT_FAILED(test, assert_type, assert_class, assert_format, INITIALIZER, fmt, ...) do { \
        static const struct kunit_loc __loc = KUNIT_CURRENT_LOC;               \
index dc7ed2f4688614a992eac65d11e25d841943ae45..2b90c48a6a871dc62b4292aa3e062dd12c270189 100644 (file)
@@ -85,8 +85,10 @@ int amd_iommu_pc_get_reg(struct amd_iommu *iommu, u8 bank, u8 cntr, u8 fxn,
                u64 *value);
 struct amd_iommu *get_amd_iommu(unsigned int idx);
 
-#ifdef CONFIG_AMD_MEM_ENCRYPT
-int amd_iommu_snp_enable(void);
+#ifdef CONFIG_KVM_AMD_SEV
+int amd_iommu_snp_disable(void);
+#else
+static inline int amd_iommu_snp_disable(void) { return 0; }
 #endif
 
 #endif /* _ASM_X86_AMD_IOMMU_H */
index 3d0fde57ba90eb7b6bf6a295181f06ab73cfb03b..c906f666ff5d22007d1732bb0706d891ded27551 100644 (file)
@@ -209,7 +209,7 @@ bool ffa_device_is_valid(struct ffa_device *ffa_dev) { return false; }
 #define module_ffa_driver(__ffa_driver)        \
        module_driver(__ffa_driver, ffa_register, ffa_unregister)
 
-extern struct bus_type ffa_bus_type;
+extern const struct bus_type ffa_bus_type;
 
 /* FFA transport related */
 struct ffa_partition_info {
index 33c9ff4afb492f4852d503f53f88029b7a72c797..19b778d08600f1d1e1bf25a8cd0e8a390b39cac5 100644 (file)
@@ -120,4 +120,5 @@ extern void async_synchronize_cookie(async_cookie_t cookie);
 extern void async_synchronize_cookie_domain(async_cookie_t cookie,
                                            struct async_domain *domain);
 extern bool current_is_async(void);
+extern void async_init(void);
 #endif
index 5e95faa959c42bfe68823669d467f2abdd09a4f7..956bcba5dbf2f8ee2432af3989043fc9dce0776b 100644 (file)
@@ -2005,6 +2005,7 @@ raw_atomic_xchg_relaxed(atomic_t *v, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_cmpxchg() elsewhere.
  *
@@ -2033,6 +2034,7 @@ raw_atomic_cmpxchg(atomic_t *v, int old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with acquire ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_cmpxchg_acquire() elsewhere.
  *
@@ -2061,6 +2063,7 @@ raw_atomic_cmpxchg_acquire(atomic_t *v, int old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with release ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_cmpxchg_release() elsewhere.
  *
@@ -2088,6 +2091,7 @@ raw_atomic_cmpxchg_release(atomic_t *v, int old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with relaxed ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_cmpxchg_relaxed() elsewhere.
  *
@@ -2112,7 +2116,8 @@ raw_atomic_cmpxchg_relaxed(atomic_t *v, int old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with full ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_try_cmpxchg() elsewhere.
  *
@@ -2145,7 +2150,8 @@ raw_atomic_try_cmpxchg(atomic_t *v, int *old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with acquire ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_try_cmpxchg_acquire() elsewhere.
  *
@@ -2178,7 +2184,8 @@ raw_atomic_try_cmpxchg_acquire(atomic_t *v, int *old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with release ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_try_cmpxchg_release() elsewhere.
  *
@@ -2210,7 +2217,8 @@ raw_atomic_try_cmpxchg_release(atomic_t *v, int *old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with relaxed ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_try_cmpxchg_relaxed() elsewhere.
  *
@@ -2403,6 +2411,7 @@ raw_atomic_add_negative_relaxed(int i, atomic_t *v)
  * @u: int value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_fetch_add_unless() elsewhere.
  *
@@ -2432,6 +2441,7 @@ raw_atomic_fetch_add_unless(atomic_t *v, int a, int u)
  * @u: int value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_add_unless() elsewhere.
  *
@@ -2452,6 +2462,7 @@ raw_atomic_add_unless(atomic_t *v, int a, int u)
  * @v: pointer to atomic_t
  *
  * If (@v != 0), atomically updates @v to (@v + 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_inc_not_zero() elsewhere.
  *
@@ -2472,6 +2483,7 @@ raw_atomic_inc_not_zero(atomic_t *v)
  * @v: pointer to atomic_t
  *
  * If (@v >= 0), atomically updates @v to (@v + 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_inc_unless_negative() elsewhere.
  *
@@ -2499,6 +2511,7 @@ raw_atomic_inc_unless_negative(atomic_t *v)
  * @v: pointer to atomic_t
  *
  * If (@v <= 0), atomically updates @v to (@v - 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_dec_unless_positive() elsewhere.
  *
@@ -2526,6 +2539,7 @@ raw_atomic_dec_unless_positive(atomic_t *v)
  * @v: pointer to atomic_t
  *
  * If (@v > 0), atomically updates @v to (@v - 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_dec_if_positive() elsewhere.
  *
@@ -4117,6 +4131,7 @@ raw_atomic64_xchg_relaxed(atomic64_t *v, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_cmpxchg() elsewhere.
  *
@@ -4145,6 +4160,7 @@ raw_atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with acquire ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_cmpxchg_acquire() elsewhere.
  *
@@ -4173,6 +4189,7 @@ raw_atomic64_cmpxchg_acquire(atomic64_t *v, s64 old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with release ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_cmpxchg_release() elsewhere.
  *
@@ -4200,6 +4217,7 @@ raw_atomic64_cmpxchg_release(atomic64_t *v, s64 old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with relaxed ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_cmpxchg_relaxed() elsewhere.
  *
@@ -4224,7 +4242,8 @@ raw_atomic64_cmpxchg_relaxed(atomic64_t *v, s64 old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with full ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_try_cmpxchg() elsewhere.
  *
@@ -4257,7 +4276,8 @@ raw_atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with acquire ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_try_cmpxchg_acquire() elsewhere.
  *
@@ -4290,7 +4310,8 @@ raw_atomic64_try_cmpxchg_acquire(atomic64_t *v, s64 *old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with release ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_try_cmpxchg_release() elsewhere.
  *
@@ -4322,7 +4343,8 @@ raw_atomic64_try_cmpxchg_release(atomic64_t *v, s64 *old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with relaxed ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_try_cmpxchg_relaxed() elsewhere.
  *
@@ -4515,6 +4537,7 @@ raw_atomic64_add_negative_relaxed(s64 i, atomic64_t *v)
  * @u: s64 value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_fetch_add_unless() elsewhere.
  *
@@ -4544,6 +4567,7 @@ raw_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
  * @u: s64 value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_add_unless() elsewhere.
  *
@@ -4564,6 +4588,7 @@ raw_atomic64_add_unless(atomic64_t *v, s64 a, s64 u)
  * @v: pointer to atomic64_t
  *
  * If (@v != 0), atomically updates @v to (@v + 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_inc_not_zero() elsewhere.
  *
@@ -4584,6 +4609,7 @@ raw_atomic64_inc_not_zero(atomic64_t *v)
  * @v: pointer to atomic64_t
  *
  * If (@v >= 0), atomically updates @v to (@v + 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_inc_unless_negative() elsewhere.
  *
@@ -4611,6 +4637,7 @@ raw_atomic64_inc_unless_negative(atomic64_t *v)
  * @v: pointer to atomic64_t
  *
  * If (@v <= 0), atomically updates @v to (@v - 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_dec_unless_positive() elsewhere.
  *
@@ -4638,6 +4665,7 @@ raw_atomic64_dec_unless_positive(atomic64_t *v)
  * @v: pointer to atomic64_t
  *
  * If (@v > 0), atomically updates @v to (@v - 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic64_dec_if_positive() elsewhere.
  *
@@ -4662,4 +4690,4 @@ raw_atomic64_dec_if_positive(atomic64_t *v)
 }
 
 #endif /* _LINUX_ATOMIC_FALLBACK_H */
-// eec048affea735b8464f58e6d96992101f8f85f1
+// 14850c0b0db20c62fdc78ccd1d42b98b88d76331
index 54d7bbe0aeaa6aeaa6dfa81b9b1bef04f9048e42..debd487fe971607b56f2a8bc403bb22ad305fa59 100644 (file)
@@ -1182,6 +1182,7 @@ atomic_xchg_relaxed(atomic_t *v, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_cmpxchg() there.
  *
@@ -1202,6 +1203,7 @@ atomic_cmpxchg(atomic_t *v, int old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with acquire ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_cmpxchg_acquire() there.
  *
@@ -1221,6 +1223,7 @@ atomic_cmpxchg_acquire(atomic_t *v, int old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with release ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_cmpxchg_release() there.
  *
@@ -1241,6 +1244,7 @@ atomic_cmpxchg_release(atomic_t *v, int old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with relaxed ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_cmpxchg_relaxed() there.
  *
@@ -1260,7 +1264,8 @@ atomic_cmpxchg_relaxed(atomic_t *v, int old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with full ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_try_cmpxchg() there.
  *
@@ -1282,7 +1287,8 @@ atomic_try_cmpxchg(atomic_t *v, int *old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with acquire ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_try_cmpxchg_acquire() there.
  *
@@ -1303,7 +1309,8 @@ atomic_try_cmpxchg_acquire(atomic_t *v, int *old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with release ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_try_cmpxchg_release() there.
  *
@@ -1325,7 +1332,8 @@ atomic_try_cmpxchg_release(atomic_t *v, int *old, int new)
  * @new: int value to assign
  *
  * If (@v == @old), atomically updates @v to @new with relaxed ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_try_cmpxchg_relaxed() there.
  *
@@ -1475,6 +1483,7 @@ atomic_add_negative_relaxed(int i, atomic_t *v)
  * @u: int value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_fetch_add_unless() there.
  *
@@ -1495,6 +1504,7 @@ atomic_fetch_add_unless(atomic_t *v, int a, int u)
  * @u: int value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_add_unless() there.
  *
@@ -1513,6 +1523,7 @@ atomic_add_unless(atomic_t *v, int a, int u)
  * @v: pointer to atomic_t
  *
  * If (@v != 0), atomically updates @v to (@v + 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_inc_not_zero() there.
  *
@@ -1531,6 +1542,7 @@ atomic_inc_not_zero(atomic_t *v)
  * @v: pointer to atomic_t
  *
  * If (@v >= 0), atomically updates @v to (@v + 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_inc_unless_negative() there.
  *
@@ -1549,6 +1561,7 @@ atomic_inc_unless_negative(atomic_t *v)
  * @v: pointer to atomic_t
  *
  * If (@v <= 0), atomically updates @v to (@v - 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_dec_unless_positive() there.
  *
@@ -1567,6 +1580,7 @@ atomic_dec_unless_positive(atomic_t *v)
  * @v: pointer to atomic_t
  *
  * If (@v > 0), atomically updates @v to (@v - 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_dec_if_positive() there.
  *
@@ -2746,6 +2760,7 @@ atomic64_xchg_relaxed(atomic64_t *v, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_cmpxchg() there.
  *
@@ -2766,6 +2781,7 @@ atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with acquire ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_cmpxchg_acquire() there.
  *
@@ -2785,6 +2801,7 @@ atomic64_cmpxchg_acquire(atomic64_t *v, s64 old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with release ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_cmpxchg_release() there.
  *
@@ -2805,6 +2822,7 @@ atomic64_cmpxchg_release(atomic64_t *v, s64 old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with relaxed ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_cmpxchg_relaxed() there.
  *
@@ -2824,7 +2842,8 @@ atomic64_cmpxchg_relaxed(atomic64_t *v, s64 old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with full ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_try_cmpxchg() there.
  *
@@ -2846,7 +2865,8 @@ atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with acquire ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_try_cmpxchg_acquire() there.
  *
@@ -2867,7 +2887,8 @@ atomic64_try_cmpxchg_acquire(atomic64_t *v, s64 *old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with release ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_try_cmpxchg_release() there.
  *
@@ -2889,7 +2910,8 @@ atomic64_try_cmpxchg_release(atomic64_t *v, s64 *old, s64 new)
  * @new: s64 value to assign
  *
  * If (@v == @old), atomically updates @v to @new with relaxed ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_try_cmpxchg_relaxed() there.
  *
@@ -3039,6 +3061,7 @@ atomic64_add_negative_relaxed(s64 i, atomic64_t *v)
  * @u: s64 value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_fetch_add_unless() there.
  *
@@ -3059,6 +3082,7 @@ atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
  * @u: s64 value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_add_unless() there.
  *
@@ -3077,6 +3101,7 @@ atomic64_add_unless(atomic64_t *v, s64 a, s64 u)
  * @v: pointer to atomic64_t
  *
  * If (@v != 0), atomically updates @v to (@v + 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_inc_not_zero() there.
  *
@@ -3095,6 +3120,7 @@ atomic64_inc_not_zero(atomic64_t *v)
  * @v: pointer to atomic64_t
  *
  * If (@v >= 0), atomically updates @v to (@v + 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_inc_unless_negative() there.
  *
@@ -3113,6 +3139,7 @@ atomic64_inc_unless_negative(atomic64_t *v)
  * @v: pointer to atomic64_t
  *
  * If (@v <= 0), atomically updates @v to (@v - 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_dec_unless_positive() there.
  *
@@ -3131,6 +3158,7 @@ atomic64_dec_unless_positive(atomic64_t *v)
  * @v: pointer to atomic64_t
  *
  * If (@v > 0), atomically updates @v to (@v - 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic64_dec_if_positive() there.
  *
@@ -4310,6 +4338,7 @@ atomic_long_xchg_relaxed(atomic_long_t *v, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_cmpxchg() there.
  *
@@ -4330,6 +4359,7 @@ atomic_long_cmpxchg(atomic_long_t *v, long old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with acquire ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_cmpxchg_acquire() there.
  *
@@ -4349,6 +4379,7 @@ atomic_long_cmpxchg_acquire(atomic_long_t *v, long old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with release ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_cmpxchg_release() there.
  *
@@ -4369,6 +4400,7 @@ atomic_long_cmpxchg_release(atomic_long_t *v, long old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with relaxed ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_cmpxchg_relaxed() there.
  *
@@ -4388,7 +4420,8 @@ atomic_long_cmpxchg_relaxed(atomic_long_t *v, long old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with full ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_try_cmpxchg() there.
  *
@@ -4410,7 +4443,8 @@ atomic_long_try_cmpxchg(atomic_long_t *v, long *old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with acquire ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_try_cmpxchg_acquire() there.
  *
@@ -4431,7 +4465,8 @@ atomic_long_try_cmpxchg_acquire(atomic_long_t *v, long *old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with release ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_try_cmpxchg_release() there.
  *
@@ -4453,7 +4488,8 @@ atomic_long_try_cmpxchg_release(atomic_long_t *v, long *old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with relaxed ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_try_cmpxchg_relaxed() there.
  *
@@ -4603,6 +4639,7 @@ atomic_long_add_negative_relaxed(long i, atomic_long_t *v)
  * @u: long value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_fetch_add_unless() there.
  *
@@ -4623,6 +4660,7 @@ atomic_long_fetch_add_unless(atomic_long_t *v, long a, long u)
  * @u: long value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_add_unless() there.
  *
@@ -4641,6 +4679,7 @@ atomic_long_add_unless(atomic_long_t *v, long a, long u)
  * @v: pointer to atomic_long_t
  *
  * If (@v != 0), atomically updates @v to (@v + 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_inc_not_zero() there.
  *
@@ -4659,6 +4698,7 @@ atomic_long_inc_not_zero(atomic_long_t *v)
  * @v: pointer to atomic_long_t
  *
  * If (@v >= 0), atomically updates @v to (@v + 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_inc_unless_negative() there.
  *
@@ -4677,6 +4717,7 @@ atomic_long_inc_unless_negative(atomic_long_t *v)
  * @v: pointer to atomic_long_t
  *
  * If (@v <= 0), atomically updates @v to (@v - 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_dec_unless_positive() there.
  *
@@ -4695,6 +4736,7 @@ atomic_long_dec_unless_positive(atomic_long_t *v)
  * @v: pointer to atomic_long_t
  *
  * If (@v > 0), atomically updates @v to (@v - 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Unsafe to use in noinstr code; use raw_atomic_long_dec_if_positive() there.
  *
@@ -5008,4 +5050,4 @@ atomic_long_dec_if_positive(atomic_long_t *v)
 
 
 #endif /* _LINUX_ATOMIC_INSTRUMENTED_H */
-// 2cc4bc990fef44d3836ec108f11b610f3f438184
+// ce5b65e0f1f8a276268b667194581d24bed219d4
index c82947170ddc8a5757d6f3532f967ca0ae8da28b..3ef844b3ab8a3d47235a6e9bbb6b4bcaa00b713d 100644 (file)
@@ -1352,6 +1352,7 @@ raw_atomic_long_xchg_relaxed(atomic_long_t *v, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_cmpxchg() elsewhere.
  *
@@ -1374,6 +1375,7 @@ raw_atomic_long_cmpxchg(atomic_long_t *v, long old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with acquire ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_cmpxchg_acquire() elsewhere.
  *
@@ -1396,6 +1398,7 @@ raw_atomic_long_cmpxchg_acquire(atomic_long_t *v, long old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with release ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_cmpxchg_release() elsewhere.
  *
@@ -1418,6 +1421,7 @@ raw_atomic_long_cmpxchg_release(atomic_long_t *v, long old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with relaxed ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_cmpxchg_relaxed() elsewhere.
  *
@@ -1440,7 +1444,8 @@ raw_atomic_long_cmpxchg_relaxed(atomic_long_t *v, long old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with full ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_try_cmpxchg() elsewhere.
  *
@@ -1463,7 +1468,8 @@ raw_atomic_long_try_cmpxchg(atomic_long_t *v, long *old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with acquire ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_try_cmpxchg_acquire() elsewhere.
  *
@@ -1486,7 +1492,8 @@ raw_atomic_long_try_cmpxchg_acquire(atomic_long_t *v, long *old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with release ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_try_cmpxchg_release() elsewhere.
  *
@@ -1509,7 +1516,8 @@ raw_atomic_long_try_cmpxchg_release(atomic_long_t *v, long *old, long new)
  * @new: long value to assign
  *
  * If (@v == @old), atomically updates @v to @new with relaxed ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_try_cmpxchg_relaxed() elsewhere.
  *
@@ -1677,6 +1685,7 @@ raw_atomic_long_add_negative_relaxed(long i, atomic_long_t *v)
  * @u: long value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_fetch_add_unless() elsewhere.
  *
@@ -1699,6 +1708,7 @@ raw_atomic_long_fetch_add_unless(atomic_long_t *v, long a, long u)
  * @u: long value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_add_unless() elsewhere.
  *
@@ -1719,6 +1729,7 @@ raw_atomic_long_add_unless(atomic_long_t *v, long a, long u)
  * @v: pointer to atomic_long_t
  *
  * If (@v != 0), atomically updates @v to (@v + 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_inc_not_zero() elsewhere.
  *
@@ -1739,6 +1750,7 @@ raw_atomic_long_inc_not_zero(atomic_long_t *v)
  * @v: pointer to atomic_long_t
  *
  * If (@v >= 0), atomically updates @v to (@v + 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_inc_unless_negative() elsewhere.
  *
@@ -1759,6 +1771,7 @@ raw_atomic_long_inc_unless_negative(atomic_long_t *v)
  * @v: pointer to atomic_long_t
  *
  * If (@v <= 0), atomically updates @v to (@v - 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_dec_unless_positive() elsewhere.
  *
@@ -1779,6 +1792,7 @@ raw_atomic_long_dec_unless_positive(atomic_long_t *v)
  * @v: pointer to atomic_long_t
  *
  * If (@v > 0), atomically updates @v to (@v - 1) with full ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * Safe to use in noinstr code; prefer atomic_long_dec_if_positive() elsewhere.
  *
@@ -1795,4 +1809,4 @@ raw_atomic_long_dec_if_positive(atomic_long_t *v)
 }
 
 #endif /* _LINUX_ATOMIC_LONG_H */
-// 4ef23f98c73cff96d239896175fd26b10b88899e
+// 1c4a26fc77f345342953770ebe3c4d08e7ce2f9a
index 1a97277f99b1b82de9e96eb8b9ca5544f9aa6e3a..8e7af9a03b41dd9261254eb4c6a74b748d625391 100644 (file)
@@ -38,7 +38,6 @@ struct backing_dev_info *bdi_alloc(int node_id);
 
 void wb_start_background_writeback(struct bdi_writeback *wb);
 void wb_workfn(struct work_struct *work);
-void wb_wakeup_delayed(struct bdi_writeback *wb);
 
 void wb_wait_for_completion(struct wb_completion *done);
 
index 99451431e4d65e6f26d75e0ee1d68cf1c130296e..df24c8fb10096f8120686090708c0041b1165fa1 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/align.h>
 #include <linux/bitops.h>
+#include <linux/cleanup.h>
 #include <linux/errno.h>
 #include <linux/find.h>
 #include <linux/limits.h>
@@ -127,6 +128,8 @@ unsigned long *bitmap_alloc_node(unsigned int nbits, gfp_t flags, int node);
 unsigned long *bitmap_zalloc_node(unsigned int nbits, gfp_t flags, int node);
 void bitmap_free(const unsigned long *bitmap);
 
+DEFINE_FREE(bitmap, unsigned long *, if (_T) bitmap_free(_T))
+
 /* Managed variants of the above. */
 unsigned long *devm_bitmap_alloc(struct device *dev,
                                 unsigned int nbits, gfp_t flags);
index 378b2459efe2da03565997d0980ed10656516c17..e253e7bd0d1793f23f1de2fb03a9032c66bbe659 100644 (file)
@@ -20,6 +20,7 @@ struct blk_integrity_iter {
        unsigned int            data_size;
        unsigned short          interval;
        unsigned char           tuple_size;
+       unsigned char           pi_offset;
        const char              *disk_name;
 };
 
index 7a8150a5f051339f680b9df83fa78da48b8c8af1..d3d8fd8e229b61443f5e3e7256dfcb2a19c34513 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/scatterlist.h>
 #include <linux/prefetch.h>
 #include <linux/srcu.h>
+#include <linux/rw_hint.h>
 
 struct blk_mq_tags;
 struct blk_flush_queue;
@@ -135,6 +136,7 @@ struct request {
        struct blk_crypto_keyslot *crypt_keyslot;
 #endif
 
+       enum rw_hint write_hint;
        unsigned short ioprio;
 
        enum mq_rq_state state;
@@ -682,17 +684,19 @@ enum {
 
 #define BLK_MQ_NO_HCTX_IDX     (-1U)
 
-struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set, void *queuedata,
+struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set,
+               struct queue_limits *lim, void *queuedata,
                struct lock_class_key *lkclass);
-#define blk_mq_alloc_disk(set, queuedata)                              \
+#define blk_mq_alloc_disk(set, lim, queuedata)                         \
 ({                                                                     \
        static struct lock_class_key __key;                             \
                                                                        \
-       __blk_mq_alloc_disk(set, queuedata, &__key);                    \
+       __blk_mq_alloc_disk(set, lim, queuedata, &__key);               \
 })
 struct gendisk *blk_mq_alloc_disk_for_queue(struct request_queue *q,
                struct lock_class_key *lkclass);
-struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *);
+struct request_queue *blk_mq_alloc_queue(struct blk_mq_tag_set *set,
+               struct queue_limits *lim, void *queuedata);
 int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
                struct request_queue *q);
 void blk_mq_destroy_queue(struct request_queue *);
index f288c94374b307fb1f47cade7e86943858fd6741..cb1526ec44b5f66572337fff1ba61dcc704a1d19 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/bvec.h>
 #include <linux/device.h>
 #include <linux/ktime.h>
+#include <linux/rw_hint.h>
 
 struct bio_set;
 struct bio;
@@ -206,52 +207,10 @@ static inline bool blk_path_error(blk_status_t error)
        return true;
 }
 
-/*
- * From most significant bit:
- * 1 bit: reserved for other usage, see below
- * 12 bits: original size of bio
- * 51 bits: issue time of bio
- */
-#define BIO_ISSUE_RES_BITS      1
-#define BIO_ISSUE_SIZE_BITS     12
-#define BIO_ISSUE_RES_SHIFT     (64 - BIO_ISSUE_RES_BITS)
-#define BIO_ISSUE_SIZE_SHIFT    (BIO_ISSUE_RES_SHIFT - BIO_ISSUE_SIZE_BITS)
-#define BIO_ISSUE_TIME_MASK     ((1ULL << BIO_ISSUE_SIZE_SHIFT) - 1)
-#define BIO_ISSUE_SIZE_MASK     \
-       (((1ULL << BIO_ISSUE_SIZE_BITS) - 1) << BIO_ISSUE_SIZE_SHIFT)
-#define BIO_ISSUE_RES_MASK      (~((1ULL << BIO_ISSUE_RES_SHIFT) - 1))
-
-/* Reserved bit for blk-throtl */
-#define BIO_ISSUE_THROTL_SKIP_LATENCY (1ULL << 63)
-
 struct bio_issue {
        u64 value;
 };
 
-static inline u64 __bio_issue_time(u64 time)
-{
-       return time & BIO_ISSUE_TIME_MASK;
-}
-
-static inline u64 bio_issue_time(struct bio_issue *issue)
-{
-       return __bio_issue_time(issue->value);
-}
-
-static inline sector_t bio_issue_size(struct bio_issue *issue)
-{
-       return ((issue->value & BIO_ISSUE_SIZE_MASK) >> BIO_ISSUE_SIZE_SHIFT);
-}
-
-static inline void bio_issue_init(struct bio_issue *issue,
-                                      sector_t size)
-{
-       size &= (1ULL << BIO_ISSUE_SIZE_BITS) - 1;
-       issue->value = ((issue->value & BIO_ISSUE_RES_MASK) |
-                       (ktime_get_ns() & BIO_ISSUE_TIME_MASK) |
-                       ((u64)size << BIO_ISSUE_SIZE_SHIFT));
-}
-
 typedef __u32 __bitwise blk_opf_t;
 
 typedef unsigned int blk_qc_t;
@@ -269,6 +228,7 @@ struct bio {
                                                 */
        unsigned short          bi_flags;       /* BIO_* below */
        unsigned short          bi_ioprio;
+       enum rw_hint            bi_write_hint;
        blk_status_t            bi_status;
        atomic_t                __bi_remaining;
 
index 99e4f5e722132c2c4f301816bbab7871f2f2ccb0..f9b87c39cab0478aac030e50174dd5b3fd7c8f16 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/sbitmap.h>
 #include <linux/uuid.h>
 #include <linux/xarray.h>
+#include <linux/file.h>
 
 struct module;
 struct request_queue;
@@ -42,7 +43,7 @@ struct blk_crypto_profile;
 
 extern const struct device_type disk_type;
 extern const struct device_type part_type;
-extern struct class block_class;
+extern const struct class block_class;
 
 /*
  * Maximum number of blkcg policies allowed to be registered concurrently.
@@ -108,6 +109,7 @@ struct blk_integrity {
        const struct blk_integrity_profile      *profile;
        unsigned char                           flags;
        unsigned char                           tuple_size;
+       unsigned char                           pi_offset;
        unsigned char                           interval_exp;
        unsigned char                           tag_size;
 };
@@ -189,8 +191,6 @@ struct gendisk {
         * blk_mq_unfreeze_queue().
         */
        unsigned int            nr_zones;
-       unsigned int            max_open_zones;
-       unsigned int            max_active_zones;
        unsigned long           *conv_zones_bitmap;
        unsigned long           *seq_zones_wlock;
 #endif /* CONFIG_BLK_DEV_ZONED */
@@ -292,6 +292,7 @@ struct queue_limits {
        unsigned int            io_opt;
        unsigned int            max_discard_sectors;
        unsigned int            max_hw_discard_sectors;
+       unsigned int            max_user_discard_sectors;
        unsigned int            max_secure_erase_sectors;
        unsigned int            max_write_zeroes_sectors;
        unsigned int            max_zone_append_sectors;
@@ -307,6 +308,8 @@ struct queue_limits {
        unsigned char           discard_misaligned;
        unsigned char           raid_partial_stripes_expensive;
        bool                    zoned;
+       unsigned int            max_open_zones;
+       unsigned int            max_active_zones;
 
        /*
         * Drivers that set dma_alignment to less than 511 must be prepared to
@@ -325,7 +328,7 @@ void disk_set_zoned(struct gendisk *disk);
 int blkdev_report_zones(struct block_device *bdev, sector_t sector,
                unsigned int nr_zones, report_zones_cb cb, void *data);
 int blkdev_zone_mgmt(struct block_device *bdev, enum req_op op,
-               sector_t sectors, sector_t nr_sectors, gfp_t gfp_mask);
+               sector_t sectors, sector_t nr_sectors);
 int blk_revalidate_disk_zones(struct gendisk *disk,
                void (*update_driver_data)(struct gendisk *disk));
 
@@ -473,6 +476,7 @@ struct request_queue {
 
        struct mutex            sysfs_lock;
        struct mutex            sysfs_dir_lock;
+       struct mutex            limits_lock;
 
        /*
         * for reusing dead hctx instance in case of updating
@@ -639,23 +643,23 @@ static inline bool disk_zone_is_seq(struct gendisk *disk, sector_t sector)
 static inline void disk_set_max_open_zones(struct gendisk *disk,
                unsigned int max_open_zones)
 {
-       disk->max_open_zones = max_open_zones;
+       disk->queue->limits.max_open_zones = max_open_zones;
 }
 
 static inline void disk_set_max_active_zones(struct gendisk *disk,
                unsigned int max_active_zones)
 {
-       disk->max_active_zones = max_active_zones;
+       disk->queue->limits.max_active_zones = max_active_zones;
 }
 
 static inline unsigned int bdev_max_open_zones(struct block_device *bdev)
 {
-       return bdev->bd_disk->max_open_zones;
+       return bdev->bd_disk->queue->limits.max_open_zones;
 }
 
 static inline unsigned int bdev_max_active_zones(struct block_device *bdev)
 {
-       return bdev->bd_disk->max_active_zones;
+       return bdev->bd_disk->queue->limits.max_active_zones;
 }
 
 #else /* CONFIG_BLK_DEV_ZONED */
@@ -763,22 +767,26 @@ static inline u64 sb_bdev_nr_blocks(struct super_block *sb)
 int bdev_disk_changed(struct gendisk *disk, bool invalidate);
 
 void put_disk(struct gendisk *disk);
-struct gendisk *__blk_alloc_disk(int node, struct lock_class_key *lkclass);
+struct gendisk *__blk_alloc_disk(struct queue_limits *lim, int node,
+               struct lock_class_key *lkclass);
 
 /**
  * blk_alloc_disk - allocate a gendisk structure
+ * @lim: queue limits to be used for this disk.
  * @node_id: numa node to allocate on
  *
  * Allocate and pre-initialize a gendisk structure for use with BIO based
  * drivers.
  *
+ * Returns an ERR_PTR on error, else the allocated disk.
+ *
  * Context: can sleep
  */
-#define blk_alloc_disk(node_id)                                                \
+#define blk_alloc_disk(lim, node_id)                                   \
 ({                                                                     \
        static struct lock_class_key __key;                             \
                                                                        \
-       __blk_alloc_disk(node_id, &__key);                              \
+       __blk_alloc_disk(lim, node_id, &__key);                         \
 })
 
 int __register_blkdev(unsigned int major, const char *name,
@@ -861,6 +869,29 @@ static inline unsigned int blk_chunk_sectors_left(sector_t offset,
        return chunk_sectors - (offset & (chunk_sectors - 1));
 }
 
+/**
+ * queue_limits_start_update - start an atomic update of queue limits
+ * @q:         queue to update
+ *
+ * This functions starts an atomic update of the queue limits.  It takes a lock
+ * to prevent other updates and returns a snapshot of the current limits that
+ * the caller can modify.  The caller must call queue_limits_commit_update()
+ * to finish the update.
+ *
+ * Context: process context.  The caller must have frozen the queue or ensured
+ * that there is outstanding I/O by other means.
+ */
+static inline struct queue_limits
+queue_limits_start_update(struct request_queue *q)
+       __acquires(q->limits_lock)
+{
+       mutex_lock(&q->limits_lock);
+       return q->limits;
+}
+int queue_limits_commit_update(struct request_queue *q,
+               struct queue_limits *lim);
+int queue_limits_set(struct request_queue *q, struct queue_limits *lim);
+
 /*
  * Access functions for manipulating queue properties
  */
@@ -894,8 +925,8 @@ extern void blk_set_queue_depth(struct request_queue *q, unsigned int depth);
 extern void blk_set_stacking_limits(struct queue_limits *lim);
 extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                            sector_t offset);
-extern void disk_stack_limits(struct gendisk *disk, struct block_device *bdev,
-                             sector_t offset);
+void queue_limits_stack_bdev(struct queue_limits *t, struct block_device *bdev,
+               sector_t offset, const char *pfx);
 extern void blk_queue_update_dma_pad(struct request_queue *, unsigned int);
 extern void blk_queue_segment_boundary(struct request_queue *, unsigned long);
 extern void blk_queue_virt_boundary(struct request_queue *, unsigned long);
@@ -942,6 +973,7 @@ struct blk_plug {
 
        /* if ios_left is > 1, we can batch tag/rq allocations */
        struct request *cached_rq;
+       u64 cur_ktime;
        unsigned short nr_ios;
 
        unsigned short rq_count;
@@ -972,6 +1004,18 @@ static inline void blk_flush_plug(struct blk_plug *plug, bool async)
                __blk_flush_plug(plug, async);
 }
 
+/*
+ * tsk == current here
+ */
+static inline void blk_plug_invalidate_ts(struct task_struct *tsk)
+{
+       struct blk_plug *plug = tsk->plug;
+
+       if (plug)
+               plug->cur_ktime = 0;
+       current->flags &= ~PF_BLOCK_TS;
+}
+
 int blkdev_issue_flush(struct block_device *bdev);
 long nr_blockdev_pages(void);
 #else /* CONFIG_BLOCK */
@@ -995,6 +1039,10 @@ static inline void blk_flush_plug(struct blk_plug *plug, bool async)
 {
 }
 
+static inline void blk_plug_invalidate_ts(struct task_struct *tsk)
+{
+}
+
 static inline int blkdev_issue_flush(struct block_device *bdev)
 {
        return 0;
@@ -1474,26 +1522,20 @@ extern const struct blk_holder_ops fs_holder_ops;
        (BLK_OPEN_READ | BLK_OPEN_RESTRICT_WRITES | \
         (((flags) & SB_RDONLY) ? 0 : BLK_OPEN_WRITE))
 
-struct bdev_handle {
-       struct block_device *bdev;
-       void *holder;
-       blk_mode_t mode;
-};
-
-struct bdev_handle *bdev_open_by_dev(dev_t dev, blk_mode_t mode, void *holder,
+struct file *bdev_file_open_by_dev(dev_t dev, blk_mode_t mode, void *holder,
                const struct blk_holder_ops *hops);
-struct bdev_handle *bdev_open_by_path(const char *path, blk_mode_t mode,
+struct file *bdev_file_open_by_path(const char *path, blk_mode_t mode,
                void *holder, const struct blk_holder_ops *hops);
 int bd_prepare_to_claim(struct block_device *bdev, void *holder,
                const struct blk_holder_ops *hops);
 void bd_abort_claiming(struct block_device *bdev, void *holder);
-void bdev_release(struct bdev_handle *handle);
 
 /* just for blk-cgroup, don't use elsewhere */
 struct block_device *blkdev_get_no_open(dev_t dev);
 void blkdev_put_no_open(struct block_device *bdev);
 
 struct block_device *I_BDEV(struct inode *inode);
+struct block_device *file_bdev(struct file *bdev_file);
 
 #ifdef CONFIG_BLOCK
 void invalidate_bdev(struct block_device *bdev);
index 555aae5448ae4ec00065e00553955b31bb44884b..bd1e361b351c5afa88ff02e7023cd79acd5454fd 100644 (file)
@@ -83,7 +83,7 @@ struct bvec_iter {
 
        unsigned int            bi_bvec_done;   /* number of bytes completed in
                                                   current bvec */
-} __packed;
+} __packed __aligned(4);
 
 struct bvec_iter_all {
        struct bio_vec  bv;
index 1d42d4b1732717056c4d7acca4ae311a3ca1cffc..0ad8b550bb4b4674fab70fc81dda94a76a7c9579 100644 (file)
@@ -291,7 +291,19 @@ static inline void timer_probe(void) {}
 #define TIMER_ACPI_DECLARE(name, table_id, fn)         \
        ACPI_DECLARE_PROBE_ENTRY(timer, name, table_id, 0, NULL, 0, fn)
 
-extern ulong max_cswd_read_retries;
+static inline unsigned int clocksource_get_max_watchdog_retry(void)
+{
+       /*
+        * When system is in the boot phase or under heavy workload, there
+        * can be random big latencies during the clocksource/watchdog
+        * read, so allow retries to filter the noise latency. As the
+        * latency's frequency and maximum value goes up with the number of
+        * CPUs, scale the number of retries with the number of online
+        * CPUs.
+        */
+       return (ilog2(num_online_cpus()) / 2) + 1;
+}
+
 void clocksource_verify_percpu(struct clocksource *cs);
 
 #endif /* _LINUX_CLOCKSOURCE_H */
index 16775d7d8f8d64197fd59dfc716de1df9d1d9768..a4fa3436940c8fc9f5ab58884b890c6fa4a5a721 100644 (file)
@@ -6,6 +6,9 @@
 enum clocksource_ids {
        CSID_GENERIC            = 0,
        CSID_ARM_ARCH_COUNTER,
+       CSID_X86_TSC_EARLY,
+       CSID_X86_TSC,
+       CSID_X86_KVM_CLK,
        CSID_MAX,
 };
 
index c1a963be7d289e6edafba98f1d7d0236ee4f69f1..aff92b1d284fd014018f1a046c90acf442395896 100644 (file)
@@ -35,7 +35,7 @@
        (typeof(ptr)) (__ptr + (off));                                  \
 })
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
 #define __noretpoline __attribute__((__indirect_branch__("keep")))
 #endif
 
 /*
  * GCC 'asm goto' with outputs miscompiles certain code sequences:
  *
- *   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110420
- *   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110422
+ *   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921
  *
- * Work it around via the same compiler barrier quirk that we used
+ * Work around it via the same compiler barrier quirk that we used
  * to use for the old 'asm goto' workaround.
  *
  * Also, always mark such 'asm goto' statements as volatile: all
  *
  *    https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98619
  */
+#ifdef CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND
 #define asm_goto_output(x...) \
        do { asm volatile goto(x); asm (""); } while (0)
+#endif
 
 #if defined(CONFIG_ARCH_USE_BUILTIN_BSWAP)
 #define __HAVE_BUILTIN_BSWAP32__
index bb1339c7057b49c877907e9db968e828a28d0f3f..cdcdaa48b4d2d705f0aa59dfe3450f73bc76b180 100644 (file)
@@ -209,7 +209,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
  */
 #define ___ADDRESSABLE(sym, __attrs) \
        static void * __used __attrs \
-               __UNIQUE_ID(__PASTE(__addressable_,sym)) = (void *)&sym;
+       __UNIQUE_ID(__PASTE(__addressable_,sym)) = (void *)(uintptr_t)&sym;
 #define __ADDRESSABLE(sym) \
        ___ADDRESSABLE(sym, __section(".discard.addressable"))
 
index 28566624f008f49ebe334f1275f59aafaf0c75f4..8bdf6e0918c15d6fa3e93ca72ebff0d64b6a40e7 100644 (file)
 #endif
 
 /*
- * Optional: only supported since gcc >= 14
+ * Optional: only supported since gcc >= 15
  * Optional: only supported since clang >= 18
  *
  *   gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896
- * clang: https://reviews.llvm.org/D148381
+ * clang: https://github.com/llvm/llvm-project/pull/76348
  */
 #if __has_attribute(__counted_by__)
 # define __counted_by(member)          __attribute__((__counted_by__(member)))
  */
 #define __section(section)              __attribute__((__section__(section)))
 
+/*
+ * Optional: only supported since gcc >= 12
+ *
+ *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-uninitialized-variable-attribute
+ * clang: https://clang.llvm.org/docs/AttributeReference.html#uninitialized
+ */
+#if __has_attribute(__uninitialized__)
+# define __uninitialized               __attribute__((__uninitialized__))
+#else
+# define __uninitialized
+#endif
+
 /*
  *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-unused-function-attribute
  *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#index-unused-type-attribute
index 663d8791c871a7310467ea1b5417b65e58db604f..0caf354cb94b5ad9d802addff81a1bd1c3250139 100644 (file)
@@ -362,8 +362,15 @@ struct ftrace_likely_data {
 #define __member_size(p)       __builtin_object_size(p, 1)
 #endif
 
+/*
+ * Some versions of gcc do not mark 'asm goto' volatile:
+ *
+ *  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103979
+ *
+ * We do it here by hand, because it doesn't hurt.
+ */
 #ifndef asm_goto_output
-#define asm_goto_output(x...) asm goto(x)
+#define asm_goto_output(x...) asm volatile goto(x)
 #endif
 
 #ifdef CONFIG_CC_HAS_ASM_INLINE
index dcb89c9871640f0a92c85c5f16d94a8e199c3a23..ae5a20cf2f9c16c6bb05b3db79d7e76a825f8be3 100644 (file)
@@ -75,6 +75,8 @@ extern ssize_t cpu_show_spec_rstack_overflow(struct device *dev,
                                             struct device_attribute *attr, char *buf);
 extern ssize_t cpu_show_gds(struct device *dev,
                            struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_reg_file_data_sampling(struct device *dev,
+                                              struct device_attribute *attr, char *buf);
 
 extern __printf(4, 5)
 struct device *cpu_device_create(struct device *parent, void *drvdata,
@@ -112,7 +114,7 @@ void notify_cpu_starting(unsigned int cpu);
 extern void cpu_maps_update_begin(void);
 extern void cpu_maps_update_done(void);
 int bringup_hibernate_cpu(unsigned int sleep_cpu);
-void bringup_nonboot_cpus(unsigned int setup_max_cpus);
+void bringup_nonboot_cpus(unsigned int max_cpus);
 
 #else  /* CONFIG_SMP */
 #define cpuhp_tasks_frozen     0
@@ -196,6 +198,8 @@ void arch_cpu_idle(void);
 void arch_cpu_idle_prepare(void);
 void arch_cpu_idle_enter(void);
 void arch_cpu_idle_exit(void);
+void arch_tick_broadcast_enter(void);
+void arch_tick_broadcast_exit(void);
 void __noreturn arch_cpu_idle_dead(void);
 
 #ifdef CONFIG_ARCH_HAS_CPU_FINALIZE_INIT
index 172d0a743e5dd89ff9fd7d99ee785dac04404651..35e78ddb2b37c70357955bb6087a1d3899adb2cd 100644 (file)
@@ -184,6 +184,7 @@ enum cpuhp_state {
        CPUHP_AP_ARM64_ISNDEP_STARTING,
        CPUHP_AP_SMPCFD_DYING,
        CPUHP_AP_HRTIMERS_DYING,
+       CPUHP_AP_TICK_DYING,
        CPUHP_AP_X86_TBOOT_DYING,
        CPUHP_AP_ARM_CACHE_B15_RAC_DYING,
        CPUHP_AP_ONLINE,
@@ -231,6 +232,7 @@ enum cpuhp_state {
        CPUHP_AP_PERF_POWERPC_HV_24x7_ONLINE,
        CPUHP_AP_PERF_POWERPC_HV_GPCI_ONLINE,
        CPUHP_AP_PERF_CSKY_ONLINE,
+       CPUHP_AP_TMIGR_ONLINE,
        CPUHP_AP_WATCHDOG_ONLINE,
        CPUHP_AP_WORKQUEUE_ONLINE,
        CPUHP_AP_RANDOM_ONLINE,
index 875d12598bd2d44fd3ba09d9ede53f1bc105b90b..0ce6ff0d9c9aad7f5f6fb31ba5f15207061cdfd9 100644 (file)
@@ -121,11 +121,6 @@ static inline int cpuset_do_page_mem_spread(void)
        return task_spread_page(current);
 }
 
-static inline int cpuset_do_slab_mem_spread(void)
-{
-       return task_spread_slab(current);
-}
-
 extern bool current_cpuset_is_being_rebound(void);
 
 extern void rebuild_sched_domains(void);
@@ -264,11 +259,6 @@ static inline int cpuset_do_page_mem_spread(void)
        return 0;
 }
 
-static inline int cpuset_do_slab_mem_spread(void)
-{
-       return 0;
-}
-
 static inline bool current_cpuset_is_being_rebound(void)
 {
        return false;
index 91125eca4c8ab8ded08a5b4b687c65c69d656401..03fa6d50d46fe5886d92d3cb6cddfe29fc43af11 100644 (file)
@@ -140,22 +140,4 @@ struct cxl_cper_event_rec {
        union cxl_event event;
 } __packed;
 
-typedef void (*cxl_cper_callback)(enum cxl_event_type type,
-                                 struct cxl_cper_event_rec *rec);
-
-#ifdef CONFIG_ACPI_APEI_GHES
-int cxl_cper_register_callback(cxl_cper_callback callback);
-int cxl_cper_unregister_callback(cxl_cper_callback callback);
-#else
-static inline int cxl_cper_register_callback(cxl_cper_callback callback)
-{
-       return 0;
-}
-
-static inline int cxl_cper_unregister_callback(cxl_cper_callback callback)
-{
-       return 0;
-}
-#endif
-
 #endif /* _LINUX_CXL_EVENT_H */
index 1666c387861f7a8fae32d7ae3acd17c950142ff5..bf53e3894aae33ef15218463db3c9f85985b9e26 100644 (file)
@@ -125,6 +125,11 @@ enum dentry_d_lock_class
        DENTRY_D_LOCK_NESTED
 };
 
+enum d_real_type {
+       D_REAL_DATA,
+       D_REAL_METADATA,
+};
+
 struct dentry_operations {
        int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_weak_revalidate)(struct dentry *, unsigned int);
@@ -139,7 +144,7 @@ struct dentry_operations {
        char *(*d_dname)(struct dentry *, char *, int);
        struct vfsmount *(*d_automount)(struct path *);
        int (*d_manage)(const struct path *, bool);
-       struct dentry *(*d_real)(struct dentry *, const struct inode *);
+       struct dentry *(*d_real)(struct dentry *, enum d_real_type type);
 } ____cacheline_aligned;
 
 /*
@@ -173,6 +178,7 @@ struct dentry_operations {
 #define DCACHE_DONTCACHE               BIT(7) /* Purge from memory on final dput() */
 
 #define DCACHE_CANT_MOUNT              BIT(8)
+#define DCACHE_GENOCIDE                        BIT(9)
 #define DCACHE_SHRINK_LIST             BIT(10)
 
 #define DCACHE_OP_WEAK_REVALIDATE      BIT(11)
@@ -546,24 +552,23 @@ static inline struct inode *d_backing_inode(const struct dentry *upper)
 /**
  * d_real - Return the real dentry
  * @dentry: the dentry to query
- * @inode: inode to select the dentry from multiple layers (can be NULL)
+ * @type: the type of real dentry (data or metadata)
  *
  * If dentry is on a union/overlay, then return the underlying, real dentry.
  * Otherwise return the dentry itself.
  *
  * See also: Documentation/filesystems/vfs.rst
  */
-static inline struct dentry *d_real(struct dentry *dentry,
-                                   const struct inode *inode)
+static inline struct dentry *d_real(struct dentry *dentry, enum d_real_type type)
 {
        if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
-               return dentry->d_op->d_real(dentry, inode);
+               return dentry->d_op->d_real(dentry, type);
        else
                return dentry;
 }
 
 /**
- * d_real_inode - Return the real inode
+ * d_real_inode - Return the real inode hosting the data
  * @dentry: The dentry to query
  *
  * If dentry is on a union/overlay, then return the underlying, real inode.
@@ -572,7 +577,7 @@ static inline struct dentry *d_real(struct dentry *dentry,
 static inline struct inode *d_real_inode(const struct dentry *dentry)
 {
        /* This usage of d_real() results in const dentry */
-       return d_backing_inode(d_real((struct dentry *) dentry, NULL));
+       return d_inode(d_real((struct dentry *) dentry, D_REAL_DATA));
 }
 
 struct name_snapshot {
index 772ab4d74d944b53d97a685c9c1e9f0b95fbb699..82b2195efaca782fc06b7018edda51311297ac87 100644 (file)
@@ -165,7 +165,7 @@ void dm_error(const char *message);
 
 struct dm_dev {
        struct block_device *bdev;
-       struct bdev_handle *bdev_handle;
+       struct file *bdev_file;
        struct dax_device *dax_dev;
        blk_mode_t mode;
        char name[16];
index 9cf896ea1d4122f3bc7094e46a5af81b999937dc..e37344f6a231893fa829bf87c8a18e86bb8b8742 100644 (file)
@@ -10,6 +10,8 @@
 #include <uapi/linux/dpll.h>
 #include <linux/device.h>
 #include <linux/netlink.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
 
 struct dpll_device;
 struct dpll_pin;
@@ -120,15 +122,24 @@ struct dpll_pin_properties {
 };
 
 #if IS_ENABLED(CONFIG_DPLL)
-size_t dpll_msg_pin_handle_size(struct dpll_pin *pin);
-int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin);
+void dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin);
+void dpll_netdev_pin_clear(struct net_device *dev);
+
+size_t dpll_netdev_pin_handle_size(const struct net_device *dev);
+int dpll_netdev_add_pin_handle(struct sk_buff *msg,
+                              const struct net_device *dev);
 #else
-static inline size_t dpll_msg_pin_handle_size(struct dpll_pin *pin)
+static inline void
+dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin) { }
+static inline void dpll_netdev_pin_clear(struct net_device *dev) { }
+
+static inline size_t dpll_netdev_pin_handle_size(const struct net_device *dev)
 {
        return 0;
 }
 
-static inline int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin)
+static inline int
+dpll_netdev_add_pin_handle(struct sk_buff *msg, const struct net_device *dev)
 {
        return 0;
 }
index 6834a29338c43c3370640a3432c98b606313cfb3..169692cb1906d8015cca7b854c1eaeedb3db09e2 100644 (file)
@@ -24,6 +24,8 @@ struct inode;
 struct path;
 extern struct file *alloc_file_pseudo(struct inode *, struct vfsmount *,
        const char *, int flags, const struct file_operations *);
+extern struct file *alloc_file_pseudo_noaccount(struct inode *, struct vfsmount *,
+       const char *, int flags, const struct file_operations *);
 extern struct file *alloc_file_clone(struct file *, int flags,
        const struct file_operations *);
 
index 95e868e09e298bb70ca23ec760d1c00fdb07201e..daee999d05f390a9fa28e83ff2643c2b1e5d1e96 100644 (file)
@@ -27,6 +27,7 @@
 #define FILE_LOCK_DEFERRED 1
 
 struct file_lock;
+struct file_lease;
 
 struct file_lock_operations {
        void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
@@ -39,14 +40,17 @@ struct lock_manager_operations {
        void (*lm_put_owner)(fl_owner_t);
        void (*lm_notify)(struct file_lock *);  /* unblock callback */
        int (*lm_grant)(struct file_lock *, int);
-       bool (*lm_break)(struct file_lock *);
-       int (*lm_change)(struct file_lock *, int, struct list_head *);
-       void (*lm_setup)(struct file_lock *, void **);
-       bool (*lm_breaker_owns_lease)(struct file_lock *);
        bool (*lm_lock_expirable)(struct file_lock *cfl);
        void (*lm_expire_lock)(void);
 };
 
+struct lease_manager_operations {
+       bool (*lm_break)(struct file_lease *);
+       int (*lm_change)(struct file_lease *, int, struct list_head *);
+       void (*lm_setup)(struct file_lease *, void **);
+       bool (*lm_breaker_owns_lease)(struct file_lease *);
+};
+
 struct lock_manager {
        struct list_head list;
        /*
@@ -85,31 +89,31 @@ bool opens_in_grace(struct net *);
  *
  * Obviously, the last two criteria only matter for POSIX locks.
  */
-struct file_lock {
-       struct file_lock *fl_blocker;   /* The lock, that is blocking us */
-       struct list_head fl_list;       /* link into file_lock_context */
-       struct hlist_node fl_link;      /* node in global lists */
-       struct list_head fl_blocked_requests;   /* list of requests with
+
+struct file_lock_core {
+       struct file_lock_core *flc_blocker;     /* The lock that is blocking us */
+       struct list_head flc_list;      /* link into file_lock_context */
+       struct hlist_node flc_link;     /* node in global lists */
+       struct list_head flc_blocked_requests;  /* list of requests with
                                                 * ->fl_blocker pointing here
                                                 */
-       struct list_head fl_blocked_member;     /* node in
+       struct list_head flc_blocked_member;    /* node in
                                                 * ->fl_blocker->fl_blocked_requests
                                                 */
-       fl_owner_t fl_owner;
-       unsigned int fl_flags;
-       unsigned char fl_type;
-       unsigned int fl_pid;
-       int fl_link_cpu;                /* what cpu's list is this on? */
-       wait_queue_head_t fl_wait;
-       struct file *fl_file;
+       fl_owner_t flc_owner;
+       unsigned int flc_flags;
+       unsigned char flc_type;
+       pid_t flc_pid;
+       int flc_link_cpu;               /* what cpu's list is this on? */
+       wait_queue_head_t flc_wait;
+       struct file *flc_file;
+};
+
+struct file_lock {
+       struct file_lock_core c;
        loff_t fl_start;
        loff_t fl_end;
 
-       struct fasync_struct *  fl_fasync; /* for lease break notifications */
-       /* for lease breaks: */
-       unsigned long fl_break_time;
-       unsigned long fl_downgrade_time;
-
        const struct file_lock_operations *fl_ops;      /* Callbacks for filesystems */
        const struct lock_manager_operations *fl_lmops; /* Callbacks for lockmanagers */
        union {
@@ -126,6 +130,15 @@ struct file_lock {
        } fl_u;
 } __randomize_layout;
 
+struct file_lease {
+       struct file_lock_core c;
+       struct fasync_struct *  fl_fasync; /* for lease break notifications */
+       /* for lease breaks: */
+       unsigned long fl_break_time;
+       unsigned long fl_downgrade_time;
+       const struct lease_manager_operations *fl_lmops; /* Callbacks for lease managers */
+} __randomize_layout;
+
 struct file_lock_context {
        spinlock_t              flc_lock;
        struct list_head        flc_flock;
@@ -147,11 +160,31 @@ int fcntl_setlk64(unsigned int, struct file *, unsigned int,
 int fcntl_setlease(unsigned int fd, struct file *filp, int arg);
 int fcntl_getlease(struct file *filp);
 
+static inline bool lock_is_unlock(struct file_lock *fl)
+{
+       return fl->c.flc_type == F_UNLCK;
+}
+
+static inline bool lock_is_read(struct file_lock *fl)
+{
+       return fl->c.flc_type == F_RDLCK;
+}
+
+static inline bool lock_is_write(struct file_lock *fl)
+{
+       return fl->c.flc_type == F_WRLCK;
+}
+
+static inline void locks_wake_up(struct file_lock *fl)
+{
+       wake_up(&fl->c.flc_wait);
+}
+
 /* fs/locks.c */
 void locks_free_lock_context(struct inode *inode);
 void locks_free_lock(struct file_lock *fl);
 void locks_init_lock(struct file_lock *);
-struct file_lock * locks_alloc_lock(void);
+struct file_lock *locks_alloc_lock(void);
 void locks_copy_lock(struct file_lock *, struct file_lock *);
 void locks_copy_conflock(struct file_lock *, struct file_lock *);
 void locks_remove_posix(struct file *, fl_owner_t);
@@ -165,11 +198,16 @@ int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_l
 int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
 bool vfs_inode_has_locks(struct inode *inode);
 int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl);
+
+void locks_init_lease(struct file_lease *);
+void locks_free_lease(struct file_lease *fl);
+struct file_lease *locks_alloc_lease(void);
 int __break_lease(struct inode *inode, unsigned int flags, unsigned int type);
 void lease_get_mtime(struct inode *, struct timespec64 *time);
-int generic_setlease(struct file *, int, struct file_lock **, void **priv);
-int vfs_setlease(struct file *, int, struct file_lock **, void **);
-int lease_modify(struct file_lock *, int, struct list_head *);
+int generic_setlease(struct file *, int, struct file_lease **, void **priv);
+int kernel_setlease(struct file *, int, struct file_lease **, void **);
+int vfs_setlease(struct file *, int, struct file_lease **, void **);
+int lease_modify(struct file_lease *, int, struct list_head *);
 
 struct notifier_block;
 int lease_register_notifier(struct notifier_block *);
@@ -223,6 +261,25 @@ static inline int fcntl_getlease(struct file *filp)
        return F_UNLCK;
 }
 
+static inline bool lock_is_unlock(struct file_lock *fl)
+{
+       return false;
+}
+
+static inline bool lock_is_read(struct file_lock *fl)
+{
+       return false;
+}
+
+static inline bool lock_is_write(struct file_lock *fl)
+{
+       return false;
+}
+
+static inline void locks_wake_up(struct file_lock *fl)
+{
+}
+
 static inline void
 locks_free_lock_context(struct inode *inode)
 {
@@ -233,6 +290,11 @@ static inline void locks_init_lock(struct file_lock *fl)
        return;
 }
 
+static inline void locks_init_lease(struct file_lease *fl)
+{
+       return;
+}
+
 static inline void locks_copy_conflock(struct file_lock *new, struct file_lock *fl)
 {
        return;
@@ -307,18 +369,24 @@ static inline void lease_get_mtime(struct inode *inode,
 }
 
 static inline int generic_setlease(struct file *filp, int arg,
-                                   struct file_lock **flp, void **priv)
+                                   struct file_lease **flp, void **priv)
+{
+       return -EINVAL;
+}
+
+static inline int kernel_setlease(struct file *filp, int arg,
+                              struct file_lease **lease, void **priv)
 {
        return -EINVAL;
 }
 
 static inline int vfs_setlease(struct file *filp, int arg,
-                              struct file_lock **lease, void **priv)
+                              struct file_lease **lease, void **priv)
 {
        return -EINVAL;
 }
 
-static inline int lease_modify(struct file_lock *fl, int arg,
+static inline int lease_modify(struct file_lease *fl, int arg,
                               struct list_head *dispose)
 {
        return -EINVAL;
@@ -341,6 +409,9 @@ locks_inode_context(const struct inode *inode)
 
 #endif /* !CONFIG_FILE_LOCKING */
 
+/* for walking lists of file_locks linked by fl_list */
+#define for_each_file_lock(_fl, _head) list_for_each_entry(_fl, _head, c.flc_list)
+
 static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl)
 {
        return locks_lock_inode_wait(file_inode(filp), fl);
index ed5966a70495129be1d6729eed2918240db62df1..0a22b7245982a5389b983a697d8fb3c87a6273da 100644 (file)
@@ -43,6 +43,8 @@
 #include <linux/cred.h>
 #include <linux/mnt_idmapping.h>
 #include <linux/slab.h>
+#include <linux/maple_tree.h>
+#include <linux/rw_hint.h>
 
 #include <asm/byteorder.h>
 #include <uapi/linux/fs.h>
@@ -309,19 +311,6 @@ struct address_space;
 struct writeback_control;
 struct readahead_control;
 
-/*
- * Write life time hint values.
- * Stored in struct inode as u8.
- */
-enum rw_hint {
-       WRITE_LIFE_NOT_SET      = 0,
-       WRITE_LIFE_NONE         = RWH_WRITE_LIFE_NONE,
-       WRITE_LIFE_SHORT        = RWH_WRITE_LIFE_SHORT,
-       WRITE_LIFE_MEDIUM       = RWH_WRITE_LIFE_MEDIUM,
-       WRITE_LIFE_LONG         = RWH_WRITE_LIFE_LONG,
-       WRITE_LIFE_EXTREME      = RWH_WRITE_LIFE_EXTREME,
-};
-
 /* Match RWF_* bits to IOCB bits */
 #define IOCB_HIPRI             (__force int) RWF_HIPRI
 #define IOCB_DSYNC             (__force int) RWF_DSYNC
@@ -352,6 +341,8 @@ enum rw_hint {
  * unrelated IO (like cache flushing, new IO generation, etc).
  */
 #define IOCB_DIO_CALLER_COMP   (1 << 22)
+/* kiocb is a read or write operation submitted by fs/aio.c. */
+#define IOCB_AIO_RW            (1 << 23)
 
 /* for use in trace events */
 #define TRACE_IOCB_STRINGS \
@@ -482,10 +473,10 @@ struct address_space {
        pgoff_t                 writeback_index;
        const struct address_space_operations *a_ops;
        unsigned long           flags;
-       struct rw_semaphore     i_mmap_rwsem;
        errseq_t                wb_err;
        spinlock_t              i_private_lock;
        struct list_head        i_private_list;
+       struct rw_semaphore     i_mmap_rwsem;
        void *                  i_private_data;
 } __attribute__((aligned(sizeof(long)))) __randomize_layout;
        /*
@@ -677,7 +668,7 @@ struct inode {
        spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
        unsigned short          i_bytes;
        u8                      i_blkbits;
-       u8                      i_write_hint;
+       enum rw_hint            i_write_hint;
        blkcnt_t                i_blocks;
 
 #ifdef __NEED_I_SIZE_ORDERED
@@ -907,7 +898,8 @@ static inline loff_t i_size_read(const struct inode *inode)
        preempt_enable();
        return i_size;
 #else
-       return inode->i_size;
+       /* Pairs with smp_store_release() in i_size_write() */
+       return smp_load_acquire(&inode->i_size);
 #endif
 }
 
@@ -929,7 +921,12 @@ static inline void i_size_write(struct inode *inode, loff_t i_size)
        inode->i_size = i_size;
        preempt_enable();
 #else
-       inode->i_size = i_size;
+       /*
+        * Pairs with smp_load_acquire() in i_size_read() to ensure
+        * changes related to inode size (such as page contents) are
+        * visible before we see the changed inode size.
+        */
+       smp_store_release(&inode->i_size, i_size);
 #endif
 }
 
@@ -1064,6 +1061,7 @@ struct file *get_file_active(struct file **f);
 typedef void *fl_owner_t;
 
 struct file_lock;
+struct file_lease;
 
 /* The following constant reflects the upper bound of the file/locking space */
 #ifndef OFFSET_MAX
@@ -1078,9 +1076,20 @@ static inline struct inode *file_inode(const struct file *f)
        return f->f_inode;
 }
 
+/*
+ * file_dentry() is a relic from the days that overlayfs was using files with a
+ * "fake" path, meaning, f_path on overlayfs and f_inode on underlying fs.
+ * In those days, file_dentry() was needed to get the underlying fs dentry that
+ * matches f_inode.
+ * Files with "fake" path should not exist nowadays, so use an assertion to make
+ * sure that file_dentry() was not papering over filesystem bugs.
+ */
 static inline struct dentry *file_dentry(const struct file *file)
 {
-       return d_real(file->f_path.dentry, file_inode(file));
+       struct dentry *dentry = file->f_path.dentry;
+
+       WARN_ON_ONCE(d_inode(dentry) != file_inode(file));
+       return dentry;
 }
 
 struct fasync_struct {
@@ -1228,8 +1237,8 @@ struct super_block {
 #endif
        struct hlist_bl_head    s_roots;        /* alternate root dentries for NFS */
        struct list_head        s_mounts;       /* list of mounts; _not_ for fs use */
-       struct block_device     *s_bdev;
-       struct bdev_handle      *s_bdev_handle;
+       struct block_device     *s_bdev;        /* can go away once we use an accessor for @s_bdev_file */
+       struct file             *s_bdev_file;
        struct backing_dev_info *s_bdi;
        struct mtd_info         *s_mtd;
        struct hlist_node       s_instances;
@@ -1255,8 +1264,22 @@ struct super_block {
        struct fsnotify_mark_connector __rcu    *s_fsnotify_marks;
 #endif
 
+       /*
+        * q: why are s_id and s_sysfs_name not the same? both are human
+        * readable strings that identify the filesystem
+        * a: s_id is allowed to change at runtime; it's used in log messages,
+        * and we want to when a device starts out as single device (s_id is dev
+        * name) but then a device is hot added and we have to switch to
+        * identifying it by UUID
+        * but s_sysfs_name is a handle for programmatic access, and can't
+        * change at runtime
+        */
        char                    s_id[32];       /* Informational name */
        uuid_t                  s_uuid;         /* UUID */
+       u8                      s_uuid_len;     /* Default 16, possibly smaller for weird filesystems */
+
+       /* if set, fs shows up under sysfs at /sys/fs/$FSTYP/s_sysfs_name */
+       char                    s_sysfs_name[UUID_STRING_LEN + 1];
 
        unsigned int            s_max_links;
 
@@ -2005,7 +2028,7 @@ struct file_operations {
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
        ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
        void (*splice_eof)(struct file *file);
-       int (*setlease)(struct file *, int, struct file_lock **, void **);
+       int (*setlease)(struct file *, int, struct file_lease **, void **);
        long (*fallocate)(struct file *file, int mode, loff_t offset,
                          loff_t len);
        void (*show_fdinfo)(struct seq_file *m, struct file *f);
@@ -2101,9 +2124,6 @@ int __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
 int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
                                  struct file *file_out, loff_t pos_out,
                                  loff_t *count, unsigned int remap_flags);
-extern loff_t do_clone_file_range(struct file *file_in, loff_t pos_in,
-                                 struct file *file_out, loff_t pos_out,
-                                 loff_t len, unsigned int remap_flags);
 extern loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in,
                                   struct file *file_out, loff_t pos_out,
                                   loff_t len, unsigned int remap_flags);
@@ -2532,6 +2552,44 @@ extern __printf(2, 3)
 int super_setup_bdi_name(struct super_block *sb, char *fmt, ...);
 extern int super_setup_bdi(struct super_block *sb);
 
+static inline void super_set_uuid(struct super_block *sb, const u8 *uuid, unsigned len)
+{
+       if (WARN_ON(len > sizeof(sb->s_uuid)))
+               len = sizeof(sb->s_uuid);
+       sb->s_uuid_len = len;
+       memcpy(&sb->s_uuid, uuid, len);
+}
+
+/* set sb sysfs name based on sb->s_bdev */
+static inline void super_set_sysfs_name_bdev(struct super_block *sb)
+{
+       snprintf(sb->s_sysfs_name, sizeof(sb->s_sysfs_name), "%pg", sb->s_bdev);
+}
+
+/* set sb sysfs name based on sb->s_uuid */
+static inline void super_set_sysfs_name_uuid(struct super_block *sb)
+{
+       WARN_ON(sb->s_uuid_len != sizeof(sb->s_uuid));
+       snprintf(sb->s_sysfs_name, sizeof(sb->s_sysfs_name), "%pU", sb->s_uuid.b);
+}
+
+/* set sb sysfs name based on sb->s_id */
+static inline void super_set_sysfs_name_id(struct super_block *sb)
+{
+       strscpy(sb->s_sysfs_name, sb->s_id, sizeof(sb->s_sysfs_name));
+}
+
+/* try to use something standard before you use this */
+__printf(2, 3)
+static inline void super_set_sysfs_name_generic(struct super_block *sb, const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       vsnprintf(sb->s_sysfs_name, sizeof(sb->s_sysfs_name), fmt, args);
+       va_end(args);
+}
+
 extern int current_umask(void);
 
 extern void ihold(struct inode * inode);
@@ -2928,6 +2986,17 @@ extern bool path_is_under(const struct path *, const struct path *);
 
 extern char *file_path(struct file *, char *, int);
 
+/**
+ * is_dot_dotdot - returns true only if @name is "." or ".."
+ * @name: file name to check
+ * @len: length of file name, in bytes
+ */
+static inline bool is_dot_dotdot(const char *name, size_t len)
+{
+       return len && unlikely(name[0] == '.') &&
+               (len == 1 || (len == 2 && name[1] == '.'));
+}
+
 #include <linux/err.h>
 
 /* needed for stackable file system support */
@@ -3238,7 +3307,7 @@ extern int simple_write_begin(struct file *file, struct address_space *mapping,
 extern const struct address_space_operations ram_aops;
 extern int always_delete_dentry(const struct dentry *);
 extern struct inode *alloc_anon_inode(struct super_block *);
-extern int simple_nosetlease(struct file *, int, struct file_lock **, void **);
+extern int simple_nosetlease(struct file *, int, struct file_lease **, void **);
 extern const struct dentry_operations simple_dentry_operations;
 
 extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);
@@ -3260,13 +3329,14 @@ extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
                const void __user *from, size_t count);
 
 struct offset_ctx {
-       struct xarray           xa;
-       u32                     next_offset;
+       struct maple_tree       mt;
+       unsigned long           next_offset;
 };
 
 void simple_offset_init(struct offset_ctx *octx);
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry);
 void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry);
+int simple_offset_empty(struct dentry *dentry);
 int simple_offset_rename_exchange(struct inode *old_dir,
                                  struct dentry *old_dentry,
                                  struct inode *new_dir,
@@ -3280,7 +3350,16 @@ extern int generic_file_fsync(struct file *, loff_t, loff_t, int);
 
 extern int generic_check_addressable(unsigned, u64);
 
-extern void generic_set_encrypted_ci_d_ops(struct dentry *dentry);
+extern void generic_set_sb_d_ops(struct super_block *sb);
+
+static inline bool sb_has_encoding(const struct super_block *sb)
+{
+#if IS_ENABLED(CONFIG_UNICODE)
+       return !!sb->s_encoding;
+#else
+       return false;
+#endif
+}
 
 int may_setattr(struct mnt_idmap *idmap, struct inode *inode,
                unsigned int ia_valid);
@@ -3335,6 +3414,8 @@ static inline int kiocb_set_rw_flags(struct kiocb *ki, rwf_t flags)
                return 0;
        if (unlikely(flags & ~RWF_SUPPORTED))
                return -EOPNOTSUPP;
+       if (unlikely((flags & RWF_APPEND) && (flags & RWF_NOAPPEND)))
+               return -EINVAL;
 
        if (flags & RWF_NOWAIT) {
                if (!(ki->ki_filp->f_mode & FMODE_NOWAIT))
@@ -3345,6 +3426,12 @@ static inline int kiocb_set_rw_flags(struct kiocb *ki, rwf_t flags)
        if (flags & RWF_SYNC)
                kiocb_flags |= IOCB_DSYNC;
 
+       if ((flags & RWF_NOAPPEND) && (ki->ki_flags & IOCB_APPEND)) {
+               if (IS_APPEND(file_inode(ki->ki_filp)))
+                       return -EPERM;
+               ki->ki_flags &= ~IOCB_APPEND;
+       }
+
        ki->ki_flags |= kiocb_flags;
        return 0;
 }
index 12f9e455d569f0a43aade8a9c6bb47402d6139b6..772f822dc6b82e92903e030b0d5c35512ffc9f55 100644 (file)
@@ -192,6 +192,8 @@ struct fscrypt_operations {
                                             unsigned int *num_devs);
 };
 
+int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags);
+
 static inline struct fscrypt_inode_info *
 fscrypt_get_inode_info(const struct inode *inode)
 {
@@ -221,15 +223,29 @@ static inline bool fscrypt_needs_contents_encryption(const struct inode *inode)
 }
 
 /*
- * When d_splice_alias() moves a directory's no-key alias to its plaintext alias
- * as a result of the encryption key being added, DCACHE_NOKEY_NAME must be
- * cleared.  Note that we don't have to support arbitrary moves of this flag
- * because fscrypt doesn't allow no-key names to be the source or target of a
- * rename().
+ * When d_splice_alias() moves a directory's no-key alias to its
+ * plaintext alias as a result of the encryption key being added,
+ * DCACHE_NOKEY_NAME must be cleared and there might be an opportunity
+ * to disable d_revalidate.  Note that we don't have to support the
+ * inverse operation because fscrypt doesn't allow no-key names to be
+ * the source or target of a rename().
  */
 static inline void fscrypt_handle_d_move(struct dentry *dentry)
 {
-       dentry->d_flags &= ~DCACHE_NOKEY_NAME;
+       /*
+        * VFS calls fscrypt_handle_d_move even for non-fscrypt
+        * filesystems.
+        */
+       if (dentry->d_flags & DCACHE_NOKEY_NAME) {
+               dentry->d_flags &= ~DCACHE_NOKEY_NAME;
+
+               /*
+                * Other filesystem features might be handling dentry
+                * revalidation, in which case it cannot be disabled.
+                */
+               if (dentry->d_op->d_revalidate == fscrypt_d_revalidate)
+                       dentry->d_flags &= ~DCACHE_OP_REVALIDATE;
+       }
 }
 
 /**
@@ -261,6 +277,35 @@ static inline bool fscrypt_is_nokey_name(const struct dentry *dentry)
        return dentry->d_flags & DCACHE_NOKEY_NAME;
 }
 
+static inline void fscrypt_prepare_dentry(struct dentry *dentry,
+                                         bool is_nokey_name)
+{
+       /*
+        * This code tries to only take ->d_lock when necessary to write
+        * to ->d_flags.  We shouldn't be peeking on d_flags for
+        * DCACHE_OP_REVALIDATE unlocked, but in the unlikely case
+        * there is a race, the worst it can happen is that we fail to
+        * unset DCACHE_OP_REVALIDATE and pay the cost of an extra
+        * d_revalidate.
+        */
+       if (is_nokey_name) {
+               spin_lock(&dentry->d_lock);
+               dentry->d_flags |= DCACHE_NOKEY_NAME;
+               spin_unlock(&dentry->d_lock);
+       } else if (dentry->d_flags & DCACHE_OP_REVALIDATE &&
+                  dentry->d_op->d_revalidate == fscrypt_d_revalidate) {
+               /*
+                * Unencrypted dentries and encrypted dentries where the
+                * key is available are always valid from fscrypt
+                * perspective. Avoid the cost of calling
+                * fscrypt_d_revalidate unnecessarily.
+                */
+               spin_lock(&dentry->d_lock);
+               dentry->d_flags &= ~DCACHE_OP_REVALIDATE;
+               spin_unlock(&dentry->d_lock);
+       }
+}
+
 /* crypto.c */
 void fscrypt_enqueue_decrypt_work(struct work_struct *);
 
@@ -368,7 +413,6 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
 bool fscrypt_match_name(const struct fscrypt_name *fname,
                        const u8 *de_name, u32 de_name_len);
 u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name);
-int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags);
 
 /* bio.c */
 bool fscrypt_decrypt_bio(struct bio *bio);
@@ -425,6 +469,11 @@ static inline bool fscrypt_is_nokey_name(const struct dentry *dentry)
        return false;
 }
 
+static inline void fscrypt_prepare_dentry(struct dentry *dentry,
+                                         bool is_nokey_name)
+{
+}
+
 /* crypto.c */
 static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work)
 {
@@ -982,6 +1031,9 @@ static inline int fscrypt_prepare_lookup(struct inode *dir,
        fname->usr_fname = &dentry->d_name;
        fname->disk_name.name = (unsigned char *)dentry->d_name.name;
        fname->disk_name.len = dentry->d_name.len;
+
+       fscrypt_prepare_dentry(dentry, false);
+
        return 0;
 }
 
index de292a0071389ed122a3540c4a98870fe30aa8d8..e2a916cf29c42ff6c9e298bf64b9e3b3f9208879 100644 (file)
@@ -353,6 +353,15 @@ static inline bool gfp_has_io_fs(gfp_t gfp)
        return (gfp & (__GFP_IO | __GFP_FS)) == (__GFP_IO | __GFP_FS);
 }
 
+/*
+ * Check if the gfp flags allow compaction - GFP_NOIO is a really
+ * tricky context because the migration might require IO.
+ */
+static inline bool gfp_compaction_allowed(gfp_t gfp_mask)
+{
+       return IS_ENABLED(CONFIG_COMPACTION) && (gfp_mask & __GFP_IO);
+}
+
 extern gfp_t vma_thp_gfp_mask(struct vm_area_struct *vma);
 
 #ifdef CONFIG_CONTIG_ALLOC
index 9a5c6c76e6533385dbb32de98abfd330c8736585..7f75c9a5187417b3b52386573a47f7c1e95e9126 100644 (file)
@@ -819,6 +819,24 @@ static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
        return ERR_PTR(-ENODEV);
 }
 
+static inline struct gpio_device *gpiod_to_gpio_device(struct gpio_desc *desc)
+{
+       WARN_ON(1);
+       return ERR_PTR(-ENODEV);
+}
+
+static inline int gpio_device_get_base(struct gpio_device *gdev)
+{
+       WARN_ON(1);
+       return -ENODEV;
+}
+
+static inline const char *gpio_device_get_label(struct gpio_device *gdev)
+{
+       WARN_ON(1);
+       return NULL;
+}
+
 static inline int gpiochip_lock_as_irq(struct gpio_chip *gc,
                                       unsigned int offset)
 {
index 641c4567cfa7aee830f8ad0b52abb24bcbe353a8..aa1e65ccb6158414fed519c984e8b0ca8dc11dcf 100644 (file)
 #include <linux/list.h>
 #include <linux/percpu-defs.h>
 #include <linux/rbtree.h>
-#include <linux/seqlock.h>
 #include <linux/timer.h>
 
-struct hrtimer_clock_base;
-struct hrtimer_cpu_base;
-
 /*
  * Mode arguments of xxx_hrtimer functions:
  *
@@ -98,107 +94,6 @@ struct hrtimer_sleeper {
        struct task_struct *task;
 };
 
-#ifdef CONFIG_64BIT
-# define __hrtimer_clock_base_align    ____cacheline_aligned
-#else
-# define __hrtimer_clock_base_align
-#endif
-
-/**
- * struct hrtimer_clock_base - the timer base for a specific clock
- * @cpu_base:          per cpu clock base
- * @index:             clock type index for per_cpu support when moving a
- *                     timer to a base on another cpu.
- * @clockid:           clock id for per_cpu support
- * @seq:               seqcount around __run_hrtimer
- * @running:           pointer to the currently running hrtimer
- * @active:            red black tree root node for the active timers
- * @get_time:          function to retrieve the current time of the clock
- * @offset:            offset of this clock to the monotonic base
- */
-struct hrtimer_clock_base {
-       struct hrtimer_cpu_base *cpu_base;
-       unsigned int            index;
-       clockid_t               clockid;
-       seqcount_raw_spinlock_t seq;
-       struct hrtimer          *running;
-       struct timerqueue_head  active;
-       ktime_t                 (*get_time)(void);
-       ktime_t                 offset;
-} __hrtimer_clock_base_align;
-
-enum  hrtimer_base_type {
-       HRTIMER_BASE_MONOTONIC,
-       HRTIMER_BASE_REALTIME,
-       HRTIMER_BASE_BOOTTIME,
-       HRTIMER_BASE_TAI,
-       HRTIMER_BASE_MONOTONIC_SOFT,
-       HRTIMER_BASE_REALTIME_SOFT,
-       HRTIMER_BASE_BOOTTIME_SOFT,
-       HRTIMER_BASE_TAI_SOFT,
-       HRTIMER_MAX_CLOCK_BASES,
-};
-
-/**
- * struct hrtimer_cpu_base - the per cpu clock bases
- * @lock:              lock protecting the base and associated clock bases
- *                     and timers
- * @cpu:               cpu number
- * @active_bases:      Bitfield to mark bases with active timers
- * @clock_was_set_seq: Sequence counter of clock was set events
- * @hres_active:       State of high resolution mode
- * @in_hrtirq:         hrtimer_interrupt() is currently executing
- * @hang_detected:     The last hrtimer interrupt detected a hang
- * @softirq_activated: displays, if the softirq is raised - update of softirq
- *                     related settings is not required then.
- * @nr_events:         Total number of hrtimer interrupt events
- * @nr_retries:                Total number of hrtimer interrupt retries
- * @nr_hangs:          Total number of hrtimer interrupt hangs
- * @max_hang_time:     Maximum time spent in hrtimer_interrupt
- * @softirq_expiry_lock: Lock which is taken while softirq based hrtimer are
- *                      expired
- * @online:            CPU is online from an hrtimers point of view
- * @timer_waiters:     A hrtimer_cancel() invocation waits for the timer
- *                     callback to finish.
- * @expires_next:      absolute time of the next event, is required for remote
- *                     hrtimer enqueue; it is the total first expiry time (hard
- *                     and soft hrtimer are taken into account)
- * @next_timer:                Pointer to the first expiring timer
- * @softirq_expires_next: Time to check, if soft queues needs also to be expired
- * @softirq_next_timer: Pointer to the first expiring softirq based timer
- * @clock_base:                array of clock bases for this cpu
- *
- * Note: next_timer is just an optimization for __remove_hrtimer().
- *      Do not dereference the pointer because it is not reliable on
- *      cross cpu removals.
- */
-struct hrtimer_cpu_base {
-       raw_spinlock_t                  lock;
-       unsigned int                    cpu;
-       unsigned int                    active_bases;
-       unsigned int                    clock_was_set_seq;
-       unsigned int                    hres_active             : 1,
-                                       in_hrtirq               : 1,
-                                       hang_detected           : 1,
-                                       softirq_activated       : 1,
-                                       online                  : 1;
-#ifdef CONFIG_HIGH_RES_TIMERS
-       unsigned int                    nr_events;
-       unsigned short                  nr_retries;
-       unsigned short                  nr_hangs;
-       unsigned int                    max_hang_time;
-#endif
-#ifdef CONFIG_PREEMPT_RT
-       spinlock_t                      softirq_expiry_lock;
-       atomic_t                        timer_waiters;
-#endif
-       ktime_t                         expires_next;
-       struct hrtimer                  *next_timer;
-       ktime_t                         softirq_expires_next;
-       struct hrtimer                  *softirq_next_timer;
-       struct hrtimer_clock_base       clock_base[HRTIMER_MAX_CLOCK_BASES];
-} ____cacheline_aligned;
-
 static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time)
 {
        timer->node.expires = time;
@@ -447,20 +342,12 @@ extern u64
 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);
 
 /**
- * hrtimer_forward_now - forward the timer expiry so it expires after now
+ * hrtimer_forward_now() - forward the timer expiry so it expires after now
  * @timer:     hrtimer to forward
  * @interval:  the interval to forward
  *
- * Forward the timer expiry so it will expire after the current time
- * of the hrtimer clock base. Returns the number of overruns.
- *
- * Can be safely called from the callback function of @timer. If
- * called from other contexts @timer must neither be enqueued nor
- * running the callback and the caller needs to take care of
- * serialization.
- *
- * Note: This only updates the timer expiry value and does not requeue
- * the timer.
+ * It is a variant of hrtimer_forward(). The timer will expire after the current
+ * time of the hrtimer clock base. See hrtimer_forward() for details.
  */
 static inline u64 hrtimer_forward_now(struct hrtimer *timer,
                                      ktime_t interval)
index 2d3e3c5fb94662cd497171e758b05364475d2ca8..c3b4b7ed7c163fa4cbcba9168266566357f5865e 100644 (file)
@@ -3,6 +3,8 @@
 #define _LINUX_HRTIMER_DEFS_H
 
 #include <linux/ktime.h>
+#include <linux/timerqueue.h>
+#include <linux/seqlock.h>
 
 #ifdef CONFIG_HIGH_RES_TIMERS
 
 
 #endif
 
+#ifdef CONFIG_64BIT
+# define __hrtimer_clock_base_align    ____cacheline_aligned
+#else
+# define __hrtimer_clock_base_align
+#endif
+
+/**
+ * struct hrtimer_clock_base - the timer base for a specific clock
+ * @cpu_base:          per cpu clock base
+ * @index:             clock type index for per_cpu support when moving a
+ *                     timer to a base on another cpu.
+ * @clockid:           clock id for per_cpu support
+ * @seq:               seqcount around __run_hrtimer
+ * @running:           pointer to the currently running hrtimer
+ * @active:            red black tree root node for the active timers
+ * @get_time:          function to retrieve the current time of the clock
+ * @offset:            offset of this clock to the monotonic base
+ */
+struct hrtimer_clock_base {
+       struct hrtimer_cpu_base *cpu_base;
+       unsigned int            index;
+       clockid_t               clockid;
+       seqcount_raw_spinlock_t seq;
+       struct hrtimer          *running;
+       struct timerqueue_head  active;
+       ktime_t                 (*get_time)(void);
+       ktime_t                 offset;
+} __hrtimer_clock_base_align;
+
+enum  hrtimer_base_type {
+       HRTIMER_BASE_MONOTONIC,
+       HRTIMER_BASE_REALTIME,
+       HRTIMER_BASE_BOOTTIME,
+       HRTIMER_BASE_TAI,
+       HRTIMER_BASE_MONOTONIC_SOFT,
+       HRTIMER_BASE_REALTIME_SOFT,
+       HRTIMER_BASE_BOOTTIME_SOFT,
+       HRTIMER_BASE_TAI_SOFT,
+       HRTIMER_MAX_CLOCK_BASES,
+};
+
+/**
+ * struct hrtimer_cpu_base - the per cpu clock bases
+ * @lock:              lock protecting the base and associated clock bases
+ *                     and timers
+ * @cpu:               cpu number
+ * @active_bases:      Bitfield to mark bases with active timers
+ * @clock_was_set_seq: Sequence counter of clock was set events
+ * @hres_active:       State of high resolution mode
+ * @in_hrtirq:         hrtimer_interrupt() is currently executing
+ * @hang_detected:     The last hrtimer interrupt detected a hang
+ * @softirq_activated: displays, if the softirq is raised - update of softirq
+ *                     related settings is not required then.
+ * @nr_events:         Total number of hrtimer interrupt events
+ * @nr_retries:                Total number of hrtimer interrupt retries
+ * @nr_hangs:          Total number of hrtimer interrupt hangs
+ * @max_hang_time:     Maximum time spent in hrtimer_interrupt
+ * @softirq_expiry_lock: Lock which is taken while softirq based hrtimer are
+ *                      expired
+ * @online:            CPU is online from an hrtimers point of view
+ * @timer_waiters:     A hrtimer_cancel() invocation waits for the timer
+ *                     callback to finish.
+ * @expires_next:      absolute time of the next event, is required for remote
+ *                     hrtimer enqueue; it is the total first expiry time (hard
+ *                     and soft hrtimer are taken into account)
+ * @next_timer:                Pointer to the first expiring timer
+ * @softirq_expires_next: Time to check, if soft queues needs also to be expired
+ * @softirq_next_timer: Pointer to the first expiring softirq based timer
+ * @clock_base:                array of clock bases for this cpu
+ *
+ * Note: next_timer is just an optimization for __remove_hrtimer().
+ *      Do not dereference the pointer because it is not reliable on
+ *      cross cpu removals.
+ */
+struct hrtimer_cpu_base {
+       raw_spinlock_t                  lock;
+       unsigned int                    cpu;
+       unsigned int                    active_bases;
+       unsigned int                    clock_was_set_seq;
+       unsigned int                    hres_active             : 1,
+                                       in_hrtirq               : 1,
+                                       hang_detected           : 1,
+                                       softirq_activated       : 1,
+                                       online                  : 1;
+#ifdef CONFIG_HIGH_RES_TIMERS
+       unsigned int                    nr_events;
+       unsigned short                  nr_retries;
+       unsigned short                  nr_hangs;
+       unsigned int                    max_hang_time;
+#endif
+#ifdef CONFIG_PREEMPT_RT
+       spinlock_t                      softirq_expiry_lock;
+       atomic_t                        timer_waiters;
+#endif
+       ktime_t                         expires_next;
+       struct hrtimer                  *next_timer;
+       ktime_t                         softirq_expires_next;
+       struct hrtimer                  *softirq_next_timer;
+       struct hrtimer_clock_base       clock_base[HRTIMER_MAX_CLOCK_BASES];
+} ____cacheline_aligned;
+
+
 #endif
index 2b00faf98017cc9c2a99da9f2cc29c45ecbaf2ec..6ef0557b4bff8ed5d14bc18391d356913136c23c 100644 (file)
@@ -164,8 +164,28 @@ struct hv_ring_buffer {
        u8 buffer[];
 } __packed;
 
+
+/*
+ * If the requested ring buffer size is at least 8 times the size of the
+ * header, steal space from the ring buffer for the header. Otherwise, add
+ * space for the header so that is doesn't take too much of the ring buffer
+ * space.
+ *
+ * The factor of 8 is somewhat arbitrary. The goal is to prevent adding a
+ * relatively small header (4 Kbytes on x86) to a large-ish power-of-2 ring
+ * buffer size (such as 128 Kbytes) and so end up making a nearly twice as
+ * large allocation that will be almost half wasted. As a contrasting example,
+ * on ARM64 with 64 Kbyte page size, we don't want to take 64 Kbytes for the
+ * header from a 128 Kbyte allocation, leaving only 64 Kbytes for the ring.
+ * In this latter case, we must add 64 Kbytes for the header and not worry
+ * about what's wasted.
+ */
+#define VMBUS_HEADER_ADJ(payload_sz) \
+       ((payload_sz) >=  8 * sizeof(struct hv_ring_buffer) ? \
+       0 : sizeof(struct hv_ring_buffer))
+
 /* Calculate the proper size of a ringbuffer, it must be page-aligned */
-#define VMBUS_RING_SIZE(payload_sz) PAGE_ALIGN(sizeof(struct hv_ring_buffer) + \
+#define VMBUS_RING_SIZE(payload_sz) PAGE_ALIGN(VMBUS_HEADER_ADJ(payload_sz) + \
                                               (payload_sz))
 
 struct hv_ring_buffer_info {
index 7852f6c9a714c6fb7dc84321c4b416717b6d4666..719cf9cc6e1ac4db6abbd1171b1590716dc50dc9 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __AD_SIGMA_DELTA_H__
 #define __AD_SIGMA_DELTA_H__
 
+#include <linux/iio/iio.h>
+
 enum ad_sigma_delta_mode {
        AD_SD_MODE_CONTINUOUS = 0,
        AD_SD_MODE_SINGLE = 1,
@@ -99,7 +101,7 @@ struct ad_sigma_delta {
         * 'rx_buf' is up to 32 bits per sample + 64 bit timestamp,
         * rounded to 16 bytes to take into account padding.
         */
-       uint8_t                         tx_buf[4] ____cacheline_aligned;
+       uint8_t                         tx_buf[4] __aligned(IIO_DMA_MINALIGN);
        uint8_t                         rx_buf[16] __aligned(8);
 };
 
index 607c3a89a6471df963e6fc4ed09df84b53c0db0f..f9ae5cdd884f5be041246b5aebbf6467980319dc 100644 (file)
@@ -258,9 +258,9 @@ struct st_sensor_data {
        bool hw_irq_trigger;
        s64 hw_timestamp;
 
-       char buffer_data[ST_SENSORS_MAX_BUFFER_SIZE] ____cacheline_aligned;
-
        struct mutex odr_lock;
+
+       char buffer_data[ST_SENSORS_MAX_BUFFER_SIZE] __aligned(IIO_DMA_MINALIGN);
 };
 
 #ifdef CONFIG_IIO_BUFFER
index dc9ea299e0885cd55018f21b80a35155d0ca1d63..8898966bc0f08c152a8156b85151b223f76e9ffe 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/spi/spi.h>
 #include <linux/interrupt.h>
+#include <linux/iio/iio.h>
 #include <linux/iio/types.h>
 
 #define ADIS_WRITE_REG(reg) ((0x80 | (reg)))
@@ -131,7 +132,7 @@ struct adis {
        unsigned long           irq_flag;
        void                    *buffer;
 
-       u8                      tx[10] ____cacheline_aligned;
+       u8                      tx[10] __aligned(IIO_DMA_MINALIGN);
        u8                      rx[4];
 };
 
index adb83a42a6b90b03cb468ef2787a568bd8a008d0..35227d47cfc98c14f80a17a01d8df6050c56768e 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef _LINUX_INDIRECT_CALL_WRAPPER_H
 #define _LINUX_INDIRECT_CALL_WRAPPER_H
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
 
 /*
  * INDIRECT_CALL_$NR - wrapper for indirect calls with $NR known builtin
index 854ad67a5f70e8a9f9055f5d76762717c3c33c69..e248936250852dd09c7e71b958a0072c1ac86193 100644 (file)
@@ -2,6 +2,7 @@
 #define IO_URING_TYPES_H
 
 #include <linux/blkdev.h>
+#include <linux/hashtable.h>
 #include <linux/task_work.h>
 #include <linux/bitmap.h>
 #include <linux/llist.h>
@@ -240,12 +241,14 @@ struct io_ring_ctx {
                unsigned int            poll_activated: 1;
                unsigned int            drain_disabled: 1;
                unsigned int            compat: 1;
+               unsigned int            iowq_limits_set : 1;
 
                struct task_struct      *submitter_task;
                struct io_rings         *rings;
                struct percpu_ref       refs;
 
                enum task_work_notify_mode      notify_method;
+               unsigned                        sq_thread_idle;
        } ____cacheline_aligned_in_smp;
 
        /* submission data */
@@ -274,10 +277,20 @@ struct io_ring_ctx {
                 */
                struct io_rsrc_node     *rsrc_node;
                atomic_t                cancel_seq;
+
+               /*
+                * ->iopoll_list is protected by the ctx->uring_lock for
+                * io_uring instances that don't use IORING_SETUP_SQPOLL.
+                * For SQPOLL, only the single threaded io_sq_thread() will
+                * manipulate the list, hence no extra locking is needed there.
+                */
+               bool                    poll_multi_queue;
+               struct io_wq_work_list  iopoll_list;
+
                struct io_file_table    file_table;
+               struct io_mapped_ubuf   **user_bufs;
                unsigned                nr_user_files;
                unsigned                nr_user_bufs;
-               struct io_mapped_ubuf   **user_bufs;
 
                struct io_submit_state  submit_state;
 
@@ -288,15 +301,6 @@ struct io_ring_ctx {
                struct io_alloc_cache   apoll_cache;
                struct io_alloc_cache   netmsg_cache;
 
-               /*
-                * ->iopoll_list is protected by the ctx->uring_lock for
-                * io_uring instances that don't use IORING_SETUP_SQPOLL.
-                * For SQPOLL, only the single threaded io_sq_thread() will
-                * manipulate the list, hence no extra locking is needed there.
-                */
-               struct io_wq_work_list  iopoll_list;
-               bool                    poll_multi_queue;
-
                /*
                 * Any cancelable uring_cmd is added to this list in
                 * ->uring_cmd() by io_uring_cmd_insert_cancelable()
@@ -343,8 +347,8 @@ struct io_ring_ctx {
        spinlock_t              completion_lock;
 
        /* IRQ completion list, under ->completion_lock */
-       struct io_wq_work_list  locked_free_list;
        unsigned int            locked_free_nr;
+       struct io_wq_work_list  locked_free_list;
 
        struct list_head        io_buffers_comp;
        struct list_head        cq_overflow_list;
@@ -366,9 +370,6 @@ struct io_ring_ctx {
        unsigned int            file_alloc_start;
        unsigned int            file_alloc_end;
 
-       struct xarray           personalities;
-       u32                     pers_next;
-
        struct list_head        io_buffers_cache;
 
        /* deferred free list, protected by ->uring_lock */
@@ -389,6 +390,9 @@ struct io_ring_ctx {
        struct wait_queue_head          rsrc_quiesce_wq;
        unsigned                        rsrc_quiesce;
 
+       u32                     pers_next;
+       struct xarray           personalities;
+
        /* hashed buffered write serialization */
        struct io_wq_hash               *hash_map;
 
@@ -405,11 +409,22 @@ struct io_ring_ctx {
 
        /* io-wq management, e.g. thread count */
        u32                             iowq_limits[2];
-       bool                            iowq_limits_set;
 
        struct callback_head            poll_wq_task_work;
        struct list_head                defer_list;
-       unsigned                        sq_thread_idle;
+
+#ifdef CONFIG_NET_RX_BUSY_POLL
+       struct list_head        napi_list;      /* track busy poll napi_id */
+       spinlock_t              napi_lock;      /* napi_list lock */
+
+       /* napi busy poll default timeout */
+       unsigned int            napi_busy_poll_to;
+       bool                    napi_prefer_busy_poll;
+       bool                    napi_enabled;
+
+       DECLARE_HASHTABLE(napi_ht, 4);
+#endif
+
        /* protected by ->completion_lock */
        unsigned                        evfd_last_cq_tail;
 
@@ -455,7 +470,6 @@ enum {
        REQ_F_SKIP_LINK_CQES_BIT,
        REQ_F_SINGLE_POLL_BIT,
        REQ_F_DOUBLE_POLL_BIT,
-       REQ_F_PARTIAL_IO_BIT,
        REQ_F_APOLL_MULTISHOT_BIT,
        REQ_F_CLEAR_POLLIN_BIT,
        REQ_F_HASH_LOCKED_BIT,
@@ -463,75 +477,88 @@ enum {
        REQ_F_SUPPORT_NOWAIT_BIT,
        REQ_F_ISREG_BIT,
        REQ_F_POLL_NO_LAZY_BIT,
+       REQ_F_CANCEL_SEQ_BIT,
+       REQ_F_CAN_POLL_BIT,
+       REQ_F_BL_EMPTY_BIT,
+       REQ_F_BL_NO_RECYCLE_BIT,
 
        /* not a real bit, just to check we're not overflowing the space */
        __REQ_F_LAST_BIT,
 };
 
+typedef u64 __bitwise io_req_flags_t;
+#define IO_REQ_FLAG(bitno)     ((__force io_req_flags_t) BIT_ULL((bitno)))
+
 enum {
        /* ctx owns file */
-       REQ_F_FIXED_FILE        = BIT(REQ_F_FIXED_FILE_BIT),
+       REQ_F_FIXED_FILE        = IO_REQ_FLAG(REQ_F_FIXED_FILE_BIT),
        /* drain existing IO first */
-       REQ_F_IO_DRAIN          = BIT(REQ_F_IO_DRAIN_BIT),
+       REQ_F_IO_DRAIN          = IO_REQ_FLAG(REQ_F_IO_DRAIN_BIT),
        /* linked sqes */
-       REQ_F_LINK              = BIT(REQ_F_LINK_BIT),
+       REQ_F_LINK              = IO_REQ_FLAG(REQ_F_LINK_BIT),
        /* doesn't sever on completion < 0 */
-       REQ_F_HARDLINK          = BIT(REQ_F_HARDLINK_BIT),
+       REQ_F_HARDLINK          = IO_REQ_FLAG(REQ_F_HARDLINK_BIT),
        /* IOSQE_ASYNC */
-       REQ_F_FORCE_ASYNC       = BIT(REQ_F_FORCE_ASYNC_BIT),
+       REQ_F_FORCE_ASYNC       = IO_REQ_FLAG(REQ_F_FORCE_ASYNC_BIT),
        /* IOSQE_BUFFER_SELECT */
-       REQ_F_BUFFER_SELECT     = BIT(REQ_F_BUFFER_SELECT_BIT),
+       REQ_F_BUFFER_SELECT     = IO_REQ_FLAG(REQ_F_BUFFER_SELECT_BIT),
        /* IOSQE_CQE_SKIP_SUCCESS */
-       REQ_F_CQE_SKIP          = BIT(REQ_F_CQE_SKIP_BIT),
+       REQ_F_CQE_SKIP          = IO_REQ_FLAG(REQ_F_CQE_SKIP_BIT),
 
        /* fail rest of links */
-       REQ_F_FAIL              = BIT(REQ_F_FAIL_BIT),
+       REQ_F_FAIL              = IO_REQ_FLAG(REQ_F_FAIL_BIT),
        /* on inflight list, should be cancelled and waited on exit reliably */
-       REQ_F_INFLIGHT          = BIT(REQ_F_INFLIGHT_BIT),
+       REQ_F_INFLIGHT          = IO_REQ_FLAG(REQ_F_INFLIGHT_BIT),
        /* read/write uses file position */
-       REQ_F_CUR_POS           = BIT(REQ_F_CUR_POS_BIT),
+       REQ_F_CUR_POS           = IO_REQ_FLAG(REQ_F_CUR_POS_BIT),
        /* must not punt to workers */
-       REQ_F_NOWAIT            = BIT(REQ_F_NOWAIT_BIT),
+       REQ_F_NOWAIT            = IO_REQ_FLAG(REQ_F_NOWAIT_BIT),
        /* has or had linked timeout */
-       REQ_F_LINK_TIMEOUT      = BIT(REQ_F_LINK_TIMEOUT_BIT),
+       REQ_F_LINK_TIMEOUT      = IO_REQ_FLAG(REQ_F_LINK_TIMEOUT_BIT),
        /* needs cleanup */
-       REQ_F_NEED_CLEANUP      = BIT(REQ_F_NEED_CLEANUP_BIT),
+       REQ_F_NEED_CLEANUP      = IO_REQ_FLAG(REQ_F_NEED_CLEANUP_BIT),
        /* already went through poll handler */
-       REQ_F_POLLED            = BIT(REQ_F_POLLED_BIT),
+       REQ_F_POLLED            = IO_REQ_FLAG(REQ_F_POLLED_BIT),
        /* buffer already selected */
-       REQ_F_BUFFER_SELECTED   = BIT(REQ_F_BUFFER_SELECTED_BIT),
+       REQ_F_BUFFER_SELECTED   = IO_REQ_FLAG(REQ_F_BUFFER_SELECTED_BIT),
        /* buffer selected from ring, needs commit */
-       REQ_F_BUFFER_RING       = BIT(REQ_F_BUFFER_RING_BIT),
+       REQ_F_BUFFER_RING       = IO_REQ_FLAG(REQ_F_BUFFER_RING_BIT),
        /* caller should reissue async */
-       REQ_F_REISSUE           = BIT(REQ_F_REISSUE_BIT),
+       REQ_F_REISSUE           = IO_REQ_FLAG(REQ_F_REISSUE_BIT),
        /* supports async reads/writes */
-       REQ_F_SUPPORT_NOWAIT    = BIT(REQ_F_SUPPORT_NOWAIT_BIT),
+       REQ_F_SUPPORT_NOWAIT    = IO_REQ_FLAG(REQ_F_SUPPORT_NOWAIT_BIT),
        /* regular file */
-       REQ_F_ISREG             = BIT(REQ_F_ISREG_BIT),
+       REQ_F_ISREG             = IO_REQ_FLAG(REQ_F_ISREG_BIT),
        /* has creds assigned */
-       REQ_F_CREDS             = BIT(REQ_F_CREDS_BIT),
+       REQ_F_CREDS             = IO_REQ_FLAG(REQ_F_CREDS_BIT),
        /* skip refcounting if not set */
-       REQ_F_REFCOUNT          = BIT(REQ_F_REFCOUNT_BIT),
+       REQ_F_REFCOUNT          = IO_REQ_FLAG(REQ_F_REFCOUNT_BIT),
        /* there is a linked timeout that has to be armed */
-       REQ_F_ARM_LTIMEOUT      = BIT(REQ_F_ARM_LTIMEOUT_BIT),
+       REQ_F_ARM_LTIMEOUT      = IO_REQ_FLAG(REQ_F_ARM_LTIMEOUT_BIT),
        /* ->async_data allocated */
-       REQ_F_ASYNC_DATA        = BIT(REQ_F_ASYNC_DATA_BIT),
+       REQ_F_ASYNC_DATA        = IO_REQ_FLAG(REQ_F_ASYNC_DATA_BIT),
        /* don't post CQEs while failing linked requests */
-       REQ_F_SKIP_LINK_CQES    = BIT(REQ_F_SKIP_LINK_CQES_BIT),
+       REQ_F_SKIP_LINK_CQES    = IO_REQ_FLAG(REQ_F_SKIP_LINK_CQES_BIT),
        /* single poll may be active */
-       REQ_F_SINGLE_POLL       = BIT(REQ_F_SINGLE_POLL_BIT),
+       REQ_F_SINGLE_POLL       = IO_REQ_FLAG(REQ_F_SINGLE_POLL_BIT),
        /* double poll may active */
-       REQ_F_DOUBLE_POLL       = BIT(REQ_F_DOUBLE_POLL_BIT),
-       /* request has already done partial IO */
-       REQ_F_PARTIAL_IO        = BIT(REQ_F_PARTIAL_IO_BIT),
+       REQ_F_DOUBLE_POLL       = IO_REQ_FLAG(REQ_F_DOUBLE_POLL_BIT),
        /* fast poll multishot mode */
-       REQ_F_APOLL_MULTISHOT   = BIT(REQ_F_APOLL_MULTISHOT_BIT),
+       REQ_F_APOLL_MULTISHOT   = IO_REQ_FLAG(REQ_F_APOLL_MULTISHOT_BIT),
        /* recvmsg special flag, clear EPOLLIN */
-       REQ_F_CLEAR_POLLIN      = BIT(REQ_F_CLEAR_POLLIN_BIT),
+       REQ_F_CLEAR_POLLIN      = IO_REQ_FLAG(REQ_F_CLEAR_POLLIN_BIT),
        /* hashed into ->cancel_hash_locked, protected by ->uring_lock */
-       REQ_F_HASH_LOCKED       = BIT(REQ_F_HASH_LOCKED_BIT),
+       REQ_F_HASH_LOCKED       = IO_REQ_FLAG(REQ_F_HASH_LOCKED_BIT),
        /* don't use lazy poll wake for this request */
-       REQ_F_POLL_NO_LAZY      = BIT(REQ_F_POLL_NO_LAZY_BIT),
+       REQ_F_POLL_NO_LAZY      = IO_REQ_FLAG(REQ_F_POLL_NO_LAZY_BIT),
+       /* cancel sequence is set and valid */
+       REQ_F_CANCEL_SEQ        = IO_REQ_FLAG(REQ_F_CANCEL_SEQ_BIT),
+       /* file is pollable */
+       REQ_F_CAN_POLL          = IO_REQ_FLAG(REQ_F_CAN_POLL_BIT),
+       /* buffer list was empty after selection of buffer */
+       REQ_F_BL_EMPTY          = IO_REQ_FLAG(REQ_F_BL_EMPTY_BIT),
+       /* don't recycle provided buffers for this request */
+       REQ_F_BL_NO_RECYCLE     = IO_REQ_FLAG(REQ_F_BL_NO_RECYCLE_BIT),
 };
 
 typedef void (*io_req_tw_func_t)(struct io_kiocb *req, struct io_tw_state *ts);
@@ -592,15 +619,17 @@ struct io_kiocb {
         * and after selection it points to the buffer ID itself.
         */
        u16                             buf_index;
-       unsigned int                    flags;
+
+       unsigned                        nr_tw;
+
+       /* REQ_F_* flags */
+       io_req_flags_t                  flags;
 
        struct io_cqe                   cqe;
 
        struct io_ring_ctx              *ctx;
        struct task_struct              *task;
 
-       struct io_rsrc_node             *rsrc_node;
-
        union {
                /* store used ubuf, so we can prevent reloading */
                struct io_mapped_ubuf   *imu;
@@ -621,10 +650,12 @@ struct io_kiocb {
                /* cache ->apoll->events */
                __poll_t apoll_events;
        };
+
+       struct io_rsrc_node             *rsrc_node;
+
        atomic_t                        refs;
        atomic_t                        poll_refs;
        struct io_task_work             io_task_work;
-       unsigned                        nr_tw;
        /* for polled requests, i.e. IORING_OP_POLL_ADD and async armed poll */
        struct hlist_node               hash_node;
        /* internal polling, see IORING_FEAT_FAST_POLL */
index 96dd0acbba44aca735ff027ffb8f1c118cb762e8..6fc1c858013d1e4dda4ed38fa4083acf25d16d36 100644 (file)
@@ -293,22 +293,32 @@ struct iomap_ioend {
        struct list_head        io_list;        /* next ioend in chain */
        u16                     io_type;
        u16                     io_flags;       /* IOMAP_F_* */
-       u32                     io_folios;      /* folios added to ioend */
        struct inode            *io_inode;      /* file being written to */
        size_t                  io_size;        /* size of the extent */
        loff_t                  io_offset;      /* offset in the file */
        sector_t                io_sector;      /* start sector of ioend */
-       struct bio              *io_bio;        /* bio being built */
-       struct bio              io_inline_bio;  /* MUST BE LAST! */
+       struct bio              io_bio;         /* MUST BE LAST! */
 };
 
+static inline struct iomap_ioend *iomap_ioend_from_bio(struct bio *bio)
+{
+       return container_of(bio, struct iomap_ioend, io_bio);
+}
+
 struct iomap_writeback_ops {
        /*
         * Required, maps the blocks so that writeback can be performed on
         * the range starting at offset.
+        *
+        * Can return arbitrarily large regions, but we need to call into it at
+        * least once per folio to allow the file systems to synchronize with
+        * the write path that could be invalidating mappings.
+        *
+        * An existing mapping from a previous call to this method can be reused
+        * by the file system if it is still valid.
         */
        int (*map_blocks)(struct iomap_writepage_ctx *wpc, struct inode *inode,
-                               loff_t offset);
+                         loff_t offset, unsigned len);
 
        /*
         * Optional, allows the file systems to perform actions just before
@@ -329,6 +339,7 @@ struct iomap_writepage_ctx {
        struct iomap            iomap;
        struct iomap_ioend      *ioend;
        const struct iomap_writeback_ops *ops;
+       u32                     nr_folios;      /* folios added to the ioend */
 };
 
 void iomap_finish_ioends(struct iomap_ioend *ioend, int error);
index 1ea2a820e1eb035c9eea2ec97d9874c52bbd0b42..5e27cb3a3be99b34e705cb7c4569cfbdf2b11f82 100644 (file)
@@ -892,11 +892,14 @@ struct iommu_fwspec {
 struct iommu_sva {
        struct device                   *dev;
        struct iommu_domain             *domain;
+       struct list_head                handle_item;
+       refcount_t                      users;
 };
 
 struct iommu_mm_data {
        u32                     pasid;
        struct list_head        sva_domains;
+       struct list_head        sva_handles;
 };
 
 int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
index 90081afa10ce529f053d97d094f65722c80b9efe..97baa937ab5b99fca75f4f707cfba14b0ba7b649 100644 (file)
@@ -179,7 +179,7 @@ struct irq_common_data {
 struct irq_data {
        u32                     mask;
        unsigned int            irq;
-       unsigned long           hwirq;
+       irq_hw_number_t         hwirq;
        struct irq_common_data  *common;
        struct irq_chip         *chip;
        struct irq_domain       *domain;
index ee0a82c6050838dcd3f62264b0693f844013d1fb..21ecf582a0fe4ac070db364192be12ce9b1f253c 100644 (file)
@@ -619,6 +619,23 @@ static inline bool irq_domain_is_msi_device(struct irq_domain *domain)
 
 #endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
 
+#ifdef CONFIG_GENERIC_MSI_IRQ
+int msi_device_domain_alloc_wired(struct irq_domain *domain, unsigned int hwirq,
+                                 unsigned int type);
+void msi_device_domain_free_wired(struct irq_domain *domain, unsigned int virq);
+#else
+static inline int msi_device_domain_alloc_wired(struct irq_domain *domain, unsigned int hwirq,
+                                               unsigned int type)
+{
+       WARN_ON_ONCE(1);
+       return -EINVAL;
+}
+static inline void msi_device_domain_free_wired(struct irq_domain *domain, unsigned int virq)
+{
+       WARN_ON_ONCE(1);
+}
+#endif
+
 #else /* CONFIG_IRQ_DOMAIN */
 static inline void irq_dispose_mapping(unsigned int virq) { }
 static inline struct irq_domain *irq_find_matching_fwnode(
index c29921fd8cd15a892adeb33752601d81747fda9c..5c1fe6f1fcde86e85c3ff2721d4a0096c0d8913e 100644 (file)
@@ -26,6 +26,8 @@ enum irq_domain_bus_token {
        DOMAIN_BUS_DMAR,
        DOMAIN_BUS_AMDVI,
        DOMAIN_BUS_PCI_DEVICE_IMS,
+       DOMAIN_BUS_DEVICE_MSI,
+       DOMAIN_BUS_WIRED_TO_MSI,
 };
 
 #endif /* _LINUX_IRQDOMAIN_DEFS_H */
index c30f454a9518f149eaf63615cf654d0d042c2e24..72dd1eb3a0e7f60cc8e6d726fd9ce12e16bd042f 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 struct irq_desc;
-struct irq_data;
+
 typedef        void (*irq_flow_handler_t)(struct irq_desc *desc);
 
 #endif
index e0ae2a43e0ebdd22d17680477c2bb152b6ba767b..d9f1435a5a13cfe4d74bfb945265bad8ab7cb772 100644 (file)
@@ -102,12 +102,15 @@ static inline u64 get_jiffies_64(void)
 }
 #endif
 
-/*
- *     These inlines deal with timer wrapping correctly. You are
- *     strongly encouraged to use them:
- *     1. Because people otherwise forget
- *     2. Because if the timer wrap changes in future you won't have to
- *        alter your driver code.
+/**
+ * DOC: General information about time_* inlines
+ *
+ * These inlines deal with timer wrapping correctly. You are strongly encouraged
+ * to use them:
+ *
+ * #. Because people otherwise forget
+ * #. Because if the timer wrap changes in future you won't have to alter your
+ *    driver code.
  */
 
 /**
index 7e7fd25b09b3ebe3d81e30fb23f506a9ee5a6519..179df96b20f88d065d0c9be4d4ef643b71a801c6 100644 (file)
@@ -2031,6 +2031,32 @@ static inline int mmu_invalidate_retry_gfn(struct kvm *kvm,
                return 1;
        return 0;
 }
+
+/*
+ * This lockless version of the range-based retry check *must* be paired with a
+ * call to the locked version after acquiring mmu_lock, i.e. this is safe to
+ * use only as a pre-check to avoid contending mmu_lock.  This version *will*
+ * get false negatives and false positives.
+ */
+static inline bool mmu_invalidate_retry_gfn_unsafe(struct kvm *kvm,
+                                                  unsigned long mmu_seq,
+                                                  gfn_t gfn)
+{
+       /*
+        * Use READ_ONCE() to ensure the in-progress flag and sequence counter
+        * are always read from memory, e.g. so that checking for retry in a
+        * loop won't result in an infinite retry loop.  Don't force loads for
+        * start+end, as the key to avoiding infinite retry loops is observing
+        * the 1=>0 transition of in-progress, i.e. getting false negatives
+        * due to stale start+end values is acceptable.
+        */
+       if (unlikely(READ_ONCE(kvm->mmu_invalidate_in_progress)) &&
+           gfn >= kvm->mmu_invalidate_range_start &&
+           gfn < kvm->mmu_invalidate_range_end)
+               return true;
+
+       return READ_ONCE(kvm->mmu_invalidate_seq) != mmu_seq;
+}
 #endif
 
 #ifdef CONFIG_HAVE_KVM_IRQ_ROUTING
index 9f565416d18671e110e1fb99e44b96e241b519d4..1b95fe31051ff393084d622b03c7ff7746f75700 100644 (file)
@@ -375,12 +375,12 @@ static inline int nlm_privileged_requester(const struct svc_rqst *rqstp)
 static inline int nlm_compare_locks(const struct file_lock *fl1,
                                    const struct file_lock *fl2)
 {
-       return file_inode(fl1->fl_file) == file_inode(fl2->fl_file)
-            && fl1->fl_pid   == fl2->fl_pid
-            && fl1->fl_owner == fl2->fl_owner
+       return file_inode(fl1->c.flc_file) == file_inode(fl2->c.flc_file)
+            && fl1->c.flc_pid   == fl2->c.flc_pid
+            && fl1->c.flc_owner == fl2->c.flc_owner
             && fl1->fl_start == fl2->fl_start
             && fl1->fl_end   == fl2->fl_end
-            &&(fl1->fl_type  == fl2->fl_type || fl2->fl_type == F_UNLCK);
+            &&(fl1->c.flc_type  == fl2->c.flc_type || fl2->c.flc_type == F_UNLCK);
 }
 
 extern const struct lock_manager_operations nlmsvc_lock_operations;
index b60fbcd8cdfad5a5e607eb0c456e3afd559e0ec2..80cca9426761532f18c274b37789ee1f4462b701 100644 (file)
@@ -52,7 +52,7 @@ struct nlm_lock {
  *     FreeBSD uses 16, Apple Mac OS X 10.3 uses 20. Therefore we set it to
  *     32 bytes.
  */
+
 struct nlm_cookie
 {
        unsigned char data[NLM_MAXCOOKIELEN];
index b3d63123b945b58bc7549142d79fd2783f2b0f07..a53ad4dabd7e8f7618a991d3fd17dc65fe2f33fd 100644 (file)
@@ -171,6 +171,7 @@ enum maple_type {
 #define MT_FLAGS_LOCK_IRQ      0x100
 #define MT_FLAGS_LOCK_BH       0x200
 #define MT_FLAGS_LOCK_EXTERN   0x300
+#define MT_FLAGS_ALLOC_WRAPPED 0x0800
 
 #define MAPLE_HEIGHT_MAX       31
 
@@ -319,6 +320,9 @@ int mtree_insert_range(struct maple_tree *mt, unsigned long first,
 int mtree_alloc_range(struct maple_tree *mt, unsigned long *startp,
                void *entry, unsigned long size, unsigned long min,
                unsigned long max, gfp_t gfp);
+int mtree_alloc_cyclic(struct maple_tree *mt, unsigned long *startp,
+               void *entry, unsigned long range_lo, unsigned long range_hi,
+               unsigned long *next, gfp_t gfp);
 int mtree_alloc_rrange(struct maple_tree *mt, unsigned long *startp,
                void *entry, unsigned long size, unsigned long min,
                unsigned long max, gfp_t gfp);
@@ -499,6 +503,9 @@ void *mas_find_range(struct ma_state *mas, unsigned long max);
 void *mas_find_rev(struct ma_state *mas, unsigned long min);
 void *mas_find_range_rev(struct ma_state *mas, unsigned long max);
 int mas_preallocate(struct ma_state *mas, void *entry, gfp_t gfp);
+int mas_alloc_cyclic(struct ma_state *mas, unsigned long *startp,
+               void *entry, unsigned long range_lo, unsigned long range_hi,
+               unsigned long *next, gfp_t gfp);
 
 bool mas_nomem(struct ma_state *mas, gfp_t gfp);
 void mas_pause(struct ma_state *mas);
index b695f9e946dabb46f08e1d1688d275bb3ff35b49..e2082240586d00b5f21af7b3f9e0ca6176b5884a 100644 (file)
@@ -121,6 +121,8 @@ int memblock_reserve(phys_addr_t base, phys_addr_t size);
 int memblock_physmem_add(phys_addr_t base, phys_addr_t size);
 #endif
 void memblock_trim_memory(phys_addr_t align);
+unsigned long memblock_addrs_overlap(phys_addr_t base1, phys_addr_t size1,
+                                    phys_addr_t base2, phys_addr_t size2);
 bool memblock_overlaps_region(struct memblock_type *type,
                              phys_addr_t base, phys_addr_t size);
 bool memblock_validate_numa_coverage(unsigned long threshold_bytes);
index c726f90ab752452cbe9726462ecedd72b21656f6..486b7492050c3daa04459c7de0e8471faca27ba4 100644 (file)
@@ -1103,7 +1103,7 @@ struct mlx5_ifc_roce_cap_bits {
        u8         sw_r_roce_src_udp_port[0x1];
        u8         fl_rc_qp_when_roce_disabled[0x1];
        u8         fl_rc_qp_when_roce_enabled[0x1];
-       u8         reserved_at_7[0x1];
+       u8         roce_cc_general[0x1];
        u8         qp_ooo_transmit_default[0x1];
        u8         reserved_at_9[0x15];
        u8         qp_ts_format[0x2];
@@ -10261,7 +10261,9 @@ struct mlx5_ifc_mcam_access_reg_bits {
 
        u8         regs_63_to_46[0x12];
        u8         mrtc[0x1];
-       u8         regs_44_to_32[0xd];
+       u8         regs_44_to_41[0x4];
+       u8         mfrl[0x1];
+       u8         regs_39_to_32[0x8];
 
        u8         regs_31_to_10[0x16];
        u8         mtmp[0x1];
index bd53cf4be7bdcbe4ea47ab640fbe0052ffc88bef..f0e55bf3ec8b5b0dd10c3270c1659e1fbb96ac64 100644 (file)
@@ -269,7 +269,10 @@ struct mlx5_wqe_eth_seg {
        union {
                struct {
                        __be16 sz;
-                       u8     start[2];
+                       union {
+                               u8     start[2];
+                               DECLARE_FLEX_ARRAY(u8, data);
+                       };
                } inline_hdr;
                struct {
                        __be16 type;
index 96bc462872c0ca9fcecfb06a4c68e3f12697d789..1153b0d99a808876f7ba62d137e5095e1e92a954 100644 (file)
@@ -885,7 +885,7 @@ static inline void module_bug_finalize(const Elf_Ehdr *hdr,
 static inline void module_bug_cleanup(struct module *mod) {}
 #endif /* CONFIG_GENERIC_BUG */
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
 extern bool retpoline_module_ok(bool has_retpoline);
 #else
 static inline bool retpoline_module_ok(bool has_retpoline)
index ddace8c34dcf958edae65de2858bf924adb9d19e..26d07e23052e05d26ca3ca9deaca219e173577d5 100644 (file)
@@ -412,6 +412,7 @@ bool arch_restore_msi_irqs(struct pci_dev *dev);
 struct irq_domain;
 struct irq_domain_ops;
 struct irq_chip;
+struct irq_fwspec;
 struct device_node;
 struct fwnode_handle;
 struct msi_domain_info;
@@ -431,6 +432,8 @@ struct msi_domain_info;
  *                     function.
  * @msi_post_free:     Optional function which is invoked after freeing
  *                     all interrupts.
+ * @msi_translate:     Optional translate callback to support the odd wire to
+ *                     MSI bridges, e.g. MBIGEN
  *
  * @get_hwirq, @msi_init and @msi_free are callbacks used by the underlying
  * irqdomain.
@@ -468,6 +471,8 @@ struct msi_domain_ops {
                                            struct device *dev);
        void            (*msi_post_free)(struct irq_domain *domain,
                                         struct device *dev);
+       int             (*msi_translate)(struct irq_domain *domain, struct irq_fwspec *fwspec,
+                                        irq_hw_number_t *hwirq, unsigned int *type);
 };
 
 /**
@@ -547,6 +552,10 @@ enum {
        MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS = (1 << 5),
        /* Free MSI descriptors */
        MSI_FLAG_FREE_MSI_DESCS         = (1 << 6),
+       /* Use dev->fwnode for MSI device domain creation */
+       MSI_FLAG_USE_DEV_FWNODE         = (1 << 7),
+       /* Set parent->dev into domain->pm_dev on device domain creation */
+       MSI_FLAG_PARENT_PM_DEV          = (1 << 8),
 
        /* Mask for the generic functionality */
        MSI_GENERIC_FLAGS_MASK          = GENMASK(15, 0),
@@ -572,6 +581,11 @@ enum {
  * struct msi_parent_ops - MSI parent domain callbacks and configuration info
  *
  * @supported_flags:   Required: The supported MSI flags of the parent domain
+ * @required_flags:    Optional: The required MSI flags of the parent MSI domain
+ * @bus_select_token:  Optional: The bus token of the real parent domain for
+ *                     irq_domain::select()
+ * @bus_select_mask:   Optional: A mask of supported BUS_DOMAINs for
+ *                     irq_domain::select()
  * @prefix:            Optional: Prefix for the domain and chip name
  * @init_dev_msi_info: Required: Callback for MSI parent domains to setup parent
  *                     domain specific domain flags, domain ops and interrupt chip
@@ -579,6 +593,9 @@ enum {
  */
 struct msi_parent_ops {
        u32             supported_flags;
+       u32             required_flags;
+       u32             bus_select_token;
+       u32             bus_select_mask;
        const char      *prefix;
        bool            (*init_dev_msi_info)(struct device *dev, struct irq_domain *domain,
                                             struct irq_domain *msi_parent_domain,
@@ -627,9 +644,6 @@ struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
 struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode,
                                                  struct msi_domain_info *info,
                                                  struct irq_domain *parent);
-int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
-                                  irq_write_msi_msg_t write_msi_msg);
-void platform_msi_domain_free_irqs(struct device *dev);
 
 /* When an MSI domain is used as an intermediate domain */
 int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
@@ -656,6 +670,10 @@ int platform_msi_device_domain_alloc(struct irq_domain *domain, unsigned int vir
 void platform_msi_device_domain_free(struct irq_domain *domain, unsigned int virq,
                                     unsigned int nvec);
 void *platform_msi_get_host_data(struct irq_domain *domain);
+/* Per device platform MSI */
+int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nvec,
+                                           irq_write_msi_msg_t write_msi_msg);
+void platform_device_msi_free_irqs_all(struct device *dev);
 
 bool msi_device_has_isolated_msi(struct device *dev);
 #else /* CONFIG_GENERIC_MSI_IRQ */
index 7e208d46ba5b838bb391fe821dae1e10cd77204e..67edc4ca2beeb77ece386f70cc81a04526e91704 100644 (file)
 # define __DEP_MAP_MUTEX_INITIALIZER(lockname)
 #endif
 
-#ifndef CONFIG_PREEMPT_RT
-
 #ifdef CONFIG_DEBUG_MUTEXES
 
-#define __DEBUG_MUTEX_INITIALIZER(lockname)                            \
+# define __DEBUG_MUTEX_INITIALIZER(lockname)                           \
        , .magic = &lockname
 
 extern void mutex_destroy(struct mutex *lock);
@@ -49,6 +47,7 @@ static inline void mutex_destroy(struct mutex *lock) {}
 
 #endif
 
+#ifndef CONFIG_PREEMPT_RT
 /**
  * mutex_init - initialize the mutex
  * @mutex: the mutex to be initialized
@@ -101,9 +100,6 @@ extern bool mutex_is_locked(struct mutex *lock);
 
 extern void __mutex_rt_init(struct mutex *lock, const char *name,
                            struct lock_class_key *key);
-extern int mutex_trylock(struct mutex *lock);
-
-static inline void mutex_destroy(struct mutex *lock) { }
 
 #define mutex_is_locked(l)     rt_mutex_base_is_locked(&(l)->rtmutex)
 
index 118c40258d07b787adf518e576e75545e4bae846..78a09af89e39b7a43ce211cbbf17e7fe035d36bb 100644 (file)
@@ -79,8 +79,6 @@ struct xdp_buff;
 struct xdp_frame;
 struct xdp_metadata_ops;
 struct xdp_md;
-/* DPLL specific */
-struct dpll_pin;
 
 typedef u32 xdp_features_t;
 
@@ -2141,6 +2139,11 @@ struct net_device {
 
        /* TXRX read-mostly hotpath */
        __cacheline_group_begin(net_device_read_txrx);
+       union {
+               struct pcpu_lstats __percpu             *lstats;
+               struct pcpu_sw_netstats __percpu        *tstats;
+               struct pcpu_dstats __percpu             *dstats;
+       };
        unsigned int            flags;
        unsigned short          hard_header_len;
        netdev_features_t       features;
@@ -2395,11 +2398,6 @@ struct net_device {
        enum netdev_ml_priv_type        ml_priv_type;
 
        enum netdev_stat_type           pcpu_stat_type:8;
-       union {
-               struct pcpu_lstats __percpu             *lstats;
-               struct pcpu_sw_netstats __percpu        *tstats;
-               struct pcpu_dstats __percpu             *dstats;
-       };
 
 #if IS_ENABLED(CONFIG_GARP)
        struct garp_port __rcu  *garp_port;
@@ -2469,7 +2467,7 @@ struct net_device {
        struct devlink_port     *devlink_port;
 
 #if IS_ENABLED(CONFIG_DPLL)
-       struct dpll_pin         *dpll_pin;
+       struct dpll_pin __rcu   *dpll_pin;
 #endif
 #if IS_ENABLED(CONFIG_PAGE_POOL)
        /** @page_pools: page pools created for this netdevice */
@@ -3499,6 +3497,16 @@ static inline void netdev_queue_set_dql_min_limit(struct netdev_queue *dev_queue
 #endif
 }
 
+static inline int netdev_queue_dql_avail(const struct netdev_queue *txq)
+{
+#ifdef CONFIG_BQL
+       /* Non-BQL migrated drivers will return 0, too. */
+       return dql_avail(&txq->dql);
+#else
+       return 0;
+#endif
+}
+
 /**
  *     netdev_txq_bql_enqueue_prefetchw - prefetch bql data for write
  *     @dev_queue: pointer to transmit queue
@@ -4032,17 +4040,6 @@ int dev_get_mac_address(struct sockaddr *sa, struct net *net, char *dev_name);
 int dev_get_port_parent_id(struct net_device *dev,
                           struct netdev_phys_item_id *ppid, bool recurse);
 bool netdev_port_same_parent_id(struct net_device *a, struct net_device *b);
-void netdev_dpll_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin);
-void netdev_dpll_pin_clear(struct net_device *dev);
-
-static inline struct dpll_pin *netdev_dpll_pin(const struct net_device *dev)
-{
-#if IS_ENABLED(CONFIG_DPLL)
-       return dev->dpll_pin;
-#else
-       return NULL;
-#endif
-}
 
 struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev, bool *again);
 struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
index 80900d9109920f686f971e431b95361a831fcc26..ce660d51549b469243357bf9187e108582bc4d95 100644 (file)
@@ -474,6 +474,7 @@ struct nf_ct_hook {
                              const struct sk_buff *);
        void (*attach)(struct sk_buff *nskb, const struct sk_buff *skb);
        void (*set_closing)(struct nf_conntrack *nfct);
+       int (*confirm)(struct sk_buff *skb);
 };
 extern const struct nf_ct_hook __rcu *nf_ct_hook;
 
index cd797e00fe359a91b44b2e012309e87d5b446a7e..92de074e63b98c03cefbb2f07d60de0b8f1fb039 100644 (file)
@@ -124,6 +124,7 @@ struct nfs_client {
        char                    cl_ipaddr[48];
        struct net              *cl_net;
        struct list_head        pending_cb_stateids;
+       struct rcu_head         rcu;
 };
 
 /*
@@ -265,6 +266,7 @@ struct nfs_server {
        const struct cred       *cred;
        bool                    has_sec_mnt_opts;
        struct kobject          kobj;
+       struct rcu_head         rcu;
 };
 
 /* Server capabilities */
index 0f1d024bd9582618a54b601988969694b4dafb47..7d22ea50b09841ed2f764273564e53588e9b7a4e 100644 (file)
@@ -7,7 +7,7 @@
 struct proc_ns_operations;
 
 struct ns_common {
-       atomic_long_t stashed;
+       struct dentry *stashed;
        const struct proc_ns_operations *ops;
        unsigned int inum;
        refcount_t count;
index 4dd7e6fe92fb011d70b5a9dcb83e16f9d0a96b3f..eb2f04d636c89866167021019049fb979006c81e 100644 (file)
@@ -6,7 +6,11 @@
 #ifndef _LINUX_NVME_RDMA_H
 #define _LINUX_NVME_RDMA_H
 
-#define NVME_RDMA_MAX_QUEUE_SIZE       128
+#define NVME_RDMA_IP_PORT              4420
+
+#define NVME_RDMA_MAX_QUEUE_SIZE 256
+#define NVME_RDMA_MAX_METADATA_QUEUE_SIZE 128
+#define NVME_RDMA_DEFAULT_QUEUE_SIZE 128
 
 enum nvme_rdma_cm_fmt {
        NVME_RDMA_CM_FMT_1_0 = 0x0,
index bc605ec4a3fd06f9145242827fe310a760f00122..425573202295352796c8261b1c9345a3721760df 100644 (file)
@@ -23,8 +23,6 @@
 
 #define NVME_DISC_SUBSYS_NAME  "nqn.2014-08.org.nvmexpress.discovery"
 
-#define NVME_RDMA_IP_PORT      4420
-
 #define NVME_NSID_ALL          0xffffffff
 
 enum nvme_subsys_type {
@@ -646,6 +644,7 @@ enum {
        NVME_CMD_EFFECTS_NCC            = 1 << 2,
        NVME_CMD_EFFECTS_NIC            = 1 << 3,
        NVME_CMD_EFFECTS_CCC            = 1 << 4,
+       NVME_CMD_EFFECTS_CSER_MASK      = GENMASK(15, 14),
        NVME_CMD_EFFECTS_CSE_MASK       = GENMASK(18, 16),
        NVME_CMD_EFFECTS_UUID_SEL       = 1 << 19,
        NVME_CMD_EFFECTS_SCOPE_MASK     = GENMASK(31, 20),
index 33212e93f4a6318493342a541894ec0879a884fa..b3b8d3dab52d5c5b43b390bb5a204226164c2796 100644 (file)
  */
 .macro VALIDATE_UNRET_BEGIN
 #if defined(CONFIG_NOINSTR_VALIDATION) && \
-       (defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_SRSO))
+       (defined(CONFIG_MITIGATION_UNRET_ENTRY) || defined(CONFIG_MITIGATION_SRSO))
 .Lhere_\@:
        .pushsection .discard.validate_unret
        .long   .Lhere_\@ - .
index 395cacce1179cac85b7f427d188361da75bfd169..c79a0efd02586b1b9147895272c0d0fd46c354f1 100644 (file)
@@ -55,6 +55,10 @@ struct pid
        refcount_t count;
        unsigned int level;
        spinlock_t lock;
+#ifdef CONFIG_FS_PID
+       struct dentry *stashed;
+       unsigned long ino;
+#endif
        /* lists of tasks that use this pid */
        struct hlist_head tasks[PIDTYPE_MAX];
        struct hlist_head inodes;
@@ -66,15 +70,13 @@ struct pid
 
 extern struct pid init_struct_pid;
 
-extern const struct file_operations pidfd_fops;
-
 struct file;
 
-extern struct pid *pidfd_pid(const struct file *file);
+struct pid *pidfd_pid(const struct file *file);
 struct pid *pidfd_get_pid(unsigned int fd, unsigned int *flags);
 struct task_struct *pidfd_get_task(int pidfd, unsigned int *flags);
-int pidfd_create(struct pid *pid, unsigned int flags);
 int pidfd_prepare(struct pid *pid, unsigned int flags, struct file **ret);
+void do_notify_pidfd(struct task_struct *task);
 
 static inline struct pid *get_pid(struct pid *pid)
 {
diff --git a/include/linux/pidfs.h b/include/linux/pidfs.h
new file mode 100644 (file)
index 0000000..40dd325
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_PID_FS_H
+#define _LINUX_PID_FS_H
+
+struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags);
+void __init pidfs_init(void);
+bool is_pidfs_sb(const struct super_block *sb);
+
+#endif /* _LINUX_PID_FS_H */
index 79594aeb160dafa2e04ff47390d37316025a5588..2f1b952d596aa4661ee20e2450d8ab4feac4c86f 100644 (file)
@@ -154,9 +154,9 @@ struct packet_stacked_data
 
 struct pktcdvd_device
 {
-       struct bdev_handle      *bdev_handle;   /* dev attached */
+       struct file             *bdev_file;     /* dev attached */
        /* handle acquired for bdev during pkt_open_dev() */
-       struct bdev_handle      *open_bdev_handle;
+       struct file             *f_open_bdev;
        dev_t                   pkt_dev;        /* our dev */
        struct packet_settings  settings;
        struct packet_stats     stats;
index 27a7dad17eefb83b917569fdc6a5df7298f3859b..1f0ee2459f2aa2db997a979ff7df74b1d1bd588c 100644 (file)
@@ -92,4 +92,7 @@
 /********** VFS **********/
 #define VFS_PTR_POISON ((void *)(0xF5 + POISON_POINTER_DELTA))
 
+/********** lib/stackdepot.c **********/
+#define STACK_DEPOT_POISON ((void *)(0xD390 + POISON_POINTER_DELTA))
+
 #endif
index a9e0e1c2d1f2ff89d99a9377a1de7d0dc78483cd..d1ea4f3714a8485677e89a4c6c07a657e53a15ca 100644 (file)
 
 /* ~832 bytes of stack space used max in sys_select/sys_poll before allocating
    additional memory. */
-#ifdef __clang__
-#define MAX_STACK_ALLOC 768
-#else
 #define MAX_STACK_ALLOC 832
-#endif
 #define FRONTEND_STACK_ALLOC   256
 #define SELECT_STACK_ALLOC     FRONTEND_STACK_ALLOC
 #define POLL_STACK_ALLOC       FRONTEND_STACK_ALLOC
index de407e7c3b55fdbd9b5d3cbe93585b1e417a3e20..0b2a8985444097f91cd0557563ad9438e3c494ea 100644 (file)
@@ -65,6 +65,7 @@ struct proc_fs_info {
        kgid_t pid_gid;
        enum proc_hidepid hide_pid;
        enum proc_pidonly pidonly;
+       struct rcu_head rcu;
 };
 
 static inline struct proc_fs_info *proc_sb_info(struct super_block *sb)
index 49539bc416cecb7b45bfd4f11df817cd11f2e791..5ea470eb4d768ad92f2785187aa9298c39025ea2 100644 (file)
@@ -66,7 +66,7 @@ static inline void proc_free_inum(unsigned int inum) {}
 
 static inline int ns_alloc_inum(struct ns_common *ns)
 {
-       atomic_long_set(&ns->stashed, 0);
+       WRITE_ONCE(ns->stashed, NULL);
        return proc_alloc_inum(&ns->inum);
 }
 
index 7fd17e82bab43ff4409cf9e4c8827ff35c9df4d9..3705c2044fc04ebabf2fff2b4d9f8aadebbbe1cf 100644 (file)
@@ -78,6 +78,36 @@ enum sev_cmd {
        SEV_CMD_DBG_DECRYPT             = 0x060,
        SEV_CMD_DBG_ENCRYPT             = 0x061,
 
+       /* SNP specific commands */
+       SEV_CMD_SNP_INIT                = 0x081,
+       SEV_CMD_SNP_SHUTDOWN            = 0x082,
+       SEV_CMD_SNP_PLATFORM_STATUS     = 0x083,
+       SEV_CMD_SNP_DF_FLUSH            = 0x084,
+       SEV_CMD_SNP_INIT_EX             = 0x085,
+       SEV_CMD_SNP_SHUTDOWN_EX         = 0x086,
+       SEV_CMD_SNP_DECOMMISSION        = 0x090,
+       SEV_CMD_SNP_ACTIVATE            = 0x091,
+       SEV_CMD_SNP_GUEST_STATUS        = 0x092,
+       SEV_CMD_SNP_GCTX_CREATE         = 0x093,
+       SEV_CMD_SNP_GUEST_REQUEST       = 0x094,
+       SEV_CMD_SNP_ACTIVATE_EX         = 0x095,
+       SEV_CMD_SNP_LAUNCH_START        = 0x0A0,
+       SEV_CMD_SNP_LAUNCH_UPDATE       = 0x0A1,
+       SEV_CMD_SNP_LAUNCH_FINISH       = 0x0A2,
+       SEV_CMD_SNP_DBG_DECRYPT         = 0x0B0,
+       SEV_CMD_SNP_DBG_ENCRYPT         = 0x0B1,
+       SEV_CMD_SNP_PAGE_SWAP_OUT       = 0x0C0,
+       SEV_CMD_SNP_PAGE_SWAP_IN        = 0x0C1,
+       SEV_CMD_SNP_PAGE_MOVE           = 0x0C2,
+       SEV_CMD_SNP_PAGE_MD_INIT        = 0x0C3,
+       SEV_CMD_SNP_PAGE_SET_STATE      = 0x0C6,
+       SEV_CMD_SNP_PAGE_RECLAIM        = 0x0C7,
+       SEV_CMD_SNP_PAGE_UNSMASH        = 0x0C8,
+       SEV_CMD_SNP_CONFIG              = 0x0C9,
+       SEV_CMD_SNP_DOWNLOAD_FIRMWARE_EX = 0x0CA,
+       SEV_CMD_SNP_COMMIT              = 0x0CB,
+       SEV_CMD_SNP_VLEK_LOAD           = 0x0CD,
+
        SEV_CMD_MAX,
 };
 
@@ -523,12 +553,269 @@ struct sev_data_attestation_report {
        u32 len;                                /* In/Out */
 } __packed;
 
+/**
+ * struct sev_data_snp_download_firmware - SNP_DOWNLOAD_FIRMWARE command params
+ *
+ * @address: physical address of firmware image
+ * @len: length of the firmware image
+ */
+struct sev_data_snp_download_firmware {
+       u64 address;                            /* In */
+       u32 len;                                /* In */
+} __packed;
+
+/**
+ * struct sev_data_snp_activate - SNP_ACTIVATE command params
+ *
+ * @gctx_paddr: system physical address guest context page
+ * @asid: ASID to bind to the guest
+ */
+struct sev_data_snp_activate {
+       u64 gctx_paddr;                         /* In */
+       u32 asid;                               /* In */
+} __packed;
+
+/**
+ * struct sev_data_snp_addr - generic SNP command params
+ *
+ * @address: physical address of generic data param
+ */
+struct sev_data_snp_addr {
+       u64 address;                            /* In/Out */
+} __packed;
+
+/**
+ * struct sev_data_snp_launch_start - SNP_LAUNCH_START command params
+ *
+ * @gctx_paddr: system physical address of guest context page
+ * @policy: guest policy
+ * @ma_gctx_paddr: system physical address of migration agent
+ * @ma_en: the guest is associated with a migration agent
+ * @imi_en: launch flow is launching an IMI (Incoming Migration Image) for the
+ *          purpose of guest-assisted migration.
+ * @rsvd: reserved
+ * @gosvw: guest OS-visible workarounds, as defined by hypervisor
+ */
+struct sev_data_snp_launch_start {
+       u64 gctx_paddr;                         /* In */
+       u64 policy;                             /* In */
+       u64 ma_gctx_paddr;                      /* In */
+       u32 ma_en:1;                            /* In */
+       u32 imi_en:1;                           /* In */
+       u32 rsvd:30;
+       u8 gosvw[16];                           /* In */
+} __packed;
+
+/* SNP support page type */
+enum {
+       SNP_PAGE_TYPE_NORMAL            = 0x1,
+       SNP_PAGE_TYPE_VMSA              = 0x2,
+       SNP_PAGE_TYPE_ZERO              = 0x3,
+       SNP_PAGE_TYPE_UNMEASURED        = 0x4,
+       SNP_PAGE_TYPE_SECRET            = 0x5,
+       SNP_PAGE_TYPE_CPUID             = 0x6,
+
+       SNP_PAGE_TYPE_MAX
+};
+
+/**
+ * struct sev_data_snp_launch_update - SNP_LAUNCH_UPDATE command params
+ *
+ * @gctx_paddr: system physical address of guest context page
+ * @page_size: page size 0 indicates 4K and 1 indicates 2MB page
+ * @page_type: encoded page type
+ * @imi_page: indicates that this page is part of the IMI (Incoming Migration
+ *            Image) of the guest
+ * @rsvd: reserved
+ * @rsvd2: reserved
+ * @address: system physical address of destination page to encrypt
+ * @rsvd3: reserved
+ * @vmpl1_perms: VMPL permission mask for VMPL1
+ * @vmpl2_perms: VMPL permission mask for VMPL2
+ * @vmpl3_perms: VMPL permission mask for VMPL3
+ * @rsvd4: reserved
+ */
+struct sev_data_snp_launch_update {
+       u64 gctx_paddr;                         /* In */
+       u32 page_size:1;                        /* In */
+       u32 page_type:3;                        /* In */
+       u32 imi_page:1;                         /* In */
+       u32 rsvd:27;
+       u32 rsvd2;
+       u64 address;                            /* In */
+       u32 rsvd3:8;
+       u32 vmpl1_perms:8;                      /* In */
+       u32 vmpl2_perms:8;                      /* In */
+       u32 vmpl3_perms:8;                      /* In */
+       u32 rsvd4;
+} __packed;
+
+/**
+ * struct sev_data_snp_launch_finish - SNP_LAUNCH_FINISH command params
+ *
+ * @gctx_paddr: system physical address of guest context page
+ * @id_block_paddr: system physical address of ID block
+ * @id_auth_paddr: system physical address of ID block authentication structure
+ * @id_block_en: indicates whether ID block is present
+ * @auth_key_en: indicates whether author key is present in authentication structure
+ * @rsvd: reserved
+ * @host_data: host-supplied data for guest, not interpreted by firmware
+ */
+struct sev_data_snp_launch_finish {
+       u64 gctx_paddr;
+       u64 id_block_paddr;
+       u64 id_auth_paddr;
+       u8 id_block_en:1;
+       u8 auth_key_en:1;
+       u64 rsvd:62;
+       u8 host_data[32];
+} __packed;
+
+/**
+ * struct sev_data_snp_guest_status - SNP_GUEST_STATUS command params
+ *
+ * @gctx_paddr: system physical address of guest context page
+ * @address: system physical address of guest status page
+ */
+struct sev_data_snp_guest_status {
+       u64 gctx_paddr;
+       u64 address;
+} __packed;
+
+/**
+ * struct sev_data_snp_page_reclaim - SNP_PAGE_RECLAIM command params
+ *
+ * @paddr: system physical address of page to be claimed. The 0th bit in the
+ *         address indicates the page size. 0h indicates 4KB and 1h indicates
+ *         2MB page.
+ */
+struct sev_data_snp_page_reclaim {
+       u64 paddr;
+} __packed;
+
+/**
+ * struct sev_data_snp_page_unsmash - SNP_PAGE_UNSMASH command params
+ *
+ * @paddr: system physical address of page to be unsmashed. The 0th bit in the
+ *         address indicates the page size. 0h indicates 4 KB and 1h indicates
+ *         2 MB page.
+ */
+struct sev_data_snp_page_unsmash {
+       u64 paddr;
+} __packed;
+
+/**
+ * struct sev_data_snp_dbg - DBG_ENCRYPT/DBG_DECRYPT command parameters
+ *
+ * @gctx_paddr: system physical address of guest context page
+ * @src_addr: source address of data to operate on
+ * @dst_addr: destination address of data to operate on
+ */
+struct sev_data_snp_dbg {
+       u64 gctx_paddr;                         /* In */
+       u64 src_addr;                           /* In */
+       u64 dst_addr;                           /* In */
+} __packed;
+
+/**
+ * struct sev_data_snp_guest_request - SNP_GUEST_REQUEST command params
+ *
+ * @gctx_paddr: system physical address of guest context page
+ * @req_paddr: system physical address of request page
+ * @res_paddr: system physical address of response page
+ */
+struct sev_data_snp_guest_request {
+       u64 gctx_paddr;                         /* In */
+       u64 req_paddr;                          /* In */
+       u64 res_paddr;                          /* In */
+} __packed;
+
+/**
+ * struct sev_data_snp_init_ex - SNP_INIT_EX structure
+ *
+ * @init_rmp: indicate that the RMP should be initialized.
+ * @list_paddr_en: indicate that list_paddr is valid
+ * @rsvd: reserved
+ * @rsvd1: reserved
+ * @list_paddr: system physical address of range list
+ * @rsvd2: reserved
+ */
+struct sev_data_snp_init_ex {
+       u32 init_rmp:1;
+       u32 list_paddr_en:1;
+       u32 rsvd:30;
+       u32 rsvd1;
+       u64 list_paddr;
+       u8  rsvd2[48];
+} __packed;
+
+/**
+ * struct sev_data_range - RANGE structure
+ *
+ * @base: system physical address of first byte of range
+ * @page_count: number of 4KB pages in this range
+ * @rsvd: reserved
+ */
+struct sev_data_range {
+       u64 base;
+       u32 page_count;
+       u32 rsvd;
+} __packed;
+
+/**
+ * struct sev_data_range_list - RANGE_LIST structure
+ *
+ * @num_elements: number of elements in RANGE_ARRAY
+ * @rsvd: reserved
+ * @ranges: array of num_elements of type RANGE
+ */
+struct sev_data_range_list {
+       u32 num_elements;
+       u32 rsvd;
+       struct sev_data_range ranges[];
+} __packed;
+
+/**
+ * struct sev_data_snp_shutdown_ex - SNP_SHUTDOWN_EX structure
+ *
+ * @len: length of the command buffer read by the PSP
+ * @iommu_snp_shutdown: Disable enforcement of SNP in the IOMMU
+ * @rsvd1: reserved
+ */
+struct sev_data_snp_shutdown_ex {
+       u32 len;
+       u32 iommu_snp_shutdown:1;
+       u32 rsvd1:31;
+} __packed;
+
+/**
+ * struct sev_platform_init_args
+ *
+ * @error: SEV firmware error code
+ * @probe: True if this is being called as part of CCP module probe, which
+ *  will defer SEV_INIT/SEV_INIT_EX firmware initialization until needed
+ *  unless psp_init_on_probe module param is set
+ */
+struct sev_platform_init_args {
+       int error;
+       bool probe;
+};
+
+/**
+ * struct sev_data_snp_commit - SNP_COMMIT structure
+ *
+ * @len: length of the command buffer read by the PSP
+ */
+struct sev_data_snp_commit {
+       u32 len;
+} __packed;
+
 #ifdef CONFIG_CRYPTO_DEV_SP_PSP
 
 /**
  * sev_platform_init - perform SEV INIT command
  *
- * @error: SEV command return code
+ * @args: struct sev_platform_init_args to pass in arguments
  *
  * Returns:
  * 0 if the SEV successfully processed the command
@@ -537,7 +824,7 @@ struct sev_data_attestation_report {
  * -%ETIMEDOUT if the SEV command timed out
  * -%EIO       if the SEV returned a non-zero return code
  */
-int sev_platform_init(int *error);
+int sev_platform_init(struct sev_platform_init_args *args);
 
 /**
  * sev_platform_status - perform SEV PLATFORM_STATUS command
@@ -637,14 +924,32 @@ int sev_guest_df_flush(int *error);
  */
 int sev_guest_decommission(struct sev_data_decommission *data, int *error);
 
+/**
+ * sev_do_cmd - issue an SEV or an SEV-SNP command
+ *
+ * @cmd: SEV or SEV-SNP firmware command to issue
+ * @data: arguments for firmware command
+ * @psp_ret: SEV command return code
+ *
+ * Returns:
+ * 0 if the SEV device successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if PSP device does not support SEV
+ * -%ETIMEDOUT if the SEV command timed out
+ * -%EIO       if PSP device returned a non-zero return code
+ */
+int sev_do_cmd(int cmd, void *data, int *psp_ret);
+
 void *psp_copy_user_blob(u64 uaddr, u32 len);
+void *snp_alloc_firmware_page(gfp_t mask);
+void snp_free_firmware_page(void *addr);
 
 #else  /* !CONFIG_CRYPTO_DEV_SP_PSP */
 
 static inline int
 sev_platform_status(struct sev_user_data_status *status, int *error) { return -ENODEV; }
 
-static inline int sev_platform_init(int *error) { return -ENODEV; }
+static inline int sev_platform_init(struct sev_platform_init_args *args) { return -ENODEV; }
 
 static inline int
 sev_guest_deactivate(struct sev_data_deactivate *data, int *error) { return -ENODEV; }
@@ -652,6 +957,9 @@ sev_guest_deactivate(struct sev_data_deactivate *data, int *error) { return -ENO
 static inline int
 sev_guest_decommission(struct sev_data_decommission *data, int *error) { return -ENODEV; }
 
+static inline int
+sev_do_cmd(int cmd, void *data, int *psp_ret) { return -ENODEV; }
+
 static inline int
 sev_guest_activate(struct sev_data_activate *data, int *error) { return -ENODEV; }
 
@@ -662,6 +970,13 @@ sev_issue_cmd_external_user(struct file *filep, unsigned int id, void *data, int
 
 static inline void *psp_copy_user_blob(u64 __user uaddr, u32 len) { return ERR_PTR(-EINVAL); }
 
+static inline void *snp_alloc_firmware_page(gfp_t mask)
+{
+       return NULL;
+}
+
+static inline void snp_free_firmware_page(void *addr) { }
+
 #endif /* CONFIG_CRYPTO_DEV_SP_PSP */
 
 #endif /* __PSP_SEV_H__ */
index 1a941efcaa6223a55a8bfcceeb7fb798bbbb1bb4..1fbf9d6c20efb67506aa9e20421f71eed1e313d4 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef _INCLUDE_PTI_H
 #define _INCLUDE_PTI_H
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 #include <asm/pti.h>
 #else
 static inline void pti_init(void) { }
index 746fd67c34806b0c19959b182a4088f5c560ceb8..e8c74fa3f455dd37e449cbdbfc5cd23d41336197 100644 (file)
@@ -8,15 +8,15 @@
 #ifndef _PTP_KVM_H_
 #define _PTP_KVM_H_
 
+#include <linux/clocksource_ids.h>
 #include <linux/types.h>
 
 struct timespec64;
-struct clocksource;
 
 int kvm_arch_ptp_init(void);
 void kvm_arch_ptp_exit(void);
 int kvm_arch_ptp_get_clock(struct timespec64 *ts);
 int kvm_arch_ptp_get_crosststamp(u64 *cycle,
-               struct timespec64 *tspec, struct clocksource **cs);
+               struct timespec64 *tspec, enum clocksource_ids *cs_id);
 
 #endif /* _PTP_KVM_H_ */
index eaaef3ffec221b93cfbb9a2f4c20646b473754fa..90507d4afcd6debb80eef494c4c874c8a1732e49 100644 (file)
@@ -393,6 +393,10 @@ static inline void user_single_step_report(struct pt_regs *regs)
 #define current_user_stack_pointer() user_stack_pointer(current_pt_regs())
 #endif
 
+#ifndef exception_ip
+#define exception_ip(x) instruction_pointer(x)
+#endif
+
 extern int task_current_syscall(struct task_struct *target, struct syscall_info *info);
 
 extern void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact);
index 1f4048bf2674deac9f9d6feba567c6c261eab27a..a64182bc72ad3f2b430c53c7a9e23e798a1c1fbe 100644 (file)
@@ -25,6 +25,7 @@ void log_non_standard_event(const guid_t *sec_type,
                            const guid_t *fru_id, const char *fru_text,
                            const u8 sev, const u8 *err, const u32 len);
 void log_arm_hw_error(struct cper_sec_proc_arm *err);
+
 #else
 static inline void
 log_non_standard_event(const guid_t *sec_type,
@@ -35,4 +36,21 @@ static inline void
 log_arm_hw_error(struct cper_sec_proc_arm *err) { return; }
 #endif
 
+struct atl_err {
+       u64 addr;
+       u64 ipid;
+       u32 cpu;
+};
+
+#if IS_ENABLED(CONFIG_AMD_ATL)
+void amd_atl_register_decoder(unsigned long (*f)(struct atl_err *));
+void amd_atl_unregister_decoder(void);
+void amd_retire_dram_row(struct atl_err *err);
+unsigned long amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
+#else
+static inline void amd_retire_dram_row(struct atl_err *err) { }
+static inline unsigned long
+amd_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { return -EINVAL; }
+#endif /* CONFIG_AMD_ATL */
+
 #endif /* __RAS_H__ */
index 0027d4c8087c9ae7aec81e2412a2444a45bf673a..3860dbb9107a2117aa0078c18550aed42d36e241 100644 (file)
@@ -37,7 +37,6 @@ static inline bool rcu_sync_is_idle(struct rcu_sync *rsp)
 }
 
 extern void rcu_sync_init(struct rcu_sync *);
-extern void rcu_sync_enter_start(struct rcu_sync *);
 extern void rcu_sync_enter(struct rcu_sync *);
 extern void rcu_sync_exit(struct rcu_sync *);
 extern void rcu_sync_dtor(struct rcu_sync *);
index 0746b1b0b6639d9a912e2ba7503b928f40e92748..16f519914415ebf5592e75be67e8660339d6b0e7 100644 (file)
@@ -184,9 +184,9 @@ void rcu_tasks_trace_qs_blkd(struct task_struct *t);
        do {                                                                    \
                int ___rttq_nesting = READ_ONCE((t)->trc_reader_nesting);       \
                                                                                \
-               if (likely(!READ_ONCE((t)->trc_reader_special.b.need_qs)) &&    \
+               if (unlikely(READ_ONCE((t)->trc_reader_special.b.need_qs) == TRC_NEED_QS) &&    \
                    likely(!___rttq_nesting)) {                                 \
-                       rcu_trc_cmpxchg_need_qs((t), 0, TRC_NEED_QS_CHECKED);   \
+                       rcu_trc_cmpxchg_need_qs((t), TRC_NEED_QS, TRC_NEED_QS_CHECKED); \
                } else if (___rttq_nesting && ___rttq_nesting != INT_MIN &&     \
                           !READ_ONCE((t)->trc_reader_special.b.blocked)) {     \
                        rcu_tasks_trace_qs_blkd(t);                             \
index 66942d7fba7fc66ca45527a7df1dbc22100a6727..a365f67131eceffe2768fe06af778d2e2360ff92 100644 (file)
@@ -6,6 +6,12 @@
 #include <linux/list.h>
 #include <linux/pid.h>
 
+/* CLOSID, RMID value used by the default control group */
+#define RESCTRL_RESERVED_CLOSID                0
+#define RESCTRL_RESERVED_RMID          0
+
+#define RESCTRL_PICK_ANY_CPU           -1
+
 #ifdef CONFIG_PROC_CPU_RESCTRL
 
 int proc_resctrl_show(struct seq_file *m,
@@ -153,7 +159,7 @@ struct resctrl_schema;
  * @cache_level:       Which cache level defines scope of this resource
  * @cache:             Cache allocation related data
  * @membw:             If the component has bandwidth controls, their properties.
- * @domains:           All domains for this resource
+ * @domains:           RCU list of all domains for this resource
  * @name:              Name to use in "schemata" file.
  * @data_width:                Character width of data when displaying
  * @default_ctrl:      Specifies default cache cbm or memory B/W percent.
@@ -219,36 +225,70 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d,
                            u32 closid, enum resctrl_conf_type type);
 int resctrl_online_domain(struct rdt_resource *r, struct rdt_domain *d);
 void resctrl_offline_domain(struct rdt_resource *r, struct rdt_domain *d);
+void resctrl_online_cpu(unsigned int cpu);
+void resctrl_offline_cpu(unsigned int cpu);
 
 /**
  * resctrl_arch_rmid_read() - Read the eventid counter corresponding to rmid
  *                           for this resource and domain.
  * @r:                 resource that the counter should be read from.
  * @d:                 domain that the counter should be read from.
+ * @closid:            closid that matches the rmid. Depending on the architecture, the
+ *                     counter may match traffic of both @closid and @rmid, or @rmid
+ *                     only.
  * @rmid:              rmid of the counter to read.
  * @eventid:           eventid to read, e.g. L3 occupancy.
  * @val:               result of the counter read in bytes.
+ * @arch_mon_ctx:      An architecture specific value from
+ *                     resctrl_arch_mon_ctx_alloc(), for MPAM this identifies
+ *                     the hardware monitor allocated for this read request.
  *
- * Call from process context on a CPU that belongs to domain @d.
+ * Some architectures need to sleep when first programming some of the counters.
+ * (specifically: arm64's MPAM cache occupancy counters can return 'not ready'
+ *  for a short period of time). Call from a non-migrateable process context on
+ * a CPU that belongs to domain @d. e.g. use smp_call_on_cpu() or
+ * schedule_work_on(). This function can be called with interrupts masked,
+ * e.g. using smp_call_function_any(), but may consistently return an error.
  *
  * Return:
  * 0 on success, or -EIO, -EINVAL etc on error.
  */
 int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d,
-                          u32 rmid, enum resctrl_event_id eventid, u64 *val);
+                          u32 closid, u32 rmid, enum resctrl_event_id eventid,
+                          u64 *val, void *arch_mon_ctx);
+
+/**
+ * resctrl_arch_rmid_read_context_check()  - warn about invalid contexts
+ *
+ * When built with CONFIG_DEBUG_ATOMIC_SLEEP generate a warning when
+ * resctrl_arch_rmid_read() is called with preemption disabled.
+ *
+ * The contract with resctrl_arch_rmid_read() is that if interrupts
+ * are unmasked, it can sleep. This allows NOHZ_FULL systems to use an
+ * IPI, (and fail if the call needed to sleep), while most of the time
+ * the work is scheduled, allowing the call to sleep.
+ */
+static inline void resctrl_arch_rmid_read_context_check(void)
+{
+       if (!irqs_disabled())
+               might_sleep();
+}
 
 /**
  * resctrl_arch_reset_rmid() - Reset any private state associated with rmid
  *                            and eventid.
  * @r:         The domain's resource.
  * @d:         The rmid's domain.
+ * @closid:    closid that matches the rmid. Depending on the architecture, the
+ *             counter may match traffic of both @closid and @rmid, or @rmid only.
  * @rmid:      The rmid whose counter values should be reset.
  * @eventid:   The eventid whose counter values should be reset.
  *
  * This can be called from any CPU.
  */
 void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d,
-                            u32 rmid, enum resctrl_event_id eventid);
+                            u32 closid, u32 rmid,
+                            enum resctrl_event_id eventid);
 
 /**
  * resctrl_arch_reset_rmid_all() - Reset all private state associated with
diff --git a/include/linux/rw_hint.h b/include/linux/rw_hint.h
new file mode 100644 (file)
index 0000000..309ca72
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_RW_HINT_H
+#define _LINUX_RW_HINT_H
+
+#include <linux/build_bug.h>
+#include <linux/compiler_attributes.h>
+#include <uapi/linux/fcntl.h>
+
+/* Block storage write lifetime hint values. */
+enum rw_hint {
+       WRITE_LIFE_NOT_SET      = RWH_WRITE_LIFE_NOT_SET,
+       WRITE_LIFE_NONE         = RWH_WRITE_LIFE_NONE,
+       WRITE_LIFE_SHORT        = RWH_WRITE_LIFE_SHORT,
+       WRITE_LIFE_MEDIUM       = RWH_WRITE_LIFE_MEDIUM,
+       WRITE_LIFE_LONG         = RWH_WRITE_LIFE_LONG,
+       WRITE_LIFE_EXTREME      = RWH_WRITE_LIFE_EXTREME,
+} __packed;
+
+/* Sparse ignores __packed annotations on enums, hence the #ifndef below. */
+#ifndef __CHECKER__
+static_assert(sizeof(enum rw_hint) == 1);
+#endif
+
+#endif /* _LINUX_RW_HINT_H */
index ffe8f618ab869729bd6c888a8a05e45d46a6c7c2..17cb0761ff658e6838aa4e04eb429d4155e55e81 100644 (file)
@@ -858,6 +858,8 @@ struct task_struct {
        u8                              rcu_tasks_idx;
        int                             rcu_tasks_idle_cpu;
        struct list_head                rcu_tasks_holdout_list;
+       int                             rcu_tasks_exit_cpu;
+       struct list_head                rcu_tasks_exit_list;
 #endif /* #ifdef CONFIG_TASKS_RCU */
 
 #ifdef CONFIG_TASKS_TRACE_RCU
@@ -1642,7 +1644,7 @@ extern struct pid *cad_pid;
 #define PF_NO_SETAFFINITY      0x04000000      /* Userland is not allowed to meddle with cpus_mask */
 #define PF_MCE_EARLY           0x08000000      /* Early kill for mce process policy */
 #define PF_MEMALLOC_PIN                0x10000000      /* Allocation context constrained to zones which allow long term pinning. */
-#define PF__HOLE__20000000     0x20000000
+#define PF_BLOCK_TS            0x20000000      /* plug has ts that needs updating */
 #define PF__HOLE__40000000     0x40000000
 #define PF_SUSPEND_TASK                0x80000000      /* This thread called freeze_processes() and should not be frozen */
 
index a8b28647aafc812d011839852c78ce81aee09ee2..b04a5d04dee901e58d26f7454ba700ded9c8d46a 100644 (file)
@@ -117,13 +117,13 @@ SD_FLAG(SD_SHARE_CPUCAPACITY, SDF_SHARED_CHILD | SDF_NEEDS_GROUPS)
 SD_FLAG(SD_CLUSTER, SDF_NEEDS_GROUPS)
 
 /*
- * Domain members share CPU package resources (i.e. caches)
+ * Domain members share CPU Last Level Caches
  *
  * SHARED_CHILD: Set from the base domain up until spanned CPUs no longer share
  *               the same cache(s).
  * NEEDS_GROUPS: Caches are shared between groups.
  */
-SD_FLAG(SD_SHARE_PKG_RESOURCES, SDF_SHARED_CHILD | SDF_NEEDS_GROUPS)
+SD_FLAG(SD_SHARE_LLC, SDF_SHARED_CHILD | SDF_NEEDS_GROUPS)
 
 /*
  * Only a single load balancing instance
index 4b7664c56208f9db855c527cd6daff672454d106..0a0e23c45406fe477a8c32534326bde451e4a45a 100644 (file)
@@ -735,8 +735,6 @@ static inline int thread_group_empty(struct task_struct *p)
 #define delay_group_leader(p) \
                (thread_group_leader(p) && !thread_group_empty(p))
 
-extern bool thread_group_exited(struct pid *pid);
-
 extern struct sighand_struct *__lock_task_sighand(struct task_struct *task,
                                                        unsigned long *flags);
 
index a6e04b4a21d70f9d3c807970815d1b79fee74ed4..18572c9ea724688bd52c1554d3690b3dff375f37 100644 (file)
@@ -38,21 +38,21 @@ extern const struct sd_flag_debug sd_flag_debug[];
 #ifdef CONFIG_SCHED_SMT
 static inline int cpu_smt_flags(void)
 {
-       return SD_SHARE_CPUCAPACITY | SD_SHARE_PKG_RESOURCES;
+       return SD_SHARE_CPUCAPACITY | SD_SHARE_LLC;
 }
 #endif
 
 #ifdef CONFIG_SCHED_CLUSTER
 static inline int cpu_cluster_flags(void)
 {
-       return SD_CLUSTER | SD_SHARE_PKG_RESOURCES;
+       return SD_CLUSTER | SD_SHARE_LLC;
 }
 #endif
 
 #ifdef CONFIG_SCHED_MC
 static inline int cpu_core_flags(void)
 {
-       return SD_SHARE_PKG_RESOURCES;
+       return SD_SHARE_LLC;
 }
 #endif
 
@@ -176,6 +176,7 @@ extern void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[],
 cpumask_var_t *alloc_sched_domains(unsigned int ndoms);
 void free_sched_domains(cpumask_var_t doms[], unsigned int ndoms);
 
+bool cpus_equal_capacity(int this_cpu, int that_cpu);
 bool cpus_share_cache(int this_cpu, int that_cpu);
 bool cpus_share_resources(int this_cpu, int that_cpu);
 
@@ -226,6 +227,11 @@ partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[],
 {
 }
 
+static inline bool cpus_equal_capacity(int this_cpu, int that_cpu)
+{
+       return true;
+}
+
 static inline bool cpus_share_cache(int this_cpu, int that_cpu)
 {
        return true;
index f2f05fb42d284034a94ba61d99e0e6d4fc523a1b..2ee94ff0320c32233a528e1b328d58237cee8452 100644 (file)
@@ -47,6 +47,10 @@ struct scmi_clock_info {
        bool rate_discrete;
        bool rate_changed_notifications;
        bool rate_change_requested_notifications;
+       bool state_ctrl_forbidden;
+       bool rate_ctrl_forbidden;
+       bool parent_ctrl_forbidden;
+       bool extended_config;
        union {
                struct {
                        int num_rates;
@@ -72,6 +76,13 @@ struct scmi_handle;
 struct scmi_device;
 struct scmi_protocol_handle;
 
+enum scmi_clock_oem_config {
+       SCMI_CLOCK_CFG_DUTY_CYCLE = 0x1,
+       SCMI_CLOCK_CFG_PHASE,
+       SCMI_CLOCK_CFG_OEM_START = 0x80,
+       SCMI_CLOCK_CFG_OEM_END = 0xFF,
+};
+
 /**
  * struct scmi_clk_proto_ops - represents the various operations provided
  *     by SCMI Clock Protocol
@@ -104,10 +115,11 @@ struct scmi_clk_proto_ops {
        int (*state_get)(const struct scmi_protocol_handle *ph, u32 clk_id,
                         bool *enabled, bool atomic);
        int (*config_oem_get)(const struct scmi_protocol_handle *ph, u32 clk_id,
-                             u8 oem_type, u32 *oem_val, u32 *attributes,
-                             bool atomic);
+                             enum scmi_clock_oem_config oem_type,
+                             u32 *oem_val, u32 *attributes, bool atomic);
        int (*config_oem_set)(const struct scmi_protocol_handle *ph, u32 clk_id,
-                             u8 oem_type, u32 oem_val, bool atomic);
+                             enum scmi_clock_oem_config oem_type,
+                             u32 oem_val, bool atomic);
        int (*parent_get)(const struct scmi_protocol_handle *ph, u32 clk_id, u32 *parent_id);
        int (*parent_set)(const struct scmi_protocol_handle *ph, u32 clk_id, u32 parent_id);
 };
@@ -953,6 +965,8 @@ struct scmi_perf_limits_report {
        unsigned int    domain_id;
        unsigned int    range_max;
        unsigned int    range_min;
+       unsigned long   range_max_freq;
+       unsigned long   range_min_freq;
 };
 
 struct scmi_perf_level_report {
@@ -960,6 +974,7 @@ struct scmi_perf_level_report {
        unsigned int    agent_id;
        unsigned int    domain_id;
        unsigned int    performance_level;
+       unsigned long   performance_level_freq;
 };
 
 struct scmi_sensor_trip_point_report {
index c44f4b47b945306318d8ed164c498abfe2512a10..fe41da0059700432044c1260952073914f7a26fc 100644 (file)
@@ -2,7 +2,10 @@
 #ifndef _LINUX_SEQ_BUF_H
 #define _LINUX_SEQ_BUF_H
 
-#include <linux/fs.h>
+#include <linux/bug.h>
+#include <linux/minmax.h>
+#include <linux/seq_file.h>
+#include <linux/types.h>
 
 /*
  * Trace sequences are used to allow a function to call several other functions
@@ -10,7 +13,7 @@
  */
 
 /**
- * seq_buf - seq buffer structure
+ * struct seq_buf - seq buffer structure
  * @buffer:    pointer to the buffer
  * @size:      size of the buffer
  * @len:       the amount of data inside the buffer
@@ -77,10 +80,10 @@ static inline unsigned int seq_buf_used(struct seq_buf *s)
 }
 
 /**
- * seq_buf_str - get %NUL-terminated C string from seq_buf
+ * seq_buf_str - get NUL-terminated C string from seq_buf
  * @s: the seq_buf handle
  *
- * This makes sure that the buffer in @s is nul terminated and
+ * This makes sure that the buffer in @s is NUL-terminated and
  * safe to read as a string.
  *
  * Note, if this is called when the buffer has overflowed, then
@@ -90,7 +93,7 @@ static inline unsigned int seq_buf_used(struct seq_buf *s)
  * After this function is called, s->buffer is safe to use
  * in string operations.
  *
- * Returns @s->buf after making sure it is terminated.
+ * Returns: @s->buf after making sure it is terminated.
  */
 static inline const char *seq_buf_str(struct seq_buf *s)
 {
@@ -110,7 +113,7 @@ static inline const char *seq_buf_str(struct seq_buf *s)
  * @s: the seq_buf handle
  * @bufp: the beginning of the buffer is stored here
  *
- * Return the number of bytes available in the buffer, or zero if
+ * Returns: the number of bytes available in the buffer, or zero if
  * there's no space.
  */
 static inline size_t seq_buf_get_buf(struct seq_buf *s, char **bufp)
@@ -132,7 +135,7 @@ static inline size_t seq_buf_get_buf(struct seq_buf *s, char **bufp)
  * @num: the number of bytes to commit
  *
  * Commit @num bytes of data written to a buffer previously acquired
- * by seq_buf_get To signal an error condition, or that the data
+ * by seq_buf_get_buf(). To signal an error condition, or that the data
  * didn't fit in the available space, pass a negative @num value.
  */
 static inline void seq_buf_commit(struct seq_buf *s, int num)
index 536b2581d3e2007593323a53c050d037d6ac5dd1..55b1f3ba48ac1725f110747b8d05ce6bbfc1de0b 100644 (file)
@@ -748,8 +748,17 @@ struct uart_driver {
 
 void uart_write_wakeup(struct uart_port *port);
 
-#define __uart_port_tx(uport, ch, tx_ready, put_char, tx_done, for_test,      \
-               for_post)                                                     \
+/**
+ * enum UART_TX_FLAGS -- flags for uart_port_tx_flags()
+ *
+ * @UART_TX_NOSTOP: don't call port->ops->stop_tx() on empty buffer
+ */
+enum UART_TX_FLAGS {
+       UART_TX_NOSTOP = BIT(0),
+};
+
+#define __uart_port_tx(uport, ch, flags, tx_ready, put_char, tx_done,        \
+                      for_test, for_post)                                    \
 ({                                                                           \
        struct uart_port *__port = (uport);                                   \
        struct circ_buf *xmit = &__port->state->xmit;                         \
@@ -777,7 +786,7 @@ void uart_write_wakeup(struct uart_port *port);
        if (pending < WAKEUP_CHARS) {                                         \
                uart_write_wakeup(__port);                                    \
                                                                              \
-               if (pending == 0)                                             \
+               if (!((flags) & UART_TX_NOSTOP) && pending == 0)              \
                        __port->ops->stop_tx(__port);                         \
        }                                                                     \
                                                                              \
@@ -812,7 +821,7 @@ void uart_write_wakeup(struct uart_port *port);
  */
 #define uart_port_tx_limited(port, ch, count, tx_ready, put_char, tx_done) ({ \
        unsigned int __count = (count);                                       \
-       __uart_port_tx(port, ch, tx_ready, put_char, tx_done, __count,        \
+       __uart_port_tx(port, ch, 0, tx_ready, put_char, tx_done, __count,     \
                        __count--);                                           \
 })
 
@@ -826,8 +835,21 @@ void uart_write_wakeup(struct uart_port *port);
  * See uart_port_tx_limited() for more details.
  */
 #define uart_port_tx(port, ch, tx_ready, put_char)                     \
-       __uart_port_tx(port, ch, tx_ready, put_char, ({}), true, ({}))
+       __uart_port_tx(port, ch, 0, tx_ready, put_char, ({}), true, ({}))
+
 
+/**
+ * uart_port_tx_flags -- transmit helper for uart_port with flags
+ * @port: uart port
+ * @ch: variable to store a character to be written to the HW
+ * @flags: %UART_TX_NOSTOP or similar
+ * @tx_ready: can HW accept more data function
+ * @put_char: function to write a character
+ *
+ * See uart_port_tx_limited() for more details.
+ */
+#define uart_port_tx_flags(port, ch, flags, tx_ready, put_char)                \
+       __uart_port_tx(port, ch, flags, tx_ready, put_char, ({}), true, ({}))
 /*
  * Baud rate helpers.
  */
index e87520dc2959dd9bd047ed2740945fd20bf7fd9a..fcd61dfe2af331a3a4448da9adb5c507e370a8cc 100644 (file)
@@ -105,6 +105,12 @@ static inline void on_each_cpu_cond(smp_cond_func_t cond_func,
        on_each_cpu_cond_mask(cond_func, func, info, wait, cpu_online_mask);
 }
 
+/*
+ * Architecture specific boot CPU setup.  Defined as empty weak function in
+ * init/main.c. Architectures can override it.
+ */
+void smp_prepare_boot_cpu(void);
+
 #ifdef CONFIG_SMP
 
 #include <linux/preempt.h>
@@ -171,12 +177,6 @@ void generic_smp_call_function_single_interrupt(void);
 #define generic_smp_call_function_interrupt \
        generic_smp_call_function_single_interrupt
 
-/*
- * Mark the boot cpu "online" so that it can call console drivers in
- * printk() and can access its per-cpu storage.
- */
-void smp_prepare_boot_cpu(void);
-
 extern unsigned int setup_max_cpus;
 extern void __init setup_nr_cpu_ids(void);
 extern void __init smp_init(void);
@@ -203,7 +203,6 @@ static inline void up_smp_call_function(smp_call_func_t func, void *info)
                        (up_smp_call_function(func, info))
 
 static inline void smp_send_reschedule(int cpu) { }
-#define smp_prepare_boot_cpu()                 do {} while (0)
 #define smp_call_function_many(mask, func, info, wait) \
                        (up_smp_call_function(func, info))
 static inline void call_function_init(void) { }
@@ -218,6 +217,8 @@ smp_call_function_any(const struct cpumask *mask, smp_call_func_t func,
 static inline void kick_all_cpus_sync(void) {  }
 static inline void wake_up_all_idle_cpus(void) {  }
 
+#define setup_max_cpus 0
+
 #ifdef CONFIG_UP_LATE_INIT
 extern void __init up_late_init(void);
 static inline void smp_init(void) { up_late_init(); }
@@ -261,7 +262,7 @@ static inline int get_boot_cpu_id(void)
  * regular asm read for the stable.
  */
 #ifndef __smp_processor_id
-#define __smp_processor_id(x) raw_smp_processor_id(x)
+#define __smp_processor_id() raw_smp_processor_id()
 #endif
 
 #ifdef CONFIG_DEBUG_PREEMPT
diff --git a/include/linux/soc/andes/irq.h b/include/linux/soc/andes/irq.h
new file mode 100644 (file)
index 0000000..edc3182
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 Andes Technology Corporation
+ */
+#ifndef __ANDES_IRQ_H
+#define __ANDES_IRQ_H
+
+/* Andes PMU irq number */
+#define ANDES_RV_IRQ_PMOVI             18
+#define ANDES_RV_IRQ_LAST              ANDES_RV_IRQ_PMOVI
+#define ANDES_SLI_CAUSE_BASE           256
+
+/* Andes PMU related registers */
+#define ANDES_CSR_SLIE                 0x9c4
+#define ANDES_CSR_SLIP                 0x9c5
+#define ANDES_CSR_SCOUNTEROF           0x9d4
+
+#endif /* __ANDES_IRQ_H */
index be98aebcb3e19b94ef139bbe21d560b1f62e552b..7161a3183eda5dc20c107169276bc3a3f6c7314c 100644 (file)
@@ -9,7 +9,7 @@
 #include <dt-bindings/soc/qcom,apr.h>
 #include <dt-bindings/soc/qcom,gpr.h>
 
-extern struct bus_type aprbus;
+extern const struct bus_type aprbus;
 
 #define APR_HDR_LEN(hdr_len) ((hdr_len)/4)
 
diff --git a/include/linux/soc/qcom/qcom-pbs.h b/include/linux/soc/qcom/qcom-pbs.h
new file mode 100644 (file)
index 0000000..8a46209
--- /dev/null
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _QCOM_PBS_H
+#define _QCOM_PBS_H
+
+#include <linux/errno.h>
+#include <linux/types.h>
+
+struct device_node;
+struct pbs_dev;
+
+#if IS_ENABLED(CONFIG_QCOM_PBS)
+int qcom_pbs_trigger_event(struct pbs_dev *pbs, u8 bitmap);
+struct pbs_dev *get_pbs_client_device(struct device *client_dev);
+#else
+static inline int qcom_pbs_trigger_event(struct pbs_dev *pbs, u8 bitmap)
+{
+       return -ENODEV;
+}
+
+static inline struct pbs_dev *get_pbs_client_device(struct device *client_dev)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif
+
+#endif
index a4f5516cc9560f4c446f1f6233ed9f7211b784f0..2bd9d12d9a520a45baa6a49a39376b3ace297053 100644 (file)
@@ -10,6 +10,7 @@
 #define __LINUX_SOC_EXYNOS_PMU_H
 
 struct regmap;
+struct device_node;
 
 enum sys_powerdown {
        SYS_AFTR,
@@ -20,12 +21,20 @@ enum sys_powerdown {
 
 extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
 #ifdef CONFIG_EXYNOS_PMU
-extern struct regmap *exynos_get_pmu_regmap(void);
+struct regmap *exynos_get_pmu_regmap(void);
+struct regmap *exynos_get_pmu_regmap_by_phandle(struct device_node *np,
+                                               const char *propname);
 #else
 static inline struct regmap *exynos_get_pmu_regmap(void)
 {
        return ERR_PTR(-ENODEV);
 }
+
+static inline struct regmap *exynos_get_pmu_regmap_by_phandle(struct device_node *np,
+                                                             const char *propname)
+{
+       return ERR_PTR(-ENODEV);
+}
 #endif
 
 #endif /* __LINUX_SOC_EXYNOS_PMU_H */
index ab148d8dbfc146d2aed178b694f33506d06bfd05..4795ee5c50c66957e34072a8e13167fd1d11c5e8 100644 (file)
@@ -217,6 +217,7 @@ extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
 extern void *kmemdup(const void *src, size_t len, gfp_t gfp) __realloc_size(2);
 extern void *kvmemdup(const void *src, size_t len, gfp_t gfp) __realloc_size(2);
 extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp);
+extern void *kmemdup_array(const void *src, size_t element_size, size_t count, gfp_t gfp);
 
 extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
 extern void argv_free(char **argv);
index 4db00ddad26169060e1d42d5ca9b9723546ab81c..378ab1cd23bdcb4be1857d0f3bada023f8a6dae7 100644 (file)
@@ -298,7 +298,7 @@ struct swap_info_struct {
        unsigned int __percpu *cluster_next_cpu; /*percpu index for next allocation */
        struct percpu_cluster __percpu *percpu_cluster; /* per cpu's swap location */
        struct rb_root swap_extent_root;/* root of the swap extent rbtree */
-       struct bdev_handle *bdev_handle;/* open handle of the bdev */
+       struct file *bdev_file;         /* open handle of the bdev */
        struct block_device *bdev;      /* swap device or bdev of swap file */
        struct file *swap_file;         /* seldom referenced */
        unsigned int old_block_size;    /* seldom referenced */
@@ -549,6 +549,11 @@ static inline int swap_duplicate(swp_entry_t swp)
        return 0;
 }
 
+static inline int swapcache_prepare(swp_entry_t swp)
+{
+       return 0;
+}
+
 static inline void swap_free(swp_entry_t swp)
 {
 }
index 89b290d8c8dc9f115df7a295bc8d2512698db169..a1c47a6d69b0efd7e62765fbd873c848da22aaec 100644 (file)
@@ -221,8 +221,10 @@ struct tcp_sock {
        u32     lost_out;       /* Lost packets                 */
        u32     sacked_out;     /* SACK'd packets                       */
        u16     tcp_header_len; /* Bytes of tcp header to send          */
+       u8      scaling_ratio;  /* see tcp_win_from_space() */
        u8      chrono_type : 2,        /* current chronograph type */
                repair      : 1,
+               tcp_usec_ts : 1, /* TSval values in usec */
                is_sack_reneg:1,    /* in recovery from loss with SACK reneg? */
                is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */
        __cacheline_group_end(tcp_sock_read_txrx);
@@ -352,7 +354,6 @@ struct tcp_sock {
        u32     compressed_ack_rcv_nxt;
        struct list_head tsq_node; /* anchor in tsq_tasklet.head list */
 
-       u8      scaling_ratio;  /* see tcp_win_from_space() */
        /* Information of the most recently (s)acked skb */
        struct tcp_rack {
                u64 mstamp; /* (Re)sent time of the skb */
@@ -368,8 +369,7 @@ struct tcp_sock {
        u8      compressed_ack;
        u8      dup_ack_counter:2,
                tlp_retrans:1,  /* TLP is a retransmission */
-               tcp_usec_ts:1, /* TSval values in usec */
-               unused:4;
+               unused:5;
        u8      thin_lto    : 1,/* Use linear timeouts for thin streams */
                recvmsg_inq : 1,/* Indicate # of bytes in queue upon recvmsg */
                fastopen_connect:1, /* FASTOPEN_CONNECT sockopt */
index 911ddf92dcee75189535df5231c7fc57bd843cbf..71632e3c5f18fb9d564542c8e6d7984eb54f5151 100644 (file)
@@ -482,7 +482,7 @@ static inline bool tee_param_is_memref(struct tee_param *param)
        }
 }
 
-extern struct bus_type tee_bus_type;
+extern const struct bus_type tee_bus_type;
 
 /**
  * struct tee_client_device - tee based device
index 716d17f31c4539d18bcdd94c993ef47bf1c42368..4924a33700b77721d6b27b07f9f37198a17d3886 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/cpumask.h>
 #include <linux/sched.h>
 #include <linux/rcupdate.h>
+#include <linux/static_key.h>
 
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
 extern void __init tick_init(void);
@@ -19,16 +20,22 @@ extern void __init tick_init(void);
 extern void tick_suspend_local(void);
 /* Should be core only, but XEN resume magic and ARM BL switcher require it */
 extern void tick_resume_local(void);
-extern void tick_handover_do_timer(void);
 extern void tick_cleanup_dead_cpu(int cpu);
 #else /* CONFIG_GENERIC_CLOCKEVENTS */
 static inline void tick_init(void) { }
 static inline void tick_suspend_local(void) { }
 static inline void tick_resume_local(void) { }
-static inline void tick_handover_do_timer(void) { }
 static inline void tick_cleanup_dead_cpu(int cpu) { }
 #endif /* !CONFIG_GENERIC_CLOCKEVENTS */
 
+#if defined(CONFIG_GENERIC_CLOCKEVENTS) && defined(CONFIG_HOTPLUG_CPU)
+extern int tick_cpu_dying(unsigned int cpu);
+extern void tick_assert_timekeeping_handover(void);
+#else
+#define tick_cpu_dying NULL
+static inline void tick_assert_timekeeping_handover(void) { }
+#endif
+
 #if defined(CONFIG_GENERIC_CLOCKEVENTS) && defined(CONFIG_SUSPEND)
 extern void tick_freeze(void);
 extern void tick_unfreeze(void);
@@ -63,18 +70,14 @@ enum tick_broadcast_state {
        TICK_BROADCAST_ENTER,
 };
 
+extern struct static_key_false arch_needs_tick_broadcast;
+
 #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 extern void tick_broadcast_control(enum tick_broadcast_mode mode);
 #else
 static inline void tick_broadcast_control(enum tick_broadcast_mode mode) { }
 #endif /* BROADCAST */
 
-#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_HOTPLUG_CPU)
-extern void tick_offline_cpu(unsigned int cpu);
-#else
-static inline void tick_offline_cpu(unsigned int cpu) { }
-#endif
-
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
 extern int tick_broadcast_oneshot_control(enum tick_broadcast_state state);
 #else
@@ -164,9 +167,16 @@ static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; }
 static inline u64 get_cpu_iowait_time_us(int cpu, u64 *unused) { return -1; }
 #endif /* !CONFIG_NO_HZ_COMMON */
 
+/*
+ * Mask of CPUs that are nohz_full.
+ *
+ * Users should be guarded by CONFIG_NO_HZ_FULL or a tick_nohz_full_cpu()
+ * check.
+ */
+extern cpumask_var_t tick_nohz_full_mask;
+
 #ifdef CONFIG_NO_HZ_FULL
 extern bool tick_nohz_full_running;
-extern cpumask_var_t tick_nohz_full_mask;
 
 static inline bool tick_nohz_full_enabled(void)
 {
index 7c43e98cf2115088c085417028ad4329be638278..7e50cbd97f86e3de4160373aaf1aff05179ed9e4 100644 (file)
@@ -268,15 +268,17 @@ struct system_device_crosststamp {
 };
 
 /**
- * struct system_counterval_t - system counter value with the pointer to the
+ * struct system_counterval_t - system counter value with the ID of the
  *                             corresponding clocksource
  * @cycles:    System counter value
- * @cs:                Clocksource corresponding to system counter value. Used by
- *             timekeeping code to verify comparibility of two cycle values
+ * @cs_id:     Clocksource ID corresponding to system counter value. Used by
+ *             timekeeping code to verify comparability of two cycle values.
+ *             The default ID, CSID_GENERIC, does not identify a specific
+ *             clocksource.
  */
 struct system_counterval_t {
        u64                     cycles;
-       struct clocksource      *cs;
+       enum clocksource_ids    cs_id;
 };
 
 /*
index f18a2f1eb79e275525967b066e91082a75dc2e59..14a633ba61d6433400a488ff21d73172f3616281 100644 (file)
  * workqueue locking issues. It's not meant for executing random crap
  * with interrupts disabled. Abuse is monitored!
  *
- * @TIMER_PINNED: A pinned timer will not be affected by any timer
- * placement heuristics (like, NOHZ) and will always expire on the CPU
- * on which the timer was enqueued.
- *
- * Note: Because enqueuing of timers can migrate the timer from one
- * CPU to another, pinned timers are not guaranteed to stay on the
- * initialy selected CPU.  They move to the CPU on which the enqueue
- * function is invoked via mod_timer() or add_timer().  If the timer
- * should be placed on a particular CPU, then add_timer_on() has to be
- * used.
+ * @TIMER_PINNED: A pinned timer will always expire on the CPU on which the
+ * timer was enqueued. When a particular CPU is required, add_timer_on()
+ * has to be used. Enqueue via mod_timer() and add_timer() is always done
+ * on the local CPU.
  */
 #define TIMER_CPUMASK          0x0003FFFF
 #define TIMER_MIGRATING                0x00040000
@@ -165,6 +159,8 @@ extern int timer_reduce(struct timer_list *timer, unsigned long expires);
 #define NEXT_TIMER_MAX_DELTA   ((1UL << 30) - 1)
 
 extern void add_timer(struct timer_list *timer);
+extern void add_timer_local(struct timer_list *timer);
+extern void add_timer_global(struct timer_list *timer);
 
 extern int try_to_del_timer_sync(struct timer_list *timer);
 extern int timer_delete_sync(struct timer_list *timer);
index 9ec229dfddaa774b9c0a4f2ae410eb273061c330..1ef95c0287f05daed3a1096ad9d5a4cf66dd0f3e 100644 (file)
@@ -9,9 +9,15 @@
 /*
  * Trace sequences are used to allow a function to call several other functions
  * to create a string of data to use.
+ *
+ * Have the trace seq to be 8K which is typically PAGE_SIZE * 2 on
+ * most architectures. The TRACE_SEQ_BUFFER_SIZE (which is
+ * TRACE_SEQ_SIZE minus the other fields of trace_seq), is the
+ * max size the output of a trace event may be.
  */
 
-#define TRACE_SEQ_BUFFER_SIZE  (PAGE_SIZE * 2 - \
+#define TRACE_SEQ_SIZE         8192
+#define TRACE_SEQ_BUFFER_SIZE  (TRACE_SEQ_SIZE - \
        (sizeof(struct seq_buf) + sizeof(size_t) + sizeof(int)))
 
 struct trace_seq {
index bea9c89922d908f66511dacb02edc8f4bcad918c..00cebe2b70de7ef3d74c814d4c59b4539c3d55da 100644 (file)
@@ -40,7 +40,6 @@ struct iov_iter_state {
 
 struct iov_iter {
        u8 iter_type;
-       bool copy_mc;
        bool nofault;
        bool data_source;
        size_t iov_offset;
@@ -248,22 +247,8 @@ size_t _copy_from_iter_flushcache(void *addr, size_t bytes, struct iov_iter *i);
 
 #ifdef CONFIG_ARCH_HAS_COPY_MC
 size_t _copy_mc_to_iter(const void *addr, size_t bytes, struct iov_iter *i);
-static inline void iov_iter_set_copy_mc(struct iov_iter *i)
-{
-       i->copy_mc = true;
-}
-
-static inline bool iov_iter_is_copy_mc(const struct iov_iter *i)
-{
-       return i->copy_mc;
-}
 #else
 #define _copy_mc_to_iter _copy_to_iter
-static inline void iov_iter_set_copy_mc(struct iov_iter *i) { }
-static inline bool iov_iter_is_copy_mc(const struct iov_iter *i)
-{
-       return false;
-}
 #endif
 
 size_t iov_iter_zero(size_t bytes, struct iov_iter *);
@@ -355,7 +340,6 @@ static inline void iov_iter_ubuf(struct iov_iter *i, unsigned int direction,
        WARN_ON(direction & ~(READ | WRITE));
        *i = (struct iov_iter) {
                .iter_type = ITER_UBUF,
-               .copy_mc = false,
                .data_source = direction,
                .ubuf = buf,
                .count = count,
index a771ccc038ac949f2b4a835e28d720735e17ee22..6532beb587b1978e09bc5b17dc088daf91f9f88c 100644 (file)
@@ -236,7 +236,6 @@ struct usb_ep {
        unsigned                max_streams:16;
        unsigned                mult:2;
        unsigned                maxburst:5;
-       unsigned                fifo_mode:1;
        u8                      address;
        const struct usb_endpoint_descriptor    *desc;
        const struct usb_ss_ep_comp_descriptor  *comp_desc;
index cd77fc6095a15b5f8d313179436fc8b33efbc769..ac95e7c89df58ace92ed4c1b401f72cbc3857d20 100644 (file)
@@ -55,7 +55,7 @@ struct giveback_urb_bh {
        bool high_prio;
        spinlock_t lock;
        struct list_head  head;
-       struct tasklet_struct bh;
+       struct work_struct bh;
        struct usb_host_endpoint *completing_ep;
 };
 
index 2cc0a9606175fa6f653db5eccadf0071027d6c2f..158784dd189ab2a424b02fca0760f95f0af7de2d 100644 (file)
  */
 #define work_data_bits(work) ((unsigned long *)(&(work)->data))
 
-enum {
+enum work_bits {
        WORK_STRUCT_PENDING_BIT = 0,    /* work item is pending execution */
-       WORK_STRUCT_INACTIVE_BIT= 1,    /* work item is inactive */
-       WORK_STRUCT_PWQ_BIT     = 2,    /* data points to pwq */
-       WORK_STRUCT_LINKED_BIT  = 3,    /* next work is linked to this one */
+       WORK_STRUCT_INACTIVE_BIT,       /* work item is inactive */
+       WORK_STRUCT_PWQ_BIT,            /* data points to pwq */
+       WORK_STRUCT_LINKED_BIT,         /* next work is linked to this one */
 #ifdef CONFIG_DEBUG_OBJECTS_WORK
-       WORK_STRUCT_STATIC_BIT  = 4,    /* static initializer (debugobjects) */
-       WORK_STRUCT_COLOR_SHIFT = 5,    /* color for workqueue flushing */
-#else
-       WORK_STRUCT_COLOR_SHIFT = 4,    /* color for workqueue flushing */
+       WORK_STRUCT_STATIC_BIT,         /* static initializer (debugobjects) */
 #endif
+       WORK_STRUCT_FLAG_BITS,
 
+       /* color for workqueue flushing */
+       WORK_STRUCT_COLOR_SHIFT = WORK_STRUCT_FLAG_BITS,
        WORK_STRUCT_COLOR_BITS  = 4,
 
+       /*
+        * When WORK_STRUCT_PWQ is set, reserve 8 bits off of pwq pointer w/
+        * debugobjects turned off. This makes pwqs aligned to 256 bytes (512
+        * bytes w/ DEBUG_OBJECTS_WORK) and allows 16 workqueue flush colors.
+        *
+        * MSB
+        * [ pwq pointer ] [ flush color ] [ STRUCT flags ]
+        *                     4 bits        4 or 5 bits
+        */
+       WORK_STRUCT_PWQ_SHIFT   = WORK_STRUCT_COLOR_SHIFT + WORK_STRUCT_COLOR_BITS,
+
+       /*
+        * data contains off-queue information when !WORK_STRUCT_PWQ.
+        *
+        * MSB
+        * [ pool ID ] [ OFFQ flags ] [ STRUCT flags ]
+        *                 1 bit        4 or 5 bits
+        */
+       WORK_OFFQ_FLAG_SHIFT    = WORK_STRUCT_FLAG_BITS,
+       WORK_OFFQ_CANCELING_BIT = WORK_OFFQ_FLAG_SHIFT,
+       WORK_OFFQ_FLAG_END,
+       WORK_OFFQ_FLAG_BITS     = WORK_OFFQ_FLAG_END - WORK_OFFQ_FLAG_SHIFT,
+
+       /*
+        * When a work item is off queue, the high bits encode off-queue flags
+        * and the last pool it was on. Cap pool ID to 31 bits and use the
+        * highest number to indicate that no pool is associated.
+        */
+       WORK_OFFQ_POOL_SHIFT    = WORK_OFFQ_FLAG_SHIFT + WORK_OFFQ_FLAG_BITS,
+       WORK_OFFQ_LEFT          = BITS_PER_LONG - WORK_OFFQ_POOL_SHIFT,
+       WORK_OFFQ_POOL_BITS     = WORK_OFFQ_LEFT <= 31 ? WORK_OFFQ_LEFT : 31,
+};
+
+enum work_flags {
        WORK_STRUCT_PENDING     = 1 << WORK_STRUCT_PENDING_BIT,
        WORK_STRUCT_INACTIVE    = 1 << WORK_STRUCT_INACTIVE_BIT,
        WORK_STRUCT_PWQ         = 1 << WORK_STRUCT_PWQ_BIT,
@@ -45,35 +79,14 @@ enum {
 #else
        WORK_STRUCT_STATIC      = 0,
 #endif
+};
 
+enum wq_misc_consts {
        WORK_NR_COLORS          = (1 << WORK_STRUCT_COLOR_BITS),
 
        /* not bound to any CPU, prefer the local CPU */
        WORK_CPU_UNBOUND        = NR_CPUS,
 
-       /*
-        * Reserve 8 bits off of pwq pointer w/ debugobjects turned off.
-        * This makes pwqs aligned to 256 bytes and allows 16 workqueue
-        * flush colors.
-        */
-       WORK_STRUCT_FLAG_BITS   = WORK_STRUCT_COLOR_SHIFT +
-                                 WORK_STRUCT_COLOR_BITS,
-
-       /* data contains off-queue information when !WORK_STRUCT_PWQ */
-       WORK_OFFQ_FLAG_BASE     = WORK_STRUCT_COLOR_SHIFT,
-
-       __WORK_OFFQ_CANCELING   = WORK_OFFQ_FLAG_BASE,
-
-       /*
-        * When a work item is off queue, its high bits point to the last
-        * pool it was on.  Cap at 31 bits and use the highest number to
-        * indicate that no pool is associated.
-        */
-       WORK_OFFQ_FLAG_BITS     = 1,
-       WORK_OFFQ_POOL_SHIFT    = WORK_OFFQ_FLAG_BASE + WORK_OFFQ_FLAG_BITS,
-       WORK_OFFQ_LEFT          = BITS_PER_LONG - WORK_OFFQ_POOL_SHIFT,
-       WORK_OFFQ_POOL_BITS     = WORK_OFFQ_LEFT <= 31 ? WORK_OFFQ_LEFT : 31,
-
        /* bit mask for work_busy() return values */
        WORK_BUSY_PENDING       = 1 << 0,
        WORK_BUSY_RUNNING       = 1 << 1,
@@ -83,12 +96,10 @@ enum {
 };
 
 /* Convenience constants - of type 'unsigned long', not 'enum'! */
-#define WORK_OFFQ_CANCELING    (1ul << __WORK_OFFQ_CANCELING)
+#define WORK_OFFQ_CANCELING    (1ul << WORK_OFFQ_CANCELING_BIT)
 #define WORK_OFFQ_POOL_NONE    ((1ul << WORK_OFFQ_POOL_BITS) - 1)
 #define WORK_STRUCT_NO_POOL    (WORK_OFFQ_POOL_NONE << WORK_OFFQ_POOL_SHIFT)
-
-#define WORK_STRUCT_FLAG_MASK    ((1ul << WORK_STRUCT_FLAG_BITS) - 1)
-#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
+#define WORK_STRUCT_PWQ_MASK   (~((1ul << WORK_STRUCT_PWQ_SHIFT) - 1))
 
 #define WORK_DATA_INIT()       ATOMIC_LONG_INIT((unsigned long)WORK_STRUCT_NO_POOL)
 #define WORK_DATA_STATIC_INIT()        \
@@ -347,7 +358,8 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
  * Workqueue flags and constants.  For details, please refer to
  * Documentation/core-api/workqueue.rst.
  */
-enum {
+enum wq_flags {
+       WQ_BH                   = 1 << 0, /* execute in bottom half (softirq) context */
        WQ_UNBOUND              = 1 << 1, /* not bound to any cpu */
        WQ_FREEZABLE            = 1 << 2, /* freeze during suspend */
        WQ_MEM_RECLAIM          = 1 << 3, /* may be used for memory reclaim */
@@ -386,11 +398,22 @@ enum {
        __WQ_DRAINING           = 1 << 16, /* internal: workqueue is draining */
        __WQ_ORDERED            = 1 << 17, /* internal: workqueue is ordered */
        __WQ_LEGACY             = 1 << 18, /* internal: create*_workqueue() */
-       __WQ_ORDERED_EXPLICIT   = 1 << 19, /* internal: alloc_ordered_workqueue() */
 
+       /* BH wq only allows the following flags */
+       __WQ_BH_ALLOWS          = WQ_BH | WQ_HIGHPRI,
+};
+
+enum wq_consts {
        WQ_MAX_ACTIVE           = 512,    /* I like 512, better ideas? */
        WQ_UNBOUND_MAX_ACTIVE   = WQ_MAX_ACTIVE,
        WQ_DFL_ACTIVE           = WQ_MAX_ACTIVE / 2,
+
+       /*
+        * Per-node default cap on min_active. Unless explicitly set, min_active
+        * is set to min(max_active, WQ_DFL_MIN_ACTIVE). For more details, see
+        * workqueue_struct->min_active definition.
+        */
+       WQ_DFL_MIN_ACTIVE       = 8,
 };
 
 /*
@@ -420,6 +443,9 @@ enum {
  * they are same as their non-power-efficient counterparts - e.g.
  * system_power_efficient_wq is identical to system_wq if
  * 'wq_power_efficient' is disabled.  See WQ_POWER_EFFICIENT for more info.
+ *
+ * system_bh[_highpri]_wq are convenience interface to softirq. BH work items
+ * are executed in the queueing CPU's BH context in the queueing order.
  */
 extern struct workqueue_struct *system_wq;
 extern struct workqueue_struct *system_highpri_wq;
@@ -428,16 +454,43 @@ extern struct workqueue_struct *system_unbound_wq;
 extern struct workqueue_struct *system_freezable_wq;
 extern struct workqueue_struct *system_power_efficient_wq;
 extern struct workqueue_struct *system_freezable_power_efficient_wq;
+extern struct workqueue_struct *system_bh_wq;
+extern struct workqueue_struct *system_bh_highpri_wq;
+
+void workqueue_softirq_action(bool highpri);
+void workqueue_softirq_dead(unsigned int cpu);
 
 /**
  * alloc_workqueue - allocate a workqueue
  * @fmt: printf format for the name of the workqueue
  * @flags: WQ_* flags
- * @max_active: max in-flight work items per CPU, 0 for default
+ * @max_active: max in-flight work items, 0 for default
  * remaining args: args for @fmt
  *
- * Allocate a workqueue with the specified parameters.  For detailed
- * information on WQ_* flags, please refer to
+ * For a per-cpu workqueue, @max_active limits the number of in-flight work
+ * items for each CPU. e.g. @max_active of 1 indicates that each CPU can be
+ * executing at most one work item for the workqueue.
+ *
+ * For unbound workqueues, @max_active limits the number of in-flight work items
+ * for the whole system. e.g. @max_active of 16 indicates that that there can be
+ * at most 16 work items executing for the workqueue in the whole system.
+ *
+ * As sharing the same active counter for an unbound workqueue across multiple
+ * NUMA nodes can be expensive, @max_active is distributed to each NUMA node
+ * according to the proportion of the number of online CPUs and enforced
+ * independently.
+ *
+ * Depending on online CPU distribution, a node may end up with per-node
+ * max_active which is significantly lower than @max_active, which can lead to
+ * deadlocks if the per-node concurrency limit is lower than the maximum number
+ * of interdependent work items for the workqueue.
+ *
+ * To guarantee forward progress regardless of online CPU distribution, the
+ * concurrency limit on every node is guaranteed to be equal to or greater than
+ * min_active which is set to min(@max_active, %WQ_DFL_MIN_ACTIVE). This means
+ * that the sum of per-node max_active's may be larger than @max_active.
+ *
+ * For detailed information on %WQ_* flags, please refer to
  * Documentation/core-api/workqueue.rst.
  *
  * RETURNS:
@@ -460,8 +513,7 @@ alloc_workqueue(const char *fmt, unsigned int flags, int max_active, ...);
  * Pointer to the allocated workqueue on success, %NULL on failure.
  */
 #define alloc_ordered_workqueue(fmt, flags, args...)                   \
-       alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED |                \
-                       __WQ_ORDERED_EXPLICIT | (flags), 1, ##args)
+       alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
 
 #define create_workqueue(name)                                         \
        alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name))
@@ -471,6 +523,9 @@ alloc_workqueue(const char *fmt, unsigned int flags, int max_active, ...);
 #define create_singlethread_workqueue(name)                            \
        alloc_ordered_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, name)
 
+#define from_work(var, callback_work, work_fieldname)  \
+       container_of(callback_work, typeof(*var), work_fieldname)
+
 extern void destroy_workqueue(struct workqueue_struct *wq);
 
 struct workqueue_attrs *alloc_workqueue_attrs(void);
@@ -508,6 +563,8 @@ extern bool flush_rcu_work(struct rcu_work *rwork);
 
 extern void workqueue_set_max_active(struct workqueue_struct *wq,
                                     int max_active);
+extern void workqueue_set_min_active(struct workqueue_struct *wq,
+                                    int min_active);
 extern struct work_struct *current_work(void);
 extern bool current_is_workqueue_rescuer(void);
 extern bool workqueue_congested(int cpu, struct workqueue_struct *wq);
index 4dabeb6c76d31da1e3725a091a0a2636fcc9667c..9b09acac538eed8dbaa2576bf2af926ecd98eb44 100644 (file)
@@ -48,6 +48,10 @@ void napi_busy_loop(unsigned int napi_id,
                    bool (*loop_end)(void *, unsigned long),
                    void *loop_end_arg, bool prefer_busy_poll, u16 budget);
 
+void napi_busy_loop_rcu(unsigned int napi_id,
+                       bool (*loop_end)(void *, unsigned long),
+                       void *loop_end_arg, bool prefer_busy_poll, u16 budget);
+
 #else /* CONFIG_NET_RX_BUSY_POLL */
 static inline unsigned long net_busy_loop_on(void)
 {
index da86e106c91d57b2eedfc7bb301867eb8e51c123..2bff5f47ce82f1c6f2774f49d13a647c573034d7 100644 (file)
@@ -249,6 +249,7 @@ struct mctp_route {
 struct mctp_route *mctp_route_lookup(struct net *net, unsigned int dnet,
                                     mctp_eid_t daddr);
 
+/* always takes ownership of skb */
 int mctp_local_output(struct sock *sk, struct mctp_route *rt,
                      struct sk_buff *skb, mctp_eid_t daddr, u8 req_tag);
 
index 956c752ceb3180115eec0b607d81cafe5f038ce8..a763dd327c6ea95d6b94fda1ea2efd8f1784335f 100644 (file)
@@ -276,7 +276,7 @@ nf_flow_table_offload_del_cb(struct nf_flowtable *flow_table,
 }
 
 void flow_offload_route_init(struct flow_offload *flow,
-                            const struct nf_flow_route *route);
+                            struct nf_flow_route *route);
 
 int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow);
 void flow_offload_refresh(struct nf_flowtable *flow_table,
index 780a5f6ad4a671252836e3c53d6aa7eeaa4fef4a..ff27cb2e166207cf8b58a96944d9b07a1779afe3 100644 (file)
@@ -93,7 +93,7 @@ extern const struct nft_set_type nft_set_bitmap_type;
 extern const struct nft_set_type nft_set_pipapo_type;
 extern const struct nft_set_type nft_set_pipapo_avx2_type;
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
 bool nft_rhash_lookup(const struct net *net, const struct nft_set *set,
                      const u32 *key, const struct nft_set_ext **ext);
 bool nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
index 934fdb9775519ff45d9455e74a8695bf8a1e4bce..cefe0c4bdae34c91868c22731a3b666f8e16e996 100644 (file)
@@ -238,12 +238,7 @@ static inline bool qdisc_may_bulk(const struct Qdisc *qdisc)
 
 static inline int qdisc_avail_bulklimit(const struct netdev_queue *txq)
 {
-#ifdef CONFIG_BQL
-       /* Non-BQL migrated drivers will return 0, too. */
-       return dql_avail(&txq->dql);
-#else
-       return 0;
-#endif
+       return netdev_queue_dql_avail(txq);
 }
 
 struct Qdisc_class_ops {
index a43062d4c734bb4e8e855fdd150b8c169a7fe172..8346b0d29542c3d5569b94b35eaa12461f78d62a 100644 (file)
@@ -308,6 +308,9 @@ void switchdev_deferred_process(void);
 int switchdev_port_attr_set(struct net_device *dev,
                            const struct switchdev_attr *attr,
                            struct netlink_ext_ack *extack);
+bool switchdev_port_obj_act_is_deferred(struct net_device *dev,
+                                       enum switchdev_notifier_type nt,
+                                       const struct switchdev_obj *obj);
 int switchdev_port_obj_add(struct net_device *dev,
                           const struct switchdev_obj *obj,
                           struct netlink_ext_ack *extack);
index a608546bcefcf81fa9056dfc567f985c8fccb9b9..ffe58a02537c3ae7979e37ace09373a443d81cc9 100644 (file)
@@ -4,7 +4,7 @@
 
 #include <net/pkt_cls.h>
 
-#if IS_ENABLED(CONFIG_RETPOLINE)
+#if IS_ENABLED(CONFIG_MITIGATION_RETPOLINE)
 
 #include <linux/cpufeature.h>
 #include <linux/static_key.h>
index dd78a11810310e84ef1c1ed8c3e0e274ddd77d7f..f6eba9652d010fbc8482bfd3c99377d631686324 100644 (file)
@@ -2506,7 +2506,7 @@ struct tcp_ulp_ops {
        /* cleanup ulp */
        void (*release)(struct sock *sk);
        /* diagnostic */
-       int (*get_info)(const struct sock *sk, struct sk_buff *skb);
+       int (*get_info)(struct sock *sk, struct sk_buff *skb);
        size_t (*get_info_size)(const struct sock *sk);
        /* clone ulp */
        void (*clone)(const struct request_sock *req, struct sock *newsk,
index 962f0c501111bac34781c4419913540c162ea058..340ad43971e4711d8091a6397bb5cf3c3c4ef0fd 100644 (file)
@@ -97,9 +97,6 @@ struct tls_sw_context_tx {
        struct tls_rec *open_rec;
        struct list_head tx_list;
        atomic_t encrypt_pending;
-       /* protect crypto_wait with encrypt_pending */
-       spinlock_t encrypt_compl_lock;
-       int async_notify;
        u8 async_capable:1;
 
 #define BIT_TX_SCHEDULED       0
@@ -136,8 +133,6 @@ struct tls_sw_context_rx {
        struct tls_strparser strp;
 
        atomic_t decrypt_pending;
-       /* protect crypto_wait with decrypt_pending*/
-       spinlock_t decrypt_compl_lock;
        struct sk_buff_head async_hold;
        struct wait_queue_head wq;
 };
index 5ec1e71a09de7698616dff799a935da15083deef..c38f4fe5e64cf4f14b668328ab0cfac76ea5d496 100644 (file)
@@ -100,10 +100,6 @@ struct scsi_vpd {
        unsigned char   data[];
 };
 
-enum scsi_vpd_parameters {
-       SCSI_VPD_HEADER_SIZE = 4,
-};
-
 struct scsi_device {
        struct Scsi_Host *host;
        struct request_queue *request_queue;
@@ -208,6 +204,7 @@ struct scsi_device {
        unsigned use_10_for_rw:1; /* first try 10-byte read / write */
        unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */
        unsigned set_dbd_for_ms:1; /* Set "DBD" field in mode sense */
+       unsigned read_before_ms:1;      /* perform a READ before MODE SENSE */
        unsigned no_report_opcodes:1;   /* no REPORT SUPPORTED OPERATION CODES */
        unsigned no_write_same:1;       /* no WRITE SAME command */
        unsigned use_16_for_rw:1; /* Use read/write(16) over read/write(10) */
index 17a0a8c3d656087fdb8b53a666b46c13b75fcf14..a62d500a6fdaf200466c64758d8948d86e65d3b2 100644 (file)
@@ -49,7 +49,7 @@
 #define PMK8350_SUBTYPE                0x2f
 #define PMR735B_SUBTYPE                0x34
 #define PM6350_SUBTYPE         0x36
-#define PM2250_SUBTYPE         0x37
+#define PM4125_SUBTYPE         0x37
 
 #define PMI8998_FAB_ID_SMIC    0x11
 #define PMI8998_FAB_ID_GF      0x30
index 4951f9d8b0bdb810e2c2548003f13dc925e91c5c..5b263c6858127cd0cbd92603db6eada8dc3c6d17 100644 (file)
@@ -7,11 +7,6 @@
 #ifndef __SPM_H__
 #define __SPM_H__
 
-#include <linux/cpuidle.h>
-
-#define MAX_PMIC_DATA          2
-#define MAX_SEQ_DATA           64
-
 enum pm_sleep_mode {
        PM_SLEEP_MODE_STBY,
        PM_SLEEP_MODE_RET,
@@ -20,23 +15,7 @@ enum pm_sleep_mode {
        PM_SLEEP_MODE_NR,
 };
 
-struct spm_reg_data {
-       const u16 *reg_offset;
-       u32 spm_cfg;
-       u32 spm_dly;
-       u32 pmic_dly;
-       u32 pmic_data[MAX_PMIC_DATA];
-       u32 avs_ctl;
-       u32 avs_limit;
-       u8 seq[MAX_SEQ_DATA];
-       u8 start_index[PM_SLEEP_MODE_NR];
-};
-
-struct spm_driver_data {
-       void __iomem *reg_base;
-       const struct spm_reg_data *reg_data;
-};
-
+struct spm_driver_data;
 void spm_set_low_power_mode(struct spm_driver_data *drv,
                            enum pm_sleep_mode mode);
 
index 3a513be502437f991cdb29518a83146e72f48a87..8f421b9f7585ca1714197c8c102d7a19e622d1a2 100644 (file)
@@ -17,6 +17,7 @@
 #define TEGRA186       0x18
 #define TEGRA194       0x19
 #define TEGRA234       0x23
+#define TEGRA241       0x24
 #define TEGRA264       0x26
 
 #define TEGRA_FUSE_SKU_CALIB_0 0xf0
index aadb845d281dd7d3c0532111d82cdfae3e742059..c545875d0ff18e6117e1ad0ffc61252240fd16a2 100644 (file)
@@ -148,10 +148,6 @@ enum tegra_io_pad {
        TEGRA_IO_PAD_AO_HV,
 };
 
-/* deprecated, use TEGRA_IO_PAD_{HDMI,LVDS} instead */
-#define TEGRA_IO_RAIL_HDMI     TEGRA_IO_PAD_HDMI
-#define TEGRA_IO_RAIL_LVDS     TEGRA_IO_PAD_LVDS
-
 #ifdef CONFIG_SOC_TEGRA_PMC
 int tegra_powergate_power_on(unsigned int id);
 int tegra_powergate_power_off(unsigned int id);
@@ -164,10 +160,6 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
 int tegra_io_pad_power_enable(enum tegra_io_pad id);
 int tegra_io_pad_power_disable(enum tegra_io_pad id);
 
-/* deprecated, use tegra_io_pad_power_{enable,disable}() instead */
-int tegra_io_rail_power_on(unsigned int id);
-int tegra_io_rail_power_off(unsigned int id);
-
 void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
 void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
 
@@ -211,16 +203,6 @@ static inline int tegra_io_pad_get_voltage(enum tegra_io_pad id)
        return -ENOSYS;
 }
 
-static inline int tegra_io_rail_power_on(unsigned int id)
-{
-       return -ENOSYS;
-}
-
-static inline int tegra_io_rail_power_off(unsigned int id)
-{
-       return -ENOSYS;
-}
-
 static inline void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
 {
 }
index ecc02e955279fdfa3f10d116eeb5a2d7271cc91c..1f4c39922d825035be15ba38e7ac6d112b36c457 100644 (file)
@@ -30,6 +30,8 @@ static inline void snd_soc_card_mutex_unlock(struct snd_soc_card *card)
 
 struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
                                               const char *name);
+struct snd_kcontrol *snd_soc_card_get_kcontrol_locked(struct snd_soc_card *soc_card,
+                                                     const char *name);
 int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
                          struct snd_soc_jack *jack);
 int snd_soc_card_jack_new_pins(struct snd_soc_card *card, const char *id,
index b00d65417c310a42a39aec6ce927b85083ace264..9aff384941de27f925d0491312a7088ebeb6a297 100644 (file)
@@ -142,6 +142,7 @@ struct tasdevice_priv {
 
 void tas2781_reset(struct tasdevice_priv *tas_dev);
 int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
+       struct module *module,
        void (*cont)(const struct firmware *fw, void *context));
 struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c);
 int tasdevice_init(struct tasdevice_priv *tas_priv);
index 08f2c93d6b1607939fb47c510153d544f496febe..450c44c83a5d21bad22485efbb5734c47edb0125 100644 (file)
@@ -1189,8 +1189,8 @@ TRACE_EVENT(afs_flock_op,
                    __entry->from = fl->fl_start;
                    __entry->len = fl->fl_end - fl->fl_start + 1;
                    __entry->op = op;
-                   __entry->type = fl->fl_type;
-                   __entry->flags = fl->fl_flags;
+                   __entry->type = fl->c.flc_type;
+                   __entry->flags = fl->c.flc_flags;
                    __entry->debug_id = fl->fl_u.afs.debug_id;
                           ),
 
index 1646dadd7f37cf7c97f6cd140e9571f43e9aa141..b8d1e00a7982c9ef966f414ee279ed91663bf550 100644 (file)
@@ -68,11 +68,11 @@ DECLARE_EVENT_CLASS(filelock_lock,
                __field(struct file_lock *, fl)
                __field(unsigned long, i_ino)
                __field(dev_t, s_dev)
-               __field(struct file_lock *, fl_blocker)
-               __field(fl_owner_t, fl_owner)
-               __field(unsigned int, fl_pid)
-               __field(unsigned int, fl_flags)
-               __field(unsigned char, fl_type)
+               __field(struct file_lock_core *, blocker)
+               __field(fl_owner_t, owner)
+               __field(unsigned int, pid)
+               __field(unsigned int, flags)
+               __field(unsigned char, type)
                __field(loff_t, fl_start)
                __field(loff_t, fl_end)
                __field(int, ret)
@@ -82,11 +82,11 @@ DECLARE_EVENT_CLASS(filelock_lock,
                __entry->fl = fl ? fl : NULL;
                __entry->s_dev = inode->i_sb->s_dev;
                __entry->i_ino = inode->i_ino;
-               __entry->fl_blocker = fl ? fl->fl_blocker : NULL;
-               __entry->fl_owner = fl ? fl->fl_owner : NULL;
-               __entry->fl_pid = fl ? fl->fl_pid : 0;
-               __entry->fl_flags = fl ? fl->fl_flags : 0;
-               __entry->fl_type = fl ? fl->fl_type : 0;
+               __entry->blocker = fl ? fl->c.flc_blocker : NULL;
+               __entry->owner = fl ? fl->c.flc_owner : NULL;
+               __entry->pid = fl ? fl->c.flc_pid : 0;
+               __entry->flags = fl ? fl->c.flc_flags : 0;
+               __entry->type = fl ? fl->c.flc_type : 0;
                __entry->fl_start = fl ? fl->fl_start : 0;
                __entry->fl_end = fl ? fl->fl_end : 0;
                __entry->ret = ret;
@@ -94,9 +94,9 @@ DECLARE_EVENT_CLASS(filelock_lock,
 
        TP_printk("fl=%p dev=0x%x:0x%x ino=0x%lx fl_blocker=%p fl_owner=%p fl_pid=%u fl_flags=%s fl_type=%s fl_start=%lld fl_end=%lld ret=%d",
                __entry->fl, MAJOR(__entry->s_dev), MINOR(__entry->s_dev),
-               __entry->i_ino, __entry->fl_blocker, __entry->fl_owner,
-               __entry->fl_pid, show_fl_flags(__entry->fl_flags),
-               show_fl_type(__entry->fl_type),
+               __entry->i_ino, __entry->blocker, __entry->owner,
+               __entry->pid, show_fl_flags(__entry->flags),
+               show_fl_type(__entry->type),
                __entry->fl_start, __entry->fl_end, __entry->ret)
 );
 
@@ -117,59 +117,59 @@ DEFINE_EVENT(filelock_lock, flock_lock_inode,
                TP_ARGS(inode, fl, ret));
 
 DECLARE_EVENT_CLASS(filelock_lease,
-       TP_PROTO(struct inode *inode, struct file_lock *fl),
+       TP_PROTO(struct inode *inode, struct file_lease *fl),
 
        TP_ARGS(inode, fl),
 
        TP_STRUCT__entry(
-               __field(struct file_lock *, fl)
+               __field(struct file_lease *, fl)
                __field(unsigned long, i_ino)
                __field(dev_t, s_dev)
-               __field(struct file_lock *, fl_blocker)
-               __field(fl_owner_t, fl_owner)
-               __field(unsigned int, fl_flags)
-               __field(unsigned char, fl_type)
-               __field(unsigned long, fl_break_time)
-               __field(unsigned long, fl_downgrade_time)
+               __field(struct file_lock_core *, blocker)
+               __field(fl_owner_t, owner)
+               __field(unsigned int, flags)
+               __field(unsigned char, type)
+               __field(unsigned long, break_time)
+               __field(unsigned long, downgrade_time)
        ),
 
        TP_fast_assign(
                __entry->fl = fl ? fl : NULL;
                __entry->s_dev = inode->i_sb->s_dev;
                __entry->i_ino = inode->i_ino;
-               __entry->fl_blocker = fl ? fl->fl_blocker : NULL;
-               __entry->fl_owner = fl ? fl->fl_owner : NULL;
-               __entry->fl_flags = fl ? fl->fl_flags : 0;
-               __entry->fl_type = fl ? fl->fl_type : 0;
-               __entry->fl_break_time = fl ? fl->fl_break_time : 0;
-               __entry->fl_downgrade_time = fl ? fl->fl_downgrade_time : 0;
+               __entry->blocker = fl ? fl->c.flc_blocker : NULL;
+               __entry->owner = fl ? fl->c.flc_owner : NULL;
+               __entry->flags = fl ? fl->c.flc_flags : 0;
+               __entry->type = fl ? fl->c.flc_type : 0;
+               __entry->break_time = fl ? fl->fl_break_time : 0;
+               __entry->downgrade_time = fl ? fl->fl_downgrade_time : 0;
        ),
 
        TP_printk("fl=%p dev=0x%x:0x%x ino=0x%lx fl_blocker=%p fl_owner=%p fl_flags=%s fl_type=%s fl_break_time=%lu fl_downgrade_time=%lu",
                __entry->fl, MAJOR(__entry->s_dev), MINOR(__entry->s_dev),
-               __entry->i_ino, __entry->fl_blocker, __entry->fl_owner,
-               show_fl_flags(__entry->fl_flags),
-               show_fl_type(__entry->fl_type),
-               __entry->fl_break_time, __entry->fl_downgrade_time)
+               __entry->i_ino, __entry->blocker, __entry->owner,
+               show_fl_flags(__entry->flags),
+               show_fl_type(__entry->type),
+               __entry->break_time, __entry->downgrade_time)
 );
 
-DEFINE_EVENT(filelock_lease, break_lease_noblock, TP_PROTO(struct inode *inode, struct file_lock *fl),
+DEFINE_EVENT(filelock_lease, break_lease_noblock, TP_PROTO(struct inode *inode, struct file_lease *fl),
                TP_ARGS(inode, fl));
 
-DEFINE_EVENT(filelock_lease, break_lease_block, TP_PROTO(struct inode *inode, struct file_lock *fl),
+DEFINE_EVENT(filelock_lease, break_lease_block, TP_PROTO(struct inode *inode, struct file_lease *fl),
                TP_ARGS(inode, fl));
 
-DEFINE_EVENT(filelock_lease, break_lease_unblock, TP_PROTO(struct inode *inode, struct file_lock *fl),
+DEFINE_EVENT(filelock_lease, break_lease_unblock, TP_PROTO(struct inode *inode, struct file_lease *fl),
                TP_ARGS(inode, fl));
 
-DEFINE_EVENT(filelock_lease, generic_delete_lease, TP_PROTO(struct inode *inode, struct file_lock *fl),
+DEFINE_EVENT(filelock_lease, generic_delete_lease, TP_PROTO(struct inode *inode, struct file_lease *fl),
                TP_ARGS(inode, fl));
 
-DEFINE_EVENT(filelock_lease, time_out_leases, TP_PROTO(struct inode *inode, struct file_lock *fl),
+DEFINE_EVENT(filelock_lease, time_out_leases, TP_PROTO(struct inode *inode, struct file_lease *fl),
                TP_ARGS(inode, fl));
 
 TRACE_EVENT(generic_add_lease,
-       TP_PROTO(struct inode *inode, struct file_lock *fl),
+       TP_PROTO(struct inode *inode, struct file_lease *fl),
 
        TP_ARGS(inode, fl),
 
@@ -179,9 +179,9 @@ TRACE_EVENT(generic_add_lease,
                __field(int, rcount)
                __field(int, icount)
                __field(dev_t, s_dev)
-               __field(fl_owner_t, fl_owner)
-               __field(unsigned int, fl_flags)
-               __field(unsigned char, fl_type)
+               __field(fl_owner_t, owner)
+               __field(unsigned int, flags)
+               __field(unsigned char, type)
        ),
 
        TP_fast_assign(
@@ -190,21 +190,21 @@ TRACE_EVENT(generic_add_lease,
                __entry->wcount = atomic_read(&inode->i_writecount);
                __entry->rcount = atomic_read(&inode->i_readcount);
                __entry->icount = atomic_read(&inode->i_count);
-               __entry->fl_owner = fl->fl_owner;
-               __entry->fl_flags = fl->fl_flags;
-               __entry->fl_type = fl->fl_type;
+               __entry->owner = fl->c.flc_owner;
+               __entry->flags = fl->c.flc_flags;
+               __entry->type = fl->c.flc_type;
        ),
 
        TP_printk("dev=0x%x:0x%x ino=0x%lx wcount=%d rcount=%d icount=%d fl_owner=%p fl_flags=%s fl_type=%s",
                MAJOR(__entry->s_dev), MINOR(__entry->s_dev),
                __entry->i_ino, __entry->wcount, __entry->rcount,
-               __entry->icount, __entry->fl_owner,
-               show_fl_flags(__entry->fl_flags),
-               show_fl_type(__entry->fl_type))
+               __entry->icount, __entry->owner,
+               show_fl_flags(__entry->flags),
+               show_fl_type(__entry->type))
 );
 
 TRACE_EVENT(leases_conflict,
-       TP_PROTO(bool conflict, struct file_lock *lease, struct file_lock *breaker),
+       TP_PROTO(bool conflict, struct file_lease *lease, struct file_lease *breaker),
 
        TP_ARGS(conflict, lease, breaker),
 
@@ -220,11 +220,11 @@ TRACE_EVENT(leases_conflict,
 
        TP_fast_assign(
                __entry->lease = lease;
-               __entry->l_fl_flags = lease->fl_flags;
-               __entry->l_fl_type = lease->fl_type;
+               __entry->l_fl_flags = lease->c.flc_flags;
+               __entry->l_fl_type = lease->c.flc_type;
                __entry->breaker = breaker;
-               __entry->b_fl_flags = breaker->fl_flags;
-               __entry->b_fl_type = breaker->fl_type;
+               __entry->b_fl_flags = breaker->c.flc_flags;
+               __entry->b_fl_type = breaker->c.flc_type;
                __entry->conflict = conflict;
        ),
 
index 69454f1f98b01eb3d16eb01eb2c9c39d69c7705b..e948df7ce62597507d88327723d5586f578c5c8d 100644 (file)
@@ -148,7 +148,7 @@ TRACE_EVENT(io_uring_queue_async_work,
                __field(  void *,                       req             )
                __field(  u64,                          user_data       )
                __field(  u8,                           opcode          )
-               __field(  unsigned int,                 flags           )
+               __field(  unsigned long long,           flags           )
                __field(  struct io_wq_work *,          work            )
                __field(  int,                          rw              )
 
@@ -159,7 +159,7 @@ TRACE_EVENT(io_uring_queue_async_work,
                __entry->ctx            = req->ctx;
                __entry->req            = req;
                __entry->user_data      = req->cqe.user_data;
-               __entry->flags          = req->flags;
+               __entry->flags          = (__force unsigned long long) req->flags;
                __entry->opcode         = req->opcode;
                __entry->work           = &req->work;
                __entry->rw             = rw;
@@ -167,10 +167,10 @@ TRACE_EVENT(io_uring_queue_async_work,
                __assign_str(op_str, io_uring_get_opcode(req->opcode));
        ),
 
-       TP_printk("ring %p, request %p, user_data 0x%llx, opcode %s, flags 0x%x, %s queue, work %p",
+       TP_printk("ring %p, request %p, user_data 0x%llx, opcode %s, flags 0x%llx, %s queue, work %p",
                __entry->ctx, __entry->req, __entry->user_data,
-               __get_str(op_str),
-               __entry->flags, __entry->rw ? "hashed" : "normal", __entry->work)
+               __get_str(op_str), __entry->flags,
+               __entry->rw ? "hashed" : "normal", __entry->work)
 );
 
 /**
@@ -378,7 +378,7 @@ TRACE_EVENT(io_uring_submit_req,
                __field(  void *,               req             )
                __field(  unsigned long long,   user_data       )
                __field(  u8,                   opcode          )
-               __field(  u32,                  flags           )
+               __field(  unsigned long long,   flags           )
                __field(  bool,                 sq_thread       )
 
                __string( op_str, io_uring_get_opcode(req->opcode) )
@@ -389,16 +389,16 @@ TRACE_EVENT(io_uring_submit_req,
                __entry->req            = req;
                __entry->user_data      = req->cqe.user_data;
                __entry->opcode         = req->opcode;
-               __entry->flags          = req->flags;
+               __entry->flags          = (__force unsigned long long) req->flags;
                __entry->sq_thread      = req->ctx->flags & IORING_SETUP_SQPOLL;
 
                __assign_str(op_str, io_uring_get_opcode(req->opcode));
        ),
 
-       TP_printk("ring %p, req %p, user_data 0x%llx, opcode %s, flags 0x%x, "
+       TP_printk("ring %p, req %p, user_data 0x%llx, opcode %s, flags 0x%llx, "
                  "sq_thread %d", __entry->ctx, __entry->req,
-                 __entry->user_data, __get_str(op_str),
-                 __entry->flags, __entry->sq_thread)
+                 __entry->user_data, __get_str(op_str), __entry->flags,
+                 __entry->sq_thread)
 );
 
 /*
@@ -602,29 +602,25 @@ TRACE_EVENT(io_uring_cqe_overflow,
  *
  * @tctx:              pointer to a io_uring_task
  * @count:             how many functions it ran
- * @loops:             how many loops it ran
  *
  */
 TRACE_EVENT(io_uring_task_work_run,
 
-       TP_PROTO(void *tctx, unsigned int count, unsigned int loops),
+       TP_PROTO(void *tctx, unsigned int count),
 
-       TP_ARGS(tctx, count, loops),
+       TP_ARGS(tctx, count),
 
        TP_STRUCT__entry (
                __field(  void *,               tctx            )
                __field(  unsigned int,         count           )
-               __field(  unsigned int,         loops           )
        ),
 
        TP_fast_assign(
                __entry->tctx           = tctx;
                __entry->count          = count;
-               __entry->loops          = loops;
        ),
 
-       TP_printk("tctx %p, count %u, loops %u",
-                __entry->tctx, __entry->count, __entry->loops)
+       TP_printk("tctx %p, count %u", __entry->tctx, __entry->count)
 );
 
 TRACE_EVENT(io_uring_short_write,
index a3995925cb057021dc779344d19f7e3724f6df3c..1f4258308b967a9ca8e17bbf61ba4ef07b6d786b 100644 (file)
@@ -81,14 +81,14 @@ TRACE_EVENT(qdisc_reset,
        TP_ARGS(q),
 
        TP_STRUCT__entry(
-               __string(       dev,            qdisc_dev(q)    )
-               __string(       kind,           q->ops->id      )
-               __field(        u32,            parent          )
-               __field(        u32,            handle          )
+               __string(       dev,            qdisc_dev(q)->name      )
+               __string(       kind,           q->ops->id              )
+               __field(        u32,            parent                  )
+               __field(        u32,            handle                  )
        ),
 
        TP_fast_assign(
-               __assign_str(dev, qdisc_dev(q));
+               __assign_str(dev, qdisc_dev(q)->name);
                __assign_str(kind, q->ops->id);
                __entry->parent = q->parent;
                __entry->handle = q->handle;
@@ -106,14 +106,14 @@ TRACE_EVENT(qdisc_destroy,
        TP_ARGS(q),
 
        TP_STRUCT__entry(
-               __string(       dev,            qdisc_dev(q)    )
-               __string(       kind,           q->ops->id      )
-               __field(        u32,            parent          )
-               __field(        u32,            handle          )
+               __string(       dev,            qdisc_dev(q)->name      )
+               __string(       kind,           q->ops->id              )
+               __field(        u32,            parent                  )
+               __field(        u32,            handle                  )
        ),
 
        TP_fast_assign(
-               __assign_str(dev, qdisc_dev(q));
+               __assign_str(dev, qdisc_dev(q)->name);
                __assign_str(kind, q->ops->id);
                __entry->parent = q->parent;
                __entry->handle = q->handle;
diff --git a/include/trace/events/timer_migration.h b/include/trace/events/timer_migration.h
new file mode 100644 (file)
index 0000000..79f19e7
--- /dev/null
@@ -0,0 +1,298 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM timer_migration
+
+#if !defined(_TRACE_TIMER_MIGRATION_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_TIMER_MIGRATION_H
+
+#include <linux/tracepoint.h>
+
+/* Group events */
+TRACE_EVENT(tmigr_group_set,
+
+       TP_PROTO(struct tmigr_group *group),
+
+       TP_ARGS(group),
+
+       TP_STRUCT__entry(
+               __field( void *,        group           )
+               __field( unsigned int,  lvl             )
+               __field( unsigned int,  numa_node       )
+       ),
+
+       TP_fast_assign(
+               __entry->group          = group;
+               __entry->lvl            = group->level;
+               __entry->numa_node      = group->numa_node;
+       ),
+
+       TP_printk("group=%p lvl=%d numa=%d",
+                 __entry->group, __entry->lvl, __entry->numa_node)
+);
+
+TRACE_EVENT(tmigr_connect_child_parent,
+
+       TP_PROTO(struct tmigr_group *child),
+
+       TP_ARGS(child),
+
+       TP_STRUCT__entry(
+               __field( void *,        child           )
+               __field( void *,        parent          )
+               __field( unsigned int,  lvl             )
+               __field( unsigned int,  numa_node       )
+               __field( unsigned int,  num_children    )
+               __field( u32,           childmask       )
+       ),
+
+       TP_fast_assign(
+               __entry->child          = child;
+               __entry->parent         = child->parent;
+               __entry->lvl            = child->parent->level;
+               __entry->numa_node      = child->parent->numa_node;
+               __entry->num_children   = child->parent->num_children;
+               __entry->childmask      = child->childmask;
+       ),
+
+       TP_printk("group=%p childmask=%0x parent=%p lvl=%d numa=%d num_children=%d",
+                 __entry->child,  __entry->childmask, __entry->parent,
+                 __entry->lvl, __entry->numa_node, __entry->num_children)
+);
+
+TRACE_EVENT(tmigr_connect_cpu_parent,
+
+       TP_PROTO(struct tmigr_cpu *tmc),
+
+       TP_ARGS(tmc),
+
+       TP_STRUCT__entry(
+               __field( void *,        parent          )
+               __field( unsigned int,  cpu             )
+               __field( unsigned int,  lvl             )
+               __field( unsigned int,  numa_node       )
+               __field( unsigned int,  num_children    )
+               __field( u32,           childmask       )
+       ),
+
+       TP_fast_assign(
+               __entry->parent         = tmc->tmgroup;
+               __entry->cpu            = tmc->cpuevt.cpu;
+               __entry->lvl            = tmc->tmgroup->level;
+               __entry->numa_node      = tmc->tmgroup->numa_node;
+               __entry->num_children   = tmc->tmgroup->num_children;
+               __entry->childmask      = tmc->childmask;
+       ),
+
+       TP_printk("cpu=%d childmask=%0x parent=%p lvl=%d numa=%d num_children=%d",
+                 __entry->cpu,  __entry->childmask, __entry->parent,
+                 __entry->lvl, __entry->numa_node, __entry->num_children)
+);
+
+DECLARE_EVENT_CLASS(tmigr_group_and_cpu,
+
+       TP_PROTO(struct tmigr_group *group, union tmigr_state state, u32 childmask),
+
+       TP_ARGS(group, state, childmask),
+
+       TP_STRUCT__entry(
+               __field( void *,        group           )
+               __field( void *,        parent          )
+               __field( unsigned int,  lvl             )
+               __field( unsigned int,  numa_node       )
+               __field( u32,           childmask       )
+               __field( u8,            active          )
+               __field( u8,            migrator        )
+       ),
+
+       TP_fast_assign(
+               __entry->group          = group;
+               __entry->parent         = group->parent;
+               __entry->lvl            = group->level;
+               __entry->numa_node      = group->numa_node;
+               __entry->childmask      = childmask;
+               __entry->active         = state.active;
+               __entry->migrator       = state.migrator;
+       ),
+
+       TP_printk("group=%p lvl=%d numa=%d active=%0x migrator=%0x "
+                 "parent=%p childmask=%0x",
+                 __entry->group, __entry->lvl, __entry->numa_node,
+                 __entry->active, __entry->migrator,
+                 __entry->parent, __entry->childmask)
+);
+
+DEFINE_EVENT(tmigr_group_and_cpu, tmigr_group_set_cpu_inactive,
+
+       TP_PROTO(struct tmigr_group *group, union tmigr_state state, u32 childmask),
+
+       TP_ARGS(group, state, childmask)
+);
+
+DEFINE_EVENT(tmigr_group_and_cpu, tmigr_group_set_cpu_active,
+
+       TP_PROTO(struct tmigr_group *group, union tmigr_state state, u32 childmask),
+
+       TP_ARGS(group, state, childmask)
+);
+
+/* CPU events*/
+DECLARE_EVENT_CLASS(tmigr_cpugroup,
+
+       TP_PROTO(struct tmigr_cpu *tmc),
+
+       TP_ARGS(tmc),
+
+       TP_STRUCT__entry(
+               __field( u64,           wakeup  )
+               __field( void *,        parent  )
+               __field( unsigned int,  cpu     )
+
+       ),
+
+       TP_fast_assign(
+               __entry->wakeup         = tmc->wakeup;
+               __entry->parent         = tmc->tmgroup;
+               __entry->cpu            = tmc->cpuevt.cpu;
+       ),
+
+       TP_printk("cpu=%d parent=%p wakeup=%llu", __entry->cpu, __entry->parent, __entry->wakeup)
+);
+
+DEFINE_EVENT(tmigr_cpugroup, tmigr_cpu_new_timer,
+
+       TP_PROTO(struct tmigr_cpu *tmc),
+
+       TP_ARGS(tmc)
+);
+
+DEFINE_EVENT(tmigr_cpugroup, tmigr_cpu_active,
+
+       TP_PROTO(struct tmigr_cpu *tmc),
+
+       TP_ARGS(tmc)
+);
+
+DEFINE_EVENT(tmigr_cpugroup, tmigr_cpu_online,
+
+       TP_PROTO(struct tmigr_cpu *tmc),
+
+       TP_ARGS(tmc)
+);
+
+DEFINE_EVENT(tmigr_cpugroup, tmigr_cpu_offline,
+
+       TP_PROTO(struct tmigr_cpu *tmc),
+
+       TP_ARGS(tmc)
+);
+
+DEFINE_EVENT(tmigr_cpugroup, tmigr_handle_remote_cpu,
+
+       TP_PROTO(struct tmigr_cpu *tmc),
+
+       TP_ARGS(tmc)
+);
+
+DECLARE_EVENT_CLASS(tmigr_idle,
+
+       TP_PROTO(struct tmigr_cpu *tmc, u64 nextevt),
+
+       TP_ARGS(tmc, nextevt),
+
+       TP_STRUCT__entry(
+               __field( u64,           nextevt)
+               __field( u64,           wakeup)
+               __field( void *,        parent)
+               __field( unsigned int,  cpu)
+       ),
+
+       TP_fast_assign(
+               __entry->nextevt        = nextevt;
+               __entry->wakeup         = tmc->wakeup;
+               __entry->parent         = tmc->tmgroup;
+               __entry->cpu            = tmc->cpuevt.cpu;
+       ),
+
+       TP_printk("cpu=%d parent=%p nextevt=%llu wakeup=%llu",
+                 __entry->cpu, __entry->parent, __entry->nextevt, __entry->wakeup)
+);
+
+DEFINE_EVENT(tmigr_idle, tmigr_cpu_idle,
+
+       TP_PROTO(struct tmigr_cpu *tmc, u64 nextevt),
+
+       TP_ARGS(tmc, nextevt)
+);
+
+DEFINE_EVENT(tmigr_idle, tmigr_cpu_new_timer_idle,
+
+       TP_PROTO(struct tmigr_cpu *tmc, u64 nextevt),
+
+       TP_ARGS(tmc, nextevt)
+);
+
+TRACE_EVENT(tmigr_update_events,
+
+       TP_PROTO(struct tmigr_group *child, struct tmigr_group *group,
+                union tmigr_state childstate,  union tmigr_state groupstate,
+                u64 nextevt),
+
+       TP_ARGS(child, group, childstate, groupstate, nextevt),
+
+       TP_STRUCT__entry(
+               __field( void *,        child                   )
+               __field( void *,        group                   )
+               __field( u64,           nextevt                 )
+               __field( u64,           group_next_expiry       )
+               __field( u64,           child_evt_expiry        )
+               __field( unsigned int,  group_lvl               )
+               __field( unsigned int,  child_evtcpu            )
+               __field( u8,            child_active            )
+               __field( u8,            group_active            )
+       ),
+
+       TP_fast_assign(
+               __entry->child                  = child;
+               __entry->group                  = group;
+               __entry->nextevt                = nextevt;
+               __entry->group_next_expiry      = group->next_expiry;
+               __entry->child_evt_expiry       = child ? child->groupevt.nextevt.expires : 0;
+               __entry->group_lvl              = group->level;
+               __entry->child_evtcpu           = child ? child->groupevt.cpu : 0;
+               __entry->child_active           = childstate.active;
+               __entry->group_active           = groupstate.active;
+       ),
+
+       TP_printk("child=%p group=%p group_lvl=%d child_active=%0x group_active=%0x "
+                 "nextevt=%llu next_expiry=%llu child_evt_expiry=%llu child_evtcpu=%d",
+                 __entry->child, __entry->group, __entry->group_lvl, __entry->child_active,
+                 __entry->group_active,
+                 __entry->nextevt, __entry->group_next_expiry, __entry->child_evt_expiry,
+                 __entry->child_evtcpu)
+);
+
+TRACE_EVENT(tmigr_handle_remote,
+
+       TP_PROTO(struct tmigr_group *group),
+
+       TP_ARGS(group),
+
+       TP_STRUCT__entry(
+               __field( void * ,       group   )
+               __field( unsigned int , lvl     )
+       ),
+
+       TP_fast_assign(
+               __entry->group          = group;
+               __entry->lvl            = group->level;
+       ),
+
+       TP_printk("group=%p lvl=%d",
+                  __entry->group, __entry->lvl)
+);
+
+#endif /*  _TRACE_TIMER_MIGRATION_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 0bade1592f34f21690eab41de48595d7aaa24fe4..77d7ff0d5b110da4a05a4a7730d01bbd2d7c581e 100644 (file)
@@ -54,6 +54,20 @@ extern "C" {
  */
 #define NOUVEAU_GETPARAM_EXEC_PUSH_MAX   17
 
+/*
+ * NOUVEAU_GETPARAM_VRAM_BAR_SIZE - query bar size
+ *
+ * Query the VRAM BAR size.
+ */
+#define NOUVEAU_GETPARAM_VRAM_BAR_SIZE 18
+
+/*
+ * NOUVEAU_GETPARAM_VRAM_USED
+ *
+ * Get remaining VRAM size.
+ */
+#define NOUVEAU_GETPARAM_VRAM_USED 19
+
 struct drm_nouveau_getparam {
        __u64 param;
        __u64 value;
index 9fa3ae324731a6a96d47d81e18566b321f2f0bca..bb0c8a9941164228fef069433194aa2e549a0174 100644 (file)
@@ -831,11 +831,6 @@ struct drm_xe_vm_destroy {
  *  - %DRM_XE_VM_BIND_OP_PREFETCH
  *
  * and the @flags can be:
- *  - %DRM_XE_VM_BIND_FLAG_READONLY
- *  - %DRM_XE_VM_BIND_FLAG_ASYNC
- *  - %DRM_XE_VM_BIND_FLAG_IMMEDIATE - Valid on a faulting VM only, do the
- *    MAP operation immediately rather than deferring the MAP to the page
- *    fault handler.
  *  - %DRM_XE_VM_BIND_FLAG_NULL - When the NULL flag is set, the page
  *    tables are setup with a special bit which indicates writes are
  *    dropped and all reads return zero. In the future, the NULL flags
@@ -928,9 +923,8 @@ struct drm_xe_vm_bind_op {
        /** @op: Bind operation to perform */
        __u32 op;
 
-#define DRM_XE_VM_BIND_FLAG_READONLY   (1 << 0)
-#define DRM_XE_VM_BIND_FLAG_IMMEDIATE  (1 << 1)
 #define DRM_XE_VM_BIND_FLAG_NULL       (1 << 2)
+#define DRM_XE_VM_BIND_FLAG_DUMPABLE   (1 << 3)
        /** @flags: Bind flags */
        __u32 flags;
 
@@ -1045,20 +1039,6 @@ struct drm_xe_exec_queue_create {
 #define DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY               0
 #define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY              0
 #define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE             1
-#define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_PREEMPTION_TIMEOUT    2
-#define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_PERSISTENCE           3
-#define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_JOB_TIMEOUT           4
-#define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_ACC_TRIGGER           5
-#define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_ACC_NOTIFY            6
-#define   DRM_XE_EXEC_QUEUE_SET_PROPERTY_ACC_GRANULARITY       7
-/* Monitor 128KB contiguous region with 4K sub-granularity */
-#define     DRM_XE_ACC_GRANULARITY_128K                                0
-/* Monitor 2MB contiguous region with 64KB sub-granularity */
-#define     DRM_XE_ACC_GRANULARITY_2M                          1
-/* Monitor 16MB contiguous region with 512KB sub-granularity */
-#define     DRM_XE_ACC_GRANULARITY_16M                         2
-/* Monitor 64MB contiguous region with 2M sub-granularity */
-#define     DRM_XE_ACC_GRANULARITY_64M                         3
 
        /** @extensions: Pointer to the first extension struct, if any */
        __u64 extensions;
index 48ad69f7722e1ae51ae5871a06482b6aa45dfc18..45e4e64fd6643ce3a83711cb295c711dd67ca511 100644 (file)
@@ -64,6 +64,24 @@ struct fstrim_range {
        __u64 minlen;
 };
 
+/*
+ * We include a length field because some filesystems (vfat) have an identifier
+ * that we do want to expose as a UUID, but doesn't have the standard length.
+ *
+ * We use a fixed size buffer beacuse this interface will, by fiat, never
+ * support "UUIDs" longer than 16 bytes; we don't want to force all downstream
+ * users to have to deal with that.
+ */
+struct fsuuid2 {
+       __u8    len;
+       __u8    uuid[16];
+};
+
+struct fs_sysfs_path {
+       __u8                    len;
+       __u8                    name[128];
+};
+
 /* extent-same (dedupe) ioctls; these MUST match the btrfs ioctl definitions */
 #define FILE_DEDUPE_RANGE_SAME         0
 #define FILE_DEDUPE_RANGE_DIFFERS      1
@@ -215,6 +233,13 @@ struct fsxattr {
 #define FS_IOC_FSSETXATTR              _IOW('X', 32, struct fsxattr)
 #define FS_IOC_GETFSLABEL              _IOR(0x94, 49, char[FSLABEL_MAX])
 #define FS_IOC_SETFSLABEL              _IOW(0x94, 50, char[FSLABEL_MAX])
+/* Returns the external filesystem UUID, the same one blkid returns */
+#define FS_IOC_GETFSUUID               _IOR(0x15, 0, struct fsuuid2)
+/*
+ * Returns the path component under /sys/fs/ that refers to this filesystem;
+ * also /sys/kernel/debug/ for filesystems with debugfs exports
+ */
+#define FS_IOC_GETFSSYSFSPATH          _IOR(0x15, 1, struct fs_sysfs_path)
 
 /*
  * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS)
@@ -301,9 +326,12 @@ typedef int __bitwise __kernel_rwf_t;
 /* per-IO O_APPEND */
 #define RWF_APPEND     ((__force __kernel_rwf_t)0x00000010)
 
+/* per-IO negation of O_APPEND */
+#define RWF_NOAPPEND   ((__force __kernel_rwf_t)0x00000020)
+
 /* mask of flags supported by the kernel */
 #define RWF_SUPPORTED  (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT |\
-                        RWF_APPEND)
+                        RWF_APPEND | RWF_NOAPPEND)
 
 /* Pagemap ioctl */
 #define PAGEMAP_SCAN   _IOWR('f', 16, struct pm_scan_arg)
index 5060963707b1ed44d9b640454e9b0656a505d761..f2e0b2d50e6b5ffadd52ced37e8a1e36999c9d97 100644 (file)
@@ -91,8 +91,6 @@ enum iio_modifier {
        IIO_MOD_CO2,
        IIO_MOD_VOC,
        IIO_MOD_LIGHT_UV,
-       IIO_MOD_LIGHT_UVA,
-       IIO_MOD_LIGHT_UVB,
        IIO_MOD_LIGHT_DUV,
        IIO_MOD_PM1,
        IIO_MOD_PM2P5,
@@ -107,6 +105,8 @@ enum iio_modifier {
        IIO_MOD_PITCH,
        IIO_MOD_YAW,
        IIO_MOD_ROLL,
+       IIO_MOD_LIGHT_UVA,
+       IIO_MOD_LIGHT_UVB,
 };
 
 enum iio_event_type {
index c4c53a9ab9595b2a5b95e5b22cafa5bd2cd6fd3c..ff8d21f9e95b7798eaf3e00635050e1631d6697a 100644 (file)
@@ -145,7 +145,7 @@ struct in6_flowlabel_req {
 #define IPV6_TLV_PADN          1
 #define IPV6_TLV_ROUTERALERT   5
 #define IPV6_TLV_CALIPSO       7       /* RFC 5570 */
-#define IPV6_TLV_IOAM          49      /* TEMPORARY IANA allocation for IOAM */
+#define IPV6_TLV_IOAM          49      /* RFC 9486 */
 #define IPV6_TLV_JUMBO         194
 #define IPV6_TLV_HAO           201     /* home address option */
 
index 7a673b52827b160afbd9d3b3bd64d3112dc7ce7c..7bd10201a02bc833a5f6334d45b03e50a17f0e1b 100644 (file)
@@ -255,6 +255,7 @@ enum io_uring_op {
        IORING_OP_FUTEX_WAKE,
        IORING_OP_FUTEX_WAITV,
        IORING_OP_FIXED_FD_INSTALL,
+       IORING_OP_FTRUNCATE,
 
        /* this goes last, obviously */
        IORING_OP_LAST,
@@ -570,6 +571,10 @@ enum {
        /* return status information for a buffer group */
        IORING_REGISTER_PBUF_STATUS             = 26,
 
+       /* set/clear busy poll settings */
+       IORING_REGISTER_NAPI                    = 27,
+       IORING_UNREGISTER_NAPI                  = 28,
+
        /* this goes last */
        IORING_REGISTER_LAST,
 
@@ -703,6 +708,14 @@ struct io_uring_buf_status {
        __u32   resv[8];
 };
 
+/* argument for IORING_(UN)REGISTER_NAPI */
+struct io_uring_napi {
+       __u32   busy_poll_to;
+       __u8    prefer_busy_poll;
+       __u8    pad[3];
+       __u64   resv;
+};
+
 /*
  * io_uring_restriction->opcode values
  */
index 6325d1d0e90f5dcdc7bdc91d612f8fc4c7b40135..1b40a968ba91fc9d2d0a8339261584a0d89ff9a9 100644 (file)
 #define DMA_BUF_MAGIC          0x444d4142      /* "DMAB" */
 #define DEVMEM_MAGIC           0x454d444d      /* "DMEM" */
 #define SECRETMEM_MAGIC                0x5345434d      /* "SECM" */
+#define PID_FS_MAGIC           0x50494446      /* "PIDF" */
 
 #endif /* __LINUX_MAGIC_H__ */
index 5406fbc1307489e2083a5c9136cf00c3844506ca..72ec000a97cda30dfeea1d04493f0ac7af7ed300 100644 (file)
@@ -7,6 +7,12 @@
 #include <linux/fcntl.h>
 
 /* Flags for pidfd_open().  */
-#define PIDFD_NONBLOCK O_NONBLOCK
+#define PIDFD_NONBLOCK O_NONBLOCK
+#define PIDFD_THREAD   O_EXCL
+
+/* Flags for pidfd_send_signal(). */
+#define PIDFD_SIGNAL_THREAD            (1UL << 0)
+#define PIDFD_SIGNAL_THREAD_GROUP      (1UL << 1)
+#define PIDFD_SIGNAL_PROCESS_GROUP     (1UL << 2)
 
 #endif /* _UAPI_LINUX_PIDFD_H */
index b44ba7dcdefcadc62444e97721ea7ef00ade6a74..b7a2c2ee35b7e8099178cc410f9756b2b5f3ce44 100644 (file)
@@ -28,6 +28,9 @@ enum {
        SEV_PEK_CERT_IMPORT,
        SEV_GET_ID,     /* This command is deprecated, use SEV_GET_ID2 */
        SEV_GET_ID2,
+       SNP_PLATFORM_STATUS,
+       SNP_COMMIT,
+       SNP_SET_CONFIG,
 
        SEV_MAX,
 };
@@ -69,6 +72,12 @@ typedef enum {
        SEV_RET_RESOURCE_LIMIT,
        SEV_RET_SECURE_DATA_INVALID,
        SEV_RET_INVALID_KEY = 0x27,
+       SEV_RET_INVALID_PAGE_SIZE,
+       SEV_RET_INVALID_PAGE_STATE,
+       SEV_RET_INVALID_MDATA_ENTRY,
+       SEV_RET_INVALID_PAGE_OWNER,
+       SEV_RET_INVALID_PAGE_AEAD_OFLOW,
+       SEV_RET_RMP_INIT_REQUIRED,
        SEV_RET_MAX,
 } sev_ret_code;
 
@@ -155,6 +164,56 @@ struct sev_user_data_get_id2 {
        __u32 length;                           /* In/Out */
 } __packed;
 
+/**
+ * struct sev_user_data_snp_status - SNP status
+ *
+ * @api_major: API major version
+ * @api_minor: API minor version
+ * @state: current platform state
+ * @is_rmp_initialized: whether RMP is initialized or not
+ * @rsvd: reserved
+ * @build_id: firmware build id for the API version
+ * @mask_chip_id: whether chip id is present in attestation reports or not
+ * @mask_chip_key: whether attestation reports are signed or not
+ * @vlek_en: VLEK (Version Loaded Endorsement Key) hashstick is loaded
+ * @rsvd1: reserved
+ * @guest_count: the number of guest currently managed by the firmware
+ * @current_tcb_version: current TCB version
+ * @reported_tcb_version: reported TCB version
+ */
+struct sev_user_data_snp_status {
+       __u8 api_major;                 /* Out */
+       __u8 api_minor;                 /* Out */
+       __u8 state;                     /* Out */
+       __u8 is_rmp_initialized:1;      /* Out */
+       __u8 rsvd:7;
+       __u32 build_id;                 /* Out */
+       __u32 mask_chip_id:1;           /* Out */
+       __u32 mask_chip_key:1;          /* Out */
+       __u32 vlek_en:1;                /* Out */
+       __u32 rsvd1:29;
+       __u32 guest_count;              /* Out */
+       __u64 current_tcb_version;      /* Out */
+       __u64 reported_tcb_version;     /* Out */
+} __packed;
+
+/**
+ * struct sev_user_data_snp_config - system wide configuration value for SNP.
+ *
+ * @reported_tcb: the TCB version to report in the guest attestation report.
+ * @mask_chip_id: whether chip id is present in attestation reports or not
+ * @mask_chip_key: whether attestation reports are signed or not
+ * @rsvd: reserved
+ * @rsvd1: reserved
+ */
+struct sev_user_data_snp_config {
+       __u64 reported_tcb  ;   /* In */
+       __u32 mask_chip_id:1;   /* In */
+       __u32 mask_chip_key:1;  /* In */
+       __u32 rsvd:30;          /* In */
+       __u8 rsvd1[52];
+} __packed;
+
 /**
  * struct sev_issue_cmd - SEV ioctl parameters
  *
index b9cfc5c962682364e6dda544322ec07aa4a1ff83..c8dc5f8ea699627402dc2069615acd066f103981 100644 (file)
@@ -49,6 +49,8 @@
        _IOR('u', UBLK_CMD_GET_DEV_INFO2, struct ublksrv_ctrl_cmd)
 #define UBLK_U_CMD_GET_FEATURES        \
        _IOR('u', 0x13, struct ublksrv_ctrl_cmd)
+#define UBLK_U_CMD_DEL_DEV_ASYNC       \
+       _IOR('u', 0x14, struct ublksrv_ctrl_cmd)
 
 /*
  * 64bits are enough now, and it should be easy to extend in case of
index d5b9cfbd9ceac69323d0fe487cc49ab388a2e523..628d46a0da92eb0393dd592a38e987d08dcf6db0 100644 (file)
@@ -142,7 +142,7 @@ struct snd_hwdep_dsp_image {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 16)
+#define SNDRV_PCM_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 17)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -416,7 +416,7 @@ struct snd_pcm_hw_params {
        unsigned int rmask;             /* W: requested masks */
        unsigned int cmask;             /* R: changed masks */
        unsigned int info;              /* R: Info flags for returned setup */
-       unsigned int msbits;            /* R: used most significant bits */
+       unsigned int msbits;            /* R: used most significant bits (in sample bit-width) */
        unsigned int rate_num;          /* R: rate numerator */
        unsigned int rate_den;          /* R: rate denominator */
        snd_pcm_uframes_t fifo_size;    /* R: chip FIFO size in frames */
index 48d2790ef928c798279babb69fbd07f7d6dcc20d..3109282672f33cecc00cd3f08e9dfd22e7991637 100644 (file)
@@ -31,7 +31,10 @@ struct ioctl_gntalloc_alloc_gref {
        __u64 index;
        /* The grant references of the newly created grant, one per page */
        /* Variable size, depending on count */
-       __u32 gref_ids[1];
+       union {
+               __u32 gref_ids[1];
+               __DECLARE_FLEX_ARRAY(__u32, gref_ids_flex);
+       };
 };
 
 #define GNTALLOC_FLAG_WRITABLE 1
index 73eb622e7663d9ba11960aff92baecdd88536721..5d5c0b8efff2d44be1c29c66a9c914ed03d5b95f 100644 (file)
 #include <vdso/time32.h>
 #include <vdso/time64.h>
 
+#ifdef CONFIG_ARM64
+#include <asm/page-def.h>
+#else
+#include <asm/page.h>
+#endif
+
 #ifdef CONFIG_ARCH_HAS_VDSO_DATA
 #include <asm/vdso/data.h>
 #else
@@ -121,6 +127,14 @@ struct vdso_data {
 extern struct vdso_data _vdso_data[CS_BASES] __attribute__((visibility("hidden")));
 extern struct vdso_data _timens_data[CS_BASES] __attribute__((visibility("hidden")));
 
+/**
+ * union vdso_data_store - Generic vDSO data page
+ */
+union vdso_data_store {
+       struct vdso_data        data[CS_BASES];
+       u8                      page[PAGE_SIZE];
+};
+
 /*
  * The generic vDSO implementation requires that gettimeofday.h
  * provides:
index 9a2af9fca45e21a1d87947e8ba0f221225dc2cb6..73501149439ddcf9735d5b1cccb90abefbf3e321 100644 (file)
@@ -30,9 +30,9 @@ static __always_inline u32 vdso_read_retry(const struct vdso_data *vd,
 static __always_inline void vdso_write_begin(struct vdso_data *vd)
 {
        /*
-        * WRITE_ONCE it is required otherwise the compiler can validly tear
+        * WRITE_ONCE() is required otherwise the compiler can validly tear
         * updates to vd[x].seq and it is possible that the value seen by the
-        * reader it is inconsistent.
+        * reader is inconsistent.
         */
        WRITE_ONCE(vd[CS_HRES_COARSE].seq, vd[CS_HRES_COARSE].seq + 1);
        WRITE_ONCE(vd[CS_RAW].seq, vd[CS_RAW].seq + 1);
@@ -43,9 +43,9 @@ static __always_inline void vdso_write_end(struct vdso_data *vd)
 {
        smp_wmb();
        /*
-        * WRITE_ONCE it is required otherwise the compiler can validly tear
+        * WRITE_ONCE() is required otherwise the compiler can validly tear
         * updates to vd[x].seq and it is possible that the value seen by the
-        * reader it is inconsistent.
+        * reader is inconsistent.
         */
        WRITE_ONCE(vd[CS_HRES_COARSE].seq, vd[CS_HRES_COARSE].seq + 1);
        WRITE_ONCE(vd[CS_RAW].seq, vd[CS_RAW].seq + 1);
index deda3d14135bb9ed54469353e44f1c1e86e8a0f2..7c5df7b0b5760c8d2235a688ffe8d98ad3ebf340 100644 (file)
@@ -89,6 +89,15 @@ config CC_HAS_ASM_GOTO_TIED_OUTPUT
        # Detect buggy gcc and clang, fixed in gcc-11 clang-14.
        def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null)
 
+config GCC_ASM_GOTO_OUTPUT_WORKAROUND
+       bool
+       depends on CC_IS_GCC && CC_HAS_ASM_GOTO_OUTPUT
+       # Fixed in GCC 14, 13.3, 12.4 and 11.5
+       # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921
+       default y if GCC_VERSION < 110500
+       default y if GCC_VERSION >= 120000 && GCC_VERSION < 120400
+       default y if GCC_VERSION >= 130000 && GCC_VERSION < 130300
+
 config TOOLS_SUPPORT_RELR
        def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh)
 
@@ -106,7 +115,7 @@ config CONSTRUCTORS
        bool
 
 config IRQ_WORK
-       bool
+       def_bool y if SMP
 
 config BUILDTIME_TABLE_SORT
        bool
@@ -867,14 +876,14 @@ config CC_IMPLICIT_FALLTHROUGH
        default "-Wimplicit-fallthrough=5" if CC_IS_GCC && $(cc-option,-Wimplicit-fallthrough=5)
        default "-Wimplicit-fallthrough" if CC_IS_CLANG && $(cc-option,-Wunreachable-code-fallthrough)
 
-# Currently, disable gcc-11+ array-bounds globally.
+# Currently, disable gcc-10+ array-bounds globally.
 # It's still broken in gcc-13, so no upper bound yet.
-config GCC11_NO_ARRAY_BOUNDS
+config GCC10_NO_ARRAY_BOUNDS
        def_bool y
 
 config CC_NO_ARRAY_BOUNDS
        bool
-       default y if CC_IS_GCC && GCC_VERSION >= 110000 && GCC11_NO_ARRAY_BOUNDS
+       default y if CC_IS_GCC && GCC_VERSION >= 100000 && GCC10_NO_ARRAY_BOUNDS
 
 # Currently, disable -Wstringop-overflow for GCC globally.
 config GCC_NO_STRINGOP_OVERFLOW
index 279ad28bf4fb148e37cbd9600842a567c813039c..3c5fd993bc7e3e955f322e506bdad8aea8e0edbb 100644 (file)
@@ -208,6 +208,9 @@ retry:
                                goto out;
                        case -EACCES:
                        case -EINVAL:
+#ifdef CONFIG_BLOCK
+                               init_flush_fput();
+#endif
                                continue;
                }
                /*
index 15e372b00ce704bc1b1e5db6514db3a4dcd654a4..6069ea3eb80d70106d6a8d8b3515d50176353206 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/major.h>
 #include <linux/root_dev.h>
 #include <linux/init_syscalls.h>
+#include <linux/task_work.h>
+#include <linux/file.h>
 
 void  mount_root_generic(char *name, char *pretty_name, int flags);
 void  mount_root(char *root_device_name);
@@ -41,3 +43,10 @@ static inline bool initrd_load(char *root_device_name)
        }
 
 #endif
+
+/* Ensure that async file closing finished to prevent spurious errors. */
+static inline void init_flush_fput(void)
+{
+       flush_delayed_fput();
+       task_work_run();
+}
index 7ecb458eb3da60eb73123f4b2072910f194c4bb5..4daee6d761c86c11bcfe76b04a137d7f0ea38ec9 100644 (file)
@@ -147,6 +147,7 @@ struct task_struct init_task __aligned(L1_CACHE_BYTES) = {
        .rcu_tasks_holdout = false,
        .rcu_tasks_holdout_list = LIST_HEAD_INIT(init_task.rcu_tasks_holdout_list),
        .rcu_tasks_idle_cpu = -1,
+       .rcu_tasks_exit_list = LIST_HEAD_INIT(init_task.rcu_tasks_exit_list),
 #endif
 #ifdef CONFIG_TASKS_TRACE_RCU
        .trc_reader_nesting = 0,
index 76deb48c38cb16dd779de7ee91b35785b6890579..01dbd0e8150180c2dd50d449adf7ad5d3ac0c8d0 100644 (file)
 #include <linux/mm.h>
 #include <linux/namei.h>
 #include <linux/init_syscalls.h>
-#include <linux/task_work.h>
 #include <linux/umh.h>
 
+#include "do_mounts.h"
+
 static __initdata bool csum_present;
 static __initdata u32 io_csum;
 
@@ -679,8 +680,6 @@ static void __init populate_initrd_image(char *err)
        struct file *file;
        loff_t pos = 0;
 
-       unpack_to_rootfs(__initramfs_start, __initramfs_size);
-
        printk(KERN_INFO "rootfs image is not initramfs (%s); looks like an initrd\n",
                        err);
        file = filp_open("/initrd.image", O_WRONLY | O_CREAT, 0700);
@@ -736,8 +735,7 @@ done:
        initrd_start = 0;
        initrd_end = 0;
 
-       flush_delayed_fput();
-       task_work_run();
+       init_flush_fput();
 }
 
 static ASYNC_DOMAIN_EXCLUSIVE(initramfs_domain);
index e24b0780fdff7a807bd027ab26e61fc303c624ef..7dce08198b13352357a1262138c71460da1cb584 100644 (file)
@@ -99,6 +99,7 @@
 #include <linux/init_syscalls.h>
 #include <linux/stackdepot.h>
 #include <linux/randomize_kstack.h>
+#include <linux/pidfs.h>
 #include <net/net_namespace.h>
 
 #include <asm/io.h>
@@ -603,7 +604,6 @@ static int __init rdinit_setup(char *str)
 __setup("rdinit=", rdinit_setup);
 
 #ifndef CONFIG_SMP
-static const unsigned int setup_max_cpus = NR_CPUS;
 static inline void setup_nr_cpu_ids(void) { }
 static inline void smp_prepare_cpus(unsigned int maxcpus) { }
 #endif
@@ -776,6 +776,10 @@ void __init __weak smp_setup_processor_id(void)
 {
 }
 
+void __init __weak smp_prepare_boot_cpu(void)
+{
+}
+
 # if THREAD_SIZE >= PAGE_SIZE
 void __init __weak thread_stack_cache_init(void)
 {
@@ -1059,6 +1063,7 @@ void start_kernel(void)
        seq_file_init();
        proc_root_init();
        nsfs_init();
+       pidfs_init();
        cpuset_init();
        cgroup_init();
        taskstats_init_early();
@@ -1545,6 +1550,7 @@ static noinline void __init kernel_init_freeable(void)
        sched_init_smp();
 
        workqueue_init_topology();
+       async_init();
        padata_init();
        page_alloc_init_late();
 
index 2cdc51825405371a05e4357b0956799c6672431f..2e1d4e03799c34f4e56fa2cc5397eaeb69756498 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_IO_URING)          += io_uring.o xattr.o nop.o fs.o splice.o \
                                        statx.o net.o msg_ring.o timeout.o \
                                        sqpoll.o fdinfo.o tctx.o poll.o \
                                        cancel.o kbuf.o rsrc.o rw.o opdef.o \
-                                       notif.o waitid.o register.o
+                                       notif.o waitid.o register.o truncate.o
 obj-$(CONFIG_IO_WQ)            += io-wq.o
 obj-$(CONFIG_FUTEX)            += futex.o
+obj-$(CONFIG_NET_RX_BUSY_POLL) += napi.o
index 8a8b07dfc444cde6181e2e5f86b6aa799ab5980b..acfcdd7f059afd871e3dba0b591e26620f3db64b 100644 (file)
@@ -58,9 +58,8 @@ bool io_cancel_req_match(struct io_kiocb *req, struct io_cancel_data *cd)
                return false;
        if (cd->flags & IORING_ASYNC_CANCEL_ALL) {
 check_seq:
-               if (cd->seq == req->work.cancel_seq)
+               if (io_cancel_match_sequence(req, cd->seq))
                        return false;
-               req->work.cancel_seq = cd->seq;
        }
 
        return true;
index c0a8e7c520b6d65479b2874d1ec536f21450342a..76b32e65c03cd72452e37293bfcdc5b604e10267 100644 (file)
@@ -25,4 +25,14 @@ void init_hash_table(struct io_hash_table *table, unsigned size);
 int io_sync_cancel(struct io_ring_ctx *ctx, void __user *arg);
 bool io_cancel_req_match(struct io_kiocb *req, struct io_cancel_data *cd);
 
+static inline bool io_cancel_match_sequence(struct io_kiocb *req, int sequence)
+{
+       if ((req->flags & REQ_F_CANCEL_SEQ) && sequence == req->work.cancel_seq)
+               return true;
+
+       req->flags |= REQ_F_CANCEL_SEQ;
+       req->work.cancel_seq = sequence;
+       return false;
+}
+
 #endif
index 976e9500f6518cbc121d212af5e80334ef3e2ace..8d444dd1b0a7b63c786198349648be8ad21c77f5 100644 (file)
@@ -55,6 +55,7 @@ __cold void io_uring_show_fdinfo(struct seq_file *m, struct file *f)
        struct io_ring_ctx *ctx = f->private_data;
        struct io_overflow_cqe *ocqe;
        struct io_rings *r = ctx->rings;
+       struct rusage sq_usage;
        unsigned int sq_mask = ctx->sq_entries - 1, cq_mask = ctx->cq_entries - 1;
        unsigned int sq_head = READ_ONCE(r->sq.head);
        unsigned int sq_tail = READ_ONCE(r->sq.tail);
@@ -64,6 +65,7 @@ __cold void io_uring_show_fdinfo(struct seq_file *m, struct file *f)
        unsigned int sq_shift = 0;
        unsigned int sq_entries, cq_entries;
        int sq_pid = -1, sq_cpu = -1;
+       u64 sq_total_time = 0, sq_work_time = 0;
        bool has_lock;
        unsigned int i;
 
@@ -145,12 +147,24 @@ __cold void io_uring_show_fdinfo(struct seq_file *m, struct file *f)
        if (has_lock && (ctx->flags & IORING_SETUP_SQPOLL)) {
                struct io_sq_data *sq = ctx->sq_data;
 
-               sq_pid = sq->task_pid;
-               sq_cpu = sq->sq_cpu;
+               /*
+                * sq->thread might be NULL if we raced with the sqpoll
+                * thread termination.
+                */
+               if (sq->thread) {
+                       sq_pid = sq->task_pid;
+                       sq_cpu = sq->sq_cpu;
+                       getrusage(sq->thread, RUSAGE_SELF, &sq_usage);
+                       sq_total_time = (sq_usage.ru_stime.tv_sec * 1000000
+                                        + sq_usage.ru_stime.tv_usec);
+                       sq_work_time = sq->work_time;
+               }
        }
 
        seq_printf(m, "SqThread:\t%d\n", sq_pid);
        seq_printf(m, "SqThreadCpu:\t%d\n", sq_cpu);
+       seq_printf(m, "SqTotalTime:\t%llu\n", sq_total_time);
+       seq_printf(m, "SqWorkTime:\t%llu\n", sq_work_time);
        seq_printf(m, "UserFiles:\t%u\n", ctx->nr_user_files);
        for (i = 0; has_lock && i < ctx->nr_user_files; i++) {
                struct file *f = io_file_from_index(&ctx->file_table, i);
index b47adf170c314daaf4c09b2b8ab1876079ccbf60..b2435c4dca1f9fd24ddadf3396edbf0d146eea96 100644 (file)
@@ -17,7 +17,7 @@ int io_fixed_fd_remove(struct io_ring_ctx *ctx, unsigned int offset);
 int io_register_file_alloc_range(struct io_ring_ctx *ctx,
                                 struct io_uring_file_index_range __user *arg);
 
-unsigned int io_file_get_flags(struct file *file);
+io_req_flags_t io_file_get_flags(struct file *file);
 
 static inline void io_file_bitmap_clear(struct io_file_table *table, int bit)
 {
index cd9a137ad6cefbb907a177fd8f0c9753ac0c70dd..cf348c33f4855e519d1d28ef29cff8f106db5ff3 100644 (file)
@@ -59,7 +59,6 @@
 #include <linux/bvec.h>
 #include <linux/net.h>
 #include <net/sock.h>
-#include <net/af_unix.h>
 #include <linux/anon_inodes.h>
 #include <linux/sched/mm.h>
 #include <linux/uaccess.h>
@@ -95,6 +94,7 @@
 #include "notif.h"
 #include "waitid.h"
 #include "futex.h"
+#include "napi.h"
 
 #include "timeout.h"
 #include "poll.h"
 #define IO_COMPL_BATCH                 32
 #define IO_REQ_ALLOC_BATCH             8
 
-enum {
-       IO_CHECK_CQ_OVERFLOW_BIT,
-       IO_CHECK_CQ_DROPPED_BIT,
-};
-
 struct io_defer_entry {
        struct list_head        list;
        struct io_kiocb         *req;
@@ -349,6 +344,8 @@ static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
        INIT_DELAYED_WORK(&ctx->fallback_work, io_fallback_req_func);
        INIT_WQ_LIST(&ctx->submit_state.compl_reqs);
        INIT_HLIST_HEAD(&ctx->cancelable_uring_cmd);
+       io_napi_init(ctx);
+
        return ctx;
 err:
        kfree(ctx->cancel_table.hbs);
@@ -463,7 +460,6 @@ static void io_prep_async_work(struct io_kiocb *req)
 
        req->work.list.next = NULL;
        req->work.flags = 0;
-       req->work.cancel_seq = atomic_read(&ctx->cancel_seq);
        if (req->flags & REQ_F_FORCE_ASYNC)
                req->work.flags |= IO_WQ_WORK_CONCURRENT;
 
@@ -670,7 +666,6 @@ static void io_cq_unlock_post(struct io_ring_ctx *ctx)
        io_commit_cqring_flush(ctx);
 }
 
-/* Returns true if there are no backlogged entries after the flush */
 static void io_cqring_overflow_kill(struct io_ring_ctx *ctx)
 {
        struct io_overflow_cqe *ocqe;
@@ -949,6 +944,8 @@ bool io_fill_cqe_req_aux(struct io_kiocb *req, bool defer, s32 res, u32 cflags)
        u64 user_data = req->cqe.user_data;
        struct io_uring_cqe *cqe;
 
+       lockdep_assert(!io_wq_current_is_worker());
+
        if (!defer)
                return __io_post_aux_cqe(ctx, user_data, res, cflags, false);
 
@@ -1025,15 +1022,15 @@ static void __io_req_complete_post(struct io_kiocb *req, unsigned issue_flags)
 
 void io_req_complete_post(struct io_kiocb *req, unsigned issue_flags)
 {
-       if (req->ctx->task_complete && req->ctx->submitter_task != current) {
+       struct io_ring_ctx *ctx = req->ctx;
+
+       if (ctx->task_complete && ctx->submitter_task != current) {
                req->io_task_work.func = io_req_task_complete;
                io_req_task_work_add(req);
        } else if (!(issue_flags & IO_URING_F_UNLOCKED) ||
-                  !(req->ctx->flags & IORING_SETUP_IOPOLL)) {
+                  !(ctx->flags & IORING_SETUP_IOPOLL)) {
                __io_req_complete_post(req, issue_flags);
        } else {
-               struct io_ring_ctx *ctx = req->ctx;
-
                mutex_lock(&ctx->uring_lock);
                __io_req_complete_post(req, issue_flags & ~IO_URING_F_UNLOCKED);
                mutex_unlock(&ctx->uring_lock);
@@ -1174,40 +1171,44 @@ static void ctx_flush_and_put(struct io_ring_ctx *ctx, struct io_tw_state *ts)
        percpu_ref_put(&ctx->refs);
 }
 
-static unsigned int handle_tw_list(struct llist_node *node,
-                                  struct io_ring_ctx **ctx,
-                                  struct io_tw_state *ts,
-                                  struct llist_node *last)
+/*
+ * Run queued task_work, returning the number of entries processed in *count.
+ * If more entries than max_entries are available, stop processing once this
+ * is reached and return the rest of the list.
+ */
+struct llist_node *io_handle_tw_list(struct llist_node *node,
+                                    unsigned int *count,
+                                    unsigned int max_entries)
 {
-       unsigned int count = 0;
+       struct io_ring_ctx *ctx = NULL;
+       struct io_tw_state ts = { };
 
-       while (node && node != last) {
+       do {
                struct llist_node *next = node->next;
                struct io_kiocb *req = container_of(node, struct io_kiocb,
                                                    io_task_work.node);
 
-               prefetch(container_of(next, struct io_kiocb, io_task_work.node));
-
-               if (req->ctx != *ctx) {
-                       ctx_flush_and_put(*ctx, ts);
-                       *ctx = req->ctx;
+               if (req->ctx != ctx) {
+                       ctx_flush_and_put(ctx, &ts);
+                       ctx = req->ctx;
                        /* if not contended, grab and improve batching */
-                       ts->locked = mutex_trylock(&(*ctx)->uring_lock);
-                       percpu_ref_get(&(*ctx)->refs);
+                       ts.locked = mutex_trylock(&ctx->uring_lock);
+                       percpu_ref_get(&ctx->refs);
                }
                INDIRECT_CALL_2(req->io_task_work.func,
                                io_poll_task_func, io_req_rw_complete,
-                               req, ts);
+                               req, &ts);
                node = next;
-               count++;
+               (*count)++;
                if (unlikely(need_resched())) {
-                       ctx_flush_and_put(*ctx, ts);
-                       *ctx = NULL;
+                       ctx_flush_and_put(ctx, &ts);
+                       ctx = NULL;
                        cond_resched();
                }
-       }
+       } while (node && *count < max_entries);
 
-       return count;
+       ctx_flush_and_put(ctx, &ts);
+       return node;
 }
 
 /**
@@ -1224,22 +1225,6 @@ static inline struct llist_node *io_llist_xchg(struct llist_head *head,
        return xchg(&head->first, new);
 }
 
-/**
- * io_llist_cmpxchg - possibly swap all entries in a lock-less list
- * @head:      the head of lock-less list to delete all entries
- * @old:       expected old value of the first entry of the list
- * @new:       new entry as the head of the list
- *
- * perform a cmpxchg on the first entry of the list.
- */
-
-static inline struct llist_node *io_llist_cmpxchg(struct llist_head *head,
-                                                 struct llist_node *old,
-                                                 struct llist_node *new)
-{
-       return cmpxchg(&head->first, old, new);
-}
-
 static __cold void io_fallback_tw(struct io_uring_task *tctx, bool sync)
 {
        struct llist_node *node = llist_del_all(&tctx->task_list);
@@ -1268,45 +1253,41 @@ static __cold void io_fallback_tw(struct io_uring_task *tctx, bool sync)
        }
 }
 
-void tctx_task_work(struct callback_head *cb)
+struct llist_node *tctx_task_work_run(struct io_uring_task *tctx,
+                                     unsigned int max_entries,
+                                     unsigned int *count)
 {
-       struct io_tw_state ts = {};
-       struct io_ring_ctx *ctx = NULL;
-       struct io_uring_task *tctx = container_of(cb, struct io_uring_task,
-                                                 task_work);
-       struct llist_node fake = {};
        struct llist_node *node;
-       unsigned int loops = 0;
-       unsigned int count = 0;
 
        if (unlikely(current->flags & PF_EXITING)) {
                io_fallback_tw(tctx, true);
-               return;
+               return NULL;
        }
 
-       do {
-               loops++;
-               node = io_llist_xchg(&tctx->task_list, &fake);
-               count += handle_tw_list(node, &ctx, &ts, &fake);
-
-               /* skip expensive cmpxchg if there are items in the list */
-               if (READ_ONCE(tctx->task_list.first) != &fake)
-                       continue;
-               if (ts.locked && !wq_list_empty(&ctx->submit_state.compl_reqs)) {
-                       io_submit_flush_completions(ctx);
-                       if (READ_ONCE(tctx->task_list.first) != &fake)
-                               continue;
-               }
-               node = io_llist_cmpxchg(&tctx->task_list, &fake, NULL);
-       } while (node != &fake);
-
-       ctx_flush_and_put(ctx, &ts);
+       node = llist_del_all(&tctx->task_list);
+       if (node) {
+               node = llist_reverse_order(node);
+               node = io_handle_tw_list(node, count, max_entries);
+       }
 
        /* relaxed read is enough as only the task itself sets ->in_cancel */
        if (unlikely(atomic_read(&tctx->in_cancel)))
                io_uring_drop_tctx_refs(current);
 
-       trace_io_uring_task_work_run(tctx, count, loops);
+       trace_io_uring_task_work_run(tctx, *count);
+       return node;
+}
+
+void tctx_task_work(struct callback_head *cb)
+{
+       struct io_uring_task *tctx;
+       struct llist_node *ret;
+       unsigned int count = 0;
+
+       tctx = container_of(cb, struct io_uring_task, task_work);
+       ret = tctx_task_work_run(tctx, UINT_MAX, &count);
+       /* can't happen */
+       WARN_ON_ONCE(ret);
 }
 
 static inline void io_req_local_work_add(struct io_kiocb *req, unsigned flags)
@@ -1389,6 +1370,15 @@ static void io_req_normal_work_add(struct io_kiocb *req)
        if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
                atomic_or(IORING_SQ_TASKRUN, &ctx->rings->sq_flags);
 
+       /* SQPOLL doesn't need the task_work added, it'll run it itself */
+       if (ctx->flags & IORING_SETUP_SQPOLL) {
+               struct io_sq_data *sqd = ctx->sq_data;
+
+               if (wq_has_sleeper(&sqd->wait))
+                       wake_up(&sqd->wait);
+               return;
+       }
+
        if (likely(!task_work_add(req->task, &tctx->task_work, ctx->notify_method)))
                return;
 
@@ -1420,7 +1410,20 @@ static void __cold io_move_task_work_from_local(struct io_ring_ctx *ctx)
        }
 }
 
-static int __io_run_local_work(struct io_ring_ctx *ctx, struct io_tw_state *ts)
+static bool io_run_local_work_continue(struct io_ring_ctx *ctx, int events,
+                                      int min_events)
+{
+       if (llist_empty(&ctx->work_llist))
+               return false;
+       if (events < min_events)
+               return true;
+       if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
+               atomic_or(IORING_SQ_TASKRUN, &ctx->rings->sq_flags);
+       return false;
+}
+
+static int __io_run_local_work(struct io_ring_ctx *ctx, struct io_tw_state *ts,
+                              int min_events)
 {
        struct llist_node *node;
        unsigned int loops = 0;
@@ -1440,7 +1443,6 @@ again:
                struct llist_node *next = node->next;
                struct io_kiocb *req = container_of(node, struct io_kiocb,
                                                    io_task_work.node);
-               prefetch(container_of(next, struct io_kiocb, io_task_work.node));
                INDIRECT_CALL_2(req->io_task_work.func,
                                io_poll_task_func, io_req_rw_complete,
                                req, ts);
@@ -1449,18 +1451,20 @@ again:
        }
        loops++;
 
-       if (!llist_empty(&ctx->work_llist))
+       if (io_run_local_work_continue(ctx, ret, min_events))
                goto again;
        if (ts->locked) {
                io_submit_flush_completions(ctx);
-               if (!llist_empty(&ctx->work_llist))
+               if (io_run_local_work_continue(ctx, ret, min_events))
                        goto again;
        }
+
        trace_io_uring_local_work_run(ctx, ret, loops);
        return ret;
 }
 
-static inline int io_run_local_work_locked(struct io_ring_ctx *ctx)
+static inline int io_run_local_work_locked(struct io_ring_ctx *ctx,
+                                          int min_events)
 {
        struct io_tw_state ts = { .locked = true, };
        int ret;
@@ -1468,20 +1472,20 @@ static inline int io_run_local_work_locked(struct io_ring_ctx *ctx)
        if (llist_empty(&ctx->work_llist))
                return 0;
 
-       ret = __io_run_local_work(ctx, &ts);
+       ret = __io_run_local_work(ctx, &ts, min_events);
        /* shouldn't happen! */
        if (WARN_ON_ONCE(!ts.locked))
                mutex_lock(&ctx->uring_lock);
        return ret;
 }
 
-static int io_run_local_work(struct io_ring_ctx *ctx)
+static int io_run_local_work(struct io_ring_ctx *ctx, int min_events)
 {
        struct io_tw_state ts = {};
        int ret;
 
        ts.locked = mutex_trylock(&ctx->uring_lock);
-       ret = __io_run_local_work(ctx, &ts);
+       ret = __io_run_local_work(ctx, &ts, min_events);
        if (ts.locked)
                mutex_unlock(&ctx->uring_lock);
 
@@ -1677,7 +1681,7 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, long min)
                    io_task_work_pending(ctx)) {
                        u32 tail = ctx->cached_cq_tail;
 
-                       (void) io_run_local_work_locked(ctx);
+                       (void) io_run_local_work_locked(ctx, min);
 
                        if (task_work_pending(current) ||
                            wq_list_empty(&ctx->iopoll_list)) {
@@ -1768,9 +1772,9 @@ static void io_iopoll_req_issued(struct io_kiocb *req, unsigned int issue_flags)
        }
 }
 
-unsigned int io_file_get_flags(struct file *file)
+io_req_flags_t io_file_get_flags(struct file *file)
 {
-       unsigned int res = 0;
+       io_req_flags_t res = 0;
 
        if (S_ISREG(file_inode(file)->i_mode))
                res |= REQ_F_ISREG;
@@ -1966,10 +1970,28 @@ fail:
                goto fail;
        }
 
+       /*
+        * If DEFER_TASKRUN is set, it's only allowed to post CQEs from the
+        * submitter task context. Final request completions are handed to the
+        * right context, however this is not the case of auxiliary CQEs,
+        * which is the main mean of operation for multishot requests.
+        * Don't allow any multishot execution from io-wq. It's more restrictive
+        * than necessary and also cleaner.
+        */
+       if (req->flags & REQ_F_APOLL_MULTISHOT) {
+               err = -EBADFD;
+               if (!io_file_can_poll(req))
+                       goto fail;
+               err = -ECANCELED;
+               if (io_arm_poll_handler(req, issue_flags) != IO_APOLL_OK)
+                       goto fail;
+               return;
+       }
+
        if (req->flags & REQ_F_FORCE_ASYNC) {
                bool opcode_poll = def->pollin || def->pollout;
 
-               if (opcode_poll && file_can_poll(req->file)) {
+               if (opcode_poll && io_file_can_poll(req)) {
                        needs_poll = true;
                        issue_flags |= IO_URING_F_NONBLOCK;
                }
@@ -2171,7 +2193,8 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
        /* req is partially pre-initialised, see io_preinit_req() */
        req->opcode = opcode = READ_ONCE(sqe->opcode);
        /* same numerical values with corresponding REQ_F_*, safe to copy */
-       req->flags = sqe_flags = READ_ONCE(sqe->flags);
+       sqe_flags = READ_ONCE(sqe->flags);
+       req->flags = (io_req_flags_t) sqe_flags;
        req->cqe.user_data = READ_ONCE(sqe->user_data);
        req->file = NULL;
        req->rsrc_node = NULL;
@@ -2475,33 +2498,6 @@ int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr)
        return ret;
 }
 
-struct io_wait_queue {
-       struct wait_queue_entry wq;
-       struct io_ring_ctx *ctx;
-       unsigned cq_tail;
-       unsigned nr_timeouts;
-       ktime_t timeout;
-};
-
-static inline bool io_has_work(struct io_ring_ctx *ctx)
-{
-       return test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq) ||
-              !llist_empty(&ctx->work_llist);
-}
-
-static inline bool io_should_wake(struct io_wait_queue *iowq)
-{
-       struct io_ring_ctx *ctx = iowq->ctx;
-       int dist = READ_ONCE(ctx->rings->cq.tail) - (int) iowq->cq_tail;
-
-       /*
-        * Wake up if we have enough events, or if a timeout occurred since we
-        * started waiting. For timeouts, we always want to return to userspace,
-        * regardless of event count.
-        */
-       return dist >= 0 || atomic_read(&ctx->cq_timeouts) != iowq->nr_timeouts;
-}
-
 static int io_wake_function(struct wait_queue_entry *curr, unsigned int mode,
                            int wake_flags, void *key)
 {
@@ -2520,7 +2516,7 @@ int io_run_task_work_sig(struct io_ring_ctx *ctx)
 {
        if (!llist_empty(&ctx->work_llist)) {
                __set_current_state(TASK_RUNNING);
-               if (io_run_local_work(ctx) > 0)
+               if (io_run_local_work(ctx, INT_MAX) > 0)
                        return 0;
        }
        if (io_run_task_work() > 0)
@@ -2588,7 +2584,7 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
        if (!io_allowed_run_tw(ctx))
                return -EEXIST;
        if (!llist_empty(&ctx->work_llist))
-               io_run_local_work(ctx);
+               io_run_local_work(ctx, min_events);
        io_run_task_work();
        io_cqring_overflow_flush(ctx);
        /* if user messes with these they will just get an early return */
@@ -2621,16 +2617,19 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
 
                if (get_timespec64(&ts, uts))
                        return -EFAULT;
+
                iowq.timeout = ktime_add_ns(timespec64_to_ktime(ts), ktime_get_ns());
+               io_napi_adjust_timeout(ctx, &iowq, &ts);
        }
 
+       io_napi_busy_loop(ctx, &iowq);
+
        trace_io_uring_cqring_wait(ctx, min_events);
        do {
+               int nr_wait = (int) iowq.cq_tail - READ_ONCE(ctx->rings->cq.tail);
                unsigned long check_cq;
 
                if (ctx->flags & IORING_SETUP_DEFER_TASKRUN) {
-                       int nr_wait = (int) iowq.cq_tail - READ_ONCE(ctx->rings->cq.tail);
-
                        atomic_set(&ctx->cq_wait_nr, nr_wait);
                        set_current_state(TASK_INTERRUPTIBLE);
                } else {
@@ -2649,7 +2648,7 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
                 */
                io_run_task_work();
                if (!llist_empty(&ctx->work_llist))
-                       io_run_local_work(ctx);
+                       io_run_local_work(ctx, nr_wait);
 
                /*
                 * Non-local task_work will be run on exit to userspace, but
@@ -2917,6 +2916,7 @@ static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx)
        io_req_caches_free(ctx);
        if (ctx->hash_map)
                io_wq_put_hash(ctx->hash_map);
+       io_napi_free(ctx);
        kfree(ctx->cancel_table.hbs);
        kfree(ctx->cancel_table_locked.hbs);
        kfree(ctx->io_bl);
@@ -3304,7 +3304,7 @@ static __cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
 
        if ((ctx->flags & IORING_SETUP_DEFER_TASKRUN) &&
            io_allowed_defer_tw_run(ctx))
-               ret |= io_run_local_work(ctx) > 0;
+               ret |= io_run_local_work(ctx, INT_MAX) > 0;
        ret |= io_cancel_defer_files(ctx, task, cancel_all);
        mutex_lock(&ctx->uring_lock);
        ret |= io_poll_remove_all(ctx, task, cancel_all);
@@ -3666,7 +3666,7 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
                         * it should handle ownership problems if any.
                         */
                        if (ctx->flags & IORING_SETUP_DEFER_TASKRUN)
-                               (void)io_run_local_work_locked(ctx);
+                               (void)io_run_local_work_locked(ctx, min_complete);
                }
                mutex_unlock(&ctx->uring_lock);
        }
@@ -4153,7 +4153,7 @@ static int __init io_uring_init(void)
        BUILD_BUG_ON(SQE_COMMON_FLAGS >= (1 << 8));
        BUILD_BUG_ON((SQE_VALID_FLAGS | SQE_COMMON_FLAGS) != SQE_VALID_FLAGS);
 
-       BUILD_BUG_ON(__REQ_F_LAST_BIT > 8 * sizeof(int));
+       BUILD_BUG_ON(__REQ_F_LAST_BIT > 8 * sizeof_field(struct io_kiocb, flags));
 
        BUILD_BUG_ON(sizeof(atomic_t) != sizeof(u32));
 
@@ -4175,9 +4175,8 @@ static int __init io_uring_init(void)
                                SLAB_ACCOUNT | SLAB_TYPESAFE_BY_RCU,
                                offsetof(struct io_kiocb, cmd.data),
                                sizeof_field(struct io_kiocb, cmd.data), NULL);
-       io_buf_cachep = kmem_cache_create("io_buffer", sizeof(struct io_buffer), 0,
-                                         SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT,
-                                         NULL);
+       io_buf_cachep = KMEM_CACHE(io_buffer,
+                                         SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT);
 
 #ifdef CONFIG_SYSCTL
        register_sysctl_init("kernel", kernel_io_uring_disabled_table);
index d5495710c17877624c75d8fa36b71af9535336a3..6426ee382276b5f298c68a450ceb894205eb374d 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/lockdep.h>
 #include <linux/resume_user_mode.h>
 #include <linux/kasan.h>
+#include <linux/poll.h>
 #include <linux/io_uring_types.h>
 #include <uapi/linux/eventpoll.h>
 #include "io-wq.h"
@@ -34,6 +35,32 @@ enum {
        IOU_STOP_MULTISHOT      = -ECANCELED,
 };
 
+struct io_wait_queue {
+       struct wait_queue_entry wq;
+       struct io_ring_ctx *ctx;
+       unsigned cq_tail;
+       unsigned nr_timeouts;
+       ktime_t timeout;
+
+#ifdef CONFIG_NET_RX_BUSY_POLL
+       unsigned int napi_busy_poll_to;
+       bool napi_prefer_busy_poll;
+#endif
+};
+
+static inline bool io_should_wake(struct io_wait_queue *iowq)
+{
+       struct io_ring_ctx *ctx = iowq->ctx;
+       int dist = READ_ONCE(ctx->rings->cq.tail) - (int) iowq->cq_tail;
+
+       /*
+        * Wake up if we have enough events, or if a timeout occurred since we
+        * started waiting. For timeouts, we always want to return to userspace,
+        * regardless of event count.
+        */
+       return dist >= 0 || atomic_read(&ctx->cq_timeouts) != iowq->nr_timeouts;
+}
+
 bool io_cqe_cache_refill(struct io_ring_ctx *ctx, bool overflow);
 void io_req_cqe_overflow(struct io_kiocb *req);
 int io_run_task_work_sig(struct io_ring_ctx *ctx);
@@ -56,6 +83,8 @@ void io_queue_iowq(struct io_kiocb *req, struct io_tw_state *ts_dont_use);
 void io_req_task_complete(struct io_kiocb *req, struct io_tw_state *ts);
 void io_req_task_queue_fail(struct io_kiocb *req, int ret);
 void io_req_task_submit(struct io_kiocb *req, struct io_tw_state *ts);
+struct llist_node *io_handle_tw_list(struct llist_node *node, unsigned int *count, unsigned int max_entries);
+struct llist_node *tctx_task_work_run(struct io_uring_task *tctx, unsigned int max_entries, unsigned int *count);
 void tctx_task_work(struct callback_head *cb);
 __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd);
 int io_uring_alloc_task_context(struct task_struct *task,
@@ -207,7 +236,7 @@ static inline void io_ring_submit_unlock(struct io_ring_ctx *ctx,
                                         unsigned issue_flags)
 {
        lockdep_assert_held(&ctx->uring_lock);
-       if (issue_flags & IO_URING_F_UNLOCKED)
+       if (unlikely(issue_flags & IO_URING_F_UNLOCKED))
                mutex_unlock(&ctx->uring_lock);
 }
 
@@ -220,7 +249,7 @@ static inline void io_ring_submit_lock(struct io_ring_ctx *ctx,
         * The only exception is when we've detached the request and issue it
         * from an async worker thread, grab the lock for that case.
         */
-       if (issue_flags & IO_URING_F_UNLOCKED)
+       if (unlikely(issue_flags & IO_URING_F_UNLOCKED))
                mutex_lock(&ctx->uring_lock);
        lockdep_assert_held(&ctx->uring_lock);
 }
@@ -274,6 +303,8 @@ static inline unsigned int io_sqring_entries(struct io_ring_ctx *ctx)
 
 static inline int io_run_task_work(void)
 {
+       bool ret = false;
+
        /*
         * Always check-and-clear the task_work notification signal. With how
         * signaling works for task_work, we can find it set with nothing to
@@ -285,18 +316,26 @@ static inline int io_run_task_work(void)
         * PF_IO_WORKER never returns to userspace, so check here if we have
         * notify work that needs processing.
         */
-       if (current->flags & PF_IO_WORKER &&
-           test_thread_flag(TIF_NOTIFY_RESUME)) {
-               __set_current_state(TASK_RUNNING);
-               resume_user_mode_work(NULL);
+       if (current->flags & PF_IO_WORKER) {
+               if (test_thread_flag(TIF_NOTIFY_RESUME)) {
+                       __set_current_state(TASK_RUNNING);
+                       resume_user_mode_work(NULL);
+               }
+               if (current->io_uring) {
+                       unsigned int count = 0;
+
+                       tctx_task_work_run(current->io_uring, UINT_MAX, &count);
+                       if (count)
+                               ret = true;
+               }
        }
        if (task_work_pending(current)) {
                __set_current_state(TASK_RUNNING);
                task_work_run();
-               return 1;
+               ret = true;
        }
 
-       return 0;
+       return ret;
 }
 
 static inline bool io_task_work_pending(struct io_ring_ctx *ctx)
@@ -398,4 +437,26 @@ static inline size_t uring_sqe_size(struct io_ring_ctx *ctx)
                return 2 * sizeof(struct io_uring_sqe);
        return sizeof(struct io_uring_sqe);
 }
+
+static inline bool io_file_can_poll(struct io_kiocb *req)
+{
+       if (req->flags & REQ_F_CAN_POLL)
+               return true;
+       if (file_can_poll(req->file)) {
+               req->flags |= REQ_F_CAN_POLL;
+               return true;
+       }
+       return false;
+}
+
+enum {
+       IO_CHECK_CQ_OVERFLOW_BIT,
+       IO_CHECK_CQ_DROPPED_BIT,
+};
+
+static inline bool io_has_work(struct io_ring_ctx *ctx)
+{
+       return test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq) ||
+              !llist_empty(&ctx->work_llist);
+}
 #endif
index 18df5a9d2f5e7defb2df04f548d9e67b737ddbaf..9be42bff936b95750beee16661893d7686a1fcb9 100644 (file)
@@ -81,15 +81,6 @@ bool io_kbuf_recycle_legacy(struct io_kiocb *req, unsigned issue_flags)
        struct io_buffer_list *bl;
        struct io_buffer *buf;
 
-       /*
-        * For legacy provided buffer mode, don't recycle if we already did
-        * IO to this buffer. For ring-mapped provided buffer mode, we should
-        * increment ring->head to explicitly monopolize the buffer to avoid
-        * multiple use.
-        */
-       if (req->flags & REQ_F_PARTIAL_IO)
-               return false;
-
        io_ring_submit_lock(ctx, issue_flags);
 
        buf = req->kbuf;
@@ -102,10 +93,8 @@ bool io_kbuf_recycle_legacy(struct io_kiocb *req, unsigned issue_flags)
        return true;
 }
 
-unsigned int __io_put_kbuf(struct io_kiocb *req, unsigned issue_flags)
+void __io_put_kbuf(struct io_kiocb *req, unsigned issue_flags)
 {
-       unsigned int cflags;
-
        /*
         * We can add this buffer back to two lists:
         *
@@ -118,21 +107,17 @@ unsigned int __io_put_kbuf(struct io_kiocb *req, unsigned issue_flags)
         * We migrate buffers from the comp_list to the issue cache list
         * when we need one.
         */
-       if (req->flags & REQ_F_BUFFER_RING) {
-               /* no buffers to recycle for this case */
-               cflags = __io_put_kbuf_list(req, NULL);
-       } else if (issue_flags & IO_URING_F_UNLOCKED) {
+       if (issue_flags & IO_URING_F_UNLOCKED) {
                struct io_ring_ctx *ctx = req->ctx;
 
                spin_lock(&ctx->completion_lock);
-               cflags = __io_put_kbuf_list(req, &ctx->io_buffers_comp);
+               __io_put_kbuf_list(req, &ctx->io_buffers_comp);
                spin_unlock(&ctx->completion_lock);
        } else {
                lockdep_assert_held(&req->ctx->uring_lock);
 
-               cflags = __io_put_kbuf_list(req, &req->ctx->io_buffers_cache);
+               __io_put_kbuf_list(req, &req->ctx->io_buffers_cache);
        }
-       return cflags;
 }
 
 static void __user *io_provided_buffer_select(struct io_kiocb *req, size_t *len,
@@ -145,6 +130,8 @@ static void __user *io_provided_buffer_select(struct io_kiocb *req, size_t *len,
                list_del(&kbuf->list);
                if (*len == 0 || *len > kbuf->len)
                        *len = kbuf->len;
+               if (list_empty(&bl->buf_list))
+                       req->flags |= REQ_F_BL_EMPTY;
                req->flags |= REQ_F_BUFFER_SELECTED;
                req->kbuf = kbuf;
                req->buf_index = kbuf->bid;
@@ -158,12 +145,16 @@ static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
                                          unsigned int issue_flags)
 {
        struct io_uring_buf_ring *br = bl->buf_ring;
+       __u16 tail, head = bl->head;
        struct io_uring_buf *buf;
-       __u16 head = bl->head;
 
-       if (unlikely(smp_load_acquire(&br->tail) == head))
+       tail = smp_load_acquire(&br->tail);
+       if (unlikely(tail == head))
                return NULL;
 
+       if (head + 1 == tail)
+               req->flags |= REQ_F_BL_EMPTY;
+
        head &= bl->mask;
        /* mmaped buffers are always contig */
        if (bl->is_mmap || head < IO_BUFFER_LIST_BUF_PER_PAGE) {
@@ -180,7 +171,7 @@ static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
        req->buf_list = bl;
        req->buf_index = buf->bid;
 
-       if (issue_flags & IO_URING_F_UNLOCKED || !file_can_poll(req->file)) {
+       if (issue_flags & IO_URING_F_UNLOCKED || !io_file_can_poll(req)) {
                /*
                 * If we came in unlocked, we have no choice but to consume the
                 * buffer here, otherwise nothing ensures that the buffer won't
index 53dfaa71a397cedd9b52923a3f0178873aaf9960..5218bfd79e871eef88d0a34445ee72731320be22 100644 (file)
@@ -57,7 +57,7 @@ int io_register_pbuf_status(struct io_ring_ctx *ctx, void __user *arg);
 
 void io_kbuf_mmap_list_free(struct io_ring_ctx *ctx);
 
-unsigned int __io_put_kbuf(struct io_kiocb *req, unsigned issue_flags);
+void __io_put_kbuf(struct io_kiocb *req, unsigned issue_flags);
 
 bool io_kbuf_recycle_legacy(struct io_kiocb *req, unsigned issue_flags);
 
@@ -73,21 +73,9 @@ static inline bool io_kbuf_recycle_ring(struct io_kiocb *req)
         * to monopolize the buffer.
         */
        if (req->buf_list) {
-               if (req->flags & REQ_F_PARTIAL_IO) {
-                       /*
-                        * If we end up here, then the io_uring_lock has
-                        * been kept held since we retrieved the buffer.
-                        * For the io-wq case, we already cleared
-                        * req->buf_list when the buffer was retrieved,
-                        * hence it cannot be set here for that case.
-                        */
-                       req->buf_list->head++;
-                       req->buf_list = NULL;
-               } else {
-                       req->buf_index = req->buf_list->bgid;
-                       req->flags &= ~REQ_F_BUFFER_RING;
-                       return true;
-               }
+               req->buf_index = req->buf_list->bgid;
+               req->flags &= ~REQ_F_BUFFER_RING;
+               return true;
        }
        return false;
 }
@@ -101,6 +89,8 @@ static inline bool io_do_buffer_select(struct io_kiocb *req)
 
 static inline bool io_kbuf_recycle(struct io_kiocb *req, unsigned issue_flags)
 {
+       if (req->flags & REQ_F_BL_NO_RECYCLE)
+               return false;
        if (req->flags & REQ_F_BUFFER_SELECTED)
                return io_kbuf_recycle_legacy(req, issue_flags);
        if (req->flags & REQ_F_BUFFER_RING)
@@ -108,41 +98,54 @@ static inline bool io_kbuf_recycle(struct io_kiocb *req, unsigned issue_flags)
        return false;
 }
 
-static inline unsigned int __io_put_kbuf_list(struct io_kiocb *req,
-                                             struct list_head *list)
+static inline void __io_put_kbuf_ring(struct io_kiocb *req)
 {
-       unsigned int ret = IORING_CQE_F_BUFFER | (req->buf_index << IORING_CQE_BUFFER_SHIFT);
+       if (req->buf_list) {
+               req->buf_index = req->buf_list->bgid;
+               req->buf_list->head++;
+       }
+       req->flags &= ~REQ_F_BUFFER_RING;
+}
 
+static inline void __io_put_kbuf_list(struct io_kiocb *req,
+                                     struct list_head *list)
+{
        if (req->flags & REQ_F_BUFFER_RING) {
-               if (req->buf_list) {
-                       req->buf_index = req->buf_list->bgid;
-                       req->buf_list->head++;
-               }
-               req->flags &= ~REQ_F_BUFFER_RING;
+               __io_put_kbuf_ring(req);
        } else {
                req->buf_index = req->kbuf->bgid;
                list_add(&req->kbuf->list, list);
                req->flags &= ~REQ_F_BUFFER_SELECTED;
        }
-
-       return ret;
 }
 
 static inline unsigned int io_put_kbuf_comp(struct io_kiocb *req)
 {
+       unsigned int ret;
+
        lockdep_assert_held(&req->ctx->completion_lock);
 
        if (!(req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)))
                return 0;
-       return __io_put_kbuf_list(req, &req->ctx->io_buffers_comp);
+
+       ret = IORING_CQE_F_BUFFER | (req->buf_index << IORING_CQE_BUFFER_SHIFT);
+       __io_put_kbuf_list(req, &req->ctx->io_buffers_comp);
+       return ret;
 }
 
 static inline unsigned int io_put_kbuf(struct io_kiocb *req,
                                       unsigned issue_flags)
 {
+       unsigned int ret;
 
-       if (!(req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)))
+       if (!(req->flags & (REQ_F_BUFFER_RING | REQ_F_BUFFER_SELECTED)))
                return 0;
-       return __io_put_kbuf(req, issue_flags);
+
+       ret = IORING_CQE_F_BUFFER | (req->buf_index << IORING_CQE_BUFFER_SHIFT);
+       if (req->flags & REQ_F_BUFFER_RING)
+               __io_put_kbuf_ring(req);
+       else
+               __io_put_kbuf(req, issue_flags);
+       return ret;
 }
 #endif
diff --git a/io_uring/napi.c b/io_uring/napi.c
new file mode 100644 (file)
index 0000000..883a1a6
--- /dev/null
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "io_uring.h"
+#include "napi.h"
+
+#ifdef CONFIG_NET_RX_BUSY_POLL
+
+/* Timeout for cleanout of stale entries. */
+#define NAPI_TIMEOUT           (60 * SEC_CONVERSION)
+
+struct io_napi_entry {
+       unsigned int            napi_id;
+       struct list_head        list;
+
+       unsigned long           timeout;
+       struct hlist_node       node;
+
+       struct rcu_head         rcu;
+};
+
+static struct io_napi_entry *io_napi_hash_find(struct hlist_head *hash_list,
+                                              unsigned int napi_id)
+{
+       struct io_napi_entry *e;
+
+       hlist_for_each_entry_rcu(e, hash_list, node) {
+               if (e->napi_id != napi_id)
+                       continue;
+               e->timeout = jiffies + NAPI_TIMEOUT;
+               return e;
+       }
+
+       return NULL;
+}
+
+void __io_napi_add(struct io_ring_ctx *ctx, struct socket *sock)
+{
+       struct hlist_head *hash_list;
+       unsigned int napi_id;
+       struct sock *sk;
+       struct io_napi_entry *e;
+
+       sk = sock->sk;
+       if (!sk)
+               return;
+
+       napi_id = READ_ONCE(sk->sk_napi_id);
+
+       /* Non-NAPI IDs can be rejected. */
+       if (napi_id < MIN_NAPI_ID)
+               return;
+
+       hash_list = &ctx->napi_ht[hash_min(napi_id, HASH_BITS(ctx->napi_ht))];
+
+       rcu_read_lock();
+       e = io_napi_hash_find(hash_list, napi_id);
+       if (e) {
+               e->timeout = jiffies + NAPI_TIMEOUT;
+               rcu_read_unlock();
+               return;
+       }
+       rcu_read_unlock();
+
+       e = kmalloc(sizeof(*e), GFP_NOWAIT);
+       if (!e)
+               return;
+
+       e->napi_id = napi_id;
+       e->timeout = jiffies + NAPI_TIMEOUT;
+
+       spin_lock(&ctx->napi_lock);
+       if (unlikely(io_napi_hash_find(hash_list, napi_id))) {
+               spin_unlock(&ctx->napi_lock);
+               kfree(e);
+               return;
+       }
+
+       hlist_add_tail_rcu(&e->node, hash_list);
+       list_add_tail(&e->list, &ctx->napi_list);
+       spin_unlock(&ctx->napi_lock);
+}
+
+static void __io_napi_remove_stale(struct io_ring_ctx *ctx)
+{
+       struct io_napi_entry *e;
+       unsigned int i;
+
+       spin_lock(&ctx->napi_lock);
+       hash_for_each(ctx->napi_ht, i, e, node) {
+               if (time_after(jiffies, e->timeout)) {
+                       list_del(&e->list);
+                       hash_del_rcu(&e->node);
+                       kfree_rcu(e, rcu);
+               }
+       }
+       spin_unlock(&ctx->napi_lock);
+}
+
+static inline void io_napi_remove_stale(struct io_ring_ctx *ctx, bool is_stale)
+{
+       if (is_stale)
+               __io_napi_remove_stale(ctx);
+}
+
+static inline bool io_napi_busy_loop_timeout(unsigned long start_time,
+                                            unsigned long bp_usec)
+{
+       if (bp_usec) {
+               unsigned long end_time = start_time + bp_usec;
+               unsigned long now = busy_loop_current_time();
+
+               return time_after(now, end_time);
+       }
+
+       return true;
+}
+
+static bool io_napi_busy_loop_should_end(void *data,
+                                        unsigned long start_time)
+{
+       struct io_wait_queue *iowq = data;
+
+       if (signal_pending(current))
+               return true;
+       if (io_should_wake(iowq) || io_has_work(iowq->ctx))
+               return true;
+       if (io_napi_busy_loop_timeout(start_time, iowq->napi_busy_poll_to))
+               return true;
+
+       return false;
+}
+
+static bool __io_napi_do_busy_loop(struct io_ring_ctx *ctx,
+                                  void *loop_end_arg)
+{
+       struct io_napi_entry *e;
+       bool (*loop_end)(void *, unsigned long) = NULL;
+       bool is_stale = false;
+
+       if (loop_end_arg)
+               loop_end = io_napi_busy_loop_should_end;
+
+       list_for_each_entry_rcu(e, &ctx->napi_list, list) {
+               napi_busy_loop_rcu(e->napi_id, loop_end, loop_end_arg,
+                                  ctx->napi_prefer_busy_poll, BUSY_POLL_BUDGET);
+
+               if (time_after(jiffies, e->timeout))
+                       is_stale = true;
+       }
+
+       return is_stale;
+}
+
+static void io_napi_blocking_busy_loop(struct io_ring_ctx *ctx,
+                                      struct io_wait_queue *iowq)
+{
+       unsigned long start_time = busy_loop_current_time();
+       void *loop_end_arg = NULL;
+       bool is_stale = false;
+
+       /* Singular lists use a different napi loop end check function and are
+        * only executed once.
+        */
+       if (list_is_singular(&ctx->napi_list))
+               loop_end_arg = iowq;
+
+       rcu_read_lock();
+       do {
+               is_stale = __io_napi_do_busy_loop(ctx, loop_end_arg);
+       } while (!io_napi_busy_loop_should_end(iowq, start_time) && !loop_end_arg);
+       rcu_read_unlock();
+
+       io_napi_remove_stale(ctx, is_stale);
+}
+
+/*
+ * io_napi_init() - Init napi settings
+ * @ctx: pointer to io-uring context structure
+ *
+ * Init napi settings in the io-uring context.
+ */
+void io_napi_init(struct io_ring_ctx *ctx)
+{
+       INIT_LIST_HEAD(&ctx->napi_list);
+       spin_lock_init(&ctx->napi_lock);
+       ctx->napi_prefer_busy_poll = false;
+       ctx->napi_busy_poll_to = READ_ONCE(sysctl_net_busy_poll);
+}
+
+/*
+ * io_napi_free() - Deallocate napi
+ * @ctx: pointer to io-uring context structure
+ *
+ * Free the napi list and the hash table in the io-uring context.
+ */
+void io_napi_free(struct io_ring_ctx *ctx)
+{
+       struct io_napi_entry *e;
+       LIST_HEAD(napi_list);
+       unsigned int i;
+
+       spin_lock(&ctx->napi_lock);
+       hash_for_each(ctx->napi_ht, i, e, node) {
+               hash_del_rcu(&e->node);
+               kfree_rcu(e, rcu);
+       }
+       spin_unlock(&ctx->napi_lock);
+}
+
+/*
+ * io_napi_register() - Register napi with io-uring
+ * @ctx: pointer to io-uring context structure
+ * @arg: pointer to io_uring_napi structure
+ *
+ * Register napi in the io-uring context.
+ */
+int io_register_napi(struct io_ring_ctx *ctx, void __user *arg)
+{
+       const struct io_uring_napi curr = {
+               .busy_poll_to     = ctx->napi_busy_poll_to,
+               .prefer_busy_poll = ctx->napi_prefer_busy_poll
+       };
+       struct io_uring_napi napi;
+
+       if (copy_from_user(&napi, arg, sizeof(napi)))
+               return -EFAULT;
+       if (napi.pad[0] || napi.pad[1] || napi.pad[2] || napi.resv)
+               return -EINVAL;
+
+       if (copy_to_user(arg, &curr, sizeof(curr)))
+               return -EFAULT;
+
+       WRITE_ONCE(ctx->napi_busy_poll_to, napi.busy_poll_to);
+       WRITE_ONCE(ctx->napi_prefer_busy_poll, !!napi.prefer_busy_poll);
+       WRITE_ONCE(ctx->napi_enabled, true);
+       return 0;
+}
+
+/*
+ * io_napi_unregister() - Unregister napi with io-uring
+ * @ctx: pointer to io-uring context structure
+ * @arg: pointer to io_uring_napi structure
+ *
+ * Unregister napi. If arg has been specified copy the busy poll timeout and
+ * prefer busy poll setting to the passed in structure.
+ */
+int io_unregister_napi(struct io_ring_ctx *ctx, void __user *arg)
+{
+       const struct io_uring_napi curr = {
+               .busy_poll_to     = ctx->napi_busy_poll_to,
+               .prefer_busy_poll = ctx->napi_prefer_busy_poll
+       };
+
+       if (arg && copy_to_user(arg, &curr, sizeof(curr)))
+               return -EFAULT;
+
+       WRITE_ONCE(ctx->napi_busy_poll_to, 0);
+       WRITE_ONCE(ctx->napi_prefer_busy_poll, false);
+       WRITE_ONCE(ctx->napi_enabled, false);
+       return 0;
+}
+
+/*
+ * __io_napi_adjust_timeout() - Add napi id to the busy poll list
+ * @ctx: pointer to io-uring context structure
+ * @iowq: pointer to io wait queue
+ * @ts: pointer to timespec or NULL
+ *
+ * Adjust the busy loop timeout according to timespec and busy poll timeout.
+ */
+void __io_napi_adjust_timeout(struct io_ring_ctx *ctx, struct io_wait_queue *iowq,
+                             struct timespec64 *ts)
+{
+       unsigned int poll_to = READ_ONCE(ctx->napi_busy_poll_to);
+
+       if (ts) {
+               struct timespec64 poll_to_ts = ns_to_timespec64(1000 * (s64)poll_to);
+
+               if (timespec64_compare(ts, &poll_to_ts) > 0) {
+                       *ts = timespec64_sub(*ts, poll_to_ts);
+               } else {
+                       u64 to = timespec64_to_ns(ts);
+
+                       do_div(to, 1000);
+                       ts->tv_sec = 0;
+                       ts->tv_nsec = 0;
+               }
+       }
+
+       iowq->napi_busy_poll_to = poll_to;
+}
+
+/*
+ * __io_napi_busy_loop() - execute busy poll loop
+ * @ctx: pointer to io-uring context structure
+ * @iowq: pointer to io wait queue
+ *
+ * Execute the busy poll loop and merge the spliced off list.
+ */
+void __io_napi_busy_loop(struct io_ring_ctx *ctx, struct io_wait_queue *iowq)
+{
+       iowq->napi_prefer_busy_poll = READ_ONCE(ctx->napi_prefer_busy_poll);
+
+       if (!(ctx->flags & IORING_SETUP_SQPOLL) && ctx->napi_enabled)
+               io_napi_blocking_busy_loop(ctx, iowq);
+}
+
+/*
+ * io_napi_sqpoll_busy_poll() - busy poll loop for sqpoll
+ * @ctx: pointer to io-uring context structure
+ *
+ * Splice of the napi list and execute the napi busy poll loop.
+ */
+int io_napi_sqpoll_busy_poll(struct io_ring_ctx *ctx)
+{
+       LIST_HEAD(napi_list);
+       bool is_stale = false;
+
+       if (!READ_ONCE(ctx->napi_busy_poll_to))
+               return 0;
+       if (list_empty_careful(&ctx->napi_list))
+               return 0;
+
+       rcu_read_lock();
+       is_stale = __io_napi_do_busy_loop(ctx, NULL);
+       rcu_read_unlock();
+
+       io_napi_remove_stale(ctx, is_stale);
+       return 1;
+}
+
+#endif
diff --git a/io_uring/napi.h b/io_uring/napi.h
new file mode 100644 (file)
index 0000000..6fc0393
--- /dev/null
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef IOU_NAPI_H
+#define IOU_NAPI_H
+
+#include <linux/kernel.h>
+#include <linux/io_uring.h>
+#include <net/busy_poll.h>
+
+#ifdef CONFIG_NET_RX_BUSY_POLL
+
+void io_napi_init(struct io_ring_ctx *ctx);
+void io_napi_free(struct io_ring_ctx *ctx);
+
+int io_register_napi(struct io_ring_ctx *ctx, void __user *arg);
+int io_unregister_napi(struct io_ring_ctx *ctx, void __user *arg);
+
+void __io_napi_add(struct io_ring_ctx *ctx, struct socket *sock);
+
+void __io_napi_adjust_timeout(struct io_ring_ctx *ctx,
+               struct io_wait_queue *iowq, struct timespec64 *ts);
+void __io_napi_busy_loop(struct io_ring_ctx *ctx, struct io_wait_queue *iowq);
+int io_napi_sqpoll_busy_poll(struct io_ring_ctx *ctx);
+
+static inline bool io_napi(struct io_ring_ctx *ctx)
+{
+       return !list_empty(&ctx->napi_list);
+}
+
+static inline void io_napi_adjust_timeout(struct io_ring_ctx *ctx,
+                                         struct io_wait_queue *iowq,
+                                         struct timespec64 *ts)
+{
+       if (!io_napi(ctx))
+               return;
+       __io_napi_adjust_timeout(ctx, iowq, ts);
+}
+
+static inline void io_napi_busy_loop(struct io_ring_ctx *ctx,
+                                    struct io_wait_queue *iowq)
+{
+       if (!io_napi(ctx))
+               return;
+       __io_napi_busy_loop(ctx, iowq);
+}
+
+/*
+ * io_napi_add() - Add napi id to the busy poll list
+ * @req: pointer to io_kiocb request
+ *
+ * Add the napi id of the socket to the napi busy poll list and hash table.
+ */
+static inline void io_napi_add(struct io_kiocb *req)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       struct socket *sock;
+
+       if (!READ_ONCE(ctx->napi_busy_poll_to))
+               return;
+
+       sock = sock_from_file(req->file);
+       if (sock)
+               __io_napi_add(ctx, sock);
+}
+
+#else
+
+static inline void io_napi_init(struct io_ring_ctx *ctx)
+{
+}
+static inline void io_napi_free(struct io_ring_ctx *ctx)
+{
+}
+static inline int io_register_napi(struct io_ring_ctx *ctx, void __user *arg)
+{
+       return -EOPNOTSUPP;
+}
+static inline int io_unregister_napi(struct io_ring_ctx *ctx, void __user *arg)
+{
+       return -EOPNOTSUPP;
+}
+static inline bool io_napi(struct io_ring_ctx *ctx)
+{
+       return false;
+}
+static inline void io_napi_add(struct io_kiocb *req)
+{
+}
+static inline void io_napi_adjust_timeout(struct io_ring_ctx *ctx,
+                                         struct io_wait_queue *iowq,
+                                         struct timespec64 *ts)
+{
+}
+static inline void io_napi_busy_loop(struct io_ring_ctx *ctx,
+                                    struct io_wait_queue *iowq)
+{
+}
+static inline int io_napi_sqpoll_busy_poll(struct io_ring_ctx *ctx)
+{
+       return 0;
+}
+#endif /* CONFIG_NET_RX_BUSY_POLL */
+
+#endif
index 43bc9a5f96f9d1ce48f2d6e2a5cf850c675aee0d..19451f0dbf813664f9b26e0a27c12b52be080944 100644 (file)
@@ -78,19 +78,6 @@ struct io_sr_msg {
  */
 #define MULTISHOT_MAX_RETRY    32
 
-static inline bool io_check_multishot(struct io_kiocb *req,
-                                     unsigned int issue_flags)
-{
-       /*
-        * When ->locked_cq is set we only allow to post CQEs from the original
-        * task context. Usual request completions will be handled in other
-        * generic paths but multipoll may decide to post extra cqes.
-        */
-       return !(issue_flags & IO_URING_F_IOWQ) ||
-               !(issue_flags & IO_URING_F_MULTISHOT) ||
-               !req->ctx->task_complete;
-}
-
 int io_shutdown_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
        struct io_shutdown *shutdown = io_kiocb_to_cmd(req, struct io_shutdown);
@@ -204,16 +191,130 @@ static int io_setup_async_msg(struct io_kiocb *req,
        return -EAGAIN;
 }
 
+#ifdef CONFIG_COMPAT
+static int io_compat_msg_copy_hdr(struct io_kiocb *req,
+                                 struct io_async_msghdr *iomsg,
+                                 struct compat_msghdr *msg, int ddir)
+{
+       struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
+       struct compat_iovec __user *uiov;
+       int ret;
+
+       if (copy_from_user(msg, sr->umsg_compat, sizeof(*msg)))
+               return -EFAULT;
+
+       uiov = compat_ptr(msg->msg_iov);
+       if (req->flags & REQ_F_BUFFER_SELECT) {
+               compat_ssize_t clen;
+
+               iomsg->free_iov = NULL;
+               if (msg->msg_iovlen == 0) {
+                       sr->len = 0;
+               } else if (msg->msg_iovlen > 1) {
+                       return -EINVAL;
+               } else {
+                       if (!access_ok(uiov, sizeof(*uiov)))
+                               return -EFAULT;
+                       if (__get_user(clen, &uiov->iov_len))
+                               return -EFAULT;
+                       if (clen < 0)
+                               return -EINVAL;
+                       sr->len = clen;
+               }
+
+               return 0;
+       }
+
+       iomsg->free_iov = iomsg->fast_iov;
+       ret = __import_iovec(ddir, (struct iovec __user *)uiov, msg->msg_iovlen,
+                               UIO_FASTIOV, &iomsg->free_iov,
+                               &iomsg->msg.msg_iter, true);
+       if (unlikely(ret < 0))
+               return ret;
+
+       return 0;
+}
+#endif
+
+static int io_msg_copy_hdr(struct io_kiocb *req, struct io_async_msghdr *iomsg,
+                          struct user_msghdr *msg, int ddir)
+{
+       struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
+       int ret;
+
+       if (!user_access_begin(sr->umsg, sizeof(*sr->umsg)))
+               return -EFAULT;
+
+       ret = -EFAULT;
+       unsafe_get_user(msg->msg_name, &sr->umsg->msg_name, ua_end);
+       unsafe_get_user(msg->msg_namelen, &sr->umsg->msg_namelen, ua_end);
+       unsafe_get_user(msg->msg_iov, &sr->umsg->msg_iov, ua_end);
+       unsafe_get_user(msg->msg_iovlen, &sr->umsg->msg_iovlen, ua_end);
+       unsafe_get_user(msg->msg_control, &sr->umsg->msg_control, ua_end);
+       unsafe_get_user(msg->msg_controllen, &sr->umsg->msg_controllen, ua_end);
+       msg->msg_flags = 0;
+
+       if (req->flags & REQ_F_BUFFER_SELECT) {
+               if (msg->msg_iovlen == 0) {
+                       sr->len = iomsg->fast_iov[0].iov_len = 0;
+                       iomsg->fast_iov[0].iov_base = NULL;
+                       iomsg->free_iov = NULL;
+               } else if (msg->msg_iovlen > 1) {
+                       ret = -EINVAL;
+                       goto ua_end;
+               } else {
+                       /* we only need the length for provided buffers */
+                       if (!access_ok(&msg->msg_iov[0].iov_len, sizeof(__kernel_size_t)))
+                               goto ua_end;
+                       unsafe_get_user(iomsg->fast_iov[0].iov_len,
+                                       &msg->msg_iov[0].iov_len, ua_end);
+                       sr->len = iomsg->fast_iov[0].iov_len;
+                       iomsg->free_iov = NULL;
+               }
+               ret = 0;
+ua_end:
+               user_access_end();
+               return ret;
+       }
+
+       user_access_end();
+       iomsg->free_iov = iomsg->fast_iov;
+       ret = __import_iovec(ddir, msg->msg_iov, msg->msg_iovlen, UIO_FASTIOV,
+                               &iomsg->free_iov, &iomsg->msg.msg_iter, false);
+       if (unlikely(ret < 0))
+               return ret;
+
+       return 0;
+}
+
 static int io_sendmsg_copy_hdr(struct io_kiocb *req,
                               struct io_async_msghdr *iomsg)
 {
        struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
+       struct user_msghdr msg;
        int ret;
 
        iomsg->msg.msg_name = &iomsg->addr;
-       iomsg->free_iov = iomsg->fast_iov;
-       ret = sendmsg_copy_msghdr(&iomsg->msg, sr->umsg, sr->msg_flags,
-                                       &iomsg->free_iov);
+       iomsg->msg.msg_iter.nr_segs = 0;
+
+#ifdef CONFIG_COMPAT
+       if (unlikely(req->ctx->compat)) {
+               struct compat_msghdr cmsg;
+
+               ret = io_compat_msg_copy_hdr(req, iomsg, &cmsg, ITER_SOURCE);
+               if (unlikely(ret))
+                       return ret;
+
+               return __get_compat_msghdr(&iomsg->msg, &cmsg, NULL);
+       }
+#endif
+
+       ret = io_msg_copy_hdr(req, iomsg, &msg, ITER_SOURCE);
+       if (unlikely(ret))
+               return ret;
+
+       ret = __copy_msghdr(&iomsg->msg, &msg, NULL);
+
        /* save msg_control as sys_sendmsg() overwrites it */
        sr->msg_control = iomsg->msg.msg_control_user;
        return ret;
@@ -273,6 +374,8 @@ int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
        struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
 
+       sr->done_io = 0;
+
        if (req->opcode == IORING_OP_SEND) {
                if (READ_ONCE(sqe->__pad3[0]))
                        return -EINVAL;
@@ -295,10 +398,20 @@ int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        if (req->ctx->compat)
                sr->msg_flags |= MSG_CMSG_COMPAT;
 #endif
-       sr->done_io = 0;
        return 0;
 }
 
+static void io_req_msg_cleanup(struct io_kiocb *req,
+                              struct io_async_msghdr *kmsg,
+                              unsigned int issue_flags)
+{
+       req->flags &= ~REQ_F_NEED_CLEANUP;
+       /* fast path, check for non-NULL to avoid function call */
+       if (kmsg->free_iov)
+               kfree(kmsg->free_iov);
+       io_netmsg_recycle(req, issue_flags);
+}
+
 int io_sendmsg(struct io_kiocb *req, unsigned int issue_flags)
 {
        struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
@@ -341,18 +454,14 @@ int io_sendmsg(struct io_kiocb *req, unsigned int issue_flags)
                        kmsg->msg.msg_controllen = 0;
                        kmsg->msg.msg_control = NULL;
                        sr->done_io += ret;
-                       req->flags |= REQ_F_PARTIAL_IO;
+                       req->flags |= REQ_F_BL_NO_RECYCLE;
                        return io_setup_async_msg(req, kmsg, issue_flags);
                }
                if (ret == -ERESTARTSYS)
                        ret = -EINTR;
                req_set_fail(req);
        }
-       /* fast path, check for non-NULL to avoid function call */
-       if (kmsg->free_iov)
-               kfree(kmsg->free_iov);
-       req->flags &= ~REQ_F_NEED_CLEANUP;
-       io_netmsg_recycle(req, issue_flags);
+       io_req_msg_cleanup(req, kmsg, issue_flags);
        if (ret >= 0)
                ret += sr->done_io;
        else if (sr->done_io)
@@ -420,7 +529,7 @@ int io_send(struct io_kiocb *req, unsigned int issue_flags)
                        sr->len -= ret;
                        sr->buf += ret;
                        sr->done_io += ret;
-                       req->flags |= REQ_F_PARTIAL_IO;
+                       req->flags |= REQ_F_BL_NO_RECYCLE;
                        return io_setup_async_addr(req, &__address, issue_flags);
                }
                if (ret == -ERESTARTSYS)
@@ -435,142 +544,77 @@ int io_send(struct io_kiocb *req, unsigned int issue_flags)
        return IOU_OK;
 }
 
-static bool io_recvmsg_multishot_overflow(struct io_async_msghdr *iomsg)
+static int io_recvmsg_mshot_prep(struct io_kiocb *req,
+                                struct io_async_msghdr *iomsg,
+                                int namelen, size_t controllen)
 {
-       int hdr;
-
-       if (iomsg->namelen < 0)
-               return true;
-       if (check_add_overflow((int)sizeof(struct io_uring_recvmsg_out),
-                              iomsg->namelen, &hdr))
-               return true;
-       if (check_add_overflow(hdr, (int)iomsg->controllen, &hdr))
-               return true;
+       if ((req->flags & (REQ_F_APOLL_MULTISHOT|REQ_F_BUFFER_SELECT)) ==
+                         (REQ_F_APOLL_MULTISHOT|REQ_F_BUFFER_SELECT)) {
+               int hdr;
+
+               if (unlikely(namelen < 0))
+                       return -EOVERFLOW;
+               if (check_add_overflow(sizeof(struct io_uring_recvmsg_out),
+                                       namelen, &hdr))
+                       return -EOVERFLOW;
+               if (check_add_overflow(hdr, controllen, &hdr))
+                       return -EOVERFLOW;
+
+               iomsg->namelen = namelen;
+               iomsg->controllen = controllen;
+               return 0;
+       }
 
-       return false;
+       return 0;
 }
 
-static int __io_recvmsg_copy_hdr(struct io_kiocb *req,
-                                struct io_async_msghdr *iomsg)
+static int io_recvmsg_copy_hdr(struct io_kiocb *req,
+                              struct io_async_msghdr *iomsg)
 {
-       struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
        struct user_msghdr msg;
        int ret;
 
-       if (copy_from_user(&msg, sr->umsg, sizeof(*sr->umsg)))
-               return -EFAULT;
-
-       ret = __copy_msghdr(&iomsg->msg, &msg, &iomsg->uaddr);
-       if (ret)
-               return ret;
-
-       if (req->flags & REQ_F_BUFFER_SELECT) {
-               if (msg.msg_iovlen == 0) {
-                       sr->len = iomsg->fast_iov[0].iov_len = 0;
-                       iomsg->fast_iov[0].iov_base = NULL;
-                       iomsg->free_iov = NULL;
-               } else if (msg.msg_iovlen > 1) {
-                       return -EINVAL;
-               } else {
-                       if (copy_from_user(iomsg->fast_iov, msg.msg_iov, sizeof(*msg.msg_iov)))
-                               return -EFAULT;
-                       sr->len = iomsg->fast_iov[0].iov_len;
-                       iomsg->free_iov = NULL;
-               }
-
-               if (req->flags & REQ_F_APOLL_MULTISHOT) {
-                       iomsg->namelen = msg.msg_namelen;
-                       iomsg->controllen = msg.msg_controllen;
-                       if (io_recvmsg_multishot_overflow(iomsg))
-                               return -EOVERFLOW;
-               }
-       } else {
-               iomsg->free_iov = iomsg->fast_iov;
-               ret = __import_iovec(ITER_DEST, msg.msg_iov, msg.msg_iovlen, UIO_FASTIOV,
-                                    &iomsg->free_iov, &iomsg->msg.msg_iter,
-                                    false);
-               if (ret > 0)
-                       ret = 0;
-       }
-
-       return ret;
-}
+       iomsg->msg.msg_name = &iomsg->addr;
+       iomsg->msg.msg_iter.nr_segs = 0;
 
 #ifdef CONFIG_COMPAT
-static int __io_compat_recvmsg_copy_hdr(struct io_kiocb *req,
-                                       struct io_async_msghdr *iomsg)
-{
-       struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
-       struct compat_msghdr msg;
-       struct compat_iovec __user *uiov;
-       int ret;
-
-       if (copy_from_user(&msg, sr->umsg_compat, sizeof(msg)))
-               return -EFAULT;
-
-       ret = __get_compat_msghdr(&iomsg->msg, &msg, &iomsg->uaddr);
-       if (ret)
-               return ret;
+       if (unlikely(req->ctx->compat)) {
+               struct compat_msghdr cmsg;
 
-       uiov = compat_ptr(msg.msg_iov);
-       if (req->flags & REQ_F_BUFFER_SELECT) {
-               compat_ssize_t clen;
-
-               iomsg->free_iov = NULL;
-               if (msg.msg_iovlen == 0) {
-                       sr->len = 0;
-               } else if (msg.msg_iovlen > 1) {
-                       return -EINVAL;
-               } else {
-                       if (!access_ok(uiov, sizeof(*uiov)))
-                               return -EFAULT;
-                       if (__get_user(clen, &uiov->iov_len))
-                               return -EFAULT;
-                       if (clen < 0)
-                               return -EINVAL;
-                       sr->len = clen;
-               }
+               ret = io_compat_msg_copy_hdr(req, iomsg, &cmsg, ITER_DEST);
+               if (unlikely(ret))
+                       return ret;
 
-               if (req->flags & REQ_F_APOLL_MULTISHOT) {
-                       iomsg->namelen = msg.msg_namelen;
-                       iomsg->controllen = msg.msg_controllen;
-                       if (io_recvmsg_multishot_overflow(iomsg))
-                               return -EOVERFLOW;
-               }
-       } else {
-               iomsg->free_iov = iomsg->fast_iov;
-               ret = __import_iovec(ITER_DEST, (struct iovec __user *)uiov, msg.msg_iovlen,
-                                  UIO_FASTIOV, &iomsg->free_iov,
-                                  &iomsg->msg.msg_iter, true);
-               if (ret < 0)
+               ret = __get_compat_msghdr(&iomsg->msg, &cmsg, &iomsg->uaddr);
+               if (unlikely(ret))
                        return ret;
-       }
 
-       return 0;
-}
+               return io_recvmsg_mshot_prep(req, iomsg, cmsg.msg_namelen,
+                                               cmsg.msg_controllen);
+       }
 #endif
 
-static int io_recvmsg_copy_hdr(struct io_kiocb *req,
-                              struct io_async_msghdr *iomsg)
-{
-       iomsg->msg.msg_name = &iomsg->addr;
-       iomsg->msg.msg_iter.nr_segs = 0;
+       ret = io_msg_copy_hdr(req, iomsg, &msg, ITER_DEST);
+       if (unlikely(ret))
+               return ret;
 
-#ifdef CONFIG_COMPAT
-       if (req->ctx->compat)
-               return __io_compat_recvmsg_copy_hdr(req, iomsg);
-#endif
+       ret = __copy_msghdr(&iomsg->msg, &msg, &iomsg->uaddr);
+       if (unlikely(ret))
+               return ret;
 
-       return __io_recvmsg_copy_hdr(req, iomsg);
+       return io_recvmsg_mshot_prep(req, iomsg, msg.msg_namelen,
+                                       msg.msg_controllen);
 }
 
 int io_recvmsg_prep_async(struct io_kiocb *req)
 {
+       struct io_async_msghdr *iomsg;
        int ret;
 
        if (!io_msg_alloc_async_prep(req))
                return -ENOMEM;
-       ret = io_recvmsg_copy_hdr(req, req->async_data);
+       iomsg = req->async_data;
+       ret = io_recvmsg_copy_hdr(req, iomsg);
        if (!ret)
                req->flags |= REQ_F_NEED_CLEANUP;
        return ret;
@@ -582,6 +626,8 @@ int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
        struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
 
+       sr->done_io = 0;
+
        if (unlikely(sqe->file_index || sqe->addr2))
                return -EINVAL;
 
@@ -618,7 +664,6 @@ int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        if (req->ctx->compat)
                sr->msg_flags |= MSG_CMSG_COMPAT;
 #endif
-       sr->done_io = 0;
        sr->nr_multishot_loops = 0;
        return 0;
 }
@@ -627,6 +672,7 @@ static inline void io_recv_prep_retry(struct io_kiocb *req)
 {
        struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
 
+       req->flags &= ~REQ_F_BL_EMPTY;
        sr->done_io = 0;
        sr->len = 0; /* get from the provided buffer */
        req->buf_index = sr->buf_group;
@@ -645,30 +691,22 @@ static inline bool io_recv_finish(struct io_kiocb *req, int *ret,
        unsigned int cflags;
 
        cflags = io_put_kbuf(req, issue_flags);
-       if (msg->msg_inq && msg->msg_inq != -1)
+       if (msg->msg_inq > 0)
                cflags |= IORING_CQE_F_SOCK_NONEMPTY;
 
-       if (!(req->flags & REQ_F_APOLL_MULTISHOT)) {
-               io_req_set_res(req, *ret, cflags);
-               *ret = IOU_OK;
-               return true;
-       }
-
-       if (mshot_finished)
-               goto finish;
-
        /*
         * Fill CQE for this receive and see if we should keep trying to
         * receive from this socket.
         */
-       if (io_fill_cqe_req_aux(req, issue_flags & IO_URING_F_COMPLETE_DEFER,
+       if ((req->flags & REQ_F_APOLL_MULTISHOT) && !mshot_finished &&
+           io_fill_cqe_req_aux(req, issue_flags & IO_URING_F_COMPLETE_DEFER,
                                *ret, cflags | IORING_CQE_F_MORE)) {
                struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
                int mshot_retry_ret = IOU_ISSUE_SKIP_COMPLETE;
 
                io_recv_prep_retry(req);
                /* Known not-empty or unknown state, retry */
-               if (cflags & IORING_CQE_F_SOCK_NONEMPTY || msg->msg_inq == -1) {
+               if (cflags & IORING_CQE_F_SOCK_NONEMPTY || msg->msg_inq < 0) {
                        if (sr->nr_multishot_loops++ < MULTISHOT_MAX_RETRY)
                                return false;
                        /* mshot retries exceeded, force a requeue */
@@ -681,8 +719,8 @@ static inline bool io_recv_finish(struct io_kiocb *req, int *ret,
                        *ret = -EAGAIN;
                return true;
        }
-       /* Otherwise stop multishot but use the current result. */
-finish:
+
+       /* Finish the request / stop multishot. */
        io_req_set_res(req, *ret, cflags);
 
        if (issue_flags & IO_URING_F_MULTISHOT)
@@ -803,8 +841,9 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
            (sr->flags & IORING_RECVSEND_POLL_FIRST))
                return io_setup_async_msg(req, kmsg, issue_flags);
 
-       if (!io_check_multishot(req, issue_flags))
-               return io_setup_async_msg(req, kmsg, issue_flags);
+       flags = sr->msg_flags;
+       if (force_nonblock)
+               flags |= MSG_DONTWAIT;
 
 retry_multishot:
        if (io_do_buffer_select(req)) {
@@ -826,10 +865,6 @@ retry_multishot:
                iov_iter_ubuf(&kmsg->msg.msg_iter, ITER_DEST, buf, len);
        }
 
-       flags = sr->msg_flags;
-       if (force_nonblock)
-               flags |= MSG_DONTWAIT;
-
        kmsg->msg.msg_get_inq = 1;
        kmsg->msg.msg_inq = -1;
        if (req->flags & REQ_F_APOLL_MULTISHOT) {
@@ -855,7 +890,7 @@ retry_multishot:
                }
                if (ret > 0 && io_net_retry(sock, flags)) {
                        sr->done_io += ret;
-                       req->flags |= REQ_F_PARTIAL_IO;
+                       req->flags |= REQ_F_BL_NO_RECYCLE;
                        return io_setup_async_msg(req, kmsg, issue_flags);
                }
                if (ret == -ERESTARTSYS)
@@ -875,13 +910,10 @@ retry_multishot:
        if (!io_recv_finish(req, &ret, &kmsg->msg, mshot_finished, issue_flags))
                goto retry_multishot;
 
-       if (mshot_finished) {
-               /* fast path, check for non-NULL to avoid function call */
-               if (kmsg->free_iov)
-                       kfree(kmsg->free_iov);
-               io_netmsg_recycle(req, issue_flags);
-               req->flags &= ~REQ_F_NEED_CLEANUP;
-       }
+       if (mshot_finished)
+               io_req_msg_cleanup(req, kmsg, issue_flags);
+       else if (ret == -EAGAIN)
+               return io_setup_async_msg(req, kmsg, issue_flags);
 
        return ret;
 }
@@ -900,9 +932,6 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags)
            (sr->flags & IORING_RECVSEND_POLL_FIRST))
                return -EAGAIN;
 
-       if (!io_check_multishot(req, issue_flags))
-               return -EAGAIN;
-
        sock = sock_from_file(req->file);
        if (unlikely(!sock))
                return -ENOTSOCK;
@@ -915,6 +944,10 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags)
        msg.msg_iocb = NULL;
        msg.msg_ubuf = NULL;
 
+       flags = sr->msg_flags;
+       if (force_nonblock)
+               flags |= MSG_DONTWAIT;
+
 retry_multishot:
        if (io_do_buffer_select(req)) {
                void __user *buf;
@@ -933,9 +966,6 @@ retry_multishot:
        msg.msg_inq = -1;
        msg.msg_flags = 0;
 
-       flags = sr->msg_flags;
-       if (force_nonblock)
-               flags |= MSG_DONTWAIT;
        if (flags & MSG_WAITALL)
                min_ret = iov_iter_count(&msg.msg_iter);
 
@@ -953,7 +983,7 @@ retry_multishot:
                        sr->len -= ret;
                        sr->buf += ret;
                        sr->done_io += ret;
-                       req->flags |= REQ_F_PARTIAL_IO;
+                       req->flags |= REQ_F_BL_NO_RECYCLE;
                        return -EAGAIN;
                }
                if (ret == -ERESTARTSYS)
@@ -1003,6 +1033,8 @@ int io_send_zc_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        struct io_ring_ctx *ctx = req->ctx;
        struct io_kiocb *notif;
 
+       zc->done_io = 0;
+
        if (unlikely(READ_ONCE(sqe->__pad2[0]) || READ_ONCE(sqe->addr3)))
                return -EINVAL;
        /* we don't support IOSQE_CQE_SKIP_SUCCESS just yet */
@@ -1055,8 +1087,6 @@ int io_send_zc_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        if (zc->msg_flags & MSG_DONTWAIT)
                req->flags |= REQ_F_NOWAIT;
 
-       zc->done_io = 0;
-
 #ifdef CONFIG_COMPAT
        if (req->ctx->compat)
                zc->msg_flags |= MSG_CMSG_COMPAT;
@@ -1196,7 +1226,7 @@ int io_send_zc(struct io_kiocb *req, unsigned int issue_flags)
                        zc->len -= ret;
                        zc->buf += ret;
                        zc->done_io += ret;
-                       req->flags |= REQ_F_PARTIAL_IO;
+                       req->flags |= REQ_F_BL_NO_RECYCLE;
                        return io_setup_async_addr(req, &__address, issue_flags);
                }
                if (ret == -ERESTARTSYS)
@@ -1266,7 +1296,7 @@ int io_sendmsg_zc(struct io_kiocb *req, unsigned int issue_flags)
 
                if (ret > 0 && io_net_retry(sock, flags)) {
                        sr->done_io += ret;
-                       req->flags |= REQ_F_PARTIAL_IO;
+                       req->flags |= REQ_F_BL_NO_RECYCLE;
                        return io_setup_async_msg(req, kmsg, issue_flags);
                }
                if (ret == -ERESTARTSYS)
@@ -1301,7 +1331,7 @@ void io_sendrecv_fail(struct io_kiocb *req)
 {
        struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
 
-       if (req->flags & REQ_F_PARTIAL_IO)
+       if (sr->done_io)
                req->cqe.res = sr->done_io;
 
        if ((req->flags & REQ_F_NEED_CLEANUP) &&
@@ -1351,8 +1381,6 @@ int io_accept(struct io_kiocb *req, unsigned int issue_flags)
        struct file *file;
        int ret, fd;
 
-       if (!io_check_multishot(req, issue_flags))
-               return -EAGAIN;
 retry:
        if (!fixed) {
                fd = __get_unused_fd_flags(accept->flags, accept->nofile);
@@ -1372,7 +1400,7 @@ retry:
                         * has already been done
                         */
                        if (issue_flags & IO_URING_F_MULTISHOT)
-                               ret = IOU_ISSUE_SKIP_COMPLETE;
+                               return IOU_ISSUE_SKIP_COMPLETE;
                        return ret;
                }
                if (ret == -ERESTARTSYS)
@@ -1397,7 +1425,8 @@ retry:
                                ret, IORING_CQE_F_MORE))
                goto retry;
 
-       return -ECANCELED;
+       io_req_set_res(req, ret, 0);
+       return IOU_STOP_MULTISHOT;
 }
 
 int io_socket_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
index b1ee3a9c38072933dd020848b7f3586af257d912..9c080aadc5a662f5fb9e8a15fd9a0f956405fb76 100644 (file)
@@ -35,6 +35,7 @@
 #include "rw.h"
 #include "waitid.h"
 #include "futex.h"
+#include "truncate.h"
 
 static int io_no_issue(struct io_kiocb *req, unsigned int issue_flags)
 {
@@ -474,6 +475,12 @@ const struct io_issue_def io_issue_defs[] = {
                .prep                   = io_install_fixed_fd_prep,
                .issue                  = io_install_fixed_fd,
        },
+       [IORING_OP_FTRUNCATE] = {
+               .needs_file             = 1,
+               .hash_reg_file          = 1,
+               .prep                   = io_ftruncate_prep,
+               .issue                  = io_ftruncate,
+       },
 };
 
 const struct io_cold_def io_cold_defs[] = {
@@ -712,6 +719,9 @@ const struct io_cold_def io_cold_defs[] = {
        [IORING_OP_FIXED_FD_INSTALL] = {
                .name                   = "FIXED_FD_INSTALL",
        },
+       [IORING_OP_FTRUNCATE] = {
+               .name                   = "FTRUNCATE",
+       },
 };
 
 const char *io_uring_get_opcode(u8 opcode)
index 7513afc7b702e4cbc727717fc59aa8eb758465df..5f779139cae1849e30f6caaae484c060f938febc 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "io_uring.h"
 #include "refs.h"
+#include "napi.h"
 #include "opdef.h"
 #include "kbuf.h"
 #include "poll.h"
@@ -343,8 +344,8 @@ static int io_poll_check_events(struct io_kiocb *req, struct io_tw_state *ts)
                 * Release all references, retry if someone tried to restart
                 * task_work while we were executing it.
                 */
-       } while (atomic_sub_return(v & IO_POLL_REF_MASK, &req->poll_refs) &
-                                       IO_POLL_REF_MASK);
+               v &= IO_POLL_REF_MASK;
+       } while (atomic_sub_return(v, &req->poll_refs) & IO_POLL_REF_MASK);
 
        return IOU_POLL_NO_ACTION;
 }
@@ -539,14 +540,6 @@ static void __io_queue_proc(struct io_poll *poll, struct io_poll_table *pt,
        poll->wait.private = (void *) wqe_private;
 
        if (poll->events & EPOLLEXCLUSIVE) {
-               /*
-                * Exclusive waits may only wake a limited amount of entries
-                * rather than all of them, this may interfere with lazy
-                * wake if someone does wait(events > 1). Ensure we don't do
-                * lazy wake for those, as we need to process each one as they
-                * come in.
-                */
-               req->flags |= REQ_F_POLL_NO_LAZY;
                add_wait_queue_exclusive(head, &poll->wait);
        } else {
                add_wait_queue(head, &poll->wait);
@@ -588,10 +581,7 @@ static int __io_arm_poll_handler(struct io_kiocb *req,
                                 struct io_poll_table *ipt, __poll_t mask,
                                 unsigned issue_flags)
 {
-       struct io_ring_ctx *ctx = req->ctx;
-
        INIT_HLIST_NODE(&req->hash_node);
-       req->work.cancel_seq = atomic_read(&ctx->cancel_seq);
        io_init_poll_iocb(poll, mask);
        poll->file = req->file;
        req->apoll_events = poll->events;
@@ -618,6 +608,17 @@ static int __io_arm_poll_handler(struct io_kiocb *req,
        if (issue_flags & IO_URING_F_UNLOCKED)
                req->flags &= ~REQ_F_HASH_LOCKED;
 
+
+       /*
+        * Exclusive waits may only wake a limited amount of entries
+        * rather than all of them, this may interfere with lazy
+        * wake if someone does wait(events > 1). Ensure we don't do
+        * lazy wake for those, as we need to process each one as they
+        * come in.
+        */
+       if (poll->events & EPOLLEXCLUSIVE)
+               req->flags |= REQ_F_POLL_NO_LAZY;
+
        mask = vfs_poll(req->file, &ipt->pt) & poll->events;
 
        if (unlikely(ipt->error || !ipt->nr_entries)) {
@@ -652,6 +653,7 @@ static int __io_arm_poll_handler(struct io_kiocb *req,
                __io_poll_execute(req, mask);
                return 0;
        }
+       io_napi_add(req);
 
        if (ipt->owning) {
                /*
@@ -727,7 +729,7 @@ int io_arm_poll_handler(struct io_kiocb *req, unsigned issue_flags)
 
        if (!def->pollin && !def->pollout)
                return IO_APOLL_ABORTED;
-       if (!file_can_poll(req->file))
+       if (!io_file_can_poll(req))
                return IO_APOLL_ABORTED;
        if (!(req->flags & REQ_F_APOLL_MULTISHOT))
                mask |= EPOLLONESHOT;
@@ -818,9 +820,8 @@ static struct io_kiocb *io_poll_find(struct io_ring_ctx *ctx, bool poll_only,
                if (poll_only && req->opcode != IORING_OP_POLL_ADD)
                        continue;
                if (cd->flags & IORING_ASYNC_CANCEL_ALL) {
-                       if (cd->seq == req->work.cancel_seq)
+                       if (io_cancel_match_sequence(req, cd->seq))
                                continue;
-                       req->work.cancel_seq = cd->seq;
                }
                *out_bucket = hb;
                return req;
index 5e62c1208996542537c6aedf4d57506863165e10..99c37775f974c02a1c2f99d244af69a7c69c4ed3 100644 (file)
@@ -26,6 +26,7 @@
 #include "register.h"
 #include "cancel.h"
 #include "kbuf.h"
+#include "napi.h"
 
 #define IORING_MAX_RESTRICTIONS        (IORING_RESTRICTION_LAST + \
                                 IORING_REGISTER_LAST + IORING_OP_LAST)
@@ -550,6 +551,18 @@ static int __io_uring_register(struct io_ring_ctx *ctx, unsigned opcode,
                        break;
                ret = io_register_pbuf_status(ctx, arg);
                break;
+       case IORING_REGISTER_NAPI:
+               ret = -EINVAL;
+               if (!arg || nr_args != 1)
+                       break;
+               ret = io_register_napi(ctx, arg);
+               break;
+       case IORING_UNREGISTER_NAPI:
+               ret = -EINVAL;
+               if (nr_args != 1)
+                       break;
+               ret = io_unregister_napi(ctx, arg);
+               break;
        default:
                ret = -EINVAL;
                break;
index c6f199bbee2843dfea2d88729b707d46a168d3d9..e210002389540b671e9cb1f00dcbff4303ae2f75 100644 (file)
@@ -2,8 +2,6 @@
 #ifndef IOU_RSRC_H
 #define IOU_RSRC_H
 
-#include <net/af_unix.h>
-
 #include "alloc_cache.h"
 
 #define IO_NODE_ALLOC_CACHE_MAX 32
index d5e79d9bdc717b8cb917d6e06b2cbbe6840dd762..47e097ab5d7e4f2e0617146cb5c139dc3b92a667 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/nospec.h>
 #include <linux/compat.h>
 #include <linux/io_uring/cmd.h>
+#include <linux/indirect_call_wrapper.h>
 
 #include <uapi/linux/io_uring.h>
 
@@ -274,7 +275,7 @@ static bool __io_complete_rw_common(struct io_kiocb *req, long res)
                         * current cycle.
                         */
                        io_req_io_end(req);
-                       req->flags |= REQ_F_REISSUE | REQ_F_PARTIAL_IO;
+                       req->flags |= REQ_F_REISSUE | REQ_F_BL_NO_RECYCLE;
                        return true;
                }
                req_set_fail(req);
@@ -341,7 +342,7 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)
                io_req_end_write(req);
        if (unlikely(res != req->cqe.res)) {
                if (res == -EAGAIN && io_rw_should_reissue(req)) {
-                       req->flags |= REQ_F_REISSUE | REQ_F_PARTIAL_IO;
+                       req->flags |= REQ_F_REISSUE | REQ_F_BL_NO_RECYCLE;
                        return;
                }
                req->cqe.res = res;
@@ -682,7 +683,7 @@ static bool io_rw_should_retry(struct io_kiocb *req)
         * just use poll if we can, and don't attempt if the fs doesn't
         * support callback based unlocks
         */
-       if (file_can_poll(req->file) || !(req->file->f_mode & FMODE_BUF_RASYNC))
+       if (io_file_can_poll(req) || !(req->file->f_mode & FMODE_BUF_RASYNC))
                return false;
 
        wait->wait.func = io_async_buf_func;
@@ -721,7 +722,7 @@ static int io_rw_init_file(struct io_kiocb *req, fmode_t mode)
        struct file *file = req->file;
        int ret;
 
-       if (unlikely(!file || !(file->f_mode & mode)))
+       if (unlikely(!(file->f_mode & mode)))
                return -EBADF;
 
        if (!(req->flags & REQ_F_FIXED_FILE))
@@ -831,7 +832,7 @@ static int __io_read(struct io_kiocb *req, unsigned int issue_flags)
                 * If we can poll, just do that. For a vectored read, we'll
                 * need to copy state first.
                 */
-               if (file_can_poll(req->file) && !io_issue_defs[req->opcode].vectored)
+               if (io_file_can_poll(req) && !io_issue_defs[req->opcode].vectored)
                        return -EAGAIN;
                /* IOPOLL retry should happen for io-wq threads */
                if (!force_nonblock && !(req->ctx->flags & IORING_SETUP_IOPOLL))
@@ -930,7 +931,7 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
        /*
         * Multishot MUST be used on a pollable file
         */
-       if (!file_can_poll(req->file))
+       if (!io_file_can_poll(req))
                return -EBADFD;
 
        ret = __io_read(req, issue_flags);
index 65b5dbe3c850ed564432c76f17e64739d430f2fe..363052b4ea76a218f2266f543203631a08d0502b 100644 (file)
 #include <uapi/linux/io_uring.h>
 
 #include "io_uring.h"
+#include "napi.h"
 #include "sqpoll.h"
 
 #define IORING_SQPOLL_CAP_ENTRIES_VALUE 8
+#define IORING_TW_CAP_ENTRIES_VALUE    8
 
 enum {
        IO_SQ_THREAD_SHOULD_STOP = 0,
@@ -193,6 +195,9 @@ static int __io_sq_thread(struct io_ring_ctx *ctx, bool cap_entries)
                        ret = io_submit_sqes(ctx, to_submit);
                mutex_unlock(&ctx->uring_lock);
 
+               if (io_napi(ctx))
+                       ret += io_napi_sqpoll_busy_poll(ctx);
+
                if (to_submit && wq_has_sleeper(&ctx->sqo_sq_wait))
                        wake_up(&ctx->sqo_sq_wait);
                if (creds)
@@ -219,10 +224,52 @@ static bool io_sqd_handle_event(struct io_sq_data *sqd)
        return did_sig || test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
 }
 
+/*
+ * Run task_work, processing the retry_list first. The retry_list holds
+ * entries that we passed on in the previous run, if we had more task_work
+ * than we were asked to process. Newly queued task_work isn't run until the
+ * retry list has been fully processed.
+ */
+static unsigned int io_sq_tw(struct llist_node **retry_list, int max_entries)
+{
+       struct io_uring_task *tctx = current->io_uring;
+       unsigned int count = 0;
+
+       if (*retry_list) {
+               *retry_list = io_handle_tw_list(*retry_list, &count, max_entries);
+               if (count >= max_entries)
+                       return count;
+               max_entries -= count;
+       }
+
+       *retry_list = tctx_task_work_run(tctx, max_entries, &count);
+       return count;
+}
+
+static bool io_sq_tw_pending(struct llist_node *retry_list)
+{
+       struct io_uring_task *tctx = current->io_uring;
+
+       return retry_list || !llist_empty(&tctx->task_list);
+}
+
+static void io_sq_update_worktime(struct io_sq_data *sqd, struct rusage *start)
+{
+       struct rusage end;
+
+       getrusage(current, RUSAGE_SELF, &end);
+       end.ru_stime.tv_sec -= start->ru_stime.tv_sec;
+       end.ru_stime.tv_usec -= start->ru_stime.tv_usec;
+
+       sqd->work_time += end.ru_stime.tv_usec + end.ru_stime.tv_sec * 1000000;
+}
+
 static int io_sq_thread(void *data)
 {
+       struct llist_node *retry_list = NULL;
        struct io_sq_data *sqd = data;
        struct io_ring_ctx *ctx;
+       struct rusage start;
        unsigned long timeout = 0;
        char buf[TASK_COMM_LEN];
        DEFINE_WAIT(wait);
@@ -251,18 +298,21 @@ static int io_sq_thread(void *data)
                }
 
                cap_entries = !list_is_singular(&sqd->ctx_list);
+               getrusage(current, RUSAGE_SELF, &start);
                list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) {
                        int ret = __io_sq_thread(ctx, cap_entries);
 
                        if (!sqt_spin && (ret > 0 || !wq_list_empty(&ctx->iopoll_list)))
                                sqt_spin = true;
                }
-               if (io_run_task_work())
+               if (io_sq_tw(&retry_list, IORING_TW_CAP_ENTRIES_VALUE))
                        sqt_spin = true;
 
                if (sqt_spin || !time_after(jiffies, timeout)) {
-                       if (sqt_spin)
+                       if (sqt_spin) {
+                               io_sq_update_worktime(sqd, &start);
                                timeout = jiffies + sqd->sq_thread_idle;
+                       }
                        if (unlikely(need_resched())) {
                                mutex_unlock(&sqd->lock);
                                cond_resched();
@@ -273,7 +323,7 @@ static int io_sq_thread(void *data)
                }
 
                prepare_to_wait(&sqd->wait, &wait, TASK_INTERRUPTIBLE);
-               if (!io_sqd_events_pending(sqd) && !task_work_pending(current)) {
+               if (!io_sqd_events_pending(sqd) && !io_sq_tw_pending(retry_list)) {
                        bool needs_sched = true;
 
                        list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) {
@@ -312,6 +362,9 @@ static int io_sq_thread(void *data)
                timeout = jiffies + sqd->sq_thread_idle;
        }
 
+       if (retry_list)
+               io_sq_tw(&retry_list, UINT_MAX);
+
        io_uring_cancel_generic(true, sqd);
        sqd->thread = NULL;
        list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
index 8df37e8c914936d777b9d0495796c236f41e5189..4171666b1cf4cc37b84cb4079483bdf7b762add1 100644 (file)
@@ -16,6 +16,7 @@ struct io_sq_data {
        pid_t                   task_pid;
        pid_t                   task_tgid;
 
+       u64                     work_time;
        unsigned long           state;
        struct completion       exited;
 };
diff --git a/io_uring/truncate.c b/io_uring/truncate.c
new file mode 100644 (file)
index 0000000..62ee73d
--- /dev/null
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "../fs/internal.h"
+
+#include "io_uring.h"
+#include "truncate.h"
+
+struct io_ftrunc {
+       struct file                     *file;
+       loff_t                          len;
+};
+
+int io_ftruncate_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_ftrunc *ft = io_kiocb_to_cmd(req, struct io_ftrunc);
+
+       if (sqe->rw_flags || sqe->addr || sqe->len || sqe->buf_index ||
+           sqe->splice_fd_in || sqe->addr3)
+               return -EINVAL;
+
+       ft->len = READ_ONCE(sqe->off);
+
+       req->flags |= REQ_F_FORCE_ASYNC;
+       return 0;
+}
+
+int io_ftruncate(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_ftrunc *ft = io_kiocb_to_cmd(req, struct io_ftrunc);
+       int ret;
+
+       WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
+
+       ret = do_ftruncate(req->file, ft->len, 1);
+
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
diff --git a/io_uring/truncate.h b/io_uring/truncate.h
new file mode 100644 (file)
index 0000000..ec08829
--- /dev/null
@@ -0,0 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int io_ftruncate_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_ftruncate(struct io_kiocb *req, unsigned int issue_flags);
index c33fca585dde5ceb993b80d88025a9d9a61c9ae7..42f63adfa54a04f0b8c67a3babb7415b2bcc96bc 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/io_uring/cmd.h>
 #include <linux/security.h>
 #include <linux/nospec.h>
+#include <net/sock.h>
 
 #include <uapi/linux/io_uring.h>
 #include <asm/ioctls.h>
index e1c810e0b85a422435979a89d1edd9dfb04d6c22..44905b82eea8305d0cf40080fe3c6cb71fa6e985 100644 (file)
@@ -112,7 +112,7 @@ int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
 
        WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
 
-       ret = do_getxattr(mnt_idmap(req->file->f_path.mnt),
+       ret = do_getxattr(file_mnt_idmap(req->file),
                        req->file->f_path.dentry,
                        &ix->ctx);
 
index 97f224a5257b4e49ed959580ae1566a46e09f3fe..4c3e6a44595fa176f06108c869d164cca26546a1 100644 (file)
@@ -64,6 +64,7 @@ static async_cookie_t next_cookie = 1;
 static LIST_HEAD(async_global_pending);        /* pending from all registered doms */
 static ASYNC_DOMAIN(async_dfl_domain);
 static DEFINE_SPINLOCK(async_lock);
+static struct workqueue_struct *async_wq;
 
 struct async_entry {
        struct list_head        domain_list;
@@ -174,7 +175,7 @@ static async_cookie_t __async_schedule_node_domain(async_func_t func,
        spin_unlock_irqrestore(&async_lock, flags);
 
        /* schedule for execution */
-       queue_work_node(node, system_unbound_wq, &entry->work);
+       queue_work_node(node, async_wq, &entry->work);
 
        return newcookie;
 }
@@ -345,3 +346,17 @@ bool current_is_async(void)
        return worker && worker->current_func == async_run_entry_fn;
 }
 EXPORT_SYMBOL_GPL(current_is_async);
+
+void __init async_init(void)
+{
+       /*
+        * Async can schedule a number of interdependent work items. However,
+        * unbound workqueues can handle only upto min_active interdependent
+        * work items. The default min_active of 8 isn't sufficient for async
+        * and can lead to stalls. Let's use a dedicated workqueue with raised
+        * min_active.
+        */
+       async_wq = alloc_workqueue("async", WQ_UNBOUND, 0);
+       BUG_ON(!async_wq);
+       workqueue_set_min_active(async_wq, WQ_DFL_ACTIVE);
+}
index 370217dd7e39a42ba6943a96c27c3d1101408cb5..a4181234232bc9fc5bada1cfec89160a9429ff81 100644 (file)
@@ -21,24 +21,20 @@ static void backtrace_test_normal(void)
        dump_stack();
 }
 
-static DECLARE_COMPLETION(backtrace_work);
-
-static void backtrace_test_irq_callback(unsigned long data)
+static void backtrace_test_bh_workfn(struct work_struct *work)
 {
        dump_stack();
-       complete(&backtrace_work);
 }
 
-static DECLARE_TASKLET_OLD(backtrace_tasklet, &backtrace_test_irq_callback);
+static DECLARE_WORK(backtrace_bh_work, &backtrace_test_bh_workfn);
 
-static void backtrace_test_irq(void)
+static void backtrace_test_bh(void)
 {
-       pr_info("Testing a backtrace from irq context.\n");
+       pr_info("Testing a backtrace from BH context.\n");
        pr_info("The following trace is a kernel self test and not a bug!\n");
 
-       init_completion(&backtrace_work);
-       tasklet_schedule(&backtrace_tasklet);
-       wait_for_completion(&backtrace_work);
+       queue_work(system_bh_wq, &backtrace_bh_work);
+       flush_work(&backtrace_bh_work);
 }
 
 #ifdef CONFIG_STACKTRACE
@@ -65,7 +61,7 @@ static int backtrace_regression_test(void)
        pr_info("====[ backtrace testing ]===========\n");
 
        backtrace_test_normal();
-       backtrace_test_irq();
+       backtrace_test_bh();
        backtrace_test_saved();
 
        pr_info("====[ end of backtrace testing ]====\n");
index 8a0bb80fe48a344964e4029fec5e895ee512babf..ef82ffc90cbe9d7aeab50c4856b45a52621a90a9 100644 (file)
@@ -178,7 +178,7 @@ static int cpu_map_bpf_prog_run_xdp(struct bpf_cpu_map_entry *rcpu,
                                    void **frames, int n,
                                    struct xdp_cpumap_stats *stats)
 {
-       struct xdp_rxq_info rxq;
+       struct xdp_rxq_info rxq = {};
        struct xdp_buff xdp;
        int i, nframes = 0;
 
index be72824f32b2cc5e3dfcb8d2bd613b86116a498c..d19cd863d294ea1b589aeae327ae6b10e7211a93 100644 (file)
@@ -1101,6 +1101,7 @@ struct bpf_hrtimer {
        struct bpf_prog *prog;
        void __rcu *callback_fn;
        void *value;
+       struct rcu_head rcu;
 };
 
 /* the actual struct hidden inside uapi struct bpf_timer */
@@ -1332,6 +1333,7 @@ BPF_CALL_1(bpf_timer_cancel, struct bpf_timer_kern *, timer)
 
        if (in_nmi())
                return -EOPNOTSUPP;
+       rcu_read_lock();
        __bpf_spin_lock_irqsave(&timer->lock);
        t = timer->timer;
        if (!t) {
@@ -1353,6 +1355,7 @@ out:
         * if it was running.
         */
        ret = ret ?: hrtimer_cancel(&t->timer);
+       rcu_read_unlock();
        return ret;
 }
 
@@ -1407,7 +1410,7 @@ out:
         */
        if (this_cpu_read(hrtimer_running) != t)
                hrtimer_cancel(&t->timer);
-       kfree(t);
+       kfree_rcu(t, rcu);
 }
 
 BPF_CALL_2(bpf_kptr_xchg, void *, map_value, void *, ptr)
index e5c3500443c6e71f4fca7a6403dc33aa054d6fd8..ec4e97c61eefe667955e984b934f354b9162b52d 100644 (file)
@@ -978,6 +978,8 @@ __bpf_kfunc int bpf_iter_task_new(struct bpf_iter_task *it,
        BUILD_BUG_ON(__alignof__(struct bpf_iter_task_kern) !=
                                        __alignof__(struct bpf_iter_task));
 
+       kit->pos = NULL;
+
        switch (flags) {
        case BPF_TASK_ITER_ALL_THREADS:
        case BPF_TASK_ITER_ALL_PROCS:
index 65f598694d550359f2b926ef26ae30d0c80c6f69..ddea9567f755946501cd2dc92aef56057ddee41d 100644 (file)
@@ -5227,7 +5227,9 @@ BTF_ID(struct, prog_test_ref_kfunc)
 #ifdef CONFIG_CGROUPS
 BTF_ID(struct, cgroup)
 #endif
+#ifdef CONFIG_BPF_JIT
 BTF_ID(struct, bpf_cpumask)
+#endif
 BTF_ID(struct, task_struct)
 BTF_SET_END(rcu_protected_types)
 
@@ -16600,6 +16602,9 @@ static bool func_states_equal(struct bpf_verifier_env *env, struct bpf_func_stat
 {
        int i;
 
+       if (old->callback_depth > cur->callback_depth)
+               return false;
+
        for (i = 0; i < MAX_BPF_REG; i++)
                if (!regsafe(env, &old->regs[i], &cur->regs[i],
                             &env->idmap_scratch, exact))
index ba36c073304a3eee081b770b12dacb0e5b1a60cd..4237c8748715d4c66f2d46787fb7297643abcddb 100644 (file)
@@ -2562,7 +2562,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
                update_partition_sd_lb(cs, old_prs);
 out_free:
        free_cpumasks(NULL, &tmp);
-       return 0;
+       return retval;
 }
 
 /**
@@ -2598,9 +2598,6 @@ static int update_exclusive_cpumask(struct cpuset *cs, struct cpuset *trialcs,
        if (cpumask_equal(cs->exclusive_cpus, trialcs->exclusive_cpus))
                return 0;
 
-       if (alloc_cpumasks(NULL, &tmp))
-               return -ENOMEM;
-
        if (*buf)
                compute_effective_exclusive_cpumask(trialcs, NULL);
 
@@ -2615,6 +2612,9 @@ static int update_exclusive_cpumask(struct cpuset *cs, struct cpuset *trialcs,
        if (retval)
                return retval;
 
+       if (alloc_cpumasks(NULL, &tmp))
+               return -ENOMEM;
+
        if (old_prs) {
                if (cpumask_empty(trialcs->effective_xcpus)) {
                        invalidate = true;
@@ -3897,6 +3897,7 @@ static struct cftype legacy_files[] = {
        },
 
        {
+               /* obsolete, may be removed in the future */
                .name = "memory_spread_slab",
                .read_u64 = cpuset_read_u64,
                .write_u64 = cpuset_write_u64,
index 6ef0b35fc28c5a50434837f89d798060a58e26b9..70ae70d0382337e1d7c361926b7162bd21cda9be 100644 (file)
@@ -458,6 +458,8 @@ static __always_inline void context_tracking_recursion_exit(void)
  * __ct_user_enter - Inform the context tracking that the CPU is going
  *                  to enter user or guest space mode.
  *
+ * @state: userspace context-tracking state to enter.
+ *
  * This function must be called right before we switch from the kernel
  * to user or guest space, when it's guaranteed the remaining kernel
  * instructions to execute won't use any RCU read side critical section
@@ -595,6 +597,8 @@ NOKPROBE_SYMBOL(user_enter_callable);
  * __ct_user_exit - Inform the context tracking that the CPU is
  *                 exiting user or guest mode and entering the kernel.
  *
+ * @state: userspace context-tracking state being exited from.
+ *
  * This function must be called after we entered the kernel from user or
  * guest space before any use of RCU read side critical section. This
  * potentially include any high level kernel code like syscalls, exceptions,
index e6ec3ba4950b48c0afa6665aba2824456dc409f5..8f6affd051f77564f96ca4682a58d0c131f62c56 100644 (file)
@@ -54,7 +54,6 @@
  * @rollback:  Perform a rollback
  * @single:    Single callback invocation
  * @bringup:   Single callback bringup or teardown selector
- * @cpu:       CPU number
  * @node:      Remote CPU node; for multi-instance, do a
  *             single entry callback for install/remove
  * @last:      For multi-instance rollback, remember how far we got
@@ -1324,10 +1323,6 @@ static int take_cpu_down(void *_param)
         */
        cpuhp_invoke_callback_range_nofail(false, cpu, st, target);
 
-       /* Give up timekeeping duties */
-       tick_handover_do_timer();
-       /* Remove CPU from timer broadcasting */
-       tick_offline_cpu(cpu);
        /* Park the stopper thread */
        stop_machine_park(cpu);
        return 0;
@@ -1403,6 +1398,7 @@ void cpuhp_report_idle_dead(void)
        struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
 
        BUG_ON(st->state != CPUHP_AP_OFFLINE);
+       tick_assert_timekeeping_handover();
        rcutree_report_cpu_dead();
        st->state = CPUHP_AP_IDLE_DEAD;
        /*
@@ -1909,14 +1905,14 @@ static bool __init cpuhp_bringup_cpus_parallel(unsigned int ncpus)
 static inline bool cpuhp_bringup_cpus_parallel(unsigned int ncpus) { return false; }
 #endif /* CONFIG_HOTPLUG_PARALLEL */
 
-void __init bringup_nonboot_cpus(unsigned int setup_max_cpus)
+void __init bringup_nonboot_cpus(unsigned int max_cpus)
 {
        /* Try parallel bringup optimization if enabled */
-       if (cpuhp_bringup_cpus_parallel(setup_max_cpus))
+       if (cpuhp_bringup_cpus_parallel(max_cpus))
                return;
 
        /* Full per CPU serialized bringup */
-       cpuhp_bringup_mask(cpu_present_mask, setup_max_cpus, CPUHP_ONLINE);
+       cpuhp_bringup_mask(cpu_present_mask, max_cpus, CPUHP_ONLINE);
 }
 
 #ifdef CONFIG_PM_SLEEP_SMP
@@ -2205,7 +2201,11 @@ static struct cpuhp_step cpuhp_hp_states[] = {
                .startup.single         = NULL,
                .teardown.single        = hrtimers_cpu_dying,
        },
-
+       [CPUHP_AP_TICK_DYING] = {
+               .name                   = "tick:dying",
+               .startup.single         = NULL,
+               .teardown.single        = tick_cpu_dying,
+       },
        /* Entry state on starting. Interrupts enabled from here on. Transient
         * state for synchronsization */
        [CPUHP_AP_ONLINE] = {
@@ -3005,7 +3005,7 @@ static ssize_t control_show(struct device *dev,
                return sysfs_emit(buf, "%d\n", cpu_smt_num_threads);
 #endif
 
-       return snprintf(buf, PAGE_SIZE - 2, "%s\n", state);
+       return sysfs_emit(buf, "%s\n", state);
 }
 
 static ssize_t control_store(struct device *dev, struct device_attribute *attr,
@@ -3018,7 +3018,7 @@ static DEVICE_ATTR_RW(control);
 static ssize_t active_show(struct device *dev,
                           struct device_attribute *attr, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE - 2, "%d\n", sched_smt_active());
+       return sysfs_emit(buf, "%d\n", sched_smt_active());
 }
 static DEVICE_ATTR_RO(active);
 
@@ -3107,10 +3107,10 @@ const DECLARE_BITMAP(cpu_all_bits, NR_CPUS) = CPU_BITS_ALL;
 EXPORT_SYMBOL(cpu_all_bits);
 
 #ifdef CONFIG_INIT_ALL_POSSIBLE
-struct cpumask __cpu_possible_mask __read_mostly
+struct cpumask __cpu_possible_mask __ro_after_init
        = {CPU_BITS_ALL};
 #else
-struct cpumask __cpu_possible_mask __read_mostly;
+struct cpumask __cpu_possible_mask __ro_after_init;
 #endif
 EXPORT_SYMBOL(__cpu_possible_mask);
 
index dfb963d2f862ada6a2f06259c6df4923272cb218..41a12630cbbc9cd80b6b5a154041c514b46ad3fe 100644 (file)
@@ -739,6 +739,13 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
                kill_orphaned_pgrp(tsk->group_leader, NULL);
 
        tsk->exit_state = EXIT_ZOMBIE;
+       /*
+        * sub-thread or delay_group_leader(), wake up the
+        * PIDFD_THREAD waiters.
+        */
+       if (!thread_group_empty(tsk))
+               do_notify_pidfd(tsk);
+
        if (unlikely(tsk->ptrace)) {
                int sig = thread_group_leader(tsk) &&
                                thread_group_empty(tsk) &&
@@ -1889,30 +1896,6 @@ Efault:
 }
 #endif
 
-/**
- * thread_group_exited - check that a thread group has exited
- * @pid: tgid of thread group to be checked.
- *
- * Test if the thread group represented by tgid has exited (all
- * threads are zombies, dead or completely gone).
- *
- * Return: true if the thread group has exited. false otherwise.
- */
-bool thread_group_exited(struct pid *pid)
-{
-       struct task_struct *task;
-       bool exited;
-
-       rcu_read_lock();
-       task = pid_task(pid, PIDTYPE_PID);
-       exited = !task ||
-               (READ_ONCE(task->exit_state) && thread_group_empty(task));
-       rcu_read_unlock();
-
-       return exited;
-}
-EXPORT_SYMBOL(thread_group_exited);
-
 /*
  * This needs to be __function_aligned as GCC implicitly makes any
  * implementation of abort() cold and drops alignment specified by
index 0d944e92a43ffa13bdbcce6c6a28c44bab29ca19..39a5046c2f0bf49e1bcade15c4c3c5574742b09d 100644 (file)
 #include <linux/user_events.h>
 #include <linux/iommu.h>
 #include <linux/rseq.h>
+#include <uapi/linux/pidfd.h>
+#include <linux/pidfs.h>
 
 #include <asm/pgalloc.h>
 #include <linux/uaccess.h>
@@ -1976,6 +1978,7 @@ static inline void rcu_copy_process(struct task_struct *p)
        p->rcu_tasks_holdout = false;
        INIT_LIST_HEAD(&p->rcu_tasks_holdout_list);
        p->rcu_tasks_idle_cpu = -1;
+       INIT_LIST_HEAD(&p->rcu_tasks_exit_list);
 #endif /* #ifdef CONFIG_TASKS_RCU */
 #ifdef CONFIG_TASKS_TRACE_RCU
        p->trc_reader_nesting = 0;
@@ -1985,119 +1988,6 @@ static inline void rcu_copy_process(struct task_struct *p)
 #endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
 }
 
-struct pid *pidfd_pid(const struct file *file)
-{
-       if (file->f_op == &pidfd_fops)
-               return file->private_data;
-
-       return ERR_PTR(-EBADF);
-}
-
-static int pidfd_release(struct inode *inode, struct file *file)
-{
-       struct pid *pid = file->private_data;
-
-       file->private_data = NULL;
-       put_pid(pid);
-       return 0;
-}
-
-#ifdef CONFIG_PROC_FS
-/**
- * pidfd_show_fdinfo - print information about a pidfd
- * @m: proc fdinfo file
- * @f: file referencing a pidfd
- *
- * Pid:
- * This function will print the pid that a given pidfd refers to in the
- * pid namespace of the procfs instance.
- * If the pid namespace of the process is not a descendant of the pid
- * namespace of the procfs instance 0 will be shown as its pid. This is
- * similar to calling getppid() on a process whose parent is outside of
- * its pid namespace.
- *
- * NSpid:
- * If pid namespaces are supported then this function will also print
- * the pid of a given pidfd refers to for all descendant pid namespaces
- * starting from the current pid namespace of the instance, i.e. the
- * Pid field and the first entry in the NSpid field will be identical.
- * If the pid namespace of the process is not a descendant of the pid
- * namespace of the procfs instance 0 will be shown as its first NSpid
- * entry and no others will be shown.
- * Note that this differs from the Pid and NSpid fields in
- * /proc/<pid>/status where Pid and NSpid are always shown relative to
- * the  pid namespace of the procfs instance. The difference becomes
- * obvious when sending around a pidfd between pid namespaces from a
- * different branch of the tree, i.e. where no ancestral relation is
- * present between the pid namespaces:
- * - create two new pid namespaces ns1 and ns2 in the initial pid
- *   namespace (also take care to create new mount namespaces in the
- *   new pid namespace and mount procfs)
- * - create a process with a pidfd in ns1
- * - send pidfd from ns1 to ns2
- * - read /proc/self/fdinfo/<pidfd> and observe that both Pid and NSpid
- *   have exactly one entry, which is 0
- */
-static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
-{
-       struct pid *pid = f->private_data;
-       struct pid_namespace *ns;
-       pid_t nr = -1;
-
-       if (likely(pid_has_task(pid, PIDTYPE_PID))) {
-               ns = proc_pid_ns(file_inode(m->file)->i_sb);
-               nr = pid_nr_ns(pid, ns);
-       }
-
-       seq_put_decimal_ll(m, "Pid:\t", nr);
-
-#ifdef CONFIG_PID_NS
-       seq_put_decimal_ll(m, "\nNSpid:\t", nr);
-       if (nr > 0) {
-               int i;
-
-               /* If nr is non-zero it means that 'pid' is valid and that
-                * ns, i.e. the pid namespace associated with the procfs
-                * instance, is in the pid namespace hierarchy of pid.
-                * Start at one below the already printed level.
-                */
-               for (i = ns->level + 1; i <= pid->level; i++)
-                       seq_put_decimal_ll(m, "\t", pid->numbers[i].nr);
-       }
-#endif
-       seq_putc(m, '\n');
-}
-#endif
-
-/*
- * Poll support for process exit notification.
- */
-static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts)
-{
-       struct pid *pid = file->private_data;
-       __poll_t poll_flags = 0;
-
-       poll_wait(file, &pid->wait_pidfd, pts);
-
-       /*
-        * Inform pollers only when the whole thread group exits.
-        * If the thread group leader exits before all other threads in the
-        * group, then poll(2) should block, similar to the wait(2) family.
-        */
-       if (thread_group_exited(pid))
-               poll_flags = EPOLLIN | EPOLLRDNORM;
-
-       return poll_flags;
-}
-
-const struct file_operations pidfd_fops = {
-       .release = pidfd_release,
-       .poll = pidfd_poll,
-#ifdef CONFIG_PROC_FS
-       .show_fdinfo = pidfd_show_fdinfo,
-#endif
-};
-
 /**
  * __pidfd_prepare - allocate a new pidfd_file and reserve a pidfd
  * @pid:   the struct pid for which to create a pidfd
@@ -2131,20 +2021,20 @@ static int __pidfd_prepare(struct pid *pid, unsigned int flags, struct file **re
        int pidfd;
        struct file *pidfd_file;
 
-       if (flags & ~(O_NONBLOCK | O_RDWR | O_CLOEXEC))
-               return -EINVAL;
-
-       pidfd = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
+       pidfd = get_unused_fd_flags(O_CLOEXEC);
        if (pidfd < 0)
                return pidfd;
 
-       pidfd_file = anon_inode_getfile("[pidfd]", &pidfd_fops, pid,
-                                       flags | O_RDWR | O_CLOEXEC);
+       pidfd_file = pidfs_alloc_file(pid, flags | O_RDWR);
        if (IS_ERR(pidfd_file)) {
                put_unused_fd(pidfd);
                return PTR_ERR(pidfd_file);
        }
-       get_pid(pid); /* held by pidfd_file now */
+       /*
+        * anon_inode_getfile() ignores everything outside of the
+        * O_ACCMODE | O_NONBLOCK mask, set PIDFD_THREAD manually.
+        */
+       pidfd_file->f_flags |= (flags & PIDFD_THREAD);
        *ret = pidfd_file;
        return pidfd;
 }
@@ -2158,7 +2048,8 @@ static int __pidfd_prepare(struct pid *pid, unsigned int flags, struct file **re
  * Allocate a new file that stashes @pid and reserve a new pidfd number in the
  * caller's file descriptor table. The pidfd is reserved but not installed yet.
  *
- * The helper verifies that @pid is used as a thread group leader.
+ * The helper verifies that @pid is still in use, without PIDFD_THREAD the
+ * task identified by @pid must be a thread-group leader.
  *
  * If this function returns successfully the caller is responsible to either
  * call fd_install() passing the returned pidfd and pidfd file as arguments in
@@ -2177,7 +2068,9 @@ static int __pidfd_prepare(struct pid *pid, unsigned int flags, struct file **re
  */
 int pidfd_prepare(struct pid *pid, unsigned int flags, struct file **ret)
 {
-       if (!pid || !pid_has_task(pid, PIDTYPE_TGID))
+       bool thread = flags & PIDFD_THREAD;
+
+       if (!pid || !pid_has_task(pid, thread ? PIDTYPE_PID : PIDTYPE_TGID))
                return -EINVAL;
 
        return __pidfd_prepare(pid, flags, ret);
@@ -2299,9 +2192,8 @@ __latent_entropy struct task_struct *copy_process(
                /*
                 * - CLONE_DETACHED is blocked so that we can potentially
                 *   reuse it later for CLONE_PIDFD.
-                * - CLONE_THREAD is blocked until someone really needs it.
                 */
-               if (clone_flags & (CLONE_DETACHED | CLONE_THREAD))
+               if (clone_flags & CLONE_DETACHED)
                        return ERR_PTR(-EINVAL);
        }
 
@@ -2524,8 +2416,10 @@ __latent_entropy struct task_struct *copy_process(
         * if the fd table isn't shared).
         */
        if (clone_flags & CLONE_PIDFD) {
+               int flags = (clone_flags & CLONE_THREAD) ? PIDFD_THREAD : 0;
+
                /* Note that no task has been attached to @pid yet. */
-               retval = __pidfd_prepare(pid, O_RDWR | O_CLOEXEC, &pidfile);
+               retval = __pidfd_prepare(pid, flags, &pidfile);
                if (retval < 0)
                        goto bad_fork_free_pid;
                pidfd = retval;
@@ -2876,8 +2770,8 @@ pid_t kernel_clone(struct kernel_clone_args *args)
         * here has the advantage that we don't need to have a separate helper
         * to check for legacy clone().
         */
-       if ((args->flags & CLONE_PIDFD) &&
-           (args->flags & CLONE_PARENT_SETTID) &&
+       if ((clone_flags & CLONE_PIDFD) &&
+           (clone_flags & CLONE_PARENT_SETTID) &&
            (args->pidfd == args->parent_tid))
                return -EINVAL;
 
index dd76323ea3fd7410d56dc648441595e3474e6426..38d6ae651ac7582a857379c3c422869dd4a6ba76 100644 (file)
@@ -4,10 +4,11 @@
  * Copyright (C) 2020 Bartosz Golaszewski <bgolaszewski@baylibre.com>
  */
 
+#include <linux/cleanup.h>
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irq_sim.h>
 #include <linux/irq_work.h>
-#include <linux/interrupt.h>
 #include <linux/slab.h>
 
 struct irq_sim_work_ctx {
@@ -19,7 +20,6 @@ struct irq_sim_work_ctx {
 };
 
 struct irq_sim_irq_ctx {
-       int                     irqnum;
        bool                    enabled;
        struct irq_sim_work_ctx *work_ctx;
 };
@@ -164,33 +164,27 @@ static const struct irq_domain_ops irq_sim_domain_ops = {
 struct irq_domain *irq_domain_create_sim(struct fwnode_handle *fwnode,
                                         unsigned int num_irqs)
 {
-       struct irq_sim_work_ctx *work_ctx;
+       struct irq_sim_work_ctx *work_ctx __free(kfree) =
+                               kmalloc(sizeof(*work_ctx), GFP_KERNEL);
 
-       work_ctx = kmalloc(sizeof(*work_ctx), GFP_KERNEL);
        if (!work_ctx)
-               goto err_out;
+               return ERR_PTR(-ENOMEM);
 
-       work_ctx->pending = bitmap_zalloc(num_irqs, GFP_KERNEL);
-       if (!work_ctx->pending)
-               goto err_free_work_ctx;
+       unsigned long *pending __free(bitmap) = bitmap_zalloc(num_irqs, GFP_KERNEL);
+       if (!pending)
+               return ERR_PTR(-ENOMEM);
 
        work_ctx->domain = irq_domain_create_linear(fwnode, num_irqs,
                                                    &irq_sim_domain_ops,
                                                    work_ctx);
        if (!work_ctx->domain)
-               goto err_free_bitmap;
+               return ERR_PTR(-ENOMEM);
 
        work_ctx->irq_count = num_irqs;
        work_ctx->work = IRQ_WORK_INIT_HARD(irq_sim_handle_irq);
+       work_ctx->pending = no_free_ptr(pending);
 
-       return work_ctx->domain;
-
-err_free_bitmap:
-       bitmap_free(work_ctx->pending);
-err_free_work_ctx:
-       kfree(work_ctx);
-err_out:
-       return ERR_PTR(-ENOMEM);
+       return no_free_ptr(work_ctx)->domain;
 }
 EXPORT_SYMBOL_GPL(irq_domain_create_sim);
 
index 371eb1711d3467baf596c477411c1d3ac554cedd..4c6b32318ce350a5fb831093424f7437f9f54cea 100644 (file)
@@ -92,11 +92,23 @@ static void desc_smp_init(struct irq_desc *desc, int node,
 #endif
 }
 
+static void free_masks(struct irq_desc *desc)
+{
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+       free_cpumask_var(desc->pending_mask);
+#endif
+       free_cpumask_var(desc->irq_common_data.affinity);
+#ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
+       free_cpumask_var(desc->irq_common_data.effective_affinity);
+#endif
+}
+
 #else
 static inline int
 alloc_masks(struct irq_desc *desc, int node) { return 0; }
 static inline void
 desc_smp_init(struct irq_desc *desc, int node, const struct cpumask *affinity) { }
+static inline void free_masks(struct irq_desc *desc) { }
 #endif
 
 static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
@@ -165,6 +177,39 @@ static void delete_irq_desc(unsigned int irq)
        mas_erase(&mas);
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+static const struct kobj_type irq_kobj_type;
+#endif
+
+static int init_desc(struct irq_desc *desc, int irq, int node,
+                    unsigned int flags,
+                    const struct cpumask *affinity,
+                    struct module *owner)
+{
+       desc->kstat_irqs = alloc_percpu(unsigned int);
+       if (!desc->kstat_irqs)
+               return -ENOMEM;
+
+       if (alloc_masks(desc, node)) {
+               free_percpu(desc->kstat_irqs);
+               return -ENOMEM;
+       }
+
+       raw_spin_lock_init(&desc->lock);
+       lockdep_set_class(&desc->lock, &irq_desc_lock_class);
+       mutex_init(&desc->request_mutex);
+       init_waitqueue_head(&desc->wait_for_threads);
+       desc_set_defaults(irq, desc, node, affinity, owner);
+       irqd_set(&desc->irq_data, flags);
+       irq_resend_init(desc);
+#ifdef CONFIG_SPARSE_IRQ
+       kobject_init(&desc->kobj, &irq_kobj_type);
+       init_rcu_head(&desc->rcu);
+#endif
+
+       return 0;
+}
+
 #ifdef CONFIG_SPARSE_IRQ
 
 static void irq_kobj_release(struct kobject *kobj);
@@ -384,21 +429,6 @@ struct irq_desc *irq_to_desc(unsigned int irq)
 EXPORT_SYMBOL_GPL(irq_to_desc);
 #endif
 
-#ifdef CONFIG_SMP
-static void free_masks(struct irq_desc *desc)
-{
-#ifdef CONFIG_GENERIC_PENDING_IRQ
-       free_cpumask_var(desc->pending_mask);
-#endif
-       free_cpumask_var(desc->irq_common_data.affinity);
-#ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
-       free_cpumask_var(desc->irq_common_data.effective_affinity);
-#endif
-}
-#else
-static inline void free_masks(struct irq_desc *desc) { }
-#endif
-
 void irq_lock_sparse(void)
 {
        mutex_lock(&sparse_irq_lock);
@@ -414,36 +444,19 @@ static struct irq_desc *alloc_desc(int irq, int node, unsigned int flags,
                                   struct module *owner)
 {
        struct irq_desc *desc;
+       int ret;
 
        desc = kzalloc_node(sizeof(*desc), GFP_KERNEL, node);
        if (!desc)
                return NULL;
-       /* allocate based on nr_cpu_ids */
-       desc->kstat_irqs = alloc_percpu(unsigned int);
-       if (!desc->kstat_irqs)
-               goto err_desc;
-
-       if (alloc_masks(desc, node))
-               goto err_kstat;
 
-       raw_spin_lock_init(&desc->lock);
-       lockdep_set_class(&desc->lock, &irq_desc_lock_class);
-       mutex_init(&desc->request_mutex);
-       init_rcu_head(&desc->rcu);
-       init_waitqueue_head(&desc->wait_for_threads);
-
-       desc_set_defaults(irq, desc, node, affinity, owner);
-       irqd_set(&desc->irq_data, flags);
-       kobject_init(&desc->kobj, &irq_kobj_type);
-       irq_resend_init(desc);
+       ret = init_desc(desc, irq, node, flags, affinity, owner);
+       if (unlikely(ret)) {
+               kfree(desc);
+               return NULL;
+       }
 
        return desc;
-
-err_kstat:
-       free_percpu(desc->kstat_irqs);
-err_desc:
-       kfree(desc);
-       return NULL;
 }
 
 static void irq_kobj_release(struct kobject *kobj)
@@ -583,26 +596,29 @@ struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
 int __init early_irq_init(void)
 {
        int count, i, node = first_online_node;
-       struct irq_desc *desc;
+       int ret;
 
        init_irq_default_affinity();
 
        printk(KERN_INFO "NR_IRQS: %d\n", NR_IRQS);
 
-       desc = irq_desc;
        count = ARRAY_SIZE(irq_desc);
 
        for (i = 0; i < count; i++) {
-               desc[i].kstat_irqs = alloc_percpu(unsigned int);
-               alloc_masks(&desc[i], node);
-               raw_spin_lock_init(&desc[i].lock);
-               lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
-               mutex_init(&desc[i].request_mutex);
-               init_waitqueue_head(&desc[i].wait_for_threads);
-               desc_set_defaults(i, &desc[i], node, NULL, NULL);
-               irq_resend_init(&desc[i]);
+               ret = init_desc(irq_desc + i, i, node, 0, NULL, NULL);
+               if (unlikely(ret))
+                       goto __free_desc_res;
        }
+
        return arch_early_irq_init();
+
+__free_desc_res:
+       while (--i >= 0) {
+               free_masks(irq_desc + i);
+               free_percpu(irq_desc[i].kstat_irqs);
+       }
+
+       return ret;
 }
 
 struct irq_desc *irq_to_desc(unsigned int irq)
index 0bdef4fe925bf5dae05d81468e3d60de8649f267..3dd1c871e0910f4c15f287122862c10e2aa5a4e4 100644 (file)
@@ -29,6 +29,7 @@ static int irq_domain_alloc_irqs_locked(struct irq_domain *domain, int irq_base,
                                        unsigned int nr_irqs, int node, void *arg,
                                        bool realloc, const struct irq_affinity_desc *affinity);
 static void irq_domain_check_hierarchy(struct irq_domain *domain);
+static void irq_domain_free_one_irq(struct irq_domain *domain, unsigned int virq);
 
 struct irqchip_fwid {
        struct fwnode_handle    fwnode;
@@ -448,7 +449,7 @@ struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
         */
        mutex_lock(&irq_domain_mutex);
        list_for_each_entry(h, &irq_domain_list, link) {
-               if (h->ops->select && fwspec->param_count)
+               if (h->ops->select && bus_token != DOMAIN_BUS_ANY)
                        rc = h->ops->select(h, fwspec, bus_token);
                else if (h->ops->match)
                        rc = h->ops->match(h, to_of_node(fwnode), bus_token);
@@ -858,8 +859,13 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
        }
 
        if (irq_domain_is_hierarchy(domain)) {
-               virq = irq_domain_alloc_irqs_locked(domain, -1, 1, NUMA_NO_NODE,
-                                                   fwspec, false, NULL);
+               if (irq_domain_is_msi_device(domain)) {
+                       mutex_unlock(&domain->root->mutex);
+                       virq = msi_device_domain_alloc_wired(domain, hwirq, type);
+                       mutex_lock(&domain->root->mutex);
+               } else
+                       virq = irq_domain_alloc_irqs_locked(domain, -1, 1, NUMA_NO_NODE,
+                                                           fwspec, false, NULL);
                if (virq <= 0) {
                        virq = 0;
                        goto out;
@@ -914,7 +920,7 @@ void irq_dispose_mapping(unsigned int virq)
                return;
 
        if (irq_domain_is_hierarchy(domain)) {
-               irq_domain_free_irqs(virq, 1);
+               irq_domain_free_one_irq(domain, virq);
        } else {
                irq_domain_disassociate(domain, virq);
                irq_free_desc(virq);
@@ -1755,6 +1761,14 @@ void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs)
        irq_free_descs(virq, nr_irqs);
 }
 
+static void irq_domain_free_one_irq(struct irq_domain *domain, unsigned int virq)
+{
+       if (irq_domain_is_msi_device(domain))
+               msi_device_domain_free_wired(domain, virq);
+       else
+               irq_domain_free_irqs(virq, 1);
+}
+
 /**
  * irq_domain_alloc_irqs_parent - Allocate interrupts from parent domain
  * @domain:    Domain below which interrupts must be allocated
@@ -1907,9 +1921,9 @@ static int irq_domain_alloc_irqs_locked(struct irq_domain *domain, int irq_base,
        return -EINVAL;
 }
 
-static void irq_domain_check_hierarchy(struct irq_domain *domain)
-{
-}
+static void irq_domain_check_hierarchy(struct irq_domain *domain) { }
+static void irq_domain_free_one_irq(struct irq_domain *domain, unsigned int virq) { }
+
 #endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
 
 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
index 1782f90cd8c6c7cf7a2b8eaedeb047543d70733a..ad3eaf2ab959616104fb7192c3cb64e935ca43f3 100644 (file)
@@ -192,10 +192,14 @@ void irq_set_thread_affinity(struct irq_desc *desc)
        struct irqaction *action;
 
        for_each_action_of_desc(desc, action) {
-               if (action->thread)
+               if (action->thread) {
                        set_bit(IRQTF_AFFINITY, &action->thread_flags);
-               if (action->secondary && action->secondary->thread)
+                       wake_up_process(action->thread);
+               }
+               if (action->secondary && action->secondary->thread) {
                        set_bit(IRQTF_AFFINITY, &action->secondary->thread_flags);
+                       wake_up_process(action->secondary->thread);
+               }
        }
 }
 
@@ -1049,10 +1053,57 @@ static irqreturn_t irq_forced_secondary_handler(int irq, void *dev_id)
        return IRQ_NONE;
 }
 
-static int irq_wait_for_interrupt(struct irqaction *action)
+#ifdef CONFIG_SMP
+/*
+ * Check whether we need to change the affinity of the interrupt thread.
+ */
+static void irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
+{
+       cpumask_var_t mask;
+       bool valid = false;
+
+       if (!test_and_clear_bit(IRQTF_AFFINITY, &action->thread_flags))
+               return;
+
+       __set_current_state(TASK_RUNNING);
+
+       /*
+        * In case we are out of memory we set IRQTF_AFFINITY again and
+        * try again next time
+        */
+       if (!alloc_cpumask_var(&mask, GFP_KERNEL)) {
+               set_bit(IRQTF_AFFINITY, &action->thread_flags);
+               return;
+       }
+
+       raw_spin_lock_irq(&desc->lock);
+       /*
+        * This code is triggered unconditionally. Check the affinity
+        * mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out.
+        */
+       if (cpumask_available(desc->irq_common_data.affinity)) {
+               const struct cpumask *m;
+
+               m = irq_data_get_effective_affinity_mask(&desc->irq_data);
+               cpumask_copy(mask, m);
+               valid = true;
+       }
+       raw_spin_unlock_irq(&desc->lock);
+
+       if (valid)
+               set_cpus_allowed_ptr(current, mask);
+       free_cpumask_var(mask);
+}
+#else
+static inline void irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) { }
+#endif
+
+static int irq_wait_for_interrupt(struct irq_desc *desc,
+                                 struct irqaction *action)
 {
        for (;;) {
                set_current_state(TASK_INTERRUPTIBLE);
+               irq_thread_check_affinity(desc, action);
 
                if (kthread_should_stop()) {
                        /* may need to run one last time */
@@ -1129,52 +1180,6 @@ out_unlock:
        chip_bus_sync_unlock(desc);
 }
 
-#ifdef CONFIG_SMP
-/*
- * Check whether we need to change the affinity of the interrupt thread.
- */
-static void
-irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
-{
-       cpumask_var_t mask;
-       bool valid = true;
-
-       if (!test_and_clear_bit(IRQTF_AFFINITY, &action->thread_flags))
-               return;
-
-       /*
-        * In case we are out of memory we set IRQTF_AFFINITY again and
-        * try again next time
-        */
-       if (!alloc_cpumask_var(&mask, GFP_KERNEL)) {
-               set_bit(IRQTF_AFFINITY, &action->thread_flags);
-               return;
-       }
-
-       raw_spin_lock_irq(&desc->lock);
-       /*
-        * This code is triggered unconditionally. Check the affinity
-        * mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out.
-        */
-       if (cpumask_available(desc->irq_common_data.affinity)) {
-               const struct cpumask *m;
-
-               m = irq_data_get_effective_affinity_mask(&desc->irq_data);
-               cpumask_copy(mask, m);
-       } else {
-               valid = false;
-       }
-       raw_spin_unlock_irq(&desc->lock);
-
-       if (valid)
-               set_cpus_allowed_ptr(current, mask);
-       free_cpumask_var(mask);
-}
-#else
-static inline void
-irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) { }
-#endif
-
 /*
  * Interrupts which are not explicitly requested as threaded
  * interrupts rely on the implicit bh/preempt disable of the hard irq
@@ -1312,13 +1317,9 @@ static int irq_thread(void *data)
        init_task_work(&on_exit_work, irq_thread_dtor);
        task_work_add(current, &on_exit_work, TWA_NONE);
 
-       irq_thread_check_affinity(desc, action);
-
-       while (!irq_wait_for_interrupt(action)) {
+       while (!irq_wait_for_interrupt(desc, action)) {
                irqreturn_t action_ret;
 
-               irq_thread_check_affinity(desc, action);
-
                action_ret = handler_fn(desc, action);
                if (action_ret == IRQ_WAKE_THREAD)
                        irq_wake_secondary(desc, action);
index 75d0ae490e29cd8b956fd1ecf7b5a5e99d883611..8f222d1cccecaef7bc079d3af73819ee275c8c29 100644 (file)
@@ -8,8 +8,6 @@
 #include <linux/cpu.h>
 #include <linux/irq.h>
 
-#define IRQ_MATRIX_SIZE        (BITS_TO_LONGS(IRQ_MATRIX_BITS))
-
 struct cpumap {
        unsigned int            available;
        unsigned int            allocated;
@@ -17,8 +15,8 @@ struct cpumap {
        unsigned int            managed_allocated;
        bool                    initialized;
        bool                    online;
-       unsigned long           alloc_map[IRQ_MATRIX_SIZE];
-       unsigned long           managed_map[IRQ_MATRIX_SIZE];
+       unsigned long           *managed_map;
+       unsigned long           alloc_map[];
 };
 
 struct irq_matrix {
@@ -32,8 +30,8 @@ struct irq_matrix {
        unsigned int            total_allocated;
        unsigned int            online_maps;
        struct cpumap __percpu  *maps;
-       unsigned long           scratch_map[IRQ_MATRIX_SIZE];
-       unsigned long           system_map[IRQ_MATRIX_SIZE];
+       unsigned long           *system_map;
+       unsigned long           scratch_map[];
 };
 
 #define CREATE_TRACE_POINTS
@@ -50,24 +48,32 @@ __init struct irq_matrix *irq_alloc_matrix(unsigned int matrix_bits,
                                           unsigned int alloc_start,
                                           unsigned int alloc_end)
 {
+       unsigned int cpu, matrix_size = BITS_TO_LONGS(matrix_bits);
        struct irq_matrix *m;
 
-       if (matrix_bits > IRQ_MATRIX_BITS)
-               return NULL;
-
-       m = kzalloc(sizeof(*m), GFP_KERNEL);
+       m = kzalloc(struct_size(m, scratch_map, matrix_size * 2), GFP_KERNEL);
        if (!m)
                return NULL;
 
+       m->system_map = &m->scratch_map[matrix_size];
+
        m->matrix_bits = matrix_bits;
        m->alloc_start = alloc_start;
        m->alloc_end = alloc_end;
        m->alloc_size = alloc_end - alloc_start;
-       m->maps = alloc_percpu(*m->maps);
+       m->maps = __alloc_percpu(struct_size(m->maps, alloc_map, matrix_size * 2),
+                                __alignof__(*m->maps));
        if (!m->maps) {
                kfree(m);
                return NULL;
        }
+
+       for_each_possible_cpu(cpu) {
+               struct cpumap *cm = per_cpu_ptr(m->maps, cpu);
+
+               cm->managed_map = &cm->alloc_map[matrix_size];
+       }
+
        return m;
 }
 
index 79b4a58ba9c3f2b8af4faa2962c44cf3d6a1aba9..f90952ebc494111ca5bedea2e4951da84618c2fa 100644 (file)
@@ -726,11 +726,26 @@ static void msi_domain_free(struct irq_domain *domain, unsigned int virq,
        irq_domain_free_irqs_top(domain, virq, nr_irqs);
 }
 
+static int msi_domain_translate(struct irq_domain *domain, struct irq_fwspec *fwspec,
+                               irq_hw_number_t *hwirq, unsigned int *type)
+{
+       struct msi_domain_info *info = domain->host_data;
+
+       /*
+        * This will catch allocations through the regular irqdomain path except
+        * for MSI domains which really support this, e.g. MBIGEN.
+        */
+       if (!info->ops->msi_translate)
+               return -ENOTSUPP;
+       return info->ops->msi_translate(domain, fwspec, hwirq, type);
+}
+
 static const struct irq_domain_ops msi_domain_ops = {
        .alloc          = msi_domain_alloc,
        .free           = msi_domain_free,
        .activate       = msi_domain_activate,
        .deactivate     = msi_domain_deactivate,
+       .translate      = msi_domain_translate,
 };
 
 static irq_hw_number_t msi_domain_ops_get_hwirq(struct msi_domain_info *info,
@@ -830,8 +845,11 @@ static struct irq_domain *__msi_create_irq_domain(struct fwnode_handle *fwnode,
        domain = irq_domain_create_hierarchy(parent, flags | IRQ_DOMAIN_FLAG_MSI, 0,
                                             fwnode, &msi_domain_ops, info);
 
-       if (domain)
+       if (domain) {
                irq_domain_update_bus_token(domain, info->bus_token);
+               if (info->flags & MSI_FLAG_PARENT_PM_DEV)
+                       domain->pm_dev = parent->pm_dev;
+       }
 
        return domain;
 }
@@ -945,9 +963,9 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid,
                                  void *chip_data)
 {
        struct irq_domain *domain, *parent = dev->msi.domain;
-       const struct msi_parent_ops *pops;
+       struct fwnode_handle *fwnode, *fwnalloced = NULL;
        struct msi_domain_template *bundle;
-       struct fwnode_handle *fwnode;
+       const struct msi_parent_ops *pops;
 
        if (!irq_domain_is_msi_parent(parent))
                return false;
@@ -970,7 +988,19 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid,
                 pops->prefix ? : "", bundle->chip.name, dev_name(dev));
        bundle->chip.name = bundle->name;
 
-       fwnode = irq_domain_alloc_named_fwnode(bundle->name);
+       /*
+        * Using the device firmware node is required for wire to MSI
+        * device domains so that the existing firmware results in a domain
+        * match.
+        * All other device domains like PCI/MSI use the named firmware
+        * node as they are not guaranteed to have a fwnode. They are never
+        * looked up and always handled in the context of the device.
+        */
+       if (bundle->info.flags & MSI_FLAG_USE_DEV_FWNODE)
+               fwnode = dev->fwnode;
+       else
+               fwnode = fwnalloced = irq_domain_alloc_named_fwnode(bundle->name);
+
        if (!fwnode)
                goto free_bundle;
 
@@ -997,7 +1027,7 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid,
 fail:
        msi_unlock_descs(dev);
 free_fwnode:
-       irq_domain_free_fwnode(fwnode);
+       irq_domain_free_fwnode(fwnalloced);
 free_bundle:
        kfree(bundle);
        return false;
@@ -1431,34 +1461,10 @@ int msi_domain_alloc_irqs_all_locked(struct device *dev, unsigned int domid, int
        return msi_domain_alloc_locked(dev, &ctrl);
 }
 
-/**
- * msi_domain_alloc_irq_at - Allocate an interrupt from a MSI interrupt domain at
- *                          a given index - or at the next free index
- *
- * @dev:       Pointer to device struct of the device for which the interrupts
- *             are allocated
- * @domid:     Id of the interrupt domain to operate on
- * @index:     Index for allocation. If @index == %MSI_ANY_INDEX the allocation
- *             uses the next free index.
- * @affdesc:   Optional pointer to an interrupt affinity descriptor structure
- * @icookie:   Optional pointer to a domain specific per instance cookie. If
- *             non-NULL the content of the cookie is stored in msi_desc::data.
- *             Must be NULL for MSI-X allocations
- *
- * This requires a MSI interrupt domain which lets the core code manage the
- * MSI descriptors.
- *
- * Return: struct msi_map
- *
- *     On success msi_map::index contains the allocated index number and
- *     msi_map::virq the corresponding Linux interrupt number
- *
- *     On failure msi_map::index contains the error code and msi_map::virq
- *     is %0.
- */
-struct msi_map msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, unsigned int index,
-                                      const struct irq_affinity_desc *affdesc,
-                                      union msi_instance_cookie *icookie)
+static struct msi_map __msi_domain_alloc_irq_at(struct device *dev, unsigned int domid,
+                                               unsigned int index,
+                                               const struct irq_affinity_desc *affdesc,
+                                               union msi_instance_cookie *icookie)
 {
        struct msi_ctrl ctrl = { .domid = domid, .nirqs = 1, };
        struct irq_domain *domain;
@@ -1466,17 +1472,16 @@ struct msi_map msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, u
        struct msi_desc *desc;
        int ret;
 
-       msi_lock_descs(dev);
        domain = msi_get_device_domain(dev, domid);
        if (!domain) {
                map.index = -ENODEV;
-               goto unlock;
+               return map;
        }
 
        desc = msi_alloc_desc(dev, 1, affdesc);
        if (!desc) {
                map.index = -ENOMEM;
-               goto unlock;
+               return map;
        }
 
        if (icookie)
@@ -1485,7 +1490,7 @@ struct msi_map msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, u
        ret = msi_insert_desc(dev, desc, domid, index);
        if (ret) {
                map.index = ret;
-               goto unlock;
+               return map;
        }
 
        ctrl.first = ctrl.last = desc->msi_index;
@@ -1498,11 +1503,90 @@ struct msi_map msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, u
                map.index = desc->msi_index;
                map.virq = desc->irq;
        }
-unlock:
+       return map;
+}
+
+/**
+ * msi_domain_alloc_irq_at - Allocate an interrupt from a MSI interrupt domain at
+ *                          a given index - or at the next free index
+ *
+ * @dev:       Pointer to device struct of the device for which the interrupts
+ *             are allocated
+ * @domid:     Id of the interrupt domain to operate on
+ * @index:     Index for allocation. If @index == %MSI_ANY_INDEX the allocation
+ *             uses the next free index.
+ * @affdesc:   Optional pointer to an interrupt affinity descriptor structure
+ * @icookie:   Optional pointer to a domain specific per instance cookie. If
+ *             non-NULL the content of the cookie is stored in msi_desc::data.
+ *             Must be NULL for MSI-X allocations
+ *
+ * This requires a MSI interrupt domain which lets the core code manage the
+ * MSI descriptors.
+ *
+ * Return: struct msi_map
+ *
+ *     On success msi_map::index contains the allocated index number and
+ *     msi_map::virq the corresponding Linux interrupt number
+ *
+ *     On failure msi_map::index contains the error code and msi_map::virq
+ *     is %0.
+ */
+struct msi_map msi_domain_alloc_irq_at(struct device *dev, unsigned int domid, unsigned int index,
+                                      const struct irq_affinity_desc *affdesc,
+                                      union msi_instance_cookie *icookie)
+{
+       struct msi_map map;
+
+       msi_lock_descs(dev);
+       map = __msi_domain_alloc_irq_at(dev, domid, index, affdesc, icookie);
        msi_unlock_descs(dev);
        return map;
 }
 
+/**
+ * msi_device_domain_alloc_wired - Allocate a "wired" interrupt on @domain
+ * @domain:    The domain to allocate on
+ * @hwirq:     The hardware interrupt number to allocate for
+ * @type:      The interrupt type
+ *
+ * This weirdness supports wire to MSI controllers like MBIGEN.
+ *
+ * @hwirq is the hardware interrupt number which is handed in from
+ * irq_create_fwspec_mapping(). As the wire to MSI domain is sparse, but
+ * sized in firmware, the hardware interrupt number cannot be used as MSI
+ * index. For the underlying irq chip the MSI index is irrelevant and
+ * all it needs is the hardware interrupt number.
+ *
+ * To handle this the MSI index is allocated with MSI_ANY_INDEX and the
+ * hardware interrupt number is stored along with the type information in
+ * msi_desc::cookie so the underlying interrupt chip and domain code can
+ * retrieve it.
+ *
+ * Return: The Linux interrupt number (> 0) or an error code
+ */
+int msi_device_domain_alloc_wired(struct irq_domain *domain, unsigned int hwirq,
+                                 unsigned int type)
+{
+       unsigned int domid = MSI_DEFAULT_DOMAIN;
+       union msi_instance_cookie icookie = { };
+       struct device *dev = domain->dev;
+       struct msi_map map = { };
+
+       if (WARN_ON_ONCE(!dev || domain->bus_token != DOMAIN_BUS_WIRED_TO_MSI))
+               return -EINVAL;
+
+       icookie.value = ((u64)type << 32) | hwirq;
+
+       msi_lock_descs(dev);
+       if (WARN_ON_ONCE(msi_get_device_domain(dev, domid) != domain))
+               map.index = -EINVAL;
+       else
+               map = __msi_domain_alloc_irq_at(dev, domid, MSI_ANY_INDEX, NULL, &icookie);
+       msi_unlock_descs(dev);
+
+       return map.index >= 0 ? map.virq : map.index;
+}
+
 static void __msi_domain_free_irqs(struct device *dev, struct irq_domain *domain,
                                   struct msi_ctrl *ctrl)
 {
@@ -1628,6 +1712,30 @@ void msi_domain_free_irqs_all(struct device *dev, unsigned int domid)
        msi_unlock_descs(dev);
 }
 
+/**
+ * msi_device_domain_free_wired - Free a wired interrupt in @domain
+ * @domain:    The domain to free the interrupt on
+ * @virq:      The Linux interrupt number to free
+ *
+ * This is the counterpart of msi_device_domain_alloc_wired() for the
+ * weird wired to MSI converting domains.
+ */
+void msi_device_domain_free_wired(struct irq_domain *domain, unsigned int virq)
+{
+       struct msi_desc *desc = irq_get_msi_desc(virq);
+       struct device *dev = domain->dev;
+
+       if (WARN_ON_ONCE(!dev || !desc || domain->bus_token != DOMAIN_BUS_WIRED_TO_MSI))
+               return;
+
+       msi_lock_descs(dev);
+       if (!WARN_ON_ONCE(msi_get_device_domain(dev, MSI_DEFAULT_DOMAIN) != domain)) {
+               msi_domain_free_irqs_range_locked(dev, MSI_DEFAULT_DOMAIN, desc->msi_index,
+                                                 desc->msi_index);
+       }
+       msi_unlock_descs(dev);
+}
+
 /**
  * msi_get_domain_info - Get the MSI interrupt domain info for @domain
  * @domain:    The interrupt domain to retrieve data from
index 185bd1c906b0113f3921385bdd00d7950100023c..6083883c4fe09444a5f770eb7ee0f092d1ad8d4e 100644 (file)
@@ -223,9 +223,10 @@ static bool readers_active_check(struct percpu_rw_semaphore *sem)
 
 void __sched percpu_down_write(struct percpu_rw_semaphore *sem)
 {
+       bool contended = false;
+
        might_sleep();
        rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
-       trace_contention_begin(sem, LCB_F_PERCPU | LCB_F_WRITE);
 
        /* Notify readers to take the slow path. */
        rcu_sync_enter(&sem->rss);
@@ -234,8 +235,11 @@ void __sched percpu_down_write(struct percpu_rw_semaphore *sem)
         * Try set sem->block; this provides writer-writer exclusion.
         * Having sem->block set makes new readers block.
         */
-       if (!__percpu_down_write_trylock(sem))
+       if (!__percpu_down_write_trylock(sem)) {
+               trace_contention_begin(sem, LCB_F_PERCPU | LCB_F_WRITE);
                percpu_rwsem_wait(sem, /* .reader = */ false);
+               contended = true;
+       }
 
        /* smp_mb() implied by __percpu_down_write_trylock() on success -- D matches A */
 
@@ -247,7 +251,8 @@ void __sched percpu_down_write(struct percpu_rw_semaphore *sem)
 
        /* Wait for all active readers to complete. */
        rcuwait_wait_event(&sem->writer, readers_active_check(sem), TASK_UNINTERRUPTIBLE);
-       trace_contention_end(sem, 0);
+       if (contended)
+               trace_contention_end(sem, 0);
 }
 EXPORT_SYMBOL_GPL(percpu_down_write);
 
index 6a0184e9c2348e3b51a60d42a1e4e911e2209dd5..ae2b12f68b908016ee52c7bff64bf281122dc083 100644 (file)
@@ -294,8 +294,8 @@ static void pv_wait_node(struct mcs_spinlock *node, struct mcs_spinlock *prev)
 {
        struct pv_node *pn = (struct pv_node *)node;
        struct pv_node *pp = (struct pv_node *)prev;
+       bool __maybe_unused wait_early;
        int loop;
-       bool wait_early;
 
        for (;;) {
                for (wait_early = false, loop = SPIN_THRESHOLD; loop; loop--) {
index 4a10e8c16fd2bd691f53871228e556a59f0f781a..88d08eeb8bc03df508146f30a8120d80654a1759 100644 (file)
@@ -237,12 +237,13 @@ static __always_inline bool rt_mutex_cmpxchg_release(struct rt_mutex_base *lock,
  */
 static __always_inline void mark_rt_mutex_waiters(struct rt_mutex_base *lock)
 {
-       unsigned long owner, *p = (unsigned long *) &lock->owner;
+       unsigned long *p = (unsigned long *) &lock->owner;
+       unsigned long owner, new;
 
+       owner = READ_ONCE(*p);
        do {
-               owner = *p;
-       } while (cmpxchg_relaxed(p, owner,
-                                owner | RT_MUTEX_HAS_WAITERS) != owner);
+               new = owner | RT_MUTEX_HAS_WAITERS;
+       } while (!try_cmpxchg_relaxed(p, &owner, new));
 
        /*
         * The cmpxchg loop above is relaxed to avoid back-to-back ACQUIRE
index 2340b6d90ec6f82e2a9c1519c5430e4c59c0a0b8..c6d17aee4209b171146265023168b0546218633c 100644 (file)
@@ -35,7 +35,7 @@
 /*
  * The least significant 2 bits of the owner value has the following
  * meanings when set.
- *  - Bit 0: RWSEM_READER_OWNED - The rwsem is owned by readers
+ *  - Bit 0: RWSEM_READER_OWNED - rwsem may be owned by readers (just a hint)
  *  - Bit 1: RWSEM_NONSPINNABLE - Cannot spin on a reader-owned lock
  *
  * When the rwsem is reader-owned and a spinning writer has timed out,
@@ -1002,8 +1002,8 @@ rwsem_down_read_slowpath(struct rw_semaphore *sem, long count, unsigned int stat
 
        /*
         * To prevent a constant stream of readers from starving a sleeping
-        * waiter, don't attempt optimistic lock stealing if the lock is
-        * currently owned by readers.
+        * writer, don't attempt optimistic lock stealing if the lock is
+        * very likely owned by readers.
         */
        if ((atomic_long_read(&sem->owner) & RWSEM_READER_OWNED) &&
            (rcnt > 1) && !(count & RWSEM_WRITER_LOCKED))
index 15781acaac1ceec97fa2ae649d284c025693186e..6ec3deec68c200eb656d2686e20a31165922f3b3 100644 (file)
@@ -573,7 +573,7 @@ SYSCALL_DEFINE2(setns, int, fd, int, flags)
        if (proc_ns_file(f.file))
                err = validate_ns(&nsset, ns);
        else
-               err = validate_nsset(&nsset, f.file->private_data);
+               err = validate_nsset(&nsset, pidfd_pid(f.file));
        if (!err) {
                commit_nsset(&nsset);
                perf_event_namespaces(current);
index b52b108654541545797c19aa0bf68c735442bbac..99a0c5eb24b8d61df9b4fa2d171ddf71b54f3a92 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/sched/signal.h>
 #include <linux/sched/task.h>
 #include <linux/idr.h>
+#include <linux/pidfs.h>
 #include <net/sock.h>
 #include <uapi/linux/pidfd.h>
 
@@ -65,6 +66,13 @@ int pid_max = PID_MAX_DEFAULT;
 
 int pid_max_min = RESERVED_PIDS + 1;
 int pid_max_max = PID_MAX_LIMIT;
+#ifdef CONFIG_FS_PID
+/*
+ * Pseudo filesystems start inode numbering after one. We use Reserved
+ * PIDs as a natural offset.
+ */
+static u64 pidfs_ino = RESERVED_PIDS;
+#endif
 
 /*
  * PID-map pages start out as NULL, they get allocated upon
@@ -272,6 +280,10 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *set_tid,
        spin_lock_irq(&pidmap_lock);
        if (!(ns->pid_allocated & PIDNS_ADDING))
                goto out_unlock;
+#ifdef CONFIG_FS_PID
+       pid->stashed = NULL;
+       pid->ino = ++pidfs_ino;
+#endif
        for ( ; upid >= pid->numbers; --upid) {
                /* Make the PID visible to find_pid_ns. */
                idr_replace(&upid->ns->idr, pid, upid->nr);
@@ -349,6 +361,11 @@ static void __change_pid(struct task_struct *task, enum pid_type type,
        hlist_del_rcu(&task->pid_links[type]);
        *pid_ptr = new;
 
+       if (type == PIDTYPE_PID) {
+               WARN_ON_ONCE(pid_has_task(pid, PIDTYPE_PID));
+               wake_up_all(&pid->wait_pidfd);
+       }
+
        for (tmp = PIDTYPE_MAX; --tmp >= 0; )
                if (pid_has_task(pid, tmp))
                        return;
@@ -391,8 +408,7 @@ void exchange_tids(struct task_struct *left, struct task_struct *right)
 void transfer_pid(struct task_struct *old, struct task_struct *new,
                           enum pid_type type)
 {
-       if (type == PIDTYPE_PID)
-               new->thread_pid = old->thread_pid;
+       WARN_ON_ONCE(type == PIDTYPE_PID);
        hlist_replace_rcu(&old->pid_links[type], &new->pid_links[type]);
 }
 
@@ -552,11 +568,6 @@ struct pid *pidfd_get_pid(unsigned int fd, unsigned int *flags)
  * Return the task associated with @pidfd. The function takes a reference on
  * the returned task. The caller is responsible for releasing that reference.
  *
- * Currently, the process identified by @pidfd is always a thread-group leader.
- * This restriction currently exists for all aspects of pidfds including pidfd
- * creation (CLONE_PIDFD cannot be used with CLONE_THREAD) and pidfd polling
- * (only supports thread group leaders).
- *
  * Return: On success, the task_struct associated with the pidfd.
  *        On error, a negative errno number will be returned.
  */
@@ -595,7 +606,7 @@ struct task_struct *pidfd_get_task(int pidfd, unsigned int *flags)
  * Return: On success, a cloexec pidfd is returned.
  *         On error, a negative errno number will be returned.
  */
-int pidfd_create(struct pid *pid, unsigned int flags)
+static int pidfd_create(struct pid *pid, unsigned int flags)
 {
        int pidfd;
        struct file *pidfd_file;
@@ -615,11 +626,8 @@ int pidfd_create(struct pid *pid, unsigned int flags)
  * @flags: flags to pass
  *
  * This creates a new pid file descriptor with the O_CLOEXEC flag set for
- * the process identified by @pid. Currently, the process identified by
- * @pid must be a thread-group leader. This restriction currently exists
- * for all aspects of pidfds including pidfd creation (CLONE_PIDFD cannot
- * be used with CLONE_THREAD) and pidfd polling (only supports thread group
- * leaders).
+ * the task identified by @pid. Without PIDFD_THREAD flag the target task
+ * must be a thread-group leader.
  *
  * Return: On success, a cloexec pidfd is returned.
  *         On error, a negative errno number will be returned.
@@ -629,7 +637,7 @@ SYSCALL_DEFINE2(pidfd_open, pid_t, pid, unsigned int, flags)
        int fd;
        struct pid *p;
 
-       if (flags & ~PIDFD_NONBLOCK)
+       if (flags & ~(PIDFD_NONBLOCK | PIDFD_THREAD))
                return -EINVAL;
 
        if (pid <= 0)
@@ -682,7 +690,26 @@ static struct file *__pidfd_fget(struct task_struct *task, int fd)
 
        up_read(&task->signal->exec_update_lock);
 
-       return file ?: ERR_PTR(-EBADF);
+       if (!file) {
+               /*
+                * It is possible that the target thread is exiting; it can be
+                * either:
+                * 1. before exit_signals(), which gives a real fd
+                * 2. before exit_files() takes the task_lock() gives a real fd
+                * 3. after exit_files() releases task_lock(), ->files is NULL;
+                *    this has PF_EXITING, since it was set in exit_signals(),
+                *    __pidfd_fget() returns EBADF.
+                * In case 3 we get EBADF, but that really means ESRCH, since
+                * the task is currently exiting and has freed its files
+                * struct, so we fix it up.
+                */
+               if (task->flags & PF_EXITING)
+                       file = ERR_PTR(-ESRCH);
+               else
+                       file = ERR_PTR(-EBADF);
+       }
+
+       return file;
 }
 
 static int pidfd_getfd(struct pid *pid, int fd)
index 6053ddddaf6540209bdacc80cac431c1bcd78222..692f12fe60c1309232d565ed0d8b3bbd98609b2c 100644 (file)
@@ -222,7 +222,7 @@ int swsusp_swap_in_use(void)
  */
 
 static unsigned short root_swap = 0xffff;
-static struct bdev_handle *hib_resume_bdev_handle;
+static struct file *hib_resume_bdev_file;
 
 struct hib_bio_batch {
        atomic_t                count;
@@ -276,7 +276,7 @@ static int hib_submit_io(blk_opf_t opf, pgoff_t page_off, void *addr,
        struct bio *bio;
        int error = 0;
 
-       bio = bio_alloc(hib_resume_bdev_handle->bdev, 1, opf,
+       bio = bio_alloc(file_bdev(hib_resume_bdev_file), 1, opf,
                        GFP_NOIO | __GFP_HIGH);
        bio->bi_iter.bi_sector = page_off * (PAGE_SIZE >> 9);
 
@@ -357,14 +357,14 @@ static int swsusp_swap_check(void)
                return res;
        root_swap = res;
 
-       hib_resume_bdev_handle = bdev_open_by_dev(swsusp_resume_device,
+       hib_resume_bdev_file = bdev_file_open_by_dev(swsusp_resume_device,
                        BLK_OPEN_WRITE, NULL, NULL);
-       if (IS_ERR(hib_resume_bdev_handle))
-               return PTR_ERR(hib_resume_bdev_handle);
+       if (IS_ERR(hib_resume_bdev_file))
+               return PTR_ERR(hib_resume_bdev_file);
 
-       res = set_blocksize(hib_resume_bdev_handle->bdev, PAGE_SIZE);
+       res = set_blocksize(file_bdev(hib_resume_bdev_file), PAGE_SIZE);
        if (res < 0)
-               bdev_release(hib_resume_bdev_handle);
+               fput(hib_resume_bdev_file);
 
        return res;
 }
@@ -1523,10 +1523,10 @@ int swsusp_check(bool exclusive)
        void *holder = exclusive ? &swsusp_holder : NULL;
        int error;
 
-       hib_resume_bdev_handle = bdev_open_by_dev(swsusp_resume_device,
+       hib_resume_bdev_file = bdev_file_open_by_dev(swsusp_resume_device,
                                BLK_OPEN_READ, holder, NULL);
-       if (!IS_ERR(hib_resume_bdev_handle)) {
-               set_blocksize(hib_resume_bdev_handle->bdev, PAGE_SIZE);
+       if (!IS_ERR(hib_resume_bdev_file)) {
+               set_blocksize(file_bdev(hib_resume_bdev_file), PAGE_SIZE);
                clear_page(swsusp_header);
                error = hib_submit_io(REQ_OP_READ, swsusp_resume_block,
                                        swsusp_header, NULL);
@@ -1551,11 +1551,11 @@ int swsusp_check(bool exclusive)
 
 put:
                if (error)
-                       bdev_release(hib_resume_bdev_handle);
+                       fput(hib_resume_bdev_file);
                else
                        pr_debug("Image signature found, resuming\n");
        } else {
-               error = PTR_ERR(hib_resume_bdev_handle);
+               error = PTR_ERR(hib_resume_bdev_file);
        }
 
        if (error)
@@ -1570,12 +1570,12 @@ put:
 
 void swsusp_close(void)
 {
-       if (IS_ERR(hib_resume_bdev_handle)) {
+       if (IS_ERR(hib_resume_bdev_file)) {
                pr_debug("Image device not initialised\n");
                return;
        }
 
-       bdev_release(hib_resume_bdev_handle);
+       fput(hib_resume_bdev_file);
 }
 
 /**
index bdd7eadb33d8fe0039349f8295cc967c9f137289..e7d2dd2675931fac627947959f3fbb9e93aae05b 100644 (file)
@@ -314,6 +314,19 @@ config RCU_LAZY
          To save power, batch RCU callbacks and flush after delay, memory
          pressure, or callback list growing too big.
 
+         Requires rcu_nocbs=all to be set.
+
+         Use rcutree.enable_rcu_lazy=0 to turn it off at boot time.
+
+config RCU_LAZY_DEFAULT_OFF
+       bool "Turn RCU lazy invocation off by default"
+       depends on RCU_LAZY
+       default n
+       help
+         Allows building the kernel with CONFIG_RCU_LAZY=y yet keep it default
+         off. Boot time param rcutree.enable_rcu_lazy=1 can be used to switch
+         it back on.
+
 config RCU_DOUBLE_CHECK_CB_TIME
        bool "RCU callback-batch backup time check"
        depends on RCU_EXPERT
index f94f65877f2b68055b4e5c7a057c22bf4fb96a18..86fce206560e83f05e3a57114e5771e0c0a76b7d 100644 (file)
@@ -528,6 +528,12 @@ struct task_struct *get_rcu_tasks_gp_kthread(void);
 struct task_struct *get_rcu_tasks_rude_gp_kthread(void);
 #endif // # ifdef CONFIG_TASKS_RUDE_RCU
 
+#ifdef CONFIG_TASKS_RCU_GENERIC
+void tasks_cblist_init_generic(void);
+#else /* #ifdef CONFIG_TASKS_RCU_GENERIC */
+static inline void tasks_cblist_init_generic(void) { }
+#endif /* #else #ifdef CONFIG_TASKS_RCU_GENERIC */
+
 #define RCU_SCHEDULER_INACTIVE 0
 #define RCU_SCHEDULER_INIT     1
 #define RCU_SCHEDULER_RUNNING  2
@@ -543,11 +549,11 @@ enum rcutorture_type {
 };
 
 #if defined(CONFIG_RCU_LAZY)
-unsigned long rcu_lazy_get_jiffies_till_flush(void);
-void rcu_lazy_set_jiffies_till_flush(unsigned long j);
+unsigned long rcu_get_jiffies_lazy_flush(void);
+void rcu_set_jiffies_lazy_flush(unsigned long j);
 #else
-static inline unsigned long rcu_lazy_get_jiffies_till_flush(void) { return 0; }
-static inline void rcu_lazy_set_jiffies_till_flush(unsigned long j) { }
+static inline unsigned long rcu_get_jiffies_lazy_flush(void) { return 0; }
+static inline void rcu_set_jiffies_lazy_flush(unsigned long j) { }
 #endif
 
 #if defined(CONFIG_TREE_RCU)
@@ -623,12 +629,7 @@ int rcu_get_gp_kthreads_prio(void);
 void rcu_fwd_progress_check(unsigned long j);
 void rcu_force_quiescent_state(void);
 extern struct workqueue_struct *rcu_gp_wq;
-#ifdef CONFIG_RCU_EXP_KTHREAD
 extern struct kthread_worker *rcu_exp_gp_kworker;
-extern struct kthread_worker *rcu_exp_par_gp_kworker;
-#else /* !CONFIG_RCU_EXP_KTHREAD */
-extern struct workqueue_struct *rcu_par_gp_wq;
-#endif /* CONFIG_RCU_EXP_KTHREAD */
 void rcu_gp_slow_register(atomic_t *rgssp);
 void rcu_gp_slow_unregister(atomic_t *rgssp);
 #endif /* #else #ifdef CONFIG_TINY_RCU */
index ffdb30495e3cc3d2a5adc2efcd550132fb8c7a4d..8db4fedaaa1eb7340cf9b4e808e9da45b0b687cc 100644 (file)
@@ -764,9 +764,9 @@ kfree_scale_init(void)
 
        if (kfree_by_call_rcu) {
                /* do a test to check the timeout. */
-               orig_jif = rcu_lazy_get_jiffies_till_flush();
+               orig_jif = rcu_get_jiffies_lazy_flush();
 
-               rcu_lazy_set_jiffies_till_flush(2 * HZ);
+               rcu_set_jiffies_lazy_flush(2 * HZ);
                rcu_barrier();
 
                jif_start = jiffies;
@@ -775,7 +775,7 @@ kfree_scale_init(void)
 
                smp_cond_load_relaxed(&rcu_lazy_test1_cb_called, VAL == 1);
 
-               rcu_lazy_set_jiffies_till_flush(orig_jif);
+               rcu_set_jiffies_lazy_flush(orig_jif);
 
                if (WARN_ON_ONCE(jiffies_at_lazy_cb - jif_start < 2 * HZ)) {
                        pr_alert("ERROR: call_rcu() CBs are not being lazy as expected!\n");
index 7567ca8e743ca62f92fe2dda179d1bce56aaedef..45d6b4c3d199c13481b281360c2f50d75e600cef 100644 (file)
@@ -1368,9 +1368,13 @@ rcu_torture_writer(void *arg)
        struct rcu_torture *rp;
        struct rcu_torture *old_rp;
        static DEFINE_TORTURE_RANDOM(rand);
+       unsigned long stallsdone = jiffies;
        bool stutter_waited;
        unsigned long ulo[NUM_ACTIVE_RCU_POLL_OLDSTATE];
 
+       // If a new stall test is added, this must be adjusted.
+       if (stall_cpu_holdoff + stall_gp_kthread + stall_cpu)
+               stallsdone += (stall_cpu_holdoff + stall_gp_kthread + stall_cpu + 60) * HZ;
        VERBOSE_TOROUT_STRING("rcu_torture_writer task started");
        if (!can_expedite)
                pr_alert("%s" TORTURE_FLAG
@@ -1576,11 +1580,11 @@ rcu_torture_writer(void *arg)
                    !atomic_read(&rcu_fwd_cb_nodelay) &&
                    !cur_ops->slow_gps &&
                    !torture_must_stop() &&
-                   boot_ended)
+                   boot_ended &&
+                   time_after(jiffies, stallsdone))
                        for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++)
                                if (list_empty(&rcu_tortures[i].rtort_free) &&
-                                   rcu_access_pointer(rcu_torture_current) !=
-                                   &rcu_tortures[i]) {
+                                   rcu_access_pointer(rcu_torture_current) != &rcu_tortures[i]) {
                                        tracing_off();
                                        show_rcu_gp_kthreads();
                                        WARN(1, "%s: rtort_pipe_count: %d\n", __func__, rcu_tortures[i].rtort_pipe_count);
@@ -2441,7 +2445,8 @@ static struct notifier_block rcu_torture_stall_block = {
 
 /*
  * CPU-stall kthread.  It waits as specified by stall_cpu_holdoff, then
- * induces a CPU stall for the time specified by stall_cpu.
+ * induces a CPU stall for the time specified by stall_cpu.  If a new
+ * stall test is added, stallsdone in rcu_torture_writer() must be adjusted.
  */
 static int rcu_torture_stall(void *args)
 {
index 0351a4e83529e322f8e96cecb6244f728478fe7b..e4d673fc30f42f9c1278e2c5ee07d1ee894706f3 100644 (file)
@@ -1234,11 +1234,20 @@ static unsigned long srcu_gp_start_if_needed(struct srcu_struct *ssp,
        if (rhp)
                rcu_segcblist_enqueue(&sdp->srcu_cblist, rhp);
        /*
-        * The snapshot for acceleration must be taken _before_ the read of the
-        * current gp sequence used for advancing, otherwise advancing may fail
-        * and acceleration may then fail too.
+        * It's crucial to capture the snapshot 's' for acceleration before
+        * reading the current gp_seq that is used for advancing. This is
+        * essential because if the acceleration snapshot is taken after a
+        * failed advancement attempt, there's a risk that a grace period may
+        * conclude and a new one may start in the interim. If the snapshot is
+        * captured after this sequence of events, the acceleration snapshot 's'
+        * could be excessively advanced, leading to acceleration failure.
+        * In such a scenario, an 'acceleration leak' can occur, where new
+        * callbacks become indefinitely stuck in the RCU_NEXT_TAIL segment.
+        * Also note that encountering advancing failures is a normal
+        * occurrence when the grace period for RCU_WAIT_TAIL is in progress.
         *
-        * This could happen if:
+        * To see this, consider the following events which occur if
+        * rcu_seq_snap() were to be called after advance:
         *
         *  1) The RCU_WAIT_TAIL segment has callbacks (gp_num = X + 4) and the
         *     RCU_NEXT_READY_TAIL also has callbacks (gp_num = X + 8).
@@ -1264,6 +1273,13 @@ static unsigned long srcu_gp_start_if_needed(struct srcu_struct *ssp,
        if (rhp) {
                rcu_segcblist_advance(&sdp->srcu_cblist,
                                      rcu_seq_current(&ssp->srcu_sup->srcu_gp_seq));
+               /*
+                * Acceleration can never fail because the base current gp_seq
+                * used for acceleration is <= the value of gp_seq used for
+                * advancing. This means that RCU_NEXT_TAIL segment will
+                * always be able to be emptied by the acceleration into the
+                * RCU_NEXT_READY_TAIL or RCU_WAIT_TAIL segments.
+                */
                WARN_ON_ONCE(!rcu_segcblist_accelerate(&sdp->srcu_cblist, s));
        }
        if (ULONG_CMP_LT(sdp->srcu_gp_seq_needed, s)) {
index e550f97779b8dc82c950bcf92e0676339688c26e..86df878a2fee8b0b78718d8158c23bbb8137fb6f 100644 (file)
@@ -24,22 +24,6 @@ void rcu_sync_init(struct rcu_sync *rsp)
        init_waitqueue_head(&rsp->gp_wait);
 }
 
-/**
- * rcu_sync_enter_start - Force readers onto slow path for multiple updates
- * @rsp: Pointer to rcu_sync structure to use for synchronization
- *
- * Must be called after rcu_sync_init() and before first use.
- *
- * Ensures rcu_sync_is_idle() returns false and rcu_sync_{enter,exit}()
- * pairs turn into NO-OPs.
- */
-void rcu_sync_enter_start(struct rcu_sync *rsp)
-{
-       rsp->gp_count++;
-       rsp->gp_state = GP_PASSED;
-}
-
-
 static void rcu_sync_func(struct rcu_head *rhp);
 
 static void rcu_sync_call(struct rcu_sync *rsp)
index 732ad5b39946a519bb0ba7a0de35537d4d19f38b..147b5945d67a046dd568e6df586881f8c1a0c25f 100644 (file)
@@ -32,6 +32,7 @@ typedef void (*postgp_func_t)(struct rcu_tasks *rtp);
  * @rtp_irq_work: IRQ work queue for deferred wakeups.
  * @barrier_q_head: RCU callback for barrier operation.
  * @rtp_blkd_tasks: List of tasks blocked as readers.
+ * @rtp_exit_list: List of tasks in the latter portion of do_exit().
  * @cpu: CPU number corresponding to this entry.
  * @rtpp: Pointer to the rcu_tasks structure.
  */
@@ -46,6 +47,7 @@ struct rcu_tasks_percpu {
        struct irq_work rtp_irq_work;
        struct rcu_head barrier_q_head;
        struct list_head rtp_blkd_tasks;
+       struct list_head rtp_exit_list;
        int cpu;
        struct rcu_tasks *rtpp;
 };
@@ -144,8 +146,6 @@ static struct rcu_tasks rt_name =                                                   \
 }
 
 #ifdef CONFIG_TASKS_RCU
-/* Track exiting tasks in order to allow them to be waited for. */
-DEFINE_STATIC_SRCU(tasks_rcu_exit_srcu);
 
 /* Report delay in synchronize_srcu() completion in rcu_tasks_postscan(). */
 static void tasks_rcu_exit_srcu_stall(struct timer_list *unused);
@@ -240,7 +240,6 @@ static const char *tasks_gp_state_getname(struct rcu_tasks *rtp)
 static void cblist_init_generic(struct rcu_tasks *rtp)
 {
        int cpu;
-       unsigned long flags;
        int lim;
        int shift;
 
@@ -266,15 +265,15 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
                WARN_ON_ONCE(!rtpcp);
                if (cpu)
                        raw_spin_lock_init(&ACCESS_PRIVATE(rtpcp, lock));
-               local_irq_save(flags);  // serialize initialization
                if (rcu_segcblist_empty(&rtpcp->cblist))
                        rcu_segcblist_init(&rtpcp->cblist);
-               local_irq_restore(flags);
                INIT_WORK(&rtpcp->rtp_work, rcu_tasks_invoke_cbs_wq);
                rtpcp->cpu = cpu;
                rtpcp->rtpp = rtp;
                if (!rtpcp->rtp_blkd_tasks.next)
                        INIT_LIST_HEAD(&rtpcp->rtp_blkd_tasks);
+               if (!rtpcp->rtp_exit_list.next)
+                       INIT_LIST_HEAD(&rtpcp->rtp_exit_list);
        }
 
        pr_info("%s: Setting shift to %d and lim to %d rcu_task_cb_adjust=%d.\n", rtp->name,
@@ -851,10 +850,12 @@ static void rcu_tasks_wait_gp(struct rcu_tasks *rtp)
 //     number of voluntary context switches, and add that task to the
 //     holdout list.
 // rcu_tasks_postscan():
-//     Invoke synchronize_srcu() to ensure that all tasks that were
-//     in the process of exiting (and which thus might not know to
-//     synchronize with this RCU Tasks grace period) have completed
-//     exiting.
+//     Gather per-CPU lists of tasks in do_exit() to ensure that all
+//     tasks that were in the process of exiting (and which thus might
+//     not know to synchronize with this RCU Tasks grace period) have
+//     completed exiting.  The synchronize_rcu() in rcu_tasks_postgp()
+//     will take care of any tasks stuck in the non-preemptible region
+//     of do_exit() following its call to exit_tasks_rcu_stop().
 // check_all_holdout_tasks(), repeatedly until holdout list is empty:
 //     Scans the holdout list, attempting to identify a quiescent state
 //     for each task on the list.  If there is a quiescent state, the
@@ -867,8 +868,10 @@ static void rcu_tasks_wait_gp(struct rcu_tasks *rtp)
 //     with interrupts disabled.
 //
 // For each exiting task, the exit_tasks_rcu_start() and
-// exit_tasks_rcu_finish() functions begin and end, respectively, the SRCU
-// read-side critical sections waited for by rcu_tasks_postscan().
+// exit_tasks_rcu_finish() functions add and remove, respectively, the
+// current task to a per-CPU list of tasks that rcu_tasks_postscan() must
+// wait on.  This is necessary because rcu_tasks_postscan() must wait on
+// tasks that have already been removed from the global list of tasks.
 //
 // Pre-grace-period update-side code is ordered before the grace
 // via the raw_spin_lock.*rcu_node().  Pre-grace-period read-side code
@@ -932,9 +935,13 @@ static void rcu_tasks_pertask(struct task_struct *t, struct list_head *hop)
        }
 }
 
+void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func);
+DEFINE_RCU_TASKS(rcu_tasks, rcu_tasks_wait_gp, call_rcu_tasks, "RCU Tasks");
+
 /* Processing between scanning taskslist and draining the holdout list. */
 static void rcu_tasks_postscan(struct list_head *hop)
 {
+       int cpu;
        int rtsi = READ_ONCE(rcu_task_stall_info);
 
        if (!IS_ENABLED(CONFIG_TINY_RCU)) {
@@ -948,9 +955,9 @@ static void rcu_tasks_postscan(struct list_head *hop)
         * this, divide the fragile exit path part in two intersecting
         * read side critical sections:
         *
-        * 1) An _SRCU_ read side starting before calling exit_notify(),
-        *    which may remove the task from the tasklist, and ending after
-        *    the final preempt_disable() call in do_exit().
+        * 1) A task_struct list addition before calling exit_notify(),
+        *    which may remove the task from the tasklist, with the
+        *    removal after the final preempt_disable() call in do_exit().
         *
         * 2) An _RCU_ read side starting with the final preempt_disable()
         *    call in do_exit() and ending with the final call to schedule()
@@ -959,7 +966,37 @@ static void rcu_tasks_postscan(struct list_head *hop)
         * This handles the part 1). And postgp will handle part 2) with a
         * call to synchronize_rcu().
         */
-       synchronize_srcu(&tasks_rcu_exit_srcu);
+
+       for_each_possible_cpu(cpu) {
+               unsigned long j = jiffies + 1;
+               struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rcu_tasks.rtpcpu, cpu);
+               struct task_struct *t;
+               struct task_struct *t1;
+               struct list_head tmp;
+
+               raw_spin_lock_irq_rcu_node(rtpcp);
+               list_for_each_entry_safe(t, t1, &rtpcp->rtp_exit_list, rcu_tasks_exit_list) {
+                       if (list_empty(&t->rcu_tasks_holdout_list))
+                               rcu_tasks_pertask(t, hop);
+
+                       // RT kernels need frequent pauses, otherwise
+                       // pause at least once per pair of jiffies.
+                       if (!IS_ENABLED(CONFIG_PREEMPT_RT) && time_before(jiffies, j))
+                               continue;
+
+                       // Keep our place in the list while pausing.
+                       // Nothing else traverses this list, so adding a
+                       // bare list_head is OK.
+                       list_add(&tmp, &t->rcu_tasks_exit_list);
+                       raw_spin_unlock_irq_rcu_node(rtpcp);
+                       cond_resched(); // For CONFIG_PREEMPT=n kernels
+                       raw_spin_lock_irq_rcu_node(rtpcp);
+                       t1 = list_entry(tmp.next, struct task_struct, rcu_tasks_exit_list);
+                       list_del(&tmp);
+                       j = jiffies + 1;
+               }
+               raw_spin_unlock_irq_rcu_node(rtpcp);
+       }
 
        if (!IS_ENABLED(CONFIG_TINY_RCU))
                del_timer_sync(&tasks_rcu_exit_srcu_stall_timer);
@@ -1027,7 +1064,6 @@ static void rcu_tasks_postgp(struct rcu_tasks *rtp)
         *
         * In addition, this synchronize_rcu() waits for exiting tasks
         * to complete their final preempt_disable() region of execution,
-        * cleaning up after synchronize_srcu(&tasks_rcu_exit_srcu),
         * enforcing the whole region before tasklist removal until
         * the final schedule() with TASK_DEAD state to be an RCU TASKS
         * read side critical section.
@@ -1035,9 +1071,6 @@ static void rcu_tasks_postgp(struct rcu_tasks *rtp)
        synchronize_rcu();
 }
 
-void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func);
-DEFINE_RCU_TASKS(rcu_tasks, rcu_tasks_wait_gp, call_rcu_tasks, "RCU Tasks");
-
 static void tasks_rcu_exit_srcu_stall(struct timer_list *unused)
 {
 #ifndef CONFIG_TINY_RCU
@@ -1118,7 +1151,6 @@ module_param(rcu_tasks_lazy_ms, int, 0444);
 
 static int __init rcu_spawn_tasks_kthread(void)
 {
-       cblist_init_generic(&rcu_tasks);
        rcu_tasks.gp_sleep = HZ / 10;
        rcu_tasks.init_fract = HZ / 10;
        if (rcu_tasks_lazy_ms >= 0)
@@ -1147,25 +1179,48 @@ struct task_struct *get_rcu_tasks_gp_kthread(void)
 EXPORT_SYMBOL_GPL(get_rcu_tasks_gp_kthread);
 
 /*
- * Contribute to protect against tasklist scan blind spot while the
- * task is exiting and may be removed from the tasklist. See
- * corresponding synchronize_srcu() for further details.
+ * Protect against tasklist scan blind spot while the task is exiting and
+ * may be removed from the tasklist.  Do this by adding the task to yet
+ * another list.
+ *
+ * Note that the task will remove itself from this list, so there is no
+ * need for get_task_struct(), except in the case where rcu_tasks_pertask()
+ * adds it to the holdout list, in which case rcu_tasks_pertask() supplies
+ * the needed get_task_struct().
  */
-void exit_tasks_rcu_start(void) __acquires(&tasks_rcu_exit_srcu)
+void exit_tasks_rcu_start(void)
 {
-       current->rcu_tasks_idx = __srcu_read_lock(&tasks_rcu_exit_srcu);
+       unsigned long flags;
+       struct rcu_tasks_percpu *rtpcp;
+       struct task_struct *t = current;
+
+       WARN_ON_ONCE(!list_empty(&t->rcu_tasks_exit_list));
+       preempt_disable();
+       rtpcp = this_cpu_ptr(rcu_tasks.rtpcpu);
+       t->rcu_tasks_exit_cpu = smp_processor_id();
+       raw_spin_lock_irqsave_rcu_node(rtpcp, flags);
+       if (!rtpcp->rtp_exit_list.next)
+               INIT_LIST_HEAD(&rtpcp->rtp_exit_list);
+       list_add(&t->rcu_tasks_exit_list, &rtpcp->rtp_exit_list);
+       raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
+       preempt_enable();
 }
 
 /*
- * Contribute to protect against tasklist scan blind spot while the
- * task is exiting and may be removed from the tasklist. See
- * corresponding synchronize_srcu() for further details.
+ * Remove the task from the "yet another list" because do_exit() is now
+ * non-preemptible, allowing synchronize_rcu() to wait beyond this point.
  */
-void exit_tasks_rcu_stop(void) __releases(&tasks_rcu_exit_srcu)
+void exit_tasks_rcu_stop(void)
 {
+       unsigned long flags;
+       struct rcu_tasks_percpu *rtpcp;
        struct task_struct *t = current;
 
-       __srcu_read_unlock(&tasks_rcu_exit_srcu, t->rcu_tasks_idx);
+       WARN_ON_ONCE(list_empty(&t->rcu_tasks_exit_list));
+       rtpcp = per_cpu_ptr(rcu_tasks.rtpcpu, t->rcu_tasks_exit_cpu);
+       raw_spin_lock_irqsave_rcu_node(rtpcp, flags);
+       list_del_init(&t->rcu_tasks_exit_list);
+       raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
 }
 
 /*
@@ -1282,7 +1337,6 @@ module_param(rcu_tasks_rude_lazy_ms, int, 0444);
 
 static int __init rcu_spawn_tasks_rude_kthread(void)
 {
-       cblist_init_generic(&rcu_tasks_rude);
        rcu_tasks_rude.gp_sleep = HZ / 10;
        if (rcu_tasks_rude_lazy_ms >= 0)
                rcu_tasks_rude.lazy_jiffies = msecs_to_jiffies(rcu_tasks_rude_lazy_ms);
@@ -1914,7 +1968,6 @@ module_param(rcu_tasks_trace_lazy_ms, int, 0444);
 
 static int __init rcu_spawn_tasks_trace_kthread(void)
 {
-       cblist_init_generic(&rcu_tasks_trace);
        if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB)) {
                rcu_tasks_trace.gp_sleep = HZ / 10;
                rcu_tasks_trace.init_fract = HZ / 10;
@@ -2086,6 +2139,24 @@ late_initcall(rcu_tasks_verify_schedule_work);
 static void rcu_tasks_initiate_self_tests(void) { }
 #endif /* #else #ifdef CONFIG_PROVE_RCU */
 
+void __init tasks_cblist_init_generic(void)
+{
+       lockdep_assert_irqs_disabled();
+       WARN_ON(num_online_cpus() > 1);
+
+#ifdef CONFIG_TASKS_RCU
+       cblist_init_generic(&rcu_tasks);
+#endif
+
+#ifdef CONFIG_TASKS_RUDE_RCU
+       cblist_init_generic(&rcu_tasks_rude);
+#endif
+
+#ifdef CONFIG_TASKS_TRACE_RCU
+       cblist_init_generic(&rcu_tasks_trace);
+#endif
+}
+
 void __init rcu_init_tasks_generic(void)
 {
 #ifdef CONFIG_TASKS_RCU
index fec804b7908032d4416ea9ff3531eae154bba8f9..705c0d16850aa28db4e0ec7d26d10204e1ed24ce 100644 (file)
@@ -261,4 +261,5 @@ void __init rcu_init(void)
 {
        open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
        rcu_early_boot_tests();
+       tasks_cblist_init_generic();
 }
index b2bccfd37c383d04692fb6a7a72eb71a1f62798b..d9642dd06c2535d9a59682e9b9416d980bd6703c 100644 (file)
@@ -145,7 +145,7 @@ static int rcu_scheduler_fully_active __read_mostly;
 
 static void rcu_report_qs_rnp(unsigned long mask, struct rcu_node *rnp,
                              unsigned long gps, unsigned long flags);
-static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu);
+static struct task_struct *rcu_boost_task(struct rcu_node *rnp);
 static void invoke_rcu_core(void);
 static void rcu_report_exp_rdp(struct rcu_data *rdp);
 static void sync_sched_exp_online_cleanup(int cpu);
@@ -2145,6 +2145,12 @@ static void rcu_do_batch(struct rcu_data *rdp)
         * Extract the list of ready callbacks, disabling IRQs to prevent
         * races with call_rcu() from interrupt handlers.  Leave the
         * callback counts, as rcu_barrier() needs to be conservative.
+        *
+        * Callbacks execution is fully ordered against preceding grace period
+        * completion (materialized by rnp->gp_seq update) thanks to the
+        * smp_mb__after_unlock_lock() upon node locking required for callbacks
+        * advancing. In NOCB mode this ordering is then further relayed through
+        * the nocb locking that protects both callbacks advancing and extraction.
         */
        rcu_nocb_lock_irqsave(rdp, flags);
        WARN_ON_ONCE(cpu_is_offline(smp_processor_id()));
@@ -2591,12 +2597,26 @@ static int __init rcu_spawn_core_kthreads(void)
        return 0;
 }
 
+static void rcutree_enqueue(struct rcu_data *rdp, struct rcu_head *head, rcu_callback_t func)
+{
+       rcu_segcblist_enqueue(&rdp->cblist, head);
+       if (__is_kvfree_rcu_offset((unsigned long)func))
+               trace_rcu_kvfree_callback(rcu_state.name, head,
+                                        (unsigned long)func,
+                                        rcu_segcblist_n_cbs(&rdp->cblist));
+       else
+               trace_rcu_callback(rcu_state.name, head,
+                                  rcu_segcblist_n_cbs(&rdp->cblist));
+       trace_rcu_segcb_stats(&rdp->cblist, TPS("SegCBQueued"));
+}
+
 /*
  * Handle any core-RCU processing required by a call_rcu() invocation.
  */
-static void __call_rcu_core(struct rcu_data *rdp, struct rcu_head *head,
-                           unsigned long flags)
+static void call_rcu_core(struct rcu_data *rdp, struct rcu_head *head,
+                         rcu_callback_t func, unsigned long flags)
 {
+       rcutree_enqueue(rdp, head, func);
        /*
         * If called from an extended quiescent state, invoke the RCU
         * core in order to force a re-evaluation of RCU's idleness.
@@ -2692,7 +2712,6 @@ __call_rcu_common(struct rcu_head *head, rcu_callback_t func, bool lazy_in)
        unsigned long flags;
        bool lazy;
        struct rcu_data *rdp;
-       bool was_alldone;
 
        /* Misaligned rcu_head! */
        WARN_ON_ONCE((unsigned long)head & (sizeof(void *) - 1));
@@ -2729,30 +2748,18 @@ __call_rcu_common(struct rcu_head *head, rcu_callback_t func, bool lazy_in)
        }
 
        check_cb_ovld(rdp);
-       if (rcu_nocb_try_bypass(rdp, head, &was_alldone, flags, lazy))
-               return; // Enqueued onto ->nocb_bypass, so just leave.
-       // If no-CBs CPU gets here, rcu_nocb_try_bypass() acquired ->nocb_lock.
-       rcu_segcblist_enqueue(&rdp->cblist, head);
-       if (__is_kvfree_rcu_offset((unsigned long)func))
-               trace_rcu_kvfree_callback(rcu_state.name, head,
-                                        (unsigned long)func,
-                                        rcu_segcblist_n_cbs(&rdp->cblist));
-       else
-               trace_rcu_callback(rcu_state.name, head,
-                                  rcu_segcblist_n_cbs(&rdp->cblist));
 
-       trace_rcu_segcb_stats(&rdp->cblist, TPS("SegCBQueued"));
-
-       /* Go handle any RCU core processing required. */
-       if (unlikely(rcu_rdp_is_offloaded(rdp))) {
-               __call_rcu_nocb_wake(rdp, was_alldone, flags); /* unlocks */
-       } else {
-               __call_rcu_core(rdp, head, flags);
-               local_irq_restore(flags);
-       }
+       if (unlikely(rcu_rdp_is_offloaded(rdp)))
+               call_rcu_nocb(rdp, head, func, flags, lazy);
+       else
+               call_rcu_core(rdp, head, func, flags);
+       local_irq_restore(flags);
 }
 
 #ifdef CONFIG_RCU_LAZY
+static bool enable_rcu_lazy __read_mostly = !IS_ENABLED(CONFIG_RCU_LAZY_DEFAULT_OFF);
+module_param(enable_rcu_lazy, bool, 0444);
+
 /**
  * call_rcu_hurry() - Queue RCU callback for invocation after grace period, and
  * flush all lazy callbacks (including the new one) to the main ->cblist while
@@ -2778,6 +2785,8 @@ void call_rcu_hurry(struct rcu_head *head, rcu_callback_t func)
        __call_rcu_common(head, func, false);
 }
 EXPORT_SYMBOL_GPL(call_rcu_hurry);
+#else
+#define enable_rcu_lazy                false
 #endif
 
 /**
@@ -2826,7 +2835,7 @@ EXPORT_SYMBOL_GPL(call_rcu_hurry);
  */
 void call_rcu(struct rcu_head *head, rcu_callback_t func)
 {
-       __call_rcu_common(head, func, IS_ENABLED(CONFIG_RCU_LAZY));
+       __call_rcu_common(head, func, enable_rcu_lazy);
 }
 EXPORT_SYMBOL_GPL(call_rcu);
 
@@ -4394,6 +4403,66 @@ rcu_boot_init_percpu_data(int cpu)
        rcu_boot_init_nocb_percpu_data(rdp);
 }
 
+struct kthread_worker *rcu_exp_gp_kworker;
+
+static void rcu_spawn_exp_par_gp_kworker(struct rcu_node *rnp)
+{
+       struct kthread_worker *kworker;
+       const char *name = "rcu_exp_par_gp_kthread_worker/%d";
+       struct sched_param param = { .sched_priority = kthread_prio };
+       int rnp_index = rnp - rcu_get_root();
+
+       if (rnp->exp_kworker)
+               return;
+
+       kworker = kthread_create_worker(0, name, rnp_index);
+       if (IS_ERR_OR_NULL(kworker)) {
+               pr_err("Failed to create par gp kworker on %d/%d\n",
+                      rnp->grplo, rnp->grphi);
+               return;
+       }
+       WRITE_ONCE(rnp->exp_kworker, kworker);
+
+       if (IS_ENABLED(CONFIG_RCU_EXP_KTHREAD))
+               sched_setscheduler_nocheck(kworker->task, SCHED_FIFO, &param);
+}
+
+static struct task_struct *rcu_exp_par_gp_task(struct rcu_node *rnp)
+{
+       struct kthread_worker *kworker = READ_ONCE(rnp->exp_kworker);
+
+       if (!kworker)
+               return NULL;
+
+       return kworker->task;
+}
+
+static void __init rcu_start_exp_gp_kworker(void)
+{
+       const char *name = "rcu_exp_gp_kthread_worker";
+       struct sched_param param = { .sched_priority = kthread_prio };
+
+       rcu_exp_gp_kworker = kthread_create_worker(0, name);
+       if (IS_ERR_OR_NULL(rcu_exp_gp_kworker)) {
+               pr_err("Failed to create %s!\n", name);
+               rcu_exp_gp_kworker = NULL;
+               return;
+       }
+
+       if (IS_ENABLED(CONFIG_RCU_EXP_KTHREAD))
+               sched_setscheduler_nocheck(rcu_exp_gp_kworker->task, SCHED_FIFO, &param);
+}
+
+static void rcu_spawn_rnp_kthreads(struct rcu_node *rnp)
+{
+       if (rcu_scheduler_fully_active) {
+               mutex_lock(&rnp->kthread_mutex);
+               rcu_spawn_one_boost_kthread(rnp);
+               rcu_spawn_exp_par_gp_kworker(rnp);
+               mutex_unlock(&rnp->kthread_mutex);
+       }
+}
+
 /*
  * Invoked early in the CPU-online process, when pretty much all services
  * are available.  The incoming CPU is not present.
@@ -4442,7 +4511,7 @@ int rcutree_prepare_cpu(unsigned int cpu)
        rdp->rcu_iw_gp_seq = rdp->gp_seq - 1;
        trace_rcu_grace_period(rcu_state.name, rdp->gp_seq, TPS("cpuonl"));
        raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
-       rcu_spawn_one_boost_kthread(rnp);
+       rcu_spawn_rnp_kthreads(rnp);
        rcu_spawn_cpu_nocb_kthread(cpu);
        WRITE_ONCE(rcu_state.n_online_cpus, rcu_state.n_online_cpus + 1);
 
@@ -4450,13 +4519,64 @@ int rcutree_prepare_cpu(unsigned int cpu)
 }
 
 /*
- * Update RCU priority boot kthread affinity for CPU-hotplug changes.
+ * Update kthreads affinity during CPU-hotplug changes.
+ *
+ * Set the per-rcu_node kthread's affinity to cover all CPUs that are
+ * served by the rcu_node in question.  The CPU hotplug lock is still
+ * held, so the value of rnp->qsmaskinit will be stable.
+ *
+ * We don't include outgoingcpu in the affinity set, use -1 if there is
+ * no outgoing CPU.  If there are no CPUs left in the affinity set,
+ * this function allows the kthread to execute on any CPU.
+ *
+ * Any future concurrent calls are serialized via ->kthread_mutex.
  */
-static void rcutree_affinity_setting(unsigned int cpu, int outgoing)
+static void rcutree_affinity_setting(unsigned int cpu, int outgoingcpu)
 {
-       struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
+       cpumask_var_t cm;
+       unsigned long mask;
+       struct rcu_data *rdp;
+       struct rcu_node *rnp;
+       struct task_struct *task_boost, *task_exp;
+
+       rdp = per_cpu_ptr(&rcu_data, cpu);
+       rnp = rdp->mynode;
+
+       task_boost = rcu_boost_task(rnp);
+       task_exp = rcu_exp_par_gp_task(rnp);
+
+       /*
+        * If CPU is the boot one, those tasks are created later from early
+        * initcall since kthreadd must be created first.
+        */
+       if (!task_boost && !task_exp)
+               return;
+
+       if (!zalloc_cpumask_var(&cm, GFP_KERNEL))
+               return;
+
+       mutex_lock(&rnp->kthread_mutex);
+       mask = rcu_rnp_online_cpus(rnp);
+       for_each_leaf_node_possible_cpu(rnp, cpu)
+               if ((mask & leaf_node_cpu_bit(rnp, cpu)) &&
+                   cpu != outgoingcpu)
+                       cpumask_set_cpu(cpu, cm);
+       cpumask_and(cm, cm, housekeeping_cpumask(HK_TYPE_RCU));
+       if (cpumask_empty(cm)) {
+               cpumask_copy(cm, housekeeping_cpumask(HK_TYPE_RCU));
+               if (outgoingcpu >= 0)
+                       cpumask_clear_cpu(outgoingcpu, cm);
+       }
+
+       if (task_exp)
+               set_cpus_allowed_ptr(task_exp, cm);
+
+       if (task_boost)
+               set_cpus_allowed_ptr(task_boost, cm);
 
-       rcu_boost_kthread_setaffinity(rdp->mynode, outgoing);
+       mutex_unlock(&rnp->kthread_mutex);
+
+       free_cpumask_var(cm);
 }
 
 /*
@@ -4640,8 +4760,9 @@ void rcutree_migrate_callbacks(int cpu)
                __call_rcu_nocb_wake(my_rdp, true, flags);
        } else {
                rcu_nocb_unlock(my_rdp); /* irqs remain disabled. */
-               raw_spin_unlock_irqrestore_rcu_node(my_rnp, flags);
+               raw_spin_unlock_rcu_node(my_rnp); /* irqs remain disabled. */
        }
+       local_irq_restore(flags);
        if (needwake)
                rcu_gp_kthread_wake();
        lockdep_assert_irqs_enabled();
@@ -4730,51 +4851,6 @@ static int rcu_pm_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-#ifdef CONFIG_RCU_EXP_KTHREAD
-struct kthread_worker *rcu_exp_gp_kworker;
-struct kthread_worker *rcu_exp_par_gp_kworker;
-
-static void __init rcu_start_exp_gp_kworkers(void)
-{
-       const char *par_gp_kworker_name = "rcu_exp_par_gp_kthread_worker";
-       const char *gp_kworker_name = "rcu_exp_gp_kthread_worker";
-       struct sched_param param = { .sched_priority = kthread_prio };
-
-       rcu_exp_gp_kworker = kthread_create_worker(0, gp_kworker_name);
-       if (IS_ERR_OR_NULL(rcu_exp_gp_kworker)) {
-               pr_err("Failed to create %s!\n", gp_kworker_name);
-               return;
-       }
-
-       rcu_exp_par_gp_kworker = kthread_create_worker(0, par_gp_kworker_name);
-       if (IS_ERR_OR_NULL(rcu_exp_par_gp_kworker)) {
-               pr_err("Failed to create %s!\n", par_gp_kworker_name);
-               kthread_destroy_worker(rcu_exp_gp_kworker);
-               return;
-       }
-
-       sched_setscheduler_nocheck(rcu_exp_gp_kworker->task, SCHED_FIFO, &param);
-       sched_setscheduler_nocheck(rcu_exp_par_gp_kworker->task, SCHED_FIFO,
-                                  &param);
-}
-
-static inline void rcu_alloc_par_gp_wq(void)
-{
-}
-#else /* !CONFIG_RCU_EXP_KTHREAD */
-struct workqueue_struct *rcu_par_gp_wq;
-
-static void __init rcu_start_exp_gp_kworkers(void)
-{
-}
-
-static inline void rcu_alloc_par_gp_wq(void)
-{
-       rcu_par_gp_wq = alloc_workqueue("rcu_par_gp", WQ_MEM_RECLAIM, 0);
-       WARN_ON(!rcu_par_gp_wq);
-}
-#endif /* CONFIG_RCU_EXP_KTHREAD */
-
 /*
  * Spawn the kthreads that handle RCU's grace periods.
  */
@@ -4809,10 +4885,10 @@ static int __init rcu_spawn_gp_kthread(void)
         * due to rcu_scheduler_fully_active.
         */
        rcu_spawn_cpu_nocb_kthread(smp_processor_id());
-       rcu_spawn_one_boost_kthread(rdp->mynode);
+       rcu_spawn_rnp_kthreads(rdp->mynode);
        rcu_spawn_core_kthreads();
        /* Create kthread worker for expedited GPs */
-       rcu_start_exp_gp_kworkers();
+       rcu_start_exp_gp_kworker();
        return 0;
 }
 early_initcall(rcu_spawn_gp_kthread);
@@ -4915,7 +4991,7 @@ static void __init rcu_init_one(void)
                        init_waitqueue_head(&rnp->exp_wq[2]);
                        init_waitqueue_head(&rnp->exp_wq[3]);
                        spin_lock_init(&rnp->exp_lock);
-                       mutex_init(&rnp->boost_kthread_mutex);
+                       mutex_init(&rnp->kthread_mutex);
                        raw_spin_lock_init(&rnp->exp_poll_lock);
                        rnp->exp_seq_poll_rq = RCU_GET_STATE_COMPLETED;
                        INIT_WORK(&rnp->exp_poll_wq, sync_rcu_do_polled_gp);
@@ -5152,7 +5228,6 @@ void __init rcu_init(void)
        /* Create workqueue for Tree SRCU and for expedited GPs. */
        rcu_gp_wq = alloc_workqueue("rcu_gp", WQ_MEM_RECLAIM, 0);
        WARN_ON(!rcu_gp_wq);
-       rcu_alloc_par_gp_wq();
 
        /* Fill in default value for rcutree.qovld boot parameter. */
        /* -After- the rcu_node ->lock fields are initialized! */
@@ -5165,6 +5240,8 @@ void __init rcu_init(void)
        (void)start_poll_synchronize_rcu_expedited();
 
        rcu_test_sync_prims();
+
+       tasks_cblist_init_generic();
 }
 
 #include "tree_stall.h"
index e9821a8422dbe7d327f875a633a8d4fc1348feba..df48160b3136dca1b668a3e0d275832ccc273dd3 100644 (file)
 
 #include "rcu_segcblist.h"
 
-/* Communicate arguments to a workqueue handler. */
+/* Communicate arguments to a kthread worker handler. */
 struct rcu_exp_work {
        unsigned long rew_s;
-#ifdef CONFIG_RCU_EXP_KTHREAD
        struct kthread_work rew_work;
-#else
-       struct work_struct rew_work;
-#endif /* CONFIG_RCU_EXP_KTHREAD */
 };
 
 /* RCU's kthread states for tracing. */
@@ -72,6 +68,9 @@ struct rcu_node {
                                /* Online CPUs for next expedited GP. */
                                /*  Any CPU that has ever been online will */
                                /*  have its bit set. */
+       struct kthread_worker *exp_kworker;
+                               /* Workers performing per node expedited GP */
+                               /* initialization. */
        unsigned long cbovldmask;
                                /* CPUs experiencing callback overload. */
        unsigned long ffmask;   /* Fully functional CPUs. */
@@ -113,7 +112,7 @@ struct rcu_node {
                                /*  side effect, not as a lock. */
        unsigned long boost_time;
                                /* When to start boosting (jiffies). */
-       struct mutex boost_kthread_mutex;
+       struct mutex kthread_mutex;
                                /* Exclusion for thread spawning and affinity */
                                /*  manipulation. */
        struct task_struct *boost_kthread_task;
@@ -467,11 +466,10 @@ static void rcu_init_one_nocb(struct rcu_node *rnp);
 static bool wake_nocb_gp(struct rcu_data *rdp, bool force);
 static bool rcu_nocb_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
                                  unsigned long j, bool lazy);
-static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
-                               bool *was_alldone, unsigned long flags,
-                               bool lazy);
-static void __call_rcu_nocb_wake(struct rcu_data *rdp, bool was_empty,
-                                unsigned long flags);
+static void call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *head,
+                         rcu_callback_t func, unsigned long flags, bool lazy);
+static void __maybe_unused __call_rcu_nocb_wake(struct rcu_data *rdp, bool was_empty,
+                                               unsigned long flags);
 static int rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp, int level);
 static bool do_nocb_deferred_wakeup(struct rcu_data *rdp);
 static void rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp);
index 2ac440bc7e10bc8e1248eae47a661eb017768cee..6b83537480b12f01c05be827b3eeae87dbb4c6ce 100644 (file)
@@ -198,10 +198,9 @@ static void __rcu_report_exp_rnp(struct rcu_node *rnp,
                }
                if (rnp->parent == NULL) {
                        raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
-                       if (wake) {
-                               smp_mb(); /* EGP done before wake_up(). */
+                       if (wake)
                                swake_up_one_online(&rcu_state.expedited_wq);
-                       }
+
                        break;
                }
                mask = rnp->grpmask;
@@ -419,7 +418,6 @@ retry_ipi:
 
 static void rcu_exp_sel_wait_wake(unsigned long s);
 
-#ifdef CONFIG_RCU_EXP_KTHREAD
 static void sync_rcu_exp_select_node_cpus(struct kthread_work *wp)
 {
        struct rcu_exp_work *rewp =
@@ -428,9 +426,14 @@ static void sync_rcu_exp_select_node_cpus(struct kthread_work *wp)
        __sync_rcu_exp_select_node_cpus(rewp);
 }
 
-static inline bool rcu_gp_par_worker_started(void)
+static inline bool rcu_exp_worker_started(void)
+{
+       return !!READ_ONCE(rcu_exp_gp_kworker);
+}
+
+static inline bool rcu_exp_par_worker_started(struct rcu_node *rnp)
 {
-       return !!READ_ONCE(rcu_exp_par_gp_kworker);
+       return !!READ_ONCE(rnp->exp_kworker);
 }
 
 static inline void sync_rcu_exp_select_cpus_queue_work(struct rcu_node *rnp)
@@ -441,7 +444,7 @@ static inline void sync_rcu_exp_select_cpus_queue_work(struct rcu_node *rnp)
         * another work item on the same kthread worker can result in
         * deadlock.
         */
-       kthread_queue_work(rcu_exp_par_gp_kworker, &rnp->rew.rew_work);
+       kthread_queue_work(READ_ONCE(rnp->exp_kworker), &rnp->rew.rew_work);
 }
 
 static inline void sync_rcu_exp_select_cpus_flush_work(struct rcu_node *rnp)
@@ -466,64 +469,6 @@ static inline void synchronize_rcu_expedited_queue_work(struct rcu_exp_work *rew
        kthread_queue_work(rcu_exp_gp_kworker, &rew->rew_work);
 }
 
-static inline void synchronize_rcu_expedited_destroy_work(struct rcu_exp_work *rew)
-{
-}
-#else /* !CONFIG_RCU_EXP_KTHREAD */
-static void sync_rcu_exp_select_node_cpus(struct work_struct *wp)
-{
-       struct rcu_exp_work *rewp =
-               container_of(wp, struct rcu_exp_work, rew_work);
-
-       __sync_rcu_exp_select_node_cpus(rewp);
-}
-
-static inline bool rcu_gp_par_worker_started(void)
-{
-       return !!READ_ONCE(rcu_par_gp_wq);
-}
-
-static inline void sync_rcu_exp_select_cpus_queue_work(struct rcu_node *rnp)
-{
-       int cpu = find_next_bit(&rnp->ffmask, BITS_PER_LONG, -1);
-
-       INIT_WORK(&rnp->rew.rew_work, sync_rcu_exp_select_node_cpus);
-       /* If all offline, queue the work on an unbound CPU. */
-       if (unlikely(cpu > rnp->grphi - rnp->grplo))
-               cpu = WORK_CPU_UNBOUND;
-       else
-               cpu += rnp->grplo;
-       queue_work_on(cpu, rcu_par_gp_wq, &rnp->rew.rew_work);
-}
-
-static inline void sync_rcu_exp_select_cpus_flush_work(struct rcu_node *rnp)
-{
-       flush_work(&rnp->rew.rew_work);
-}
-
-/*
- * Work-queue handler to drive an expedited grace period forward.
- */
-static void wait_rcu_exp_gp(struct work_struct *wp)
-{
-       struct rcu_exp_work *rewp;
-
-       rewp = container_of(wp, struct rcu_exp_work, rew_work);
-       rcu_exp_sel_wait_wake(rewp->rew_s);
-}
-
-static inline void synchronize_rcu_expedited_queue_work(struct rcu_exp_work *rew)
-{
-       INIT_WORK_ONSTACK(&rew->rew_work, wait_rcu_exp_gp);
-       queue_work(rcu_gp_wq, &rew->rew_work);
-}
-
-static inline void synchronize_rcu_expedited_destroy_work(struct rcu_exp_work *rew)
-{
-       destroy_work_on_stack(&rew->rew_work);
-}
-#endif /* CONFIG_RCU_EXP_KTHREAD */
-
 /*
  * Select the nodes that the upcoming expedited grace period needs
  * to wait for.
@@ -541,7 +486,7 @@ static void sync_rcu_exp_select_cpus(void)
                rnp->exp_need_flush = false;
                if (!READ_ONCE(rnp->expmask))
                        continue; /* Avoid early boot non-existent wq. */
-               if (!rcu_gp_par_worker_started() ||
+               if (!rcu_exp_par_worker_started(rnp) ||
                    rcu_scheduler_active != RCU_SCHEDULER_RUNNING ||
                    rcu_is_last_leaf_node(rnp)) {
                        /* No worker started yet or last leaf, do direct call. */
@@ -956,7 +901,6 @@ static void rcu_exp_print_detail_task_stall_rnp(struct rcu_node *rnp)
  */
 void synchronize_rcu_expedited(void)
 {
-       bool boottime = (rcu_scheduler_active == RCU_SCHEDULER_INIT);
        unsigned long flags;
        struct rcu_exp_work rew;
        struct rcu_node *rnp;
@@ -996,7 +940,7 @@ void synchronize_rcu_expedited(void)
                return;  /* Someone else did our work for us. */
 
        /* Ensure that load happens before action based on it. */
-       if (unlikely(boottime)) {
+       if (unlikely((rcu_scheduler_active == RCU_SCHEDULER_INIT) || !rcu_exp_worker_started())) {
                /* Direct call during scheduler init and early_initcalls(). */
                rcu_exp_sel_wait_wake(s);
        } else {
@@ -1013,9 +957,6 @@ void synchronize_rcu_expedited(void)
 
        /* Let the next expedited grace period start. */
        mutex_unlock(&rcu_state.exp_mutex);
-
-       if (likely(!boottime))
-               synchronize_rcu_expedited_destroy_work(&rew);
 }
 EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
 
index 4efbf7333d4e168c3bbaca61b43b919d5ce3fe26..3f85577bddd4ef101cbfc682a3c9622ca816d14a 100644 (file)
@@ -256,6 +256,7 @@ static bool wake_nocb_gp(struct rcu_data *rdp, bool force)
        return __wake_nocb_gp(rdp_gp, rdp, force, flags);
 }
 
+#ifdef CONFIG_RCU_LAZY
 /*
  * LAZY_FLUSH_JIFFIES decides the maximum amount of time that
  * can elapse before lazy callbacks are flushed. Lazy callbacks
@@ -264,21 +265,20 @@ static bool wake_nocb_gp(struct rcu_data *rdp, bool force)
  * left unsubmitted to RCU after those many jiffies.
  */
 #define LAZY_FLUSH_JIFFIES (10 * HZ)
-static unsigned long jiffies_till_flush = LAZY_FLUSH_JIFFIES;
+static unsigned long jiffies_lazy_flush = LAZY_FLUSH_JIFFIES;
 
-#ifdef CONFIG_RCU_LAZY
 // To be called only from test code.
-void rcu_lazy_set_jiffies_till_flush(unsigned long jif)
+void rcu_set_jiffies_lazy_flush(unsigned long jif)
 {
-       jiffies_till_flush = jif;
+       jiffies_lazy_flush = jif;
 }
-EXPORT_SYMBOL(rcu_lazy_set_jiffies_till_flush);
+EXPORT_SYMBOL(rcu_set_jiffies_lazy_flush);
 
-unsigned long rcu_lazy_get_jiffies_till_flush(void)
+unsigned long rcu_get_jiffies_lazy_flush(void)
 {
-       return jiffies_till_flush;
+       return jiffies_lazy_flush;
 }
-EXPORT_SYMBOL(rcu_lazy_get_jiffies_till_flush);
+EXPORT_SYMBOL(rcu_get_jiffies_lazy_flush);
 #endif
 
 /*
@@ -299,7 +299,7 @@ static void wake_nocb_gp_defer(struct rcu_data *rdp, int waketype,
         */
        if (waketype == RCU_NOCB_WAKE_LAZY &&
            rdp->nocb_defer_wakeup == RCU_NOCB_WAKE_NOT) {
-               mod_timer(&rdp_gp->nocb_timer, jiffies + jiffies_till_flush);
+               mod_timer(&rdp_gp->nocb_timer, jiffies + rcu_get_jiffies_lazy_flush());
                WRITE_ONCE(rdp_gp->nocb_defer_wakeup, waketype);
        } else if (waketype == RCU_NOCB_WAKE_BYPASS) {
                mod_timer(&rdp_gp->nocb_timer, jiffies + 2);
@@ -482,7 +482,7 @@ static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
        // flush ->nocb_bypass to ->cblist.
        if ((ncbs && !bypass_is_lazy && j != READ_ONCE(rdp->nocb_bypass_first)) ||
            (ncbs &&  bypass_is_lazy &&
-            (time_after(j, READ_ONCE(rdp->nocb_bypass_first) + jiffies_till_flush))) ||
+            (time_after(j, READ_ONCE(rdp->nocb_bypass_first) + rcu_get_jiffies_lazy_flush()))) ||
            ncbs >= qhimark) {
                rcu_nocb_lock(rdp);
                *was_alldone = !rcu_segcblist_pend_cbs(&rdp->cblist);
@@ -532,9 +532,7 @@ static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
        // 2. Both of these conditions are met:
        //    a. The bypass list previously had only lazy CBs, and:
        //    b. The new CB is non-lazy.
-       if (ncbs && (!bypass_is_lazy || lazy)) {
-               local_irq_restore(flags);
-       } else {
+       if (!ncbs || (bypass_is_lazy && !lazy)) {
                // No-CBs GP kthread might be indefinitely asleep, if so, wake.
                rcu_nocb_lock(rdp); // Rare during call_rcu() flood.
                if (!rcu_segcblist_pend_cbs(&rdp->cblist)) {
@@ -544,7 +542,7 @@ static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
                } else {
                        trace_rcu_nocb_wake(rcu_state.name, rdp->cpu,
                                            TPS("FirstBQnoWake"));
-                       rcu_nocb_unlock_irqrestore(rdp, flags);
+                       rcu_nocb_unlock(rdp);
                }
        }
        return true; // Callback already enqueued.
@@ -566,11 +564,12 @@ static void __call_rcu_nocb_wake(struct rcu_data *rdp, bool was_alldone,
        long lazy_len;
        long len;
        struct task_struct *t;
+       struct rcu_data *rdp_gp = rdp->nocb_gp_rdp;
 
        // If we are being polled or there is no kthread, just leave.
        t = READ_ONCE(rdp->nocb_gp_kthread);
        if (rcu_nocb_poll || !t) {
-               rcu_nocb_unlock_irqrestore(rdp, flags);
+               rcu_nocb_unlock(rdp);
                trace_rcu_nocb_wake(rcu_state.name, rdp->cpu,
                                    TPS("WakeNotPoll"));
                return;
@@ -583,17 +582,17 @@ static void __call_rcu_nocb_wake(struct rcu_data *rdp, bool was_alldone,
                rdp->qlen_last_fqs_check = len;
                // Only lazy CBs in bypass list
                if (lazy_len && bypass_len == lazy_len) {
-                       rcu_nocb_unlock_irqrestore(rdp, flags);
+                       rcu_nocb_unlock(rdp);
                        wake_nocb_gp_defer(rdp, RCU_NOCB_WAKE_LAZY,
                                           TPS("WakeLazy"));
                } else if (!irqs_disabled_flags(flags)) {
                        /* ... if queue was empty ... */
-                       rcu_nocb_unlock_irqrestore(rdp, flags);
+                       rcu_nocb_unlock(rdp);
                        wake_nocb_gp(rdp, false);
                        trace_rcu_nocb_wake(rcu_state.name, rdp->cpu,
                                            TPS("WakeEmpty"));
                } else {
-                       rcu_nocb_unlock_irqrestore(rdp, flags);
+                       rcu_nocb_unlock(rdp);
                        wake_nocb_gp_defer(rdp, RCU_NOCB_WAKE,
                                           TPS("WakeEmptyIsDeferred"));
                }
@@ -610,20 +609,32 @@ static void __call_rcu_nocb_wake(struct rcu_data *rdp, bool was_alldone,
                smp_mb(); /* Enqueue before timer_pending(). */
                if ((rdp->nocb_cb_sleep ||
                     !rcu_segcblist_ready_cbs(&rdp->cblist)) &&
-                   !timer_pending(&rdp->nocb_timer)) {
-                       rcu_nocb_unlock_irqrestore(rdp, flags);
+                   !timer_pending(&rdp_gp->nocb_timer)) {
+                       rcu_nocb_unlock(rdp);
                        wake_nocb_gp_defer(rdp, RCU_NOCB_WAKE_FORCE,
                                           TPS("WakeOvfIsDeferred"));
                } else {
-                       rcu_nocb_unlock_irqrestore(rdp, flags);
+                       rcu_nocb_unlock(rdp);
                        trace_rcu_nocb_wake(rcu_state.name, rdp->cpu, TPS("WakeNot"));
                }
        } else {
-               rcu_nocb_unlock_irqrestore(rdp, flags);
+               rcu_nocb_unlock(rdp);
                trace_rcu_nocb_wake(rcu_state.name, rdp->cpu, TPS("WakeNot"));
        }
 }
 
+static void call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *head,
+                         rcu_callback_t func, unsigned long flags, bool lazy)
+{
+       bool was_alldone;
+
+       if (!rcu_nocb_try_bypass(rdp, head, &was_alldone, flags, lazy)) {
+               /* Not enqueued on bypass but locked, do regular enqueue */
+               rcutree_enqueue(rdp, head, func);
+               __call_rcu_nocb_wake(rdp, was_alldone, flags); /* unlocks */
+       }
+}
+
 static int nocb_gp_toggle_rdp(struct rcu_data *rdp,
                               bool *wake_state)
 {
@@ -723,7 +734,7 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
                lazy_ncbs = READ_ONCE(rdp->lazy_len);
 
                if (bypass_ncbs && (lazy_ncbs == bypass_ncbs) &&
-                   (time_after(j, READ_ONCE(rdp->nocb_bypass_first) + jiffies_till_flush) ||
+                   (time_after(j, READ_ONCE(rdp->nocb_bypass_first) + rcu_get_jiffies_lazy_flush()) ||
                     bypass_ncbs > 2 * qhimark)) {
                        flush_bypass = true;
                } else if (bypass_ncbs && (lazy_ncbs != bypass_ncbs) &&
@@ -779,7 +790,6 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
                if (rcu_segcblist_ready_cbs(&rdp->cblist)) {
                        needwake = rdp->nocb_cb_sleep;
                        WRITE_ONCE(rdp->nocb_cb_sleep, false);
-                       smp_mb(); /* CB invocation -after- GP end. */
                } else {
                        needwake = false;
                }
@@ -933,8 +943,7 @@ static void nocb_cb_wait(struct rcu_data *rdp)
                swait_event_interruptible_exclusive(rdp->nocb_cb_wq,
                                                    nocb_cb_wait_cond(rdp));
 
-               // VVV Ensure CB invocation follows _sleep test.
-               if (smp_load_acquire(&rdp->nocb_cb_sleep)) { // ^^^
+               if (READ_ONCE(rdp->nocb_cb_sleep)) {
                        WARN_ON(signal_pending(current));
                        trace_rcu_nocb_wake(rcu_state.name, rdp->cpu, TPS("WokeEmpty"));
                }
@@ -1383,7 +1392,7 @@ lazy_rcu_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
                        rcu_nocb_unlock_irqrestore(rdp, flags);
                        continue;
                }
-               WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, jiffies, false));
+               rcu_nocb_try_flush_bypass(rdp, jiffies);
                rcu_nocb_unlock_irqrestore(rdp, flags);
                wake_nocb_gp(rdp, false);
                sc->nr_to_scan -= _count;
@@ -1768,10 +1777,10 @@ static bool rcu_nocb_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
        return true;
 }
 
-static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
-                               bool *was_alldone, unsigned long flags, bool lazy)
+static void call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *head,
+                         rcu_callback_t func, unsigned long flags, bool lazy)
 {
-       return false;
+       WARN_ON_ONCE(1);  /* Should be dead code! */
 }
 
 static void __call_rcu_nocb_wake(struct rcu_data *rdp, bool was_empty,
index 41021080ad258d7f68d43762ceb2299266754712..36a8b5dbf5b52ecff9e879f102a53fa6cd264474 100644 (file)
@@ -1195,14 +1195,13 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp)
        struct sched_param sp;
        struct task_struct *t;
 
-       mutex_lock(&rnp->boost_kthread_mutex);
-       if (rnp->boost_kthread_task || !rcu_scheduler_fully_active)
-               goto out;
+       if (rnp->boost_kthread_task)
+               return;
 
        t = kthread_create(rcu_boost_kthread, (void *)rnp,
                           "rcub/%d", rnp_index);
        if (WARN_ON_ONCE(IS_ERR(t)))
-               goto out;
+               return;
 
        raw_spin_lock_irqsave_rcu_node(rnp, flags);
        rnp->boost_kthread_task = t;
@@ -1210,48 +1209,11 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp)
        sp.sched_priority = kthread_prio;
        sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
        wake_up_process(t); /* get to TASK_INTERRUPTIBLE quickly. */
-
- out:
-       mutex_unlock(&rnp->boost_kthread_mutex);
 }
 
-/*
- * Set the per-rcu_node kthread's affinity to cover all CPUs that are
- * served by the rcu_node in question.  The CPU hotplug lock is still
- * held, so the value of rnp->qsmaskinit will be stable.
- *
- * We don't include outgoingcpu in the affinity set, use -1 if there is
- * no outgoing CPU.  If there are no CPUs left in the affinity set,
- * this function allows the kthread to execute on any CPU.
- *
- * Any future concurrent calls are serialized via ->boost_kthread_mutex.
- */
-static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
+static struct task_struct *rcu_boost_task(struct rcu_node *rnp)
 {
-       struct task_struct *t = rnp->boost_kthread_task;
-       unsigned long mask;
-       cpumask_var_t cm;
-       int cpu;
-
-       if (!t)
-               return;
-       if (!zalloc_cpumask_var(&cm, GFP_KERNEL))
-               return;
-       mutex_lock(&rnp->boost_kthread_mutex);
-       mask = rcu_rnp_online_cpus(rnp);
-       for_each_leaf_node_possible_cpu(rnp, cpu)
-               if ((mask & leaf_node_cpu_bit(rnp, cpu)) &&
-                   cpu != outgoingcpu)
-                       cpumask_set_cpu(cpu, cm);
-       cpumask_and(cm, cm, housekeeping_cpumask(HK_TYPE_RCU));
-       if (cpumask_empty(cm)) {
-               cpumask_copy(cm, housekeeping_cpumask(HK_TYPE_RCU));
-               if (outgoingcpu >= 0)
-                       cpumask_clear_cpu(outgoingcpu, cm);
-       }
-       set_cpus_allowed_ptr(t, cm);
-       mutex_unlock(&rnp->boost_kthread_mutex);
-       free_cpumask_var(cm);
+       return READ_ONCE(rnp->boost_kthread_task);
 }
 
 #else /* #ifdef CONFIG_RCU_BOOST */
@@ -1270,10 +1232,10 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp)
 {
 }
 
-static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
+static struct task_struct *rcu_boost_task(struct rcu_node *rnp)
 {
+       return NULL;
 }
-
 #endif /* #else #ifdef CONFIG_RCU_BOOST */
 
 /*
index 9116bcc903467fe0d5854e3deb06b8d334cf85eb..d44efa0d06112a8b4f022fe450aa7725987dca9b 100644 (file)
@@ -1792,7 +1792,6 @@ static void cpu_util_update_eff(struct cgroup_subsys_state *css);
 #endif
 
 #ifdef CONFIG_SYSCTL
-#ifdef CONFIG_UCLAMP_TASK
 #ifdef CONFIG_UCLAMP_TASK_GROUP
 static void uclamp_update_root_tg(void)
 {
@@ -1898,7 +1897,6 @@ undo:
        return result;
 }
 #endif
-#endif
 
 static int uclamp_validate(struct task_struct *p,
                           const struct sched_attr *attr)
@@ -2065,7 +2063,7 @@ static void __init init_uclamp(void)
        }
 }
 
-#else /* CONFIG_UCLAMP_TASK */
+#else /* !CONFIG_UCLAMP_TASK */
 static inline void uclamp_rq_inc(struct rq *rq, struct task_struct *p) { }
 static inline void uclamp_rq_dec(struct rq *rq, struct task_struct *p) { }
 static inline int uclamp_validate(struct task_struct *p,
@@ -3955,6 +3953,17 @@ void wake_up_if_idle(int cpu)
        }
 }
 
+bool cpus_equal_capacity(int this_cpu, int that_cpu)
+{
+       if (!sched_asym_cpucap_active())
+               return true;
+
+       if (this_cpu == that_cpu)
+               return true;
+
+       return arch_scale_cpu_capacity(this_cpu) == arch_scale_cpu_capacity(that_cpu);
+}
+
 bool cpus_share_cache(int this_cpu, int that_cpu)
 {
        if (this_cpu == that_cpu)
@@ -6787,10 +6796,12 @@ static inline void sched_submit_work(struct task_struct *tsk)
 
 static void sched_update_worker(struct task_struct *tsk)
 {
-       if (tsk->flags & (PF_WQ_WORKER | PF_IO_WORKER)) {
+       if (tsk->flags & (PF_WQ_WORKER | PF_IO_WORKER | PF_BLOCK_TS)) {
+               if (tsk->flags & PF_BLOCK_TS)
+                       blk_plug_invalidate_ts(tsk);
                if (tsk->flags & PF_WQ_WORKER)
                        wq_worker_running(tsk);
-               else
+               else if (tsk->flags & PF_IO_WORKER)
                        io_wq_worker_running(tsk);
        }
 }
index 533547e3c90a755f58bd0261570c7904a2bffb9e..6a16129f9a5c0a90655bb37277c52f4dc1137721 100644 (file)
@@ -7289,7 +7289,7 @@ static int select_idle_core(struct task_struct *p, int core, struct cpumask *cpu
                if (!available_idle_cpu(cpu)) {
                        idle = false;
                        if (*idle_cpu == -1) {
-                               if (sched_idle_cpu(cpu) && cpumask_test_cpu(cpu, p->cpus_ptr)) {
+                               if (sched_idle_cpu(cpu) && cpumask_test_cpu(cpu, cpus)) {
                                        *idle_cpu = cpu;
                                        break;
                                }
@@ -7297,7 +7297,7 @@ static int select_idle_core(struct task_struct *p, int core, struct cpumask *cpu
                        }
                        break;
                }
-               if (*idle_cpu == -1 && cpumask_test_cpu(cpu, p->cpus_ptr))
+               if (*idle_cpu == -1 && cpumask_test_cpu(cpu, cpus))
                        *idle_cpu = cpu;
        }
 
@@ -7311,13 +7311,19 @@ static int select_idle_core(struct task_struct *p, int core, struct cpumask *cpu
 /*
  * Scan the local SMT mask for idle CPUs.
  */
-static int select_idle_smt(struct task_struct *p, int target)
+static int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int target)
 {
        int cpu;
 
        for_each_cpu_and(cpu, cpu_smt_mask(target), p->cpus_ptr) {
                if (cpu == target)
                        continue;
+               /*
+                * Check if the CPU is in the LLC scheduling domain of @target.
+                * Due to isolcpus, there is no guarantee that all the siblings are in the domain.
+                */
+               if (!cpumask_test_cpu(cpu, sched_domain_span(sd)))
+                       continue;
                if (available_idle_cpu(cpu) || sched_idle_cpu(cpu))
                        return cpu;
        }
@@ -7341,7 +7347,7 @@ static inline int select_idle_core(struct task_struct *p, int core, struct cpuma
        return __select_idle_cpu(core, p);
 }
 
-static inline int select_idle_smt(struct task_struct *p, int target)
+static inline int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int target)
 {
        return -1;
 }
@@ -7591,7 +7597,7 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
                has_idle_core = test_idle_cores(target);
 
                if (!has_idle_core && cpus_share_cache(prev, target)) {
-                       i = select_idle_smt(p, prev);
+                       i = select_idle_smt(p, sd, prev);
                        if ((unsigned int)i < nr_cpumask_bits)
                                return i;
                }
@@ -9237,19 +9243,17 @@ static inline bool cfs_rq_has_blocked(struct cfs_rq *cfs_rq)
 
 static inline bool others_have_blocked(struct rq *rq)
 {
-       if (READ_ONCE(rq->avg_rt.util_avg))
+       if (cpu_util_rt(rq))
                return true;
 
-       if (READ_ONCE(rq->avg_dl.util_avg))
+       if (cpu_util_dl(rq))
                return true;
 
        if (thermal_load_avg(rq))
                return true;
 
-#ifdef CONFIG_HAVE_SCHED_AVG_IRQ
-       if (READ_ONCE(rq->avg_irq.util_avg))
+       if (cpu_util_irq(rq))
                return true;
-#endif
 
        return false;
 }
@@ -9506,8 +9510,8 @@ static unsigned long scale_rt_capacity(int cpu)
         * avg_thermal.load_avg tracks thermal pressure and the weighted
         * average uses the actual delta max capacity(load).
         */
-       used = READ_ONCE(rq->avg_rt.util_avg);
-       used += READ_ONCE(rq->avg_dl.util_avg);
+       used = cpu_util_rt(rq);
+       used += cpu_util_dl(rq);
        used += thermal_load_avg(rq);
 
        if (unlikely(used >= max))
@@ -9740,51 +9744,49 @@ group_type group_classify(unsigned int imbalance_pct,
  */
 static bool sched_use_asym_prio(struct sched_domain *sd, int cpu)
 {
+       if (!(sd->flags & SD_ASYM_PACKING))
+               return false;
+
        if (!sched_smt_active())
                return true;
 
        return sd->flags & SD_SHARE_CPUCAPACITY || is_core_idle(cpu);
 }
 
+static inline bool sched_asym(struct sched_domain *sd, int dst_cpu, int src_cpu)
+{
+       /*
+        * First check if @dst_cpu can do asym_packing load balance. Only do it
+        * if it has higher priority than @src_cpu.
+        */
+       return sched_use_asym_prio(sd, dst_cpu) &&
+               sched_asym_prefer(dst_cpu, src_cpu);
+}
+
 /**
- * sched_asym - Check if the destination CPU can do asym_packing load balance
+ * sched_group_asym - Check if the destination CPU can do asym_packing balance
  * @env:       The load balancing environment
- * @sds:       Load-balancing data with statistics of the local group
  * @sgs:       Load-balancing statistics of the candidate busiest group
  * @group:     The candidate busiest group
  *
  * @env::dst_cpu can do asym_packing if it has higher priority than the
  * preferred CPU of @group.
  *
- * SMT is a special case. If we are balancing load between cores, @env::dst_cpu
- * can do asym_packing balance only if all its SMT siblings are idle. Also, it
- * can only do it if @group is an SMT group and has exactly on busy CPU. Larger
- * imbalances in the number of CPUS are dealt with in find_busiest_group().
- *
- * If we are balancing load within an SMT core, or at PKG domain level, always
- * proceed.
- *
  * Return: true if @env::dst_cpu can do with asym_packing load balance. False
  * otherwise.
  */
 static inline bool
-sched_asym(struct lb_env *env, struct sd_lb_stats *sds,  struct sg_lb_stats *sgs,
-          struct sched_group *group)
+sched_group_asym(struct lb_env *env, struct sg_lb_stats *sgs, struct sched_group *group)
 {
-       /* Ensure that the whole local core is idle, if applicable. */
-       if (!sched_use_asym_prio(env->sd, env->dst_cpu))
-               return false;
-
        /*
-        * CPU priorities does not make sense for SMT cores with more than one
+        * CPU priorities do not make sense for SMT cores with more than one
         * busy sibling.
         */
-       if (group->flags & SD_SHARE_CPUCAPACITY) {
-               if (sgs->group_weight - sgs->idle_cpus != 1)
-                       return false;
-       }
+       if ((group->flags & SD_SHARE_CPUCAPACITY) &&
+           (sgs->group_weight - sgs->idle_cpus != 1))
+               return false;
 
-       return sched_asym_prefer(env->dst_cpu, group->asym_prefer_cpu);
+       return sched_asym(env->sd, env->dst_cpu, group->asym_prefer_cpu);
 }
 
 /* One group has more than one SMT CPU while the other group does not */
@@ -9938,11 +9940,9 @@ static inline void update_sg_lb_stats(struct lb_env *env,
        sgs->group_weight = group->group_weight;
 
        /* Check if dst CPU is idle and preferred to this group */
-       if (!local_group && env->sd->flags & SD_ASYM_PACKING &&
-           env->idle != CPU_NOT_IDLE && sgs->sum_h_nr_running &&
-           sched_asym(env, sds, sgs, group)) {
+       if (!local_group && env->idle != CPU_NOT_IDLE && sgs->sum_h_nr_running &&
+           sched_group_asym(env, sgs, group))
                sgs->group_asym_packing = 1;
-       }
 
        /* Check for loaded SMT group to be balanced to dst CPU */
        if (!local_group && smt_balance(env, sgs, group))
@@ -10006,9 +10006,7 @@ static bool update_sd_pick_busiest(struct lb_env *env,
        switch (sgs->group_type) {
        case group_overloaded:
                /* Select the overloaded group with highest avg_load. */
-               if (sgs->avg_load <= busiest->avg_load)
-                       return false;
-               break;
+               return sgs->avg_load > busiest->avg_load;
 
        case group_imbalanced:
                /*
@@ -10019,18 +10017,14 @@ static bool update_sd_pick_busiest(struct lb_env *env,
 
        case group_asym_packing:
                /* Prefer to move from lowest priority CPU's work */
-               if (sched_asym_prefer(sg->asym_prefer_cpu, sds->busiest->asym_prefer_cpu))
-                       return false;
-               break;
+               return sched_asym_prefer(sds->busiest->asym_prefer_cpu, sg->asym_prefer_cpu);
 
        case group_misfit_task:
                /*
                 * If we have more than one misfit sg go with the biggest
                 * misfit.
                 */
-               if (sgs->group_misfit_task_load < busiest->group_misfit_task_load)
-                       return false;
-               break;
+               return sgs->group_misfit_task_load > busiest->group_misfit_task_load;
 
        case group_smt_balance:
                /*
@@ -10182,10 +10176,8 @@ static int idle_cpu_without(int cpu, struct task_struct *p)
         * be computed and tested before calling idle_cpu_without().
         */
 
-#ifdef CONFIG_SMP
        if (rq->ttwu_pending)
                return 0;
-#endif
 
        return 1;
 }
@@ -10578,16 +10570,11 @@ static inline void update_sd_lb_stats(struct lb_env *env, struct sd_lb_stats *sd
 
                update_sg_lb_stats(env, sds, sg, sgs, &sg_status);
 
-               if (local_group)
-                       goto next_group;
-
-
-               if (update_sd_pick_busiest(env, sds, sg, sgs)) {
+               if (!local_group && update_sd_pick_busiest(env, sds, sg, sgs)) {
                        sds->busiest = sg;
                        sds->busiest_stat = *sgs;
                }
 
-next_group:
                /* Now, start updating sd_lb_stats */
                sds->total_load += sgs->group_load;
                sds->total_capacity += sgs->group_capacity;
@@ -10691,7 +10678,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
         */
        if (local->group_type == group_has_spare) {
                if ((busiest->group_type > group_fully_busy) &&
-                   !(env->sd->flags & SD_SHARE_PKG_RESOURCES)) {
+                   !(env->sd->flags & SD_SHARE_LLC)) {
                        /*
                         * If busiest is overloaded, try to fill spare
                         * capacity. This might end up creating spare capacity
@@ -11038,10 +11025,7 @@ static struct rq *find_busiest_queue(struct lb_env *env,
                 * If balancing between cores, let lower priority CPUs help
                 * SMT cores with more than one busy sibling.
                 */
-               if ((env->sd->flags & SD_ASYM_PACKING) &&
-                   sched_use_asym_prio(env->sd, i) &&
-                   sched_asym_prefer(i, env->dst_cpu) &&
-                   nr_running == 1)
+               if (sched_asym(env->sd, i, env->dst_cpu) && nr_running == 1)
                        continue;
 
                switch (env->migration_type) {
@@ -11137,8 +11121,7 @@ asym_active_balance(struct lb_env *env)
         * the lower priority @env::dst_cpu help it. Do not follow
         * CPU priority.
         */
-       return env->idle != CPU_NOT_IDLE && (env->sd->flags & SD_ASYM_PACKING) &&
-              sched_use_asym_prio(env->sd, env->dst_cpu) &&
+       return env->idle != CPU_NOT_IDLE && sched_use_asym_prio(env->sd, env->dst_cpu) &&
               (sched_asym_prefer(env->dst_cpu, env->src_cpu) ||
                !sched_use_asym_prio(env->sd, env->src_cpu));
 }
@@ -11910,8 +11893,7 @@ static void nohz_balancer_kick(struct rq *rq)
                 * preferred CPU must be idle.
                 */
                for_each_cpu_and(i, sched_domain_span(sd), nohz.idle_cpus_mask) {
-                       if (sched_use_asym_prio(sd, i) &&
-                           sched_asym_prefer(i, cpu)) {
+                       if (sched_asym(sd, i, cpu)) {
                                flags = NOHZ_STATS_KICK | NOHZ_BALANCE_KICK;
                                goto unlock;
                        }
index 31231925f1ece276c96269a2516d4d00ff011420..6135fbe83d68ced36706bcff01563688b393074f 100644 (file)
@@ -81,6 +81,25 @@ void __weak arch_cpu_idle(void)
        cpu_idle_force_poll = 1;
 }
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST_IDLE
+DEFINE_STATIC_KEY_FALSE(arch_needs_tick_broadcast);
+
+static inline void cond_tick_broadcast_enter(void)
+{
+       if (static_branch_unlikely(&arch_needs_tick_broadcast))
+               tick_broadcast_enter();
+}
+
+static inline void cond_tick_broadcast_exit(void)
+{
+       if (static_branch_unlikely(&arch_needs_tick_broadcast))
+               tick_broadcast_exit();
+}
+#else
+static inline void cond_tick_broadcast_enter(void) { }
+static inline void cond_tick_broadcast_exit(void) { }
+#endif
+
 /**
  * default_idle_call - Default CPU idle routine.
  *
@@ -90,6 +109,7 @@ void __cpuidle default_idle_call(void)
 {
        instrumentation_begin();
        if (!current_clr_polling_and_test()) {
+               cond_tick_broadcast_enter();
                trace_cpu_idle(1, smp_processor_id());
                stop_critical_timings();
 
@@ -99,6 +119,7 @@ void __cpuidle default_idle_call(void)
 
                start_critical_timings();
                trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
+               cond_tick_broadcast_exit();
        }
        local_irq_enable();
        instrumentation_end();
@@ -291,7 +312,6 @@ static void do_idle(void)
                local_irq_disable();
 
                if (cpu_is_offline(cpu)) {
-                       tick_nohz_idle_stop_tick();
                        cpuhp_report_idle_dead();
                        arch_cpu_idle_dead();
                }
index 2ad881d07752c15f60a4c14bee21051117d5aeb2..4e715b9b278e7fd7fbea70110f5a829635a4bc01 100644 (file)
        | MEMBARRIER_PRIVATE_EXPEDITED_RSEQ_BITMASK                     \
        | MEMBARRIER_CMD_GET_REGISTRATIONS)
 
+static DEFINE_MUTEX(membarrier_ipi_mutex);
+#define SERIALIZE_IPI() guard(mutex)(&membarrier_ipi_mutex)
+
 static void ipi_mb(void *info)
 {
        smp_mb();       /* IPIs should be serializing but paranoid. */
@@ -259,6 +262,7 @@ static int membarrier_global_expedited(void)
        if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
                return -ENOMEM;
 
+       SERIALIZE_IPI();
        cpus_read_lock();
        rcu_read_lock();
        for_each_online_cpu(cpu) {
@@ -347,6 +351,7 @@ static int membarrier_private_expedited(int flags, int cpu_id)
        if (cpu_id < 0 && !zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
                return -ENOMEM;
 
+       SERIALIZE_IPI();
        cpus_read_lock();
 
        if (cpu_id >= 0) {
@@ -460,6 +465,7 @@ static int sync_runqueues_membarrier_state(struct mm_struct *mm)
         * between threads which are users of @mm has its membarrier state
         * updated.
         */
+       SERIALIZE_IPI();
        cpus_read_lock();
        rcu_read_lock();
        for_each_online_cpu(cpu) {
index 001fe047bd5d80b841776719b5fa73f4401288a4..d2242679239ec5ad49152400350882d7d7b9819c 100644 (file)
@@ -3136,7 +3136,7 @@ static inline bool uclamp_rq_is_idle(struct rq *rq)
 #ifdef CONFIG_HAVE_SCHED_AVG_IRQ
 static inline unsigned long cpu_util_irq(struct rq *rq)
 {
-       return rq->avg_irq.util_avg;
+       return READ_ONCE(rq->avg_irq.util_avg);
 }
 
 static inline
index 10d1391e741612b5c5a80c6565ab1ad2e7e032a2..99ea5986038ce44997627fee1e01f6e36bef1b26 100644 (file)
@@ -657,13 +657,13 @@ static void destroy_sched_domains(struct sched_domain *sd)
 }
 
 /*
- * Keep a special pointer to the highest sched_domain that has
- * SD_SHARE_PKG_RESOURCE set (Last Level Cache Domain) for this
- * allows us to avoid some pointer chasing select_idle_sibling().
+ * Keep a special pointer to the highest sched_domain that has SD_SHARE_LLC set
+ * (Last Level Cache Domain) for this allows us to avoid some pointer chasing
+ * select_idle_sibling().
  *
- * Also keep a unique ID per domain (we use the first CPU number in
- * the cpumask of the domain), this allows us to quickly tell if
- * two CPUs are in the same cache domain, see cpus_share_cache().
+ * Also keep a unique ID per domain (we use the first CPU number in the cpumask
+ * of the domain), this allows us to quickly tell if two CPUs are in the same
+ * cache domain, see cpus_share_cache().
  */
 DEFINE_PER_CPU(struct sched_domain __rcu *, sd_llc);
 DEFINE_PER_CPU(int, sd_llc_size);
@@ -684,7 +684,7 @@ static void update_top_cache_domain(int cpu)
        int id = cpu;
        int size = 1;
 
-       sd = highest_flag_domain(cpu, SD_SHARE_PKG_RESOURCES);
+       sd = highest_flag_domain(cpu, SD_SHARE_LLC);
        if (sd) {
                id = cpumask_first(sched_domain_span(sd));
                size = cpumask_weight(sched_domain_span(sd));
@@ -1551,11 +1551,12 @@ static struct cpumask           ***sched_domains_numa_masks;
  *
  * These flags are purely descriptive of the topology and do not prescribe
  * behaviour. Behaviour is artificial and mapped in the below sd_init()
- * function:
+ * function. For details, see include/linux/sched/sd_flags.h.
  *
- *   SD_SHARE_CPUCAPACITY   - describes SMT topologies
- *   SD_SHARE_PKG_RESOURCES - describes shared caches
- *   SD_NUMA                - describes NUMA topologies
+ *   SD_SHARE_CPUCAPACITY
+ *   SD_SHARE_LLC
+ *   SD_CLUSTER
+ *   SD_NUMA
  *
  * Odd one out, which beside describing the topology has a quirk also
  * prescribes the desired behaviour that goes along with it:
@@ -1565,7 +1566,7 @@ static struct cpumask             ***sched_domains_numa_masks;
 #define TOPOLOGY_SD_FLAGS              \
        (SD_SHARE_CPUCAPACITY   |       \
         SD_CLUSTER             |       \
-        SD_SHARE_PKG_RESOURCES |       \
+        SD_SHARE_LLC           |       \
         SD_NUMA                |       \
         SD_ASYM_PACKING)
 
@@ -1608,7 +1609,7 @@ sd_init(struct sched_domain_topology_level *tl,
                                        | 0*SD_BALANCE_WAKE
                                        | 1*SD_WAKE_AFFINE
                                        | 0*SD_SHARE_CPUCAPACITY
-                                       | 0*SD_SHARE_PKG_RESOURCES
+                                       | 0*SD_SHARE_LLC
                                        | 0*SD_SERIALIZE
                                        | 1*SD_PREFER_SIBLING
                                        | 0*SD_NUMA
@@ -1645,7 +1646,7 @@ sd_init(struct sched_domain_topology_level *tl,
        if (sd->flags & SD_SHARE_CPUCAPACITY) {
                sd->imbalance_pct = 110;
 
-       } else if (sd->flags & SD_SHARE_PKG_RESOURCES) {
+       } else if (sd->flags & SD_SHARE_LLC) {
                sd->imbalance_pct = 117;
                sd->cache_nice_tries = 1;
 
@@ -1670,7 +1671,7 @@ sd_init(struct sched_domain_topology_level *tl,
         * For all levels sharing cache; connect a sched_domain_shared
         * instance.
         */
-       if (sd->flags & SD_SHARE_PKG_RESOURCES) {
+       if (sd->flags & SD_SHARE_LLC) {
                sd->shared = *per_cpu_ptr(sdd->sds, sd_id);
                atomic_inc(&sd->shared->ref);
                atomic_set(&sd->shared->nr_busy_cpus, sd_weight);
@@ -2445,8 +2446,8 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att
                for (sd = *per_cpu_ptr(d.sd, i); sd; sd = sd->parent) {
                        struct sched_domain *child = sd->child;
 
-                       if (!(sd->flags & SD_SHARE_PKG_RESOURCES) && child &&
-                           (child->flags & SD_SHARE_PKG_RESOURCES)) {
+                       if (!(sd->flags & SD_SHARE_LLC) && child &&
+                           (child->flags & SD_SHARE_LLC)) {
                                struct sched_domain __rcu *top_p;
                                unsigned int nr_llcs;
 
index c9c57d053ce4f64d9a832f358b4e1ee837959b8b..bdca529f0f7b7aa23e377afca0bf9cc6d04a6473 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/cgroup.h>
 #include <linux/audit.h>
 #include <linux/sysctl.h>
+#include <uapi/linux/pidfd.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/signal.h>
@@ -1436,7 +1437,8 @@ void lockdep_assert_task_sighand_held(struct task_struct *task)
 #endif
 
 /*
- * send signal info to all the members of a group
+ * send signal info to all the members of a thread group or to the
+ * individual thread if type == PIDTYPE_PID.
  */
 int group_send_sig_info(int sig, struct kernel_siginfo *info,
                        struct task_struct *p, enum pid_type type)
@@ -1478,7 +1480,8 @@ int __kill_pgrp_info(int sig, struct kernel_siginfo *info, struct pid *pgrp)
        return ret;
 }
 
-int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid)
+static int kill_pid_info_type(int sig, struct kernel_siginfo *info,
+                               struct pid *pid, enum pid_type type)
 {
        int error = -ESRCH;
        struct task_struct *p;
@@ -1487,11 +1490,10 @@ int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid)
                rcu_read_lock();
                p = pid_task(pid, PIDTYPE_PID);
                if (p)
-                       error = group_send_sig_info(sig, info, p, PIDTYPE_TGID);
+                       error = group_send_sig_info(sig, info, p, type);
                rcu_read_unlock();
                if (likely(!p || error != -ESRCH))
                        return error;
-
                /*
                 * The task was unhashed in between, try again.  If it
                 * is dead, pid_task() will return NULL, if we race with
@@ -1500,6 +1502,11 @@ int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid)
        }
 }
 
+int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid)
+{
+       return kill_pid_info_type(sig, info, pid, PIDTYPE_TGID);
+}
+
 static int kill_proc_info(int sig, struct kernel_siginfo *info, pid_t pid)
 {
        int error;
@@ -1898,16 +1905,19 @@ int send_sig_fault_trapno(int sig, int code, void __user *addr, int trapno,
        return send_sig_info(info.si_signo, &info, t);
 }
 
-int kill_pgrp(struct pid *pid, int sig, int priv)
+static int kill_pgrp_info(int sig, struct kernel_siginfo *info, struct pid *pgrp)
 {
        int ret;
-
        read_lock(&tasklist_lock);
-       ret = __kill_pgrp_info(sig, __si_special(priv), pid);
+       ret = __kill_pgrp_info(sig, info, pgrp);
        read_unlock(&tasklist_lock);
-
        return ret;
 }
+
+int kill_pgrp(struct pid *pid, int sig, int priv)
+{
+       return kill_pgrp_info(sig, __si_special(priv), pid);
+}
 EXPORT_SYMBOL(kill_pgrp);
 
 int kill_pid(struct pid *pid, int sig, int priv)
@@ -2019,13 +2029,14 @@ ret:
        return ret;
 }
 
-static void do_notify_pidfd(struct task_struct *task)
+void do_notify_pidfd(struct task_struct *task)
 {
-       struct pid *pid;
+       struct pid *pid = task_pid(task);
 
        WARN_ON(task->exit_state == 0);
-       pid = task_pid(task);
-       wake_up_all(&pid->wait_pidfd);
+
+       __wake_up(&pid->wait_pidfd, TASK_NORMAL, 0,
+                       poll_to_key(EPOLLIN | EPOLLRDNORM));
 }
 
 /*
@@ -2050,9 +2061,12 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
 
        WARN_ON_ONCE(!tsk->ptrace &&
               (tsk->group_leader != tsk || !thread_group_empty(tsk)));
-
-       /* Wake up all pidfd waiters */
-       do_notify_pidfd(tsk);
+       /*
+        * tsk is a group leader and has no threads, wake up the
+        * non-PIDFD_THREAD waiters.
+        */
+       if (thread_group_empty(tsk))
+               do_notify_pidfd(tsk);
 
        if (sig != SIGCHLD) {
                /*
@@ -3789,12 +3803,13 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait_time32, compat_sigset_t __user *, uthese,
 #endif
 #endif
 
-static inline void prepare_kill_siginfo(int sig, struct kernel_siginfo *info)
+static void prepare_kill_siginfo(int sig, struct kernel_siginfo *info,
+                                enum pid_type type)
 {
        clear_siginfo(info);
        info->si_signo = sig;
        info->si_errno = 0;
-       info->si_code = SI_USER;
+       info->si_code = (type == PIDTYPE_PID) ? SI_TKILL : SI_USER;
        info->si_pid = task_tgid_vnr(current);
        info->si_uid = from_kuid_munged(current_user_ns(), current_uid());
 }
@@ -3808,7 +3823,7 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
 {
        struct kernel_siginfo info;
 
-       prepare_kill_siginfo(sig, &info);
+       prepare_kill_siginfo(sig, &info, PIDTYPE_TGID);
 
        return kill_something_info(sig, &info, pid);
 }
@@ -3861,6 +3876,10 @@ static struct pid *pidfd_to_pid(const struct file *file)
        return tgid_pidfd_to_pid(file);
 }
 
+#define PIDFD_SEND_SIGNAL_FLAGS                            \
+       (PIDFD_SIGNAL_THREAD | PIDFD_SIGNAL_THREAD_GROUP | \
+        PIDFD_SIGNAL_PROCESS_GROUP)
+
 /**
  * sys_pidfd_send_signal - Signal a process through a pidfd
  * @pidfd:  file descriptor of the process
@@ -3868,14 +3887,10 @@ static struct pid *pidfd_to_pid(const struct file *file)
  * @info:   signal info
  * @flags:  future flags
  *
- * The syscall currently only signals via PIDTYPE_PID which covers
- * kill(<positive-pid>, <signal>. It does not signal threads or process
- * groups.
- * In order to extend the syscall to threads and process groups the @flags
- * argument should be used. In essence, the @flags argument will determine
- * what is signaled and not the file descriptor itself. Put in other words,
- * grouping is a property of the flags argument not a property of the file
- * descriptor.
+ * Send the signal to the thread group or to the individual thread depending
+ * on PIDFD_THREAD.
+ * In the future extension to @flags may be used to override the default scope
+ * of @pidfd.
  *
  * Return: 0 on success, negative errno on failure
  */
@@ -3886,9 +3901,14 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
        struct fd f;
        struct pid *pid;
        kernel_siginfo_t kinfo;
+       enum pid_type type;
 
        /* Enforce flags be set to 0 until we add an extension. */
-       if (flags)
+       if (flags & ~PIDFD_SEND_SIGNAL_FLAGS)
+               return -EINVAL;
+
+       /* Ensure that only a single signal scope determining flag is set. */
+       if (hweight32(flags & PIDFD_SEND_SIGNAL_FLAGS) > 1)
                return -EINVAL;
 
        f = fdget(pidfd);
@@ -3906,6 +3926,25 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
        if (!access_pidfd_pidns(pid))
                goto err;
 
+       switch (flags) {
+       case 0:
+               /* Infer scope from the type of pidfd. */
+               if (f.file->f_flags & PIDFD_THREAD)
+                       type = PIDTYPE_PID;
+               else
+                       type = PIDTYPE_TGID;
+               break;
+       case PIDFD_SIGNAL_THREAD:
+               type = PIDTYPE_PID;
+               break;
+       case PIDFD_SIGNAL_THREAD_GROUP:
+               type = PIDTYPE_TGID;
+               break;
+       case PIDFD_SIGNAL_PROCESS_GROUP:
+               type = PIDTYPE_PGID;
+               break;
+       }
+
        if (info) {
                ret = copy_siginfo_from_user_any(&kinfo, info);
                if (unlikely(ret))
@@ -3917,15 +3956,17 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
 
                /* Only allow sending arbitrary signals to yourself. */
                ret = -EPERM;
-               if ((task_pid(current) != pid) &&
+               if ((task_pid(current) != pid || type > PIDTYPE_TGID) &&
                    (kinfo.si_code >= 0 || kinfo.si_code == SI_TKILL))
                        goto err;
        } else {
-               prepare_kill_siginfo(sig, &kinfo);
+               prepare_kill_siginfo(sig, &kinfo, type);
        }
 
-       ret = kill_pid_info(sig, &kinfo, pid);
-
+       if (type == PIDTYPE_PGID)
+               ret = kill_pgrp_info(sig, &kinfo, pid);
+       else
+               ret = kill_pid_info_type(sig, &kinfo, pid, type);
 err:
        fdput(f);
        return ret;
@@ -3965,12 +4006,7 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig)
 {
        struct kernel_siginfo info;
 
-       clear_siginfo(&info);
-       info.si_signo = sig;
-       info.si_errno = 0;
-       info.si_code = SI_TKILL;
-       info.si_pid = task_tgid_vnr(current);
-       info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
+       prepare_kill_siginfo(sig, &info, PIDTYPE_PID);
 
        return do_send_specific(tgid, pid, sig, &info);
 }
index 210cf5f8d92c2c2aa99d0e14db127c26d70f7e96..b315b21fb28cd281fc38d1a8a00ed9f9527e2f53 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/tick.h>
 #include <linux/irq.h>
 #include <linux/wait_bit.h>
+#include <linux/workqueue.h>
 
 #include <asm/softirq_stack.h>
 
@@ -802,11 +803,13 @@ static void tasklet_action_common(struct softirq_action *a,
 
 static __latent_entropy void tasklet_action(struct softirq_action *a)
 {
+       workqueue_softirq_action(false);
        tasklet_action_common(a, this_cpu_ptr(&tasklet_vec), TASKLET_SOFTIRQ);
 }
 
 static __latent_entropy void tasklet_hi_action(struct softirq_action *a)
 {
+       workqueue_softirq_action(true);
        tasklet_action_common(a, this_cpu_ptr(&tasklet_hi_vec), HI_SOFTIRQ);
 }
 
@@ -929,6 +932,8 @@ static void run_ksoftirqd(unsigned int cpu)
 #ifdef CONFIG_HOTPLUG_CPU
 static int takeover_tasklets(unsigned int cpu)
 {
+       workqueue_softirq_dead(cpu);
+
        /* CPU is dead, so no lock needed. */
        local_irq_disable();
 
index bae8f11070befeefb1fe5c5ed1957c806f9195ff..fc3b1a06c9816e9802e9a8a68084707f38d91ecc 100644 (file)
@@ -39,6 +39,11 @@ config GENERIC_CLOCKEVENTS_BROADCAST
        bool
        depends on GENERIC_CLOCKEVENTS
 
+# Handle broadcast in default_idle_call()
+config GENERIC_CLOCKEVENTS_BROADCAST_IDLE
+       bool
+       depends on GENERIC_CLOCKEVENTS_BROADCAST
+
 # Automatically adjust the min. reprogramming time for
 # clock event device
 config GENERIC_CLOCKEVENTS_MIN_ADJUST
index 7e875e63ff3b65034637b9ffe1450cc831d49661..4af2a264a16073046b5dadba4ce4f8816dfa0a5b 100644 (file)
@@ -17,6 +17,9 @@ endif
 obj-$(CONFIG_GENERIC_SCHED_CLOCK)              += sched_clock.o
 obj-$(CONFIG_TICK_ONESHOT)                     += tick-oneshot.o tick-sched.o
 obj-$(CONFIG_LEGACY_TIMER_TICK)                        += tick-legacy.o
+ifeq ($(CONFIG_SMP),y)
+ obj-$(CONFIG_NO_HZ_COMMON)                    += timer_migration.o
+endif
 obj-$(CONFIG_HAVE_GENERIC_VDSO)                        += vsyscall.o
 obj-$(CONFIG_DEBUG_FS)                         += timekeeping_debug.o
 obj-$(CONFIG_TEST_UDELAY)                      += test_udelay.o
index 960143b183cdb38c088936664937c3d98d9e92a5..a7ca458cdd9cd6ebf138ca466b3f197d9e4e619f 100644 (file)
@@ -659,7 +659,7 @@ void tick_cleanup_dead_cpu(int cpu)
 #endif
 
 #ifdef CONFIG_SYSFS
-static struct bus_type clockevents_subsys = {
+static const struct bus_type clockevents_subsys = {
        .name           = "clockevents",
        .dev_name       = "clockevent",
 };
index df922f49d171baa2128005988faf80965b45ba25..d06185e054ea2173f273c826098cb04dde7dd05f 100644 (file)
@@ -104,8 +104,8 @@ static void wdtest_ktime_clocksource_reset(void)
 static int wdtest_func(void *arg)
 {
        unsigned long j1, j2;
+       int i, max_retries;
        char *s;
-       int i;
 
        schedule_timeout_uninterruptible(holdoff * HZ);
 
@@ -139,18 +139,19 @@ static int wdtest_func(void *arg)
        WARN_ON_ONCE(time_before(j2, j1 + NSEC_PER_USEC));
 
        /* Verify tsc-like stability with various numbers of errors injected. */
-       for (i = 0; i <= max_cswd_read_retries + 1; i++) {
-               if (i <= 1 && i < max_cswd_read_retries)
+       max_retries = clocksource_get_max_watchdog_retry();
+       for (i = 0; i <= max_retries + 1; i++) {
+               if (i <= 1 && i < max_retries)
                        s = "";
-               else if (i <= max_cswd_read_retries)
+               else if (i <= max_retries)
                        s = ", expect message";
                else
                        s = ", expect clock skew";
-               pr_info("--- Watchdog with %dx error injection, %lu retries%s.\n", i, max_cswd_read_retries, s);
+               pr_info("--- Watchdog with %dx error injection, %d retries%s.\n", i, max_retries, s);
                WRITE_ONCE(wdtest_ktime_read_ndelays, i);
                schedule_timeout_uninterruptible(2 * HZ);
                WARN_ON_ONCE(READ_ONCE(wdtest_ktime_read_ndelays));
-               WARN_ON_ONCE((i <= max_cswd_read_retries) !=
+               WARN_ON_ONCE((i <= max_retries) !=
                             !(clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE));
                wdtest_ktime_clocksource_reset();
        }
index 3052b1f1168e29c4432ba3b068488af11029018d..e5b260aa0e02c2de1293f8433280dd7122e14159 100644 (file)
@@ -210,9 +210,6 @@ void clocksource_mark_unstable(struct clocksource *cs)
        spin_unlock_irqrestore(&watchdog_lock, flags);
 }
 
-ulong max_cswd_read_retries = 2;
-module_param(max_cswd_read_retries, ulong, 0644);
-EXPORT_SYMBOL_GPL(max_cswd_read_retries);
 static int verify_n_cpus = 8;
 module_param(verify_n_cpus, int, 0644);
 
@@ -224,11 +221,12 @@ enum wd_read_status {
 
 static enum wd_read_status cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow)
 {
-       unsigned int nretries;
+       unsigned int nretries, max_retries;
        u64 wd_end, wd_end2, wd_delta;
        int64_t wd_delay, wd_seq_delay;
 
-       for (nretries = 0; nretries <= max_cswd_read_retries; nretries++) {
+       max_retries = clocksource_get_max_watchdog_retry();
+       for (nretries = 0; nretries <= max_retries; nretries++) {
                local_irq_disable();
                *wdnow = watchdog->read(watchdog);
                *csnow = cs->read(cs);
@@ -240,7 +238,7 @@ static enum wd_read_status cs_watchdog_read(struct clocksource *cs, u64 *csnow,
                wd_delay = clocksource_cyc2ns(wd_delta, watchdog->mult,
                                              watchdog->shift);
                if (wd_delay <= WATCHDOG_MAX_SKEW) {
-                       if (nretries > 1 || nretries >= max_cswd_read_retries) {
+                       if (nretries > 1 || nretries >= max_retries) {
                                pr_warn("timekeeping watchdog on CPU%d: %s retried %d times before success\n",
                                        smp_processor_id(), watchdog->name, nretries);
                        }
@@ -1468,7 +1466,7 @@ static struct attribute *clocksource_attrs[] = {
 };
 ATTRIBUTE_GROUPS(clocksource);
 
-static struct bus_type clocksource_subsys = {
+static const struct bus_type clocksource_subsys = {
        .name = "clocksource",
        .dev_name = "clocksource",
 };
index edb0f821dceaa1720ac94fc53f4002a1e5f7bdd3..70625dff62ce10150a49110715e5edf49ff19147 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/sched/deadline.h>
 #include <linux/sched/nohz.h>
 #include <linux/sched/debug.h>
+#include <linux/sched/isolation.h>
 #include <linux/timer.h>
 #include <linux/freezer.h>
 #include <linux/compat.h>
@@ -746,7 +747,7 @@ static void hrtimer_switch_to_hres(void)
        base->hres_active = 1;
        hrtimer_resolution = HIGH_RES_NSEC;
 
-       tick_setup_sched_timer();
+       tick_setup_sched_timer(true);
        /* "Retrigger" the interrupt to get things going */
        retrigger_next_event(NULL);
 }
@@ -1021,21 +1022,23 @@ void unlock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags)
 }
 
 /**
- * hrtimer_forward - forward the timer expiry
+ * hrtimer_forward() - forward the timer expiry
  * @timer:     hrtimer to forward
  * @now:       forward past this time
  * @interval:  the interval to forward
  *
  * Forward the timer expiry so it will expire in the future.
- * Returns the number of overruns.
  *
- * Can be safely called from the callback function of @timer. If
- * called from other contexts @timer must neither be enqueued nor
- * running the callback and the caller needs to take care of
- * serialization.
+ * .. note::
+ *  This only updates the timer expiry value and does not requeue the timer.
  *
- * Note: This only updates the timer expiry value and does not requeue
- * the timer.
+ * There is also a variant of the function hrtimer_forward_now().
+ *
+ * Context: Can be safely called from the callback function of @timer. If called
+ *          from other contexts @timer must neither be enqueued nor running the
+ *          callback and the caller needs to take care of serialization.
+ *
+ * Return: The number of overruns are returned.
  */
 u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
 {
@@ -2223,10 +2226,8 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
 
 int hrtimers_cpu_dying(unsigned int dying_cpu)
 {
+       int i, ncpu = cpumask_any_and(cpu_active_mask, housekeeping_cpumask(HK_TYPE_TIMER));
        struct hrtimer_cpu_base *old_base, *new_base;
-       int i, ncpu = cpumask_first(cpu_active_mask);
-
-       tick_cancel_sched_timer(dying_cpu);
 
        old_base = this_cpu_ptr(&hrtimer_bases);
        new_base = &per_cpu(hrtimer_bases, ncpu);
index e9138cd7a0f52f3920f0c7093c98539b6ea281c0..fb0fdec8719a13ed5fd5eb66d13027e184dce5de 100644 (file)
@@ -111,15 +111,13 @@ void tick_handle_periodic(struct clock_event_device *dev)
 
        tick_periodic(cpu);
 
-#if defined(CONFIG_HIGH_RES_TIMERS) || defined(CONFIG_NO_HZ_COMMON)
        /*
         * The cpu might have transitioned to HIGHRES or NOHZ mode via
         * update_process_times() -> run_local_timers() ->
         * hrtimer_run_queues().
         */
-       if (dev->event_handler != tick_handle_periodic)
+       if (IS_ENABLED(CONFIG_TICK_ONESHOT) && dev->event_handler != tick_handle_periodic)
                return;
-#endif
 
        if (!clockevent_state_oneshot(dev))
                return;
@@ -398,16 +396,31 @@ int tick_broadcast_oneshot_control(enum tick_broadcast_state state)
 EXPORT_SYMBOL_GPL(tick_broadcast_oneshot_control);
 
 #ifdef CONFIG_HOTPLUG_CPU
+void tick_assert_timekeeping_handover(void)
+{
+       WARN_ON_ONCE(tick_do_timer_cpu == smp_processor_id());
+}
 /*
- * Transfer the do_timer job away from a dying cpu.
- *
- * Called with interrupts disabled. No locking required. If
- * tick_do_timer_cpu is owned by this cpu, nothing can change it.
+ * Stop the tick and transfer the timekeeping job away from a dying cpu.
  */
-void tick_handover_do_timer(void)
+int tick_cpu_dying(unsigned int dying_cpu)
 {
-       if (tick_do_timer_cpu == smp_processor_id())
+       /*
+        * If the current CPU is the timekeeper, it's the only one that
+        * can safely hand over its duty. Also all online CPUs are in
+        * stop machine, guaranteed not to be idle, therefore it's safe
+        * to pick any online successor.
+        */
+       if (tick_do_timer_cpu == dying_cpu)
                tick_do_timer_cpu = cpumask_first(cpu_online_mask);
+
+       /* Make sure the CPU won't try to retake the timekeeping duty */
+       tick_sched_timer_dying(dying_cpu);
+
+       /* Remove CPU from timer broadcasting */
+       tick_offline_cpu(dying_cpu);
+
+       return 0;
 }
 
 /*
index 481b7ab65e2cf514c7ed939ee2bbffe3a187f064..5f2105e637bdf0df16718f35afbc9cc0ca4edec5 100644 (file)
@@ -8,6 +8,11 @@
 #include "timekeeping.h"
 #include "tick-sched.h"
 
+struct timer_events {
+       u64     local;
+       u64     global;
+};
+
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
 
 # define TICK_DO_TIMER_NONE    -1
@@ -137,8 +142,10 @@ static inline bool tick_broadcast_oneshot_available(void) { return tick_oneshot_
 #endif /* !(BROADCAST && ONESHOT) */
 
 #if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_HOTPLUG_CPU)
+extern void tick_offline_cpu(unsigned int cpu);
 extern void tick_broadcast_offline(unsigned int cpu);
 #else
+static inline void tick_offline_cpu(unsigned int cpu) { }
 static inline void tick_broadcast_offline(unsigned int cpu) { }
 #endif
 
@@ -152,8 +159,16 @@ static inline void tick_nohz_init(void) { }
 #ifdef CONFIG_NO_HZ_COMMON
 extern unsigned long tick_nohz_active;
 extern void timers_update_nohz(void);
+extern u64 get_jiffies_update(unsigned long *basej);
 # ifdef CONFIG_SMP
 extern struct static_key_false timers_migration_enabled;
+extern void fetch_next_timer_interrupt_remote(unsigned long basej, u64 basem,
+                                             struct timer_events *tevt,
+                                             unsigned int cpu);
+extern void timer_lock_remote_bases(unsigned int cpu);
+extern void timer_unlock_remote_bases(unsigned int cpu);
+extern bool timer_base_is_idle(void);
+extern void timer_expire_remote(unsigned int cpu);
 # endif
 #else /* CONFIG_NO_HZ_COMMON */
 static inline void timers_update_nohz(void) { }
@@ -163,6 +178,7 @@ static inline void timers_update_nohz(void) { }
 DECLARE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases);
 
 extern u64 get_next_timer_interrupt(unsigned long basej, u64 basem);
+u64 timer_base_try_to_set_idle(unsigned long basej, u64 basem, bool *idle);
 void timer_clear_idle(void);
 
 #define CLOCK_SET_WALL                                                 \
index 01fb50c1b17e4f1b33285ae2ce2690f0747f8ee8..269e21590df5368bd6fc84d422f44162501a3f31 100644 (file)
@@ -43,7 +43,6 @@ struct tick_sched *tick_get_tick_sched(int cpu)
        return &per_cpu(tick_cpu_sched, cpu);
 }
 
-#if defined(CONFIG_NO_HZ_COMMON) || defined(CONFIG_HIGH_RES_TIMERS)
 /*
  * The time when the last jiffy update happened. Write access must hold
  * jiffies_lock and jiffies_seq. tick_nohz_next_event() needs to get a
@@ -181,13 +180,32 @@ static ktime_t tick_init_jiffy_update(void)
        return period;
 }
 
+static inline int tick_sched_flag_test(struct tick_sched *ts,
+                                      unsigned long flag)
+{
+       return !!(ts->flags & flag);
+}
+
+static inline void tick_sched_flag_set(struct tick_sched *ts,
+                                      unsigned long flag)
+{
+       lockdep_assert_irqs_disabled();
+       ts->flags |= flag;
+}
+
+static inline void tick_sched_flag_clear(struct tick_sched *ts,
+                                        unsigned long flag)
+{
+       lockdep_assert_irqs_disabled();
+       ts->flags &= ~flag;
+}
+
 #define MAX_STALLED_JIFFIES 5
 
 static void tick_sched_do_timer(struct tick_sched *ts, ktime_t now)
 {
        int cpu = smp_processor_id();
 
-#ifdef CONFIG_NO_HZ_COMMON
        /*
         * Check if the do_timer duty was dropped. We don't care about
         * concurrency: This happens only when the CPU in charge went
@@ -198,13 +216,13 @@ static void tick_sched_do_timer(struct tick_sched *ts, ktime_t now)
         * If nohz_full is enabled, this should not happen because the
         * 'tick_do_timer_cpu' CPU never relinquishes.
         */
-       if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) {
+       if (IS_ENABLED(CONFIG_NO_HZ_COMMON) &&
+           unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) {
 #ifdef CONFIG_NO_HZ_FULL
                WARN_ON_ONCE(tick_nohz_full_running);
 #endif
                tick_do_timer_cpu = cpu;
        }
-#endif
 
        /* Check if jiffies need an update */
        if (tick_do_timer_cpu == cpu)
@@ -225,13 +243,12 @@ static void tick_sched_do_timer(struct tick_sched *ts, ktime_t now)
                }
        }
 
-       if (ts->inidle)
+       if (tick_sched_flag_test(ts, TS_FLAG_INIDLE))
                ts->got_idle_tick = 1;
 }
 
 static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs)
 {
-#ifdef CONFIG_NO_HZ_COMMON
        /*
         * When we are idle and the tick is stopped, we have to touch
         * the watchdog as we might not schedule for a really long
@@ -240,7 +257,8 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs)
         * idle" jiffy stamp so the idle accounting adjustment we do
         * when we go busy again does not account too many ticks.
         */
-       if (ts->tick_stopped) {
+       if (IS_ENABLED(CONFIG_NO_HZ_COMMON) &&
+           tick_sched_flag_test(ts, TS_FLAG_STOPPED)) {
                touch_softlockup_watchdog_sched();
                if (is_idle_task(current))
                        ts->idle_jiffies++;
@@ -251,11 +269,52 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs)
                 */
                ts->next_tick = 0;
        }
-#endif
+
        update_process_times(user_mode(regs));
        profile_tick(CPU_PROFILING);
 }
-#endif
+
+/*
+ * We rearm the timer until we get disabled by the idle code.
+ * Called with interrupts disabled.
+ */
+static enum hrtimer_restart tick_nohz_handler(struct hrtimer *timer)
+{
+       struct tick_sched *ts = container_of(timer, struct tick_sched, sched_timer);
+       struct pt_regs *regs = get_irq_regs();
+       ktime_t now = ktime_get();
+
+       tick_sched_do_timer(ts, now);
+
+       /*
+        * Do not call when we are not in IRQ context and have
+        * no valid 'regs' pointer
+        */
+       if (regs)
+               tick_sched_handle(ts, regs);
+       else
+               ts->next_tick = 0;
+
+       /*
+        * In dynticks mode, tick reprogram is deferred:
+        * - to the idle task if in dynticks-idle
+        * - to IRQ exit if in full-dynticks.
+        */
+       if (unlikely(tick_sched_flag_test(ts, TS_FLAG_STOPPED)))
+               return HRTIMER_NORESTART;
+
+       hrtimer_forward(timer, now, TICK_NSEC);
+
+       return HRTIMER_RESTART;
+}
+
+static void tick_sched_timer_cancel(struct tick_sched *ts)
+{
+       if (tick_sched_flag_test(ts, TS_FLAG_HIGHRES))
+               hrtimer_cancel(&ts->sched_timer);
+       else if (tick_sched_flag_test(ts, TS_FLAG_NOHZ))
+               tick_program_event(KTIME_MAX, 1);
+}
 
 #ifdef CONFIG_NO_HZ_FULL
 cpumask_var_t tick_nohz_full_mask;
@@ -529,7 +588,7 @@ void __tick_nohz_task_switch(void)
 
        ts = this_cpu_ptr(&tick_cpu_sched);
 
-       if (ts->tick_stopped) {
+       if (tick_sched_flag_test(ts, TS_FLAG_STOPPED)) {
                if (atomic_read(&current->tick_dep_mask) ||
                    atomic_read(&current->signal->tick_dep_mask))
                        tick_nohz_full_kick();
@@ -601,7 +660,7 @@ void __init tick_nohz_init(void)
        pr_info("NO_HZ: Full dynticks CPUs: %*pbl.\n",
                cpumask_pr_args(tick_nohz_full_mask));
 }
-#endif
+#endif /* #ifdef CONFIG_NO_HZ_FULL */
 
 /*
  * NOHZ - aka dynamic tick functionality
@@ -626,14 +685,14 @@ bool tick_nohz_tick_stopped(void)
 {
        struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
 
-       return ts->tick_stopped;
+       return tick_sched_flag_test(ts, TS_FLAG_STOPPED);
 }
 
 bool tick_nohz_tick_stopped_cpu(int cpu)
 {
        struct tick_sched *ts = per_cpu_ptr(&tick_cpu_sched, cpu);
 
-       return ts->tick_stopped;
+       return tick_sched_flag_test(ts, TS_FLAG_STOPPED);
 }
 
 /**
@@ -663,7 +722,7 @@ static void tick_nohz_stop_idle(struct tick_sched *ts, ktime_t now)
 {
        ktime_t delta;
 
-       if (WARN_ON_ONCE(!ts->idle_active))
+       if (WARN_ON_ONCE(!tick_sched_flag_test(ts, TS_FLAG_IDLE_ACTIVE)))
                return;
 
        delta = ktime_sub(now, ts->idle_entrytime);
@@ -675,7 +734,7 @@ static void tick_nohz_stop_idle(struct tick_sched *ts, ktime_t now)
                ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
 
        ts->idle_entrytime = now;
-       ts->idle_active = 0;
+       tick_sched_flag_clear(ts, TS_FLAG_IDLE_ACTIVE);
        write_seqcount_end(&ts->idle_sleeptime_seq);
 
        sched_clock_idle_wakeup_event();
@@ -685,7 +744,7 @@ static void tick_nohz_start_idle(struct tick_sched *ts)
 {
        write_seqcount_begin(&ts->idle_sleeptime_seq);
        ts->idle_entrytime = ktime_get();
-       ts->idle_active = 1;
+       tick_sched_flag_set(ts, TS_FLAG_IDLE_ACTIVE);
        write_seqcount_end(&ts->idle_sleeptime_seq);
 
        sched_clock_idle_sleep_event();
@@ -707,7 +766,7 @@ static u64 get_cpu_sleep_time_us(struct tick_sched *ts, ktime_t *sleeptime,
        do {
                seq = read_seqcount_begin(&ts->idle_sleeptime_seq);
 
-               if (ts->idle_active && compute_delta) {
+               if (tick_sched_flag_test(ts, TS_FLAG_IDLE_ACTIVE) && compute_delta) {
                        ktime_t delta = ktime_sub(now, ts->idle_entrytime);
 
                        idle = ktime_add(*sleeptime, delta);
@@ -780,7 +839,7 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
        /* Forward the time to expire in the future */
        hrtimer_forward(&ts->sched_timer, now, TICK_NSEC);
 
-       if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
+       if (tick_sched_flag_test(ts, TS_FLAG_HIGHRES)) {
                hrtimer_start_expires(&ts->sched_timer,
                                      HRTIMER_MODE_ABS_PINNED_HARD);
        } else {
@@ -799,18 +858,40 @@ static inline bool local_timer_softirq_pending(void)
        return local_softirq_pending() & BIT(TIMER_SOFTIRQ);
 }
 
-static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
+/*
+ * Read jiffies and the time when jiffies were updated last
+ */
+u64 get_jiffies_update(unsigned long *basej)
 {
-       u64 basemono, next_tick, delta, expires;
        unsigned long basejiff;
        unsigned int seq;
+       u64 basemono;
 
-       /* Read jiffies and the time when jiffies were updated last */
        do {
                seq = read_seqcount_begin(&jiffies_seq);
                basemono = last_jiffies_update;
                basejiff = jiffies;
        } while (read_seqcount_retry(&jiffies_seq, seq));
+       *basej = basejiff;
+       return basemono;
+}
+
+/**
+ * tick_nohz_next_event() - return the clock monotonic based next event
+ * @ts:                pointer to tick_sched struct
+ * @cpu:       CPU number
+ *
+ * Return:
+ * *%0         - When the next event is a maximum of TICK_NSEC in the future
+ *               and the tick is not stopped yet
+ * *%next_event        - Next event based on clock monotonic
+ */
+static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
+{
+       u64 basemono, next_tick, delta, expires;
+       unsigned long basejiff;
+
+       basemono = get_jiffies_update(&basejiff);
        ts->last_jiffies = basejiff;
        ts->timer_expires_base = basemono;
 
@@ -849,16 +930,11 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
         */
        delta = next_tick - basemono;
        if (delta <= (u64)TICK_NSEC) {
-               /*
-                * Tell the timer code that the base is not idle, i.e. undo
-                * the effect of get_next_timer_interrupt():
-                */
-               timer_clear_idle();
                /*
                 * We've not stopped the tick yet, and there's a timer in the
                 * next period, so no point in stopping it either, bail.
                 */
-               if (!ts->tick_stopped) {
+               if (!tick_sched_flag_test(ts, TS_FLAG_STOPPED)) {
                        ts->timer_expires = 0;
                        goto out;
                }
@@ -871,7 +947,8 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
         */
        delta = timekeeping_max_deferment();
        if (cpu != tick_do_timer_cpu &&
-           (tick_do_timer_cpu != TICK_DO_TIMER_NONE || !ts->do_timer_last))
+           (tick_do_timer_cpu != TICK_DO_TIMER_NONE ||
+            !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST)))
                delta = KTIME_MAX;
 
        /* Calculate the next expiry time */
@@ -889,12 +966,38 @@ out:
 static void tick_nohz_stop_tick(struct tick_sched *ts, int cpu)
 {
        struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
+       unsigned long basejiff = ts->last_jiffies;
        u64 basemono = ts->timer_expires_base;
-       u64 expires = ts->timer_expires;
+       bool timer_idle = tick_sched_flag_test(ts, TS_FLAG_STOPPED);
+       u64 expires;
 
        /* Make sure we won't be trying to stop it twice in a row. */
        ts->timer_expires_base = 0;
 
+       /*
+        * Now the tick should be stopped definitely - so the timer base needs
+        * to be marked idle as well to not miss a newly queued timer.
+        */
+       expires = timer_base_try_to_set_idle(basejiff, basemono, &timer_idle);
+       if (expires > ts->timer_expires) {
+               /*
+                * This path could only happen when the first timer was removed
+                * between calculating the possible sleep length and now (when
+                * high resolution mode is not active, timer could also be a
+                * hrtimer).
+                *
+                * We have to stick to the original calculated expiry value to
+                * not stop the tick for too long with a shallow C-state (which
+                * was programmed by cpuidle because of an early next expiration
+                * value).
+                */
+               expires = ts->timer_expires;
+       }
+
+       /* If the timer base is not idle, retain the not yet stopped tick. */
+       if (!timer_idle)
+               return;
+
        /*
         * If this CPU is the one which updates jiffies, then give up
         * the assignment and let it be taken by the CPU which runs
@@ -905,13 +1008,13 @@ static void tick_nohz_stop_tick(struct tick_sched *ts, int cpu)
         */
        if (cpu == tick_do_timer_cpu) {
                tick_do_timer_cpu = TICK_DO_TIMER_NONE;
-               ts->do_timer_last = 1;
+               tick_sched_flag_set(ts, TS_FLAG_DO_TIMER_LAST);
        } else if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) {
-               ts->do_timer_last = 0;
+               tick_sched_flag_clear(ts, TS_FLAG_DO_TIMER_LAST);
        }
 
        /* Skip reprogram of event if it's not changed */
-       if (ts->tick_stopped && (expires == ts->next_tick)) {
+       if (tick_sched_flag_test(ts, TS_FLAG_STOPPED) && (expires == ts->next_tick)) {
                /* Sanity check: make sure clockevent is actually programmed */
                if (expires == KTIME_MAX || ts->next_tick == hrtimer_get_expires(&ts->sched_timer))
                        return;
@@ -929,12 +1032,12 @@ static void tick_nohz_stop_tick(struct tick_sched *ts, int cpu)
         * call we save the current tick time, so we can restart the
         * scheduler tick in tick_nohz_restart_sched_tick().
         */
-       if (!ts->tick_stopped) {
+       if (!tick_sched_flag_test(ts, TS_FLAG_STOPPED)) {
                calc_load_nohz_start();
                quiet_vmstat();
 
                ts->last_tick = hrtimer_get_expires(&ts->sched_timer);
-               ts->tick_stopped = 1;
+               tick_sched_flag_set(ts, TS_FLAG_STOPPED);
                trace_tick_stop(1, TICK_DEP_MASK_NONE);
        }
 
@@ -945,14 +1048,11 @@ static void tick_nohz_stop_tick(struct tick_sched *ts, int cpu)
         * the tick timer.
         */
        if (unlikely(expires == KTIME_MAX)) {
-               if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
-                       hrtimer_cancel(&ts->sched_timer);
-               else
-                       tick_program_event(KTIME_MAX, 1);
+               tick_sched_timer_cancel(ts);
                return;
        }
 
-       if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
+       if (tick_sched_flag_test(ts, TS_FLAG_HIGHRES)) {
                hrtimer_start(&ts->sched_timer, expires,
                              HRTIMER_MODE_ABS_PINNED_HARD);
        } else {
@@ -967,7 +1067,7 @@ static void tick_nohz_retain_tick(struct tick_sched *ts)
 }
 
 #ifdef CONFIG_NO_HZ_FULL
-static void tick_nohz_stop_sched_tick(struct tick_sched *ts, int cpu)
+static void tick_nohz_full_stop_tick(struct tick_sched *ts, int cpu)
 {
        if (tick_nohz_next_event(ts, cpu))
                tick_nohz_stop_tick(ts, cpu);
@@ -991,7 +1091,7 @@ static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now)
        touch_softlockup_watchdog_sched();
 
        /* Cancel the scheduled timer and restore the tick: */
-       ts->tick_stopped  = 0;
+       tick_sched_flag_clear(ts, TS_FLAG_STOPPED);
        tick_nohz_restart(ts, now);
 }
 
@@ -1002,8 +1102,8 @@ static void __tick_nohz_full_update_tick(struct tick_sched *ts,
        int cpu = smp_processor_id();
 
        if (can_stop_full_tick(cpu, ts))
-               tick_nohz_stop_sched_tick(ts, cpu);
-       else if (ts->tick_stopped)
+               tick_nohz_full_stop_tick(ts, cpu);
+       else if (tick_sched_flag_test(ts, TS_FLAG_STOPPED))
                tick_nohz_restart_sched_tick(ts, now);
 #endif
 }
@@ -1013,7 +1113,7 @@ static void tick_nohz_full_update_tick(struct tick_sched *ts)
        if (!tick_nohz_full_cpu(smp_processor_id()))
                return;
 
-       if (!ts->tick_stopped && ts->nohz_mode == NOHZ_MODE_INACTIVE)
+       if (!tick_sched_flag_test(ts, TS_FLAG_NOHZ))
                return;
 
        __tick_nohz_full_update_tick(ts, ktime_get());
@@ -1060,25 +1160,9 @@ static bool report_idle_softirq(void)
 
 static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
 {
-       /*
-        * If this CPU is offline and it is the one which updates
-        * jiffies, then give up the assignment and let it be taken by
-        * the CPU which runs the tick timer next. If we don't drop
-        * this here, the jiffies might be stale and do_timer() never
-        * gets invoked.
-        */
-       if (unlikely(!cpu_online(cpu))) {
-               if (cpu == tick_do_timer_cpu)
-                       tick_do_timer_cpu = TICK_DO_TIMER_NONE;
-               /*
-                * Make sure the CPU doesn't get fooled by obsolete tick
-                * deadline if it comes back online later.
-                */
-               ts->next_tick = 0;
-               return false;
-       }
+       WARN_ON_ONCE(cpu_is_offline(cpu));
 
-       if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
+       if (unlikely(!tick_sched_flag_test(ts, TS_FLAG_NOHZ)))
                return false;
 
        if (need_resched())
@@ -1128,14 +1212,14 @@ void tick_nohz_idle_stop_tick(void)
        ts->idle_calls++;
 
        if (expires > 0LL) {
-               int was_stopped = ts->tick_stopped;
+               int was_stopped = tick_sched_flag_test(ts, TS_FLAG_STOPPED);
 
                tick_nohz_stop_tick(ts, cpu);
 
                ts->idle_sleeps++;
                ts->idle_expires = expires;
 
-               if (!was_stopped && ts->tick_stopped) {
+               if (!was_stopped && tick_sched_flag_test(ts, TS_FLAG_STOPPED)) {
                        ts->idle_jiffies = ts->last_jiffies;
                        nohz_balance_enter_idle(cpu);
                }
@@ -1147,11 +1231,6 @@ void tick_nohz_idle_stop_tick(void)
 void tick_nohz_idle_retain_tick(void)
 {
        tick_nohz_retain_tick(this_cpu_ptr(&tick_cpu_sched));
-       /*
-        * Undo the effect of get_next_timer_interrupt() called from
-        * tick_nohz_next_event().
-        */
-       timer_clear_idle();
 }
 
 /**
@@ -1171,7 +1250,7 @@ void tick_nohz_idle_enter(void)
 
        WARN_ON_ONCE(ts->timer_expires_base);
 
-       ts->inidle = 1;
+       tick_sched_flag_set(ts, TS_FLAG_INIDLE);
        tick_nohz_start_idle(ts);
 
        local_irq_enable();
@@ -1200,7 +1279,7 @@ void tick_nohz_irq_exit(void)
 {
        struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
 
-       if (ts->inidle)
+       if (tick_sched_flag_test(ts, TS_FLAG_INIDLE))
                tick_nohz_start_idle(ts);
        else
                tick_nohz_full_update_tick(ts);
@@ -1254,7 +1333,7 @@ ktime_t tick_nohz_get_sleep_length(ktime_t *delta_next)
        ktime_t now = ts->idle_entrytime;
        ktime_t next_event;
 
-       WARN_ON_ONCE(!ts->inidle);
+       WARN_ON_ONCE(!tick_sched_flag_test(ts, TS_FLAG_INIDLE));
 
        *delta_next = ktime_sub(dev->next_event, now);
 
@@ -1326,7 +1405,7 @@ void tick_nohz_idle_restart_tick(void)
 {
        struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
 
-       if (ts->tick_stopped) {
+       if (tick_sched_flag_test(ts, TS_FLAG_STOPPED)) {
                ktime_t now = ktime_get();
                tick_nohz_restart_sched_tick(ts, now);
                tick_nohz_account_idle_time(ts, now);
@@ -1367,12 +1446,12 @@ void tick_nohz_idle_exit(void)
 
        local_irq_disable();
 
-       WARN_ON_ONCE(!ts->inidle);
+       WARN_ON_ONCE(!tick_sched_flag_test(ts, TS_FLAG_INIDLE));
        WARN_ON_ONCE(ts->timer_expires_base);
 
-       ts->inidle = 0;
-       idle_active = ts->idle_active;
-       tick_stopped = ts->tick_stopped;
+       tick_sched_flag_clear(ts, TS_FLAG_INIDLE);
+       idle_active = tick_sched_flag_test(ts, TS_FLAG_IDLE_ACTIVE);
+       tick_stopped = tick_sched_flag_test(ts, TS_FLAG_STOPPED);
 
        if (idle_active || tick_stopped)
                now = ktime_get();
@@ -1391,38 +1470,22 @@ void tick_nohz_idle_exit(void)
  * at the clockevent level. hrtimer can't be used instead, because its
  * infrastructure actually relies on the tick itself as a backend in
  * low-resolution mode (see hrtimer_run_queues()).
- *
- * This low-resolution handler still makes use of some hrtimer APIs meanwhile
- * for convenience with expiration calculation and forwarding.
  */
 static void tick_nohz_lowres_handler(struct clock_event_device *dev)
 {
        struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
-       struct pt_regs *regs = get_irq_regs();
-       ktime_t now = ktime_get();
 
        dev->next_event = KTIME_MAX;
 
-       tick_sched_do_timer(ts, now);
-       tick_sched_handle(ts, regs);
-
-       /*
-        * In dynticks mode, tick reprogram is deferred:
-        * - to the idle task if in dynticks-idle
-        * - to IRQ exit if in full-dynticks.
-        */
-       if (likely(!ts->tick_stopped)) {
-               hrtimer_forward(&ts->sched_timer, now, TICK_NSEC);
+       if (likely(tick_nohz_handler(&ts->sched_timer) == HRTIMER_RESTART))
                tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1);
-       }
-
 }
 
-static inline void tick_nohz_activate(struct tick_sched *ts, int mode)
+static inline void tick_nohz_activate(struct tick_sched *ts)
 {
        if (!tick_nohz_enabled)
                return;
-       ts->nohz_mode = mode;
+       tick_sched_flag_set(ts, TS_FLAG_NOHZ);
        /* One update is enough */
        if (!test_and_set_bit(0, &tick_nohz_active))
                timers_update_nohz();
@@ -1433,9 +1496,6 @@ static inline void tick_nohz_activate(struct tick_sched *ts, int mode)
  */
 static void tick_nohz_switch_to_nohz(void)
 {
-       struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
-       ktime_t next;
-
        if (!tick_nohz_enabled)
                return;
 
@@ -1444,16 +1504,9 @@ static void tick_nohz_switch_to_nohz(void)
 
        /*
         * Recycle the hrtimer in 'ts', so we can share the
-        * hrtimer_forward_now() function with the highres code.
+        * highres code.
         */
-       hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD);
-       /* Get the next period */
-       next = tick_init_jiffy_update();
-
-       hrtimer_set_expires(&ts->sched_timer, next);
-       hrtimer_forward_now(&ts->sched_timer, TICK_NSEC);
-       tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1);
-       tick_nohz_activate(ts, NOHZ_MODE_LOWRES);
+       tick_setup_sched_timer(false);
 }
 
 static inline void tick_nohz_irq_enter(void)
@@ -1461,10 +1514,10 @@ static inline void tick_nohz_irq_enter(void)
        struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
        ktime_t now;
 
-       if (!ts->idle_active && !ts->tick_stopped)
+       if (!tick_sched_flag_test(ts, TS_FLAG_STOPPED | TS_FLAG_IDLE_ACTIVE))
                return;
        now = ktime_get();
-       if (ts->idle_active)
+       if (tick_sched_flag_test(ts, TS_FLAG_IDLE_ACTIVE))
                tick_nohz_stop_idle(ts, now);
        /*
         * If all CPUs are idle we may need to update a stale jiffies value.
@@ -1473,7 +1526,7 @@ static inline void tick_nohz_irq_enter(void)
         * rare case (typically stop machine). So we must make sure we have a
         * last resort.
         */
-       if (ts->tick_stopped)
+       if (tick_sched_flag_test(ts, TS_FLAG_STOPPED))
                tick_nohz_update_jiffies(now);
 }
 
@@ -1481,7 +1534,7 @@ static inline void tick_nohz_irq_enter(void)
 
 static inline void tick_nohz_switch_to_nohz(void) { }
 static inline void tick_nohz_irq_enter(void) { }
-static inline void tick_nohz_activate(struct tick_sched *ts, int mode) { }
+static inline void tick_nohz_activate(struct tick_sched *ts) { }
 
 #endif /* CONFIG_NO_HZ_COMMON */
 
@@ -1494,45 +1547,6 @@ void tick_irq_enter(void)
        tick_nohz_irq_enter();
 }
 
-/*
- * High resolution timer specific code
- */
-#ifdef CONFIG_HIGH_RES_TIMERS
-/*
- * We rearm the timer until we get disabled by the idle code.
- * Called with interrupts disabled.
- */
-static enum hrtimer_restart tick_nohz_highres_handler(struct hrtimer *timer)
-{
-       struct tick_sched *ts =
-               container_of(timer, struct tick_sched, sched_timer);
-       struct pt_regs *regs = get_irq_regs();
-       ktime_t now = ktime_get();
-
-       tick_sched_do_timer(ts, now);
-
-       /*
-        * Do not call when we are not in IRQ context and have
-        * no valid 'regs' pointer
-        */
-       if (regs)
-               tick_sched_handle(ts, regs);
-       else
-               ts->next_tick = 0;
-
-       /*
-        * In dynticks mode, tick reprogram is deferred:
-        * - to the idle task if in dynticks-idle
-        * - to IRQ exit if in full-dynticks.
-        */
-       if (unlikely(ts->tick_stopped))
-               return HRTIMER_NORESTART;
-
-       hrtimer_forward(timer, now, TICK_NSEC);
-
-       return HRTIMER_RESTART;
-}
-
 static int sched_skew_tick;
 
 static int __init skew_tick(char *str)
@@ -1545,15 +1559,19 @@ early_param("skew_tick", skew_tick);
 
 /**
  * tick_setup_sched_timer - setup the tick emulation timer
+ * @mode: tick_nohz_mode to setup for
  */
-void tick_setup_sched_timer(void)
+void tick_setup_sched_timer(bool hrtimer)
 {
        struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
-       ktime_t now = ktime_get();
 
        /* Emulate tick processing via per-CPU hrtimers: */
        hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD);
-       ts->sched_timer.function = tick_nohz_highres_handler;
+
+       if (IS_ENABLED(CONFIG_HIGH_RES_TIMERS) && hrtimer) {
+               tick_sched_flag_set(ts, TS_FLAG_HIGHRES);
+               ts->sched_timer.function = tick_nohz_handler;
+       }
 
        /* Get the next period (per-CPU) */
        hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update());
@@ -1566,23 +1584,35 @@ void tick_setup_sched_timer(void)
                hrtimer_add_expires_ns(&ts->sched_timer, offset);
        }
 
-       hrtimer_forward(&ts->sched_timer, now, TICK_NSEC);
-       hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED_HARD);
-       tick_nohz_activate(ts, NOHZ_MODE_HIGHRES);
+       hrtimer_forward_now(&ts->sched_timer, TICK_NSEC);
+       if (IS_ENABLED(CONFIG_HIGH_RES_TIMERS) && hrtimer)
+               hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED_HARD);
+       else
+               tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1);
+       tick_nohz_activate(ts);
 }
-#endif /* HIGH_RES_TIMERS */
 
-#if defined CONFIG_NO_HZ_COMMON || defined CONFIG_HIGH_RES_TIMERS
-void tick_cancel_sched_timer(int cpu)
+/*
+ * Shut down the tick and make sure the CPU won't try to retake the timekeeping
+ * duty before disabling IRQs in idle for the last time.
+ */
+void tick_sched_timer_dying(int cpu)
 {
+       struct tick_device *td = &per_cpu(tick_cpu_device, cpu);
        struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
+       struct clock_event_device *dev = td->evtdev;
        ktime_t idle_sleeptime, iowait_sleeptime;
        unsigned long idle_calls, idle_sleeps;
 
-# ifdef CONFIG_HIGH_RES_TIMERS
-       if (ts->sched_timer.base)
-               hrtimer_cancel(&ts->sched_timer);
-# endif
+       /* This must happen before hrtimers are migrated! */
+       tick_sched_timer_cancel(ts);
+
+       /*
+        * If the clockevents doesn't support CLOCK_EVT_STATE_ONESHOT_STOPPED,
+        * make sure not to call low-res tick handler.
+        */
+       if (tick_sched_flag_test(ts, TS_FLAG_NOHZ))
+               dev->event_handler = clockevents_handle_noop;
 
        idle_sleeptime = ts->idle_sleeptime;
        iowait_sleeptime = ts->iowait_sleeptime;
@@ -1594,7 +1624,6 @@ void tick_cancel_sched_timer(int cpu)
        ts->idle_calls = idle_calls;
        ts->idle_sleeps = idle_sleeps;
 }
-#endif
 
 /*
  * Async notification about clocksource changes
@@ -1632,7 +1661,7 @@ int tick_check_oneshot_change(int allow_nohz)
        if (!test_and_clear_bit(0, &ts->check_clocks))
                return 0;
 
-       if (ts->nohz_mode != NOHZ_MODE_INACTIVE)
+       if (tick_sched_flag_test(ts, TS_FLAG_NOHZ))
                return 0;
 
        if (!timekeeping_valid_for_hres() || !tick_is_oneshot_available())
index 5ed5a9d41d5a7a9489f954635b64a5bf04c0cf6e..e11c4dc65bcb24b3b4200c83d538e5a800ad4fc2 100644 (file)
@@ -14,20 +14,26 @@ struct tick_device {
        enum tick_device_mode mode;
 };
 
-enum tick_nohz_mode {
-       NOHZ_MODE_INACTIVE,
-       NOHZ_MODE_LOWRES,
-       NOHZ_MODE_HIGHRES,
-};
+/* The CPU is in the tick idle mode */
+#define TS_FLAG_INIDLE         BIT(0)
+/* The idle tick has been stopped */
+#define TS_FLAG_STOPPED                BIT(1)
+/*
+ * Indicator that the CPU is actively in the tick idle mode;
+ * it is reset during irq handling phases.
+ */
+#define TS_FLAG_IDLE_ACTIVE    BIT(2)
+/* CPU was the last one doing do_timer before going idle */
+#define TS_FLAG_DO_TIMER_LAST  BIT(3)
+/* NO_HZ is enabled */
+#define TS_FLAG_NOHZ           BIT(4)
+/* High resolution tick mode */
+#define TS_FLAG_HIGHRES                BIT(5)
 
 /**
  * struct tick_sched - sched tick emulation and no idle tick control/stats
  *
- * @inidle:            Indicator that the CPU is in the tick idle mode
- * @tick_stopped:      Indicator that the idle tick has been stopped
- * @idle_active:       Indicator that the CPU is actively in the tick idle mode;
- *                     it is reset during irq handling phases.
- * @do_timer_last:     CPU was the last one doing do_timer before going idle
+ * @flags:             State flags gathering the TS_FLAG_* features
  * @got_idle_tick:     Tick timer function has run with @inidle set
  * @stalled_jiffies:   Number of stalled jiffies detected across ticks
  * @last_tick_jiffies: Value of jiffies seen on last tick
@@ -57,11 +63,7 @@ enum tick_nohz_mode {
  */
 struct tick_sched {
        /* Common flags */
-       unsigned int                    inidle          : 1;
-       unsigned int                    tick_stopped    : 1;
-       unsigned int                    idle_active     : 1;
-       unsigned int                    do_timer_last   : 1;
-       unsigned int                    got_idle_tick   : 1;
+       unsigned long                   flags;
 
        /* Tick handling: jiffies stall check */
        unsigned int                    stalled_jiffies;
@@ -73,13 +75,13 @@ struct tick_sched {
        ktime_t                         next_tick;
        unsigned long                   idle_jiffies;
        ktime_t                         idle_waketime;
+       unsigned int                    got_idle_tick;
 
        /* Idle entry */
        seqcount_t                      idle_sleeptime_seq;
        ktime_t                         idle_entrytime;
 
        /* Tick stop */
-       enum tick_nohz_mode             nohz_mode;
        unsigned long                   last_jiffies;
        u64                             timer_expires_base;
        u64                             timer_expires;
@@ -102,11 +104,11 @@ struct tick_sched {
 
 extern struct tick_sched *tick_get_tick_sched(int cpu);
 
-extern void tick_setup_sched_timer(void);
-#if defined CONFIG_NO_HZ_COMMON || defined CONFIG_HIGH_RES_TIMERS
-extern void tick_cancel_sched_timer(int cpu);
+extern void tick_setup_sched_timer(bool hrtimer);
+#if defined CONFIG_TICK_ONESHOT
+extern void tick_sched_timer_dying(int cpu);
 #else
-static inline void tick_cancel_sched_timer(int cpu) { }
+static inline void tick_sched_timer_dying(int cpu) { }
 #endif
 
 #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
index ca058c8af6bafdf2581733e8e4d5f7b6aa1dc88c..3e5d422dd15cbf32e0fec3a44d100c35671fa202 100644 (file)
@@ -73,7 +73,7 @@ static void time64_to_tm_test_date_range(struct kunit *test)
 
                days = div_s64(secs, 86400);
 
-               #define FAIL_MSG "%05ld/%02d/%02d (%2d) : %ld", \
+               #define FAIL_MSG "%05ld/%02d/%02d (%2d) : %lld", \
                        year, month, mdday, yday, days
 
                KUNIT_ASSERT_EQ_MSG(test, year - 1900, result.tm_year, FAIL_MSG);
index 266d02809dbb1dceabfb2a05276385c6a3be9b0c..b58dffc58a8f40c7529da8d9a89297edf81e0098 100644 (file)
@@ -1180,13 +1180,15 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history,
 }
 
 /*
- * cycle_between - true if test occurs chronologically between before and after
+ * timestamp_in_interval - true if ts is chronologically in [start, end]
+ *
+ * True if ts occurs chronologically at or after start, and before or at end.
  */
-static bool cycle_between(u64 before, u64 test, u64 after)
+static bool timestamp_in_interval(u64 start, u64 end, u64 ts)
 {
-       if (test > before && test < after)
+       if (ts >= start && ts <= end)
                return true;
-       if (test < before && before > after)
+       if (start > end && (ts >= start || ts <= end))
                return true;
        return false;
 }
@@ -1232,11 +1234,12 @@ int get_device_system_crosststamp(int (*get_time_fn)
                        return ret;
 
                /*
-                * Verify that the clocksource associated with the captured
-                * system counter value is the same as the currently installed
-                * timekeeper clocksource
+                * Verify that the clocksource ID associated with the captured
+                * system counter value is the same as for the currently
+                * installed timekeeper clocksource
                 */
-               if (tk->tkr_mono.clock != system_counterval.cs)
+               if (system_counterval.cs_id == CSID_GENERIC ||
+                   tk->tkr_mono.clock->id != system_counterval.cs_id)
                        return -ENODEV;
                cycles = system_counterval.cycles;
 
@@ -1246,7 +1249,7 @@ int get_device_system_crosststamp(int (*get_time_fn)
                 */
                now = tk_clock_read(&tk->tkr_mono);
                interval_start = tk->tkr_mono.cycle_last;
-               if (!cycle_between(interval_start, cycles, now)) {
+               if (!timestamp_in_interval(interval_start, now, cycles)) {
                        clock_was_set_seq = tk->clock_was_set_seq;
                        cs_was_changed_seq = tk->cs_was_changed_seq;
                        cycles = interval_start;
@@ -1259,10 +1262,8 @@ int get_device_system_crosststamp(int (*get_time_fn)
                                      tk_core.timekeeper.offs_real);
                base_raw = tk->tkr_raw.base;
 
-               nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono,
-                                                    system_counterval.cycles);
-               nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw,
-                                                   system_counterval.cycles);
+               nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, cycles);
+               nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, cycles);
        } while (read_seqcount_retry(&tk_core.seq, seq));
 
        xtstamp->sys_realtime = ktime_add_ns(base_real, nsec_real);
@@ -1277,13 +1278,13 @@ int get_device_system_crosststamp(int (*get_time_fn)
                bool discontinuity;
 
                /*
-                * Check that the counter value occurs after the provided
+                * Check that the counter value is not before the provided
                 * history reference and that the history doesn't cross a
                 * clocksource change
                 */
                if (!history_begin ||
-                   !cycle_between(history_begin->cycles,
-                                  system_counterval.cycles, cycles) ||
+                   !timestamp_in_interval(history_begin->cycles,
+                                          cycles, system_counterval.cycles) ||
                    history_begin->cs_was_changed_seq != cs_was_changed_seq)
                        return -EINVAL;
                partial_history_cycles = cycles - system_counterval.cycles;
index 352b161113cda6856a6fac08e9cc5eb01818a056..e69e75d3858c21d9ce8bf8f60afbe7750bda3f0d 100644 (file)
@@ -53,6 +53,7 @@
 #include <asm/io.h>
 
 #include "tick-internal.h"
+#include "timer_migration.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/timer.h>
@@ -187,15 +188,66 @@ EXPORT_SYMBOL(jiffies_64);
 #define WHEEL_SIZE     (LVL_SIZE * LVL_DEPTH)
 
 #ifdef CONFIG_NO_HZ_COMMON
-# define NR_BASES      2
-# define BASE_STD      0
-# define BASE_DEF      1
+/*
+ * If multiple bases need to be locked, use the base ordering for lock
+ * nesting, i.e. lowest number first.
+ */
+# define NR_BASES      3
+# define BASE_LOCAL    0
+# define BASE_GLOBAL   1
+# define BASE_DEF      2
 #else
 # define NR_BASES      1
-# define BASE_STD      0
+# define BASE_LOCAL    0
+# define BASE_GLOBAL   0
 # define BASE_DEF      0
 #endif
 
+/**
+ * struct timer_base - Per CPU timer base (number of base depends on config)
+ * @lock:              Lock protecting the timer_base
+ * @running_timer:     When expiring timers, the lock is dropped. To make
+ *                     sure not to race agains deleting/modifying a
+ *                     currently running timer, the pointer is set to the
+ *                     timer, which expires at the moment. If no timer is
+ *                     running, the pointer is NULL.
+ * @expiry_lock:       PREEMPT_RT only: Lock is taken in softirq around
+ *                     timer expiry callback execution and when trying to
+ *                     delete a running timer and it wasn't successful in
+ *                     the first glance. It prevents priority inversion
+ *                     when callback was preempted on a remote CPU and a
+ *                     caller tries to delete the running timer. It also
+ *                     prevents a life lock, when the task which tries to
+ *                     delete a timer preempted the softirq thread which
+ *                     is running the timer callback function.
+ * @timer_waiters:     PREEMPT_RT only: Tells, if there is a waiter
+ *                     waiting for the end of the timer callback function
+ *                     execution.
+ * @clk:               clock of the timer base; is updated before enqueue
+ *                     of a timer; during expiry, it is 1 offset ahead of
+ *                     jiffies to avoid endless requeuing to current
+ *                     jiffies
+ * @next_expiry:       expiry value of the first timer; it is updated when
+ *                     finding the next timer and during enqueue; the
+ *                     value is not valid, when next_expiry_recalc is set
+ * @cpu:               Number of CPU the timer base belongs to
+ * @next_expiry_recalc: States, whether a recalculation of next_expiry is
+ *                     required. Value is set true, when a timer was
+ *                     deleted.
+ * @is_idle:           Is set, when timer_base is idle. It is triggered by NOHZ
+ *                     code. This state is only used in standard
+ *                     base. Deferrable timers, which are enqueued remotely
+ *                     never wake up an idle CPU. So no matter of supporting it
+ *                     for this base.
+ * @timers_pending:    Is set, when a timer is pending in the base. It is only
+ *                     reliable when next_expiry_recalc is not set.
+ * @pending_map:       bitmap of the timer wheel; each bit reflects a
+ *                     bucket of the wheel. When a bit is set, at least a
+ *                     single timer is enqueued in the related bucket.
+ * @vectors:           Array of lists; Each array member reflects a bucket
+ *                     of the timer wheel. The list contains all timers
+ *                     which are enqueued into a specific bucket.
+ */
 struct timer_base {
        raw_spinlock_t          lock;
        struct timer_list       *running_timer;
@@ -583,11 +635,16 @@ trigger_dyntick_cpu(struct timer_base *base, struct timer_list *timer)
 
        /*
         * We might have to IPI the remote CPU if the base is idle and the
-        * timer is not deferrable. If the other CPU is on the way to idle
-        * then it can't set base->is_idle as we hold the base lock:
+        * timer is pinned. If it is a non pinned timer, it is only queued
+        * on the remote CPU, when timer was running during queueing. Then
+        * everything is handled by remote CPU anyway. If the other CPU is
+        * on the way to idle then it can't set base->is_idle as we hold
+        * the base lock:
         */
-       if (base->is_idle)
+       if (base->is_idle) {
+               WARN_ON_ONCE(!(timer->flags & TIMER_PINNED));
                wake_up_nohz_cpu(base->cpu);
+       }
 }
 
 /*
@@ -899,7 +956,10 @@ static int detach_if_pending(struct timer_list *timer, struct timer_base *base,
 
 static inline struct timer_base *get_timer_cpu_base(u32 tflags, u32 cpu)
 {
-       struct timer_base *base = per_cpu_ptr(&timer_bases[BASE_STD], cpu);
+       int index = tflags & TIMER_PINNED ? BASE_LOCAL : BASE_GLOBAL;
+       struct timer_base *base;
+
+       base = per_cpu_ptr(&timer_bases[index], cpu);
 
        /*
         * If the timer is deferrable and NO_HZ_COMMON is set then we need
@@ -912,7 +972,10 @@ static inline struct timer_base *get_timer_cpu_base(u32 tflags, u32 cpu)
 
 static inline struct timer_base *get_timer_this_cpu_base(u32 tflags)
 {
-       struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
+       int index = tflags & TIMER_PINNED ? BASE_LOCAL : BASE_GLOBAL;
+       struct timer_base *base;
+
+       base = this_cpu_ptr(&timer_bases[index]);
 
        /*
         * If the timer is deferrable and NO_HZ_COMMON is set then we need
@@ -928,17 +991,6 @@ static inline struct timer_base *get_timer_base(u32 tflags)
        return get_timer_cpu_base(tflags, tflags & TIMER_CPUMASK);
 }
 
-static inline struct timer_base *
-get_target_base(struct timer_base *base, unsigned tflags)
-{
-#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
-       if (static_branch_likely(&timers_migration_enabled) &&
-           !(tflags & TIMER_PINNED))
-               return get_timer_cpu_base(tflags, get_nohz_timer_target());
-#endif
-       return get_timer_this_cpu_base(tflags);
-}
-
 static inline void __forward_timer_base(struct timer_base *base,
                                        unsigned long basej)
 {
@@ -1093,7 +1145,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
        if (!ret && (options & MOD_TIMER_PENDING_ONLY))
                goto out_unlock;
 
-       new_base = get_target_base(base, timer->flags);
+       new_base = get_timer_this_cpu_base(timer->flags);
 
        if (base != new_base) {
                /*
@@ -1245,12 +1297,49 @@ void add_timer(struct timer_list *timer)
 }
 EXPORT_SYMBOL(add_timer);
 
+/**
+ * add_timer_local() - Start a timer on the local CPU
+ * @timer:     The timer to be started
+ *
+ * Same as add_timer() except that the timer flag TIMER_PINNED is set.
+ *
+ * See add_timer() for further details.
+ */
+void add_timer_local(struct timer_list *timer)
+{
+       if (WARN_ON_ONCE(timer_pending(timer)))
+               return;
+       timer->flags |= TIMER_PINNED;
+       __mod_timer(timer, timer->expires, MOD_TIMER_NOTPENDING);
+}
+EXPORT_SYMBOL(add_timer_local);
+
+/**
+ * add_timer_global() - Start a timer without TIMER_PINNED flag set
+ * @timer:     The timer to be started
+ *
+ * Same as add_timer() except that the timer flag TIMER_PINNED is unset.
+ *
+ * See add_timer() for further details.
+ */
+void add_timer_global(struct timer_list *timer)
+{
+       if (WARN_ON_ONCE(timer_pending(timer)))
+               return;
+       timer->flags &= ~TIMER_PINNED;
+       __mod_timer(timer, timer->expires, MOD_TIMER_NOTPENDING);
+}
+EXPORT_SYMBOL(add_timer_global);
+
 /**
  * add_timer_on - Start a timer on a particular CPU
  * @timer:     The timer to be started
  * @cpu:       The CPU to start it on
  *
- * Same as add_timer() except that it starts the timer on the given CPU.
+ * Same as add_timer() except that it starts the timer on the given CPU and
+ * the TIMER_PINNED flag is set. When timer shouldn't be a pinned timer in
+ * the next round, add_timer_global() should be used instead as it unsets
+ * the TIMER_PINNED flag.
  *
  * See add_timer() for further details.
  */
@@ -1264,6 +1353,9 @@ void add_timer_on(struct timer_list *timer, int cpu)
        if (WARN_ON_ONCE(timer_pending(timer)))
                return;
 
+       /* Make sure timer flags have TIMER_PINNED flag set */
+       timer->flags |= TIMER_PINNED;
+
        new_base = get_timer_cpu_base(timer->flags, cpu);
 
        /*
@@ -1911,71 +2003,350 @@ static u64 cmp_next_hrtimer_event(u64 basem, u64 expires)
        return DIV_ROUND_UP_ULL(nextevt, TICK_NSEC) * TICK_NSEC;
 }
 
+static unsigned long next_timer_interrupt(struct timer_base *base,
+                                         unsigned long basej)
+{
+       if (base->next_expiry_recalc)
+               next_expiry_recalc(base);
+
+       /*
+        * Move next_expiry for the empty base into the future to prevent an
+        * unnecessary raise of the timer softirq when the next_expiry value
+        * will be reached even if there is no timer pending.
+        *
+        * This update is also required to make timer_base::next_expiry values
+        * easy comparable to find out which base holds the first pending timer.
+        */
+       if (!base->timers_pending)
+               base->next_expiry = basej + NEXT_TIMER_MAX_DELTA;
+
+       return base->next_expiry;
+}
+
+static unsigned long fetch_next_timer_interrupt(unsigned long basej, u64 basem,
+                                               struct timer_base *base_local,
+                                               struct timer_base *base_global,
+                                               struct timer_events *tevt)
+{
+       unsigned long nextevt, nextevt_local, nextevt_global;
+       bool local_first;
+
+       nextevt_local = next_timer_interrupt(base_local, basej);
+       nextevt_global = next_timer_interrupt(base_global, basej);
+
+       local_first = time_before_eq(nextevt_local, nextevt_global);
+
+       nextevt = local_first ? nextevt_local : nextevt_global;
+
+       /*
+        * If the @nextevt is at max. one tick away, use @nextevt and store
+        * it in the local expiry value. The next global event is irrelevant in
+        * this case and can be left as KTIME_MAX.
+        */
+       if (time_before_eq(nextevt, basej + 1)) {
+               /* If we missed a tick already, force 0 delta */
+               if (time_before(nextevt, basej))
+                       nextevt = basej;
+               tevt->local = basem + (u64)(nextevt - basej) * TICK_NSEC;
+
+               /*
+                * This is required for the remote check only but it doesn't
+                * hurt, when it is done for both call sites:
+                *
+                * * The remote callers will only take care of the global timers
+                *   as local timers will be handled by CPU itself. When not
+                *   updating tevt->global with the already missed first global
+                *   timer, it is possible that it will be missed completely.
+                *
+                * * The local callers will ignore the tevt->global anyway, when
+                *   nextevt is max. one tick away.
+                */
+               if (!local_first)
+                       tevt->global = tevt->local;
+               return nextevt;
+       }
+
+       /*
+        * Update tevt.* values:
+        *
+        * If the local queue expires first, then the global event can be
+        * ignored. If the global queue is empty, nothing to do either.
+        */
+       if (!local_first && base_global->timers_pending)
+               tevt->global = basem + (u64)(nextevt_global - basej) * TICK_NSEC;
+
+       if (base_local->timers_pending)
+               tevt->local = basem + (u64)(nextevt_local - basej) * TICK_NSEC;
+
+       return nextevt;
+}
+
+# ifdef CONFIG_SMP
 /**
- * get_next_timer_interrupt - return the time (clock mono) of the next timer
+ * fetch_next_timer_interrupt_remote() - Store next timers into @tevt
  * @basej:     base time jiffies
  * @basem:     base time clock monotonic
+ * @tevt:      Pointer to the storage for the expiry values
+ * @cpu:       Remote CPU
+ *
+ * Stores the next pending local and global timer expiry values in the
+ * struct pointed to by @tevt. If a queue is empty the corresponding
+ * field is set to KTIME_MAX. If local event expires before global
+ * event, global event is set to KTIME_MAX as well.
  *
- * Returns the tick aligned clock monotonic time of the next pending
- * timer or KTIME_MAX if no timer is pending.
+ * Caller needs to make sure timer base locks are held (use
+ * timer_lock_remote_bases() for this purpose).
  */
-u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
+void fetch_next_timer_interrupt_remote(unsigned long basej, u64 basem,
+                                      struct timer_events *tevt,
+                                      unsigned int cpu)
+{
+       struct timer_base *base_local, *base_global;
+
+       /* Preset local / global events */
+       tevt->local = tevt->global = KTIME_MAX;
+
+       base_local = per_cpu_ptr(&timer_bases[BASE_LOCAL], cpu);
+       base_global = per_cpu_ptr(&timer_bases[BASE_GLOBAL], cpu);
+
+       lockdep_assert_held(&base_local->lock);
+       lockdep_assert_held(&base_global->lock);
+
+       fetch_next_timer_interrupt(basej, basem, base_local, base_global, tevt);
+}
+
+/**
+ * timer_unlock_remote_bases - unlock timer bases of cpu
+ * @cpu:       Remote CPU
+ *
+ * Unlocks the remote timer bases.
+ */
+void timer_unlock_remote_bases(unsigned int cpu)
+       __releases(timer_bases[BASE_LOCAL]->lock)
+       __releases(timer_bases[BASE_GLOBAL]->lock)
+{
+       struct timer_base *base_local, *base_global;
+
+       base_local = per_cpu_ptr(&timer_bases[BASE_LOCAL], cpu);
+       base_global = per_cpu_ptr(&timer_bases[BASE_GLOBAL], cpu);
+
+       raw_spin_unlock(&base_global->lock);
+       raw_spin_unlock(&base_local->lock);
+}
+
+/**
+ * timer_lock_remote_bases - lock timer bases of cpu
+ * @cpu:       Remote CPU
+ *
+ * Locks the remote timer bases.
+ */
+void timer_lock_remote_bases(unsigned int cpu)
+       __acquires(timer_bases[BASE_LOCAL]->lock)
+       __acquires(timer_bases[BASE_GLOBAL]->lock)
+{
+       struct timer_base *base_local, *base_global;
+
+       base_local = per_cpu_ptr(&timer_bases[BASE_LOCAL], cpu);
+       base_global = per_cpu_ptr(&timer_bases[BASE_GLOBAL], cpu);
+
+       lockdep_assert_irqs_disabled();
+
+       raw_spin_lock(&base_local->lock);
+       raw_spin_lock_nested(&base_global->lock, SINGLE_DEPTH_NESTING);
+}
+
+/**
+ * timer_base_is_idle() - Return whether timer base is set idle
+ *
+ * Returns value of local timer base is_idle value.
+ */
+bool timer_base_is_idle(void)
+{
+       return __this_cpu_read(timer_bases[BASE_LOCAL].is_idle);
+}
+
+static void __run_timer_base(struct timer_base *base);
+
+/**
+ * timer_expire_remote() - expire global timers of cpu
+ * @cpu:       Remote CPU
+ *
+ * Expire timers of global base of remote CPU.
+ */
+void timer_expire_remote(unsigned int cpu)
+{
+       struct timer_base *base = per_cpu_ptr(&timer_bases[BASE_GLOBAL], cpu);
+
+       __run_timer_base(base);
+}
+
+static void timer_use_tmigr(unsigned long basej, u64 basem,
+                           unsigned long *nextevt, bool *tick_stop_path,
+                           bool timer_base_idle, struct timer_events *tevt)
 {
-       struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
-       unsigned long nextevt = basej + NEXT_TIMER_MAX_DELTA;
-       u64 expires = KTIME_MAX;
-       bool was_idle;
+       u64 next_tmigr;
+
+       if (timer_base_idle)
+               next_tmigr = tmigr_cpu_new_timer(tevt->global);
+       else if (tick_stop_path)
+               next_tmigr = tmigr_cpu_deactivate(tevt->global);
+       else
+               next_tmigr = tmigr_quick_check(tevt->global);
 
        /*
-        * Pretend that there is no timer pending if the cpu is offline.
-        * Possible pending timers will be migrated later to an active cpu.
+        * If the CPU is the last going idle in timer migration hierarchy, make
+        * sure the CPU will wake up in time to handle remote timers.
+        * next_tmigr == KTIME_MAX if other CPUs are still active.
         */
-       if (cpu_is_offline(smp_processor_id()))
-               return expires;
+       if (next_tmigr < tevt->local) {
+               u64 tmp;
 
-       raw_spin_lock(&base->lock);
-       if (base->next_expiry_recalc)
-               next_expiry_recalc(base);
+               /* If we missed a tick already, force 0 delta */
+               if (next_tmigr < basem)
+                       next_tmigr = basem;
+
+               tmp = div_u64(next_tmigr - basem, TICK_NSEC);
+
+               *nextevt = basej + (unsigned long)tmp;
+               tevt->local = next_tmigr;
+       }
+}
+# else
+static void timer_use_tmigr(unsigned long basej, u64 basem,
+                           unsigned long *nextevt, bool *tick_stop_path,
+                           bool timer_base_idle, struct timer_events *tevt)
+{
+       /*
+        * Make sure first event is written into tevt->local to not miss a
+        * timer on !SMP systems.
+        */
+       tevt->local = min_t(u64, tevt->local, tevt->global);
+}
+# endif /* CONFIG_SMP */
+
+static inline u64 __get_next_timer_interrupt(unsigned long basej, u64 basem,
+                                            bool *idle)
+{
+       struct timer_events tevt = { .local = KTIME_MAX, .global = KTIME_MAX };
+       struct timer_base *base_local, *base_global;
+       unsigned long nextevt;
+       bool idle_is_possible;
+
+       /*
+        * When the CPU is offline, the tick is cancelled and nothing is supposed
+        * to try to stop it.
+        */
+       if (WARN_ON_ONCE(cpu_is_offline(smp_processor_id()))) {
+               if (idle)
+                       *idle = true;
+               return tevt.local;
+       }
+
+       base_local = this_cpu_ptr(&timer_bases[BASE_LOCAL]);
+       base_global = this_cpu_ptr(&timer_bases[BASE_GLOBAL]);
+
+       raw_spin_lock(&base_local->lock);
+       raw_spin_lock_nested(&base_global->lock, SINGLE_DEPTH_NESTING);
+
+       nextevt = fetch_next_timer_interrupt(basej, basem, base_local,
+                                            base_global, &tevt);
+
+       /*
+        * If the next event is only one jiffie ahead there is no need to call
+        * timer migration hierarchy related functions. The value for the next
+        * global timer in @tevt struct equals then KTIME_MAX. This is also
+        * true, when the timer base is idle.
+        *
+        * The proper timer migration hierarchy function depends on the callsite
+        * and whether timer base is idle or not. @nextevt will be updated when
+        * this CPU needs to handle the first timer migration hierarchy
+        * event. See timer_use_tmigr() for detailed information.
+        */
+       idle_is_possible = time_after(nextevt, basej + 1);
+       if (idle_is_possible)
+               timer_use_tmigr(basej, basem, &nextevt, idle,
+                               base_local->is_idle, &tevt);
 
        /*
         * We have a fresh next event. Check whether we can forward the
         * base.
         */
-       __forward_timer_base(base, basej);
+       __forward_timer_base(base_local, basej);
+       __forward_timer_base(base_global, basej);
 
-       if (base->timers_pending) {
-               nextevt = base->next_expiry;
+       /*
+        * Set base->is_idle only when caller is timer_base_try_to_set_idle()
+        */
+       if (idle) {
+               /*
+                * Bases are idle if the next event is more than a tick
+                * away. Caution: @nextevt could have changed by enqueueing a
+                * global timer into timer migration hierarchy. Therefore a new
+                * check is required here.
+                *
+                * If the base is marked idle then any timer add operation must
+                * forward the base clk itself to keep granularity small. This
+                * idle logic is only maintained for the BASE_LOCAL and
+                * BASE_GLOBAL base, deferrable timers may still see large
+                * granularity skew (by design).
+                */
+               if (!base_local->is_idle && time_after(nextevt, basej + 1)) {
+                       base_local->is_idle = true;
+                       trace_timer_base_idle(true, base_local->cpu);
+               }
+               *idle = base_local->is_idle;
 
-               /* If we missed a tick already, force 0 delta */
-               if (time_before(nextevt, basej))
-                       nextevt = basej;
-               expires = basem + (u64)(nextevt - basej) * TICK_NSEC;
-       } else {
                /*
-                * Move next_expiry for the empty base into the future to
-                * prevent a unnecessary raise of the timer softirq when the
-                * next_expiry value will be reached even if there is no timer
-                * pending.
+                * When timer base is not set idle, undo the effect of
+                * tmigr_cpu_deactivate() to prevent inconsitent states - active
+                * timer base but inactive timer migration hierarchy.
+                *
+                * When timer base was already marked idle, nothing will be
+                * changed here.
                 */
-               base->next_expiry = nextevt;
+               if (!base_local->is_idle && idle_is_possible)
+                       tmigr_cpu_activate();
        }
 
-       /*
-        * Base is idle if the next event is more than a tick away.
-        *
-        * If the base is marked idle then any timer add operation must forward
-        * the base clk itself to keep granularity small. This idle logic is
-        * only maintained for the BASE_STD base, deferrable timers may still
-        * see large granularity skew (by design).
-        */
-       was_idle = base->is_idle;
-       base->is_idle = time_after(nextevt, basej + 1);
-       if (was_idle != base->is_idle)
-               trace_timer_base_idle(base->is_idle, base->cpu);
+       raw_spin_unlock(&base_global->lock);
+       raw_spin_unlock(&base_local->lock);
 
-       raw_spin_unlock(&base->lock);
+       return cmp_next_hrtimer_event(basem, tevt.local);
+}
 
-       return cmp_next_hrtimer_event(basem, expires);
+/**
+ * get_next_timer_interrupt() - return the time (clock mono) of the next timer
+ * @basej:     base time jiffies
+ * @basem:     base time clock monotonic
+ *
+ * Returns the tick aligned clock monotonic time of the next pending timer or
+ * KTIME_MAX if no timer is pending. If timer of global base was queued into
+ * timer migration hierarchy, first global timer is not taken into account. If
+ * it was the last CPU of timer migration hierarchy going idle, first global
+ * event is taken into account.
+ */
+u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
+{
+       return __get_next_timer_interrupt(basej, basem, NULL);
+}
+
+/**
+ * timer_base_try_to_set_idle() - Try to set the idle state of the timer bases
+ * @basej:     base time jiffies
+ * @basem:     base time clock monotonic
+ * @idle:      pointer to store the value of timer_base->is_idle on return;
+ *             *idle contains the information whether tick was already stopped
+ *
+ * Returns the tick aligned clock monotonic time of the next pending timer or
+ * KTIME_MAX if no timer is pending. When tick was already stopped KTIME_MAX is
+ * returned as well.
+ */
+u64 timer_base_try_to_set_idle(unsigned long basej, u64 basem, bool *idle)
+{
+       if (*idle)
+               return KTIME_MAX;
+
+       return __get_next_timer_interrupt(basej, basem, idle);
 }
 
 /**
@@ -1985,18 +2356,18 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
  */
 void timer_clear_idle(void)
 {
-       struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
-
        /*
-        * We do this unlocked. The worst outcome is a remote enqueue sending
-        * a pointless IPI, but taking the lock would just make the window for
-        * sending the IPI a few instructions smaller for the cost of taking
-        * the lock in the exit from idle path.
+        * We do this unlocked. The worst outcome is a remote pinned timer
+        * enqueue sending a pointless IPI, but taking the lock would just
+        * make the window for sending the IPI a few instructions smaller
+        * for the cost of taking the lock in the exit from idle
+        * path. Required for BASE_LOCAL only.
         */
-       if (base->is_idle) {
-               base->is_idle = false;
-               trace_timer_base_idle(false, smp_processor_id());
-       }
+       __this_cpu_write(timer_bases[BASE_LOCAL].is_idle, false);
+       trace_timer_base_idle(false, smp_processor_id());
+
+       /* Activate without holding the timer_base->lock */
+       tmigr_cpu_activate();
 }
 #endif
 
@@ -2009,11 +2380,10 @@ static inline void __run_timers(struct timer_base *base)
        struct hlist_head heads[LVL_DEPTH];
        int levels;
 
-       if (time_before(jiffies, base->next_expiry))
-               return;
+       lockdep_assert_held(&base->lock);
 
-       timer_base_lock_expiry(base);
-       raw_spin_lock_irq(&base->lock);
+       if (base->running_timer)
+               return;
 
        while (time_after_eq(jiffies, base->clk) &&
               time_after_eq(jiffies, base->next_expiry)) {
@@ -2037,20 +2407,40 @@ static inline void __run_timers(struct timer_base *base)
                while (levels--)
                        expire_timers(base, heads + levels);
        }
+}
+
+static void __run_timer_base(struct timer_base *base)
+{
+       if (time_before(jiffies, base->next_expiry))
+               return;
+
+       timer_base_lock_expiry(base);
+       raw_spin_lock_irq(&base->lock);
+       __run_timers(base);
        raw_spin_unlock_irq(&base->lock);
        timer_base_unlock_expiry(base);
 }
 
+static void run_timer_base(int index)
+{
+       struct timer_base *base = this_cpu_ptr(&timer_bases[index]);
+
+       __run_timer_base(base);
+}
+
 /*
  * This function runs timers and the timer-tq in bottom half context.
  */
 static __latent_entropy void run_timer_softirq(struct softirq_action *h)
 {
-       struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
+       run_timer_base(BASE_LOCAL);
+       if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) {
+               run_timer_base(BASE_GLOBAL);
+               run_timer_base(BASE_DEF);
 
-       __run_timers(base);
-       if (IS_ENABLED(CONFIG_NO_HZ_COMMON))
-               __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF]));
+               if (is_timers_nohz_active())
+                       tmigr_handle_remote();
+       }
 }
 
 /*
@@ -2058,19 +2448,18 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h)
  */
 static void run_local_timers(void)
 {
-       struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
+       struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_LOCAL]);
 
        hrtimer_run_queues();
-       /* Raise the softirq only if required. */
-       if (time_before(jiffies, base->next_expiry)) {
-               if (!IS_ENABLED(CONFIG_NO_HZ_COMMON))
-                       return;
-               /* CPU is awake, so check the deferrable base. */
-               base++;
-               if (time_before(jiffies, base->next_expiry))
+
+       for (int i = 0; i < NR_BASES; i++, base++) {
+               /* Raise the softirq only if required. */
+               if (time_after_eq(jiffies, base->next_expiry) ||
+                   (i == BASE_DEF && tmigr_requires_handle_remote())) {
+                       raise_softirq(TIMER_SOFTIRQ);
                        return;
+               }
        }
-       raise_softirq(TIMER_SOFTIRQ);
 }
 
 /*
index ed7d6ad694fba63e84db9dd5972470febc59e4cf..1c311c46da5074c1cb33027c96638e68a606574a 100644 (file)
@@ -147,11 +147,15 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
 # define P_ns(x) \
        SEQ_printf(m, "  .%-15s: %Lu nsecs\n", #x, \
                   (unsigned long long)(ktime_to_ns(ts->x)))
+# define P_flag(x, f)                      \
+       SEQ_printf(m, "  .%-15s: %d\n", #x, !!(ts->flags & (f)))
+
        {
                struct tick_sched *ts = tick_get_tick_sched(cpu);
-               P(nohz_mode);
+               P_flag(nohz, TS_FLAG_NOHZ);
+               P_flag(highres, TS_FLAG_HIGHRES);
                P_ns(last_tick);
-               P(tick_stopped);
+               P_flag(tick_stopped, TS_FLAG_STOPPED);
                P(idle_jiffies);
                P(idle_calls);
                P(idle_sleeps);
@@ -256,7 +260,7 @@ static void timer_list_show_tickdevices_header(struct seq_file *m)
 
 static inline void timer_list_header(struct seq_file *m, u64 now)
 {
-       SEQ_printf(m, "Timer List Version: v0.9\n");
+       SEQ_printf(m, "Timer List Version: v0.10\n");
        SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES);
        SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now);
        SEQ_printf(m, "\n");
diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c
new file mode 100644 (file)
index 0000000..8f49b6b
--- /dev/null
@@ -0,0 +1,1793 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Infrastructure for migratable timers
+ *
+ * Copyright(C) 2022 linutronix GmbH
+ */
+#include <linux/cpuhotplug.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/timerqueue.h>
+#include <trace/events/ipi.h>
+
+#include "timer_migration.h"
+#include "tick-internal.h"
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/timer_migration.h>
+
+/*
+ * The timer migration mechanism is built on a hierarchy of groups. The
+ * lowest level group contains CPUs, the next level groups of CPU groups
+ * and so forth. The CPU groups are kept per node so for the normal case
+ * lock contention won't happen across nodes. Depending on the number of
+ * CPUs per node even the next level might be kept as groups of CPU groups
+ * per node and only the levels above cross the node topology.
+ *
+ * Example topology for a two node system with 24 CPUs each.
+ *
+ * LVL 2                           [GRP2:0]
+ *                              GRP1:0 = GRP1:M
+ *
+ * LVL 1            [GRP1:0]                      [GRP1:1]
+ *               GRP0:0 - GRP0:2               GRP0:3 - GRP0:5
+ *
+ * LVL 0  [GRP0:0]  [GRP0:1]  [GRP0:2]  [GRP0:3]  [GRP0:4]  [GRP0:5]
+ * CPUS     0-7       8-15      16-23     24-31     32-39     40-47
+ *
+ * The groups hold a timer queue of events sorted by expiry time. These
+ * queues are updated when CPUs go in idle. When they come out of idle
+ * ignore flag of events is set.
+ *
+ * Each group has a designated migrator CPU/group as long as a CPU/group is
+ * active in the group. This designated role is necessary to avoid that all
+ * active CPUs in a group try to migrate expired timers from other CPUs,
+ * which would result in massive lock bouncing.
+ *
+ * When a CPU is awake, it checks in it's own timer tick the group
+ * hierarchy up to the point where it is assigned the migrator role or if
+ * no CPU is active, it also checks the groups where no migrator is set
+ * (TMIGR_NONE).
+ *
+ * If it finds expired timers in one of the group queues it pulls them over
+ * from the idle CPU and runs the timer function. After that it updates the
+ * group and the parent groups if required.
+ *
+ * CPUs which go idle arm their CPU local timer hardware for the next local
+ * (pinned) timer event. If the next migratable timer expires after the
+ * next local timer or the CPU has no migratable timer pending then the
+ * CPU does not queue an event in the LVL0 group. If the next migratable
+ * timer expires before the next local timer then the CPU queues that timer
+ * in the LVL0 group. In both cases the CPU marks itself idle in the LVL0
+ * group.
+ *
+ * When CPU comes out of idle and when a group has at least a single active
+ * child, the ignore flag of the tmigr_event is set. This indicates, that
+ * the event is ignored even if it is still enqueued in the parent groups
+ * timer queue. It will be removed when touching the timer queue the next
+ * time. This spares locking in active path as the lock protects (after
+ * setup) only event information. For more information about locking,
+ * please read the section "Locking rules".
+ *
+ * If the CPU is the migrator of the group then it delegates that role to
+ * the next active CPU in the group or sets migrator to TMIGR_NONE when
+ * there is no active CPU in the group. This delegation needs to be
+ * propagated up the hierarchy so hand over from other leaves can happen at
+ * all hierarchy levels w/o doing a search.
+ *
+ * When the last CPU in the system goes idle, then it drops all migrator
+ * duties up to the top level of the hierarchy (LVL2 in the example). It
+ * then has to make sure, that it arms it's own local hardware timer for
+ * the earliest event in the system.
+ *
+ *
+ * Lifetime rules:
+ * ---------------
+ *
+ * The groups are built up at init time or when CPUs come online. They are
+ * not destroyed when a group becomes empty due to offlining. The group
+ * just won't participate in the hierarchy management anymore. Destroying
+ * groups would result in interesting race conditions which would just make
+ * the whole mechanism slow and complex.
+ *
+ *
+ * Locking rules:
+ * --------------
+ *
+ * For setting up new groups and handling events it's required to lock both
+ * child and parent group. The lock ordering is always bottom up. This also
+ * includes the per CPU locks in struct tmigr_cpu. For updating the migrator and
+ * active CPU/group information atomic_try_cmpxchg() is used instead and only
+ * the per CPU tmigr_cpu->lock is held.
+ *
+ * During the setup of groups tmigr_level_list is required. It is protected by
+ * @tmigr_mutex.
+ *
+ * When @timer_base->lock as well as tmigr related locks are required, the lock
+ * ordering is: first @timer_base->lock, afterwards tmigr related locks.
+ *
+ *
+ * Protection of the tmigr group state information:
+ * ------------------------------------------------
+ *
+ * The state information with the list of active children and migrator needs to
+ * be protected by a sequence counter. It prevents a race when updates in child
+ * groups are propagated in changed order. The state update is performed
+ * lockless and group wise. The following scenario describes what happens
+ * without updating the sequence counter:
+ *
+ * Therefore, let's take three groups and four CPUs (CPU2 and CPU3 as well
+ * as GRP0:1 will not change during the scenario):
+ *
+ *    LVL 1            [GRP1:0]
+ *                     migrator = GRP0:1
+ *                     active   = GRP0:0, GRP0:1
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *           migrator = CPU0           migrator = CPU2
+ *           active   = CPU0           active   = CPU2
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *             active      idle           active      idle
+ *
+ *
+ * 1. CPU0 goes idle. As the update is performed group wise, in the first step
+ *    only GRP0:0 is updated. The update of GRP1:0 is pending as CPU0 has to
+ *    walk the hierarchy.
+ *
+ *    LVL 1            [GRP1:0]
+ *                     migrator = GRP0:1
+ *                     active   = GRP0:0, GRP0:1
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *       --> migrator = TMIGR_NONE     migrator = CPU2
+ *       --> active   =                active   = CPU2
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *         --> idle        idle           active      idle
+ *
+ * 2. While CPU0 goes idle and continues to update the state, CPU1 comes out of
+ *    idle. CPU1 updates GRP0:0. The update for GRP1:0 is pending as CPU1 also
+ *    has to walk the hierarchy. Both CPUs (CPU0 and CPU1) now walk the
+ *    hierarchy to perform the needed update from their point of view. The
+ *    currently visible state looks the following:
+ *
+ *    LVL 1            [GRP1:0]
+ *                     migrator = GRP0:1
+ *                     active   = GRP0:0, GRP0:1
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *       --> migrator = CPU1           migrator = CPU2
+ *       --> active   = CPU1           active   = CPU2
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *             idle    --> active         active      idle
+ *
+ * 3. Here is the race condition: CPU1 managed to propagate its changes (from
+ *    step 2) through the hierarchy to GRP1:0 before CPU0 (step 1) did. The
+ *    active members of GRP1:0 remain unchanged after the update since it is
+ *    still valid from CPU1 current point of view:
+ *
+ *    LVL 1            [GRP1:0]
+ *                 --> migrator = GRP0:1
+ *                 --> active   = GRP0:0, GRP0:1
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *           migrator = CPU1           migrator = CPU2
+ *           active   = CPU1           active   = CPU2
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *             idle        active         active      idle
+ *
+ * 4. Now CPU0 finally propagates its changes (from step 1) to GRP1:0.
+ *
+ *    LVL 1            [GRP1:0]
+ *                 --> migrator = GRP0:1
+ *                 --> active   = GRP0:1
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *           migrator = CPU1           migrator = CPU2
+ *           active   = CPU1           active   = CPU2
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *             idle        active         active      idle
+ *
+ *
+ * The race of CPU0 vs. CPU1 led to an inconsistent state in GRP1:0. CPU1 is
+ * active and is correctly listed as active in GRP0:0. However GRP1:0 does not
+ * have GRP0:0 listed as active, which is wrong. The sequence counter has been
+ * added to avoid inconsistent states during updates. The state is updated
+ * atomically only if all members, including the sequence counter, match the
+ * expected value (compare-and-exchange).
+ *
+ * Looking back at the previous example with the addition of the sequence
+ * counter: The update as performed by CPU0 in step 4 will fail. CPU1 changed
+ * the sequence number during the update in step 3 so the expected old value (as
+ * seen by CPU0 before starting the walk) does not match.
+ *
+ * Prevent race between new event and last CPU going inactive
+ * ----------------------------------------------------------
+ *
+ * When the last CPU is going idle and there is a concurrent update of a new
+ * first global timer of an idle CPU, the group and child states have to be read
+ * while holding the lock in tmigr_update_events(). The following scenario shows
+ * what happens, when this is not done.
+ *
+ * 1. Only CPU2 is active:
+ *
+ *    LVL 1            [GRP1:0]
+ *                     migrator = GRP0:1
+ *                     active   = GRP0:1
+ *                     next_expiry = KTIME_MAX
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *           migrator = TMIGR_NONE     migrator = CPU2
+ *           active   =                active   = CPU2
+ *           next_expiry = KTIME_MAX   next_expiry = KTIME_MAX
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *             idle        idle           active      idle
+ *
+ * 2. Now CPU 2 goes idle (and has no global timer, that has to be handled) and
+ *    propagates that to GRP0:1:
+ *
+ *    LVL 1            [GRP1:0]
+ *                     migrator = GRP0:1
+ *                     active   = GRP0:1
+ *                     next_expiry = KTIME_MAX
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *           migrator = TMIGR_NONE --> migrator = TMIGR_NONE
+ *           active   =            --> active   =
+ *           next_expiry = KTIME_MAX   next_expiry = KTIME_MAX
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *             idle        idle       --> idle        idle
+ *
+ * 3. Now the idle state is propagated up to GRP1:0. As this is now the last
+ *    child going idle in top level group, the expiry of the next group event
+ *    has to be handed back to make sure no event is lost. As there is no event
+ *    enqueued, KTIME_MAX is handed back to CPU2.
+ *
+ *    LVL 1            [GRP1:0]
+ *                 --> migrator = TMIGR_NONE
+ *                 --> active   =
+ *                     next_expiry = KTIME_MAX
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *           migrator = TMIGR_NONE     migrator = TMIGR_NONE
+ *           active   =                active   =
+ *           next_expiry = KTIME_MAX   next_expiry = KTIME_MAX
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *             idle        idle       --> idle        idle
+ *
+ * 4. CPU 0 has a new timer queued from idle and it expires at TIMER0. CPU0
+ *    propagates that to GRP0:0:
+ *
+ *    LVL 1            [GRP1:0]
+ *                     migrator = TMIGR_NONE
+ *                     active   =
+ *                     next_expiry = KTIME_MAX
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *           migrator = TMIGR_NONE     migrator = TMIGR_NONE
+ *           active   =                active   =
+ *       --> next_expiry = TIMER0      next_expiry  = KTIME_MAX
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *             idle        idle           idle        idle
+ *
+ * 5. GRP0:0 is not active, so the new timer has to be propagated to
+ *    GRP1:0. Therefore the GRP1:0 state has to be read. When the stalled value
+ *    (from step 2) is read, the timer is enqueued into GRP1:0, but nothing is
+ *    handed back to CPU0, as it seems that there is still an active child in
+ *    top level group.
+ *
+ *    LVL 1            [GRP1:0]
+ *                     migrator = TMIGR_NONE
+ *                     active   =
+ *                 --> next_expiry = TIMER0
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *           migrator = TMIGR_NONE     migrator = TMIGR_NONE
+ *           active   =                active   =
+ *           next_expiry = TIMER0      next_expiry  = KTIME_MAX
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *             idle        idle           idle        idle
+ *
+ * This is prevented by reading the state when holding the lock (when a new
+ * timer has to be propagated from idle path)::
+ *
+ *   CPU2 (tmigr_inactive_up())          CPU0 (tmigr_new_timer_up())
+ *   --------------------------          ---------------------------
+ *   // step 3:
+ *   cmpxchg(&GRP1:0->state);
+ *   tmigr_update_events() {
+ *       spin_lock(&GRP1:0->lock);
+ *       // ... update events ...
+ *       // hand back first expiry when GRP1:0 is idle
+ *       spin_unlock(&GRP1:0->lock);
+ *       // ^^^ release state modification
+ *   }
+ *                                       tmigr_update_events() {
+ *                                           spin_lock(&GRP1:0->lock)
+ *                                           // ^^^ acquire state modification
+ *                                           group_state = atomic_read(&GRP1:0->state)
+ *                                           // .... update events ...
+ *                                           // hand back first expiry when GRP1:0 is idle
+ *                                           spin_unlock(&GRP1:0->lock) <3>
+ *                                           // ^^^ makes state visible for other
+ *                                           // callers of tmigr_new_timer_up()
+ *                                       }
+ *
+ * When CPU0 grabs the lock directly after cmpxchg, the first timer is reported
+ * back to CPU0 and also later on to CPU2. So no timer is missed. A concurrent
+ * update of the group state from active path is no problem, as the upcoming CPU
+ * will take care of the group events.
+ *
+ * Required event and timerqueue update after a remote expiry:
+ * -----------------------------------------------------------
+ *
+ * After expiring timers of a remote CPU, a walk through the hierarchy and
+ * update of events and timerqueues is required. It is obviously needed if there
+ * is a 'new' global timer but also if there is no new global timer but the
+ * remote CPU is still idle.
+ *
+ * 1. CPU0 and CPU1 are idle and have both a global timer expiring at the same
+ *    time. So both have an event enqueued in the timerqueue of GRP0:0. CPU3 is
+ *    also idle and has no global timer pending. CPU2 is the only active CPU and
+ *    thus also the migrator:
+ *
+ *    LVL 1            [GRP1:0]
+ *                     migrator = GRP0:1
+ *                     active   = GRP0:1
+ *                 --> timerqueue = evt-GRP0:0
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *           migrator = TMIGR_NONE     migrator = CPU2
+ *           active   =                active   = CPU2
+ *           groupevt.ignore = false   groupevt.ignore = true
+ *           groupevt.cpu = CPU0       groupevt.cpu =
+ *           timerqueue = evt-CPU0,    timerqueue =
+ *                        evt-CPU1
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *             idle        idle           active      idle
+ *
+ * 2. CPU2 starts to expire remote timers. It starts with LVL0 group
+ *    GRP0:1. There is no event queued in the timerqueue, so CPU2 continues with
+ *    the parent of GRP0:1: GRP1:0. In GRP1:0 it dequeues the first event. It
+ *    looks at tmigr_event::cpu struct member and expires the pending timer(s)
+ *    of CPU0.
+ *
+ *    LVL 1            [GRP1:0]
+ *                     migrator = GRP0:1
+ *                     active   = GRP0:1
+ *                 --> timerqueue =
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *           migrator = TMIGR_NONE     migrator = CPU2
+ *           active   =                active   = CPU2
+ *           groupevt.ignore = false   groupevt.ignore = true
+ *       --> groupevt.cpu = CPU0       groupevt.cpu =
+ *           timerqueue = evt-CPU0,    timerqueue =
+ *                        evt-CPU1
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *             idle        idle           active      idle
+ *
+ * 3. Some work has to be done after expiring the timers of CPU0. If we stop
+ *    here, then CPU1's pending global timer(s) will not expire in time and the
+ *    timerqueue of GRP0:0 has still an event for CPU0 enqueued which has just
+ *    been processed. So it is required to walk the hierarchy from CPU0's point
+ *    of view and update it accordingly. CPU0's event will be removed from the
+ *    timerqueue because it has no pending timer. If CPU0 would have a timer
+ *    pending then it has to expire after CPU1's first timer because all timers
+ *    from this period were just expired. Either way CPU1's event will be first
+ *    in GRP0:0's timerqueue and therefore set in the CPU field of the group
+ *    event which is then enqueued in GRP1:0's timerqueue as GRP0:0 is still not
+ *    active:
+ *
+ *    LVL 1            [GRP1:0]
+ *                     migrator = GRP0:1
+ *                     active   = GRP0:1
+ *                 --> timerqueue = evt-GRP0:0
+ *                   /                \
+ *    LVL 0  [GRP0:0]                  [GRP0:1]
+ *           migrator = TMIGR_NONE     migrator = CPU2
+ *           active   =                active   = CPU2
+ *           groupevt.ignore = false   groupevt.ignore = true
+ *       --> groupevt.cpu = CPU1       groupevt.cpu =
+ *       --> timerqueue = evt-CPU1     timerqueue =
+ *              /         \                /         \
+ *    CPUs     0           1              2           3
+ *             idle        idle           active      idle
+ *
+ * Now CPU2 (migrator) will continue step 2 at GRP1:0 and will expire the
+ * timer(s) of CPU1.
+ *
+ * The hierarchy walk in step 3 can be skipped if the migrator notices that a
+ * CPU of GRP0:0 is active again. The CPU will mark GRP0:0 active and take care
+ * of the group as migrator and any needed updates within the hierarchy.
+ */
+
+static DEFINE_MUTEX(tmigr_mutex);
+static struct list_head *tmigr_level_list __read_mostly;
+
+static unsigned int tmigr_hierarchy_levels __read_mostly;
+static unsigned int tmigr_crossnode_level __read_mostly;
+
+static DEFINE_PER_CPU(struct tmigr_cpu, tmigr_cpu);
+
+#define TMIGR_NONE     0xFF
+#define BIT_CNT                8
+
+static inline bool tmigr_is_not_available(struct tmigr_cpu *tmc)
+{
+       return !(tmc->tmgroup && tmc->online);
+}
+
+/*
+ * Returns true, when @childmask corresponds to the group migrator or when the
+ * group is not active - so no migrator is set.
+ */
+static bool tmigr_check_migrator(struct tmigr_group *group, u8 childmask)
+{
+       union tmigr_state s;
+
+       s.state = atomic_read(&group->migr_state);
+
+       if ((s.migrator == childmask) || (s.migrator == TMIGR_NONE))
+               return true;
+
+       return false;
+}
+
+static bool tmigr_check_migrator_and_lonely(struct tmigr_group *group, u8 childmask)
+{
+       bool lonely, migrator = false;
+       unsigned long active;
+       union tmigr_state s;
+
+       s.state = atomic_read(&group->migr_state);
+
+       if ((s.migrator == childmask) || (s.migrator == TMIGR_NONE))
+               migrator = true;
+
+       active = s.active;
+       lonely = bitmap_weight(&active, BIT_CNT) <= 1;
+
+       return (migrator && lonely);
+}
+
+static bool tmigr_check_lonely(struct tmigr_group *group)
+{
+       unsigned long active;
+       union tmigr_state s;
+
+       s.state = atomic_read(&group->migr_state);
+
+       active = s.active;
+
+       return bitmap_weight(&active, BIT_CNT) <= 1;
+}
+
+typedef bool (*up_f)(struct tmigr_group *, struct tmigr_group *, void *);
+
+static void __walk_groups(up_f up, void *data,
+                         struct tmigr_cpu *tmc)
+{
+       struct tmigr_group *child = NULL, *group = tmc->tmgroup;
+
+       do {
+               WARN_ON_ONCE(group->level >= tmigr_hierarchy_levels);
+
+               if (up(group, child, data))
+                       break;
+
+               child = group;
+               group = group->parent;
+       } while (group);
+}
+
+static void walk_groups(up_f up, void *data, struct tmigr_cpu *tmc)
+{
+       lockdep_assert_held(&tmc->lock);
+
+       __walk_groups(up, data, tmc);
+}
+
+/**
+ * struct tmigr_walk - data required for walking the hierarchy
+ * @nextexp:           Next CPU event expiry information which is handed into
+ *                     the timer migration code by the timer code
+ *                     (get_next_timer_interrupt())
+ * @firstexp:          Contains the first event expiry information when last
+ *                     active CPU of hierarchy is on the way to idle to make
+ *                     sure CPU will be back in time.
+ * @evt:               Pointer to tmigr_event which needs to be queued (of idle
+ *                     child group)
+ * @childmask:         childmask of child group
+ * @remote:            Is set, when the new timer path is executed in
+ *                     tmigr_handle_remote_cpu()
+ */
+struct tmigr_walk {
+       u64                     nextexp;
+       u64                     firstexp;
+       struct tmigr_event      *evt;
+       u8                      childmask;
+       bool                    remote;
+};
+
+/**
+ * struct tmigr_remote_data - data required for remote expiry hierarchy walk
+ * @basej:             timer base in jiffies
+ * @now:               timer base monotonic
+ * @firstexp:          returns expiry of the first timer in the idle timer
+ *                     migration hierarchy to make sure the timer is handled in
+ *                     time; it is stored in the per CPU tmigr_cpu struct of
+ *                     CPU which expires remote timers
+ * @childmask:         childmask of child group
+ * @check:             is set if there is the need to handle remote timers;
+ *                     required in tmigr_requires_handle_remote() only
+ * @tmc_active:                this flag indicates, whether the CPU which triggers
+ *                     the hierarchy walk is !idle in the timer migration
+ *                     hierarchy. When the CPU is idle and the whole hierarchy is
+ *                     idle, only the first event of the top level has to be
+ *                     considered.
+ */
+struct tmigr_remote_data {
+       unsigned long   basej;
+       u64             now;
+       u64             firstexp;
+       u8              childmask;
+       bool            check;
+       bool            tmc_active;
+};
+
+/*
+ * Returns the next event of the timerqueue @group->events
+ *
+ * Removes timers with ignore flag and update next_expiry of the group. Values
+ * of the group event are updated in tmigr_update_events() only.
+ */
+static struct tmigr_event *tmigr_next_groupevt(struct tmigr_group *group)
+{
+       struct timerqueue_node *node = NULL;
+       struct tmigr_event *evt = NULL;
+
+       lockdep_assert_held(&group->lock);
+
+       WRITE_ONCE(group->next_expiry, KTIME_MAX);
+
+       while ((node = timerqueue_getnext(&group->events))) {
+               evt = container_of(node, struct tmigr_event, nextevt);
+
+               if (!evt->ignore) {
+                       WRITE_ONCE(group->next_expiry, evt->nextevt.expires);
+                       return evt;
+               }
+
+               /*
+                * Remove next timers with ignore flag, because the group lock
+                * is held anyway
+                */
+               if (!timerqueue_del(&group->events, node))
+                       break;
+       }
+
+       return NULL;
+}
+
+/*
+ * Return the next event (with the expiry equal or before @now)
+ *
+ * Event, which is returned, is also removed from the queue.
+ */
+static struct tmigr_event *tmigr_next_expired_groupevt(struct tmigr_group *group,
+                                                      u64 now)
+{
+       struct tmigr_event *evt = tmigr_next_groupevt(group);
+
+       if (!evt || now < evt->nextevt.expires)
+               return NULL;
+
+       /*
+        * The event is ready to expire. Remove it and update next group event.
+        */
+       timerqueue_del(&group->events, &evt->nextevt);
+       tmigr_next_groupevt(group);
+
+       return evt;
+}
+
+static u64 tmigr_next_groupevt_expires(struct tmigr_group *group)
+{
+       struct tmigr_event *evt;
+
+       evt = tmigr_next_groupevt(group);
+
+       if (!evt)
+               return KTIME_MAX;
+       else
+               return evt->nextevt.expires;
+}
+
+static bool tmigr_active_up(struct tmigr_group *group,
+                           struct tmigr_group *child,
+                           void *ptr)
+{
+       union tmigr_state curstate, newstate;
+       struct tmigr_walk *data = ptr;
+       bool walk_done;
+       u8 childmask;
+
+       childmask = data->childmask;
+       /*
+        * No memory barrier is required here in contrast to
+        * tmigr_inactive_up(), as the group state change does not depend on the
+        * child state.
+        */
+       curstate.state = atomic_read(&group->migr_state);
+
+       do {
+               newstate = curstate;
+               walk_done = true;
+
+               if (newstate.migrator == TMIGR_NONE) {
+                       newstate.migrator = childmask;
+
+                       /* Changes need to be propagated */
+                       walk_done = false;
+               }
+
+               newstate.active |= childmask;
+               newstate.seq++;
+
+       } while (!atomic_try_cmpxchg(&group->migr_state, &curstate.state, newstate.state));
+
+       if ((walk_done == false) && group->parent)
+               data->childmask = group->childmask;
+
+       /*
+        * The group is active (again). The group event might be still queued
+        * into the parent group's timerqueue but can now be handled by the
+        * migrator of this group. Therefore the ignore flag for the group event
+        * is updated to reflect this.
+        *
+        * The update of the ignore flag in the active path is done lockless. In
+        * worst case the migrator of the parent group observes the change too
+        * late and expires remotely all events belonging to this group. The
+        * lock is held while updating the ignore flag in idle path. So this
+        * state change will not be lost.
+        */
+       group->groupevt.ignore = true;
+
+       trace_tmigr_group_set_cpu_active(group, newstate, childmask);
+
+       return walk_done;
+}
+
+static void __tmigr_cpu_activate(struct tmigr_cpu *tmc)
+{
+       struct tmigr_walk data;
+
+       data.childmask = tmc->childmask;
+
+       trace_tmigr_cpu_active(tmc);
+
+       tmc->cpuevt.ignore = true;
+       WRITE_ONCE(tmc->wakeup, KTIME_MAX);
+
+       walk_groups(&tmigr_active_up, &data, tmc);
+}
+
+/**
+ * tmigr_cpu_activate() - set this CPU active in timer migration hierarchy
+ *
+ * Call site timer_clear_idle() is called with interrupts disabled.
+ */
+void tmigr_cpu_activate(void)
+{
+       struct tmigr_cpu *tmc = this_cpu_ptr(&tmigr_cpu);
+
+       if (tmigr_is_not_available(tmc))
+               return;
+
+       if (WARN_ON_ONCE(!tmc->idle))
+               return;
+
+       raw_spin_lock(&tmc->lock);
+       tmc->idle = false;
+       __tmigr_cpu_activate(tmc);
+       raw_spin_unlock(&tmc->lock);
+}
+
+/*
+ * Returns true, if there is nothing to be propagated to the next level
+ *
+ * @data->firstexp is set to expiry of first gobal event of the (top level of
+ * the) hierarchy, but only when hierarchy is completely idle.
+ *
+ * The child and group states need to be read under the lock, to prevent a race
+ * against a concurrent tmigr_inactive_up() run when the last CPU goes idle. See
+ * also section "Prevent race between new event and last CPU going inactive" in
+ * the documentation at the top.
+ *
+ * This is the only place where the group event expiry value is set.
+ */
+static
+bool tmigr_update_events(struct tmigr_group *group, struct tmigr_group *child,
+                        struct tmigr_walk *data)
+{
+       struct tmigr_event *evt, *first_childevt;
+       union tmigr_state childstate, groupstate;
+       bool remote = data->remote;
+       bool walk_done = false;
+       u64 nextexp;
+
+       if (child) {
+               raw_spin_lock(&child->lock);
+               raw_spin_lock_nested(&group->lock, SINGLE_DEPTH_NESTING);
+
+               childstate.state = atomic_read(&child->migr_state);
+               groupstate.state = atomic_read(&group->migr_state);
+
+               if (childstate.active) {
+                       walk_done = true;
+                       goto unlock;
+               }
+
+               first_childevt = tmigr_next_groupevt(child);
+               nextexp = child->next_expiry;
+               evt = &child->groupevt;
+
+               evt->ignore = (nextexp == KTIME_MAX) ? true : false;
+       } else {
+               nextexp = data->nextexp;
+
+               first_childevt = evt = data->evt;
+
+               /*
+                * Walking the hierarchy is required in any case when a
+                * remote expiry was done before. This ensures to not lose
+                * already queued events in non active groups (see section
+                * "Required event and timerqueue update after a remote
+                * expiry" in the documentation at the top).
+                *
+                * The two call sites which are executed without a remote expiry
+                * before, are not prevented from propagating changes through
+                * the hierarchy by the return:
+                *  - When entering this path by tmigr_new_timer(), @evt->ignore
+                *    is never set.
+                *  - tmigr_inactive_up() takes care of the propagation by
+                *    itself and ignores the return value. But an immediate
+                *    return is required because nothing has to be done in this
+                *    level as the event could be ignored.
+                */
+               if (evt->ignore && !remote)
+                       return true;
+
+               raw_spin_lock(&group->lock);
+
+               childstate.state = 0;
+               groupstate.state = atomic_read(&group->migr_state);
+       }
+
+       /*
+        * If the child event is already queued in the group, remove it from the
+        * queue when the expiry time changed only or when it could be ignored.
+        */
+       if (timerqueue_node_queued(&evt->nextevt)) {
+               if ((evt->nextevt.expires == nextexp) && !evt->ignore)
+                       goto check_toplvl;
+
+               if (!timerqueue_del(&group->events, &evt->nextevt))
+                       WRITE_ONCE(group->next_expiry, KTIME_MAX);
+       }
+
+       if (evt->ignore) {
+               /*
+                * When the next child event could be ignored (nextexp is
+                * KTIME_MAX) and there was no remote timer handling before or
+                * the group is already active, there is no need to walk the
+                * hierarchy even if there is a parent group.
+                *
+                * The other way round: even if the event could be ignored, but
+                * if a remote timer handling was executed before and the group
+                * is not active, walking the hierarchy is required to not miss
+                * an enqueued timer in the non active group. The enqueued timer
+                * of the group needs to be propagated to a higher level to
+                * ensure it is handled.
+                */
+               if (!remote || groupstate.active)
+                       walk_done = true;
+       } else {
+               evt->nextevt.expires = nextexp;
+               evt->cpu = first_childevt->cpu;
+
+               if (timerqueue_add(&group->events, &evt->nextevt))
+                       WRITE_ONCE(group->next_expiry, nextexp);
+       }
+
+check_toplvl:
+       if (!group->parent && (groupstate.migrator == TMIGR_NONE)) {
+               walk_done = true;
+
+               /*
+                * Nothing to do when update was done during remote timer
+                * handling. First timer in top level group which needs to be
+                * handled when top level group is not active, is calculated
+                * directly in tmigr_handle_remote_up().
+                */
+               if (remote)
+                       goto unlock;
+
+               /*
+                * The top level group is idle and it has to be ensured the
+                * global timers are handled in time. (This could be optimized
+                * by keeping track of the last global scheduled event and only
+                * arming it on the CPU if the new event is earlier. Not sure if
+                * its worth the complexity.)
+                */
+               data->firstexp = tmigr_next_groupevt_expires(group);
+       }
+
+       trace_tmigr_update_events(child, group, childstate, groupstate,
+                                 nextexp);
+
+unlock:
+       raw_spin_unlock(&group->lock);
+
+       if (child)
+               raw_spin_unlock(&child->lock);
+
+       return walk_done;
+}
+
+static bool tmigr_new_timer_up(struct tmigr_group *group,
+                              struct tmigr_group *child,
+                              void *ptr)
+{
+       struct tmigr_walk *data = ptr;
+
+       return tmigr_update_events(group, child, data);
+}
+
+/*
+ * Returns the expiry of the next timer that needs to be handled. KTIME_MAX is
+ * returned, if an active CPU will handle all the timer migration hierarchy
+ * timers.
+ */
+static u64 tmigr_new_timer(struct tmigr_cpu *tmc, u64 nextexp)
+{
+       struct tmigr_walk data = { .nextexp = nextexp,
+                                  .firstexp = KTIME_MAX,
+                                  .evt = &tmc->cpuevt };
+
+       lockdep_assert_held(&tmc->lock);
+
+       if (tmc->remote)
+               return KTIME_MAX;
+
+       trace_tmigr_cpu_new_timer(tmc);
+
+       tmc->cpuevt.ignore = false;
+       data.remote = false;
+
+       walk_groups(&tmigr_new_timer_up, &data, tmc);
+
+       /* If there is a new first global event, make sure it is handled */
+       return data.firstexp;
+}
+
+static void tmigr_handle_remote_cpu(unsigned int cpu, u64 now,
+                                   unsigned long jif)
+{
+       struct timer_events tevt;
+       struct tmigr_walk data;
+       struct tmigr_cpu *tmc;
+
+       tmc = per_cpu_ptr(&tmigr_cpu, cpu);
+
+       raw_spin_lock_irq(&tmc->lock);
+
+       /*
+        * If the remote CPU is offline then the timers have been migrated to
+        * another CPU.
+        *
+        * If tmigr_cpu::remote is set, at the moment another CPU already
+        * expires the timers of the remote CPU.
+        *
+        * If tmigr_event::ignore is set, then the CPU returns from idle and
+        * takes care of its timers.
+        *
+        * If the next event expires in the future, then the event has been
+        * updated and there are no timers to expire right now. The CPU which
+        * updated the event takes care when hierarchy is completely
+        * idle. Otherwise the migrator does it as the event is enqueued.
+        */
+       if (!tmc->online || tmc->remote || tmc->cpuevt.ignore ||
+           now < tmc->cpuevt.nextevt.expires) {
+               raw_spin_unlock_irq(&tmc->lock);
+               return;
+       }
+
+       trace_tmigr_handle_remote_cpu(tmc);
+
+       tmc->remote = true;
+       WRITE_ONCE(tmc->wakeup, KTIME_MAX);
+
+       /* Drop the lock to allow the remote CPU to exit idle */
+       raw_spin_unlock_irq(&tmc->lock);
+
+       if (cpu != smp_processor_id())
+               timer_expire_remote(cpu);
+
+       /*
+        * Lock ordering needs to be preserved - timer_base locks before tmigr
+        * related locks (see section "Locking rules" in the documentation at
+        * the top). During fetching the next timer interrupt, also tmc->lock
+        * needs to be held. Otherwise there is a possible race window against
+        * the CPU itself when it comes out of idle, updates the first timer in
+        * the hierarchy and goes back to idle.
+        *
+        * timer base locks are dropped as fast as possible: After checking
+        * whether the remote CPU went offline in the meantime and after
+        * fetching the next remote timer interrupt. Dropping the locks as fast
+        * as possible keeps the locking region small and prevents holding
+        * several (unnecessary) locks during walking the hierarchy for updating
+        * the timerqueue and group events.
+        */
+       local_irq_disable();
+       timer_lock_remote_bases(cpu);
+       raw_spin_lock(&tmc->lock);
+
+       /*
+        * When the CPU went offline in the meantime, no hierarchy walk has to
+        * be done for updating the queued events, because the walk was
+        * already done during marking the CPU offline in the hierarchy.
+        *
+        * When the CPU is no longer idle, the CPU takes care of the timers and
+        * also of the timers in the hierarchy.
+        *
+        * (See also section "Required event and timerqueue update after a
+        * remote expiry" in the documentation at the top)
+        */
+       if (!tmc->online || !tmc->idle) {
+               timer_unlock_remote_bases(cpu);
+               goto unlock;
+       }
+
+       /* next event of CPU */
+       fetch_next_timer_interrupt_remote(jif, now, &tevt, cpu);
+       timer_unlock_remote_bases(cpu);
+
+       data.nextexp = tevt.global;
+       data.firstexp = KTIME_MAX;
+       data.evt = &tmc->cpuevt;
+       data.remote = true;
+
+       /*
+        * The update is done even when there is no 'new' global timer pending
+        * on the remote CPU (see section "Required event and timerqueue update
+        * after a remote expiry" in the documentation at the top)
+        */
+       walk_groups(&tmigr_new_timer_up, &data, tmc);
+
+unlock:
+       tmc->remote = false;
+       raw_spin_unlock_irq(&tmc->lock);
+}
+
+static bool tmigr_handle_remote_up(struct tmigr_group *group,
+                                  struct tmigr_group *child,
+                                  void *ptr)
+{
+       struct tmigr_remote_data *data = ptr;
+       struct tmigr_event *evt;
+       unsigned long jif;
+       u8 childmask;
+       u64 now;
+
+       jif = data->basej;
+       now = data->now;
+
+       childmask = data->childmask;
+
+       trace_tmigr_handle_remote(group);
+again:
+       /*
+        * Handle the group only if @childmask is the migrator or if the
+        * group has no migrator. Otherwise the group is active and is
+        * handled by its own migrator.
+        */
+       if (!tmigr_check_migrator(group, childmask))
+               return true;
+
+       raw_spin_lock_irq(&group->lock);
+
+       evt = tmigr_next_expired_groupevt(group, now);
+
+       if (evt) {
+               unsigned int remote_cpu = evt->cpu;
+
+               raw_spin_unlock_irq(&group->lock);
+
+               tmigr_handle_remote_cpu(remote_cpu, now, jif);
+
+               /* check if there is another event, that needs to be handled */
+               goto again;
+       }
+
+       /*
+        * Update of childmask for the next level and keep track of the expiry
+        * of the first event that needs to be handled (group->next_expiry was
+        * updated by tmigr_next_expired_groupevt(), next was set by
+        * tmigr_handle_remote_cpu()).
+        */
+       data->childmask = group->childmask;
+       data->firstexp = group->next_expiry;
+
+       raw_spin_unlock_irq(&group->lock);
+
+       return false;
+}
+
+/**
+ * tmigr_handle_remote() - Handle global timers of remote idle CPUs
+ *
+ * Called from the timer soft interrupt with interrupts enabled.
+ */
+void tmigr_handle_remote(void)
+{
+       struct tmigr_cpu *tmc = this_cpu_ptr(&tmigr_cpu);
+       struct tmigr_remote_data data;
+
+       if (tmigr_is_not_available(tmc))
+               return;
+
+       data.childmask = tmc->childmask;
+       data.firstexp = KTIME_MAX;
+
+       /*
+        * NOTE: This is a doubled check because the migrator test will be done
+        * in tmigr_handle_remote_up() anyway. Keep this check to speed up the
+        * return when nothing has to be done.
+        */
+       if (!tmigr_check_migrator(tmc->tmgroup, tmc->childmask))
+               return;
+
+       data.now = get_jiffies_update(&data.basej);
+
+       /*
+        * Update @tmc->wakeup only at the end and do not reset @tmc->wakeup to
+        * KTIME_MAX. Even if tmc->lock is not held during the whole remote
+        * handling, tmc->wakeup is fine to be stale as it is called in
+        * interrupt context and tick_nohz_next_event() is executed in interrupt
+        * exit path only after processing the last pending interrupt.
+        */
+
+       __walk_groups(&tmigr_handle_remote_up, &data, tmc);
+
+       raw_spin_lock_irq(&tmc->lock);
+       WRITE_ONCE(tmc->wakeup, data.firstexp);
+       raw_spin_unlock_irq(&tmc->lock);
+}
+
+static bool tmigr_requires_handle_remote_up(struct tmigr_group *group,
+                                           struct tmigr_group *child,
+                                           void *ptr)
+{
+       struct tmigr_remote_data *data = ptr;
+       u8 childmask;
+
+       childmask = data->childmask;
+
+       /*
+        * Handle the group only if the child is the migrator or if the group
+        * has no migrator. Otherwise the group is active and is handled by its
+        * own migrator.
+        */
+       if (!tmigr_check_migrator(group, childmask))
+               return true;
+
+       /*
+        * When there is a parent group and the CPU which triggered the
+        * hierarchy walk is not active, proceed the walk to reach the top level
+        * group before reading the next_expiry value.
+        */
+       if (group->parent && !data->tmc_active)
+               goto out;
+
+       /*
+        * The lock is required on 32bit architectures to read the variable
+        * consistently with a concurrent writer. On 64bit the lock is not
+        * required because the read operation is not split and so it is always
+        * consistent.
+        */
+       if (IS_ENABLED(CONFIG_64BIT)) {
+               data->firstexp = READ_ONCE(group->next_expiry);
+               if (data->now >= data->firstexp) {
+                       data->check = true;
+                       return true;
+               }
+       } else {
+               raw_spin_lock(&group->lock);
+               data->firstexp = group->next_expiry;
+               if (data->now >= group->next_expiry) {
+                       data->check = true;
+                       raw_spin_unlock(&group->lock);
+                       return true;
+               }
+               raw_spin_unlock(&group->lock);
+       }
+
+out:
+       /* Update of childmask for the next level */
+       data->childmask = group->childmask;
+       return false;
+}
+
+/**
+ * tmigr_requires_handle_remote() - Check the need of remote timer handling
+ *
+ * Must be called with interrupts disabled.
+ */
+bool tmigr_requires_handle_remote(void)
+{
+       struct tmigr_cpu *tmc = this_cpu_ptr(&tmigr_cpu);
+       struct tmigr_remote_data data;
+       unsigned long jif;
+       bool ret = false;
+
+       if (tmigr_is_not_available(tmc))
+               return ret;
+
+       data.now = get_jiffies_update(&jif);
+       data.childmask = tmc->childmask;
+       data.firstexp = KTIME_MAX;
+       data.tmc_active = !tmc->idle;
+       data.check = false;
+
+       /*
+        * If the CPU is active, walk the hierarchy to check whether a remote
+        * expiry is required.
+        *
+        * Check is done lockless as interrupts are disabled and @tmc->idle is
+        * set only by the local CPU.
+        */
+       if (!tmc->idle) {
+               __walk_groups(&tmigr_requires_handle_remote_up, &data, tmc);
+
+               return data.check;
+       }
+
+       /*
+        * When the CPU is idle, compare @tmc->wakeup with @data.now. The lock
+        * is required on 32bit architectures to read the variable consistently
+        * with a concurrent writer. On 64bit the lock is not required because
+        * the read operation is not split and so it is always consistent.
+        */
+       if (IS_ENABLED(CONFIG_64BIT)) {
+               if (data.now >= READ_ONCE(tmc->wakeup))
+                       return true;
+       } else {
+               raw_spin_lock(&tmc->lock);
+               if (data.now >= tmc->wakeup)
+                       ret = true;
+               raw_spin_unlock(&tmc->lock);
+       }
+
+       return ret;
+}
+
+/**
+ * tmigr_cpu_new_timer() - enqueue next global timer into hierarchy (idle tmc)
+ * @nextexp:   Next expiry of global timer (or KTIME_MAX if not)
+ *
+ * The CPU is already deactivated in the timer migration
+ * hierarchy. tick_nohz_get_sleep_length() calls tick_nohz_next_event()
+ * and thereby the timer idle path is executed once more. @tmc->wakeup
+ * holds the first timer, when the timer migration hierarchy is
+ * completely idle.
+ *
+ * Returns the first timer that needs to be handled by this CPU or KTIME_MAX if
+ * nothing needs to be done.
+ */
+u64 tmigr_cpu_new_timer(u64 nextexp)
+{
+       struct tmigr_cpu *tmc = this_cpu_ptr(&tmigr_cpu);
+       u64 ret;
+
+       if (tmigr_is_not_available(tmc))
+               return nextexp;
+
+       raw_spin_lock(&tmc->lock);
+
+       ret = READ_ONCE(tmc->wakeup);
+       if (nextexp != KTIME_MAX) {
+               if (nextexp != tmc->cpuevt.nextevt.expires ||
+                   tmc->cpuevt.ignore) {
+                       ret = tmigr_new_timer(tmc, nextexp);
+               }
+       }
+       /*
+        * Make sure the reevaluation of timers in idle path will not miss an
+        * event.
+        */
+       WRITE_ONCE(tmc->wakeup, ret);
+
+       trace_tmigr_cpu_new_timer_idle(tmc, nextexp);
+       raw_spin_unlock(&tmc->lock);
+       return ret;
+}
+
+static bool tmigr_inactive_up(struct tmigr_group *group,
+                             struct tmigr_group *child,
+                             void *ptr)
+{
+       union tmigr_state curstate, newstate, childstate;
+       struct tmigr_walk *data = ptr;
+       bool walk_done;
+       u8 childmask;
+
+       childmask = data->childmask;
+       childstate.state = 0;
+
+       /*
+        * The memory barrier is paired with the cmpxchg() in tmigr_active_up()
+        * to make sure the updates of child and group states are ordered. The
+        * ordering is mandatory, as the group state change depends on the child
+        * state.
+        */
+       curstate.state = atomic_read_acquire(&group->migr_state);
+
+       for (;;) {
+               if (child)
+                       childstate.state = atomic_read(&child->migr_state);
+
+               newstate = curstate;
+               walk_done = true;
+
+               /* Reset active bit when the child is no longer active */
+               if (!childstate.active)
+                       newstate.active &= ~childmask;
+
+               if (newstate.migrator == childmask) {
+                       /*
+                        * Find a new migrator for the group, because the child
+                        * group is idle!
+                        */
+                       if (!childstate.active) {
+                               unsigned long new_migr_bit, active = newstate.active;
+
+                               new_migr_bit = find_first_bit(&active, BIT_CNT);
+
+                               if (new_migr_bit != BIT_CNT) {
+                                       newstate.migrator = BIT(new_migr_bit);
+                               } else {
+                                       newstate.migrator = TMIGR_NONE;
+
+                                       /* Changes need to be propagated */
+                                       walk_done = false;
+                               }
+                       }
+               }
+
+               newstate.seq++;
+
+               WARN_ON_ONCE((newstate.migrator != TMIGR_NONE) && !(newstate.active));
+
+               if (atomic_try_cmpxchg(&group->migr_state, &curstate.state,
+                                      newstate.state))
+                       break;
+
+               /*
+                * The memory barrier is paired with the cmpxchg() in
+                * tmigr_active_up() to make sure the updates of child and group
+                * states are ordered. It is required only when the above
+                * try_cmpxchg() fails.
+                */
+               smp_mb__after_atomic();
+       }
+
+       data->remote = false;
+
+       /* Event Handling */
+       tmigr_update_events(group, child, data);
+
+       if (group->parent && (walk_done == false))
+               data->childmask = group->childmask;
+
+       /*
+        * data->firstexp was set by tmigr_update_events() and contains the
+        * expiry of the first global event which needs to be handled. It
+        * differs from KTIME_MAX if:
+        * - group is the top level group and
+        * - group is idle (which means CPU was the last active CPU in the
+        *   hierarchy) and
+        * - there is a pending event in the hierarchy
+        */
+       WARN_ON_ONCE(data->firstexp != KTIME_MAX && group->parent);
+
+       trace_tmigr_group_set_cpu_inactive(group, newstate, childmask);
+
+       return walk_done;
+}
+
+static u64 __tmigr_cpu_deactivate(struct tmigr_cpu *tmc, u64 nextexp)
+{
+       struct tmigr_walk data = { .nextexp = nextexp,
+                                  .firstexp = KTIME_MAX,
+                                  .evt = &tmc->cpuevt,
+                                  .childmask = tmc->childmask };
+
+       /*
+        * If nextexp is KTIME_MAX, the CPU event will be ignored because the
+        * local timer expires before the global timer, no global timer is set
+        * or CPU goes offline.
+        */
+       if (nextexp != KTIME_MAX)
+               tmc->cpuevt.ignore = false;
+
+       walk_groups(&tmigr_inactive_up, &data, tmc);
+       return data.firstexp;
+}
+
+/**
+ * tmigr_cpu_deactivate() - Put current CPU into inactive state
+ * @nextexp:   The next global timer expiry of the current CPU
+ *
+ * Must be called with interrupts disabled.
+ *
+ * Return: the next event expiry of the current CPU or the next event expiry
+ * from the hierarchy if this CPU is the top level migrator or the hierarchy is
+ * completely idle.
+ */
+u64 tmigr_cpu_deactivate(u64 nextexp)
+{
+       struct tmigr_cpu *tmc = this_cpu_ptr(&tmigr_cpu);
+       u64 ret;
+
+       if (tmigr_is_not_available(tmc))
+               return nextexp;
+
+       raw_spin_lock(&tmc->lock);
+
+       ret = __tmigr_cpu_deactivate(tmc, nextexp);
+
+       tmc->idle = true;
+
+       /*
+        * Make sure the reevaluation of timers in idle path will not miss an
+        * event.
+        */
+       WRITE_ONCE(tmc->wakeup, ret);
+
+       trace_tmigr_cpu_idle(tmc, nextexp);
+       raw_spin_unlock(&tmc->lock);
+       return ret;
+}
+
+/**
+ * tmigr_quick_check() - Quick forecast of next tmigr event when CPU wants to
+ *                      go idle
+ * @nextevt:   The next global timer expiry of the current CPU
+ *
+ * Return:
+ * * KTIME_MAX         - when it is probable that nothing has to be done (not
+ *                       the only one in the level 0 group; and if it is the
+ *                       only one in level 0 group, but there are more than a
+ *                       single group active on the way to top level)
+ * * nextevt           - when CPU is offline and has to handle timer on his own
+ *                       or when on the way to top in every group only a single
+ *                       child is active but @nextevt is before the lowest
+ *                       next_expiry encountered while walking up to top level.
+ * * next_expiry       - value of lowest expiry encountered while walking groups
+ *                       if only a single child is active on each and @nextevt
+ *                       is after this lowest expiry.
+ */
+u64 tmigr_quick_check(u64 nextevt)
+{
+       struct tmigr_cpu *tmc = this_cpu_ptr(&tmigr_cpu);
+       struct tmigr_group *group = tmc->tmgroup;
+
+       if (tmigr_is_not_available(tmc))
+               return nextevt;
+
+       if (WARN_ON_ONCE(tmc->idle))
+               return nextevt;
+
+       if (!tmigr_check_migrator_and_lonely(tmc->tmgroup, tmc->childmask))
+               return KTIME_MAX;
+
+       do {
+               if (!tmigr_check_lonely(group)) {
+                       return KTIME_MAX;
+               } else {
+                       /*
+                        * Since current CPU is active, events may not be sorted
+                        * from bottom to the top because the CPU's event is ignored
+                        * up to the top and its sibling's events not propagated upwards.
+                        * Thus keep track of the lowest observed expiry.
+                        */
+                       nextevt = min_t(u64, nextevt, READ_ONCE(group->next_expiry));
+                       if (!group->parent)
+                               return nextevt;
+               }
+               group = group->parent;
+       } while (group);
+
+       return KTIME_MAX;
+}
+
+static void tmigr_init_group(struct tmigr_group *group, unsigned int lvl,
+                            int node)
+{
+       union tmigr_state s;
+
+       raw_spin_lock_init(&group->lock);
+
+       group->level = lvl;
+       group->numa_node = lvl < tmigr_crossnode_level ? node : NUMA_NO_NODE;
+
+       group->num_children = 0;
+
+       s.migrator = TMIGR_NONE;
+       s.active = 0;
+       s.seq = 0;
+       atomic_set(&group->migr_state, s.state);
+
+       timerqueue_init_head(&group->events);
+       timerqueue_init(&group->groupevt.nextevt);
+       group->groupevt.nextevt.expires = KTIME_MAX;
+       WRITE_ONCE(group->next_expiry, KTIME_MAX);
+       group->groupevt.ignore = true;
+}
+
+static struct tmigr_group *tmigr_get_group(unsigned int cpu, int node,
+                                          unsigned int lvl)
+{
+       struct tmigr_group *tmp, *group = NULL;
+
+       lockdep_assert_held(&tmigr_mutex);
+
+       /* Try to attach to an existing group first */
+       list_for_each_entry(tmp, &tmigr_level_list[lvl], list) {
+               /*
+                * If @lvl is below the cross NUMA node level, check whether
+                * this group belongs to the same NUMA node.
+                */
+               if (lvl < tmigr_crossnode_level && tmp->numa_node != node)
+                       continue;
+
+               /* Capacity left? */
+               if (tmp->num_children >= TMIGR_CHILDREN_PER_GROUP)
+                       continue;
+
+               /*
+                * TODO: A possible further improvement: Make sure that all CPU
+                * siblings end up in the same group of the lowest level of the
+                * hierarchy. Rely on the topology sibling mask would be a
+                * reasonable solution.
+                */
+
+               group = tmp;
+               break;
+       }
+
+       if (group)
+               return group;
+
+       /* Allocate and set up a new group */
+       group = kzalloc_node(sizeof(*group), GFP_KERNEL, node);
+       if (!group)
+               return ERR_PTR(-ENOMEM);
+
+       tmigr_init_group(group, lvl, node);
+
+       /* Setup successful. Add it to the hierarchy */
+       list_add(&group->list, &tmigr_level_list[lvl]);
+       trace_tmigr_group_set(group);
+       return group;
+}
+
+static void tmigr_connect_child_parent(struct tmigr_group *child,
+                                      struct tmigr_group *parent)
+{
+       union tmigr_state childstate;
+
+       raw_spin_lock_irq(&child->lock);
+       raw_spin_lock_nested(&parent->lock, SINGLE_DEPTH_NESTING);
+
+       child->parent = parent;
+       child->childmask = BIT(parent->num_children++);
+
+       raw_spin_unlock(&parent->lock);
+       raw_spin_unlock_irq(&child->lock);
+
+       trace_tmigr_connect_child_parent(child);
+
+       /*
+        * To prevent inconsistent states, active children need to be active in
+        * the new parent as well. Inactive children are already marked inactive
+        * in the parent group:
+        *
+        * * When new groups were created by tmigr_setup_groups() starting from
+        *   the lowest level (and not higher then one level below the current
+        *   top level), then they are not active. They will be set active when
+        *   the new online CPU comes active.
+        *
+        * * But if a new group above the current top level is required, it is
+        *   mandatory to propagate the active state of the already existing
+        *   child to the new parent. So tmigr_connect_child_parent() is
+        *   executed with the formerly top level group (child) and the newly
+        *   created group (parent).
+        */
+       childstate.state = atomic_read(&child->migr_state);
+       if (childstate.migrator != TMIGR_NONE) {
+               struct tmigr_walk data;
+
+               data.childmask = child->childmask;
+
+               /*
+                * There is only one new level per time. When connecting the
+                * child and the parent and set the child active when the parent
+                * is inactive, the parent needs to be the uppermost
+                * level. Otherwise there went something wrong!
+                */
+               WARN_ON(!tmigr_active_up(parent, child, &data) && parent->parent);
+       }
+}
+
+static int tmigr_setup_groups(unsigned int cpu, unsigned int node)
+{
+       struct tmigr_group *group, *child, **stack;
+       int top = 0, err = 0, i = 0;
+       struct list_head *lvllist;
+
+       stack = kcalloc(tmigr_hierarchy_levels, sizeof(*stack), GFP_KERNEL);
+       if (!stack)
+               return -ENOMEM;
+
+       do {
+               group = tmigr_get_group(cpu, node, i);
+               if (IS_ERR(group)) {
+                       err = PTR_ERR(group);
+                       break;
+               }
+
+               top = i;
+               stack[i++] = group;
+
+               /*
+                * When booting only less CPUs of a system than CPUs are
+                * available, not all calculated hierarchy levels are required.
+                *
+                * The loop is aborted as soon as the highest level, which might
+                * be different from tmigr_hierarchy_levels, contains only a
+                * single group.
+                */
+               if (group->parent || i == tmigr_hierarchy_levels ||
+                   (list_empty(&tmigr_level_list[i]) &&
+                    list_is_singular(&tmigr_level_list[i - 1])))
+                       break;
+
+       } while (i < tmigr_hierarchy_levels);
+
+       do {
+               group = stack[--i];
+
+               if (err < 0) {
+                       list_del(&group->list);
+                       kfree(group);
+                       continue;
+               }
+
+               WARN_ON_ONCE(i != group->level);
+
+               /*
+                * Update tmc -> group / child -> group connection
+                */
+               if (i == 0) {
+                       struct tmigr_cpu *tmc = this_cpu_ptr(&tmigr_cpu);
+
+                       raw_spin_lock_irq(&group->lock);
+
+                       tmc->tmgroup = group;
+                       tmc->childmask = BIT(group->num_children++);
+
+                       raw_spin_unlock_irq(&group->lock);
+
+                       trace_tmigr_connect_cpu_parent(tmc);
+
+                       /* There are no children that need to be connected */
+                       continue;
+               } else {
+                       child = stack[i - 1];
+                       tmigr_connect_child_parent(child, group);
+               }
+
+               /* check if uppermost level was newly created */
+               if (top != i)
+                       continue;
+
+               WARN_ON_ONCE(top == 0);
+
+               lvllist = &tmigr_level_list[top];
+               if (group->num_children == 1 && list_is_singular(lvllist)) {
+                       lvllist = &tmigr_level_list[top - 1];
+                       list_for_each_entry(child, lvllist, list) {
+                               if (child->parent)
+                                       continue;
+
+                               tmigr_connect_child_parent(child, group);
+                       }
+               }
+       } while (i > 0);
+
+       kfree(stack);
+
+       return err;
+}
+
+static int tmigr_add_cpu(unsigned int cpu)
+{
+       int node = cpu_to_node(cpu);
+       int ret;
+
+       mutex_lock(&tmigr_mutex);
+       ret = tmigr_setup_groups(cpu, node);
+       mutex_unlock(&tmigr_mutex);
+
+       return ret;
+}
+
+static int tmigr_cpu_online(unsigned int cpu)
+{
+       struct tmigr_cpu *tmc = this_cpu_ptr(&tmigr_cpu);
+       int ret;
+
+       /* First online attempt? Initialize CPU data */
+       if (!tmc->tmgroup) {
+               raw_spin_lock_init(&tmc->lock);
+
+               ret = tmigr_add_cpu(cpu);
+               if (ret < 0)
+                       return ret;
+
+               if (tmc->childmask == 0)
+                       return -EINVAL;
+
+               timerqueue_init(&tmc->cpuevt.nextevt);
+               tmc->cpuevt.nextevt.expires = KTIME_MAX;
+               tmc->cpuevt.ignore = true;
+               tmc->cpuevt.cpu = cpu;
+
+               tmc->remote = false;
+               WRITE_ONCE(tmc->wakeup, KTIME_MAX);
+       }
+       raw_spin_lock_irq(&tmc->lock);
+       trace_tmigr_cpu_online(tmc);
+       tmc->idle = timer_base_is_idle();
+       if (!tmc->idle)
+               __tmigr_cpu_activate(tmc);
+       tmc->online = true;
+       raw_spin_unlock_irq(&tmc->lock);
+       return 0;
+}
+
+/*
+ * tmigr_trigger_active() - trigger a CPU to become active again
+ *
+ * This function is executed on a CPU which is part of cpu_online_mask, when the
+ * last active CPU in the hierarchy is offlining. With this, it is ensured that
+ * the other CPU is active and takes over the migrator duty.
+ */
+static long tmigr_trigger_active(void *unused)
+{
+       struct tmigr_cpu *tmc = this_cpu_ptr(&tmigr_cpu);
+
+       WARN_ON_ONCE(!tmc->online || tmc->idle);
+
+       return 0;
+}
+
+static int tmigr_cpu_offline(unsigned int cpu)
+{
+       struct tmigr_cpu *tmc = this_cpu_ptr(&tmigr_cpu);
+       int migrator;
+       u64 firstexp;
+
+       raw_spin_lock_irq(&tmc->lock);
+       tmc->online = false;
+       WRITE_ONCE(tmc->wakeup, KTIME_MAX);
+
+       /*
+        * CPU has to handle the local events on his own, when on the way to
+        * offline; Therefore nextevt value is set to KTIME_MAX
+        */
+       firstexp = __tmigr_cpu_deactivate(tmc, KTIME_MAX);
+       trace_tmigr_cpu_offline(tmc);
+       raw_spin_unlock_irq(&tmc->lock);
+
+       if (firstexp != KTIME_MAX) {
+               migrator = cpumask_any_but(cpu_online_mask, cpu);
+               work_on_cpu(migrator, tmigr_trigger_active, NULL);
+       }
+
+       return 0;
+}
+
+static int __init tmigr_init(void)
+{
+       unsigned int cpulvl, nodelvl, cpus_per_node, i;
+       unsigned int nnodes = num_possible_nodes();
+       unsigned int ncpus = num_possible_cpus();
+       int ret = -ENOMEM;
+
+       BUILD_BUG_ON_NOT_POWER_OF_2(TMIGR_CHILDREN_PER_GROUP);
+
+       /* Nothing to do if running on UP */
+       if (ncpus == 1)
+               return 0;
+
+       /*
+        * Calculate the required hierarchy levels. Unfortunately there is no
+        * reliable information available, unless all possible CPUs have been
+        * brought up and all NUMA nodes are populated.
+        *
+        * Estimate the number of levels with the number of possible nodes and
+        * the number of possible CPUs. Assume CPUs are spread evenly across
+        * nodes. We cannot rely on cpumask_of_node() because it only works for
+        * online CPUs.
+        */
+       cpus_per_node = DIV_ROUND_UP(ncpus, nnodes);
+
+       /* Calc the hierarchy levels required to hold the CPUs of a node */
+       cpulvl = DIV_ROUND_UP(order_base_2(cpus_per_node),
+                             ilog2(TMIGR_CHILDREN_PER_GROUP));
+
+       /* Calculate the extra levels to connect all nodes */
+       nodelvl = DIV_ROUND_UP(order_base_2(nnodes),
+                              ilog2(TMIGR_CHILDREN_PER_GROUP));
+
+       tmigr_hierarchy_levels = cpulvl + nodelvl;
+
+       /*
+        * If a NUMA node spawns more than one CPU level group then the next
+        * level(s) of the hierarchy contains groups which handle all CPU groups
+        * of the same NUMA node. The level above goes across NUMA nodes. Store
+        * this information for the setup code to decide in which level node
+        * matching is no longer required.
+        */
+       tmigr_crossnode_level = cpulvl;
+
+       tmigr_level_list = kcalloc(tmigr_hierarchy_levels, sizeof(struct list_head), GFP_KERNEL);
+       if (!tmigr_level_list)
+               goto err;
+
+       for (i = 0; i < tmigr_hierarchy_levels; i++)
+               INIT_LIST_HEAD(&tmigr_level_list[i]);
+
+       pr_info("Timer migration: %d hierarchy levels; %d children per group;"
+               " %d crossnode level\n",
+               tmigr_hierarchy_levels, TMIGR_CHILDREN_PER_GROUP,
+               tmigr_crossnode_level);
+
+       ret = cpuhp_setup_state(CPUHP_AP_TMIGR_ONLINE, "tmigr:online",
+                               tmigr_cpu_online, tmigr_cpu_offline);
+       if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       pr_err("Timer migration setup failed\n");
+       return ret;
+}
+late_initcall(tmigr_init);
diff --git a/kernel/time/timer_migration.h b/kernel/time/timer_migration.h
new file mode 100644 (file)
index 0000000..6c37d94
--- /dev/null
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _KERNEL_TIME_MIGRATION_H
+#define _KERNEL_TIME_MIGRATION_H
+
+/* Per group capacity. Must be a power of 2! */
+#define TMIGR_CHILDREN_PER_GROUP 8
+
+/**
+ * struct tmigr_event - a timer event associated to a CPU
+ * @nextevt:   The node to enqueue an event in the parent group queue
+ * @cpu:       The CPU to which this event belongs
+ * @ignore:    Hint whether the event could be ignored; it is set when
+ *             CPU or group is active;
+ */
+struct tmigr_event {
+       struct timerqueue_node  nextevt;
+       unsigned int            cpu;
+       bool                    ignore;
+};
+
+/**
+ * struct tmigr_group - timer migration hierarchy group
+ * @lock:              Lock protecting the event information and group hierarchy
+ *                     information during setup
+ * @parent:            Pointer to the parent group
+ * @groupevt:          Next event of the group which is only used when the
+ *                     group is !active. The group event is then queued into
+ *                     the parent timer queue.
+ *                     Ignore bit of @groupevt is set when the group is active.
+ * @next_expiry:       Base monotonic expiry time of the next event of the
+ *                     group; It is used for the racy lockless check whether a
+ *                     remote expiry is required; it is always reliable
+ * @events:            Timer queue for child events queued in the group
+ * @migr_state:                State of the group (see union tmigr_state)
+ * @level:             Hierarchy level of the group; Required during setup
+ * @numa_node:         Required for setup only to make sure CPU and low level
+ *                     group information is NUMA local. It is set to NUMA node
+ *                     as long as the group level is per NUMA node (level <
+ *                     tmigr_crossnode_level); otherwise it is set to
+ *                     NUMA_NO_NODE
+ * @num_children:      Counter of group children to make sure the group is only
+ *                     filled with TMIGR_CHILDREN_PER_GROUP; Required for setup
+ *                     only
+ * @childmask:         childmask of the group in the parent group; is set
+ *                     during setup and will never change; can be read
+ *                     lockless
+ * @list:              List head that is added to the per level
+ *                     tmigr_level_list; is required during setup when a
+ *                     new group needs to be connected to the existing
+ *                     hierarchy groups
+ */
+struct tmigr_group {
+       raw_spinlock_t          lock;
+       struct tmigr_group      *parent;
+       struct tmigr_event      groupevt;
+       u64                     next_expiry;
+       struct timerqueue_head  events;
+       atomic_t                migr_state;
+       unsigned int            level;
+       int                     numa_node;
+       unsigned int            num_children;
+       u8                      childmask;
+       struct list_head        list;
+};
+
+/**
+ * struct tmigr_cpu - timer migration per CPU group
+ * @lock:              Lock protecting the tmigr_cpu group information
+ * @online:            Indicates whether the CPU is online; In deactivate path
+ *                     it is required to know whether the migrator in the top
+ *                     level group is to be set offline, while a timer is
+ *                     pending. Then another online CPU needs to be notified to
+ *                     take over the migrator role. Furthermore the information
+ *                     is required in CPU hotplug path as the CPU is able to go
+ *                     idle before the timer migration hierarchy hotplug AP is
+ *                     reached. During this phase, the CPU has to handle the
+ *                     global timers on its own and must not act as a migrator.
+ * @idle:              Indicates whether the CPU is idle in the timer migration
+ *                     hierarchy
+ * @remote:            Is set when timers of the CPU are expired remotely
+ * @tmgroup:           Pointer to the parent group
+ * @childmask:         childmask of tmigr_cpu in the parent group
+ * @wakeup:            Stores the first timer when the timer migration
+ *                     hierarchy is completely idle and remote expiry was done;
+ *                     is returned to timer code in the idle path and is only
+ *                     used in idle path.
+ * @cpuevt:            CPU event which could be enqueued into the parent group
+ */
+struct tmigr_cpu {
+       raw_spinlock_t          lock;
+       bool                    online;
+       bool                    idle;
+       bool                    remote;
+       struct tmigr_group      *tmgroup;
+       u8                      childmask;
+       u64                     wakeup;
+       struct tmigr_event      cpuevt;
+};
+
+/**
+ * union tmigr_state - state of tmigr_group
+ * @state:     Combined version of the state - only used for atomic
+ *             read/cmpxchg function
+ * @struct:    Split version of the state - only use the struct members to
+ *             update information to stay independent of endianness
+ */
+union tmigr_state {
+       u32 state;
+       /**
+        * struct - split state of tmigr_group
+        * @active:     Contains each childmask bit of the active children
+        * @migrator:   Contains childmask of the child which is migrator
+        * @seq:        Sequence counter needs to be increased when an update
+        *              to the tmigr_state is done. It prevents a race when
+        *              updates in the child groups are propagated in changed
+        *              order. Detailed information about the scenario is
+        *              given in the documentation at the begin of
+        *              timer_migration.c.
+        */
+       struct {
+               u8      active;
+               u8      migrator;
+               u16     seq;
+       } __packed;
+};
+
+#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
+extern void tmigr_handle_remote(void);
+extern bool tmigr_requires_handle_remote(void);
+extern void tmigr_cpu_activate(void);
+extern u64 tmigr_cpu_deactivate(u64 nextevt);
+extern u64 tmigr_cpu_new_timer(u64 nextevt);
+extern u64 tmigr_quick_check(u64 nextevt);
+#else
+static inline void tmigr_handle_remote(void) { }
+static inline bool tmigr_requires_handle_remote(void) { return false; }
+static inline void tmigr_cpu_activate(void) { }
+#endif
+
+#endif
index 6cd2a4e3afb8fb6045dbf27543a67147dea20900..9ff0182458408438ddc5d7c720d866d0adc02dfd 100644 (file)
@@ -189,9 +189,6 @@ static int fprobe_init_rethook(struct fprobe *fp, int num)
 {
        int size;
 
-       if (num <= 0)
-               return -EINVAL;
-
        if (!fp->exit_handler) {
                fp->rethook = NULL;
                return 0;
@@ -199,15 +196,16 @@ static int fprobe_init_rethook(struct fprobe *fp, int num)
 
        /* Initialize rethook if needed */
        if (fp->nr_maxactive)
-               size = fp->nr_maxactive;
+               num = fp->nr_maxactive;
        else
-               size = num * num_possible_cpus() * 2;
-       if (size <= 0)
+               num *= num_possible_cpus() * 2;
+       if (num <= 0)
                return -EINVAL;
 
+       size = sizeof(struct fprobe_rethook_node) + fp->entry_data_size;
+
        /* Initialize rethook */
-       fp->rethook = rethook_alloc((void *)fp, fprobe_exit_handler,
-                               sizeof(struct fprobe_rethook_node), size);
+       fp->rethook = rethook_alloc((void *)fp, fprobe_exit_handler, size, num);
        if (IS_ERR(fp->rethook))
                return PTR_ERR(fp->rethook);
 
index c060d5b479102dc1a4ddfb4ae283f626fc192ada..83ba342aef31f7d919f4c24a73d2c4cea76be137 100644 (file)
@@ -5331,7 +5331,7 @@ static int register_ftrace_function_nolock(struct ftrace_ops *ops);
  * not support ftrace_regs_caller but direct_call, use SAVE_ARGS so that it
  * jumps from ftrace_caller for multiple ftrace_ops.
  */
-#ifndef HAVE_DYNAMIC_FTRACE_WITH_REGS
+#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS
 #define MULTI_FLAGS (FTRACE_OPS_FL_DIRECT | FTRACE_OPS_FL_SAVE_ARGS)
 #else
 #define MULTI_FLAGS (FTRACE_OPS_FL_DIRECT | FTRACE_OPS_FL_SAVE_REGS)
index fd4bfe3ecf014f6b3c83f9a7fa043b7df44dac32..3103a484182eb9ded0489922a89d26f6b348593d 100644 (file)
@@ -384,7 +384,6 @@ struct rb_irq_work {
        struct irq_work                 work;
        wait_queue_head_t               waiters;
        wait_queue_head_t               full_waiters;
-       long                            wait_index;
        bool                            waiters_pending;
        bool                            full_waiters_pending;
        bool                            wakeup_full;
@@ -756,8 +755,19 @@ static void rb_wake_up_waiters(struct irq_work *work)
 
        wake_up_all(&rbwork->waiters);
        if (rbwork->full_waiters_pending || rbwork->wakeup_full) {
+               /* Only cpu_buffer sets the above flags */
+               struct ring_buffer_per_cpu *cpu_buffer =
+                       container_of(rbwork, struct ring_buffer_per_cpu, irq_work);
+
+               /* Called from interrupt context */
+               raw_spin_lock(&cpu_buffer->reader_lock);
                rbwork->wakeup_full = false;
                rbwork->full_waiters_pending = false;
+
+               /* Waking up all waiters, they will reset the shortest full */
+               cpu_buffer->shortest_full = 0;
+               raw_spin_unlock(&cpu_buffer->reader_lock);
+
                wake_up_all(&rbwork->full_waiters);
        }
 }
@@ -798,14 +808,40 @@ void ring_buffer_wake_waiters(struct trace_buffer *buffer, int cpu)
                rbwork = &cpu_buffer->irq_work;
        }
 
-       rbwork->wait_index++;
-       /* make sure the waiters see the new index */
-       smp_wmb();
-
        /* This can be called in any context */
        irq_work_queue(&rbwork->work);
 }
 
+static bool rb_watermark_hit(struct trace_buffer *buffer, int cpu, int full)
+{
+       struct ring_buffer_per_cpu *cpu_buffer;
+       bool ret = false;
+
+       /* Reads of all CPUs always waits for any data */
+       if (cpu == RING_BUFFER_ALL_CPUS)
+               return !ring_buffer_empty(buffer);
+
+       cpu_buffer = buffer->buffers[cpu];
+
+       if (!ring_buffer_empty_cpu(buffer, cpu)) {
+               unsigned long flags;
+               bool pagebusy;
+
+               if (!full)
+                       return true;
+
+               raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
+               pagebusy = cpu_buffer->reader_page == cpu_buffer->commit_page;
+               ret = !pagebusy && full_hit(buffer, cpu, full);
+
+               if (!cpu_buffer->shortest_full ||
+                   cpu_buffer->shortest_full > full)
+                       cpu_buffer->shortest_full = full;
+               raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
+       }
+       return ret;
+}
+
 /**
  * ring_buffer_wait - wait for input to the ring buffer
  * @buffer: buffer to wait on
@@ -821,7 +857,6 @@ int ring_buffer_wait(struct trace_buffer *buffer, int cpu, int full)
        struct ring_buffer_per_cpu *cpu_buffer;
        DEFINE_WAIT(wait);
        struct rb_irq_work *work;
-       long wait_index;
        int ret = 0;
 
        /*
@@ -840,81 +875,54 @@ int ring_buffer_wait(struct trace_buffer *buffer, int cpu, int full)
                work = &cpu_buffer->irq_work;
        }
 
-       wait_index = READ_ONCE(work->wait_index);
-
-       while (true) {
-               if (full)
-                       prepare_to_wait(&work->full_waiters, &wait, TASK_INTERRUPTIBLE);
-               else
-                       prepare_to_wait(&work->waiters, &wait, TASK_INTERRUPTIBLE);
-
-               /*
-                * The events can happen in critical sections where
-                * checking a work queue can cause deadlocks.
-                * After adding a task to the queue, this flag is set
-                * only to notify events to try to wake up the queue
-                * using irq_work.
-                *
-                * We don't clear it even if the buffer is no longer
-                * empty. The flag only causes the next event to run
-                * irq_work to do the work queue wake up. The worse
-                * that can happen if we race with !trace_empty() is that
-                * an event will cause an irq_work to try to wake up
-                * an empty queue.
-                *
-                * There's no reason to protect this flag either, as
-                * the work queue and irq_work logic will do the necessary
-                * synchronization for the wake ups. The only thing
-                * that is necessary is that the wake up happens after
-                * a task has been queued. It's OK for spurious wake ups.
-                */
-               if (full)
-                       work->full_waiters_pending = true;
-               else
-                       work->waiters_pending = true;
-
-               if (signal_pending(current)) {
-                       ret = -EINTR;
-                       break;
-               }
-
-               if (cpu == RING_BUFFER_ALL_CPUS && !ring_buffer_empty(buffer))
-                       break;
-
-               if (cpu != RING_BUFFER_ALL_CPUS &&
-                   !ring_buffer_empty_cpu(buffer, cpu)) {
-                       unsigned long flags;
-                       bool pagebusy;
-                       bool done;
-
-                       if (!full)
-                               break;
-
-                       raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
-                       pagebusy = cpu_buffer->reader_page == cpu_buffer->commit_page;
-                       done = !pagebusy && full_hit(buffer, cpu, full);
+       if (full)
+               prepare_to_wait(&work->full_waiters, &wait, TASK_INTERRUPTIBLE);
+       else
+               prepare_to_wait(&work->waiters, &wait, TASK_INTERRUPTIBLE);
 
-                       if (!cpu_buffer->shortest_full ||
-                           cpu_buffer->shortest_full > full)
-                               cpu_buffer->shortest_full = full;
-                       raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
-                       if (done)
-                               break;
-               }
+       /*
+        * The events can happen in critical sections where
+        * checking a work queue can cause deadlocks.
+        * After adding a task to the queue, this flag is set
+        * only to notify events to try to wake up the queue
+        * using irq_work.
+        *
+        * We don't clear it even if the buffer is no longer
+        * empty. The flag only causes the next event to run
+        * irq_work to do the work queue wake up. The worse
+        * that can happen if we race with !trace_empty() is that
+        * an event will cause an irq_work to try to wake up
+        * an empty queue.
+        *
+        * There's no reason to protect this flag either, as
+        * the work queue and irq_work logic will do the necessary
+        * synchronization for the wake ups. The only thing
+        * that is necessary is that the wake up happens after
+        * a task has been queued. It's OK for spurious wake ups.
+        */
+       if (full)
+               work->full_waiters_pending = true;
+       else
+               work->waiters_pending = true;
 
-               schedule();
+       if (rb_watermark_hit(buffer, cpu, full))
+               goto out;
 
-               /* Make sure to see the new wait index */
-               smp_rmb();
-               if (wait_index != work->wait_index)
-                       break;
+       if (signal_pending(current)) {
+               ret = -EINTR;
+               goto out;
        }
 
+       schedule();
+ out:
        if (full)
                finish_wait(&work->full_waiters, &wait);
        else
                finish_wait(&work->waiters, &wait);
 
+       if (!ret && !rb_watermark_hit(buffer, cpu, full) && signal_pending(current))
+               ret = -EINTR;
+
        return ret;
 }
 
@@ -937,28 +945,33 @@ __poll_t ring_buffer_poll_wait(struct trace_buffer *buffer, int cpu,
                          struct file *filp, poll_table *poll_table, int full)
 {
        struct ring_buffer_per_cpu *cpu_buffer;
-       struct rb_irq_work *work;
+       struct rb_irq_work *rbwork;
 
        if (cpu == RING_BUFFER_ALL_CPUS) {
-               work = &buffer->irq_work;
+               rbwork = &buffer->irq_work;
                full = 0;
        } else {
                if (!cpumask_test_cpu(cpu, buffer->cpumask))
                        return EPOLLERR;
 
                cpu_buffer = buffer->buffers[cpu];
-               work = &cpu_buffer->irq_work;
+               rbwork = &cpu_buffer->irq_work;
        }
 
        if (full) {
-               poll_wait(filp, &work->full_waiters, poll_table);
-               work->full_waiters_pending = true;
+               unsigned long flags;
+
+               poll_wait(filp, &rbwork->full_waiters, poll_table);
+
+               raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
+               rbwork->full_waiters_pending = true;
                if (!cpu_buffer->shortest_full ||
                    cpu_buffer->shortest_full > full)
                        cpu_buffer->shortest_full = full;
+               raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
        } else {
-               poll_wait(filp, &work->waiters, poll_table);
-               work->waiters_pending = true;
+               poll_wait(filp, &rbwork->waiters, poll_table);
+               rbwork->waiters_pending = true;
        }
 
        /*
@@ -1009,7 +1022,7 @@ static inline u64 rb_time_stamp(struct trace_buffer *buffer)
        u64 ts;
 
        /* Skip retpolines :-( */
-       if (IS_ENABLED(CONFIG_RETPOLINE) && likely(buffer->clock == trace_clock_local))
+       if (IS_ENABLED(CONFIG_MITIGATION_RETPOLINE) && likely(buffer->clock == trace_clock_local))
                ts = trace_clock_local();
        else
                ts = buffer->clock();
@@ -5877,6 +5890,10 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
        if (psize <= BUF_PAGE_HDR_SIZE)
                return -EINVAL;
 
+       /* Size of a subbuf cannot be greater than the write counter */
+       if (psize > RB_WRITE_MASK + 1)
+               return -EINVAL;
+
        old_order = buffer->subbuf_order;
        old_size = buffer->subbuf_size;
 
index 9ff8a439d6746fe16e7256e4040aaad729fff1bc..c9c8983073485bb3645062760ffc4b0dcef94e9d 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/panic_notifier.h>
+#include <linux/kmemleak.h>
 #include <linux/poll.h>
 #include <linux/nmi.h>
 #include <linux/fs.h>
@@ -1532,7 +1533,7 @@ void disable_trace_on_warning(void)
 bool tracer_tracing_is_on(struct trace_array *tr)
 {
        if (tr->array_buffer.buffer)
-               return ring_buffer_record_is_on(tr->array_buffer.buffer);
+               return ring_buffer_record_is_set_on(tr->array_buffer.buffer);
        return !tr->buffer_disabled;
 }
 
@@ -2339,6 +2340,7 @@ static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s)
        int order = get_order(sizeof(*s) + s->cmdline_num * TASK_COMM_LEN);
 
        kfree(s->map_cmdline_to_pid);
+       kmemleak_free(s);
        free_pages((unsigned long)s, order);
 }
 
@@ -2358,6 +2360,7 @@ static struct saved_cmdlines_buffer *allocate_cmdlines_buffer(unsigned int val)
                return NULL;
 
        s = page_address(page);
+       kmemleak_alloc(s, size, 1, GFP_KERNEL);
        memset(s, 0, sizeof(*s));
 
        /* Round up to actual allocation */
@@ -7290,6 +7293,8 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
+#define TRACE_MARKER_MAX_SIZE          4096
+
 static ssize_t
 tracing_mark_write(struct file *filp, const char __user *ubuf,
                                        size_t cnt, loff_t *fpos)
@@ -7317,6 +7322,9 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
        if ((ssize_t)cnt < 0)
                return -EINVAL;
 
+       if (cnt > TRACE_MARKER_MAX_SIZE)
+               cnt = TRACE_MARKER_MAX_SIZE;
+
        meta_size = sizeof(*entry) + 2;  /* add '\0' and possible '\n' */
  again:
        size = cnt + meta_size;
@@ -7325,11 +7333,6 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
        if (cnt < FAULTED_SIZE)
                size += FAULTED_SIZE - cnt;
 
-       if (size > TRACE_SEQ_BUFFER_SIZE) {
-               cnt -= size - TRACE_SEQ_BUFFER_SIZE;
-               goto again;
-       }
-
        buffer = tr->array_buffer.buffer;
        event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
                                            tracing_gen_ctx());
@@ -8390,6 +8393,20 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
        return size;
 }
 
+static int tracing_buffers_flush(struct file *file, fl_owner_t id)
+{
+       struct ftrace_buffer_info *info = file->private_data;
+       struct trace_iterator *iter = &info->iter;
+
+       iter->wait_index++;
+       /* Make sure the waiters see the new wait_index */
+       smp_wmb();
+
+       ring_buffer_wake_waiters(iter->array_buffer->buffer, iter->cpu_file);
+
+       return 0;
+}
+
 static int tracing_buffers_release(struct inode *inode, struct file *file)
 {
        struct ftrace_buffer_info *info = file->private_data;
@@ -8401,12 +8418,6 @@ static int tracing_buffers_release(struct inode *inode, struct file *file)
 
        __trace_array_put(iter->tr);
 
-       iter->wait_index++;
-       /* Make sure the waiters see the new wait_index */
-       smp_wmb();
-
-       ring_buffer_wake_waiters(iter->array_buffer->buffer, iter->cpu_file);
-
        if (info->spare)
                ring_buffer_free_read_page(iter->array_buffer->buffer,
                                           info->spare_cpu, info->spare);
@@ -8622,6 +8633,7 @@ static const struct file_operations tracing_buffers_fops = {
        .read           = tracing_buffers_read,
        .poll           = tracing_buffers_poll,
        .release        = tracing_buffers_release,
+       .flush          = tracing_buffers_flush,
        .splice_read    = tracing_buffers_splice_read,
        .unlocked_ioctl = tracing_buffers_ioctl,
        .llseek         = no_llseek,
index ca224d53bfdcd0df9f6609d3f30a4a6054868136..5bbdbcbbde3cd281f82f3cbc79f72f7a0c3e67ee 100644 (file)
@@ -91,8 +91,8 @@ retry:
        for_each_member(i, type, member) {
                if (!member->name_off) {
                        /* Anonymous union/struct: push it for later use */
-                       type = btf_type_skip_modifiers(btf, member->type, &tid);
-                       if (type && top < BTF_ANON_STACK_MAX) {
+                       if (btf_type_skip_modifiers(btf, member->type, &tid) &&
+                           top < BTF_ANON_STACK_MAX) {
                                anon_stack[top].tid = tid;
                                anon_stack[top++].offset =
                                        cur_offset + member->offset;
index e7af286af4f1ad9d3ac578cb3ce3c58ba3d5ce0b..c82b401a294d961ae75c48f3a164e92f3ad181b1 100644 (file)
@@ -441,8 +441,9 @@ static unsigned int trace_string(struct synth_trace_event *entry,
        if (is_dynamic) {
                union trace_synth_field *data = &entry->fields[*n_u64];
 
+               len = fetch_store_strlen((unsigned long)str_val);
                data->as_dynamic.offset = struct_size(entry, fields, event->n_u64) + data_size;
-               data->as_dynamic.len = fetch_store_strlen((unsigned long)str_val);
+               data->as_dynamic.len = len;
 
                ret = fetch_store_string((unsigned long)str_val, &entry->fields[*n_u64], entry);
 
index 3e7fa44dc2b24850f8b836f6bd223807fbcf0c48..d8b302d0108302d9ef2debe735c4b7778a217f90 100644 (file)
@@ -1587,12 +1587,11 @@ static enum print_line_t trace_print_print(struct trace_iterator *iter,
 {
        struct print_entry *field;
        struct trace_seq *s = &iter->seq;
-       int max = iter->ent_size - offsetof(struct print_entry, buf);
 
        trace_assign_type(field, iter->ent);
 
        seq_print_ip_sym(s, field->ip, flags);
-       trace_seq_printf(s, ": %.*s", max, field->buf);
+       trace_seq_printf(s, ": %s", field->buf);
 
        return trace_handle_return(s);
 }
@@ -1601,11 +1600,10 @@ static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags,
                                         struct trace_event *event)
 {
        struct print_entry *field;
-       int max = iter->ent_size - offsetof(struct print_entry, buf);
 
        trace_assign_type(field, iter->ent);
 
-       trace_seq_printf(&iter->seq, "# %lx %.*s", field->ip, max, field->buf);
+       trace_seq_printf(&iter->seq, "# %lx %s", field->ip, field->buf);
 
        return trace_handle_return(&iter->seq);
 }
index 76e60faed892357002868cdf9fb41c76ad4eba54..bf2bdac46843dc945a7daa37a124e42eeaea489e 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/signal.h>
 #include <linux/completion.h>
 #include <linux/workqueue.h>
 #include <linux/nmi.h>
 #include <linux/kvm_para.h>
 #include <linux/delay.h>
+#include <linux/irq_work.h>
 
 #include "workqueue_internal.h"
 
-enum {
+enum worker_pool_flags {
        /*
         * worker_pool flags
         *
@@ -72,10 +74,17 @@ enum {
         * Note that DISASSOCIATED should be flipped only while holding
         * wq_pool_attach_mutex to avoid changing binding state while
         * worker_attach_to_pool() is in progress.
+        *
+        * As there can only be one concurrent BH execution context per CPU, a
+        * BH pool is per-CPU and always DISASSOCIATED.
         */
-       POOL_MANAGER_ACTIVE     = 1 << 0,       /* being managed */
+       POOL_BH                 = 1 << 0,       /* is a BH pool */
+       POOL_MANAGER_ACTIVE     = 1 << 1,       /* being managed */
        POOL_DISASSOCIATED      = 1 << 2,       /* cpu can't serve workers */
+       POOL_BH_DRAINING        = 1 << 3,       /* draining after CPU offline */
+};
 
+enum worker_flags {
        /* worker flags */
        WORKER_DIE              = 1 << 1,       /* die die die */
        WORKER_IDLE             = 1 << 2,       /* is idle */
@@ -86,7 +95,13 @@ enum {
 
        WORKER_NOT_RUNNING      = WORKER_PREP | WORKER_CPU_INTENSIVE |
                                  WORKER_UNBOUND | WORKER_REBOUND,
+};
+
+enum work_cancel_flags {
+       WORK_CANCEL_DELAYED     = 1 << 0,       /* canceling a delayed_work */
+};
 
+enum wq_internal_consts {
        NR_STD_WORKER_POOLS     = 2,            /* # standard pools per cpu */
 
        UNBOUND_POOL_HASH_ORDER = 6,            /* hashed by pool->attrs */
@@ -108,9 +123,17 @@ enum {
        RESCUER_NICE_LEVEL      = MIN_NICE,
        HIGHPRI_NICE_LEVEL      = MIN_NICE,
 
-       WQ_NAME_LEN             = 24,
+       WQ_NAME_LEN             = 32,
 };
 
+/*
+ * We don't want to trap softirq for too long. See MAX_SOFTIRQ_TIME and
+ * MAX_SOFTIRQ_RESTART in kernel/softirq.c. These are macros because
+ * msecs_to_jiffies() can't be an initializer.
+ */
+#define BH_WORKER_JIFFIES      msecs_to_jiffies(2)
+#define BH_WORKER_RESTARTS     10
+
 /*
  * Structure fields follow one of the following exclusion rules.
  *
@@ -122,6 +145,9 @@ enum {
  *
  * L: pool->lock protected.  Access with pool->lock held.
  *
+ * LN: pool->lock and wq_node_nr_active->lock protected for writes. Either for
+ *     reads.
+ *
  * K: Only modified by worker while holding pool->lock. Can be safely read by
  *    self, while holding pool->lock or from IRQ context if %current is the
  *    kworker.
@@ -143,6 +169,9 @@ enum {
  *
  * WR: wq->mutex protected for writes.  RCU protected for reads.
  *
+ * WO: wq->mutex protected for writes. Updated with WRITE_ONCE() and can be read
+ *     with READ_ONCE() without locking.
+ *
  * MD: wq_mayday_lock protected.
  *
  * WD: Used internally by the watchdog.
@@ -219,7 +248,7 @@ enum pool_workqueue_stats {
 };
 
 /*
- * The per-pool workqueue.  While queued, the lower WORK_STRUCT_FLAG_BITS
+ * The per-pool workqueue.  While queued, bits below WORK_PWQ_SHIFT
  * of work_struct->data are used for flags and the remaining high bits
  * point to the pwq; thus, pwqs need to be aligned at two's power of the
  * number of flag bits.
@@ -232,6 +261,7 @@ struct pool_workqueue {
        int                     refcnt;         /* L: reference count */
        int                     nr_in_flight[WORK_NR_COLORS];
                                                /* L: nr of in_flight works */
+       bool                    plugged;        /* L: execution suspended */
 
        /*
         * nr_active management and WORK_STRUCT_INACTIVE:
@@ -240,18 +270,18 @@ struct pool_workqueue {
         * pwq->inactive_works instead of pool->worklist and marked with
         * WORK_STRUCT_INACTIVE.
         *
-        * All work items marked with WORK_STRUCT_INACTIVE do not participate
-        * in pwq->nr_active and all work items in pwq->inactive_works are
-        * marked with WORK_STRUCT_INACTIVE.  But not all WORK_STRUCT_INACTIVE
-        * work items are in pwq->inactive_works.  Some of them are ready to
-        * run in pool->worklist or worker->scheduled.  Those work itmes are
-        * only struct wq_barrier which is used for flush_work() and should
-        * not participate in pwq->nr_active.  For non-barrier work item, it
-        * is marked with WORK_STRUCT_INACTIVE iff it is in pwq->inactive_works.
+        * All work items marked with WORK_STRUCT_INACTIVE do not participate in
+        * nr_active and all work items in pwq->inactive_works are marked with
+        * WORK_STRUCT_INACTIVE. But not all WORK_STRUCT_INACTIVE work items are
+        * in pwq->inactive_works. Some of them are ready to run in
+        * pool->worklist or worker->scheduled. Those work itmes are only struct
+        * wq_barrier which is used for flush_work() and should not participate
+        * in nr_active. For non-barrier work item, it is marked with
+        * WORK_STRUCT_INACTIVE iff it is in pwq->inactive_works.
         */
        int                     nr_active;      /* L: nr of active works */
-       int                     max_active;     /* L: max active works */
        struct list_head        inactive_works; /* L: inactive works */
+       struct list_head        pending_node;   /* LN: node on wq_node_nr_active->pending_pwqs */
        struct list_head        pwqs_node;      /* WR: node on wq->pwqs */
        struct list_head        mayday_node;    /* MD: node on wq->maydays */
 
@@ -265,7 +295,7 @@ struct pool_workqueue {
         */
        struct kthread_work     release_work;
        struct rcu_head         rcu;
-} __aligned(1 << WORK_STRUCT_FLAG_BITS);
+} __aligned(1 << WORK_STRUCT_PWQ_SHIFT);
 
 /*
  * Structure used to wait for workqueue flush.
@@ -278,6 +308,26 @@ struct wq_flusher {
 
 struct wq_device;
 
+/*
+ * Unlike in a per-cpu workqueue where max_active limits its concurrency level
+ * on each CPU, in an unbound workqueue, max_active applies to the whole system.
+ * As sharing a single nr_active across multiple sockets can be very expensive,
+ * the counting and enforcement is per NUMA node.
+ *
+ * The following struct is used to enforce per-node max_active. When a pwq wants
+ * to start executing a work item, it should increment ->nr using
+ * tryinc_node_nr_active(). If acquisition fails due to ->nr already being over
+ * ->max, the pwq is queued on ->pending_pwqs. As in-flight work items finish
+ * and decrement ->nr, node_activate_pending_pwq() activates the pending pwqs in
+ * round-robin order.
+ */
+struct wq_node_nr_active {
+       int                     max;            /* per-node max_active */
+       atomic_t                nr;             /* per-node nr_active */
+       raw_spinlock_t          lock;           /* nests inside pool locks */
+       struct list_head        pending_pwqs;   /* LN: pwqs with inactive works */
+};
+
 /*
  * The externally visible workqueue.  It relays the issued work items to
  * the appropriate worker_pool through its pool_workqueues.
@@ -298,10 +348,15 @@ struct workqueue_struct {
        struct worker           *rescuer;       /* MD: rescue worker */
 
        int                     nr_drainers;    /* WQ: drain in progress */
-       int                     saved_max_active; /* WQ: saved pwq max_active */
+
+       /* See alloc_workqueue() function comment for info on min/max_active */
+       int                     max_active;     /* WO: max active works */
+       int                     min_active;     /* WO: min active works */
+       int                     saved_max_active; /* WQ: saved max_active */
+       int                     saved_min_active; /* WQ: saved min_active */
 
        struct workqueue_attrs  *unbound_attrs; /* PW: only for unbound wqs */
-       struct pool_workqueue   *dfl_pwq;       /* PW: only for unbound wqs */
+       struct pool_workqueue __rcu *dfl_pwq;   /* PW: only for unbound wqs */
 
 #ifdef CONFIG_SYSFS
        struct wq_device        *wq_dev;        /* I: for sysfs interface */
@@ -323,10 +378,9 @@ struct workqueue_struct {
        /* hot fields used during command issue, aligned to cacheline */
        unsigned int            flags ____cacheline_aligned; /* WQ: WQ_* flags */
        struct pool_workqueue __percpu __rcu **cpu_pwq; /* I: per-cpu pwqs */
+       struct wq_node_nr_active *node_nr_active[]; /* I: per-node nr_active */
 };
 
-static struct kmem_cache *pwq_cache;
-
 /*
  * Each pod type describes how CPUs should be grouped for unbound workqueues.
  * See the comment above workqueue_attrs->affn_scope.
@@ -338,16 +392,13 @@ struct wq_pod_type {
        int                     *cpu_pod;       /* cpu -> pod */
 };
 
-static struct wq_pod_type wq_pod_types[WQ_AFFN_NR_TYPES];
-static enum wq_affn_scope wq_affn_dfl = WQ_AFFN_CACHE;
-
 static const char *wq_affn_names[WQ_AFFN_NR_TYPES] = {
-       [WQ_AFFN_DFL]                   = "default",
-       [WQ_AFFN_CPU]                   = "cpu",
-       [WQ_AFFN_SMT]                   = "smt",
-       [WQ_AFFN_CACHE]                 = "cache",
-       [WQ_AFFN_NUMA]                  = "numa",
-       [WQ_AFFN_SYSTEM]                = "system",
+       [WQ_AFFN_DFL]           = "default",
+       [WQ_AFFN_CPU]           = "cpu",
+       [WQ_AFFN_SMT]           = "smt",
+       [WQ_AFFN_CACHE]         = "cache",
+       [WQ_AFFN_NUMA]          = "numa",
+       [WQ_AFFN_SYSTEM]        = "system",
 };
 
 /*
@@ -359,12 +410,22 @@ static const char *wq_affn_names[WQ_AFFN_NR_TYPES] = {
  */
 static unsigned long wq_cpu_intensive_thresh_us = ULONG_MAX;
 module_param_named(cpu_intensive_thresh_us, wq_cpu_intensive_thresh_us, ulong, 0644);
+#ifdef CONFIG_WQ_CPU_INTENSIVE_REPORT
+static unsigned int wq_cpu_intensive_warning_thresh = 4;
+module_param_named(cpu_intensive_warning_thresh, wq_cpu_intensive_warning_thresh, uint, 0644);
+#endif
 
 /* see the comment above the definition of WQ_POWER_EFFICIENT */
 static bool wq_power_efficient = IS_ENABLED(CONFIG_WQ_POWER_EFFICIENT_DEFAULT);
 module_param_named(power_efficient, wq_power_efficient, bool, 0444);
 
 static bool wq_online;                 /* can kworkers be created yet? */
+static bool wq_topo_initialized __read_mostly = false;
+
+static struct kmem_cache *pwq_cache;
+
+static struct wq_pod_type wq_pod_types[WQ_AFFN_NR_TYPES];
+static enum wq_affn_scope wq_affn_dfl = WQ_AFFN_CACHE;
 
 /* buf for wq_update_unbound_pod_attrs(), protected by CPU hotplug exclusion */
 static struct workqueue_attrs *wq_update_pod_attrs_buf;
@@ -405,8 +466,17 @@ static bool wq_debug_force_rr_cpu = false;
 #endif
 module_param_named(debug_force_rr_cpu, wq_debug_force_rr_cpu, bool, 0644);
 
+/* to raise softirq for the BH worker pools on other CPUs */
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct irq_work [NR_STD_WORKER_POOLS],
+                                    bh_pool_irq_works);
+
+/* the BH worker pools */
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS],
+                                    bh_worker_pools);
+
 /* the per-cpu worker pools */
-static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS], cpu_worker_pools);
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS],
+                                    cpu_worker_pools);
 
 static DEFINE_IDR(worker_pool_idr);    /* PR: idr of all pools */
 
@@ -419,6 +489,12 @@ static struct workqueue_attrs *unbound_std_wq_attrs[NR_STD_WORKER_POOLS];
 /* I: attributes used when instantiating ordered pools on demand */
 static struct workqueue_attrs *ordered_wq_attrs[NR_STD_WORKER_POOLS];
 
+/*
+ * Used to synchronize multiple cancel_sync attempts on the same work item. See
+ * work_grab_pending() and __cancel_work_sync().
+ */
+static DECLARE_WAIT_QUEUE_HEAD(wq_cancel_waitq);
+
 /*
  * I: kthread_worker to release pwq's. pwq release needs to be bounced to a
  * process context while holding a pool lock. Bounce to a dedicated kthread
@@ -440,6 +516,10 @@ struct workqueue_struct *system_power_efficient_wq __ro_after_init;
 EXPORT_SYMBOL_GPL(system_power_efficient_wq);
 struct workqueue_struct *system_freezable_power_efficient_wq __ro_after_init;
 EXPORT_SYMBOL_GPL(system_freezable_power_efficient_wq);
+struct workqueue_struct *system_bh_wq;
+EXPORT_SYMBOL_GPL(system_bh_wq);
+struct workqueue_struct *system_bh_highpri_wq;
+EXPORT_SYMBOL_GPL(system_bh_highpri_wq);
 
 static int worker_thread(void *__worker);
 static void workqueue_sysfs_unregister(struct workqueue_struct *wq);
@@ -450,16 +530,21 @@ static void show_one_worker_pool(struct worker_pool *pool);
 #include <trace/events/workqueue.h>
 
 #define assert_rcu_or_pool_mutex()                                     \
-       RCU_LOCKDEP_WARN(!rcu_read_lock_held() &&                       \
+       RCU_LOCKDEP_WARN(!rcu_read_lock_any_held() &&                   \
                         !lockdep_is_held(&wq_pool_mutex),              \
                         "RCU or wq_pool_mutex should be held")
 
 #define assert_rcu_or_wq_mutex_or_pool_mutex(wq)                       \
-       RCU_LOCKDEP_WARN(!rcu_read_lock_held() &&                       \
+       RCU_LOCKDEP_WARN(!rcu_read_lock_any_held() &&                   \
                         !lockdep_is_held(&wq->mutex) &&                \
                         !lockdep_is_held(&wq_pool_mutex),              \
                         "RCU, wq->mutex or wq_pool_mutex should be held")
 
+#define for_each_bh_worker_pool(pool, cpu)                             \
+       for ((pool) = &per_cpu(bh_worker_pools, cpu)[0];                \
+            (pool) < &per_cpu(bh_worker_pools, cpu)[NR_STD_WORKER_POOLS]; \
+            (pool)++)
+
 #define for_each_cpu_worker_pool(pool, cpu)                            \
        for ((pool) = &per_cpu(cpu_worker_pools, cpu)[0];               \
             (pool) < &per_cpu(cpu_worker_pools, cpu)[NR_STD_WORKER_POOLS]; \
@@ -632,6 +717,36 @@ static int worker_pool_assign_id(struct worker_pool *pool)
        return ret;
 }
 
+static struct pool_workqueue __rcu **
+unbound_pwq_slot(struct workqueue_struct *wq, int cpu)
+{
+       if (cpu >= 0)
+               return per_cpu_ptr(wq->cpu_pwq, cpu);
+       else
+               return &wq->dfl_pwq;
+}
+
+/* @cpu < 0 for dfl_pwq */
+static struct pool_workqueue *unbound_pwq(struct workqueue_struct *wq, int cpu)
+{
+       return rcu_dereference_check(*unbound_pwq_slot(wq, cpu),
+                                    lockdep_is_held(&wq_pool_mutex) ||
+                                    lockdep_is_held(&wq->mutex));
+}
+
+/**
+ * unbound_effective_cpumask - effective cpumask of an unbound workqueue
+ * @wq: workqueue of interest
+ *
+ * @wq->unbound_attrs->cpumask contains the cpumask requested by the user which
+ * is masked with wq_unbound_cpumask to determine the effective cpumask. The
+ * default pwq is always mapped to the pool with the current effective cpumask.
+ */
+static struct cpumask *unbound_effective_cpumask(struct workqueue_struct *wq)
+{
+       return unbound_pwq(wq, -1)->pool->attrs->__pod_cpumask;
+}
+
 static unsigned int work_color_to_flags(int color)
 {
        return color << WORK_STRUCT_COLOR_SHIFT;
@@ -653,10 +768,9 @@ static int work_next_color(int color)
  * contain the pointer to the queued pwq.  Once execution starts, the flag
  * is cleared and the high bits contain OFFQ flags and pool ID.
  *
- * set_work_pwq(), set_work_pool_and_clear_pending(), mark_work_canceling()
- * and clear_work_data() can be used to set the pwq, pool or clear
- * work->data.  These functions should only be called while the work is
- * owned - ie. while the PENDING bit is set.
+ * set_work_pwq(), set_work_pool_and_clear_pending() and mark_work_canceling()
+ * can be used to set the pwq, pool or clear work->data. These functions should
+ * only be called while the work is owned - ie. while the PENDING bit is set.
  *
  * get_work_pool() and get_work_pwq() can be used to obtain the pool or pwq
  * corresponding to a work.  Pool is available once the work has been
@@ -668,29 +782,28 @@ static int work_next_color(int color)
  * but stay off timer and worklist for arbitrarily long and nobody should
  * try to steal the PENDING bit.
  */
-static inline void set_work_data(struct work_struct *work, unsigned long data,
-                                unsigned long flags)
+static inline void set_work_data(struct work_struct *work, unsigned long data)
 {
        WARN_ON_ONCE(!work_pending(work));
-       atomic_long_set(&work->data, data | flags | work_static(work));
+       atomic_long_set(&work->data, data | work_static(work));
 }
 
 static void set_work_pwq(struct work_struct *work, struct pool_workqueue *pwq,
-                        unsigned long extra_flags)
+                        unsigned long flags)
 {
-       set_work_data(work, (unsigned long)pwq,
-                     WORK_STRUCT_PENDING | WORK_STRUCT_PWQ | extra_flags);
+       set_work_data(work, (unsigned long)pwq | WORK_STRUCT_PENDING |
+                     WORK_STRUCT_PWQ | flags);
 }
 
 static void set_work_pool_and_keep_pending(struct work_struct *work,
-                                          int pool_id)
+                                          int pool_id, unsigned long flags)
 {
-       set_work_data(work, (unsigned long)pool_id << WORK_OFFQ_POOL_SHIFT,
-                     WORK_STRUCT_PENDING);
+       set_work_data(work, ((unsigned long)pool_id << WORK_OFFQ_POOL_SHIFT) |
+                     WORK_STRUCT_PENDING | flags);
 }
 
 static void set_work_pool_and_clear_pending(struct work_struct *work,
-                                           int pool_id)
+                                           int pool_id, unsigned long flags)
 {
        /*
         * The following wmb is paired with the implied mb in
@@ -699,7 +812,8 @@ static void set_work_pool_and_clear_pending(struct work_struct *work,
         * owner.
         */
        smp_wmb();
-       set_work_data(work, (unsigned long)pool_id << WORK_OFFQ_POOL_SHIFT, 0);
+       set_work_data(work, ((unsigned long)pool_id << WORK_OFFQ_POOL_SHIFT) |
+                     flags);
        /*
         * The following mb guarantees that previous clear of a PENDING bit
         * will not be reordered with any speculative LOADS or STORES from
@@ -731,15 +845,9 @@ static void set_work_pool_and_clear_pending(struct work_struct *work,
        smp_mb();
 }
 
-static void clear_work_data(struct work_struct *work)
-{
-       smp_wmb();      /* see set_work_pool_and_clear_pending() */
-       set_work_data(work, WORK_STRUCT_NO_POOL, 0);
-}
-
 static inline struct pool_workqueue *work_struct_pwq(unsigned long data)
 {
-       return (struct pool_workqueue *)(data & WORK_STRUCT_WQ_DATA_MASK);
+       return (struct pool_workqueue *)(data & WORK_STRUCT_PWQ_MASK);
 }
 
 static struct pool_workqueue *get_work_pwq(struct work_struct *work)
@@ -806,7 +914,7 @@ static void mark_work_canceling(struct work_struct *work)
        unsigned long pool_id = get_work_pool_id(work);
 
        pool_id <<= WORK_OFFQ_POOL_SHIFT;
-       set_work_data(work, pool_id | WORK_OFFQ_CANCELING, WORK_STRUCT_PENDING);
+       set_work_data(work, pool_id | WORK_STRUCT_PENDING | WORK_OFFQ_CANCELING);
 }
 
 static bool work_is_canceling(struct work_struct *work)
@@ -1101,6 +1209,29 @@ static bool assign_work(struct work_struct *work, struct worker *worker,
        return true;
 }
 
+static struct irq_work *bh_pool_irq_work(struct worker_pool *pool)
+{
+       int high = pool->attrs->nice == HIGHPRI_NICE_LEVEL ? 1 : 0;
+
+       return &per_cpu(bh_pool_irq_works, pool->cpu)[high];
+}
+
+static void kick_bh_pool(struct worker_pool *pool)
+{
+#ifdef CONFIG_SMP
+       /* see drain_dead_softirq_workfn() for BH_DRAINING */
+       if (unlikely(pool->cpu != smp_processor_id() &&
+                    !(pool->flags & POOL_BH_DRAINING))) {
+               irq_work_queue_on(bh_pool_irq_work(pool), pool->cpu);
+               return;
+       }
+#endif
+       if (pool->attrs->nice == HIGHPRI_NICE_LEVEL)
+               raise_softirq_irqoff(HI_SOFTIRQ);
+       else
+               raise_softirq_irqoff(TASKLET_SOFTIRQ);
+}
+
 /**
  * kick_pool - wake up an idle worker if necessary
  * @pool: pool to kick
@@ -1118,6 +1249,11 @@ static bool kick_pool(struct worker_pool *pool)
        if (!need_more_worker(pool) || !worker)
                return false;
 
+       if (pool->flags & POOL_BH) {
+               kick_bh_pool(pool);
+               return true;
+       }
+
        p = worker->task;
 
 #ifdef CONFIG_SMP
@@ -1198,11 +1334,13 @@ restart:
                u64 cnt;
 
                /*
-                * Start reporting from the fourth time and back off
+                * Start reporting from the warning_thresh and back off
                 * exponentially.
                 */
                cnt = atomic64_inc_return_relaxed(&ent->cnt);
-               if (cnt >= 4 && is_power_of_2(cnt))
+               if (wq_cpu_intensive_warning_thresh &&
+                   cnt >= wq_cpu_intensive_warning_thresh &&
+                   is_power_of_2(cnt + 1 - wq_cpu_intensive_warning_thresh))
                        printk_deferred(KERN_WARNING "workqueue: %ps hogged CPU for >%luus %llu times, consider switching to WQ_UNBOUND\n",
                                        ent->func, wq_cpu_intensive_thresh_us,
                                        atomic64_read(&ent->cnt));
@@ -1231,10 +1369,12 @@ restart:
 
        ent = &wci_ents[wci_nr_ents++];
        ent->func = func;
-       atomic64_set(&ent->cnt, 1);
+       atomic64_set(&ent->cnt, 0);
        hash_add_rcu(wci_hash, &ent->hash_node, (unsigned long)func);
 
        raw_spin_unlock(&wci_lock);
+
+       goto restart;
 }
 
 #else  /* CONFIG_WQ_CPU_INTENSIVE_REPORT */
@@ -1401,6 +1541,74 @@ work_func_t wq_worker_last_func(struct task_struct *task)
        return worker->last_func;
 }
 
+/**
+ * wq_node_nr_active - Determine wq_node_nr_active to use
+ * @wq: workqueue of interest
+ * @node: NUMA node, can be %NUMA_NO_NODE
+ *
+ * Determine wq_node_nr_active to use for @wq on @node. Returns:
+ *
+ * - %NULL for per-cpu workqueues as they don't need to use shared nr_active.
+ *
+ * - node_nr_active[nr_node_ids] if @node is %NUMA_NO_NODE.
+ *
+ * - Otherwise, node_nr_active[@node].
+ */
+static struct wq_node_nr_active *wq_node_nr_active(struct workqueue_struct *wq,
+                                                  int node)
+{
+       if (!(wq->flags & WQ_UNBOUND))
+               return NULL;
+
+       if (node == NUMA_NO_NODE)
+               node = nr_node_ids;
+
+       return wq->node_nr_active[node];
+}
+
+/**
+ * wq_update_node_max_active - Update per-node max_actives to use
+ * @wq: workqueue to update
+ * @off_cpu: CPU that's going down, -1 if a CPU is not going down
+ *
+ * Update @wq->node_nr_active[]->max. @wq must be unbound. max_active is
+ * distributed among nodes according to the proportions of numbers of online
+ * cpus. The result is always between @wq->min_active and max_active.
+ */
+static void wq_update_node_max_active(struct workqueue_struct *wq, int off_cpu)
+{
+       struct cpumask *effective = unbound_effective_cpumask(wq);
+       int min_active = READ_ONCE(wq->min_active);
+       int max_active = READ_ONCE(wq->max_active);
+       int total_cpus, node;
+
+       lockdep_assert_held(&wq->mutex);
+
+       if (!wq_topo_initialized)
+               return;
+
+       if (off_cpu >= 0 && !cpumask_test_cpu(off_cpu, effective))
+               off_cpu = -1;
+
+       total_cpus = cpumask_weight_and(effective, cpu_online_mask);
+       if (off_cpu >= 0)
+               total_cpus--;
+
+       for_each_node(node) {
+               int node_cpus;
+
+               node_cpus = cpumask_weight_and(effective, cpumask_of_node(node));
+               if (off_cpu >= 0 && cpu_to_node(off_cpu) == node)
+                       node_cpus--;
+
+               wq_node_nr_active(wq, node)->max =
+                       clamp(DIV_ROUND_UP(max_active * node_cpus, total_cpus),
+                             min_active, max_active);
+       }
+
+       wq_node_nr_active(wq, NUMA_NO_NODE)->max = min_active;
+}
+
 /**
  * get_pwq - get an extra reference on the specified pool_workqueue
  * @pwq: pool_workqueue to get
@@ -1453,24 +1661,336 @@ static void put_pwq_unlocked(struct pool_workqueue *pwq)
        }
 }
 
-static void pwq_activate_inactive_work(struct work_struct *work)
+static bool pwq_is_empty(struct pool_workqueue *pwq)
 {
-       struct pool_workqueue *pwq = get_work_pwq(work);
+       return !pwq->nr_active && list_empty(&pwq->inactive_works);
+}
 
+static void __pwq_activate_work(struct pool_workqueue *pwq,
+                               struct work_struct *work)
+{
+       unsigned long *wdb = work_data_bits(work);
+
+       WARN_ON_ONCE(!(*wdb & WORK_STRUCT_INACTIVE));
        trace_workqueue_activate_work(work);
        if (list_empty(&pwq->pool->worklist))
                pwq->pool->watchdog_ts = jiffies;
        move_linked_works(work, &pwq->pool->worklist, NULL);
-       __clear_bit(WORK_STRUCT_INACTIVE_BIT, work_data_bits(work));
+       __clear_bit(WORK_STRUCT_INACTIVE_BIT, wdb);
+}
+
+/**
+ * pwq_activate_work - Activate a work item if inactive
+ * @pwq: pool_workqueue @work belongs to
+ * @work: work item to activate
+ *
+ * Returns %true if activated. %false if already active.
+ */
+static bool pwq_activate_work(struct pool_workqueue *pwq,
+                             struct work_struct *work)
+{
+       struct worker_pool *pool = pwq->pool;
+       struct wq_node_nr_active *nna;
+
+       lockdep_assert_held(&pool->lock);
+
+       if (!(*work_data_bits(work) & WORK_STRUCT_INACTIVE))
+               return false;
+
+       nna = wq_node_nr_active(pwq->wq, pool->node);
+       if (nna)
+               atomic_inc(&nna->nr);
+
        pwq->nr_active++;
+       __pwq_activate_work(pwq, work);
+       return true;
 }
 
-static void pwq_activate_first_inactive(struct pool_workqueue *pwq)
+static bool tryinc_node_nr_active(struct wq_node_nr_active *nna)
 {
-       struct work_struct *work = list_first_entry(&pwq->inactive_works,
-                                                   struct work_struct, entry);
+       int max = READ_ONCE(nna->max);
+
+       while (true) {
+               int old, tmp;
+
+               old = atomic_read(&nna->nr);
+               if (old >= max)
+                       return false;
+               tmp = atomic_cmpxchg_relaxed(&nna->nr, old, old + 1);
+               if (tmp == old)
+                       return true;
+       }
+}
+
+/**
+ * pwq_tryinc_nr_active - Try to increment nr_active for a pwq
+ * @pwq: pool_workqueue of interest
+ * @fill: max_active may have increased, try to increase concurrency level
+ *
+ * Try to increment nr_active for @pwq. Returns %true if an nr_active count is
+ * successfully obtained. %false otherwise.
+ */
+static bool pwq_tryinc_nr_active(struct pool_workqueue *pwq, bool fill)
+{
+       struct workqueue_struct *wq = pwq->wq;
+       struct worker_pool *pool = pwq->pool;
+       struct wq_node_nr_active *nna = wq_node_nr_active(wq, pool->node);
+       bool obtained = false;
+
+       lockdep_assert_held(&pool->lock);
+
+       if (!nna) {
+               /* BH or per-cpu workqueue, pwq->nr_active is sufficient */
+               obtained = pwq->nr_active < READ_ONCE(wq->max_active);
+               goto out;
+       }
+
+       if (unlikely(pwq->plugged))
+               return false;
+
+       /*
+        * Unbound workqueue uses per-node shared nr_active $nna. If @pwq is
+        * already waiting on $nna, pwq_dec_nr_active() will maintain the
+        * concurrency level. Don't jump the line.
+        *
+        * We need to ignore the pending test after max_active has increased as
+        * pwq_dec_nr_active() can only maintain the concurrency level but not
+        * increase it. This is indicated by @fill.
+        */
+       if (!list_empty(&pwq->pending_node) && likely(!fill))
+               goto out;
+
+       obtained = tryinc_node_nr_active(nna);
+       if (obtained)
+               goto out;
+
+       /*
+        * Lockless acquisition failed. Lock, add ourself to $nna->pending_pwqs
+        * and try again. The smp_mb() is paired with the implied memory barrier
+        * of atomic_dec_return() in pwq_dec_nr_active() to ensure that either
+        * we see the decremented $nna->nr or they see non-empty
+        * $nna->pending_pwqs.
+        */
+       raw_spin_lock(&nna->lock);
+
+       if (list_empty(&pwq->pending_node))
+               list_add_tail(&pwq->pending_node, &nna->pending_pwqs);
+       else if (likely(!fill))
+               goto out_unlock;
+
+       smp_mb();
+
+       obtained = tryinc_node_nr_active(nna);
+
+       /*
+        * If @fill, @pwq might have already been pending. Being spuriously
+        * pending in cold paths doesn't affect anything. Let's leave it be.
+        */
+       if (obtained && likely(!fill))
+               list_del_init(&pwq->pending_node);
+
+out_unlock:
+       raw_spin_unlock(&nna->lock);
+out:
+       if (obtained)
+               pwq->nr_active++;
+       return obtained;
+}
+
+/**
+ * pwq_activate_first_inactive - Activate the first inactive work item on a pwq
+ * @pwq: pool_workqueue of interest
+ * @fill: max_active may have increased, try to increase concurrency level
+ *
+ * Activate the first inactive work item of @pwq if available and allowed by
+ * max_active limit.
+ *
+ * Returns %true if an inactive work item has been activated. %false if no
+ * inactive work item is found or max_active limit is reached.
+ */
+static bool pwq_activate_first_inactive(struct pool_workqueue *pwq, bool fill)
+{
+       struct work_struct *work =
+               list_first_entry_or_null(&pwq->inactive_works,
+                                        struct work_struct, entry);
+
+       if (work && pwq_tryinc_nr_active(pwq, fill)) {
+               __pwq_activate_work(pwq, work);
+               return true;
+       } else {
+               return false;
+       }
+}
+
+/**
+ * unplug_oldest_pwq - unplug the oldest pool_workqueue
+ * @wq: workqueue_struct where its oldest pwq is to be unplugged
+ *
+ * This function should only be called for ordered workqueues where only the
+ * oldest pwq is unplugged, the others are plugged to suspend execution to
+ * ensure proper work item ordering::
+ *
+ *    dfl_pwq --------------+     [P] - plugged
+ *                          |
+ *                          v
+ *    pwqs -> A -> B [P] -> C [P] (newest)
+ *            |    |        |
+ *            1    3        5
+ *            |    |        |
+ *            2    4        6
+ *
+ * When the oldest pwq is drained and removed, this function should be called
+ * to unplug the next oldest one to start its work item execution. Note that
+ * pwq's are linked into wq->pwqs with the oldest first, so the first one in
+ * the list is the oldest.
+ */
+static void unplug_oldest_pwq(struct workqueue_struct *wq)
+{
+       struct pool_workqueue *pwq;
+
+       lockdep_assert_held(&wq->mutex);
+
+       /* Caller should make sure that pwqs isn't empty before calling */
+       pwq = list_first_entry_or_null(&wq->pwqs, struct pool_workqueue,
+                                      pwqs_node);
+       raw_spin_lock_irq(&pwq->pool->lock);
+       if (pwq->plugged) {
+               pwq->plugged = false;
+               if (pwq_activate_first_inactive(pwq, true))
+                       kick_pool(pwq->pool);
+       }
+       raw_spin_unlock_irq(&pwq->pool->lock);
+}
+
+/**
+ * node_activate_pending_pwq - Activate a pending pwq on a wq_node_nr_active
+ * @nna: wq_node_nr_active to activate a pending pwq for
+ * @caller_pool: worker_pool the caller is locking
+ *
+ * Activate a pwq in @nna->pending_pwqs. Called with @caller_pool locked.
+ * @caller_pool may be unlocked and relocked to lock other worker_pools.
+ */
+static void node_activate_pending_pwq(struct wq_node_nr_active *nna,
+                                     struct worker_pool *caller_pool)
+{
+       struct worker_pool *locked_pool = caller_pool;
+       struct pool_workqueue *pwq;
+       struct work_struct *work;
+
+       lockdep_assert_held(&caller_pool->lock);
+
+       raw_spin_lock(&nna->lock);
+retry:
+       pwq = list_first_entry_or_null(&nna->pending_pwqs,
+                                      struct pool_workqueue, pending_node);
+       if (!pwq)
+               goto out_unlock;
+
+       /*
+        * If @pwq is for a different pool than @locked_pool, we need to lock
+        * @pwq->pool->lock. Let's trylock first. If unsuccessful, do the unlock
+        * / lock dance. For that, we also need to release @nna->lock as it's
+        * nested inside pool locks.
+        */
+       if (pwq->pool != locked_pool) {
+               raw_spin_unlock(&locked_pool->lock);
+               locked_pool = pwq->pool;
+               if (!raw_spin_trylock(&locked_pool->lock)) {
+                       raw_spin_unlock(&nna->lock);
+                       raw_spin_lock(&locked_pool->lock);
+                       raw_spin_lock(&nna->lock);
+                       goto retry;
+               }
+       }
+
+       /*
+        * $pwq may not have any inactive work items due to e.g. cancellations.
+        * Drop it from pending_pwqs and see if there's another one.
+        */
+       work = list_first_entry_or_null(&pwq->inactive_works,
+                                       struct work_struct, entry);
+       if (!work) {
+               list_del_init(&pwq->pending_node);
+               goto retry;
+       }
+
+       /*
+        * Acquire an nr_active count and activate the inactive work item. If
+        * $pwq still has inactive work items, rotate it to the end of the
+        * pending_pwqs so that we round-robin through them. This means that
+        * inactive work items are not activated in queueing order which is fine
+        * given that there has never been any ordering across different pwqs.
+        */
+       if (likely(tryinc_node_nr_active(nna))) {
+               pwq->nr_active++;
+               __pwq_activate_work(pwq, work);
+
+               if (list_empty(&pwq->inactive_works))
+                       list_del_init(&pwq->pending_node);
+               else
+                       list_move_tail(&pwq->pending_node, &nna->pending_pwqs);
+
+               /* if activating a foreign pool, make sure it's running */
+               if (pwq->pool != caller_pool)
+                       kick_pool(pwq->pool);
+       }
+
+out_unlock:
+       raw_spin_unlock(&nna->lock);
+       if (locked_pool != caller_pool) {
+               raw_spin_unlock(&locked_pool->lock);
+               raw_spin_lock(&caller_pool->lock);
+       }
+}
+
+/**
+ * pwq_dec_nr_active - Retire an active count
+ * @pwq: pool_workqueue of interest
+ *
+ * Decrement @pwq's nr_active and try to activate the first inactive work item.
+ * For unbound workqueues, this function may temporarily drop @pwq->pool->lock.
+ */
+static void pwq_dec_nr_active(struct pool_workqueue *pwq)
+{
+       struct worker_pool *pool = pwq->pool;
+       struct wq_node_nr_active *nna = wq_node_nr_active(pwq->wq, pool->node);
+
+       lockdep_assert_held(&pool->lock);
+
+       /*
+        * @pwq->nr_active should be decremented for both percpu and unbound
+        * workqueues.
+        */
+       pwq->nr_active--;
+
+       /*
+        * For a percpu workqueue, it's simple. Just need to kick the first
+        * inactive work item on @pwq itself.
+        */
+       if (!nna) {
+               pwq_activate_first_inactive(pwq, false);
+               return;
+       }
+
+       /*
+        * If @pwq is for an unbound workqueue, it's more complicated because
+        * multiple pwqs and pools may be sharing the nr_active count. When a
+        * pwq needs to wait for an nr_active count, it puts itself on
+        * $nna->pending_pwqs. The following atomic_dec_return()'s implied
+        * memory barrier is paired with smp_mb() in pwq_tryinc_nr_active() to
+        * guarantee that either we see non-empty pending_pwqs or they see
+        * decremented $nna->nr.
+        *
+        * $nna->max may change as CPUs come online/offline and @pwq->wq's
+        * max_active gets updated. However, it is guaranteed to be equal to or
+        * larger than @pwq->wq->min_active which is above zero unless freezing.
+        * This maintains the forward progress guarantee.
+        */
+       if (atomic_dec_return(&nna->nr) >= READ_ONCE(nna->max))
+               return;
 
-       pwq_activate_inactive_work(work);
+       if (!list_empty(&nna->pending_pwqs))
+               node_activate_pending_pwq(nna, pool);
 }
 
 /**
@@ -1481,6 +2001,11 @@ static void pwq_activate_first_inactive(struct pool_workqueue *pwq)
  * A work either has completed or is removed from pending queue,
  * decrement nr_in_flight of its pwq and handle workqueue flushing.
  *
+ * NOTE:
+ * For unbound workqueues, this function may temporarily drop @pwq->pool->lock
+ * and thus should be called after all other state updates for the in-flight
+ * work item is complete.
+ *
  * CONTEXT:
  * raw_spin_lock_irq(pool->lock).
  */
@@ -1488,14 +2013,8 @@ static void pwq_dec_nr_in_flight(struct pool_workqueue *pwq, unsigned long work_
 {
        int color = get_work_color(work_data);
 
-       if (!(work_data & WORK_STRUCT_INACTIVE)) {
-               pwq->nr_active--;
-               if (!list_empty(&pwq->inactive_works)) {
-                       /* one down, submit an inactive one */
-                       if (pwq->nr_active < pwq->max_active)
-                               pwq_activate_first_inactive(pwq);
-               }
-       }
+       if (!(work_data & WORK_STRUCT_INACTIVE))
+               pwq_dec_nr_active(pwq);
 
        pwq->nr_in_flight[color]--;
 
@@ -1523,8 +2042,8 @@ out_put:
 /**
  * try_to_grab_pending - steal work item from worklist and disable irq
  * @work: work item to steal
- * @is_dwork: @work is a delayed_work
- * @flags: place to store irq state
+ * @cflags: %WORK_CANCEL_ flags
+ * @irq_flags: place to store irq state
  *
  * Try to grab PENDING bit of @work.  This function can handle @work in any
  * stable state - idle, on timer or on worklist.
@@ -1546,20 +2065,20 @@ out_put:
  * irqsafe, ensures that we return -EAGAIN for finite short period of time.
  *
  * On successful return, >= 0, irq is disabled and the caller is
- * responsible for releasing it using local_irq_restore(*@flags).
+ * responsible for releasing it using local_irq_restore(*@irq_flags).
  *
  * This function is safe to call from any context including IRQ handler.
  */
-static int try_to_grab_pending(struct work_struct *work, bool is_dwork,
-                              unsigned long *flags)
+static int try_to_grab_pending(struct work_struct *work, u32 cflags,
+                              unsigned long *irq_flags)
 {
        struct worker_pool *pool;
        struct pool_workqueue *pwq;
 
-       local_irq_save(*flags);
+       local_irq_save(*irq_flags);
 
        /* try to steal the timer if it exists */
-       if (is_dwork) {
+       if (cflags & WORK_CANCEL_DELAYED) {
                struct delayed_work *dwork = to_delayed_work(work);
 
                /*
@@ -1595,6 +2114,8 @@ static int try_to_grab_pending(struct work_struct *work, bool is_dwork,
         */
        pwq = get_work_pwq(work);
        if (pwq && pwq->pool == pool) {
+               unsigned long work_data;
+
                debug_work_deactivate(work);
 
                /*
@@ -1608,14 +2129,19 @@ static int try_to_grab_pending(struct work_struct *work, bool is_dwork,
                 * management later on and cause stall.  Make sure the work
                 * item is activated before grabbing.
                 */
-               if (*work_data_bits(work) & WORK_STRUCT_INACTIVE)
-                       pwq_activate_inactive_work(work);
+               pwq_activate_work(pwq, work);
 
                list_del_init(&work->entry);
-               pwq_dec_nr_in_flight(pwq, *work_data_bits(work));
 
-               /* work->data points to pwq iff queued, point to pool */
-               set_work_pool_and_keep_pending(work, pool->id);
+               /*
+                * work->data points to pwq iff queued. Let's point to pool. As
+                * this destroys work->data needed by the next step, stash it.
+                */
+               work_data = *work_data_bits(work);
+               set_work_pool_and_keep_pending(work, pool->id, 0);
+
+               /* must be the last step, see the function comment */
+               pwq_dec_nr_in_flight(pwq, work_data);
 
                raw_spin_unlock(&pool->lock);
                rcu_read_unlock();
@@ -1624,13 +2150,82 @@ static int try_to_grab_pending(struct work_struct *work, bool is_dwork,
        raw_spin_unlock(&pool->lock);
 fail:
        rcu_read_unlock();
-       local_irq_restore(*flags);
+       local_irq_restore(*irq_flags);
        if (work_is_canceling(work))
                return -ENOENT;
        cpu_relax();
        return -EAGAIN;
 }
 
+struct cwt_wait {
+       wait_queue_entry_t      wait;
+       struct work_struct      *work;
+};
+
+static int cwt_wakefn(wait_queue_entry_t *wait, unsigned mode, int sync, void *key)
+{
+       struct cwt_wait *cwait = container_of(wait, struct cwt_wait, wait);
+
+       if (cwait->work != key)
+               return 0;
+       return autoremove_wake_function(wait, mode, sync, key);
+}
+
+/**
+ * work_grab_pending - steal work item from worklist and disable irq
+ * @work: work item to steal
+ * @cflags: %WORK_CANCEL_ flags
+ * @irq_flags: place to store IRQ state
+ *
+ * Grab PENDING bit of @work. @work can be in any stable state - idle, on timer
+ * or on worklist.
+ *
+ * Must be called in process context. IRQ is disabled on return with IRQ state
+ * stored in *@irq_flags. The caller is responsible for re-enabling it using
+ * local_irq_restore().
+ *
+ * Returns %true if @work was pending. %false if idle.
+ */
+static bool work_grab_pending(struct work_struct *work, u32 cflags,
+                             unsigned long *irq_flags)
+{
+       struct cwt_wait cwait;
+       int ret;
+
+       might_sleep();
+repeat:
+       ret = try_to_grab_pending(work, cflags, irq_flags);
+       if (likely(ret >= 0))
+               return ret;
+       if (ret != -ENOENT)
+               goto repeat;
+
+       /*
+        * Someone is already canceling. Wait for it to finish. flush_work()
+        * doesn't work for PREEMPT_NONE because we may get woken up between
+        * @work's completion and the other canceling task resuming and clearing
+        * CANCELING - flush_work() will return false immediately as @work is no
+        * longer busy, try_to_grab_pending() will return -ENOENT as @work is
+        * still being canceled and the other canceling task won't be able to
+        * clear CANCELING as we're hogging the CPU.
+        *
+        * Let's wait for completion using a waitqueue. As this may lead to the
+        * thundering herd problem, use a custom wake function which matches
+        * @work along with exclusive wait and wakeup.
+        */
+       init_wait(&cwait.wait);
+       cwait.wait.func = cwt_wakefn;
+       cwait.work = work;
+
+       prepare_to_wait_exclusive(&wq_cancel_waitq, &cwait.wait,
+                                 TASK_UNINTERRUPTIBLE);
+       if (work_is_canceling(work))
+               schedule();
+       finish_wait(&wq_cancel_waitq, &cwait.wait);
+
+       goto repeat;
+}
+
 /**
  * insert_work - insert a work into a pool
  * @pwq: pwq @work belongs to
@@ -1718,7 +2313,6 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
         */
        lockdep_assert_irqs_disabled();
 
-
        /*
         * For a draining wq, only works from the same workqueue are
         * allowed. The __WQ_DESTROYING helps to spot the issue that
@@ -1793,12 +2387,16 @@ retry:
        pwq->nr_in_flight[pwq->work_color]++;
        work_flags = work_color_to_flags(pwq->work_color);
 
-       if (likely(pwq->nr_active < pwq->max_active)) {
+       /*
+        * Limit the number of concurrently active work items to max_active.
+        * @work must also queue behind existing inactive work items to maintain
+        * ordering when max_active changes. See wq_adjust_max_active().
+        */
+       if (list_empty(&pwq->inactive_works) && pwq_tryinc_nr_active(pwq, false)) {
                if (list_empty(&pool->worklist))
                        pool->watchdog_ts = jiffies;
 
                trace_workqueue_activate_work(work);
-               pwq->nr_active++;
                insert_work(pwq, work, &pool->worklist, work_flags);
                kick_pool(pool);
        } else {
@@ -1829,16 +2427,16 @@ bool queue_work_on(int cpu, struct workqueue_struct *wq,
                   struct work_struct *work)
 {
        bool ret = false;
-       unsigned long flags;
+       unsigned long irq_flags;
 
-       local_irq_save(flags);
+       local_irq_save(irq_flags);
 
        if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
                __queue_work(cpu, wq, work);
                ret = true;
        }
 
-       local_irq_restore(flags);
+       local_irq_restore(irq_flags);
        return ret;
 }
 EXPORT_SYMBOL(queue_work_on);
@@ -1895,7 +2493,7 @@ static int select_numa_node_cpu(int node)
 bool queue_work_node(int node, struct workqueue_struct *wq,
                     struct work_struct *work)
 {
-       unsigned long flags;
+       unsigned long irq_flags;
        bool ret = false;
 
        /*
@@ -1909,7 +2507,7 @@ bool queue_work_node(int node, struct workqueue_struct *wq,
         */
        WARN_ON_ONCE(!(wq->flags & WQ_UNBOUND));
 
-       local_irq_save(flags);
+       local_irq_save(irq_flags);
 
        if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
                int cpu = select_numa_node_cpu(node);
@@ -1918,7 +2516,7 @@ bool queue_work_node(int node, struct workqueue_struct *wq,
                ret = true;
        }
 
-       local_irq_restore(flags);
+       local_irq_restore(irq_flags);
        return ret;
 }
 EXPORT_SYMBOL_GPL(queue_work_node);
@@ -1958,10 +2556,18 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq,
        dwork->cpu = cpu;
        timer->expires = jiffies + delay;
 
-       if (unlikely(cpu != WORK_CPU_UNBOUND))
+       if (housekeeping_enabled(HK_TYPE_TIMER)) {
+               /* If the current cpu is a housekeeping cpu, use it. */
+               cpu = smp_processor_id();
+               if (!housekeeping_test_cpu(cpu, HK_TYPE_TIMER))
+                       cpu = housekeeping_any_cpu(HK_TYPE_TIMER);
                add_timer_on(timer, cpu);
-       else
-               add_timer(timer);
+       } else {
+               if (likely(cpu == WORK_CPU_UNBOUND))
+                       add_timer_global(timer);
+               else
+                       add_timer_on(timer, cpu);
+       }
 }
 
 /**
@@ -1980,17 +2586,17 @@ bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
 {
        struct work_struct *work = &dwork->work;
        bool ret = false;
-       unsigned long flags;
+       unsigned long irq_flags;
 
        /* read the comment in __queue_work() */
-       local_irq_save(flags);
+       local_irq_save(irq_flags);
 
        if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
                __queue_delayed_work(cpu, wq, dwork, delay);
                ret = true;
        }
 
-       local_irq_restore(flags);
+       local_irq_restore(irq_flags);
        return ret;
 }
 EXPORT_SYMBOL(queue_delayed_work_on);
@@ -2016,16 +2622,17 @@ EXPORT_SYMBOL(queue_delayed_work_on);
 bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
                         struct delayed_work *dwork, unsigned long delay)
 {
-       unsigned long flags;
+       unsigned long irq_flags;
        int ret;
 
        do {
-               ret = try_to_grab_pending(&dwork->work, true, &flags);
+               ret = try_to_grab_pending(&dwork->work, WORK_CANCEL_DELAYED,
+                                         &irq_flags);
        } while (unlikely(ret == -EAGAIN));
 
        if (likely(ret >= 0)) {
                __queue_delayed_work(cpu, wq, dwork, delay);
-               local_irq_restore(flags);
+               local_irq_restore(irq_flags);
        }
 
        /* -ENOENT from try_to_grab_pending() becomes %true */
@@ -2100,19 +2707,21 @@ static cpumask_t *pool_allowed_cpus(struct worker_pool *pool)
  * cpu-[un]hotplugs.
  */
 static void worker_attach_to_pool(struct worker *worker,
-                                  struct worker_pool *pool)
+                                 struct worker_pool *pool)
 {
        mutex_lock(&wq_pool_attach_mutex);
 
        /*
-        * The wq_pool_attach_mutex ensures %POOL_DISASSOCIATED remains
-        * stable across this function.  See the comments above the flag
-        * definition for details.
+        * The wq_pool_attach_mutex ensures %POOL_DISASSOCIATED remains stable
+        * across this function. See the comments above the flag definition for
+        * details. BH workers are, while per-CPU, always DISASSOCIATED.
         */
-       if (pool->flags & POOL_DISASSOCIATED)
+       if (pool->flags & POOL_DISASSOCIATED) {
                worker->flags |= WORKER_UNBOUND;
-       else
+       } else {
+               WARN_ON_ONCE(pool->flags & POOL_BH);
                kthread_set_per_cpu(worker->task, pool->cpu);
+       }
 
        if (worker->rescue_wq)
                set_cpus_allowed_ptr(worker->task, pool_allowed_cpus(pool));
@@ -2136,6 +2745,9 @@ static void worker_detach_from_pool(struct worker *worker)
        struct worker_pool *pool = worker->pool;
        struct completion *detach_completion = NULL;
 
+       /* there is one permanent BH worker per CPU which should never detach */
+       WARN_ON_ONCE(pool->flags & POOL_BH);
+
        mutex_lock(&wq_pool_attach_mutex);
 
        kthread_set_per_cpu(worker->task, -1);
@@ -2187,27 +2799,29 @@ static struct worker *create_worker(struct worker_pool *pool)
 
        worker->id = id;
 
-       if (pool->cpu >= 0)
-               snprintf(id_buf, sizeof(id_buf), "%d:%d%s", pool->cpu, id,
-                        pool->attrs->nice < 0  ? "H" : "");
-       else
-               snprintf(id_buf, sizeof(id_buf), "u%d:%d", pool->id, id);
-
-       worker->task = kthread_create_on_node(worker_thread, worker, pool->node,
-                                             "kworker/%s", id_buf);
-       if (IS_ERR(worker->task)) {
-               if (PTR_ERR(worker->task) == -EINTR) {
-                       pr_err("workqueue: Interrupted when creating a worker thread \"kworker/%s\"\n",
-                              id_buf);
-               } else {
-                       pr_err_once("workqueue: Failed to create a worker thread: %pe",
-                                   worker->task);
+       if (!(pool->flags & POOL_BH)) {
+               if (pool->cpu >= 0)
+                       snprintf(id_buf, sizeof(id_buf), "%d:%d%s", pool->cpu, id,
+                                pool->attrs->nice < 0  ? "H" : "");
+               else
+                       snprintf(id_buf, sizeof(id_buf), "u%d:%d", pool->id, id);
+
+               worker->task = kthread_create_on_node(worker_thread, worker,
+                                       pool->node, "kworker/%s", id_buf);
+               if (IS_ERR(worker->task)) {
+                       if (PTR_ERR(worker->task) == -EINTR) {
+                               pr_err("workqueue: Interrupted when creating a worker thread \"kworker/%s\"\n",
+                                      id_buf);
+                       } else {
+                               pr_err_once("workqueue: Failed to create a worker thread: %pe",
+                                           worker->task);
+                       }
+                       goto fail;
                }
-               goto fail;
-       }
 
-       set_user_nice(worker->task, pool->attrs->nice);
-       kthread_bind_mask(worker->task, pool_allowed_cpus(pool));
+               set_user_nice(worker->task, pool->attrs->nice);
+               kthread_bind_mask(worker->task, pool_allowed_cpus(pool));
+       }
 
        /* successful, attach the worker to the pool */
        worker_attach_to_pool(worker, pool);
@@ -2217,14 +2831,14 @@ static struct worker *create_worker(struct worker_pool *pool)
 
        worker->pool->nr_workers++;
        worker_enter_idle(worker);
-       kick_pool(pool);
 
        /*
         * @worker is waiting on a completion in kthread() and will trigger hung
-        * check if not woken up soon. As kick_pool() might not have waken it
-        * up, wake it up explicitly once more.
+        * check if not woken up soon. As kick_pool() is noop if @pool is empty,
+        * wake it up explicitly.
         */
-       wake_up_process(worker->task);
+       if (worker->task)
+               wake_up_process(worker->task);
 
        raw_spin_unlock_irq(&pool->lock);
 
@@ -2543,6 +3157,8 @@ __acquires(&pool->lock)
        struct pool_workqueue *pwq = get_work_pwq(work);
        struct worker_pool *pool = worker->pool;
        unsigned long work_data;
+       int lockdep_start_depth, rcu_start_depth;
+       bool bh_draining = pool->flags & POOL_BH_DRAINING;
 #ifdef CONFIG_LOCKDEP
        /*
         * It is permissible to free the struct work_struct from
@@ -2565,7 +3181,8 @@ __acquires(&pool->lock)
        worker->current_work = work;
        worker->current_func = work->func;
        worker->current_pwq = pwq;
-       worker->current_at = worker->task->se.sum_exec_runtime;
+       if (worker->task)
+               worker->current_at = worker->task->se.sum_exec_runtime;
        work_data = *work_data_bits(work);
        worker->current_color = get_work_color(work_data);
 
@@ -2600,12 +3217,16 @@ __acquires(&pool->lock)
         * PENDING and queued state changes happen together while IRQ is
         * disabled.
         */
-       set_work_pool_and_clear_pending(work, pool->id);
+       set_work_pool_and_clear_pending(work, pool->id, 0);
 
        pwq->stats[PWQ_STAT_STARTED]++;
        raw_spin_unlock_irq(&pool->lock);
 
-       lock_map_acquire(&pwq->wq->lockdep_map);
+       rcu_start_depth = rcu_preempt_depth();
+       lockdep_start_depth = lockdep_depth(current);
+       /* see drain_dead_softirq_workfn() */
+       if (!bh_draining)
+               lock_map_acquire(&pwq->wq->lockdep_map);
        lock_map_acquire(&lockdep_map);
        /*
         * Strictly speaking we should mark the invariant state without holding
@@ -2638,12 +3259,17 @@ __acquires(&pool->lock)
        trace_workqueue_execute_end(work, worker->current_func);
        pwq->stats[PWQ_STAT_COMPLETED]++;
        lock_map_release(&lockdep_map);
-       lock_map_release(&pwq->wq->lockdep_map);
+       if (!bh_draining)
+               lock_map_release(&pwq->wq->lockdep_map);
 
-       if (unlikely(in_atomic() || lockdep_depth(current) > 0)) {
-               pr_err("BUG: workqueue leaked lock or atomic: %s/0x%08x/%d\n"
-                      "     last function: %ps\n",
-                      current->comm, preempt_count(), task_pid_nr(current),
+       if (unlikely((worker->task && in_atomic()) ||
+                    lockdep_depth(current) != lockdep_start_depth ||
+                    rcu_preempt_depth() != rcu_start_depth)) {
+               pr_err("BUG: workqueue leaked atomic, lock or RCU: %s[%d]\n"
+                      "     preempt=0x%08x lock=%d->%d RCU=%d->%d workfn=%ps\n",
+                      current->comm, task_pid_nr(current), preempt_count(),
+                      lockdep_start_depth, lockdep_depth(current),
+                      rcu_start_depth, rcu_preempt_depth(),
                       worker->current_func);
                debug_show_held_locks(current);
                dump_stack();
@@ -2657,7 +3283,8 @@ __acquires(&pool->lock)
         * stop_machine. At the same time, report a quiescent RCU state so
         * the same condition doesn't freeze RCU.
         */
-       cond_resched();
+       if (worker->task)
+               cond_resched();
 
        raw_spin_lock_irq(&pool->lock);
 
@@ -2677,6 +3304,8 @@ __acquires(&pool->lock)
        worker->current_func = NULL;
        worker->current_pwq = NULL;
        worker->current_color = INT_MAX;
+
+       /* must be the last step, see the function comment */
        pwq_dec_nr_in_flight(pwq, work_data);
 }
 
@@ -2938,6 +3567,139 @@ repeat:
        goto repeat;
 }
 
+static void bh_worker(struct worker *worker)
+{
+       struct worker_pool *pool = worker->pool;
+       int nr_restarts = BH_WORKER_RESTARTS;
+       unsigned long end = jiffies + BH_WORKER_JIFFIES;
+
+       raw_spin_lock_irq(&pool->lock);
+       worker_leave_idle(worker);
+
+       /*
+        * This function follows the structure of worker_thread(). See there for
+        * explanations on each step.
+        */
+       if (!need_more_worker(pool))
+               goto done;
+
+       WARN_ON_ONCE(!list_empty(&worker->scheduled));
+       worker_clr_flags(worker, WORKER_PREP | WORKER_REBOUND);
+
+       do {
+               struct work_struct *work =
+                       list_first_entry(&pool->worklist,
+                                        struct work_struct, entry);
+
+               if (assign_work(work, worker, NULL))
+                       process_scheduled_works(worker);
+       } while (keep_working(pool) &&
+                --nr_restarts && time_before(jiffies, end));
+
+       worker_set_flags(worker, WORKER_PREP);
+done:
+       worker_enter_idle(worker);
+       kick_pool(pool);
+       raw_spin_unlock_irq(&pool->lock);
+}
+
+/*
+ * TODO: Convert all tasklet users to workqueue and use softirq directly.
+ *
+ * This is currently called from tasklet[_hi]action() and thus is also called
+ * whenever there are tasklets to run. Let's do an early exit if there's nothing
+ * queued. Once conversion from tasklet is complete, the need_more_worker() test
+ * can be dropped.
+ *
+ * After full conversion, we'll add worker->softirq_action, directly use the
+ * softirq action and obtain the worker pointer from the softirq_action pointer.
+ */
+void workqueue_softirq_action(bool highpri)
+{
+       struct worker_pool *pool =
+               &per_cpu(bh_worker_pools, smp_processor_id())[highpri];
+       if (need_more_worker(pool))
+               bh_worker(list_first_entry(&pool->workers, struct worker, node));
+}
+
+struct wq_drain_dead_softirq_work {
+       struct work_struct      work;
+       struct worker_pool      *pool;
+       struct completion       done;
+};
+
+static void drain_dead_softirq_workfn(struct work_struct *work)
+{
+       struct wq_drain_dead_softirq_work *dead_work =
+               container_of(work, struct wq_drain_dead_softirq_work, work);
+       struct worker_pool *pool = dead_work->pool;
+       bool repeat;
+
+       /*
+        * @pool's CPU is dead and we want to execute its still pending work
+        * items from this BH work item which is running on a different CPU. As
+        * its CPU is dead, @pool can't be kicked and, as work execution path
+        * will be nested, a lockdep annotation needs to be suppressed. Mark
+        * @pool with %POOL_BH_DRAINING for the special treatments.
+        */
+       raw_spin_lock_irq(&pool->lock);
+       pool->flags |= POOL_BH_DRAINING;
+       raw_spin_unlock_irq(&pool->lock);
+
+       bh_worker(list_first_entry(&pool->workers, struct worker, node));
+
+       raw_spin_lock_irq(&pool->lock);
+       pool->flags &= ~POOL_BH_DRAINING;
+       repeat = need_more_worker(pool);
+       raw_spin_unlock_irq(&pool->lock);
+
+       /*
+        * bh_worker() might hit consecutive execution limit and bail. If there
+        * still are pending work items, reschedule self and return so that we
+        * don't hog this CPU's BH.
+        */
+       if (repeat) {
+               if (pool->attrs->nice == HIGHPRI_NICE_LEVEL)
+                       queue_work(system_bh_highpri_wq, work);
+               else
+                       queue_work(system_bh_wq, work);
+       } else {
+               complete(&dead_work->done);
+       }
+}
+
+/*
+ * @cpu is dead. Drain the remaining BH work items on the current CPU. It's
+ * possible to allocate dead_work per CPU and avoid flushing. However, then we
+ * have to worry about draining overlapping with CPU coming back online or
+ * nesting (one CPU's dead_work queued on another CPU which is also dead and so
+ * on). Let's keep it simple and drain them synchronously. These are BH work
+ * items which shouldn't be requeued on the same pool. Shouldn't take long.
+ */
+void workqueue_softirq_dead(unsigned int cpu)
+{
+       int i;
+
+       for (i = 0; i < NR_STD_WORKER_POOLS; i++) {
+               struct worker_pool *pool = &per_cpu(bh_worker_pools, cpu)[i];
+               struct wq_drain_dead_softirq_work dead_work;
+
+               if (!need_more_worker(pool))
+                       continue;
+
+               INIT_WORK(&dead_work.work, drain_dead_softirq_workfn);
+               dead_work.pool = pool;
+               init_completion(&dead_work.done);
+
+               if (pool->attrs->nice == HIGHPRI_NICE_LEVEL)
+                       queue_work(system_bh_highpri_wq, &dead_work.work);
+               else
+                       queue_work(system_bh_wq, &dead_work.work);
+
+               wait_for_completion(&dead_work.done);
+       }
+}
+
 /**
  * check_flush_dependency - check for flush dependency sanity
  * @target_wq: workqueue being flushed
@@ -3010,6 +3772,7 @@ static void insert_wq_barrier(struct pool_workqueue *pwq,
                              struct wq_barrier *barr,
                              struct work_struct *target, struct worker *worker)
 {
+       static __maybe_unused struct lock_class_key bh_key, thr_key;
        unsigned int work_flags = 0;
        unsigned int work_color;
        struct list_head *head;
@@ -3019,15 +3782,20 @@ static void insert_wq_barrier(struct pool_workqueue *pwq,
         * as we know for sure that this will not trigger any of the
         * checks and call back into the fixup functions where we
         * might deadlock.
+        *
+        * BH and threaded workqueues need separate lockdep keys to avoid
+        * spuriously triggering "inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W}
+        * usage".
         */
-       INIT_WORK_ONSTACK(&barr->work, wq_barrier_func);
+       INIT_WORK_ONSTACK_KEY(&barr->work, wq_barrier_func,
+                             (pwq->wq->flags & WQ_BH) ? &bh_key : &thr_key);
        __set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&barr->work));
 
        init_completion_map(&barr->done, &target->lockdep_map);
 
        barr->task = current;
 
-       /* The barrier work item does not participate in pwq->nr_active. */
+       /* The barrier work item does not participate in nr_active. */
        work_flags |= WORK_STRUCT_INACTIVE;
 
        /*
@@ -3124,6 +3892,35 @@ static bool flush_workqueue_prep_pwqs(struct workqueue_struct *wq,
        return wait;
 }
 
+static void touch_wq_lockdep_map(struct workqueue_struct *wq)
+{
+#ifdef CONFIG_LOCKDEP
+       if (wq->flags & WQ_BH)
+               local_bh_disable();
+
+       lock_map_acquire(&wq->lockdep_map);
+       lock_map_release(&wq->lockdep_map);
+
+       if (wq->flags & WQ_BH)
+               local_bh_enable();
+#endif
+}
+
+static void touch_work_lockdep_map(struct work_struct *work,
+                                  struct workqueue_struct *wq)
+{
+#ifdef CONFIG_LOCKDEP
+       if (wq->flags & WQ_BH)
+               local_bh_disable();
+
+       lock_map_acquire(&work->lockdep_map);
+       lock_map_release(&work->lockdep_map);
+
+       if (wq->flags & WQ_BH)
+               local_bh_enable();
+#endif
+}
+
 /**
  * __flush_workqueue - ensure that any scheduled work has run to completion.
  * @wq: workqueue to flush
@@ -3143,8 +3940,7 @@ void __flush_workqueue(struct workqueue_struct *wq)
        if (WARN_ON(!wq_online))
                return;
 
-       lock_map_acquire(&wq->lockdep_map);
-       lock_map_release(&wq->lockdep_map);
+       touch_wq_lockdep_map(wq);
 
        mutex_lock(&wq->mutex);
 
@@ -3316,7 +4112,7 @@ reflush:
                bool drained;
 
                raw_spin_lock_irq(&pwq->pool->lock);
-               drained = !pwq->nr_active && list_empty(&pwq->inactive_works);
+               drained = pwq_is_empty(pwq);
                raw_spin_unlock_irq(&pwq->pool->lock);
 
                if (drained)
@@ -3343,6 +4139,7 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr,
        struct worker *worker = NULL;
        struct worker_pool *pool;
        struct pool_workqueue *pwq;
+       struct workqueue_struct *wq;
 
        might_sleep();
 
@@ -3366,11 +4163,14 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr,
                pwq = worker->current_pwq;
        }
 
-       check_flush_dependency(pwq->wq, work);
+       wq = pwq->wq;
+       check_flush_dependency(wq, work);
 
        insert_wq_barrier(pwq, barr, work, worker);
        raw_spin_unlock_irq(&pool->lock);
 
+       touch_work_lockdep_map(work, wq);
+
        /*
         * Force a lock recursion deadlock when using flush_work() inside a
         * single-threaded or rescuer equipped workqueue.
@@ -3380,11 +4180,9 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr,
         * workqueues the deadlock happens when the rescuer stalls, blocking
         * forward progress.
         */
-       if (!from_cancel &&
-           (pwq->wq->saved_max_active == 1 || pwq->wq->rescuer)) {
-               lock_map_acquire(&pwq->wq->lockdep_map);
-               lock_map_release(&pwq->wq->lockdep_map);
-       }
+       if (!from_cancel && (wq->saved_max_active == 1 || wq->rescuer))
+               touch_wq_lockdep_map(wq);
+
        rcu_read_unlock();
        return true;
 already_gone:
@@ -3395,144 +4193,39 @@ already_gone:
 
 static bool __flush_work(struct work_struct *work, bool from_cancel)
 {
-       struct wq_barrier barr;
-
-       if (WARN_ON(!wq_online))
-               return false;
-
-       if (WARN_ON(!work->func))
-               return false;
-
-       lock_map_acquire(&work->lockdep_map);
-       lock_map_release(&work->lockdep_map);
-
-       if (start_flush_work(work, &barr, from_cancel)) {
-               wait_for_completion(&barr.done);
-               destroy_work_on_stack(&barr.work);
-               return true;
-       } else {
-               return false;
-       }
-}
-
-/**
- * flush_work - wait for a work to finish executing the last queueing instance
- * @work: the work to flush
- *
- * Wait until @work has finished execution.  @work is guaranteed to be idle
- * on return if it hasn't been requeued since flush started.
- *
- * Return:
- * %true if flush_work() waited for the work to finish execution,
- * %false if it was already idle.
- */
-bool flush_work(struct work_struct *work)
-{
-       return __flush_work(work, false);
-}
-EXPORT_SYMBOL_GPL(flush_work);
-
-struct cwt_wait {
-       wait_queue_entry_t              wait;
-       struct work_struct      *work;
-};
-
-static int cwt_wakefn(wait_queue_entry_t *wait, unsigned mode, int sync, void *key)
-{
-       struct cwt_wait *cwait = container_of(wait, struct cwt_wait, wait);
-
-       if (cwait->work != key)
-               return 0;
-       return autoremove_wake_function(wait, mode, sync, key);
-}
-
-static bool __cancel_work_timer(struct work_struct *work, bool is_dwork)
-{
-       static DECLARE_WAIT_QUEUE_HEAD(cancel_waitq);
-       unsigned long flags;
-       int ret;
-
-       do {
-               ret = try_to_grab_pending(work, is_dwork, &flags);
-               /*
-                * If someone else is already canceling, wait for it to
-                * finish.  flush_work() doesn't work for PREEMPT_NONE
-                * because we may get scheduled between @work's completion
-                * and the other canceling task resuming and clearing
-                * CANCELING - flush_work() will return false immediately
-                * as @work is no longer busy, try_to_grab_pending() will
-                * return -ENOENT as @work is still being canceled and the
-                * other canceling task won't be able to clear CANCELING as
-                * we're hogging the CPU.
-                *
-                * Let's wait for completion using a waitqueue.  As this
-                * may lead to the thundering herd problem, use a custom
-                * wake function which matches @work along with exclusive
-                * wait and wakeup.
-                */
-               if (unlikely(ret == -ENOENT)) {
-                       struct cwt_wait cwait;
-
-                       init_wait(&cwait.wait);
-                       cwait.wait.func = cwt_wakefn;
-                       cwait.work = work;
-
-                       prepare_to_wait_exclusive(&cancel_waitq, &cwait.wait,
-                                                 TASK_UNINTERRUPTIBLE);
-                       if (work_is_canceling(work))
-                               schedule();
-                       finish_wait(&cancel_waitq, &cwait.wait);
-               }
-       } while (unlikely(ret < 0));
-
-       /* tell other tasks trying to grab @work to back off */
-       mark_work_canceling(work);
-       local_irq_restore(flags);
-
-       /*
-        * This allows canceling during early boot.  We know that @work
-        * isn't executing.
-        */
-       if (wq_online)
-               __flush_work(work, true);
+       struct wq_barrier barr;
 
-       clear_work_data(work);
+       if (WARN_ON(!wq_online))
+               return false;
 
-       /*
-        * Paired with prepare_to_wait() above so that either
-        * waitqueue_active() is visible here or !work_is_canceling() is
-        * visible there.
-        */
-       smp_mb();
-       if (waitqueue_active(&cancel_waitq))
-               __wake_up(&cancel_waitq, TASK_NORMAL, 1, work);
+       if (WARN_ON(!work->func))
+               return false;
 
-       return ret;
+       if (start_flush_work(work, &barr, from_cancel)) {
+               wait_for_completion(&barr.done);
+               destroy_work_on_stack(&barr.work);
+               return true;
+       } else {
+               return false;
+       }
 }
 
 /**
- * cancel_work_sync - cancel a work and wait for it to finish
- * @work: the work to cancel
- *
- * Cancel @work and wait for its execution to finish.  This function
- * can be used even if the work re-queues itself or migrates to
- * another workqueue.  On return from this function, @work is
- * guaranteed to be not pending or executing on any CPU.
- *
- * cancel_work_sync(&delayed_work->work) must not be used for
- * delayed_work's.  Use cancel_delayed_work_sync() instead.
+ * flush_work - wait for a work to finish executing the last queueing instance
+ * @work: the work to flush
  *
- * The caller must ensure that the workqueue on which @work was last
- * queued can't be destroyed before this function returns.
+ * Wait until @work has finished execution.  @work is guaranteed to be idle
+ * on return if it hasn't been requeued since flush started.
  *
  * Return:
- * %true if @work was pending, %false otherwise.
+ * %true if flush_work() waited for the work to finish execution,
+ * %false if it was already idle.
  */
-bool cancel_work_sync(struct work_struct *work)
+bool flush_work(struct work_struct *work)
 {
-       return __cancel_work_timer(work, false);
+       return __flush_work(work, false);
 }
-EXPORT_SYMBOL_GPL(cancel_work_sync);
+EXPORT_SYMBOL_GPL(flush_work);
 
 /**
  * flush_delayed_work - wait for a dwork to finish executing the last queueing
@@ -3576,20 +4269,50 @@ bool flush_rcu_work(struct rcu_work *rwork)
 }
 EXPORT_SYMBOL(flush_rcu_work);
 
-static bool __cancel_work(struct work_struct *work, bool is_dwork)
+static bool __cancel_work(struct work_struct *work, u32 cflags)
 {
-       unsigned long flags;
+       unsigned long irq_flags;
        int ret;
 
        do {
-               ret = try_to_grab_pending(work, is_dwork, &flags);
+               ret = try_to_grab_pending(work, cflags, &irq_flags);
        } while (unlikely(ret == -EAGAIN));
 
        if (unlikely(ret < 0))
                return false;
 
-       set_work_pool_and_clear_pending(work, get_work_pool_id(work));
-       local_irq_restore(flags);
+       set_work_pool_and_clear_pending(work, get_work_pool_id(work), 0);
+       local_irq_restore(irq_flags);
+       return ret;
+}
+
+static bool __cancel_work_sync(struct work_struct *work, u32 cflags)
+{
+       unsigned long irq_flags;
+       bool ret;
+
+       /* claim @work and tell other tasks trying to grab @work to back off */
+       ret = work_grab_pending(work, cflags, &irq_flags);
+       mark_work_canceling(work);
+       local_irq_restore(irq_flags);
+
+       /*
+        * Skip __flush_work() during early boot when we know that @work isn't
+        * executing. This allows canceling during early boot.
+        */
+       if (wq_online)
+               __flush_work(work, true);
+
+       /*
+        * smp_mb() at the end of set_work_pool_and_clear_pending() is paired
+        * with prepare_to_wait() above so that either waitqueue_active() is
+        * visible here or !work_is_canceling() is visible there.
+        */
+       set_work_pool_and_clear_pending(work, WORK_OFFQ_POOL_NONE, 0);
+
+       if (waitqueue_active(&wq_cancel_waitq))
+               __wake_up(&wq_cancel_waitq, TASK_NORMAL, 1, work);
+
        return ret;
 }
 
@@ -3598,10 +4321,34 @@ static bool __cancel_work(struct work_struct *work, bool is_dwork)
  */
 bool cancel_work(struct work_struct *work)
 {
-       return __cancel_work(work, false);
+       return __cancel_work(work, 0);
 }
 EXPORT_SYMBOL(cancel_work);
 
+/**
+ * cancel_work_sync - cancel a work and wait for it to finish
+ * @work: the work to cancel
+ *
+ * Cancel @work and wait for its execution to finish.  This function
+ * can be used even if the work re-queues itself or migrates to
+ * another workqueue.  On return from this function, @work is
+ * guaranteed to be not pending or executing on any CPU.
+ *
+ * cancel_work_sync(&delayed_work->work) must not be used for
+ * delayed_work's.  Use cancel_delayed_work_sync() instead.
+ *
+ * The caller must ensure that the workqueue on which @work was last
+ * queued can't be destroyed before this function returns.
+ *
+ * Return:
+ * %true if @work was pending, %false otherwise.
+ */
+bool cancel_work_sync(struct work_struct *work)
+{
+       return __cancel_work_sync(work, 0);
+}
+EXPORT_SYMBOL_GPL(cancel_work_sync);
+
 /**
  * cancel_delayed_work - cancel a delayed work
  * @dwork: delayed_work to cancel
@@ -3620,7 +4367,7 @@ EXPORT_SYMBOL(cancel_work);
  */
 bool cancel_delayed_work(struct delayed_work *dwork)
 {
-       return __cancel_work(&dwork->work, true);
+       return __cancel_work(&dwork->work, WORK_CANCEL_DELAYED);
 }
 EXPORT_SYMBOL(cancel_delayed_work);
 
@@ -3635,7 +4382,7 @@ EXPORT_SYMBOL(cancel_delayed_work);
  */
 bool cancel_delayed_work_sync(struct delayed_work *dwork)
 {
-       return __cancel_work_timer(&dwork->work, true);
+       return __cancel_work_sync(&dwork->work, WORK_CANCEL_DELAYED);
 }
 EXPORT_SYMBOL(cancel_delayed_work_sync);
 
@@ -3927,11 +4674,66 @@ static void wq_free_lockdep(struct workqueue_struct *wq)
 }
 #endif
 
+static void free_node_nr_active(struct wq_node_nr_active **nna_ar)
+{
+       int node;
+
+       for_each_node(node) {
+               kfree(nna_ar[node]);
+               nna_ar[node] = NULL;
+       }
+
+       kfree(nna_ar[nr_node_ids]);
+       nna_ar[nr_node_ids] = NULL;
+}
+
+static void init_node_nr_active(struct wq_node_nr_active *nna)
+{
+       nna->max = WQ_DFL_MIN_ACTIVE;
+       atomic_set(&nna->nr, 0);
+       raw_spin_lock_init(&nna->lock);
+       INIT_LIST_HEAD(&nna->pending_pwqs);
+}
+
+/*
+ * Each node's nr_active counter will be accessed mostly from its own node and
+ * should be allocated in the node.
+ */
+static int alloc_node_nr_active(struct wq_node_nr_active **nna_ar)
+{
+       struct wq_node_nr_active *nna;
+       int node;
+
+       for_each_node(node) {
+               nna = kzalloc_node(sizeof(*nna), GFP_KERNEL, node);
+               if (!nna)
+                       goto err_free;
+               init_node_nr_active(nna);
+               nna_ar[node] = nna;
+       }
+
+       /* [nr_node_ids] is used as the fallback */
+       nna = kzalloc_node(sizeof(*nna), GFP_KERNEL, NUMA_NO_NODE);
+       if (!nna)
+               goto err_free;
+       init_node_nr_active(nna);
+       nna_ar[nr_node_ids] = nna;
+
+       return 0;
+
+err_free:
+       free_node_nr_active(nna_ar);
+       return -ENOMEM;
+}
+
 static void rcu_free_wq(struct rcu_head *rcu)
 {
        struct workqueue_struct *wq =
                container_of(rcu, struct workqueue_struct, rcu);
 
+       if (wq->flags & WQ_UNBOUND)
+               free_node_nr_active(wq->node_nr_active);
+
        wq_free_lockdep(wq);
        free_percpu(wq->cpu_pwq);
        free_workqueue_attrs(wq->unbound_attrs);
@@ -4121,6 +4923,13 @@ static void pwq_release_workfn(struct kthread_work *work)
                mutex_lock(&wq->mutex);
                list_del_rcu(&pwq->pwqs_node);
                is_last = list_empty(&wq->pwqs);
+
+               /*
+                * For ordered workqueue with a plugged dfl_pwq, restart it now.
+                */
+               if (!is_last && (wq->flags & __WQ_ORDERED))
+                       unplug_oldest_pwq(wq);
+
                mutex_unlock(&wq->mutex);
        }
 
@@ -4130,6 +4939,15 @@ static void pwq_release_workfn(struct kthread_work *work)
                mutex_unlock(&wq_pool_mutex);
        }
 
+       if (!list_empty(&pwq->pending_node)) {
+               struct wq_node_nr_active *nna =
+                       wq_node_nr_active(pwq->wq, pwq->pool->node);
+
+               raw_spin_lock_irq(&nna->lock);
+               list_del_init(&pwq->pending_node);
+               raw_spin_unlock_irq(&nna->lock);
+       }
+
        call_rcu(&pwq->rcu, rcu_free_pwq);
 
        /*
@@ -4142,55 +4960,11 @@ static void pwq_release_workfn(struct kthread_work *work)
        }
 }
 
-/**
- * pwq_adjust_max_active - update a pwq's max_active to the current setting
- * @pwq: target pool_workqueue
- *
- * If @pwq isn't freezing, set @pwq->max_active to the associated
- * workqueue's saved_max_active and activate inactive work items
- * accordingly.  If @pwq is freezing, clear @pwq->max_active to zero.
- */
-static void pwq_adjust_max_active(struct pool_workqueue *pwq)
-{
-       struct workqueue_struct *wq = pwq->wq;
-       bool freezable = wq->flags & WQ_FREEZABLE;
-       unsigned long flags;
-
-       /* for @wq->saved_max_active */
-       lockdep_assert_held(&wq->mutex);
-
-       /* fast exit for non-freezable wqs */
-       if (!freezable && pwq->max_active == wq->saved_max_active)
-               return;
-
-       /* this function can be called during early boot w/ irq disabled */
-       raw_spin_lock_irqsave(&pwq->pool->lock, flags);
-
-       /*
-        * During [un]freezing, the caller is responsible for ensuring that
-        * this function is called at least once after @workqueue_freezing
-        * is updated and visible.
-        */
-       if (!freezable || !workqueue_freezing) {
-               pwq->max_active = wq->saved_max_active;
-
-               while (!list_empty(&pwq->inactive_works) &&
-                      pwq->nr_active < pwq->max_active)
-                       pwq_activate_first_inactive(pwq);
-
-               kick_pool(pwq->pool);
-       } else {
-               pwq->max_active = 0;
-       }
-
-       raw_spin_unlock_irqrestore(&pwq->pool->lock, flags);
-}
-
 /* initialize newly allocated @pwq which is associated with @wq and @pool */
 static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq,
                     struct worker_pool *pool)
 {
-       BUG_ON((unsigned long)pwq & WORK_STRUCT_FLAG_MASK);
+       BUG_ON((unsigned long)pwq & ~WORK_STRUCT_PWQ_MASK);
 
        memset(pwq, 0, sizeof(*pwq));
 
@@ -4199,6 +4973,7 @@ static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq,
        pwq->flush_color = -1;
        pwq->refcnt = 1;
        INIT_LIST_HEAD(&pwq->inactive_works);
+       INIT_LIST_HEAD(&pwq->pending_node);
        INIT_LIST_HEAD(&pwq->pwqs_node);
        INIT_LIST_HEAD(&pwq->mayday_node);
        kthread_init_work(&pwq->release_work, pwq_release_workfn);
@@ -4218,11 +4993,8 @@ static void link_pwq(struct pool_workqueue *pwq)
        /* set the matching work_color */
        pwq->work_color = wq->work_color;
 
-       /* sync max_active to the current setting */
-       pwq_adjust_max_active(pwq);
-
        /* link in @pwq */
-       list_add_rcu(&pwq->pwqs_node, &wq->pwqs);
+       list_add_tail_rcu(&pwq->pwqs_node, &wq->pwqs);
 }
 
 /* obtain a pool matching @attr and create a pwq associating the pool and @wq */
@@ -4289,10 +5061,11 @@ static void wq_calc_pod_cpumask(struct workqueue_attrs *attrs, int cpu,
                                "possible intersect\n");
 }
 
-/* install @pwq into @wq's cpu_pwq and return the old pwq */
+/* install @pwq into @wq and return the old pwq, @cpu < 0 for dfl_pwq */
 static struct pool_workqueue *install_unbound_pwq(struct workqueue_struct *wq,
                                        int cpu, struct pool_workqueue *pwq)
 {
+       struct pool_workqueue __rcu **slot = unbound_pwq_slot(wq, cpu);
        struct pool_workqueue *old_pwq;
 
        lockdep_assert_held(&wq_pool_mutex);
@@ -4301,8 +5074,8 @@ static struct pool_workqueue *install_unbound_pwq(struct workqueue_struct *wq,
        /* link_pwq() can handle duplicate calls */
        link_pwq(pwq);
 
-       old_pwq = rcu_access_pointer(*per_cpu_ptr(wq->cpu_pwq, cpu));
-       rcu_assign_pointer(*per_cpu_ptr(wq->cpu_pwq, cpu), pwq);
+       old_pwq = rcu_access_pointer(*slot);
+       rcu_assign_pointer(*slot, pwq);
        return old_pwq;
 }
 
@@ -4383,6 +5156,15 @@ apply_wqattrs_prepare(struct workqueue_struct *wq,
        cpumask_copy(new_attrs->__pod_cpumask, new_attrs->cpumask);
        ctx->attrs = new_attrs;
 
+       /*
+        * For initialized ordered workqueues, there should only be one pwq
+        * (dfl_pwq). Set the plugged flag of ctx->dfl_pwq to suspend execution
+        * of newly queued work items until execution of older work items in
+        * the old pwq's have completed.
+        */
+       if ((wq->flags & __WQ_ORDERED) && !list_empty(&wq->pwqs))
+               ctx->dfl_pwq->plugged = true;
+
        ctx->wq = wq;
        return ctx;
 
@@ -4402,14 +5184,19 @@ static void apply_wqattrs_commit(struct apply_wqattrs_ctx *ctx)
 
        copy_workqueue_attrs(ctx->wq->unbound_attrs, ctx->attrs);
 
-       /* save the previous pwq and install the new one */
+       /* save the previous pwqs and install the new ones */
        for_each_possible_cpu(cpu)
                ctx->pwq_tbl[cpu] = install_unbound_pwq(ctx->wq, cpu,
                                                        ctx->pwq_tbl[cpu]);
+       ctx->dfl_pwq = install_unbound_pwq(ctx->wq, -1, ctx->dfl_pwq);
+
+       /* update node_nr_active->max */
+       wq_update_node_max_active(ctx->wq, -1);
 
-       /* @dfl_pwq might not have been used, ensure it's linked */
-       link_pwq(ctx->dfl_pwq);
-       swap(ctx->wq->dfl_pwq, ctx->dfl_pwq);
+       /* rescuer needs to respect wq cpumask changes */
+       if (ctx->wq->rescuer)
+               set_cpus_allowed_ptr(ctx->wq->rescuer->task,
+                                    unbound_effective_cpumask(ctx->wq));
 
        mutex_unlock(&ctx->wq->mutex);
 }
@@ -4423,14 +5210,6 @@ static int apply_workqueue_attrs_locked(struct workqueue_struct *wq,
        if (WARN_ON(!(wq->flags & WQ_UNBOUND)))
                return -EINVAL;
 
-       /* creating multiple pwqs breaks ordering guarantee */
-       if (!list_empty(&wq->pwqs)) {
-               if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
-                       return -EINVAL;
-
-               wq->flags &= ~__WQ_ORDERED;
-       }
-
        ctx = apply_wqattrs_prepare(wq, attrs, wq_unbound_cpumask);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
@@ -4519,9 +5298,7 @@ static void wq_update_pod(struct workqueue_struct *wq, int cpu,
 
        /* nothing to do if the target cpumask matches the current pwq */
        wq_calc_pod_cpumask(target_attrs, cpu, off_cpu);
-       pwq = rcu_dereference_protected(*per_cpu_ptr(wq->cpu_pwq, cpu),
-                                       lockdep_is_held(&wq_pool_mutex));
-       if (wqattrs_equal(target_attrs, pwq->pool->attrs))
+       if (wqattrs_equal(target_attrs, unbound_pwq(wq, cpu)->pool->attrs))
                return;
 
        /* create a new pwq */
@@ -4539,10 +5316,11 @@ static void wq_update_pod(struct workqueue_struct *wq, int cpu,
 
 use_dfl_pwq:
        mutex_lock(&wq->mutex);
-       raw_spin_lock_irq(&wq->dfl_pwq->pool->lock);
-       get_pwq(wq->dfl_pwq);
-       raw_spin_unlock_irq(&wq->dfl_pwq->pool->lock);
-       old_pwq = install_unbound_pwq(wq, cpu, wq->dfl_pwq);
+       pwq = unbound_pwq(wq, -1);
+       raw_spin_lock_irq(&pwq->pool->lock);
+       get_pwq(pwq);
+       raw_spin_unlock_irq(&pwq->pool->lock);
+       old_pwq = install_unbound_pwq(wq, cpu, pwq);
 out_unlock:
        mutex_unlock(&wq->mutex);
        put_pwq_unlocked(old_pwq);
@@ -4559,10 +5337,17 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq)
 
        if (!(wq->flags & WQ_UNBOUND)) {
                for_each_possible_cpu(cpu) {
-                       struct pool_workqueue **pwq_p =
-                               per_cpu_ptr(wq->cpu_pwq, cpu);
-                       struct worker_pool *pool =
-                               &(per_cpu_ptr(cpu_worker_pools, cpu)[highpri]);
+                       struct pool_workqueue **pwq_p;
+                       struct worker_pool __percpu *pools;
+                       struct worker_pool *pool;
+
+                       if (wq->flags & WQ_BH)
+                               pools = bh_worker_pools;
+                       else
+                               pools = cpu_worker_pools;
+
+                       pool = &(per_cpu_ptr(pools, cpu)[highpri]);
+                       pwq_p = per_cpu_ptr(wq->cpu_pwq, cpu);
 
                        *pwq_p = kmem_cache_alloc_node(pwq_cache, GFP_KERNEL,
                                                       pool->node);
@@ -4580,10 +5365,13 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq)
 
        cpus_read_lock();
        if (wq->flags & __WQ_ORDERED) {
+               struct pool_workqueue *dfl_pwq;
+
                ret = apply_workqueue_attrs(wq, ordered_wq_attrs[highpri]);
                /* there should only be single pwq for ordering guarantee */
-               WARN(!ret && (wq->pwqs.next != &wq->dfl_pwq->pwqs_node ||
-                             wq->pwqs.prev != &wq->dfl_pwq->pwqs_node),
+               dfl_pwq = rcu_access_pointer(wq->dfl_pwq);
+               WARN(!ret && (wq->pwqs.next != &dfl_pwq->pwqs_node ||
+                             wq->pwqs.prev != &dfl_pwq->pwqs_node),
                     "ordering guarantee broken for workqueue %s\n", wq->name);
        } else {
                ret = apply_workqueue_attrs(wq, unbound_std_wq_attrs[highpri]);
@@ -4652,12 +5440,78 @@ static int init_rescuer(struct workqueue_struct *wq)
        }
 
        wq->rescuer = rescuer;
-       kthread_bind_mask(rescuer->task, cpu_possible_mask);
+       if (wq->flags & WQ_UNBOUND)
+               kthread_bind_mask(rescuer->task, wq_unbound_cpumask);
+       else
+               kthread_bind_mask(rescuer->task, cpu_possible_mask);
        wake_up_process(rescuer->task);
 
        return 0;
 }
 
+/**
+ * wq_adjust_max_active - update a wq's max_active to the current setting
+ * @wq: target workqueue
+ *
+ * If @wq isn't freezing, set @wq->max_active to the saved_max_active and
+ * activate inactive work items accordingly. If @wq is freezing, clear
+ * @wq->max_active to zero.
+ */
+static void wq_adjust_max_active(struct workqueue_struct *wq)
+{
+       bool activated;
+       int new_max, new_min;
+
+       lockdep_assert_held(&wq->mutex);
+
+       if ((wq->flags & WQ_FREEZABLE) && workqueue_freezing) {
+               new_max = 0;
+               new_min = 0;
+       } else {
+               new_max = wq->saved_max_active;
+               new_min = wq->saved_min_active;
+       }
+
+       if (wq->max_active == new_max && wq->min_active == new_min)
+               return;
+
+       /*
+        * Update @wq->max/min_active and then kick inactive work items if more
+        * active work items are allowed. This doesn't break work item ordering
+        * because new work items are always queued behind existing inactive
+        * work items if there are any.
+        */
+       WRITE_ONCE(wq->max_active, new_max);
+       WRITE_ONCE(wq->min_active, new_min);
+
+       if (wq->flags & WQ_UNBOUND)
+               wq_update_node_max_active(wq, -1);
+
+       if (new_max == 0)
+               return;
+
+       /*
+        * Round-robin through pwq's activating the first inactive work item
+        * until max_active is filled.
+        */
+       do {
+               struct pool_workqueue *pwq;
+
+               activated = false;
+               for_each_pwq(pwq, wq) {
+                       unsigned long irq_flags;
+
+                       /* can be called during early boot w/ irq disabled */
+                       raw_spin_lock_irqsave(&pwq->pool->lock, irq_flags);
+                       if (pwq_activate_first_inactive(pwq, true)) {
+                               activated = true;
+                               kick_pool(pwq->pool);
+                       }
+                       raw_spin_unlock_irqrestore(&pwq->pool->lock, irq_flags);
+               }
+       } while (activated);
+}
+
 __printf(1, 4)
 struct workqueue_struct *alloc_workqueue(const char *fmt,
                                         unsigned int flags,
@@ -4665,23 +5519,27 @@ struct workqueue_struct *alloc_workqueue(const char *fmt,
 {
        va_list args;
        struct workqueue_struct *wq;
-       struct pool_workqueue *pwq;
+       size_t wq_size;
+       int name_len;
 
-       /*
-        * Unbound && max_active == 1 used to imply ordered, which is no longer
-        * the case on many machines due to per-pod pools. While
-        * alloc_ordered_workqueue() is the right way to create an ordered
-        * workqueue, keep the previous behavior to avoid subtle breakages.
-        */
-       if ((flags & WQ_UNBOUND) && max_active == 1)
-               flags |= __WQ_ORDERED;
+       if (flags & WQ_BH) {
+               if (WARN_ON_ONCE(flags & ~__WQ_BH_ALLOWS))
+                       return NULL;
+               if (WARN_ON_ONCE(max_active))
+                       return NULL;
+       }
 
        /* see the comment above the definition of WQ_POWER_EFFICIENT */
        if ((flags & WQ_POWER_EFFICIENT) && wq_power_efficient)
                flags |= WQ_UNBOUND;
 
        /* allocate wq and format name */
-       wq = kzalloc(sizeof(*wq), GFP_KERNEL);
+       if (flags & WQ_UNBOUND)
+               wq_size = struct_size(wq, node_nr_active, nr_node_ids + 1);
+       else
+               wq_size = sizeof(*wq);
+
+       wq = kzalloc(wq_size, GFP_KERNEL);
        if (!wq)
                return NULL;
 
@@ -4692,15 +5550,30 @@ struct workqueue_struct *alloc_workqueue(const char *fmt,
        }
 
        va_start(args, max_active);
-       vsnprintf(wq->name, sizeof(wq->name), fmt, args);
+       name_len = vsnprintf(wq->name, sizeof(wq->name), fmt, args);
        va_end(args);
 
-       max_active = max_active ?: WQ_DFL_ACTIVE;
-       max_active = wq_clamp_max_active(max_active, flags, wq->name);
+       if (name_len >= WQ_NAME_LEN)
+               pr_warn_once("workqueue: name exceeds WQ_NAME_LEN. Truncating to: %s\n",
+                            wq->name);
+
+       if (flags & WQ_BH) {
+               /*
+                * BH workqueues always share a single execution context per CPU
+                * and don't impose any max_active limit.
+                */
+               max_active = INT_MAX;
+       } else {
+               max_active = max_active ?: WQ_DFL_ACTIVE;
+               max_active = wq_clamp_max_active(max_active, flags, wq->name);
+       }
 
        /* init wq */
        wq->flags = flags;
-       wq->saved_max_active = max_active;
+       wq->max_active = max_active;
+       wq->min_active = min(max_active, WQ_DFL_MIN_ACTIVE);
+       wq->saved_max_active = wq->max_active;
+       wq->saved_min_active = wq->min_active;
        mutex_init(&wq->mutex);
        atomic_set(&wq->nr_pwqs_to_flush, 0);
        INIT_LIST_HEAD(&wq->pwqs);
@@ -4711,8 +5584,13 @@ struct workqueue_struct *alloc_workqueue(const char *fmt,
        wq_init_lockdep(wq);
        INIT_LIST_HEAD(&wq->list);
 
+       if (flags & WQ_UNBOUND) {
+               if (alloc_node_nr_active(wq->node_nr_active) < 0)
+                       goto err_unreg_lockdep;
+       }
+
        if (alloc_and_link_pwqs(wq) < 0)
-               goto err_unreg_lockdep;
+               goto err_free_node_nr_active;
 
        if (wq_online && init_rescuer(wq) < 0)
                goto err_destroy;
@@ -4728,8 +5606,7 @@ struct workqueue_struct *alloc_workqueue(const char *fmt,
        mutex_lock(&wq_pool_mutex);
 
        mutex_lock(&wq->mutex);
-       for_each_pwq(pwq, wq)
-               pwq_adjust_max_active(pwq);
+       wq_adjust_max_active(wq);
        mutex_unlock(&wq->mutex);
 
        list_add_tail_rcu(&wq->list, &workqueues);
@@ -4738,6 +5615,9 @@ struct workqueue_struct *alloc_workqueue(const char *fmt,
 
        return wq;
 
+err_free_node_nr_active:
+       if (wq->flags & WQ_UNBOUND)
+               free_node_nr_active(wq->node_nr_active);
 err_unreg_lockdep:
        wq_unregister_lockdep(wq);
        wq_free_lockdep(wq);
@@ -4759,9 +5639,9 @@ static bool pwq_busy(struct pool_workqueue *pwq)
                if (pwq->nr_in_flight[i])
                        return true;
 
-       if ((pwq != pwq->wq->dfl_pwq) && (pwq->refcnt > 1))
+       if ((pwq != rcu_access_pointer(pwq->wq->dfl_pwq)) && (pwq->refcnt > 1))
                return true;
-       if (pwq->nr_active || !list_empty(&pwq->inactive_works))
+       if (!pwq_is_empty(pwq))
                return true;
 
        return false;
@@ -4843,13 +5723,12 @@ void destroy_workqueue(struct workqueue_struct *wq)
        rcu_read_lock();
 
        for_each_possible_cpu(cpu) {
-               pwq = rcu_access_pointer(*per_cpu_ptr(wq->cpu_pwq, cpu));
-               RCU_INIT_POINTER(*per_cpu_ptr(wq->cpu_pwq, cpu), NULL);
-               put_pwq_unlocked(pwq);
+               put_pwq_unlocked(unbound_pwq(wq, cpu));
+               RCU_INIT_POINTER(*unbound_pwq_slot(wq, cpu), NULL);
        }
 
-       put_pwq_unlocked(wq->dfl_pwq);
-       wq->dfl_pwq = NULL;
+       put_pwq_unlocked(unbound_pwq(wq, -1));
+       RCU_INIT_POINTER(*unbound_pwq_slot(wq, -1), NULL);
 
        rcu_read_unlock();
 }
@@ -4860,33 +5739,62 @@ EXPORT_SYMBOL_GPL(destroy_workqueue);
  * @wq: target workqueue
  * @max_active: new max_active value.
  *
- * Set max_active of @wq to @max_active.
+ * Set max_active of @wq to @max_active. See the alloc_workqueue() function
+ * comment.
  *
  * CONTEXT:
  * Don't call from IRQ context.
  */
 void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)
 {
-       struct pool_workqueue *pwq;
-
+       /* max_active doesn't mean anything for BH workqueues */
+       if (WARN_ON(wq->flags & WQ_BH))
+               return;
        /* disallow meddling with max_active for ordered workqueues */
-       if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
+       if (WARN_ON(wq->flags & __WQ_ORDERED))
                return;
 
        max_active = wq_clamp_max_active(max_active, wq->flags, wq->name);
 
        mutex_lock(&wq->mutex);
 
-       wq->flags &= ~__WQ_ORDERED;
        wq->saved_max_active = max_active;
+       if (wq->flags & WQ_UNBOUND)
+               wq->saved_min_active = min(wq->saved_min_active, max_active);
 
-       for_each_pwq(pwq, wq)
-               pwq_adjust_max_active(pwq);
+       wq_adjust_max_active(wq);
 
        mutex_unlock(&wq->mutex);
 }
 EXPORT_SYMBOL_GPL(workqueue_set_max_active);
 
+/**
+ * workqueue_set_min_active - adjust min_active of an unbound workqueue
+ * @wq: target unbound workqueue
+ * @min_active: new min_active value
+ *
+ * Set min_active of an unbound workqueue. Unlike other types of workqueues, an
+ * unbound workqueue is not guaranteed to be able to process max_active
+ * interdependent work items. Instead, an unbound workqueue is guaranteed to be
+ * able to process min_active number of interdependent work items which is
+ * %WQ_DFL_MIN_ACTIVE by default.
+ *
+ * Use this function to adjust the min_active value between 0 and the current
+ * max_active.
+ */
+void workqueue_set_min_active(struct workqueue_struct *wq, int min_active)
+{
+       /* min_active is only meaningful for non-ordered unbound workqueues */
+       if (WARN_ON((wq->flags & (WQ_BH | WQ_UNBOUND | __WQ_ORDERED)) !=
+                   WQ_UNBOUND))
+               return;
+
+       mutex_lock(&wq->mutex);
+       wq->saved_min_active = clamp(min_active, 0, wq->saved_max_active);
+       wq_adjust_max_active(wq);
+       mutex_unlock(&wq->mutex);
+}
+
 /**
  * current_work - retrieve %current task's work struct
  *
@@ -4972,7 +5880,7 @@ EXPORT_SYMBOL_GPL(workqueue_congested);
 unsigned int work_busy(struct work_struct *work)
 {
        struct worker_pool *pool;
-       unsigned long flags;
+       unsigned long irq_flags;
        unsigned int ret = 0;
 
        if (work_pending(work))
@@ -4981,10 +5889,10 @@ unsigned int work_busy(struct work_struct *work)
        rcu_read_lock();
        pool = get_work_pool(work);
        if (pool) {
-               raw_spin_lock_irqsave(&pool->lock, flags);
+               raw_spin_lock_irqsave(&pool->lock, irq_flags);
                if (find_worker_executing_work(pool, work))
                        ret |= WORK_BUSY_RUNNING;
-               raw_spin_unlock_irqrestore(&pool->lock, flags);
+               raw_spin_unlock_irqrestore(&pool->lock, irq_flags);
        }
        rcu_read_unlock();
 
@@ -5069,7 +5977,24 @@ static void pr_cont_pool_info(struct worker_pool *pool)
        pr_cont(" cpus=%*pbl", nr_cpumask_bits, pool->attrs->cpumask);
        if (pool->node != NUMA_NO_NODE)
                pr_cont(" node=%d", pool->node);
-       pr_cont(" flags=0x%x nice=%d", pool->flags, pool->attrs->nice);
+       pr_cont(" flags=0x%x", pool->flags);
+       if (pool->flags & POOL_BH)
+               pr_cont(" bh%s",
+                       pool->attrs->nice == HIGHPRI_NICE_LEVEL ? "-hi" : "");
+       else
+               pr_cont(" nice=%d", pool->attrs->nice);
+}
+
+static void pr_cont_worker_id(struct worker *worker)
+{
+       struct worker_pool *pool = worker->pool;
+
+       if (pool->flags & WQ_BH)
+               pr_cont("bh%s",
+                       pool->attrs->nice == HIGHPRI_NICE_LEVEL ? "-hi" : "");
+       else
+               pr_cont("%d%s", task_pid_nr(worker->task),
+                       worker->rescue_wq ? "(RESCUER)" : "");
 }
 
 struct pr_cont_work_struct {
@@ -5128,8 +6053,8 @@ static void show_pwq(struct pool_workqueue *pwq)
        pr_info("  pwq %d:", pool->id);
        pr_cont_pool_info(pool);
 
-       pr_cont(" active=%d/%d refcnt=%d%s\n",
-               pwq->nr_active, pwq->max_active, pwq->refcnt,
+       pr_cont(" active=%d refcnt=%d%s\n",
+               pwq->nr_active, pwq->refcnt,
                !list_empty(&pwq->mayday_node) ? " MAYDAY" : "");
 
        hash_for_each(pool->busy_hash, bkt, worker, hentry) {
@@ -5146,10 +6071,9 @@ static void show_pwq(struct pool_workqueue *pwq)
                        if (worker->current_pwq != pwq)
                                continue;
 
-                       pr_cont("%s %d%s:%ps", comma ? "," : "",
-                               task_pid_nr(worker->task),
-                               worker->rescue_wq ? "(RESCUER)" : "",
-                               worker->current_func);
+                       pr_cont(" %s", comma ? "," : "");
+                       pr_cont_worker_id(worker);
+                       pr_cont(":%ps", worker->current_func);
                        list_for_each_entry(work, &worker->scheduled, entry)
                                pr_cont_work(false, work, &pcws);
                        pr_cont_work_flush(comma, (work_func_t)-1L, &pcws);
@@ -5200,10 +6124,10 @@ void show_one_workqueue(struct workqueue_struct *wq)
 {
        struct pool_workqueue *pwq;
        bool idle = true;
-       unsigned long flags;
+       unsigned long irq_flags;
 
        for_each_pwq(pwq, wq) {
-               if (pwq->nr_active || !list_empty(&pwq->inactive_works)) {
+               if (!pwq_is_empty(pwq)) {
                        idle = false;
                        break;
                }
@@ -5214,8 +6138,8 @@ void show_one_workqueue(struct workqueue_struct *wq)
        pr_info("workqueue %s: flags=0x%x\n", wq->name, wq->flags);
 
        for_each_pwq(pwq, wq) {
-               raw_spin_lock_irqsave(&pwq->pool->lock, flags);
-               if (pwq->nr_active || !list_empty(&pwq->inactive_works)) {
+               raw_spin_lock_irqsave(&pwq->pool->lock, irq_flags);
+               if (!pwq_is_empty(pwq)) {
                        /*
                         * Defer printing to avoid deadlocks in console
                         * drivers that queue work while holding locks
@@ -5225,7 +6149,7 @@ void show_one_workqueue(struct workqueue_struct *wq)
                        show_pwq(pwq);
                        printk_deferred_exit();
                }
-               raw_spin_unlock_irqrestore(&pwq->pool->lock, flags);
+               raw_spin_unlock_irqrestore(&pwq->pool->lock, irq_flags);
                /*
                 * We could be printing a lot from atomic context, e.g.
                 * sysrq-t -> show_all_workqueues(). Avoid triggering
@@ -5244,10 +6168,10 @@ static void show_one_worker_pool(struct worker_pool *pool)
 {
        struct worker *worker;
        bool first = true;
-       unsigned long flags;
+       unsigned long irq_flags;
        unsigned long hung = 0;
 
-       raw_spin_lock_irqsave(&pool->lock, flags);
+       raw_spin_lock_irqsave(&pool->lock, irq_flags);
        if (pool->nr_workers == pool->nr_idle)
                goto next_pool;
 
@@ -5268,14 +6192,14 @@ static void show_one_worker_pool(struct worker_pool *pool)
                pr_cont(" manager: %d",
                        task_pid_nr(pool->manager->task));
        list_for_each_entry(worker, &pool->idle_list, entry) {
-               pr_cont(" %s%d", first ? "idle: " : "",
-                       task_pid_nr(worker->task));
+               pr_cont(" %s", first ? "idle: " : "");
+               pr_cont_worker_id(worker);
                first = false;
        }
        pr_cont("\n");
        printk_deferred_exit();
 next_pool:
-       raw_spin_unlock_irqrestore(&pool->lock, flags);
+       raw_spin_unlock_irqrestore(&pool->lock, irq_flags);
        /*
         * We could be printing a lot from atomic context, e.g.
         * sysrq-t -> show_all_workqueues(). Avoid triggering
@@ -5542,13 +6466,15 @@ int workqueue_online_cpu(unsigned int cpu)
        mutex_lock(&wq_pool_mutex);
 
        for_each_pool(pool, pi) {
-               mutex_lock(&wq_pool_attach_mutex);
+               /* BH pools aren't affected by hotplug */
+               if (pool->flags & POOL_BH)
+                       continue;
 
+               mutex_lock(&wq_pool_attach_mutex);
                if (pool->cpu == cpu)
                        rebind_workers(pool);
                else if (pool->cpu < 0)
                        restore_unbound_workers_cpumask(pool, cpu);
-
                mutex_unlock(&wq_pool_attach_mutex);
        }
 
@@ -5562,6 +6488,10 @@ int workqueue_online_cpu(unsigned int cpu)
 
                        for_each_cpu(tcpu, pt->pod_cpus[pt->cpu_pod[cpu]])
                                wq_update_pod(wq, tcpu, cpu, true);
+
+                       mutex_lock(&wq->mutex);
+                       wq_update_node_max_active(wq, -1);
+                       mutex_unlock(&wq->mutex);
                }
        }
 
@@ -5590,6 +6520,10 @@ int workqueue_offline_cpu(unsigned int cpu)
 
                        for_each_cpu(tcpu, pt->pod_cpus[pt->cpu_pod[cpu]])
                                wq_update_pod(wq, tcpu, cpu, false);
+
+                       mutex_lock(&wq->mutex);
+                       wq_update_node_max_active(wq, cpu);
+                       mutex_unlock(&wq->mutex);
                }
        }
        mutex_unlock(&wq_pool_mutex);
@@ -5677,7 +6611,6 @@ EXPORT_SYMBOL_GPL(work_on_cpu_safe_key);
 void freeze_workqueues_begin(void)
 {
        struct workqueue_struct *wq;
-       struct pool_workqueue *pwq;
 
        mutex_lock(&wq_pool_mutex);
 
@@ -5686,8 +6619,7 @@ void freeze_workqueues_begin(void)
 
        list_for_each_entry(wq, &workqueues, list) {
                mutex_lock(&wq->mutex);
-               for_each_pwq(pwq, wq)
-                       pwq_adjust_max_active(pwq);
+               wq_adjust_max_active(wq);
                mutex_unlock(&wq->mutex);
        }
 
@@ -5752,7 +6684,6 @@ out_unlock:
 void thaw_workqueues(void)
 {
        struct workqueue_struct *wq;
-       struct pool_workqueue *pwq;
 
        mutex_lock(&wq_pool_mutex);
 
@@ -5764,8 +6695,7 @@ void thaw_workqueues(void)
        /* restore max_active and repopulate worklist */
        list_for_each_entry(wq, &workqueues, list) {
                mutex_lock(&wq->mutex);
-               for_each_pwq(pwq, wq)
-                       pwq_adjust_max_active(pwq);
+               wq_adjust_max_active(wq);
                mutex_unlock(&wq->mutex);
        }
 
@@ -5784,16 +6714,9 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
        lockdep_assert_held(&wq_pool_mutex);
 
        list_for_each_entry(wq, &workqueues, list) {
-               if (!(wq->flags & WQ_UNBOUND))
+               if (!(wq->flags & WQ_UNBOUND) || (wq->flags & __WQ_DESTROYING))
                        continue;
 
-               /* creating multiple pwqs breaks ordering guarantee */
-               if (!list_empty(&wq->pwqs)) {
-                       if (wq->flags & __WQ_ORDERED_EXPLICIT)
-                               continue;
-                       wq->flags &= ~__WQ_ORDERED;
-               }
-
                ctx = apply_wqattrs_prepare(wq, wq->unbound_attrs, unbound_cpumask);
                if (IS_ERR(ctx)) {
                        ret = PTR_ERR(ctx);
@@ -6307,11 +7230,10 @@ int workqueue_sysfs_register(struct workqueue_struct *wq)
        int ret;
 
        /*
-        * Adjusting max_active or creating new pwqs by applying
-        * attributes breaks ordering guarantee.  Disallow exposing ordered
-        * workqueues.
+        * Adjusting max_active breaks ordering guarantee.  Disallow exposing
+        * ordered workqueues.
         */
-       if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
+       if (WARN_ON(wq->flags & __WQ_ORDERED))
                return -EINVAL;
 
        wq->wq_dev = wq_dev = kzalloc(sizeof(*wq_dev), GFP_KERNEL);
@@ -6408,10 +7330,10 @@ static DEFINE_PER_CPU(unsigned long, wq_watchdog_touched_cpu) = INITIAL_JIFFIES;
 static void show_cpu_pool_hog(struct worker_pool *pool)
 {
        struct worker *worker;
-       unsigned long flags;
+       unsigned long irq_flags;
        int bkt;
 
-       raw_spin_lock_irqsave(&pool->lock, flags);
+       raw_spin_lock_irqsave(&pool->lock, irq_flags);
 
        hash_for_each(pool->busy_hash, bkt, worker, hentry) {
                if (task_is_running(worker->task)) {
@@ -6429,7 +7351,7 @@ static void show_cpu_pool_hog(struct worker_pool *pool)
                }
        }
 
-       raw_spin_unlock_irqrestore(&pool->lock, flags);
+       raw_spin_unlock_irqrestore(&pool->lock, irq_flags);
 }
 
 static void show_cpu_pools_hogs(void)
@@ -6501,7 +7423,7 @@ static void wq_watchdog_timer_fn(struct timer_list *unused)
                /* did we stall? */
                if (time_after(now, ts + thresh)) {
                        lockup_detected = true;
-                       if (pool->cpu >= 0) {
+                       if (pool->cpu >= 0 && !(pool->flags & POOL_BH)) {
                                pool->cpu_stall = true;
                                cpu_pool_stall = true;
                        }
@@ -6584,6 +7506,16 @@ static inline void wq_watchdog_init(void) { }
 
 #endif /* CONFIG_WQ_WATCHDOG */
 
+static void bh_pool_kick_normal(struct irq_work *irq_work)
+{
+       raise_softirq_irqoff(TASKLET_SOFTIRQ);
+}
+
+static void bh_pool_kick_highpri(struct irq_work *irq_work)
+{
+       raise_softirq_irqoff(HI_SOFTIRQ);
+}
+
 static void __init restrict_unbound_cpumask(const char *name, const struct cpumask *mask)
 {
        if (!cpumask_intersects(wq_unbound_cpumask, mask)) {
@@ -6595,6 +7527,22 @@ static void __init restrict_unbound_cpumask(const char *name, const struct cpuma
        cpumask_and(wq_unbound_cpumask, wq_unbound_cpumask, mask);
 }
 
+static void __init init_cpu_worker_pool(struct worker_pool *pool, int cpu, int nice)
+{
+       BUG_ON(init_worker_pool(pool));
+       pool->cpu = cpu;
+       cpumask_copy(pool->attrs->cpumask, cpumask_of(cpu));
+       cpumask_copy(pool->attrs->__pod_cpumask, cpumask_of(cpu));
+       pool->attrs->nice = nice;
+       pool->attrs->affn_strict = true;
+       pool->node = cpu_to_node(cpu);
+
+       /* alloc pool ID */
+       mutex_lock(&wq_pool_mutex);
+       BUG_ON(worker_pool_assign_id(pool));
+       mutex_unlock(&wq_pool_mutex);
+}
+
 /**
  * workqueue_init_early - early init for workqueue subsystem
  *
@@ -6609,6 +7557,8 @@ void __init workqueue_init_early(void)
 {
        struct wq_pod_type *pt = &wq_pod_types[WQ_AFFN_SYSTEM];
        int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL };
+       void (*irq_work_fns[2])(struct irq_work *) = { bh_pool_kick_normal,
+                                                      bh_pool_kick_highpri };
        int i, cpu;
 
        BUILD_BUG_ON(__alignof__(struct pool_workqueue) < __alignof__(long long));
@@ -6630,6 +7580,13 @@ void __init workqueue_init_early(void)
        wq_update_pod_attrs_buf = alloc_workqueue_attrs();
        BUG_ON(!wq_update_pod_attrs_buf);
 
+       /*
+        * If nohz_full is enabled, set power efficient workqueue as unbound.
+        * This allows workqueue items to be moved to HK CPUs.
+        */
+       if (housekeeping_enabled(HK_TYPE_TICK))
+               wq_power_efficient = true;
+
        /* initialize WQ_AFFN_SYSTEM pods */
        pt->pod_cpus = kcalloc(1, sizeof(pt->pod_cpus[0]), GFP_KERNEL);
        pt->pod_node = kcalloc(1, sizeof(pt->pod_node[0]), GFP_KERNEL);
@@ -6643,25 +7600,21 @@ void __init workqueue_init_early(void)
        pt->pod_node[0] = NUMA_NO_NODE;
        pt->cpu_pod[0] = 0;
 
-       /* initialize CPU pools */
+       /* initialize BH and CPU pools */
        for_each_possible_cpu(cpu) {
                struct worker_pool *pool;
 
                i = 0;
-               for_each_cpu_worker_pool(pool, cpu) {
-                       BUG_ON(init_worker_pool(pool));
-                       pool->cpu = cpu;
-                       cpumask_copy(pool->attrs->cpumask, cpumask_of(cpu));
-                       cpumask_copy(pool->attrs->__pod_cpumask, cpumask_of(cpu));
-                       pool->attrs->nice = std_nice[i++];
-                       pool->attrs->affn_strict = true;
-                       pool->node = cpu_to_node(cpu);
-
-                       /* alloc pool ID */
-                       mutex_lock(&wq_pool_mutex);
-                       BUG_ON(worker_pool_assign_id(pool));
-                       mutex_unlock(&wq_pool_mutex);
+               for_each_bh_worker_pool(pool, cpu) {
+                       init_cpu_worker_pool(pool, cpu, std_nice[i]);
+                       pool->flags |= POOL_BH;
+                       init_irq_work(bh_pool_irq_work(pool), irq_work_fns[i]);
+                       i++;
                }
+
+               i = 0;
+               for_each_cpu_worker_pool(pool, cpu)
+                       init_cpu_worker_pool(pool, cpu, std_nice[i++]);
        }
 
        /* create default unbound and ordered wq attrs */
@@ -6691,13 +7644,17 @@ void __init workqueue_init_early(void)
                                              WQ_FREEZABLE, 0);
        system_power_efficient_wq = alloc_workqueue("events_power_efficient",
                                              WQ_POWER_EFFICIENT, 0);
-       system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_power_efficient",
+       system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_pwr_efficient",
                                              WQ_FREEZABLE | WQ_POWER_EFFICIENT,
                                              0);
+       system_bh_wq = alloc_workqueue("events_bh", WQ_BH, 0);
+       system_bh_highpri_wq = alloc_workqueue("events_bh_highpri",
+                                              WQ_BH | WQ_HIGHPRI, 0);
        BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq ||
               !system_unbound_wq || !system_freezable_wq ||
               !system_power_efficient_wq ||
-              !system_freezable_power_efficient_wq);
+              !system_freezable_power_efficient_wq ||
+              !system_bh_wq || !system_bh_highpri_wq);
 }
 
 static void __init wq_cpu_intensive_thresh_init(void)
@@ -6763,9 +7720,10 @@ void __init workqueue_init(void)
         * up. Also, create a rescuer for workqueues that requested it.
         */
        for_each_possible_cpu(cpu) {
-               for_each_cpu_worker_pool(pool, cpu) {
+               for_each_bh_worker_pool(pool, cpu)
+                       pool->node = cpu_to_node(cpu);
+               for_each_cpu_worker_pool(pool, cpu)
                        pool->node = cpu_to_node(cpu);
-               }
        }
 
        list_for_each_entry(wq, &workqueues, list) {
@@ -6776,7 +7734,16 @@ void __init workqueue_init(void)
 
        mutex_unlock(&wq_pool_mutex);
 
-       /* create the initial workers */
+       /*
+        * Create the initial workers. A BH pool has one pseudo worker that
+        * represents the shared BH execution context and thus doesn't get
+        * affected by hotplug events. Create the BH pseudo workers for all
+        * possible CPUs here.
+        */
+       for_each_possible_cpu(cpu)
+               for_each_bh_worker_pool(pool, cpu)
+                       BUG_ON(!create_worker(pool));
+
        for_each_online_cpu(cpu) {
                for_each_cpu_worker_pool(pool, cpu) {
                        pool->flags &= ~POOL_DISASSOCIATED;
@@ -6856,7 +7823,7 @@ static bool __init cpus_share_numa(int cpu0, int cpu1)
 /**
  * workqueue_init_topology - initialize CPU pods for unbound workqueues
  *
- * This is the third step of there-staged workqueue subsystem initialization and
+ * This is the third step of three-staged workqueue subsystem initialization and
  * invoked after SMP and topology information are fully initialized. It
  * initializes the unbound CPU pods accordingly.
  */
@@ -6870,6 +7837,8 @@ void __init workqueue_init_topology(void)
        init_pod_type(&wq_pod_types[WQ_AFFN_CACHE], cpus_share_cache);
        init_pod_type(&wq_pod_types[WQ_AFFN_NUMA], cpus_share_numa);
 
+       wq_topo_initialized = true;
+
        mutex_lock(&wq_pool_mutex);
 
        /*
@@ -6878,8 +7847,12 @@ void __init workqueue_init_topology(void)
         * combinations to apply per-pod sharing.
         */
        list_for_each_entry(wq, &workqueues, list) {
-               for_each_online_cpu(cpu) {
+               for_each_online_cpu(cpu)
                        wq_update_pod(wq, cpu, cpu, true);
+               if (wq->flags & WQ_UNBOUND) {
+                       mutex_lock(&wq->mutex);
+                       wq_update_node_max_active(wq, -1);
+                       mutex_unlock(&wq->mutex);
                }
        }
 
index 975a07f9f1cc08838d272f83d5f04a85ff2f5cd2..6c596e65de8ae121271aea42bb4f165bac88dbd6 100644 (file)
@@ -1303,7 +1303,7 @@ config PROVE_LOCKING
        select DEBUG_SPINLOCK
        select DEBUG_MUTEXES if !PREEMPT_RT
        select DEBUG_RT_MUTEXES if RT_MUTEXES
-       select DEBUG_RWSEMS
+       select DEBUG_RWSEMS if !PREEMPT_RT
        select DEBUG_WW_MUTEX_SLOWPATH
        select DEBUG_LOCK_ALLOC
        select PREEMPT_COUNT if !ARCH_NO_PREEMPT
@@ -1426,7 +1426,7 @@ config DEBUG_WW_MUTEX_SLOWPATH
 
 config DEBUG_RWSEMS
        bool "RW Semaphore debugging: basic checks"
-       depends on DEBUG_KERNEL
+       depends on DEBUG_KERNEL && !PREEMPT_RT
        help
          This debugging feature allows mismatched rw semaphore locks
          and unlocks to be detected and reported.
@@ -2235,6 +2235,7 @@ config TEST_DIV64
 config TEST_IOV_ITER
        tristate "Test iov_iter operation" if !KUNIT_ALL_TESTS
        depends on KUNIT
+       depends on MMU
        default KUNIT_ALL_TESTS
        help
          Enable this to turn on testing of the operation of the I/O iterator
@@ -2857,28 +2858,6 @@ config TEST_MEMCAT_P
 
          If unsure, say N.
 
-config TEST_LIVEPATCH
-       tristate "Test livepatching"
-       default n
-       depends on DYNAMIC_DEBUG
-       depends on LIVEPATCH
-       depends on m
-       help
-         Test kernel livepatching features for correctness.  The tests will
-         load test modules that will be livepatched in various scenarios.
-
-         To run all the livepatching tests:
-
-         make -C tools/testing/selftests TARGETS=livepatch run_tests
-
-         Alternatively, individual tests may be invoked:
-
-         tools/testing/selftests/livepatch/test-callbacks.sh
-         tools/testing/selftests/livepatch/test-livepatch.sh
-         tools/testing/selftests/livepatch/test-shadow-vars.sh
-
-         If unsure, say N.
-
 config TEST_OBJAGG
        tristate "Perform selftest on object aggreration manager"
        default n
index 6b09731d8e6195603aab99a3fd3f5dc56331f567..95ed57f377fd9b9493d25bc9e7dd4681d86c75c6 100644 (file)
@@ -134,8 +134,6 @@ endif
 obj-$(CONFIG_TEST_FPU) += test_fpu.o
 CFLAGS_test_fpu.o += $(FPU_CFLAGS)
 
-obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/
-
 # Some KUnit files (hooks.o) need to be built-in even when KUnit is a module,
 # so we can't just use obj-$(CONFIG_KUNIT).
 ifdef CONFIG_KUNIT
index 225bb77014600f796e972a9c0f03638c23750a06..bf70850035c76f468c7c0af023454bf5bc6716e3 100644 (file)
@@ -215,7 +215,7 @@ static const u32 init_sums_no_overflow[] = {
        0xffff0000, 0xfffffffb,
 };
 
-static const __sum16 expected_csum_ipv6_magic[] = {
+static const u16 expected_csum_ipv6_magic[] = {
        0x18d4, 0x3085, 0x2e4b, 0xd9f4, 0xbdc8, 0x78f,  0x1034, 0x8422, 0x6fc0,
        0xd2f6, 0xbeb5, 0x9d3,  0x7e2a, 0x312e, 0x778e, 0xc1bb, 0x7cf2, 0x9d1e,
        0xca21, 0xf3ff, 0x7569, 0xb02e, 0xca86, 0x7e76, 0x4539, 0x45e3, 0xf28d,
@@ -241,7 +241,7 @@ static const __sum16 expected_csum_ipv6_magic[] = {
        0x3845, 0x1014
 };
 
-static const __sum16 expected_fast_csum[] = {
+static const u16 expected_fast_csum[] = {
        0xda83, 0x45da, 0x4f46, 0x4e4f, 0x34e,  0xe902, 0xa5e9, 0x87a5, 0x7187,
        0x5671, 0xf556, 0x6df5, 0x816d, 0x8f81, 0xbb8f, 0xfbba, 0x5afb, 0xbe5a,
        0xedbe, 0xabee, 0x6aac, 0xe6b,  0xea0d, 0x67ea, 0x7e68, 0x8a7e, 0x6f8a,
@@ -577,7 +577,8 @@ static void test_csum_no_carry_inputs(struct kunit *test)
 
 static void test_ip_fast_csum(struct kunit *test)
 {
-       __sum16 csum_result, expected;
+       __sum16 csum_result;
+       u16 expected;
 
        for (int len = IPv4_MIN_WORDS; len < IPv4_MAX_WORDS; len++) {
                for (int index = 0; index < NUM_IP_FAST_CSUM_TESTS; index++) {
@@ -586,7 +587,7 @@ static void test_ip_fast_csum(struct kunit *test)
                                expected_fast_csum[(len - IPv4_MIN_WORDS) *
                                                   NUM_IP_FAST_CSUM_TESTS +
                                                   index];
-                       CHECK_EQ(expected, csum_result);
+                       CHECK_EQ(to_sum16(expected), csum_result);
                }
        }
 }
@@ -598,7 +599,7 @@ static void test_csum_ipv6_magic(struct kunit *test)
        const struct in6_addr *daddr;
        unsigned int len;
        unsigned char proto;
-       unsigned int csum;
+       __wsum csum;
 
        const int daddr_offset = sizeof(struct in6_addr);
        const int len_offset = sizeof(struct in6_addr) + sizeof(struct in6_addr);
@@ -611,10 +612,10 @@ static void test_csum_ipv6_magic(struct kunit *test)
                saddr = (const struct in6_addr *)(random_buf + i);
                daddr = (const struct in6_addr *)(random_buf + i +
                                                  daddr_offset);
-               len = *(unsigned int *)(random_buf + i + len_offset);
+               len = le32_to_cpu(*(__le32 *)(random_buf + i + len_offset));
                proto = *(random_buf + i + proto_offset);
-               csum = *(unsigned int *)(random_buf + i + csum_offset);
-               CHECK_EQ(expected_csum_ipv6_magic[i],
+               csum = *(__wsum *)(random_buf + i + csum_offset);
+               CHECK_EQ(to_sum16(expected_csum_ipv6_magic[i]),
                         csum_ipv6_magic(saddr, daddr, len, proto, csum));
        }
 #endif /* !CONFIG_NET */
index d4572dbc914539a56c8b2a6da5ab101a9e11d80d..705b82736be0890de9417ca62233479eb3999cd9 100644 (file)
@@ -124,7 +124,7 @@ static void cmdline_do_one_range_test(struct kunit *test, const char *in,
                            n, e[0], r[0]);
 
        p = memchr_inv(&r[1], 0, sizeof(r) - sizeof(r[0]));
-       KUNIT_EXPECT_PTR_EQ_MSG(test, p, NULL, "in test %u at %u out of bound", n, p - r);
+       KUNIT_EXPECT_PTR_EQ_MSG(test, p, NULL, "in test %u at %td out of bound", n, p - r);
 }
 
 static void cmdline_test_range(struct kunit *test)
index e0aa6b440ca5f4a4f3560100985e39c068c7a6a8..4a6a9f419bd7eb8cf1370eed5f42c98eb6914f3e 100644 (file)
@@ -166,7 +166,6 @@ void iov_iter_init(struct iov_iter *i, unsigned int direction,
        WARN_ON(direction & ~(READ | WRITE));
        *i = (struct iov_iter) {
                .iter_type = ITER_IOVEC,
-               .copy_mc = false,
                .nofault = false,
                .data_source = direction,
                .__iov = iov,
@@ -244,27 +243,9 @@ size_t _copy_mc_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
 EXPORT_SYMBOL_GPL(_copy_mc_to_iter);
 #endif /* CONFIG_ARCH_HAS_COPY_MC */
 
-static __always_inline
-size_t memcpy_from_iter_mc(void *iter_from, size_t progress,
-                          size_t len, void *to, void *priv2)
-{
-       return copy_mc_to_kernel(to + progress, iter_from, len);
-}
-
-static size_t __copy_from_iter_mc(void *addr, size_t bytes, struct iov_iter *i)
-{
-       if (unlikely(i->count < bytes))
-               bytes = i->count;
-       if (unlikely(!bytes))
-               return 0;
-       return iterate_bvec(i, bytes, addr, NULL, memcpy_from_iter_mc);
-}
-
 static __always_inline
 size_t __copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
 {
-       if (unlikely(iov_iter_is_copy_mc(i)))
-               return __copy_from_iter_mc(addr, bytes, i);
        return iterate_and_advance(i, bytes, addr,
                                   copy_from_user_iter, memcpy_from_iter);
 }
@@ -633,7 +614,6 @@ void iov_iter_kvec(struct iov_iter *i, unsigned int direction,
        WARN_ON(direction & ~(READ | WRITE));
        *i = (struct iov_iter){
                .iter_type = ITER_KVEC,
-               .copy_mc = false,
                .data_source = direction,
                .kvec = kvec,
                .nr_segs = nr_segs,
@@ -650,7 +630,6 @@ void iov_iter_bvec(struct iov_iter *i, unsigned int direction,
        WARN_ON(direction & ~(READ | WRITE));
        *i = (struct iov_iter){
                .iter_type = ITER_BVEC,
-               .copy_mc = false,
                .data_source = direction,
                .bvec = bvec,
                .nr_segs = nr_segs,
@@ -679,7 +658,6 @@ void iov_iter_xarray(struct iov_iter *i, unsigned int direction,
        BUG_ON(direction & ~1);
        *i = (struct iov_iter) {
                .iter_type = ITER_XARRAY,
-               .copy_mc = false,
                .data_source = direction,
                .xarray = xarray,
                .xarray_start = start,
@@ -703,7 +681,6 @@ void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count)
        BUG_ON(direction != READ);
        *i = (struct iov_iter){
                .iter_type = ITER_DISCARD,
-               .copy_mc = false,
                .data_source = false,
                .count = count,
                .iov_offset = 0
@@ -714,12 +691,11 @@ EXPORT_SYMBOL(iov_iter_discard);
 static bool iov_iter_aligned_iovec(const struct iov_iter *i, unsigned addr_mask,
                                   unsigned len_mask)
 {
+       const struct iovec *iov = iter_iov(i);
        size_t size = i->count;
        size_t skip = i->iov_offset;
-       unsigned k;
 
-       for (k = 0; k < i->nr_segs; k++, skip = 0) {
-               const struct iovec *iov = iter_iov(i) + k;
+       do {
                size_t len = iov->iov_len - skip;
 
                if (len > size)
@@ -729,34 +705,36 @@ static bool iov_iter_aligned_iovec(const struct iov_iter *i, unsigned addr_mask,
                if ((unsigned long)(iov->iov_base + skip) & addr_mask)
                        return false;
 
+               iov++;
                size -= len;
-               if (!size)
-                       break;
-       }
+               skip = 0;
+       } while (size);
+
        return true;
 }
 
 static bool iov_iter_aligned_bvec(const struct iov_iter *i, unsigned addr_mask,
                                  unsigned len_mask)
 {
-       size_t size = i->count;
+       const struct bio_vec *bvec = i->bvec;
        unsigned skip = i->iov_offset;
-       unsigned k;
+       size_t size = i->count;
 
-       for (k = 0; k < i->nr_segs; k++, skip = 0) {
-               size_t len = i->bvec[k].bv_len - skip;
+       do {
+               size_t len = bvec->bv_len;
 
                if (len > size)
                        len = size;
                if (len & len_mask)
                        return false;
-               if ((unsigned long)(i->bvec[k].bv_offset + skip) & addr_mask)
+               if ((unsigned long)(bvec->bv_offset + skip) & addr_mask)
                        return false;
 
+               bvec++;
                size -= len;
-               if (!size)
-                       break;
-       }
+               skip = 0;
+       } while (size);
+
        return true;
 }
 
@@ -800,13 +778,12 @@ EXPORT_SYMBOL_GPL(iov_iter_is_aligned);
 
 static unsigned long iov_iter_alignment_iovec(const struct iov_iter *i)
 {
+       const struct iovec *iov = iter_iov(i);
        unsigned long res = 0;
        size_t size = i->count;
        size_t skip = i->iov_offset;
-       unsigned k;
 
-       for (k = 0; k < i->nr_segs; k++, skip = 0) {
-               const struct iovec *iov = iter_iov(i) + k;
+       do {
                size_t len = iov->iov_len - skip;
                if (len) {
                        res |= (unsigned long)iov->iov_base + skip;
@@ -814,30 +791,31 @@ static unsigned long iov_iter_alignment_iovec(const struct iov_iter *i)
                                len = size;
                        res |= len;
                        size -= len;
-                       if (!size)
-                               break;
                }
-       }
+               iov++;
+               skip = 0;
+       } while (size);
        return res;
 }
 
 static unsigned long iov_iter_alignment_bvec(const struct iov_iter *i)
 {
+       const struct bio_vec *bvec = i->bvec;
        unsigned res = 0;
        size_t size = i->count;
        unsigned skip = i->iov_offset;
-       unsigned k;
 
-       for (k = 0; k < i->nr_segs; k++, skip = 0) {
-               size_t len = i->bvec[k].bv_len - skip;
-               res |= (unsigned long)i->bvec[k].bv_offset + skip;
+       do {
+               size_t len = bvec->bv_len - skip;
+               res |= (unsigned long)bvec->bv_offset + skip;
                if (len > size)
                        len = size;
                res |= len;
+               bvec++;
                size -= len;
-               if (!size)
-                       break;
-       }
+               skip = 0;
+       } while (size);
+
        return res;
 }
 
@@ -1166,11 +1144,12 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
 EXPORT_SYMBOL(dup_iter);
 
 static __noclone int copy_compat_iovec_from_user(struct iovec *iov,
-               const struct iovec __user *uvec, unsigned long nr_segs)
+               const struct iovec __user *uvec, u32 nr_segs)
 {
        const struct compat_iovec __user *uiov =
                (const struct compat_iovec __user *)uvec;
-       int ret = -EFAULT, i;
+       int ret = -EFAULT;
+       u32 i;
 
        if (!user_access_begin(uiov, nr_segs * sizeof(*uiov)))
                return -EFAULT;
index 59dbcbdb1c916d93dcbcbb3b97911098ef9420a7..72fa20f405f1520a63dd50d9aa37f6609306eb3e 100644 (file)
@@ -74,10 +74,12 @@ static int create_dir(struct kobject *kobj)
        if (error)
                return error;
 
-       error = sysfs_create_groups(kobj, ktype->default_groups);
-       if (error) {
-               sysfs_remove_dir(kobj);
-               return error;
+       if (ktype) {
+               error = sysfs_create_groups(kobj, ktype->default_groups);
+               if (error) {
+                       sysfs_remove_dir(kobj);
+                       return error;
+               }
        }
 
        /*
@@ -589,7 +591,8 @@ static void __kobject_del(struct kobject *kobj)
        sd = kobj->sd;
        ktype = get_ktype(kobj);
 
-       sysfs_remove_groups(kobj, ktype->default_groups);
+       if (ktype)
+               sysfs_remove_groups(kobj, ktype->default_groups);
 
        /* send "remove" if the caller did not do it but sent "add" */
        if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) {
@@ -666,6 +669,10 @@ static void kobject_cleanup(struct kobject *kobj)
        pr_debug("'%s' (%p): %s, parent %p\n",
                 kobject_name(kobj), kobj, __func__, kobj->parent);
 
+       if (t && !t->release)
+               pr_debug("'%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n",
+                        kobject_name(kobj), kobj);
+
        /* remove from sysfs if the caller did not do it */
        if (kobj->state_in_sysfs) {
                pr_debug("'%s' (%p): auto cleanup kobject_del\n",
@@ -676,13 +683,10 @@ static void kobject_cleanup(struct kobject *kobj)
                parent = NULL;
        }
 
-       if (t->release) {
+       if (t && t->release) {
                pr_debug("'%s' (%p): calling ktype release\n",
                         kobject_name(kobj), kobj);
                t->release(kobj);
-       } else {
-               pr_debug("'%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n",
-                        kobject_name(kobj), kobj);
        }
 
        /* free name if we allocated it */
@@ -1056,7 +1060,7 @@ const struct kobj_ns_type_operations *kobj_child_ns_ops(const struct kobject *pa
 {
        const struct kobj_ns_type_operations *ops = NULL;
 
-       if (parent && parent->ktype->child_ns_type)
+       if (parent && parent->ktype && parent->ktype->child_ns_type)
                ops = parent->ktype->child_ns_type(parent);
 
        return ops;
index 54bd558364053c2eb5437e0bf5b94da6cdfba0e1..5fcd48ff0f36a37415c67cf2223cdf7ffeaef794 100644 (file)
@@ -13,5 +13,7 @@
 
 // For internal use only -- registers the kunit_bus.
 int kunit_bus_init(void);
+// For internal use only -- unregisters the kunit_bus.
+void kunit_bus_shutdown(void);
 
 #endif //_KUNIT_DEVICE_IMPL_H
index 074c6dd2e36a7d9e8154a604db7c2a8e4f669921..abc603730b8ea4e55e320419b671130a2266f0a3 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/dma-mapping.h>
 
 #include <kunit/test.h>
 #include <kunit/device.h>
@@ -35,7 +36,7 @@ struct kunit_device {
 
 #define to_kunit_device(d) container_of_const(d, struct kunit_device, dev)
 
-static struct bus_type kunit_bus_type = {
+static const struct bus_type kunit_bus_type = {
        .name           = "kunit",
 };
 
@@ -54,6 +55,20 @@ int kunit_bus_init(void)
        return error;
 }
 
+/* Unregister the 'kunit_bus' in case the KUnit module is unloaded. */
+void kunit_bus_shutdown(void)
+{
+       /* Make sure the bus exists before we unregister it. */
+       if (IS_ERR_OR_NULL(kunit_bus_device))
+               return;
+
+       bus_unregister(&kunit_bus_type);
+
+       root_device_unregister(kunit_bus_device);
+
+       kunit_bus_device = NULL;
+}
+
 /* Release a 'fake' KUnit device. */
 static void kunit_device_release(struct device *d)
 {
@@ -119,6 +134,9 @@ static struct kunit_device *kunit_device_register_internal(struct kunit *test,
                return ERR_PTR(err);
        }
 
+       kunit_dev->dev.dma_mask = &kunit_dev->dev.coherent_dma_mask;
+       kunit_dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
        kunit_add_action(test, device_unregister_wrapper, &kunit_dev->dev);
 
        return kunit_dev;
index 689fff2b2b106a597bbf9b2e473d37e193537b03..70b9a43cd2571620f8f7d3d12dd72c736e3741ab 100644 (file)
@@ -33,13 +33,13 @@ static char *filter_glob_param;
 static char *filter_param;
 static char *filter_action_param;
 
-module_param_named(filter_glob, filter_glob_param, charp, 0400);
+module_param_named(filter_glob, filter_glob_param, charp, 0600);
 MODULE_PARM_DESC(filter_glob,
                "Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test");
-module_param_named(filter, filter_param, charp, 0400);
+module_param_named(filter, filter_param, charp, 0600);
 MODULE_PARM_DESC(filter,
                "Filter which KUnit test suites/tests run at boot-time using attributes, e.g. speed>slow");
-module_param_named(filter_action, filter_action_param, charp, 0400);
+module_param_named(filter_action, filter_action_param, charp, 0600);
 MODULE_PARM_DESC(filter_action,
                "Changes behavior of filtered tests using attributes, valid values are:\n"
                "<none>: do not run filtered tests as normal\n"
index 22d4ee86dbedde1c477ee1cd1ed68cbc2b999d23..3f7f967e3688ee0de7e0e883c858bee2c2e9f683 100644 (file)
@@ -129,7 +129,7 @@ static void parse_filter_attr_test(struct kunit *test)
                        GFP_KERNEL);
        for (j = 0; j < filter_count; j++) {
                parsed_filters[j] = kunit_next_attr_filter(&filter, &err);
-               KUNIT_ASSERT_EQ_MSG(test, err, 0, "failed to parse filter '%s'", filters[j]);
+               KUNIT_ASSERT_EQ_MSG(test, err, 0, "failed to parse filter from '%s'", filters);
        }
 
        KUNIT_EXPECT_STREQ(test, kunit_attr_filter_name(parsed_filters[0]), "speed");
index 31a5a992e64670f35a9717659f99ca1b385d5f2e..1d1475578515c261fe74b454502f1a2a5ac3bb81 100644 (file)
@@ -928,6 +928,9 @@ static void __exit kunit_exit(void)
 #ifdef CONFIG_MODULES
        unregister_module_notifier(&kunit_mod_nb);
 #endif
+
+       kunit_bus_shutdown();
+
        kunit_debugfs_cleanup();
 }
 module_exit(kunit_exit);
diff --git a/lib/livepatch/Makefile b/lib/livepatch/Makefile
deleted file mode 100644 (file)
index dcc912b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for livepatch test code.
-
-obj-$(CONFIG_TEST_LIVEPATCH) += test_klp_atomic_replace.o \
-                               test_klp_callbacks_demo.o \
-                               test_klp_callbacks_demo2.o \
-                               test_klp_callbacks_busy.o \
-                               test_klp_callbacks_mod.o \
-                               test_klp_livepatch.o \
-                               test_klp_shadow_vars.o \
-                               test_klp_state.o \
-                               test_klp_state2.o \
-                               test_klp_state3.o
index 6f241bb38799201defb1b31154920dcc257b9831..af097028872722f4e3a0225f5ca4adb9097c3f39 100644 (file)
@@ -4290,6 +4290,56 @@ exists:
 
 }
 
+/**
+ * mas_alloc_cyclic() - Internal call to find somewhere to store an entry
+ * @mas: The maple state.
+ * @startp: Pointer to ID.
+ * @range_lo: Lower bound of range to search.
+ * @range_hi: Upper bound of range to search.
+ * @entry: The entry to store.
+ * @next: Pointer to next ID to allocate.
+ * @gfp: The GFP_FLAGS to use for allocations.
+ *
+ * Return: 0 if the allocation succeeded without wrapping, 1 if the
+ * allocation succeeded after wrapping, or -EBUSY if there are no
+ * free entries.
+ */
+int mas_alloc_cyclic(struct ma_state *mas, unsigned long *startp,
+               void *entry, unsigned long range_lo, unsigned long range_hi,
+               unsigned long *next, gfp_t gfp)
+{
+       unsigned long min = range_lo;
+       int ret = 0;
+
+       range_lo = max(min, *next);
+       ret = mas_empty_area(mas, range_lo, range_hi, 1);
+       if ((mas->tree->ma_flags & MT_FLAGS_ALLOC_WRAPPED) && ret == 0) {
+               mas->tree->ma_flags &= ~MT_FLAGS_ALLOC_WRAPPED;
+               ret = 1;
+       }
+       if (ret < 0 && range_lo > min) {
+               ret = mas_empty_area(mas, min, range_hi, 1);
+               if (ret == 0)
+                       ret = 1;
+       }
+       if (ret < 0)
+               return ret;
+
+       do {
+               mas_insert(mas, entry);
+       } while (mas_nomem(mas, gfp));
+       if (mas_is_err(mas))
+               return xa_err(mas->node);
+
+       *startp = mas->index;
+       *next = *startp + 1;
+       if (*next == 0)
+               mas->tree->ma_flags |= MT_FLAGS_ALLOC_WRAPPED;
+
+       return ret;
+}
+EXPORT_SYMBOL(mas_alloc_cyclic);
+
 static __always_inline void mas_rewalk(struct ma_state *mas, unsigned long index)
 {
 retry:
@@ -6443,6 +6493,49 @@ unlock:
 }
 EXPORT_SYMBOL(mtree_alloc_range);
 
+/**
+ * mtree_alloc_cyclic() - Find somewhere to store this entry in the tree.
+ * @mt: The maple tree.
+ * @startp: Pointer to ID.
+ * @range_lo: Lower bound of range to search.
+ * @range_hi: Upper bound of range to search.
+ * @entry: The entry to store.
+ * @next: Pointer to next ID to allocate.
+ * @gfp: The GFP_FLAGS to use for allocations.
+ *
+ * Finds an empty entry in @mt after @next, stores the new index into
+ * the @id pointer, stores the entry at that index, then updates @next.
+ *
+ * @mt must be initialized with the MT_FLAGS_ALLOC_RANGE flag.
+ *
+ * Context: Any context.  Takes and releases the mt.lock.  May sleep if
+ * the @gfp flags permit.
+ *
+ * Return: 0 if the allocation succeeded without wrapping, 1 if the
+ * allocation succeeded after wrapping, -ENOMEM if memory could not be
+ * allocated, -EINVAL if @mt cannot be used, or -EBUSY if there are no
+ * free entries.
+ */
+int mtree_alloc_cyclic(struct maple_tree *mt, unsigned long *startp,
+               void *entry, unsigned long range_lo, unsigned long range_hi,
+               unsigned long *next, gfp_t gfp)
+{
+       int ret;
+
+       MA_STATE(mas, mt, 0, 0);
+
+       if (!mt_is_alloc(mt))
+               return -EINVAL;
+       if (WARN_ON_ONCE(mt_is_reserved(entry)))
+               return -EINVAL;
+       mtree_lock(mt);
+       ret = mas_alloc_cyclic(&mas, startp, entry, range_lo, range_hi,
+                              next, gfp);
+       mtree_unlock(mt);
+       return ret;
+}
+EXPORT_SYMBOL(mtree_alloc_cyclic);
+
 int mtree_alloc_rrange(struct maple_tree *mt, unsigned long *startp,
                void *entry, unsigned long size, unsigned long min,
                unsigned long max, gfp_t gfp)
index 440aee705cccab09a616870b5fb4640ad6f2b7cd..30e00ef0bf2e0f8e407a97ef555f8aa4f648dac3 100644 (file)
@@ -32,7 +32,7 @@ struct some_bytes {
        BUILD_BUG_ON(sizeof(instance.data) != 32);      \
        for (size_t i = 0; i < sizeof(instance.data); i++) {    \
                KUNIT_ASSERT_EQ_MSG(test, instance.data[i], v, \
-                       "line %d: '%s' not initialized to 0x%02x @ %d (saw 0x%02x)\n", \
+                       "line %d: '%s' not initialized to 0x%02x @ %zu (saw 0x%02x)\n", \
                        __LINE__, #instance, v, i, instance.data[i]);   \
        }       \
 } while (0)
@@ -41,7 +41,7 @@ struct some_bytes {
        BUILD_BUG_ON(sizeof(one) != sizeof(two)); \
        for (size_t i = 0; i < sizeof(one); i++) {      \
                KUNIT_EXPECT_EQ_MSG(test, one.data[i], two.data[i], \
-                       "line %d: %s.data[%d] (0x%02x) != %s.data[%d] (0x%02x)\n", \
+                       "line %d: %s.data[%zu] (0x%02x) != %s.data[%zu] (0x%02x)\n", \
                        __LINE__, #one, i, one.data[i], #two, i, two.data[i]); \
        }       \
        kunit_info(test, "ok: " TEST_OP "() " name "\n");       \
index ed2ab43e1b22c0156e5d361c6bfa7eb745759232..be9c576b6e2dc6d35d67d31f15014ab747f478ce 100644 (file)
@@ -30,6 +30,8 @@ static const u8 nla_attr_len[NLA_TYPE_MAX+1] = {
        [NLA_S16]       = sizeof(s16),
        [NLA_S32]       = sizeof(s32),
        [NLA_S64]       = sizeof(s64),
+       [NLA_BE16]      = sizeof(__be16),
+       [NLA_BE32]      = sizeof(__be32),
 };
 
 static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
@@ -43,6 +45,8 @@ static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
        [NLA_S16]       = sizeof(s16),
        [NLA_S32]       = sizeof(s32),
        [NLA_S64]       = sizeof(s64),
+       [NLA_BE16]      = sizeof(__be16),
+       [NLA_BE32]      = sizeof(__be32),
 };
 
 /*
index cd0b9e95f499d2424c3bb92abbc668529224a15b..863e2d32093891c7302fb81ab169022c6684eaf9 100644 (file)
  */
 
 #include <linux/raid/pq.h>
-#include <asm/fpu/api.h>
-#include <asm/vx-insn.h>
+#include <asm/fpu.h>
 
 #define NSIZE 16
 
-static inline void LOAD_CONST(void)
+static __always_inline void LOAD_CONST(void)
 {
-       asm volatile("VREPIB %v24,7");
-       asm volatile("VREPIB %v25,0x1d");
+       fpu_vrepib(24, 0x07);
+       fpu_vrepib(25, 0x1d);
 }
 
 /*
@@ -28,10 +27,7 @@ static inline void LOAD_CONST(void)
  * vector register y left by 1 bit and stores the result in
  * vector register x.
  */
-static inline void SHLBYTE(int x, int y)
-{
-       asm volatile ("VAB %0,%1,%1" : : "i" (x), "i" (y));
-}
+#define SHLBYTE(x, y)          fpu_vab(x, y, y)
 
 /*
  * For each of the 16 bytes in the vector register y the MASK()
@@ -39,49 +35,17 @@ static inline void SHLBYTE(int x, int y)
  * or 0x00 if the high bit is 0. The result is stored in vector
  * register x.
  */
-static inline void MASK(int x, int y)
-{
-       asm volatile ("VESRAVB  %0,%1,24" : : "i" (x), "i" (y));
-}
-
-static inline void AND(int x, int y, int z)
-{
-       asm volatile ("VN %0,%1,%2" : : "i" (x), "i" (y), "i" (z));
-}
-
-static inline void XOR(int x, int y, int z)
-{
-       asm volatile ("VX %0,%1,%2" : : "i" (x), "i" (y), "i" (z));
-}
+#define MASK(x, y)             fpu_vesravb(x, y, 24)
 
-static inline void LOAD_DATA(int x, u8 *ptr)
-{
-       typedef struct { u8 _[16 * $#]; } addrtype;
-       register addrtype *__ptr asm("1") = (addrtype *) ptr;
-
-       asm volatile ("VLM %2,%3,0,%1"
-                     : : "m" (*__ptr), "a" (__ptr), "i" (x),
-                         "i" (x + $# - 1));
-}
-
-static inline void STORE_DATA(int x, u8 *ptr)
-{
-       typedef struct { u8 _[16 * $#]; } addrtype;
-       register addrtype *__ptr asm("1") = (addrtype *) ptr;
-
-       asm volatile ("VSTM %2,%3,0,1"
-                     : "=m" (*__ptr) : "a" (__ptr), "i" (x),
-                       "i" (x + $# - 1));
-}
-
-static inline void COPY_VEC(int x, int y)
-{
-       asm volatile ("VLR %0,%1" : : "i" (x), "i" (y));
-}
+#define AND(x, y, z)           fpu_vn(x, y, z)
+#define XOR(x, y, z)           fpu_vx(x, y, z)
+#define LOAD_DATA(x, ptr)      fpu_vlm(x, x + $# - 1, ptr)
+#define STORE_DATA(x, ptr)     fpu_vstm(x, x + $# - 1, ptr)
+#define COPY_VEC(x, y)         fpu_vlr(x, y)
 
 static void raid6_s390vx$#_gen_syndrome(int disks, size_t bytes, void **ptrs)
 {
-       struct kernel_fpu vxstate;
+       DECLARE_KERNEL_FPU_ONSTACK32(vxstate);
        u8 **dptr, *p, *q;
        int d, z, z0;
 
@@ -114,7 +78,7 @@ static void raid6_s390vx$#_gen_syndrome(int disks, size_t bytes, void **ptrs)
 static void raid6_s390vx$#_xor_syndrome(int disks, int start, int stop,
                                        size_t bytes, void **ptrs)
 {
-       struct kernel_fpu vxstate;
+       DECLARE_KERNEL_FPU_ONSTACK32(vxstate);
        u8 **dptr, *p, *q;
        int d, z, z0;
 
index 010c730ca7fca9b9aab83960a78638046043693f..f3f3436d60a9403eae5b1ef9b091b027881f14fb 100644 (file)
  * seq_buf_init() more than once to reset the seq_buf to start
  * from scratch.
  */
-#include <linux/uaccess.h>
-#include <linux/seq_file.h>
+
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/hex.h>
+#include <linux/minmax.h>
+#include <linux/printk.h>
 #include <linux/seq_buf.h>
+#include <linux/seq_file.h>
+#include <linux/sprintf.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
 
 /**
  * seq_buf_can_fit - can the new data fit in the current buffer?
  * @s: the seq_buf descriptor
  * @len: The length to see if it can fit in the current buffer
  *
- * Returns true if there's enough unused space in the seq_buf buffer
+ * Returns: true if there's enough unused space in the seq_buf buffer
  * to fit the amount of new data according to @len.
  */
 static bool seq_buf_can_fit(struct seq_buf *s, size_t len)
@@ -35,7 +45,7 @@ static bool seq_buf_can_fit(struct seq_buf *s, size_t len)
  * @m: the seq_file descriptor that is the destination
  * @s: the seq_buf descriptor that is the source.
  *
- * Returns zero on success, non zero otherwise
+ * Returns: zero on success, non-zero otherwise.
  */
 int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s)
 {
@@ -50,9 +60,9 @@ int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s)
  * @fmt: printf format string
  * @args: va_list of arguments from a printf() type function
  *
- * Writes a vnprintf() format into the sequencce buffer.
+ * Writes a vnprintf() format into the sequence buffer.
  *
- * Returns zero on success, -1 on overflow.
+ * Returns: zero on success, -1 on overflow.
  */
 int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
 {
@@ -78,7 +88,7 @@ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
  *
  * Writes a printf() format into the sequence buffer.
  *
- * Returns zero on success, -1 on overflow.
+ * Returns: zero on success, -1 on overflow.
  */
 int seq_buf_printf(struct seq_buf *s, const char *fmt, ...)
 {
@@ -94,12 +104,12 @@ int seq_buf_printf(struct seq_buf *s, const char *fmt, ...)
 EXPORT_SYMBOL_GPL(seq_buf_printf);
 
 /**
- * seq_buf_do_printk - printk seq_buf line by line
+ * seq_buf_do_printk - printk() seq_buf line by line
  * @s: seq_buf descriptor
  * @lvl: printk level
  *
  * printk()-s a multi-line sequential buffer line by line. The function
- * makes sure that the buffer in @s is nul terminated and safe to read
+ * makes sure that the buffer in @s is NUL-terminated and safe to read
  * as a string.
  */
 void seq_buf_do_printk(struct seq_buf *s, const char *lvl)
@@ -139,7 +149,7 @@ EXPORT_SYMBOL_GPL(seq_buf_do_printk);
  * This function will take the format and the binary array and finish
  * the conversion into the ASCII string within the buffer.
  *
- * Returns zero on success, -1 on overflow.
+ * Returns: zero on success, -1 on overflow.
  */
 int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)
 {
@@ -167,7 +177,7 @@ int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)
  *
  * Copy a simple string into the sequence buffer.
  *
- * Returns zero on success, -1 on overflow
+ * Returns: zero on success, -1 on overflow.
  */
 int seq_buf_puts(struct seq_buf *s, const char *str)
 {
@@ -196,7 +206,7 @@ EXPORT_SYMBOL_GPL(seq_buf_puts);
  *
  * Copy a single character into the sequence buffer.
  *
- * Returns zero on success, -1 on overflow
+ * Returns: zero on success, -1 on overflow.
  */
 int seq_buf_putc(struct seq_buf *s, unsigned char c)
 {
@@ -212,7 +222,7 @@ int seq_buf_putc(struct seq_buf *s, unsigned char c)
 EXPORT_SYMBOL_GPL(seq_buf_putc);
 
 /**
- * seq_buf_putmem - write raw data into the sequenc buffer
+ * seq_buf_putmem - write raw data into the sequence buffer
  * @s: seq_buf descriptor
  * @mem: The raw memory to copy into the buffer
  * @len: The length of the raw memory to copy (in bytes)
@@ -221,7 +231,7 @@ EXPORT_SYMBOL_GPL(seq_buf_putc);
  * buffer and a strcpy() would not work. Using this function allows
  * for such cases.
  *
- * Returns zero on success, -1 on overflow
+ * Returns: zero on success, -1 on overflow.
  */
 int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len)
 {
@@ -249,7 +259,7 @@ int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len)
  * raw memory into the buffer it writes its ASCII representation of it
  * in hex characters.
  *
- * Returns zero on success, -1 on overflow
+ * Returns: zero on success, -1 on overflow.
  */
 int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,
                       unsigned int len)
@@ -297,7 +307,7 @@ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,
  *
  * Write a path name into the sequence buffer.
  *
- * Returns the number of written bytes on success, -1 on overflow
+ * Returns: the number of written bytes on success, -1 on overflow.
  */
 int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc)
 {
@@ -332,6 +342,7 @@ int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc)
  * or until it reaches the end of the content in the buffer (@s->len),
  * whichever comes first.
  *
+ * Returns:
  * On success, it returns a positive number of the number of bytes
  * it copied.
  *
@@ -382,11 +393,11 @@ int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, size_t start, int cnt)
  * linebuf size is maximal length for one line.
  * 32 * 3 - maximum bytes per line, each printed into 2 chars + 1 for
  *     separating space
- * 2 - spaces separating hex dump and ascii representation
- * 32 - ascii representation
+ * 2 - spaces separating hex dump and ASCII representation
+ * 32 - ASCII representation
  * 1 - terminating '\0'
  *
- * Returns zero on success, -1 on overflow
+ * Returns: zero on success, -1 on overflow.
  */
 int seq_buf_hex_dump(struct seq_buf *s, const char *prefix_str, int prefix_type,
                     int rowsize, int groupsize,
index 5caa1f566553843911ffdf2edafd32ee70277ea8..4a7055a63d9f8a8a6723563fd8a30115653eea83 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/list.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
+#include <linux/poison.h>
 #include <linux/printk.h>
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
 #define DEPOT_OFFSET_BITS (DEPOT_POOL_ORDER + PAGE_SHIFT - DEPOT_STACK_ALIGN)
 #define DEPOT_POOL_INDEX_BITS (DEPOT_HANDLE_BITS - DEPOT_OFFSET_BITS - \
                               STACK_DEPOT_EXTRA_BITS)
-#if IS_ENABLED(CONFIG_KMSAN) && CONFIG_STACKDEPOT_MAX_FRAMES >= 32
-/*
- * KMSAN is frequently used in fuzzing scenarios and thus saves a lot of stack
- * traces. As KMSAN does not support evicting stack traces from the stack
- * depot, the stack depot capacity might be reached quickly with large stack
- * records. Adjust the maximum number of stack depot pools for this case.
- */
-#define DEPOT_POOLS_CAP (8192 * (CONFIG_STACKDEPOT_MAX_FRAMES / 16))
-#else
 #define DEPOT_POOLS_CAP 8192
-#endif
 #define DEPOT_MAX_POOLS \
        (((1LL << (DEPOT_POOL_INDEX_BITS)) < DEPOT_POOLS_CAP) ? \
         (1LL << (DEPOT_POOL_INDEX_BITS)) : DEPOT_POOLS_CAP)
@@ -93,9 +84,6 @@ struct stack_record {
        };
 };
 
-#define DEPOT_STACK_RECORD_SIZE \
-       ALIGN(sizeof(struct stack_record), 1 << DEPOT_STACK_ALIGN)
-
 static bool stack_depot_disabled;
 static bool __stack_depot_early_init_requested __initdata = IS_ENABLED(CONFIG_STACKDEPOT_ALWAYS_INIT);
 static bool __stack_depot_early_init_passed __initdata;
@@ -121,32 +109,31 @@ static void *stack_pools[DEPOT_MAX_POOLS];
 static void *new_pool;
 /* Number of pools in stack_pools. */
 static int pools_num;
+/* Offset to the unused space in the currently used pool. */
+static size_t pool_offset = DEPOT_POOL_SIZE;
 /* Freelist of stack records within stack_pools. */
 static LIST_HEAD(free_stacks);
-/*
- * Stack depot tries to keep an extra pool allocated even before it runs out
- * of space in the currently used pool. This flag marks whether this extra pool
- * needs to be allocated. It has the value 0 when either an extra pool is not
- * yet allocated or if the limit on the number of pools is reached.
- */
-static bool new_pool_required = true;
 /* The lock must be held when performing pool or freelist modifications. */
 static DEFINE_RAW_SPINLOCK(pool_lock);
 
 /* Statistics counters for debugfs. */
 enum depot_counter_id {
-       DEPOT_COUNTER_ALLOCS,
-       DEPOT_COUNTER_FREES,
-       DEPOT_COUNTER_INUSE,
+       DEPOT_COUNTER_REFD_ALLOCS,
+       DEPOT_COUNTER_REFD_FREES,
+       DEPOT_COUNTER_REFD_INUSE,
        DEPOT_COUNTER_FREELIST_SIZE,
+       DEPOT_COUNTER_PERSIST_COUNT,
+       DEPOT_COUNTER_PERSIST_BYTES,
        DEPOT_COUNTER_COUNT,
 };
 static long counters[DEPOT_COUNTER_COUNT];
 static const char *const counter_names[] = {
-       [DEPOT_COUNTER_ALLOCS]          = "allocations",
-       [DEPOT_COUNTER_FREES]           = "frees",
-       [DEPOT_COUNTER_INUSE]           = "in_use",
+       [DEPOT_COUNTER_REFD_ALLOCS]     = "refcounted_allocations",
+       [DEPOT_COUNTER_REFD_FREES]      = "refcounted_frees",
+       [DEPOT_COUNTER_REFD_INUSE]      = "refcounted_in_use",
        [DEPOT_COUNTER_FREELIST_SIZE]   = "freelist_size",
+       [DEPOT_COUNTER_PERSIST_COUNT]   = "persistent_count",
+       [DEPOT_COUNTER_PERSIST_BYTES]   = "persistent_bytes",
 };
 static_assert(ARRAY_SIZE(counter_names) == DEPOT_COUNTER_COUNT);
 
@@ -294,48 +281,52 @@ out_unlock:
 EXPORT_SYMBOL_GPL(stack_depot_init);
 
 /*
- * Initializes new stack depot @pool, release all its entries to the freelist,
- * and update the list of pools.
+ * Initializes new stack pool, and updates the list of pools.
  */
-static void depot_init_pool(void *pool)
+static bool depot_init_pool(void **prealloc)
 {
-       int offset;
-
        lockdep_assert_held(&pool_lock);
 
-       /* Initialize handles and link stack records into the freelist. */
-       for (offset = 0; offset <= DEPOT_POOL_SIZE - DEPOT_STACK_RECORD_SIZE;
-            offset += DEPOT_STACK_RECORD_SIZE) {
-               struct stack_record *stack = pool + offset;
-
-               stack->handle.pool_index = pools_num;
-               stack->handle.offset = offset >> DEPOT_STACK_ALIGN;
-               stack->handle.extra = 0;
-
-               /*
-                * Stack traces of size 0 are never saved, and we can simply use
-                * the size field as an indicator if this is a new unused stack
-                * record in the freelist.
-                */
-               stack->size = 0;
+       if (unlikely(pools_num >= DEPOT_MAX_POOLS)) {
+               /* Bail out if we reached the pool limit. */
+               WARN_ON_ONCE(pools_num > DEPOT_MAX_POOLS); /* should never happen */
+               WARN_ON_ONCE(!new_pool); /* to avoid unnecessary pre-allocation */
+               WARN_ONCE(1, "Stack depot reached limit capacity");
+               return false;
+       }
 
-               INIT_LIST_HEAD(&stack->hash_list);
-               /*
-                * Add to the freelist front to prioritize never-used entries:
-                * required in case there are entries in the freelist, but their
-                * RCU cookie still belongs to the current RCU grace period
-                * (there can still be concurrent readers).
-                */
-               list_add(&stack->free_list, &free_stacks);
-               counters[DEPOT_COUNTER_FREELIST_SIZE]++;
+       if (!new_pool && *prealloc) {
+               /* We have preallocated memory, use it. */
+               WRITE_ONCE(new_pool, *prealloc);
+               *prealloc = NULL;
        }
 
+       if (!new_pool)
+               return false; /* new_pool and *prealloc are NULL */
+
        /* Save reference to the pool to be used by depot_fetch_stack(). */
-       stack_pools[pools_num] = pool;
+       stack_pools[pools_num] = new_pool;
+
+       /*
+        * Stack depot tries to keep an extra pool allocated even before it runs
+        * out of space in the currently used pool.
+        *
+        * To indicate that a new preallocation is needed new_pool is reset to
+        * NULL; do not reset to NULL if we have reached the maximum number of
+        * pools.
+        */
+       if (pools_num < DEPOT_MAX_POOLS)
+               WRITE_ONCE(new_pool, NULL);
+       else
+               WRITE_ONCE(new_pool, STACK_DEPOT_POISON);
 
        /* Pairs with concurrent READ_ONCE() in depot_fetch_stack(). */
        WRITE_ONCE(pools_num, pools_num + 1);
        ASSERT_EXCLUSIVE_WRITER(pools_num);
+
+       pool_offset = 0;
+
+       return true;
 }
 
 /* Keeps the preallocated memory to be used for a new stack depot pool. */
@@ -347,63 +338,51 @@ static void depot_keep_new_pool(void **prealloc)
         * If a new pool is already saved or the maximum number of
         * pools is reached, do not use the preallocated memory.
         */
-       if (!new_pool_required)
+       if (new_pool)
                return;
 
-       /*
-        * Use the preallocated memory for the new pool
-        * as long as we do not exceed the maximum number of pools.
-        */
-       if (pools_num < DEPOT_MAX_POOLS) {
-               new_pool = *prealloc;
-               *prealloc = NULL;
-       }
-
-       /*
-        * At this point, either a new pool is kept or the maximum
-        * number of pools is reached. In either case, take note that
-        * keeping another pool is not required.
-        */
-       WRITE_ONCE(new_pool_required, false);
+       WRITE_ONCE(new_pool, *prealloc);
+       *prealloc = NULL;
 }
 
 /*
- * Try to initialize a new stack depot pool from either a previous or the
- * current pre-allocation, and release all its entries to the freelist.
+ * Try to initialize a new stack record from the current pool, a cached pool, or
+ * the current pre-allocation.
  */
-static bool depot_try_init_pool(void **prealloc)
+static struct stack_record *depot_pop_free_pool(void **prealloc, size_t size)
 {
+       struct stack_record *stack;
+       void *current_pool;
+       u32 pool_index;
+
        lockdep_assert_held(&pool_lock);
 
-       /* Check if we have a new pool saved and use it. */
-       if (new_pool) {
-               depot_init_pool(new_pool);
-               new_pool = NULL;
+       if (pool_offset + size > DEPOT_POOL_SIZE) {
+               if (!depot_init_pool(prealloc))
+                       return NULL;
+       }
 
-               /* Take note that we might need a new new_pool. */
-               if (pools_num < DEPOT_MAX_POOLS)
-                       WRITE_ONCE(new_pool_required, true);
+       if (WARN_ON_ONCE(pools_num < 1))
+               return NULL;
+       pool_index = pools_num - 1;
+       current_pool = stack_pools[pool_index];
+       if (WARN_ON_ONCE(!current_pool))
+               return NULL;
 
-               return true;
-       }
+       stack = current_pool + pool_offset;
 
-       /* Bail out if we reached the pool limit. */
-       if (unlikely(pools_num >= DEPOT_MAX_POOLS)) {
-               WARN_ONCE(1, "Stack depot reached limit capacity");
-               return false;
-       }
+       /* Pre-initialize handle once. */
+       stack->handle.pool_index = pool_index;
+       stack->handle.offset = pool_offset >> DEPOT_STACK_ALIGN;
+       stack->handle.extra = 0;
+       INIT_LIST_HEAD(&stack->hash_list);
 
-       /* Check if we have preallocated memory and use it. */
-       if (*prealloc) {
-               depot_init_pool(*prealloc);
-               *prealloc = NULL;
-               return true;
-       }
+       pool_offset += size;
 
-       return false;
+       return stack;
 }
 
-/* Try to find next free usable entry. */
+/* Try to find next free usable entry from the freelist. */
 static struct stack_record *depot_pop_free(void)
 {
        struct stack_record *stack;
@@ -420,7 +399,7 @@ static struct stack_record *depot_pop_free(void)
         * check the first entry.
         */
        stack = list_first_entry(&free_stacks, struct stack_record, free_list);
-       if (stack->size && !poll_state_synchronize_rcu(stack->rcu_state))
+       if (!poll_state_synchronize_rcu(stack->rcu_state))
                return NULL;
 
        list_del(&stack->free_list);
@@ -429,48 +408,73 @@ static struct stack_record *depot_pop_free(void)
        return stack;
 }
 
+static inline size_t depot_stack_record_size(struct stack_record *s, unsigned int nr_entries)
+{
+       const size_t used = flex_array_size(s, entries, nr_entries);
+       const size_t unused = sizeof(s->entries) - used;
+
+       WARN_ON_ONCE(sizeof(s->entries) < used);
+
+       return ALIGN(sizeof(struct stack_record) - unused, 1 << DEPOT_STACK_ALIGN);
+}
+
 /* Allocates a new stack in a stack depot pool. */
 static struct stack_record *
-depot_alloc_stack(unsigned long *entries, int size, u32 hash, void **prealloc)
+depot_alloc_stack(unsigned long *entries, unsigned int nr_entries, u32 hash, depot_flags_t flags, void **prealloc)
 {
-       struct stack_record *stack;
+       struct stack_record *stack = NULL;
+       size_t record_size;
 
        lockdep_assert_held(&pool_lock);
 
        /* This should already be checked by public API entry points. */
-       if (WARN_ON_ONCE(!size))
+       if (WARN_ON_ONCE(!nr_entries))
                return NULL;
 
-       /* Check if we have a stack record to save the stack trace. */
-       stack = depot_pop_free();
-       if (!stack) {
-               /* No usable entries on the freelist - try to refill the freelist. */
-               if (!depot_try_init_pool(prealloc))
-                       return NULL;
+       /* Limit number of saved frames to CONFIG_STACKDEPOT_MAX_FRAMES. */
+       if (nr_entries > CONFIG_STACKDEPOT_MAX_FRAMES)
+               nr_entries = CONFIG_STACKDEPOT_MAX_FRAMES;
+
+       if (flags & STACK_DEPOT_FLAG_GET) {
+               /*
+                * Evictable entries have to allocate the max. size so they may
+                * safely be re-used by differently sized allocations.
+                */
+               record_size = depot_stack_record_size(stack, CONFIG_STACKDEPOT_MAX_FRAMES);
                stack = depot_pop_free();
-               if (WARN_ON(!stack))
-                       return NULL;
+       } else {
+               record_size = depot_stack_record_size(stack, nr_entries);
        }
 
-       /* Limit number of saved frames to CONFIG_STACKDEPOT_MAX_FRAMES. */
-       if (size > CONFIG_STACKDEPOT_MAX_FRAMES)
-               size = CONFIG_STACKDEPOT_MAX_FRAMES;
+       if (!stack) {
+               stack = depot_pop_free_pool(prealloc, record_size);
+               if (!stack)
+                       return NULL;
+       }
 
        /* Save the stack trace. */
        stack->hash = hash;
-       stack->size = size;
-       /* stack->handle is already filled in by depot_init_pool(). */
-       refcount_set(&stack->count, 1);
-       memcpy(stack->entries, entries, flex_array_size(stack, entries, size));
+       stack->size = nr_entries;
+       /* stack->handle is already filled in by depot_pop_free_pool(). */
+       memcpy(stack->entries, entries, flex_array_size(stack, entries, nr_entries));
+
+       if (flags & STACK_DEPOT_FLAG_GET) {
+               refcount_set(&stack->count, 1);
+               counters[DEPOT_COUNTER_REFD_ALLOCS]++;
+               counters[DEPOT_COUNTER_REFD_INUSE]++;
+       } else {
+               /* Warn on attempts to switch to refcounting this entry. */
+               refcount_set(&stack->count, REFCOUNT_SATURATED);
+               counters[DEPOT_COUNTER_PERSIST_COUNT]++;
+               counters[DEPOT_COUNTER_PERSIST_BYTES] += record_size;
+       }
 
        /*
         * Let KMSAN know the stored stack record is initialized. This shall
         * prevent false positive reports if instrumented code accesses it.
         */
-       kmsan_unpoison_memory(stack, DEPOT_STACK_RECORD_SIZE);
+       kmsan_unpoison_memory(stack, record_size);
 
-       counters[DEPOT_COUNTER_ALLOCS]++;
-       counters[DEPOT_COUNTER_INUSE]++;
        return stack;
 }
 
@@ -538,8 +542,8 @@ static void depot_free_stack(struct stack_record *stack)
        list_add_tail(&stack->free_list, &free_stacks);
 
        counters[DEPOT_COUNTER_FREELIST_SIZE]++;
-       counters[DEPOT_COUNTER_FREES]++;
-       counters[DEPOT_COUNTER_INUSE]--;
+       counters[DEPOT_COUNTER_REFD_FREES]++;
+       counters[DEPOT_COUNTER_REFD_INUSE]--;
 
        printk_deferred_exit();
        raw_spin_unlock_irqrestore(&pool_lock, flags);
@@ -660,7 +664,7 @@ depot_stack_handle_t stack_depot_save_flags(unsigned long *entries,
         * Allocate memory for a new pool if required now:
         * we won't be able to do that under the lock.
         */
-       if (unlikely(can_alloc && READ_ONCE(new_pool_required))) {
+       if (unlikely(can_alloc && !READ_ONCE(new_pool))) {
                /*
                 * Zero out zone modifiers, as we don't have specific zone
                 * requirements. Keep the flags related to allocation in atomic
@@ -681,7 +685,7 @@ depot_stack_handle_t stack_depot_save_flags(unsigned long *entries,
        found = find_stack(bucket, entries, nr_entries, hash, depot_flags);
        if (!found) {
                struct stack_record *new =
-                       depot_alloc_stack(entries, nr_entries, hash, &prealloc);
+                       depot_alloc_stack(entries, nr_entries, hash, depot_flags, &prealloc);
 
                if (new) {
                        /*
index 29185ac5c727f6f14bf2bd62ed9c16c9acdca085..399380db449cdd7c4b224d615fc5fc8a5528e06c 100644 (file)
@@ -3599,6 +3599,45 @@ static noinline void __init check_state_handling(struct maple_tree *mt)
        mas_unlock(&mas);
 }
 
+static noinline void __init alloc_cyclic_testing(struct maple_tree *mt)
+{
+       unsigned long location;
+       unsigned long next;
+       int ret = 0;
+       MA_STATE(mas, mt, 0, 0);
+
+       next = 0;
+       mtree_lock(mt);
+       for (int i = 0; i < 100; i++) {
+               mas_alloc_cyclic(&mas, &location, mt, 2, ULONG_MAX, &next, GFP_KERNEL);
+               MAS_BUG_ON(&mas, i != location - 2);
+               MAS_BUG_ON(&mas, mas.index != location);
+               MAS_BUG_ON(&mas, mas.last != location);
+               MAS_BUG_ON(&mas, i != next - 3);
+       }
+
+       mtree_unlock(mt);
+       mtree_destroy(mt);
+       next = 0;
+       mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
+       for (int i = 0; i < 100; i++) {
+               mtree_alloc_cyclic(mt, &location, mt, 2, ULONG_MAX, &next, GFP_KERNEL);
+               MT_BUG_ON(mt, i != location - 2);
+               MT_BUG_ON(mt, i != next - 3);
+               MT_BUG_ON(mt, mtree_load(mt, location) != mt);
+       }
+
+       mtree_destroy(mt);
+       /* Overflow test */
+       next = ULONG_MAX - 1;
+       ret = mtree_alloc_cyclic(mt, &location, mt, 2, ULONG_MAX, &next, GFP_KERNEL);
+       MT_BUG_ON(mt, ret != 0);
+       ret = mtree_alloc_cyclic(mt, &location, mt, 2, ULONG_MAX, &next, GFP_KERNEL);
+       MT_BUG_ON(mt, ret != 0);
+       ret = mtree_alloc_cyclic(mt, &location, mt, 2, ULONG_MAX, &next, GFP_KERNEL);
+       MT_BUG_ON(mt, ret != 1);
+}
+
 static DEFINE_MTREE(tree);
 static int __init maple_tree_seed(void)
 {
@@ -3880,6 +3919,11 @@ static int __init maple_tree_seed(void)
        check_state_handling(&tree);
        mtree_destroy(&tree);
 
+       mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
+       alloc_cyclic_testing(&tree);
+       mtree_destroy(&tree);
+
+
 #if defined(BENCH)
 skip:
 #endif
index e039d05304dd9ca52da735962c0ef951fb448ec5..5f2be8c8df11f1ba31a1c2ea78be76651eb98747 100644 (file)
@@ -372,31 +372,6 @@ static int __init default_bdi_init(void)
 }
 subsys_initcall(default_bdi_init);
 
-/*
- * This function is used when the first inode for this wb is marked dirty. It
- * wakes-up the corresponding bdi thread which should then take care of the
- * periodic background write-out of dirty inodes. Since the write-out would
- * starts only 'dirty_writeback_interval' centisecs from now anyway, we just
- * set up a timer which wakes the bdi thread up later.
- *
- * Note, we wouldn't bother setting up the timer, but this function is on the
- * fast-path (used by '__mark_inode_dirty()'), so we save few context switches
- * by delaying the wake-up.
- *
- * We have to be careful not to postpone flush work if it is scheduled for
- * earlier. Thus we use queue_delayed_work().
- */
-void wb_wakeup_delayed(struct bdi_writeback *wb)
-{
-       unsigned long timeout;
-
-       timeout = msecs_to_jiffies(dirty_writeback_interval * 10);
-       spin_lock_irq(&wb->work_lock);
-       if (test_bit(WB_registered, &wb->state))
-               queue_delayed_work(bdi_wq, &wb->dwork, timeout);
-       spin_unlock_irq(&wb->work_lock);
-}
-
 static void wb_update_bandwidth_workfn(struct work_struct *work)
 {
        struct bdi_writeback *wb = container_of(to_delayed_work(work),
index 4add68d40e8d99c72bd6af648510aadd587dddfc..b961db601df4194f4cc69535bf154bef4a2624f0 100644 (file)
@@ -2723,16 +2723,11 @@ enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
                unsigned int alloc_flags, const struct alloc_context *ac,
                enum compact_priority prio, struct page **capture)
 {
-       int may_perform_io = (__force int)(gfp_mask & __GFP_IO);
        struct zoneref *z;
        struct zone *zone;
        enum compact_result rc = COMPACT_SKIPPED;
 
-       /*
-        * Check if the GFP flags allow compaction - GFP_NOIO is really
-        * tricky context because the migration might require IO
-        */
-       if (!may_perform_io)
+       if (!gfp_compaction_allowed(gfp_mask))
                return COMPACT_SKIPPED;
 
        trace_mm_compaction_try_to_compact_pages(order, gfp_mask, prio);
index 36f6f1d21ff069de12575a4f0d932e0dfc316c11..5b325749fc12597ddd273ae605bdb1c04a93f99e 100644 (file)
@@ -1026,6 +1026,9 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
        damon_for_each_scheme(s, c) {
                struct damos_quota *quota = &s->quota;
 
+               if (c->passed_sample_intervals != s->next_apply_sis)
+                       continue;
+
                if (!s->wmarks.activated)
                        continue;
 
@@ -1176,10 +1179,6 @@ static void kdamond_apply_schemes(struct damon_ctx *c)
                if (c->passed_sample_intervals != s->next_apply_sis)
                        continue;
 
-               s->next_apply_sis +=
-                       (s->apply_interval_us ? s->apply_interval_us :
-                        c->attrs.aggr_interval) / sample_interval;
-
                if (!s->wmarks.activated)
                        continue;
 
@@ -1195,6 +1194,14 @@ static void kdamond_apply_schemes(struct damon_ctx *c)
                damon_for_each_region_safe(r, next_r, t)
                        damon_do_apply_schemes(c, t, r);
        }
+
+       damon_for_each_scheme(s, c) {
+               if (c->passed_sample_intervals != s->next_apply_sis)
+                       continue;
+               s->next_apply_sis +=
+                       (s->apply_interval_us ? s->apply_interval_us :
+                        c->attrs.aggr_interval) / sample_interval;
+       }
 }
 
 /*
index f2e5f9431892eb207bec1da87224282e3de27371..3de2916a65c38c372b5ed8472b7a87b34026aed7 100644 (file)
@@ -185,9 +185,21 @@ static struct damos *damon_lru_sort_new_cold_scheme(unsigned int cold_thres)
        return damon_lru_sort_new_scheme(&pattern, DAMOS_LRU_DEPRIO);
 }
 
+static void damon_lru_sort_copy_quota_status(struct damos_quota *dst,
+               struct damos_quota *src)
+{
+       dst->total_charged_sz = src->total_charged_sz;
+       dst->total_charged_ns = src->total_charged_ns;
+       dst->charged_sz = src->charged_sz;
+       dst->charged_from = src->charged_from;
+       dst->charge_target_from = src->charge_target_from;
+       dst->charge_addr_from = src->charge_addr_from;
+}
+
 static int damon_lru_sort_apply_parameters(void)
 {
-       struct damos *scheme;
+       struct damos *scheme, *hot_scheme, *cold_scheme;
+       struct damos *old_hot_scheme = NULL, *old_cold_scheme = NULL;
        unsigned int hot_thres, cold_thres;
        int err = 0;
 
@@ -195,18 +207,35 @@ static int damon_lru_sort_apply_parameters(void)
        if (err)
                return err;
 
+       damon_for_each_scheme(scheme, ctx) {
+               if (!old_hot_scheme) {
+                       old_hot_scheme = scheme;
+                       continue;
+               }
+               old_cold_scheme = scheme;
+       }
+
        hot_thres = damon_max_nr_accesses(&damon_lru_sort_mon_attrs) *
                hot_thres_access_freq / 1000;
-       scheme = damon_lru_sort_new_hot_scheme(hot_thres);
-       if (!scheme)
+       hot_scheme = damon_lru_sort_new_hot_scheme(hot_thres);
+       if (!hot_scheme)
                return -ENOMEM;
-       damon_set_schemes(ctx, &scheme, 1);
+       if (old_hot_scheme)
+               damon_lru_sort_copy_quota_status(&hot_scheme->quota,
+                               &old_hot_scheme->quota);
 
        cold_thres = cold_min_age / damon_lru_sort_mon_attrs.aggr_interval;
-       scheme = damon_lru_sort_new_cold_scheme(cold_thres);
-       if (!scheme)
+       cold_scheme = damon_lru_sort_new_cold_scheme(cold_thres);
+       if (!cold_scheme) {
+               damon_destroy_scheme(hot_scheme);
                return -ENOMEM;
-       damon_add_scheme(ctx, scheme);
+       }
+       if (old_cold_scheme)
+               damon_lru_sort_copy_quota_status(&cold_scheme->quota,
+                               &old_cold_scheme->quota);
+
+       damon_set_schemes(ctx, &hot_scheme, 1);
+       damon_add_scheme(ctx, cold_scheme);
 
        return damon_set_region_biggest_system_ram_default(target,
                                        &monitor_region_start,
index ab974e477d2f2850f642fbbafac48a8b3a5d136b..66e190f0374ac84b47100b8ba21fe4c32e104891 100644 (file)
@@ -150,9 +150,20 @@ static struct damos *damon_reclaim_new_scheme(void)
                        &damon_reclaim_wmarks);
 }
 
+static void damon_reclaim_copy_quota_status(struct damos_quota *dst,
+               struct damos_quota *src)
+{
+       dst->total_charged_sz = src->total_charged_sz;
+       dst->total_charged_ns = src->total_charged_ns;
+       dst->charged_sz = src->charged_sz;
+       dst->charged_from = src->charged_from;
+       dst->charge_target_from = src->charge_target_from;
+       dst->charge_addr_from = src->charge_addr_from;
+}
+
 static int damon_reclaim_apply_parameters(void)
 {
-       struct damos *scheme;
+       struct damos *scheme, *old_scheme;
        struct damos_filter *filter;
        int err = 0;
 
@@ -164,6 +175,11 @@ static int damon_reclaim_apply_parameters(void)
        scheme = damon_reclaim_new_scheme();
        if (!scheme)
                return -ENOMEM;
+       if (!list_empty(&ctx->schemes)) {
+               damon_for_each_scheme(old_scheme, ctx)
+                       damon_reclaim_copy_quota_status(&scheme->quota,
+                                       &old_scheme->quota);
+       }
        if (skip_anon) {
                filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true);
                if (!filter) {
index dd2fb512700920803b10621b82ffaa88bff30a92..ae0f0b314f3a9a5ec251021d0fb68d423fa53cd7 100644 (file)
@@ -1905,6 +1905,10 @@ void damos_sysfs_set_quota_scores(struct damon_sysfs_schemes *sysfs_schemes,
        damon_for_each_scheme(scheme, ctx) {
                struct damon_sysfs_scheme *sysfs_scheme;
 
+               /* user could have removed the scheme sysfs dir */
+               if (i >= sysfs_schemes->nr)
+                       break;
+
                sysfs_scheme = sysfs_schemes->schemes_arr[i];
                damos_sysfs_set_quota_score(sysfs_scheme->quotas->goals,
                                &scheme->quota);
index 5662e29fe25335cf9e6227ae9fd4f22971095adb..65c19025da3dfee99ba0c1129874283bfcd5c72f 100644 (file)
@@ -362,6 +362,12 @@ static void __init pud_advanced_tests(struct pgtable_debug_args *args)
        vaddr &= HPAGE_PUD_MASK;
 
        pud = pfn_pud(args->pud_pfn, args->page_prot);
+       /*
+        * Some architectures have debug checks to make sure
+        * huge pud mapping are only found with devmap entries
+        * For now test with only devmap entries.
+        */
+       pud = pud_mkdevmap(pud);
        set_pud_at(args->mm, vaddr, args->pudp, pud);
        flush_dcache_page(page);
        pudp_set_wrprotect(args->mm, vaddr, args->pudp);
@@ -374,6 +380,7 @@ static void __init pud_advanced_tests(struct pgtable_debug_args *args)
        WARN_ON(!pud_none(pud));
 #endif /* __PAGETABLE_PMD_FOLDED */
        pud = pfn_pud(args->pud_pfn, args->page_prot);
+       pud = pud_mkdevmap(pud);
        pud = pud_wrprotect(pud);
        pud = pud_mkclean(pud);
        set_pud_at(args->mm, vaddr, args->pudp, pud);
@@ -391,6 +398,7 @@ static void __init pud_advanced_tests(struct pgtable_debug_args *args)
 #endif /* __PAGETABLE_PMD_FOLDED */
 
        pud = pfn_pud(args->pud_pfn, args->page_prot);
+       pud = pud_mkdevmap(pud);
        pud = pud_mkyoung(pud);
        set_pud_at(args->mm, vaddr, args->pudp, pud);
        flush_dcache_page(page);
index 750e779c23db74730fa7743c2307d1b996729d62..8df4797c5287fa748aef1c26dd63f92dc24f03fd 100644 (file)
@@ -2608,15 +2608,6 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter,
                        goto put_folios;
                end_offset = min_t(loff_t, isize, iocb->ki_pos + iter->count);
 
-               /*
-                * Pairs with a barrier in
-                * block_write_end()->mark_buffer_dirty() or other page
-                * dirtying routines like iomap_write_end() to ensure
-                * changes to page contents are visible before we see
-                * increased inode size.
-                */
-               smp_rmb();
-
                /*
                 * Once we start copying data, we don't want to be touching any
                 * cachelines that might be contended:
@@ -4111,28 +4102,40 @@ static void filemap_cachestat(struct address_space *mapping,
 
        rcu_read_lock();
        xas_for_each(&xas, folio, last_index) {
+               int order;
                unsigned long nr_pages;
                pgoff_t folio_first_index, folio_last_index;
 
+               /*
+                * Don't deref the folio. It is not pinned, and might
+                * get freed (and reused) underneath us.
+                *
+                * We *could* pin it, but that would be expensive for
+                * what should be a fast and lightweight syscall.
+                *
+                * Instead, derive all information of interest from
+                * the rcu-protected xarray.
+                */
+
                if (xas_retry(&xas, folio))
                        continue;
 
+               order = xa_get_order(xas.xa, xas.xa_index);
+               nr_pages = 1 << order;
+               folio_first_index = round_down(xas.xa_index, 1 << order);
+               folio_last_index = folio_first_index + nr_pages - 1;
+
+               /* Folios might straddle the range boundaries, only count covered pages */
+               if (folio_first_index < first_index)
+                       nr_pages -= first_index - folio_first_index;
+
+               if (folio_last_index > last_index)
+                       nr_pages -= folio_last_index - last_index;
+
                if (xa_is_value(folio)) {
                        /* page is evicted */
                        void *shadow = (void *)folio;
                        bool workingset; /* not used */
-                       int order = xa_get_order(xas.xa, xas.xa_index);
-
-                       nr_pages = 1 << order;
-                       folio_first_index = round_down(xas.xa_index, 1 << order);
-                       folio_last_index = folio_first_index + nr_pages - 1;
-
-                       /* Folios might straddle the range boundaries, only count covered pages */
-                       if (folio_first_index < first_index)
-                               nr_pages -= first_index - folio_first_index;
-
-                       if (folio_last_index > last_index)
-                               nr_pages -= folio_last_index - last_index;
 
                        cs->nr_evicted += nr_pages;
 
@@ -4150,24 +4153,13 @@ static void filemap_cachestat(struct address_space *mapping,
                        goto resched;
                }
 
-               nr_pages = folio_nr_pages(folio);
-               folio_first_index = folio_pgoff(folio);
-               folio_last_index = folio_first_index + nr_pages - 1;
-
-               /* Folios might straddle the range boundaries, only count covered pages */
-               if (folio_first_index < first_index)
-                       nr_pages -= first_index - folio_first_index;
-
-               if (folio_last_index > last_index)
-                       nr_pages -= folio_last_index - last_index;
-
                /* page is in cache */
                cs->nr_cache += nr_pages;
 
-               if (folio_test_dirty(folio))
+               if (xas_get_mark(&xas, PAGECACHE_TAG_DIRTY))
                        cs->nr_dirty += nr_pages;
 
-               if (folio_test_writeback(folio))
+               if (xas_get_mark(&xas, PAGECACHE_TAG_WRITEBACK))
                        cs->nr_writeback += nr_pages;
 
 resched:
index 610efae912209472d818628778f1ebce5b0e2cc1..6ca63e8dda741b5e4094f7205f0b74a163be2e43 100644 (file)
@@ -65,8 +65,7 @@ void kasan_save_track(struct kasan_track *track, gfp_t flags)
 {
        depot_stack_handle_t stack;
 
-       stack = kasan_save_stack(flags,
-                       STACK_DEPOT_FLAG_CAN_ALLOC | STACK_DEPOT_FLAG_GET);
+       stack = kasan_save_stack(flags, STACK_DEPOT_FLAG_CAN_ALLOC);
        kasan_set_track(track, stack);
 }
 
@@ -266,10 +265,9 @@ bool __kasan_slab_free(struct kmem_cache *cache, void *object,
                return true;
 
        /*
-        * If the object is not put into quarantine, it will likely be quickly
-        * reallocated. Thus, release its metadata now.
+        * Note: Keep per-object metadata to allow KASAN print stack traces for
+        * use-after-free-before-realloc bugs.
         */
-       kasan_release_object_meta(cache, object);
 
        /* Let slab put the object onto the freelist. */
        return false;
index df6627f62402c01dab04e6955bf80e7fb4b4b2ae..1900f857603456ec20c1f7bb0841362624c11260 100644 (file)
@@ -485,16 +485,6 @@ void kasan_init_object_meta(struct kmem_cache *cache, const void *object)
        if (alloc_meta) {
                /* Zero out alloc meta to mark it as invalid. */
                __memset(alloc_meta, 0, sizeof(*alloc_meta));
-
-               /*
-                * Prepare the lock for saving auxiliary stack traces.
-                * Temporarily disable KASAN bug reporting to allow instrumented
-                * raw_spin_lock_init to access aux_lock, which resides inside
-                * of a redzone.
-                */
-               kasan_disable_current();
-               raw_spin_lock_init(&alloc_meta->aux_lock);
-               kasan_enable_current();
        }
 
        /*
@@ -506,47 +496,23 @@ void kasan_init_object_meta(struct kmem_cache *cache, const void *object)
 
 static void release_alloc_meta(struct kasan_alloc_meta *meta)
 {
-       /* Evict the stack traces from stack depot. */
-       stack_depot_put(meta->alloc_track.stack);
-       stack_depot_put(meta->aux_stack[0]);
-       stack_depot_put(meta->aux_stack[1]);
-
-       /*
-        * Zero out alloc meta to mark it as invalid but keep aux_lock
-        * initialized to avoid having to reinitialize it when another object
-        * is allocated in the same slot.
-        */
-       __memset(&meta->alloc_track, 0, sizeof(meta->alloc_track));
-       __memset(meta->aux_stack, 0, sizeof(meta->aux_stack));
+       /* Zero out alloc meta to mark it as invalid. */
+       __memset(meta, 0, sizeof(*meta));
 }
 
 static void release_free_meta(const void *object, struct kasan_free_meta *meta)
 {
+       if (!kasan_arch_is_ready())
+               return;
+
        /* Check if free meta is valid. */
        if (*(u8 *)kasan_mem_to_shadow(object) != KASAN_SLAB_FREE_META)
                return;
 
-       /* Evict the stack trace from the stack depot. */
-       stack_depot_put(meta->free_track.stack);
-
        /* Mark free meta as invalid. */
        *(u8 *)kasan_mem_to_shadow(object) = KASAN_SLAB_FREE;
 }
 
-void kasan_release_object_meta(struct kmem_cache *cache, const void *object)
-{
-       struct kasan_alloc_meta *alloc_meta;
-       struct kasan_free_meta *free_meta;
-
-       alloc_meta = kasan_get_alloc_meta(cache, object);
-       if (alloc_meta)
-               release_alloc_meta(alloc_meta);
-
-       free_meta = kasan_get_free_meta(cache, object);
-       if (free_meta)
-               release_free_meta(object, free_meta);
-}
-
 size_t kasan_metadata_size(struct kmem_cache *cache, bool in_object)
 {
        struct kasan_cache *info = &cache->kasan_info;
@@ -571,8 +537,6 @@ static void __kasan_record_aux_stack(void *addr, depot_flags_t depot_flags)
        struct kmem_cache *cache;
        struct kasan_alloc_meta *alloc_meta;
        void *object;
-       depot_stack_handle_t new_handle, old_handle;
-       unsigned long flags;
 
        if (is_kfence_address(addr) || !slab)
                return;
@@ -583,33 +547,18 @@ static void __kasan_record_aux_stack(void *addr, depot_flags_t depot_flags)
        if (!alloc_meta)
                return;
 
-       new_handle = kasan_save_stack(0, depot_flags);
-
-       /*
-        * Temporarily disable KASAN bug reporting to allow instrumented
-        * spinlock functions to access aux_lock, which resides inside of a
-        * redzone.
-        */
-       kasan_disable_current();
-       raw_spin_lock_irqsave(&alloc_meta->aux_lock, flags);
-       old_handle = alloc_meta->aux_stack[1];
        alloc_meta->aux_stack[1] = alloc_meta->aux_stack[0];
-       alloc_meta->aux_stack[0] = new_handle;
-       raw_spin_unlock_irqrestore(&alloc_meta->aux_lock, flags);
-       kasan_enable_current();
-
-       stack_depot_put(old_handle);
+       alloc_meta->aux_stack[0] = kasan_save_stack(0, depot_flags);
 }
 
 void kasan_record_aux_stack(void *addr)
 {
-       return __kasan_record_aux_stack(addr,
-                       STACK_DEPOT_FLAG_CAN_ALLOC | STACK_DEPOT_FLAG_GET);
+       return __kasan_record_aux_stack(addr, STACK_DEPOT_FLAG_CAN_ALLOC);
 }
 
 void kasan_record_aux_stack_noalloc(void *addr)
 {
-       return __kasan_record_aux_stack(addr, STACK_DEPOT_FLAG_GET);
+       return __kasan_record_aux_stack(addr, 0);
 }
 
 void kasan_save_alloc_info(struct kmem_cache *cache, void *object, gfp_t flags)
@@ -620,7 +569,7 @@ void kasan_save_alloc_info(struct kmem_cache *cache, void *object, gfp_t flags)
        if (!alloc_meta)
                return;
 
-       /* Evict previous stack traces (might exist for krealloc or mempool). */
+       /* Invalidate previous stack traces (might exist for krealloc or mempool). */
        release_alloc_meta(alloc_meta);
 
        kasan_save_track(&alloc_meta->alloc_track, flags);
@@ -634,7 +583,7 @@ void kasan_save_free_info(struct kmem_cache *cache, void *object)
        if (!free_meta)
                return;
 
-       /* Evict previous stack trace (might exist for mempool). */
+       /* Invalidate previous stack trace (might exist for mempool). */
        release_free_meta(object, free_meta);
 
        kasan_save_track(&free_meta->free_track, 0);
index d0f172f2b9783f1b1e73ea82ed5d3e6aaf2bec75..fb2b9ac0659a7add8f4ca95b9dcdc38b937cd216 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/kasan.h>
 #include <linux/kasan-tags.h>
 #include <linux/kfence.h>
-#include <linux/spinlock.h>
 #include <linux/stackdepot.h>
 
 #if defined(CONFIG_KASAN_SW_TAGS) || defined(CONFIG_KASAN_HW_TAGS)
@@ -265,13 +264,6 @@ struct kasan_global {
 struct kasan_alloc_meta {
        struct kasan_track alloc_track;
        /* Free track is stored in kasan_free_meta. */
-       /*
-        * aux_lock protects aux_stack from accesses from concurrent
-        * kasan_record_aux_stack calls. It is a raw spinlock to avoid sleeping
-        * on RT kernels, as kasan_record_aux_stack_noalloc can be called from
-        * non-sleepable contexts.
-        */
-       raw_spinlock_t aux_lock;
        depot_stack_handle_t aux_stack[2];
 };
 
@@ -398,10 +390,8 @@ struct kasan_alloc_meta *kasan_get_alloc_meta(struct kmem_cache *cache,
 struct kasan_free_meta *kasan_get_free_meta(struct kmem_cache *cache,
                                                const void *object);
 void kasan_init_object_meta(struct kmem_cache *cache, const void *object);
-void kasan_release_object_meta(struct kmem_cache *cache, const void *object);
 #else
 static inline void kasan_init_object_meta(struct kmem_cache *cache, const void *object) { }
-static inline void kasan_release_object_meta(struct kmem_cache *cache, const void *object) { }
 #endif
 
 depot_stack_handle_t kasan_save_stack(gfp_t flags, depot_flags_t depot_flags);
index 3ba02efb952aac15b4e511ad985caae0d0935bac..6958aa713c67ee7b0d2c74af676ecb82788d22cd 100644 (file)
@@ -145,7 +145,10 @@ static void qlink_free(struct qlist_node *qlink, struct kmem_cache *cache)
        void *object = qlink_to_object(qlink, cache);
        struct kasan_free_meta *free_meta = kasan_get_free_meta(cache, object);
 
-       kasan_release_object_meta(cache, object);
+       /*
+        * Note: Keep per-object metadata to allow KASAN print stack traces for
+        * use-after-free-before-realloc bugs.
+        */
 
        /*
         * If init_on_free is enabled and KASAN's free metadata is stored in
index 4dcb2ee35eca856a43694f4402dea0c1c9bf6d8a..d09136e040d3cc37b1b7b74a7cdd5d2c92eb8cb7 100644 (file)
@@ -180,8 +180,9 @@ static inline phys_addr_t memblock_cap_size(phys_addr_t base, phys_addr_t *size)
 /*
  * Address comparison utilities
  */
-static unsigned long __init_memblock memblock_addrs_overlap(phys_addr_t base1, phys_addr_t size1,
-                                      phys_addr_t base2, phys_addr_t size2)
+unsigned long __init_memblock
+memblock_addrs_overlap(phys_addr_t base1, phys_addr_t size1, phys_addr_t base2,
+                      phys_addr_t size2)
 {
        return ((base1 < (base2 + size2)) && (base2 < (base1 + size1)));
 }
@@ -2249,6 +2250,7 @@ static const char * const flagname[] = {
        [ilog2(MEMBLOCK_MIRROR)] = "MIRROR",
        [ilog2(MEMBLOCK_NOMAP)] = "NOMAP",
        [ilog2(MEMBLOCK_DRIVER_MANAGED)] = "DRV_MNG",
+       [ilog2(MEMBLOCK_RSRV_NOINIT)] = "RSV_NIT",
 };
 
 static int memblock_debug_show(struct seq_file *m, void *private)
index 1ed40f9d3a277ec8912c77326c5527a259a96c47..61932c9215e7734e4dfc7dc6e427c3692d1c3c6f 100644 (file)
@@ -7971,9 +7971,13 @@ bool mem_cgroup_swap_full(struct folio *folio)
 
 static int __init setup_swap_account(char *s)
 {
-       pr_warn_once("The swapaccount= commandline option is deprecated. "
-                    "Please report your usecase to linux-mm@kvack.org if you "
-                    "depend on this functionality.\n");
+       bool res;
+
+       if (!kstrtobool(s, &res) && !res)
+               pr_warn_once("The swapaccount=0 commandline option is deprecated "
+                            "in favor of configuring swap control via cgroupfs. "
+                            "Please report your usecase to linux-mm@kvack.org if you "
+                            "depend on this functionality.\n");
        return 1;
 }
 __setup("swapaccount=", setup_swap_account);
index 89bcae0b224d6d43b4720c5c71a6c528e683bafb..0bfc8b007c01a3323a15a17d51c4da46a6207540 100644 (file)
@@ -3799,6 +3799,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
        struct page *page;
        struct swap_info_struct *si = NULL;
        rmap_t rmap_flags = RMAP_NONE;
+       bool need_clear_cache = false;
        bool exclusive = false;
        swp_entry_t entry;
        pte_t pte;
@@ -3867,6 +3868,20 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
        if (!folio) {
                if (data_race(si->flags & SWP_SYNCHRONOUS_IO) &&
                    __swap_count(entry) == 1) {
+                       /*
+                        * Prevent parallel swapin from proceeding with
+                        * the cache flag. Otherwise, another thread may
+                        * finish swapin first, free the entry, and swapout
+                        * reusing the same entry. It's undetectable as
+                        * pte_same() returns true due to entry reuse.
+                        */
+                       if (swapcache_prepare(entry)) {
+                               /* Relax a bit to prevent rapid repeated page faults */
+                               schedule_timeout_uninterruptible(1);
+                               goto out;
+                       }
+                       need_clear_cache = true;
+
                        /* skip swapcache */
                        folio = vma_alloc_folio(GFP_HIGHUSER_MOVABLE, 0,
                                                vma, vmf->address, false);
@@ -4117,6 +4132,9 @@ unlock:
        if (vmf->pte)
                pte_unmap_unlock(vmf->pte, vmf->ptl);
 out:
+       /* Clear the swap cache pin for direct swapin after PTL unlock */
+       if (need_clear_cache)
+               swapcache_clear(si, entry);
        if (si)
                put_swap_device(si);
        return ret;
@@ -4131,6 +4149,8 @@ out_release:
                folio_unlock(swapcache);
                folio_put(swapcache);
        }
+       if (need_clear_cache)
+               swapcache_clear(si, entry);
        if (si)
                put_swap_device(si);
        return ret;
@@ -5478,7 +5498,7 @@ static inline bool get_mmap_lock_carefully(struct mm_struct *mm, struct pt_regs
                return true;
 
        if (regs && !user_mode(regs)) {
-               unsigned long ip = instruction_pointer(regs);
+               unsigned long ip = exception_ip(regs);
                if (!search_exception_tables(ip))
                        return false;
        }
@@ -5503,7 +5523,7 @@ static inline bool upgrade_mmap_lock_carefully(struct mm_struct *mm, struct pt_r
 {
        mmap_read_unlock(mm);
        if (regs && !user_mode(regs)) {
-               unsigned long ip = instruction_pointer(regs);
+               unsigned long ip = exception_ip(regs);
                if (!search_exception_tables(ip))
                        return false;
        }
index cc9f2bcd73b492aebacab4b812a515cf7e70b92b..c27b1f8097d4a72e569ce5a06be42b93184e9db0 100644 (file)
@@ -2519,6 +2519,14 @@ static int numamigrate_isolate_folio(pg_data_t *pgdat, struct folio *folio)
                        if (managed_zone(pgdat->node_zones + z))
                                break;
                }
+
+               /*
+                * If there are no managed zones, it should not proceed
+                * further.
+                */
+               if (z < 0)
+                       return 0;
+
                wakeup_kswapd(pgdat->node_zones + z, 0,
                              folio_order(folio), ZONE_MOVABLE);
                return 0;
index d89770eaab6b6111117783ca7ff532871c1d71a5..3281287771c9c6100ebefde692bca06e247ae0f8 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -954,13 +954,21 @@ static struct vm_area_struct
        } else if (merge_prev) {                        /* case 2 */
                if (curr) {
                        vma_start_write(curr);
-                       err = dup_anon_vma(prev, curr, &anon_dup);
                        if (end == curr->vm_end) {      /* case 7 */
+                               /*
+                                * can_vma_merge_after() assumed we would not be
+                                * removing prev vma, so it skipped the check
+                                * for vm_ops->close, but we are removing curr
+                                */
+                               if (curr->vm_ops && curr->vm_ops->close)
+                                       err = -EINVAL;
                                remove = curr;
                        } else {                        /* case 5 */
                                adjust = curr;
                                adj_start = (end - curr->vm_start);
                        }
+                       if (!err)
+                               err = dup_anon_vma(prev, curr, &anon_dup);
                }
        } else { /* merge_next */
                vma_start_write(next);
index 150d4f23b01048ed7af53a74ec3e12a208fc17b5..a663202045dc437a4ff6186afb48e728fa30839a 100644 (file)
@@ -4041,6 +4041,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
                                                struct alloc_context *ac)
 {
        bool can_direct_reclaim = gfp_mask & __GFP_DIRECT_RECLAIM;
+       bool can_compact = gfp_compaction_allowed(gfp_mask);
        const bool costly_order = order > PAGE_ALLOC_COSTLY_ORDER;
        struct page *page = NULL;
        unsigned int alloc_flags;
@@ -4111,7 +4112,7 @@ restart:
         * Don't try this for allocations that are allowed to ignore
         * watermarks, as the ALLOC_NO_WATERMARKS attempt didn't yet happen.
         */
-       if (can_direct_reclaim &&
+       if (can_direct_reclaim && can_compact &&
                        (costly_order ||
                           (order > 0 && ac->migratetype != MIGRATE_MOVABLE))
                        && !gfp_pfmemalloc_allowed(gfp_mask)) {
@@ -4209,9 +4210,10 @@ retry:
 
        /*
         * Do not retry costly high order allocations unless they are
-        * __GFP_RETRY_MAYFAIL
+        * __GFP_RETRY_MAYFAIL and we can compact
         */
-       if (costly_order && !(gfp_mask & __GFP_RETRY_MAYFAIL))
+       if (costly_order && (!can_compact ||
+                            !(gfp_mask & __GFP_RETRY_MAYFAIL)))
                goto nopage;
 
        if (should_reclaim_retry(gfp_mask, order, ac, alloc_flags,
@@ -4224,7 +4226,7 @@ retry:
         * implementation of the compaction depends on the sufficient amount
         * of free memory (see __compaction_suitable)
         */
-       if (did_some_progress > 0 &&
+       if (did_some_progress > 0 && can_compact &&
                        should_compact_retry(ac, order, alloc_flags,
                                compact_result, &compact_priority,
                                &compaction_retries))
index d7c84ff621860b85090cf61d9b2970357da01b76..29d5a024df48ae85ca2c39793477bf359d0c3980 100644 (file)
@@ -3374,7 +3374,7 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry)
 
 static int shmem_rmdir(struct inode *dir, struct dentry *dentry)
 {
-       if (!simple_empty(dentry))
+       if (!simple_offset_empty(dentry))
                return -ENOTEMPTY;
 
        drop_nlink(d_inode(dentry));
@@ -3431,7 +3431,7 @@ static int shmem_rename2(struct mnt_idmap *idmap,
                return simple_offset_rename_exchange(old_dir, old_dentry,
                                                     new_dir, new_dentry);
 
-       if (!simple_empty(new_dentry))
+       if (!simple_offset_empty(new_dentry))
                return -ENOTEMPTY;
 
        if (flags & RENAME_WHITEOUT) {
@@ -4355,7 +4355,9 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
 #ifdef CONFIG_TMPFS_POSIX_ACL
        sb->s_flags |= SB_POSIXACL;
 #endif
-       uuid_gen(&sb->s_uuid);
+       uuid_t uuid;
+       uuid_gen(&uuid);
+       super_set_uuid(sb, uuid.b, sizeof(uuid));
 
 #ifdef CONFIG_TMPFS_QUOTA
        if (ctx->seen & SHMEM_SEEN_QUOTA) {
index 758c46ca671ed110ae8e25fad48196d3feed03dc..fc2f6ade7f80b399707bcc67c44f813aea0b846d 100644 (file)
--- a/mm/swap.h
+++ b/mm/swap.h
@@ -41,6 +41,7 @@ void __delete_from_swap_cache(struct folio *folio,
 void delete_from_swap_cache(struct folio *folio);
 void clear_shadow_from_swap_cache(int type, unsigned long begin,
                                  unsigned long end);
+void swapcache_clear(struct swap_info_struct *si, swp_entry_t entry);
 struct folio *swap_cache_get_folio(swp_entry_t entry,
                struct vm_area_struct *vma, unsigned long addr);
 struct folio *filemap_get_incore_folio(struct address_space *mapping,
@@ -97,6 +98,10 @@ static inline int swap_writepage(struct page *p, struct writeback_control *wbc)
        return 0;
 }
 
+static inline void swapcache_clear(struct swap_info_struct *si, swp_entry_t entry)
+{
+}
+
 static inline struct folio *swap_cache_get_folio(swp_entry_t entry,
                struct vm_area_struct *vma, unsigned long addr)
 {
index e671266ad77241f461a17cbb2e486fe48a423f69..7255c01a1e4e16d758186019f904e70a7890a5cc 100644 (file)
@@ -680,9 +680,10 @@ skip:
        /* The page was likely read above, so no need for plugging here */
        folio = __read_swap_cache_async(entry, gfp_mask, mpol, ilx,
                                        &page_allocated, false);
-       if (unlikely(page_allocated))
+       if (unlikely(page_allocated)) {
+               zswap_folio_swapin(folio);
                swap_read_folio(folio, false, NULL);
-       zswap_folio_swapin(folio);
+       }
        return folio;
 }
 
@@ -855,9 +856,10 @@ skip:
        /* The folio was likely read above, so no need for plugging here */
        folio = __read_swap_cache_async(targ_entry, gfp_mask, mpol, targ_ilx,
                                        &page_allocated, false);
-       if (unlikely(page_allocated))
+       if (unlikely(page_allocated)) {
+               zswap_folio_swapin(folio);
                swap_read_folio(folio, false, NULL);
-       zswap_folio_swapin(folio);
+       }
        return folio;
 }
 
index 556ff7347d5f04402b61cc5bd9d0d123a36dc1d5..573843d9cc91ca8061ab45fbabbd3fe319bedc78 100644 (file)
@@ -2532,10 +2532,10 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        exit_swap_address_space(p->type);
 
        inode = mapping->host;
-       if (p->bdev_handle) {
+       if (p->bdev_file) {
                set_blocksize(p->bdev, old_block_size);
-               bdev_release(p->bdev_handle);
-               p->bdev_handle = NULL;
+               fput(p->bdev_file);
+               p->bdev_file = NULL;
        }
 
        inode_lock(inode);
@@ -2765,14 +2765,14 @@ static int claim_swapfile(struct swap_info_struct *p, struct inode *inode)
        int error;
 
        if (S_ISBLK(inode->i_mode)) {
-               p->bdev_handle = bdev_open_by_dev(inode->i_rdev,
+               p->bdev_file = bdev_file_open_by_dev(inode->i_rdev,
                                BLK_OPEN_READ | BLK_OPEN_WRITE, p, NULL);
-               if (IS_ERR(p->bdev_handle)) {
-                       error = PTR_ERR(p->bdev_handle);
-                       p->bdev_handle = NULL;
+               if (IS_ERR(p->bdev_file)) {
+                       error = PTR_ERR(p->bdev_file);
+                       p->bdev_file = NULL;
                        return error;
                }
-               p->bdev = p->bdev_handle->bdev;
+               p->bdev = file_bdev(p->bdev_file);
                p->old_block_size = block_size(p->bdev);
                error = set_blocksize(p->bdev, PAGE_SIZE);
                if (error < 0)
@@ -3208,10 +3208,10 @@ bad_swap:
        p->percpu_cluster = NULL;
        free_percpu(p->cluster_next_cpu);
        p->cluster_next_cpu = NULL;
-       if (p->bdev_handle) {
+       if (p->bdev_file) {
                set_blocksize(p->bdev, p->old_block_size);
-               bdev_release(p->bdev_handle);
-               p->bdev_handle = NULL;
+               fput(p->bdev_file);
+               p->bdev_file = NULL;
        }
        inode = NULL;
        destroy_swap_extents(p);
@@ -3365,6 +3365,19 @@ int swapcache_prepare(swp_entry_t entry)
        return __swap_duplicate(entry, SWAP_HAS_CACHE);
 }
 
+void swapcache_clear(struct swap_info_struct *si, swp_entry_t entry)
+{
+       struct swap_cluster_info *ci;
+       unsigned long offset = swp_offset(entry);
+       unsigned char usage;
+
+       ci = lock_cluster_or_swap_info(si, offset);
+       usage = __swap_entry_free_locked(si, offset, SWAP_HAS_CACHE);
+       unlock_cluster_or_swap_info(si, ci);
+       if (!usage)
+               free_swap_slot(entry);
+}
+
 struct swap_info_struct *swp_swap_info(swp_entry_t entry)
 {
        return swap_type_to_swap_info(swp_type(entry));
index 7cf7d43842590ccd99bf37795918a7054b61a8c4..313f1c42768a621d59385a0673e0cdf85d5c1720 100644 (file)
@@ -914,9 +914,6 @@ static int move_present_pte(struct mm_struct *mm,
                goto out;
        }
 
-       folio_move_anon_rmap(src_folio, dst_vma);
-       WRITE_ONCE(src_folio->index, linear_page_index(dst_vma, dst_addr));
-
        orig_src_pte = ptep_clear_flush(src_vma, src_addr, src_pte);
        /* Folio got pinned from under us. Put it back and fail the move. */
        if (folio_maybe_dma_pinned(src_folio)) {
@@ -925,6 +922,9 @@ static int move_present_pte(struct mm_struct *mm,
                goto out;
        }
 
+       folio_move_anon_rmap(src_folio, dst_vma);
+       WRITE_ONCE(src_folio->index, linear_page_index(dst_vma, dst_addr));
+
        orig_dst_pte = mk_pte(&src_folio->page, dst_vma->vm_page_prot);
        /* Follow mremap() behavior and treat the entry dirty after the move */
        orig_dst_pte = pte_mkwrite(pte_mkdirty(orig_dst_pte), dst_vma);
index 5a6a9802583b18992ea4d81d0a47794b169541ad..5faf3adc6f433ab153465a3f391027ee73aa4a31 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -135,6 +135,23 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp)
 }
 EXPORT_SYMBOL(kmemdup);
 
+/**
+ * kmemdup_array - duplicate a given array.
+ *
+ * @src: array to duplicate.
+ * @element_size: size of each element of array.
+ * @count: number of elements to duplicate from array.
+ * @gfp: GFP mask to use.
+ *
+ * Return: duplicated array of @src or %NULL in case of error,
+ * result is physically contiguous. Use kfree() to free.
+ */
+void *kmemdup_array(const void *src, size_t element_size, size_t count, gfp_t gfp)
+{
+       return kmemdup(src, size_mul(element_size, count), gfp);
+}
+EXPORT_SYMBOL(kmemdup_array);
+
 /**
  * kvmemdup - duplicate region of memory
  *
index 4f9c854ce6cc66c2d971767a8f00e51eeab8a65e..4255619a1a314717df613e20090b160fce72a7e9 100644 (file)
@@ -5753,7 +5753,7 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
 /* Use reclaim/compaction for costly allocs or under memory pressure */
 static bool in_reclaim_compaction(struct scan_control *sc)
 {
-       if (IS_ENABLED(CONFIG_COMPACTION) && sc->order &&
+       if (gfp_compaction_allowed(sc->gfp_mask) && sc->order &&
                        (sc->order > PAGE_ALLOC_COSTLY_ORDER ||
                         sc->priority < DEF_PRIORITY - 2))
                return true;
@@ -5998,6 +5998,9 @@ static inline bool compaction_ready(struct zone *zone, struct scan_control *sc)
 {
        unsigned long watermark;
 
+       if (!gfp_compaction_allowed(sc->gfp_mask))
+               return false;
+
        /* Allocation can already succeed, nothing to do */
        if (zone_watermark_ok(zone, sc->order, min_wmark_pages(zone),
                              sc->reclaim_idx, 0))
index 350dd2fc815994739d2012e0bcf483445350bb88..db4625af65fb7f6655a057e145bbe20dd64f7ae9 100644 (file)
@@ -377,10 +377,9 @@ void zswap_folio_swapin(struct folio *folio)
 {
        struct lruvec *lruvec;
 
-       if (folio) {
-               lruvec = folio_lruvec(folio);
-               atomic_long_inc(&lruvec->zswap_lruvec_state.nr_zswap_protected);
-       }
+       VM_WARN_ON_ONCE(!folio_test_locked(folio));
+       lruvec = folio_lruvec(folio);
+       atomic_long_inc(&lruvec->zswap_lruvec_state.nr_zswap_protected);
 }
 
 /*********************************
@@ -1440,6 +1439,8 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
        if (zswap_rb_search(&tree->rbroot, swp_offset(entry->swpentry)) != entry) {
                spin_unlock(&tree->lock);
                delete_from_swap_cache(folio);
+               folio_unlock(folio);
+               folio_put(folio);
                return -ENOMEM;
        }
        spin_unlock(&tree->lock);
@@ -1517,7 +1518,7 @@ bool zswap_store(struct folio *folio)
        if (folio_test_large(folio))
                return false;
 
-       if (!zswap_enabled || !tree)
+       if (!tree)
                return false;
 
        /*
@@ -1532,6 +1533,10 @@ bool zswap_store(struct folio *folio)
                zswap_invalidate_entry(tree, dupentry);
        }
        spin_unlock(&tree->lock);
+
+       if (!zswap_enabled)
+               return false;
+
        objcg = get_obj_cgroup_from_folio(folio);
        if (objcg && !obj_cgroup_may_zswap(objcg)) {
                memcg = get_mem_cgroup_from_objcg(objcg);
index 7b3341cef926ef37ce84c7dd09301c84c0a103c6..850d4a185f55f87f70a5e0a5112d1ab20d3eb070 100644 (file)
@@ -179,4 +179,5 @@ static void __exit lowpan_module_exit(void)
 module_init(lowpan_module_init);
 module_exit(lowpan_module_exit);
 
+MODULE_DESCRIPTION("IPv6 over Low-Power Wireless Personal Area Network core module");
 MODULE_LICENSE("GPL");
index 033871e718a34f7430929f862fcbcc886d933622..324e3ab96bb393d815901bb2d221ef6e18cf25e4 100644 (file)
@@ -1532,4 +1532,5 @@ static void __exit atm_mpoa_cleanup(void)
 module_init(atm_mpoa_init);
 module_exit(atm_mpoa_cleanup);
 
+MODULE_DESCRIPTION("Multi-Protocol Over ATM (MPOA) driver");
 MODULE_LICENSE("GPL");
index 65601aa52e0d8b669ac8aaec116301398a5e865b..2821a42cefdc6e0f83fa4a765bc881a67795a2b5 100644 (file)
@@ -1049,6 +1049,7 @@ static void hci_error_reset(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev, error_reset);
 
+       hci_dev_hold(hdev);
        BT_DBG("%s", hdev->name);
 
        if (hdev->hw_error)
@@ -1056,10 +1057,10 @@ static void hci_error_reset(struct work_struct *work)
        else
                bt_dev_err(hdev, "hardware error 0x%2.2x", hdev->hw_error_code);
 
-       if (hci_dev_do_close(hdev))
-               return;
+       if (!hci_dev_do_close(hdev))
+               hci_dev_do_open(hdev);
 
-       hci_dev_do_open(hdev);
+       hci_dev_put(hdev);
 }
 
 void hci_uuids_clear(struct hci_dev *hdev)
index ef8c3bed73617efa01052f7c84f170bee4666eef..2a5f5a7d2412be4aef32e8bfeb69cab0f6ad4fec 100644 (file)
@@ -5329,9 +5329,12 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, void *data,
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-       if (!conn || !hci_conn_ssp_enabled(conn))
+       if (!conn || !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
                goto unlock;
 
+       /* Assume remote supports SSP since it has triggered this event */
+       set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
+
        hci_conn_hold(conn);
 
        if (!hci_dev_test_flag(hdev, HCI_MGMT))
@@ -6794,6 +6797,10 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
                return send_conn_param_neg_reply(hdev, handle,
                                                 HCI_ERROR_UNKNOWN_CONN_ID);
 
+       if (max > hcon->le_conn_max_interval)
+               return send_conn_param_neg_reply(hdev, handle,
+                                                HCI_ERROR_INVALID_LL_PARAMS);
+
        if (hci_check_conn_params(min, max, latency, timeout))
                return send_conn_param_neg_reply(hdev, handle,
                                                 HCI_ERROR_INVALID_LL_PARAMS);
@@ -7420,10 +7427,10 @@ static void hci_store_wake_reason(struct hci_dev *hdev, u8 event,
         * keep track of the bdaddr of the connection event that woke us up.
         */
        if (event == HCI_EV_CONN_REQUEST) {
-               bacpy(&hdev->wake_addr, &conn_complete->bdaddr);
+               bacpy(&hdev->wake_addr, &conn_request->bdaddr);
                hdev->wake_addr_type = BDADDR_BREDR;
        } else if (event == HCI_EV_CONN_COMPLETE) {
-               bacpy(&hdev->wake_addr, &conn_request->bdaddr);
+               bacpy(&hdev->wake_addr, &conn_complete->bdaddr);
                hdev->wake_addr_type = BDADDR_BREDR;
        } else if (event == HCI_EV_LE_META) {
                struct hci_ev_le_meta *le_ev = (void *)skb->data;
index a6fc8a2a5c673d5266ceb98bef1d69b70ae19e4c..5716345a26dfb757b540137fa7616f4af49d013c 100644 (file)
@@ -2206,8 +2206,11 @@ static int hci_le_add_accept_list_sync(struct hci_dev *hdev,
 
        /* During suspend, only wakeable devices can be in acceptlist */
        if (hdev->suspended &&
-           !(params->flags & HCI_CONN_FLAG_REMOTE_WAKEUP))
+           !(params->flags & HCI_CONN_FLAG_REMOTE_WAKEUP)) {
+               hci_le_del_accept_list_sync(hdev, &params->addr,
+                                           params->addr_type);
                return 0;
+       }
 
        /* Select filter policy to accept all advertising */
        if (*num_entries >= hdev->le_accept_list_size)
@@ -5559,7 +5562,7 @@ static int hci_inquiry_sync(struct hci_dev *hdev, u8 length)
 
        bt_dev_dbg(hdev, "");
 
-       if (hci_dev_test_flag(hdev, HCI_INQUIRY))
+       if (test_bit(HCI_INQUIRY, &hdev->flags))
                return 0;
 
        hci_dev_lock(hdev);
index 60298975d5c45620f21ca5fe161da1a9fdf55eec..656f49b299d20d9141b9579aef84acf3b81bff7e 100644 (file)
@@ -5613,7 +5613,13 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
 
        memset(&rsp, 0, sizeof(rsp));
 
-       err = hci_check_conn_params(min, max, latency, to_multiplier);
+       if (max > hcon->le_conn_max_interval) {
+               BT_DBG("requested connection interval exceeds current bounds.");
+               err = -EINVAL;
+       } else {
+               err = hci_check_conn_params(min, max, latency, to_multiplier);
+       }
+
        if (err)
                rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
        else
index bb72ff6eb22f4b30864aefd2588cce982d37d153..ee3b4aad8bd8d65239efc591cf33a631690a270f 100644 (file)
@@ -1045,6 +1045,8 @@ static void rpa_expired(struct work_struct *work)
        hci_cmd_sync_queue(hdev, rpa_expired_sync, NULL, NULL);
 }
 
+static int set_discoverable_sync(struct hci_dev *hdev, void *data);
+
 static void discov_off(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev,
@@ -1063,7 +1065,7 @@ static void discov_off(struct work_struct *work)
        hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
        hdev->discov_timeout = 0;
 
-       hci_update_discoverable(hdev);
+       hci_cmd_sync_queue(hdev, set_discoverable_sync, NULL, NULL);
 
        mgmt_new_settings(hdev);
 
index 053ef8f25fae47b369068adb49f1391b32fd7bc9..1d34d8497033299907d341212c2977b2b1d9b870 100644 (file)
@@ -1941,7 +1941,7 @@ static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s)
        /* Get data directly from socket receive queue without copying it. */
        while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
                skb_orphan(skb);
-               if (!skb_linearize(skb)) {
+               if (!skb_linearize(skb) && sk->sk_state != BT_CLOSED) {
                        s = rfcomm_recv_frame(s, skb);
                        if (!s)
                                break;
index ed17208907578a231d283c04bd97ce48bebdffaa..35e10c5a766d550e0c5cb85cf5a0c4835b52a89d 100644 (file)
 #include <linux/sysctl.h>
 #endif
 
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
+#include <net/netfilter/nf_conntrack_core.h>
+#endif
+
 static unsigned int brnf_net_id __read_mostly;
 
 struct brnf_net {
@@ -553,6 +557,90 @@ static unsigned int br_nf_pre_routing(void *priv,
        return NF_STOLEN;
 }
 
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
+/* conntracks' nf_confirm logic cannot handle cloned skbs referencing
+ * the same nf_conn entry, which will happen for multicast (broadcast)
+ * Frames on bridges.
+ *
+ * Example:
+ *      macvlan0
+ *      br0
+ *  ethX  ethY
+ *
+ * ethX (or Y) receives multicast or broadcast packet containing
+ * an IP packet, not yet in conntrack table.
+ *
+ * 1. skb passes through bridge and fake-ip (br_netfilter)Prerouting.
+ *    -> skb->_nfct now references a unconfirmed entry
+ * 2. skb is broad/mcast packet. bridge now passes clones out on each bridge
+ *    interface.
+ * 3. skb gets passed up the stack.
+ * 4. In macvlan case, macvlan driver retains clone(s) of the mcast skb
+ *    and schedules a work queue to send them out on the lower devices.
+ *
+ *    The clone skb->_nfct is not a copy, it is the same entry as the
+ *    original skb.  The macvlan rx handler then returns RX_HANDLER_PASS.
+ * 5. Normal conntrack hooks (in NF_INET_LOCAL_IN) confirm the orig skb.
+ *
+ * The Macvlan broadcast worker and normal confirm path will race.
+ *
+ * This race will not happen if step 2 already confirmed a clone. In that
+ * case later steps perform skb_clone() with skb->_nfct already confirmed (in
+ * hash table).  This works fine.
+ *
+ * But such confirmation won't happen when eb/ip/nftables rules dropped the
+ * packets before they reached the nf_confirm step in postrouting.
+ *
+ * Work around this problem by explicit confirmation of the entry at
+ * LOCAL_IN time, before upper layer has a chance to clone the unconfirmed
+ * entry.
+ *
+ */
+static unsigned int br_nf_local_in(void *priv,
+                                  struct sk_buff *skb,
+                                  const struct nf_hook_state *state)
+{
+       struct nf_conntrack *nfct = skb_nfct(skb);
+       const struct nf_ct_hook *ct_hook;
+       struct nf_conn *ct;
+       int ret;
+
+       if (!nfct || skb->pkt_type == PACKET_HOST)
+               return NF_ACCEPT;
+
+       ct = container_of(nfct, struct nf_conn, ct_general);
+       if (likely(nf_ct_is_confirmed(ct)))
+               return NF_ACCEPT;
+
+       WARN_ON_ONCE(skb_shared(skb));
+       WARN_ON_ONCE(refcount_read(&nfct->use) != 1);
+
+       /* We can't call nf_confirm here, it would create a dependency
+        * on nf_conntrack module.
+        */
+       ct_hook = rcu_dereference(nf_ct_hook);
+       if (!ct_hook) {
+               skb->_nfct = 0ul;
+               nf_conntrack_put(nfct);
+               return NF_ACCEPT;
+       }
+
+       nf_bridge_pull_encap_header(skb);
+       ret = ct_hook->confirm(skb);
+       switch (ret & NF_VERDICT_MASK) {
+       case NF_STOLEN:
+               return NF_STOLEN;
+       default:
+               nf_bridge_push_encap_header(skb);
+               break;
+       }
+
+       ct = container_of(nfct, struct nf_conn, ct_general);
+       WARN_ON_ONCE(!nf_ct_is_confirmed(ct));
+
+       return ret;
+}
+#endif
 
 /* PF_BRIDGE/FORWARD *************************************************/
 static int br_nf_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
@@ -964,6 +1052,14 @@ static const struct nf_hook_ops br_nf_ops[] = {
                .hooknum = NF_BR_PRE_ROUTING,
                .priority = NF_BR_PRI_BRNF,
        },
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
+       {
+               .hook = br_nf_local_in,
+               .pf = NFPROTO_BRIDGE,
+               .hooknum = NF_BR_LOCAL_IN,
+               .priority = NF_BR_PRI_LAST,
+       },
+#endif
        {
                .hook = br_nf_forward,
                .pf = NFPROTO_BRIDGE,
index ee84e783e1dff5b67994a3ba5a4e5d8aa875eeef..7b41ee8740cbbaf6b959d9273c49ebcd4830a5c8 100644 (file)
@@ -595,21 +595,40 @@ br_switchdev_mdb_replay_one(struct notifier_block *nb, struct net_device *dev,
 }
 
 static int br_switchdev_mdb_queue_one(struct list_head *mdb_list,
+                                     struct net_device *dev,
+                                     unsigned long action,
                                      enum switchdev_obj_id id,
                                      const struct net_bridge_mdb_entry *mp,
                                      struct net_device *orig_dev)
 {
-       struct switchdev_obj_port_mdb *mdb;
+       struct switchdev_obj_port_mdb mdb = {
+               .obj = {
+                       .id = id,
+                       .orig_dev = orig_dev,
+               },
+       };
+       struct switchdev_obj_port_mdb *pmdb;
 
-       mdb = kzalloc(sizeof(*mdb), GFP_ATOMIC);
-       if (!mdb)
-               return -ENOMEM;
+       br_switchdev_mdb_populate(&mdb, mp);
+
+       if (action == SWITCHDEV_PORT_OBJ_ADD &&
+           switchdev_port_obj_act_is_deferred(dev, action, &mdb.obj)) {
+               /* This event is already in the deferred queue of
+                * events, so this replay must be elided, lest the
+                * driver receives duplicate events for it. This can
+                * only happen when replaying additions, since
+                * modifications are always immediately visible in
+                * br->mdb_list, whereas actual event delivery may be
+                * delayed.
+                */
+               return 0;
+       }
 
-       mdb->obj.id = id;
-       mdb->obj.orig_dev = orig_dev;
-       br_switchdev_mdb_populate(mdb, mp);
-       list_add_tail(&mdb->obj.list, mdb_list);
+       pmdb = kmemdup(&mdb, sizeof(mdb), GFP_ATOMIC);
+       if (!pmdb)
+               return -ENOMEM;
 
+       list_add_tail(&pmdb->obj.list, mdb_list);
        return 0;
 }
 
@@ -677,51 +696,50 @@ br_switchdev_mdb_replay(struct net_device *br_dev, struct net_device *dev,
        if (!br_opt_get(br, BROPT_MULTICAST_ENABLED))
                return 0;
 
-       /* We cannot walk over br->mdb_list protected just by the rtnl_mutex,
-        * because the write-side protection is br->multicast_lock. But we
-        * need to emulate the [ blocking ] calling context of a regular
-        * switchdev event, so since both br->multicast_lock and RCU read side
-        * critical sections are atomic, we have no choice but to pick the RCU
-        * read side lock, queue up all our events, leave the critical section
-        * and notify switchdev from blocking context.
+       if (adding)
+               action = SWITCHDEV_PORT_OBJ_ADD;
+       else
+               action = SWITCHDEV_PORT_OBJ_DEL;
+
+       /* br_switchdev_mdb_queue_one() will take care to not queue a
+        * replay of an event that is already pending in the switchdev
+        * deferred queue. In order to safely determine that, there
+        * must be no new deferred MDB notifications enqueued for the
+        * duration of the MDB scan. Therefore, grab the write-side
+        * lock to avoid racing with any concurrent IGMP/MLD snooping.
         */
-       rcu_read_lock();
+       spin_lock_bh(&br->multicast_lock);
 
-       hlist_for_each_entry_rcu(mp, &br->mdb_list, mdb_node) {
+       hlist_for_each_entry(mp, &br->mdb_list, mdb_node) {
                struct net_bridge_port_group __rcu * const *pp;
                const struct net_bridge_port_group *p;
 
                if (mp->host_joined) {
-                       err = br_switchdev_mdb_queue_one(&mdb_list,
+                       err = br_switchdev_mdb_queue_one(&mdb_list, dev, action,
                                                         SWITCHDEV_OBJ_ID_HOST_MDB,
                                                         mp, br_dev);
                        if (err) {
-                               rcu_read_unlock();
+                               spin_unlock_bh(&br->multicast_lock);
                                goto out_free_mdb;
                        }
                }
 
-               for (pp = &mp->ports; (p = rcu_dereference(*pp)) != NULL;
+               for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL;
                     pp = &p->next) {
                        if (p->key.port->dev != dev)
                                continue;
 
-                       err = br_switchdev_mdb_queue_one(&mdb_list,
+                       err = br_switchdev_mdb_queue_one(&mdb_list, dev, action,
                                                         SWITCHDEV_OBJ_ID_PORT_MDB,
                                                         mp, dev);
                        if (err) {
-                               rcu_read_unlock();
+                               spin_unlock_bh(&br->multicast_lock);
                                goto out_free_mdb;
                        }
                }
        }
 
-       rcu_read_unlock();
-
-       if (adding)
-               action = SWITCHDEV_PORT_OBJ_ADD;
-       else
-               action = SWITCHDEV_PORT_OBJ_DEL;
+       spin_unlock_bh(&br->multicast_lock);
 
        list_for_each_entry(obj, &mdb_list, list) {
                err = br_switchdev_mdb_replay_one(nb, dev,
@@ -786,6 +804,16 @@ static void nbp_switchdev_unsync_objs(struct net_bridge_port *p,
        br_switchdev_mdb_replay(br_dev, dev, ctx, false, blocking_nb, NULL);
 
        br_switchdev_vlan_replay(br_dev, ctx, false, blocking_nb, NULL);
+
+       /* Make sure that the device leaving this bridge has seen all
+        * relevant events before it is disassociated. In the normal
+        * case, when the device is directly attached to the bridge,
+        * this is covered by del_nbp(). If the association was indirect
+        * however, e.g. via a team or bond, and the device is leaving
+        * that intermediate device, then the bridge port remains in
+        * place.
+        */
+       switchdev_deferred_process();
 }
 
 /* Let the bridge know that this port is offloaded, so that it can assign a
index abb090f94ed2609eeb9cd54b4e5faed1c3cb7bfe..6f877e31709bad3646ea15bf3a96999ed275bdc1 100644 (file)
@@ -291,6 +291,30 @@ static unsigned int nf_ct_bridge_pre(void *priv, struct sk_buff *skb,
        return nf_conntrack_in(skb, &bridge_state);
 }
 
+static unsigned int nf_ct_bridge_in(void *priv, struct sk_buff *skb,
+                                   const struct nf_hook_state *state)
+{
+       enum ip_conntrack_info ctinfo;
+       struct nf_conn *ct;
+
+       if (skb->pkt_type == PACKET_HOST)
+               return NF_ACCEPT;
+
+       /* nf_conntrack_confirm() cannot handle concurrent clones,
+        * this happens for broad/multicast frames with e.g. macvlan on top
+        * of the bridge device.
+        */
+       ct = nf_ct_get(skb, &ctinfo);
+       if (!ct || nf_ct_is_confirmed(ct) || nf_ct_is_template(ct))
+               return NF_ACCEPT;
+
+       /* let inet prerouting call conntrack again */
+       skb->_nfct = 0;
+       nf_ct_put(ct);
+
+       return NF_ACCEPT;
+}
+
 static void nf_ct_bridge_frag_save(struct sk_buff *skb,
                                   struct nf_bridge_frag_data *data)
 {
@@ -385,6 +409,12 @@ static struct nf_hook_ops nf_ct_bridge_hook_ops[] __read_mostly = {
                .hooknum        = NF_BR_PRE_ROUTING,
                .priority       = NF_IP_PRI_CONNTRACK,
        },
+       {
+               .hook           = nf_ct_bridge_in,
+               .pf             = NFPROTO_BRIDGE,
+               .hooknum        = NF_BR_LOCAL_IN,
+               .priority       = NF_IP_PRI_CONNTRACK_CONFIRM,
+       },
        {
                .hook           = nf_ct_bridge_post,
                .pf             = NFPROTO_BRIDGE,
index 16af1a7f80f60e18b5526c973f66e98821786a78..31a93cae5111b50d54e10a061a9e235e81a1da1c 100644 (file)
@@ -86,7 +86,7 @@ struct j1939_priv {
        unsigned int tp_max_packet_size;
 
        /* lock for j1939_socks list */
-       spinlock_t j1939_socks_lock;
+       rwlock_t j1939_socks_lock;
        struct list_head j1939_socks;
 
        struct kref rx_kref;
@@ -301,6 +301,7 @@ struct j1939_sock {
 
        int ifindex;
        struct j1939_addr addr;
+       spinlock_t filters_lock;
        struct j1939_filter *filters;
        int nfilters;
        pgn_t pgn_rx_filter;
index ecff1c947d683b2f3e4eeff144f39a8f5ff5de1a..a6fb89fa62785121f9edc42308b052142fda5fdd 100644 (file)
@@ -274,7 +274,7 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev)
                return ERR_PTR(-ENOMEM);
 
        j1939_tp_init(priv);
-       spin_lock_init(&priv->j1939_socks_lock);
+       rwlock_init(&priv->j1939_socks_lock);
        INIT_LIST_HEAD(&priv->j1939_socks);
 
        mutex_lock(&j1939_netdev_lock);
index 14c43166323393541bc102f47a311c79199a2acd..305dd72c844c70f1589f14fcb668bd46b92ff6f2 100644 (file)
@@ -80,16 +80,16 @@ static void j1939_jsk_add(struct j1939_priv *priv, struct j1939_sock *jsk)
        jsk->state |= J1939_SOCK_BOUND;
        j1939_priv_get(priv);
 
-       spin_lock_bh(&priv->j1939_socks_lock);
+       write_lock_bh(&priv->j1939_socks_lock);
        list_add_tail(&jsk->list, &priv->j1939_socks);
-       spin_unlock_bh(&priv->j1939_socks_lock);
+       write_unlock_bh(&priv->j1939_socks_lock);
 }
 
 static void j1939_jsk_del(struct j1939_priv *priv, struct j1939_sock *jsk)
 {
-       spin_lock_bh(&priv->j1939_socks_lock);
+       write_lock_bh(&priv->j1939_socks_lock);
        list_del_init(&jsk->list);
-       spin_unlock_bh(&priv->j1939_socks_lock);
+       write_unlock_bh(&priv->j1939_socks_lock);
 
        j1939_priv_put(priv);
        jsk->state &= ~J1939_SOCK_BOUND;
@@ -262,12 +262,17 @@ static bool j1939_sk_match_dst(struct j1939_sock *jsk,
 static bool j1939_sk_match_filter(struct j1939_sock *jsk,
                                  const struct j1939_sk_buff_cb *skcb)
 {
-       const struct j1939_filter *f = jsk->filters;
-       int nfilter = jsk->nfilters;
+       const struct j1939_filter *f;
+       int nfilter;
+
+       spin_lock_bh(&jsk->filters_lock);
+
+       f = jsk->filters;
+       nfilter = jsk->nfilters;
 
        if (!nfilter)
                /* receive all when no filters are assigned */
-               return true;
+               goto filter_match_found;
 
        for (; nfilter; ++f, --nfilter) {
                if ((skcb->addr.pgn & f->pgn_mask) != f->pgn)
@@ -276,9 +281,15 @@ static bool j1939_sk_match_filter(struct j1939_sock *jsk,
                        continue;
                if ((skcb->addr.src_name & f->name_mask) != f->name)
                        continue;
-               return true;
+               goto filter_match_found;
        }
+
+       spin_unlock_bh(&jsk->filters_lock);
        return false;
+
+filter_match_found:
+       spin_unlock_bh(&jsk->filters_lock);
+       return true;
 }
 
 static bool j1939_sk_recv_match_one(struct j1939_sock *jsk,
@@ -329,13 +340,13 @@ bool j1939_sk_recv_match(struct j1939_priv *priv, struct j1939_sk_buff_cb *skcb)
        struct j1939_sock *jsk;
        bool match = false;
 
-       spin_lock_bh(&priv->j1939_socks_lock);
+       read_lock_bh(&priv->j1939_socks_lock);
        list_for_each_entry(jsk, &priv->j1939_socks, list) {
                match = j1939_sk_recv_match_one(jsk, skcb);
                if (match)
                        break;
        }
-       spin_unlock_bh(&priv->j1939_socks_lock);
+       read_unlock_bh(&priv->j1939_socks_lock);
 
        return match;
 }
@@ -344,11 +355,11 @@ void j1939_sk_recv(struct j1939_priv *priv, struct sk_buff *skb)
 {
        struct j1939_sock *jsk;
 
-       spin_lock_bh(&priv->j1939_socks_lock);
+       read_lock_bh(&priv->j1939_socks_lock);
        list_for_each_entry(jsk, &priv->j1939_socks, list) {
                j1939_sk_recv_one(jsk, skb);
        }
-       spin_unlock_bh(&priv->j1939_socks_lock);
+       read_unlock_bh(&priv->j1939_socks_lock);
 }
 
 static void j1939_sk_sock_destruct(struct sock *sk)
@@ -401,6 +412,7 @@ static int j1939_sk_init(struct sock *sk)
        atomic_set(&jsk->skb_pending, 0);
        spin_lock_init(&jsk->sk_session_queue_lock);
        INIT_LIST_HEAD(&jsk->sk_session_queue);
+       spin_lock_init(&jsk->filters_lock);
 
        /* j1939_sk_sock_destruct() depends on SOCK_RCU_FREE flag */
        sock_set_flag(sk, SOCK_RCU_FREE);
@@ -703,9 +715,11 @@ static int j1939_sk_setsockopt(struct socket *sock, int level, int optname,
                }
 
                lock_sock(&jsk->sk);
+               spin_lock_bh(&jsk->filters_lock);
                ofilters = jsk->filters;
                jsk->filters = filters;
                jsk->nfilters = count;
+               spin_unlock_bh(&jsk->filters_lock);
                release_sock(&jsk->sk);
                kfree(ofilters);
                return 0;
@@ -1080,12 +1094,12 @@ void j1939_sk_errqueue(struct j1939_session *session,
        }
 
        /* spread RX notifications to all sockets subscribed to this session */
-       spin_lock_bh(&priv->j1939_socks_lock);
+       read_lock_bh(&priv->j1939_socks_lock);
        list_for_each_entry(jsk, &priv->j1939_socks, list) {
                if (j1939_sk_recv_match_one(jsk, &session->skcb))
                        __j1939_sk_errqueue(session, &jsk->sk, type);
        }
-       spin_unlock_bh(&priv->j1939_socks_lock);
+       read_unlock_bh(&priv->j1939_socks_lock);
 };
 
 void j1939_sk_send_loop_abort(struct sock *sk, int err)
@@ -1273,7 +1287,7 @@ void j1939_sk_netdev_event_netdown(struct j1939_priv *priv)
        struct j1939_sock *jsk;
        int error_code = ENETDOWN;
 
-       spin_lock_bh(&priv->j1939_socks_lock);
+       read_lock_bh(&priv->j1939_socks_lock);
        list_for_each_entry(jsk, &priv->j1939_socks, list) {
                jsk->sk.sk_err = error_code;
                if (!sock_flag(&jsk->sk, SOCK_DEAD))
@@ -1281,7 +1295,7 @@ void j1939_sk_netdev_event_netdown(struct j1939_priv *priv)
 
                j1939_sk_queue_drop_all(priv, jsk, error_code);
        }
-       spin_unlock_bh(&priv->j1939_socks_lock);
+       read_unlock_bh(&priv->j1939_socks_lock);
 }
 
 static int j1939_sk_no_ioctlcmd(struct socket *sock, unsigned int cmd,
index a0ca5414b333df92b3aa0085a95b928cdc0609a5..bd608ffa06279704b5f4f43e5e369035e3ff032c 100644 (file)
@@ -2034,6 +2034,9 @@ static int prepare_sparse_read_data(struct ceph_connection *con)
        if (!con_secure(con))
                con->in_data_crc = -1;
 
+       ceph_msg_data_cursor_init(&con->v2.in_cursor, msg,
+                                 msg->sparse_read_total);
+
        reset_in_kvecs(con);
        con->v2.in_state = IN_S_PREPARE_SPARSE_DATA_CONT;
        con->v2.data_len_remain = data_len(msg);
index cb2dab0feee0abe758479a7a001342bf6613df08..a892f72651890d4da0c1b954991130c07eb91ee9 100644 (file)
@@ -336,7 +336,7 @@ int netdev_name_node_alt_create(struct net_device *dev, const char *name)
                return -ENOMEM;
        netdev_name_node_add(net, name_node);
        /* The node that holds dev->name acts as a head of per-device list. */
-       list_add_tail(&name_node->list, &dev->name_node->list);
+       list_add_tail_rcu(&name_node->list, &dev->name_node->list);
 
        return 0;
 }
@@ -6177,8 +6177,13 @@ static void __busy_poll_stop(struct napi_struct *napi, bool skip_schedule)
        clear_bit(NAPI_STATE_SCHED, &napi->state);
 }
 
-static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock, bool prefer_busy_poll,
-                          u16 budget)
+enum {
+       NAPI_F_PREFER_BUSY_POLL = 1,
+       NAPI_F_END_ON_RESCHED   = 2,
+};
+
+static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock,
+                          unsigned flags, u16 budget)
 {
        bool skip_schedule = false;
        unsigned long timeout;
@@ -6198,7 +6203,7 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock, bool
 
        local_bh_disable();
 
-       if (prefer_busy_poll) {
+       if (flags & NAPI_F_PREFER_BUSY_POLL) {
                napi->defer_hard_irqs_count = READ_ONCE(napi->dev->napi_defer_hard_irqs);
                timeout = READ_ONCE(napi->dev->gro_flush_timeout);
                if (napi->defer_hard_irqs_count && timeout) {
@@ -6222,23 +6227,23 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock, bool
        local_bh_enable();
 }
 
-void napi_busy_loop(unsigned int napi_id,
-                   bool (*loop_end)(void *, unsigned long),
-                   void *loop_end_arg, bool prefer_busy_poll, u16 budget)
+static void __napi_busy_loop(unsigned int napi_id,
+                     bool (*loop_end)(void *, unsigned long),
+                     void *loop_end_arg, unsigned flags, u16 budget)
 {
        unsigned long start_time = loop_end ? busy_loop_current_time() : 0;
        int (*napi_poll)(struct napi_struct *napi, int budget);
        void *have_poll_lock = NULL;
        struct napi_struct *napi;
 
+       WARN_ON_ONCE(!rcu_read_lock_held());
+
 restart:
        napi_poll = NULL;
 
-       rcu_read_lock();
-
        napi = napi_by_id(napi_id);
        if (!napi)
-               goto out;
+               return;
 
        if (!IS_ENABLED(CONFIG_PREEMPT_RT))
                preempt_disable();
@@ -6254,14 +6259,14 @@ restart:
                         */
                        if (val & (NAPIF_STATE_DISABLE | NAPIF_STATE_SCHED |
                                   NAPIF_STATE_IN_BUSY_POLL)) {
-                               if (prefer_busy_poll)
+                               if (flags & NAPI_F_PREFER_BUSY_POLL)
                                        set_bit(NAPI_STATE_PREFER_BUSY_POLL, &napi->state);
                                goto count;
                        }
                        if (cmpxchg(&napi->state, val,
                                    val | NAPIF_STATE_IN_BUSY_POLL |
                                          NAPIF_STATE_SCHED) != val) {
-                               if (prefer_busy_poll)
+                               if (flags & NAPI_F_PREFER_BUSY_POLL)
                                        set_bit(NAPI_STATE_PREFER_BUSY_POLL, &napi->state);
                                goto count;
                        }
@@ -6281,12 +6286,15 @@ count:
                        break;
 
                if (unlikely(need_resched())) {
+                       if (flags & NAPI_F_END_ON_RESCHED)
+                               break;
                        if (napi_poll)
-                               busy_poll_stop(napi, have_poll_lock, prefer_busy_poll, budget);
+                               busy_poll_stop(napi, have_poll_lock, flags, budget);
                        if (!IS_ENABLED(CONFIG_PREEMPT_RT))
                                preempt_enable();
                        rcu_read_unlock();
                        cond_resched();
+                       rcu_read_lock();
                        if (loop_end(loop_end_arg, start_time))
                                return;
                        goto restart;
@@ -6294,10 +6302,31 @@ count:
                cpu_relax();
        }
        if (napi_poll)
-               busy_poll_stop(napi, have_poll_lock, prefer_busy_poll, budget);
+               busy_poll_stop(napi, have_poll_lock, flags, budget);
        if (!IS_ENABLED(CONFIG_PREEMPT_RT))
                preempt_enable();
-out:
+}
+
+void napi_busy_loop_rcu(unsigned int napi_id,
+                       bool (*loop_end)(void *, unsigned long),
+                       void *loop_end_arg, bool prefer_busy_poll, u16 budget)
+{
+       unsigned flags = NAPI_F_END_ON_RESCHED;
+
+       if (prefer_busy_poll)
+               flags |= NAPI_F_PREFER_BUSY_POLL;
+
+       __napi_busy_loop(napi_id, loop_end, loop_end_arg, flags, budget);
+}
+
+void napi_busy_loop(unsigned int napi_id,
+                   bool (*loop_end)(void *, unsigned long),
+                   void *loop_end_arg, bool prefer_busy_poll, u16 budget)
+{
+       unsigned flags = prefer_busy_poll ? NAPI_F_PREFER_BUSY_POLL : 0;
+
+       rcu_read_lock();
+       __napi_busy_loop(napi_id, loop_end, loop_end_arg, flags, budget);
        rcu_read_unlock();
 }
 EXPORT_SYMBOL(napi_busy_loop);
@@ -9074,28 +9103,6 @@ bool netdev_port_same_parent_id(struct net_device *a, struct net_device *b)
 }
 EXPORT_SYMBOL(netdev_port_same_parent_id);
 
-static void netdev_dpll_pin_assign(struct net_device *dev, struct dpll_pin *dpll_pin)
-{
-#if IS_ENABLED(CONFIG_DPLL)
-       rtnl_lock();
-       dev->dpll_pin = dpll_pin;
-       rtnl_unlock();
-#endif
-}
-
-void netdev_dpll_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)
-{
-       WARN_ON(!dpll_pin);
-       netdev_dpll_pin_assign(dev, dpll_pin);
-}
-EXPORT_SYMBOL(netdev_dpll_pin_set);
-
-void netdev_dpll_pin_clear(struct net_device *dev)
-{
-       netdev_dpll_pin_assign(dev, NULL);
-}
-EXPORT_SYMBOL(netdev_dpll_pin_clear);
-
 /**
  *     dev_change_proto_down - set carrier according to proto_down.
  *
@@ -11652,11 +11659,12 @@ static void __init net_dev_struct_check(void)
        CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_tx, 160);
 
        /* TXRX read-mostly hotpath */
+       CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, lstats);
        CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, flags);
        CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, hard_header_len);
        CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, features);
        CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, ip6_ptr);
-       CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_txrx, 30);
+       CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_txrx, 38);
 
        /* RX read-mostly hotpath */
        CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, ptype_specific);
index 4c2e77bd12f4b17f57f115ce4f9b99fb1da0a875..358c44680d917dfe8b324ab3a2a86fe78de44930 100644 (file)
@@ -225,7 +225,7 @@ static void gso_test_func(struct kunit *test)
 
        segs = skb_segment(skb, features);
        if (IS_ERR(segs)) {
-               KUNIT_FAIL(test, "segs error %lld", PTR_ERR(segs));
+               KUNIT_FAIL(test, "segs error %pe", segs);
                goto free_gso_skb;
        } else if (!segs) {
                KUNIT_FAIL(test, "no segments");
index ffe5244e5597e806e1cbd2dc82894276e107e91c..278294aca66ababdf5f7d383833ff5496255b274 100644 (file)
@@ -94,11 +94,12 @@ netdev_nl_page_pool_get_dump(struct sk_buff *skb, struct netlink_callback *cb,
                        state->pp_id = pool->user.id;
                        err = fill(skb, pool, info);
                        if (err)
-                               break;
+                               goto out;
                }
 
                state->pp_id = 0;
        }
+out:
        mutex_unlock(&page_pools_lock);
        rtnl_unlock();
 
index f6f29eb03ec277a1ea17ccc220fa7624bf6db092..bd50e9fe3234b6c252a199f05adcae2a09b1bbdd 100644 (file)
@@ -1020,14 +1020,17 @@ static size_t rtnl_xdp_size(void)
 static size_t rtnl_prop_list_size(const struct net_device *dev)
 {
        struct netdev_name_node *name_node;
-       size_t size;
+       unsigned int cnt = 0;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(name_node, &dev->name_node->list, list)
+               cnt++;
+       rcu_read_unlock();
 
-       if (list_empty(&dev->name_node->list))
+       if (!cnt)
                return 0;
-       size = nla_total_size(0);
-       list_for_each_entry(name_node, &dev->name_node->list, list)
-               size += nla_total_size(ALTIFNAMSIZ);
-       return size;
+
+       return nla_total_size(0) + cnt * nla_total_size(ALTIFNAMSIZ);
 }
 
 static size_t rtnl_proto_down_size(const struct net_device *dev)
@@ -1054,7 +1057,7 @@ static size_t rtnl_dpll_pin_size(const struct net_device *dev)
 {
        size_t size = nla_total_size(0); /* nest IFLA_DPLL_PIN */
 
-       size += dpll_msg_pin_handle_size(netdev_dpll_pin(dev));
+       size += dpll_netdev_pin_handle_size(dev);
 
        return size;
 }
@@ -1789,7 +1792,7 @@ static int rtnl_fill_dpll_pin(struct sk_buff *skb,
        if (!dpll_pin_nest)
                return -EMSGSIZE;
 
-       ret = dpll_msg_add_pin_handle(skb, netdev_dpll_pin(dev));
+       ret = dpll_netdev_add_pin_handle(skb, dev);
        if (ret < 0)
                goto nest_cancel;
 
@@ -5166,10 +5169,9 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
        struct net *net = sock_net(skb->sk);
        struct ifinfomsg *ifm;
        struct net_device *dev;
-       struct nlattr *br_spec, *attr = NULL;
+       struct nlattr *br_spec, *attr, *br_flags_attr = NULL;
        int rem, err = -EOPNOTSUPP;
        u16 flags = 0;
-       bool have_flags = false;
 
        if (nlmsg_len(nlh) < sizeof(*ifm))
                return -EINVAL;
@@ -5187,11 +5189,11 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
        br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
        if (br_spec) {
                nla_for_each_nested(attr, br_spec, rem) {
-                       if (nla_type(attr) == IFLA_BRIDGE_FLAGS && !have_flags) {
+                       if (nla_type(attr) == IFLA_BRIDGE_FLAGS && !br_flags_attr) {
                                if (nla_len(attr) < sizeof(flags))
                                        return -EINVAL;
 
-                               have_flags = true;
+                               br_flags_attr = attr;
                                flags = nla_get_u16(attr);
                        }
 
@@ -5235,8 +5237,8 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
                }
        }
 
-       if (have_flags)
-               memcpy(nla_data(attr), &flags, sizeof(flags));
+       if (br_flags_attr)
+               memcpy(nla_data(br_flags_attr), &flags, sizeof(flags));
 out:
        return err;
 }
index 93ecfceac1bc49bd843728518215ade5ced374a5..4d75ef9d24bfa7cbffe642448f5116ac0b943ed2 100644 (file)
@@ -1226,8 +1226,11 @@ static void sk_psock_verdict_data_ready(struct sock *sk)
 
                rcu_read_lock();
                psock = sk_psock(sk);
-               if (psock)
-                       psock->saved_data_ready(sk);
+               if (psock) {
+                       read_lock_bh(&sk->sk_callback_lock);
+                       sk_psock_data_ready(sk, psock);
+                       read_unlock_bh(&sk->sk_callback_lock);
+               }
                rcu_read_unlock();
        }
 }
index 0a7f46c37f0cfc169e11377107c8342c229da0de..5e78798456fd81dbd34e94021531340f7ba5ab0a 100644 (file)
@@ -1188,6 +1188,17 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
                 */
                WRITE_ONCE(sk->sk_txrehash, (u8)val);
                return 0;
+       case SO_PEEK_OFF:
+               {
+               int (*set_peek_off)(struct sock *sk, int val);
+
+               set_peek_off = READ_ONCE(sock->ops)->set_peek_off;
+               if (set_peek_off)
+                       ret = set_peek_off(sk, val);
+               else
+                       ret = -EOPNOTSUPP;
+               return ret;
+               }
        }
 
        sockopt_lock_sock(sk);
@@ -1430,18 +1441,6 @@ set_sndbuf:
                sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool);
                break;
 
-       case SO_PEEK_OFF:
-               {
-               int (*set_peek_off)(struct sock *sk, int val);
-
-               set_peek_off = READ_ONCE(sock->ops)->set_peek_off;
-               if (set_peek_off)
-                       ret = set_peek_off(sk, val);
-               else
-                       ret = -EOPNOTSUPP;
-               break;
-               }
-
        case SO_NOFCS:
                sock_valbool_flag(sk, SOCK_NOFCS, valbool);
                break;
index 6a58342752b4690d1f13d19eb94ee1d44b9cda61..7f0b093208d75b91e25cb78a73bece8ef2577831 100644 (file)
@@ -529,14 +529,20 @@ static int __init devlink_init(void)
 {
        int err;
 
-       err = genl_register_family(&devlink_nl_family);
-       if (err)
-               goto out;
        err = register_pernet_subsys(&devlink_pernet_ops);
        if (err)
                goto out;
+       err = genl_register_family(&devlink_nl_family);
+       if (err)
+               goto out_unreg_pernet_subsys;
        err = register_netdevice_notifier(&devlink_port_netdevice_nb);
+       if (!err)
+               return 0;
+
+       genl_unregister_family(&devlink_nl_family);
 
+out_unreg_pernet_subsys:
+       unregister_pernet_subsys(&devlink_pernet_ops);
 out:
        WARN_ON(err);
        return err;
index 78592912f657c934885077c900ef95b9d79aed4c..4b2d46ccfe484f1ae2c21b5b2921a113d59e13f5 100644 (file)
@@ -583,7 +583,7 @@ devlink_nl_port_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
 
        xa_for_each_start(&devlink->ports, port_index, devlink_port, state->idx) {
                err = devlink_nl_port_fill(msg, devlink_port,
-                                          DEVLINK_CMD_NEW,
+                                          DEVLINK_CMD_PORT_NEW,
                                           NETLINK_CB(cb->skb).portid,
                                           cb->nlh->nlmsg_seq, flags,
                                           cb->extack);
index 16ed7bfd29e4fbf39e204278950834b9e69b9f97..34fd1d9b2db861de15f7ce68828abedbf6bc771c 100644 (file)
@@ -471,7 +471,10 @@ static void handshake_req_destroy_test1(struct kunit *test)
        handshake_req_cancel(sock->sk);
 
        /* Act */
-       fput(filp);
+       /* Ensure the close/release/put process has run to
+        * completion before checking the result.
+        */
+       __fput_sync(filp);
 
        /* Assert */
        KUNIT_EXPECT_PTR_EQ(test, handshake_req_destroy_test, req);
index 80cdc6f6b34c97601961179c4839dc68c0a6d2e1..5d68cb181695d9a9f83809142a0300b8ddad5f53 100644 (file)
@@ -83,7 +83,7 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb)
                return false;
 
        /* Get next tlv */
-       total_length += sizeof(struct hsr_sup_tlv) + hsr_sup_tag->tlv.HSR_TLV_length;
+       total_length += hsr_sup_tag->tlv.HSR_TLV_length;
        if (!pskb_may_pull(skb, total_length))
                return false;
        skb_pull(skb, total_length);
@@ -435,7 +435,7 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
                        continue;
 
                /* Don't send frame over port where it has been sent before.
-                * Also fro SAN, this shouldn't be done.
+                * Also for SAN, this shouldn't be done.
                 */
                if (!frame->is_from_san &&
                    hsr_register_frame_out(port, frame->node_src,
index a2e6e1fdf82be44c15daefa2a423967ccd8999f7..64aec3dff8ec85135a8d14e5618900927eb59959 100644 (file)
@@ -597,5 +597,6 @@ static void __exit ah4_fini(void)
 
 module_init(ah4_init);
 module_exit(ah4_fini);
+MODULE_DESCRIPTION("IPv4 AH transformation library");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_AH);
index 9456f5bb35e5d9e97d6c05be21561b435e2b704a..0d0d725b46ad0c56b19b6356f6d3e6be8bdcae83 100644 (file)
@@ -1125,7 +1125,8 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)
        if (neigh) {
                if (!(READ_ONCE(neigh->nud_state) & NUD_NOARP)) {
                        read_lock_bh(&neigh->lock);
-                       memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len);
+                       memcpy(r->arp_ha.sa_data, neigh->ha,
+                              min(dev->addr_len, sizeof(r->arp_ha.sa_data_min)));
                        r->arp_flags = arp_state_to_flags(neigh);
                        read_unlock_bh(&neigh->lock);
                        r->arp_ha.sa_family = dev->type;
index ca0ff15dc8fa358b81a804eda7398ecd10f00743..bc74f131fe4dfad327e71c1a8f0a4b66cdc526e5 100644 (file)
@@ -1825,6 +1825,21 @@ done:
        return err;
 }
 
+/* Combine dev_addr_genid and dev_base_seq to detect changes.
+ */
+static u32 inet_base_seq(const struct net *net)
+{
+       u32 res = atomic_read(&net->ipv4.dev_addr_genid) +
+                 net->dev_base_seq;
+
+       /* Must not return 0 (see nl_dump_check_consistent()).
+        * Chose a value far away from 0.
+        */
+       if (!res)
+               res = 0x80000000;
+       return res;
+}
+
 static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
        const struct nlmsghdr *nlh = cb->nlh;
@@ -1876,8 +1891,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
                idx = 0;
                head = &tgt_net->dev_index_head[h];
                rcu_read_lock();
-               cb->seq = atomic_read(&tgt_net->ipv4.dev_addr_genid) ^
-                         tgt_net->dev_base_seq;
+               cb->seq = inet_base_seq(tgt_net);
                hlist_for_each_entry_rcu(dev, head, index_hlist) {
                        if (idx < s_idx)
                                goto cont;
@@ -2278,8 +2292,7 @@ static int inet_netconf_dump_devconf(struct sk_buff *skb,
                idx = 0;
                head = &net->dev_index_head[h];
                rcu_read_lock();
-               cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
-                         net->dev_base_seq;
+               cb->seq = inet_base_seq(net);
                hlist_for_each_entry_rcu(dev, head, index_hlist) {
                        if (idx < s_idx)
                                goto cont;
index 4ccfc104f13a517ec15e5b609502708c289e3b57..4dd9e50406720cfc90d280f61e4616d6a2e58d3c 100644 (file)
@@ -1247,5 +1247,6 @@ static void __exit esp4_fini(void)
 
 module_init(esp4_init);
 module_exit(esp4_fini);
+MODULE_DESCRIPTION("IPv4 ESP transformation library");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_ESP);
index 93e9193df54461b25c61089bd5db4dd33c32dab6..308ff34002ea6b5e0620004f65ffd833087afbc1 100644 (file)
@@ -1130,10 +1130,33 @@ ok:
        return 0;
 
 error:
+       if (sk_hashed(sk)) {
+               spinlock_t *lock = inet_ehash_lockp(hinfo, sk->sk_hash);
+
+               sock_prot_inuse_add(net, sk->sk_prot, -1);
+
+               spin_lock(lock);
+               sk_nulls_del_node_init_rcu(sk);
+               spin_unlock(lock);
+
+               sk->sk_hash = 0;
+               inet_sk(sk)->inet_sport = 0;
+               inet_sk(sk)->inet_num = 0;
+
+               if (tw)
+                       inet_twsk_bind_unhash(tw, hinfo);
+       }
+
        spin_unlock(&head2->lock);
        if (tb_created)
                inet_bind_bucket_destroy(hinfo->bind_bucket_cachep, tb);
-       spin_unlock_bh(&head->lock);
+       spin_unlock(&head->lock);
+
+       if (tw)
+               inet_twsk_deschedule_put(tw);
+
+       local_bh_enable();
+
        return -ENOMEM;
 }
 
index 5169c3c72cffe49cef613e69889d139db867ff74..6b9cf5a24c19ff06634f7841141b8a30639b8d17 100644 (file)
@@ -1793,6 +1793,7 @@ static void __exit ipgre_fini(void)
 
 module_init(ipgre_init);
 module_exit(ipgre_fini);
+MODULE_DESCRIPTION("IPv4 GRE tunnels over IP library");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_RTNL_LINK("gre");
 MODULE_ALIAS_RTNL_LINK("gretap");
index 41537d18eecfd6e1163aacc35e047c22468e04e6..67d846622365e8da9c2295f76943a504d16b066f 100644 (file)
@@ -972,8 +972,8 @@ static int __ip_append_data(struct sock *sk,
        unsigned int maxfraglen, fragheaderlen, maxnonfragsize;
        int csummode = CHECKSUM_NONE;
        struct rtable *rt = (struct rtable *)cork->dst;
+       bool paged, hold_tskey, extra_uref = false;
        unsigned int wmem_alloc_delta = 0;
-       bool paged, extra_uref = false;
        u32 tskey = 0;
 
        skb = skb_peek_tail(queue);
@@ -982,10 +982,6 @@ static int __ip_append_data(struct sock *sk,
        mtu = cork->gso_size ? IP_MAX_MTU : cork->fragsize;
        paged = !!cork->gso_size;
 
-       if (cork->tx_flags & SKBTX_ANY_TSTAMP &&
-           READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID)
-               tskey = atomic_inc_return(&sk->sk_tskey) - 1;
-
        hh_len = LL_RESERVED_SPACE(rt->dst.dev);
 
        fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
@@ -1052,6 +1048,11 @@ static int __ip_append_data(struct sock *sk,
 
        cork->length += length;
 
+       hold_tskey = cork->tx_flags & SKBTX_ANY_TSTAMP &&
+                    READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID;
+       if (hold_tskey)
+               tskey = atomic_inc_return(&sk->sk_tskey) - 1;
+
        /* So, what's going on in the loop below?
         *
         * We use calculated fragment length to generate chained skb,
@@ -1274,6 +1275,8 @@ error:
        cork->length -= length;
        IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS);
        refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
+       if (hold_tskey)
+               atomic_dec(&sk->sk_tskey);
        return err;
 }
 
index beeae624c412d752bd5ee5d459a88f57640445e9..1b6981de3f29514dac72161be02f3ac6e4625551 100644 (file)
@@ -554,6 +554,20 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
        return 0;
 }
 
+static void ip_tunnel_adj_headroom(struct net_device *dev, unsigned int headroom)
+{
+       /* we must cap headroom to some upperlimit, else pskb_expand_head
+        * will overflow header offsets in skb_headers_offset_update().
+        */
+       static const unsigned int max_allowed = 512;
+
+       if (headroom > max_allowed)
+               headroom = max_allowed;
+
+       if (headroom > READ_ONCE(dev->needed_headroom))
+               WRITE_ONCE(dev->needed_headroom, headroom);
+}
+
 void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                       u8 proto, int tunnel_hlen)
 {
@@ -632,13 +646,13 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        }
 
        headroom += LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len;
-       if (headroom > READ_ONCE(dev->needed_headroom))
-               WRITE_ONCE(dev->needed_headroom, headroom);
-
-       if (skb_cow_head(skb, READ_ONCE(dev->needed_headroom))) {
+       if (skb_cow_head(skb, headroom)) {
                ip_rt_put(rt);
                goto tx_dropped;
        }
+
+       ip_tunnel_adj_headroom(dev, headroom);
+
        iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, proto, tos, ttl,
                      df, !net_eq(tunnel->net, dev_net(dev)));
        return;
@@ -818,16 +832,16 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
 
        max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr)
                        + rt->dst.header_len + ip_encap_hlen(&tunnel->encap);
-       if (max_headroom > READ_ONCE(dev->needed_headroom))
-               WRITE_ONCE(dev->needed_headroom, max_headroom);
 
-       if (skb_cow_head(skb, READ_ONCE(dev->needed_headroom))) {
+       if (skb_cow_head(skb, max_headroom)) {
                ip_rt_put(rt);
                DEV_STATS_INC(dev, tx_dropped);
                kfree_skb(skb);
                return;
        }
 
+       ip_tunnel_adj_headroom(dev, max_headroom);
+
        iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl,
                      df, !net_eq(tunnel->net, dev_net(dev)));
        return;
@@ -1298,4 +1312,5 @@ void ip_tunnel_setup(struct net_device *dev, unsigned int net_id)
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_setup);
 
+MODULE_DESCRIPTION("IPv4 tunnel implementation library");
 MODULE_LICENSE("GPL");
index 9ab9b3ebe0cd1a9e95f489d98c5a3d89c7c0edf6..d1d6bb28ed6e95c6e9c247bf1df1b27287bc8328 100644 (file)
@@ -721,6 +721,7 @@ static void __exit vti_fini(void)
 
 module_init(vti_init);
 module_exit(vti_fini);
+MODULE_DESCRIPTION("Virtual (secure) IP tunneling library");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_RTNL_LINK("vti");
 MODULE_ALIAS_NETDEV("ip_vti0");
index 27b8f83c6ea200314f41a29ecfea494b9ddef2ca..03afa3871efc53b5af543e7d53283be69a02f818 100644 (file)
@@ -658,6 +658,7 @@ static void __exit ipip_fini(void)
 
 module_init(ipip_init);
 module_exit(ipip_fini);
+MODULE_DESCRIPTION("IP/IP protocol decoder library");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_RTNL_LINK("ipip");
 MODULE_ALIAS_NETDEV("tunl0");
index 7e2481b9eae1b791e1ec65f39efa41837a9fcbd3..c82dc42f57c65df112f79080ff407cd98d11ce68 100644 (file)
@@ -4615,7 +4615,8 @@ static void __init tcp_struct_check(void)
        CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, prr_out);
        CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, lost_out);
        CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, sacked_out);
-       CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_read_txrx, 31);
+       CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, scaling_ratio);
+       CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_read_txrx, 32);
 
        /* RX read-mostly hotpath cache lines */
        CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, copied_seq);
index 5048c47c79b2848a1b42032dceb4884f43cd4748..4c1f836aae38b7a75b912db9e2cdc84ccfc48e56 100644 (file)
@@ -294,4 +294,5 @@ static void __exit tunnel4_fini(void)
 
 module_init(tunnel4_init);
 module_exit(tunnel4_fini);
+MODULE_DESCRIPTION("IPv4 XFRM tunnel library");
 MODULE_LICENSE("GPL");
index f631b0a21af4c7a520212c94ed0580f86d269ed2..e474b201900f9317069a31e4b507964fe11b2297 100644 (file)
@@ -1589,12 +1589,7 @@ int udp_init_sock(struct sock *sk)
 
 void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len)
 {
-       if (unlikely(READ_ONCE(sk->sk_peek_off) >= 0)) {
-               bool slow = lock_sock_fast(sk);
-
-               sk_peek_offset_bwd(sk, len);
-               unlock_sock_fast(sk, slow);
-       }
+       sk_peek_offset_bwd(sk, len);
 
        if (!skb_unref(skb))
                return;
index a87defb2b16729886d20fcec53cea939c7fea4b7..860aff5f85990252607651c173a6d84006e5afe1 100644 (file)
@@ -253,4 +253,5 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb,
 }
 EXPORT_SYMBOL_GPL(udp_tunnel_dst_lookup);
 
+MODULE_DESCRIPTION("IPv4 Foo over UDP tunnel driver");
 MODULE_LICENSE("GPL");
index 8489fa10658377eb0942943e537a453d781f4520..8cb266af139311b48af474fc19eff32c6d8b5e37 100644 (file)
@@ -114,5 +114,6 @@ static void __exit ipip_fini(void)
 
 module_init(ipip_init);
 module_exit(ipip_fini);
+MODULE_DESCRIPTION("IPv4 XFRM tunnel driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_IPIP);
index 733ace18806c61f487d83081dc6d39d079959f77..055230b669cf21d87738a4371543c599c3476f98 100644 (file)
@@ -708,6 +708,22 @@ errout:
        return err;
 }
 
+/* Combine dev_addr_genid and dev_base_seq to detect changes.
+ */
+static u32 inet6_base_seq(const struct net *net)
+{
+       u32 res = atomic_read(&net->ipv6.dev_addr_genid) +
+                 net->dev_base_seq;
+
+       /* Must not return 0 (see nl_dump_check_consistent()).
+        * Chose a value far away from 0.
+        */
+       if (!res)
+               res = 0x80000000;
+       return res;
+}
+
+
 static int inet6_netconf_dump_devconf(struct sk_buff *skb,
                                      struct netlink_callback *cb)
 {
@@ -741,8 +757,7 @@ static int inet6_netconf_dump_devconf(struct sk_buff *skb,
                idx = 0;
                head = &net->dev_index_head[h];
                rcu_read_lock();
-               cb->seq = atomic_read(&net->ipv6.dev_addr_genid) ^
-                         net->dev_base_seq;
+               cb->seq = inet6_base_seq(net);
                hlist_for_each_entry_rcu(dev, head, index_hlist) {
                        if (idx < s_idx)
                                goto cont;
@@ -5362,7 +5377,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
        }
 
        rcu_read_lock();
-       cb->seq = atomic_read(&tgt_net->ipv6.dev_addr_genid) ^ tgt_net->dev_base_seq;
+       cb->seq = inet6_base_seq(tgt_net);
        for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
                idx = 0;
                head = &tgt_net->dev_index_head[h];
@@ -5494,9 +5509,10 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh,
        }
 
        addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL], &peer);
-       if (!addr)
-               return -EINVAL;
-
+       if (!addr) {
+               err = -EINVAL;
+               goto errout;
+       }
        ifm = nlmsg_data(nlh);
        if (ifm->ifa_index)
                dev = dev_get_by_index(tgt_net, ifm->ifa_index);
index 2016e90e6e1d21a49696c9933f1b77320cc71953..eb474f0987ae016b9d800e9f83d70d73171b21d2 100644 (file)
@@ -800,5 +800,6 @@ static void __exit ah6_fini(void)
 module_init(ah6_init);
 module_exit(ah6_fini);
 
+MODULE_DESCRIPTION("IPv6 AH transformation helpers");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_AH);
index 2cc1a45742d823a793d95140910942fb83e7f331..6e6efe026cdcc2feab9a1f18fb784042b586f045 100644 (file)
@@ -1301,5 +1301,6 @@ static void __exit esp6_fini(void)
 module_init(esp6_init);
 module_exit(esp6_fini);
 
+MODULE_DESCRIPTION("IPv6 ESP transformation helpers");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ESP);
index 4952ae792450575d275f1565d2bc198e440b67f6..02e9ffb63af1971c0949ccd0c392b995efb41ccb 100644 (file)
@@ -177,6 +177,8 @@ static bool ip6_parse_tlv(bool hopbyhop,
                                case IPV6_TLV_IOAM:
                                        if (!ipv6_hop_ioam(skb, off))
                                                return false;
+
+                                       nh = skb_network_header(skb);
                                        break;
                                case IPV6_TLV_JUMBO:
                                        if (!ipv6_hop_jumbo(skb, off))
@@ -943,6 +945,14 @@ static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff)
                if (!skb_valid_dst(skb))
                        ip6_route_input(skb);
 
+               /* About to mangle packet header */
+               if (skb_ensure_writable(skb, optoff + 2 + hdr->opt_len))
+                       goto drop;
+
+               /* Trace pointer may have changed */
+               trace = (struct ioam6_trace_hdr *)(skb_network_header(skb)
+                                                  + optoff + sizeof(*hdr));
+
                ioam6_fill_trace_data(skb, ns, trace, true);
                break;
        default:
index a722a43dd668581cf4efb08ee5ab8410e5adebb7..31b86fe661aa6cd94fb5d8848900406c2db110e3 100644 (file)
@@ -1424,11 +1424,11 @@ static int __ip6_append_data(struct sock *sk,
        bool zc = false;
        u32 tskey = 0;
        struct rt6_info *rt = (struct rt6_info *)cork->dst;
+       bool paged, hold_tskey, extra_uref = false;
        struct ipv6_txoptions *opt = v6_cork->opt;
        int csummode = CHECKSUM_NONE;
        unsigned int maxnonfragsize, headersize;
        unsigned int wmem_alloc_delta = 0;
-       bool paged, extra_uref = false;
 
        skb = skb_peek_tail(queue);
        if (!skb) {
@@ -1440,10 +1440,6 @@ static int __ip6_append_data(struct sock *sk,
        mtu = cork->gso_size ? IP6_MAX_MTU : cork->fragsize;
        orig_mtu = mtu;
 
-       if (cork->tx_flags & SKBTX_ANY_TSTAMP &&
-           READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID)
-               tskey = atomic_inc_return(&sk->sk_tskey) - 1;
-
        hh_len = LL_RESERVED_SPACE(rt->dst.dev);
 
        fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
@@ -1538,6 +1534,11 @@ emsgsize:
                        flags &= ~MSG_SPLICE_PAGES;
        }
 
+       hold_tskey = cork->tx_flags & SKBTX_ANY_TSTAMP &&
+                    READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID;
+       if (hold_tskey)
+               tskey = atomic_inc_return(&sk->sk_tskey) - 1;
+
        /*
         * Let's try using as much space as possible.
         * Use MTU if total length of the message fits into the MTU.
@@ -1794,6 +1795,8 @@ error:
        cork->length -= length;
        IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
        refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
+       if (hold_tskey)
+               atomic_dec(&sk->sk_tskey);
        return err;
 }
 
index a7bf0327b380be90bfdcc2182ed3a4296a0e814f..c99053189ea8a13be63927290576655e8da0c0fb 100644 (file)
@@ -182,4 +182,5 @@ struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb,
 }
 EXPORT_SYMBOL_GPL(udp_tunnel6_dst_lookup);
 
+MODULE_DESCRIPTION("IPv6 Foo over UDP tunnel driver");
 MODULE_LICENSE("GPL");
index 83d2a8be263fb7bdd0cbe820168b1aac9a4336b2..6a16a5bd0d910bca55a87c55580cbd1cae71bede 100644 (file)
@@ -405,6 +405,7 @@ static void __exit mip6_fini(void)
 module_init(mip6_init);
 module_exit(mip6_fini);
 
+MODULE_DESCRIPTION("IPv6 Mobility driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_DSTOPTS);
 MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ROUTING);
index ea1dec8448fce8ccf29be650301e937cfce6bd7a..ef815ba583a8f4ed0ca523a13c515f108132a939 100644 (file)
@@ -5332,19 +5332,7 @@ static int ip6_route_multipath_add(struct fib6_config *cfg,
        err_nh = NULL;
        list_for_each_entry(nh, &rt6_nh_list, next) {
                err = __ip6_ins_rt(nh->fib6_info, info, extack);
-               fib6_info_release(nh->fib6_info);
-
-               if (!err) {
-                       /* save reference to last route successfully inserted */
-                       rt_last = nh->fib6_info;
-
-                       /* save reference to first route for notification */
-                       if (!rt_notif)
-                               rt_notif = nh->fib6_info;
-               }
 
-               /* nh->fib6_info is used or freed at this point, reset to NULL*/
-               nh->fib6_info = NULL;
                if (err) {
                        if (replace && nhn)
                                NL_SET_ERR_MSG_MOD(extack,
@@ -5352,6 +5340,12 @@ static int ip6_route_multipath_add(struct fib6_config *cfg,
                        err_nh = nh;
                        goto add_errout;
                }
+               /* save reference to last route successfully inserted */
+               rt_last = nh->fib6_info;
+
+               /* save reference to first route for notification */
+               if (!rt_notif)
+                       rt_notif = nh->fib6_info;
 
                /* Because each route is added like a single route we remove
                 * these flags after the first nexthop: if there is a collision,
@@ -5412,8 +5406,7 @@ add_errout:
 
 cleanup:
        list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
-               if (nh->fib6_info)
-                       fib6_info_release(nh->fib6_info);
+               fib6_info_release(nh->fib6_info);
                list_del(&nh->next);
                kfree(nh);
        }
index 29346a6eec9ffed46b00153c4a6cb0295a327ceb..35508abd76f43d771ed7e66f29bc143af4a81977 100644 (file)
@@ -512,22 +512,24 @@ int __init seg6_init(void)
 {
        int err;
 
-       err = genl_register_family(&seg6_genl_family);
+       err = register_pernet_subsys(&ip6_segments_ops);
        if (err)
                goto out;
 
-       err = register_pernet_subsys(&ip6_segments_ops);
+       err = genl_register_family(&seg6_genl_family);
        if (err)
-               goto out_unregister_genl;
+               goto out_unregister_pernet;
 
 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
        err = seg6_iptunnel_init();
        if (err)
-               goto out_unregister_pernet;
+               goto out_unregister_genl;
 
        err = seg6_local_init();
-       if (err)
-               goto out_unregister_pernet;
+       if (err) {
+               seg6_iptunnel_exit();
+               goto out_unregister_genl;
+       }
 #endif
 
 #ifdef CONFIG_IPV6_SEG6_HMAC
@@ -548,11 +550,11 @@ out_unregister_iptun:
 #endif
 #endif
 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
-out_unregister_pernet:
-       unregister_pernet_subsys(&ip6_segments_ops);
-#endif
 out_unregister_genl:
        genl_unregister_family(&seg6_genl_family);
+#endif
+out_unregister_pernet:
+       unregister_pernet_subsys(&ip6_segments_ops);
        goto out;
 }
 
index cc24cefdb85c0944c03c019b1c4214302d18e2c8..5e9f625b76e36b9a61c6c2db0b4163e78dca549a 100644 (file)
@@ -1956,6 +1956,7 @@ xfrm_tunnel_failed:
 
 module_init(sit_init);
 module_exit(sit_cleanup);
+MODULE_DESCRIPTION("IPv6-in-IPv4 tunnel SIT driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_RTNL_LINK("sit");
 MODULE_ALIAS_NETDEV("sit0");
index 00e8d8b1c9a75fa1a820ac85eba91e3e24750c01..dc4ea9b11794e800eb027855e59a56fa6197df0b 100644 (file)
@@ -302,4 +302,5 @@ static void __exit tunnel6_fini(void)
 
 module_init(tunnel6_init);
 module_exit(tunnel6_fini);
+MODULE_DESCRIPTION("IP-in-IPv6 tunnel driver");
 MODULE_LICENSE("GPL");
index 1323f2f6928e2abf277e9ce7bd06025cd0049031..f6cb94f82cc3a2b40717a0c4406801dd26ac18c3 100644 (file)
@@ -401,5 +401,6 @@ static void __exit xfrm6_tunnel_fini(void)
 
 module_init(xfrm6_tunnel_init);
 module_exit(xfrm6_tunnel_fini);
+MODULE_DESCRIPTION("IPv6 XFRM tunnel driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_IPV6);
index 6334f64f04d5f28c7e01e959d18b343d7c641336..b0b3e9c5af44fdd83b0a108bdeb0f3f6a3ffb85e 100644 (file)
@@ -156,7 +156,7 @@ static char iucv_error_pathid[16] = "INVALID PATHID";
 static LIST_HEAD(iucv_handler_list);
 
 /*
- * iucv_path_table: an array of iucv_path structures.
+ * iucv_path_table: array of pointers to iucv_path structures.
  */
 static struct iucv_path **iucv_path_table;
 static unsigned long iucv_max_pathid;
@@ -544,7 +544,7 @@ static int iucv_enable(void)
 
        cpus_read_lock();
        rc = -ENOMEM;
-       alloc_size = iucv_max_pathid * sizeof(struct iucv_path);
+       alloc_size = iucv_max_pathid * sizeof(*iucv_path_table);
        iucv_path_table = kzalloc(alloc_size, GFP_KERNEL);
        if (!iucv_path_table)
                goto out;
index d68d01804dc7bcf7df78ff6968518298fe9d596a..f79fb99271ed84b8fe981a2b34a25b6abcf9d8e0 100644 (file)
@@ -3924,5 +3924,6 @@ out_unregister_key_proto:
 
 module_init(ipsec_pfkey_init);
 module_exit(ipsec_pfkey_exit);
+MODULE_DESCRIPTION("PF_KEY socket helpers");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_NETPROTO(PF_KEY);
index dd3153966173db09d42de02fa3ad4d44d05620f4..7bf14cf9ffaa967483ac0ee01e3f8e835754cd57 100644 (file)
@@ -627,7 +627,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 
 back_from_confirm:
        lock_sock(sk);
-       ulen = len + skb_queue_empty(&sk->sk_write_queue) ? transhdrlen : 0;
+       ulen = len + (skb_queue_empty(&sk->sk_write_queue) ? transhdrlen : 0);
        err = ip6_append_data(sk, ip_generic_getfrag, msg,
                              ulen, transhdrlen, &ipc6,
                              &fl6, (struct rt6_info *)dst,
index d5ea5f5bcf3a069e1d4dc5dd2638275e58aae51f..9d33fd2377c88af8ec38b6e398d103449f3b03b8 100644 (file)
@@ -119,7 +119,8 @@ void rate_control_rate_update(struct ieee80211_local *local,
                rcu_read_unlock();
        }
 
-       drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
+       if (sta->uploaded)
+               drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
 }
 
 int ieee80211_rate_control_register(const struct rate_control_ops *ops)
index e448ab33844896881bfbf1f5283a2f77ae5ee4e8..6fbb15b65902c754ea4c2487a40d4ce0ed38634a 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
- * Copyright (C) 2018-2022 Intel Corporation
+ * Copyright (C) 2018-2024 Intel Corporation
  *
  * Transmit and frame generation functions.
  */
@@ -3927,6 +3927,7 @@ begin:
                        goto begin;
 
                skb = __skb_dequeue(&tx.skbs);
+               info = IEEE80211_SKB_CB(skb);
 
                if (!skb_queue_empty(&tx.skbs)) {
                        spin_lock_bh(&fq->lock);
@@ -3971,7 +3972,7 @@ begin:
        }
 
 encap_out:
-       IEEE80211_SKB_CB(skb)->control.vif = vif;
+       info->control.vif = vif;
 
        if (tx.sta &&
            wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
index 7a47a58aa54b446acf7451ba6bdc1b834adda327..ceee44ea09d97b025a490058403cf435e3337ef5 100644 (file)
@@ -663,7 +663,7 @@ struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk,
        spin_unlock_irqrestore(&mns->keys_lock, flags);
 
        if (!tagbits) {
-               kfree(key);
+               mctp_key_unref(key);
                return ERR_PTR(-EBUSY);
        }
 
@@ -888,7 +888,7 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt,
                dev = dev_get_by_index_rcu(sock_net(sk), cb->ifindex);
                if (!dev) {
                        rcu_read_unlock();
-                       return rc;
+                       goto out_free;
                }
                rt->dev = __mctp_dev_get(dev);
                rcu_read_unlock();
@@ -903,7 +903,8 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt,
                rt->mtu = 0;
 
        } else {
-               return -EINVAL;
+               rc = -EINVAL;
+               goto out_free;
        }
 
        spin_lock_irqsave(&rt->dev->addrs_lock, flags);
@@ -966,12 +967,17 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt,
                rc = mctp_do_fragment_route(rt, skb, mtu, tag);
        }
 
+       /* route output functions consume the skb, even on error */
+       skb = NULL;
+
 out_release:
        if (!ext_rt)
                mctp_route_release(rt);
 
        mctp_dev_put(tmp_rt.dev);
 
+out_free:
+       kfree_skb(skb);
        return rc;
 }
 
index a536586742f28c1ddd54c79e62eb56fea267a8fa..7017dd60659dc7133318c1c82e3f429bea3a5d57 100644 (file)
 #include <uapi/linux/mptcp.h>
 #include "protocol.h"
 
-static int subflow_get_info(const struct sock *sk, struct sk_buff *skb)
+static int subflow_get_info(struct sock *sk, struct sk_buff *skb)
 {
        struct mptcp_subflow_context *sf;
        struct nlattr *start;
        u32 flags = 0;
+       bool slow;
        int err;
 
+       if (inet_sk_state_load(sk) == TCP_LISTEN)
+               return 0;
+
        start = nla_nest_start_noflag(skb, INET_ULP_INFO_MPTCP);
        if (!start)
                return -EMSGSIZE;
 
+       slow = lock_sock_fast(sk);
        rcu_read_lock();
        sf = rcu_dereference(inet_csk(sk)->icsk_ulp_data);
        if (!sf) {
@@ -63,17 +68,19 @@ static int subflow_get_info(const struct sock *sk, struct sk_buff *skb)
                        sf->map_data_len) ||
            nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_FLAGS, flags) ||
            nla_put_u8(skb, MPTCP_SUBFLOW_ATTR_ID_REM, sf->remote_id) ||
-           nla_put_u8(skb, MPTCP_SUBFLOW_ATTR_ID_LOC, sf->local_id)) {
+           nla_put_u8(skb, MPTCP_SUBFLOW_ATTR_ID_LOC, subflow_get_local_id(sf))) {
                err = -EMSGSIZE;
                goto nla_failure;
        }
 
        rcu_read_unlock();
+       unlock_sock_fast(sk, slow);
        nla_nest_end(skb, start);
        return 0;
 
 nla_failure:
        rcu_read_unlock();
+       unlock_sock_fast(sk, slow);
        nla_nest_cancel(skb, start);
        return err;
 }
index 74698582a2859e4d6ea40abaf8d0f31943e0d128..ad28da655f8bcc75e4ea05d4de2e2ab073ebc2c5 100644 (file)
@@ -59,13 +59,12 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf
        mptcp_data_unlock(sk);
 }
 
-void mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow,
-                                  const struct mptcp_options_received *mp_opt)
+void __mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow,
+                                    const struct mptcp_options_received *mp_opt)
 {
        struct sock *sk = (struct sock *)msk;
        struct sk_buff *skb;
 
-       mptcp_data_lock(sk);
        skb = skb_peek_tail(&sk->sk_receive_queue);
        if (skb) {
                WARN_ON_ONCE(MPTCP_SKB_CB(skb)->end_seq);
@@ -77,5 +76,4 @@ void mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_
        }
 
        pr_debug("msk=%p ack_seq=%llx", msk, msk->ack_seq);
-       mptcp_data_unlock(sk);
 }
index d2527d189a799319c068a5b76a5816cc7a905861..63fc0758c22d45e356d4edadff991b7e88ec8659 100644 (file)
@@ -962,9 +962,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
                /* subflows are fully established as soon as we get any
                 * additional ack, including ADD_ADDR.
                 */
-               subflow->fully_established = 1;
-               WRITE_ONCE(msk->fully_established, true);
-               goto check_notify;
+               goto set_fully_established;
        }
 
        /* If the first established packet does not contain MP_CAPABLE + data
@@ -983,10 +981,13 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
        if (mp_opt->deny_join_id0)
                WRITE_ONCE(msk->pm.remote_deny_join_id0, true);
 
-set_fully_established:
        if (unlikely(!READ_ONCE(msk->pm.server_side)))
                pr_warn_once("bogus mpc option on established client sk");
-       mptcp_subflow_fully_established(subflow, mp_opt);
+
+set_fully_established:
+       mptcp_data_lock((struct sock *)msk);
+       __mptcp_subflow_fully_established(msk, subflow, mp_opt);
+       mptcp_data_unlock((struct sock *)msk);
 
 check_notify:
        /* if the subflow is not already linked into the conn_list, we can't
index 287a60381eae6e39c68d49a65530ea5bdc8a6675..58d17d9604e78fde24795219e53e18646c53b0de 100644 (file)
@@ -396,19 +396,6 @@ void mptcp_pm_free_anno_list(struct mptcp_sock *msk)
        }
 }
 
-static bool lookup_address_in_vec(const struct mptcp_addr_info *addrs, unsigned int nr,
-                                 const struct mptcp_addr_info *addr)
-{
-       int i;
-
-       for (i = 0; i < nr; i++) {
-               if (addrs[i].id == addr->id)
-                       return true;
-       }
-
-       return false;
-}
-
 /* Fill all the remote addresses into the array addrs[],
  * and return the array size.
  */
@@ -440,18 +427,34 @@ static unsigned int fill_remote_addresses_vec(struct mptcp_sock *msk,
                msk->pm.subflows++;
                addrs[i++] = remote;
        } else {
+               DECLARE_BITMAP(unavail_id, MPTCP_PM_MAX_ADDR_ID + 1);
+
+               /* Forbid creation of new subflows matching existing
+                * ones, possibly already created by incoming ADD_ADDR
+                */
+               bitmap_zero(unavail_id, MPTCP_PM_MAX_ADDR_ID + 1);
+               mptcp_for_each_subflow(msk, subflow)
+                       if (READ_ONCE(subflow->local_id) == local->id)
+                               __set_bit(subflow->remote_id, unavail_id);
+
                mptcp_for_each_subflow(msk, subflow) {
                        ssk = mptcp_subflow_tcp_sock(subflow);
                        remote_address((struct sock_common *)ssk, &addrs[i]);
-                       addrs[i].id = subflow->remote_id;
+                       addrs[i].id = READ_ONCE(subflow->remote_id);
                        if (deny_id0 && !addrs[i].id)
                                continue;
 
+                       if (test_bit(addrs[i].id, unavail_id))
+                               continue;
+
                        if (!mptcp_pm_addr_families_match(sk, local, &addrs[i]))
                                continue;
 
-                       if (!lookup_address_in_vec(addrs, i, &addrs[i]) &&
-                           msk->pm.subflows < subflows_max) {
+                       if (msk->pm.subflows < subflows_max) {
+                               /* forbid creating multiple address towards
+                                * this id
+                                */
+                               __set_bit(addrs[i].id, unavail_id);
                                msk->pm.subflows++;
                                i++;
                        }
@@ -799,18 +802,18 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,
 
                mptcp_for_each_subflow_safe(msk, subflow, tmp) {
                        struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
+                       u8 remote_id = READ_ONCE(subflow->remote_id);
                        int how = RCV_SHUTDOWN | SEND_SHUTDOWN;
-                       u8 id = subflow->local_id;
+                       u8 id = subflow_get_local_id(subflow);
 
-                       if (rm_type == MPTCP_MIB_RMADDR && subflow->remote_id != rm_id)
+                       if (rm_type == MPTCP_MIB_RMADDR && remote_id != rm_id)
                                continue;
                        if (rm_type == MPTCP_MIB_RMSUBFLOW && !mptcp_local_id_match(msk, id, rm_id))
                                continue;
 
                        pr_debug(" -> %s rm_list_ids[%d]=%u local_id=%u remote_id=%u mpc_id=%u",
                                 rm_type == MPTCP_MIB_RMADDR ? "address" : "subflow",
-                                i, rm_id, subflow->local_id, subflow->remote_id,
-                                msk->mpc_endpoint_id);
+                                i, rm_id, id, remote_id, msk->mpc_endpoint_id);
                        spin_unlock_bh(&msk->pm.lock);
                        mptcp_subflow_shutdown(sk, ssk, how);
 
@@ -901,7 +904,8 @@ static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry *entry)
 }
 
 static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
-                                            struct mptcp_pm_addr_entry *entry)
+                                            struct mptcp_pm_addr_entry *entry,
+                                            bool needs_id)
 {
        struct mptcp_pm_addr_entry *cur, *del_entry = NULL;
        unsigned int addr_max;
@@ -949,7 +953,7 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
                }
        }
 
-       if (!entry->addr.id) {
+       if (!entry->addr.id && needs_id) {
 find_next:
                entry->addr.id = find_next_zero_bit(pernet->id_bitmap,
                                                    MPTCP_PM_MAX_ADDR_ID + 1,
@@ -960,7 +964,7 @@ find_next:
                }
        }
 
-       if (!entry->addr.id)
+       if (!entry->addr.id && needs_id)
                goto out;
 
        __set_bit(entry->addr.id, pernet->id_bitmap);
@@ -1092,7 +1096,7 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc
        entry->ifindex = 0;
        entry->flags = MPTCP_PM_ADDR_FLAG_IMPLICIT;
        entry->lsk = NULL;
-       ret = mptcp_pm_nl_append_new_local_addr(pernet, entry);
+       ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, true);
        if (ret < 0)
                kfree(entry);
 
@@ -1285,6 +1289,18 @@ next:
        return 0;
 }
 
+static bool mptcp_pm_has_addr_attr_id(const struct nlattr *attr,
+                                     struct genl_info *info)
+{
+       struct nlattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1];
+
+       if (!nla_parse_nested_deprecated(tb, MPTCP_PM_ADDR_ATTR_MAX, attr,
+                                        mptcp_pm_address_nl_policy, info->extack) &&
+           tb[MPTCP_PM_ADDR_ATTR_ID])
+               return true;
+       return false;
+}
+
 int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr *attr = info->attrs[MPTCP_PM_ENDPOINT_ADDR];
@@ -1326,7 +1342,8 @@ int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info)
                        goto out_free;
                }
        }
-       ret = mptcp_pm_nl_append_new_local_addr(pernet, entry);
+       ret = mptcp_pm_nl_append_new_local_addr(pernet, entry,
+                                               !mptcp_pm_has_addr_attr_id(attr, info));
        if (ret < 0) {
                GENL_SET_ERR_MSG_FMT(info, "too many addresses or duplicate one: %d", ret);
                goto out_free;
@@ -1980,7 +1997,7 @@ static int mptcp_event_add_subflow(struct sk_buff *skb, const struct sock *ssk)
        if (WARN_ON_ONCE(!sf))
                return -EINVAL;
 
-       if (nla_put_u8(skb, MPTCP_ATTR_LOC_ID, sf->local_id))
+       if (nla_put_u8(skb, MPTCP_ATTR_LOC_ID, subflow_get_local_id(sf)))
                return -EMSGSIZE;
 
        if (nla_put_u8(skb, MPTCP_ATTR_REM_ID, sf->remote_id))
index efecbe3cf41533324a5df71da39f775dd2078ca6..bc97cc30f013abdba076aa93596dd213e9353eb8 100644 (file)
@@ -26,7 +26,8 @@ void mptcp_free_local_addr_list(struct mptcp_sock *msk)
 }
 
 static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
-                                                   struct mptcp_pm_addr_entry *entry)
+                                                   struct mptcp_pm_addr_entry *entry,
+                                                   bool needs_id)
 {
        DECLARE_BITMAP(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
        struct mptcp_pm_addr_entry *match = NULL;
@@ -41,7 +42,7 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
        spin_lock_bh(&msk->pm.lock);
        list_for_each_entry(e, &msk->pm.userspace_pm_local_addr_list, list) {
                addr_match = mptcp_addresses_equal(&e->addr, &entry->addr, true);
-               if (addr_match && entry->addr.id == 0)
+               if (addr_match && entry->addr.id == 0 && needs_id)
                        entry->addr.id = e->addr.id;
                id_match = (e->addr.id == entry->addr.id);
                if (addr_match && id_match) {
@@ -64,7 +65,7 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
                }
 
                *e = *entry;
-               if (!e->addr.id)
+               if (!e->addr.id && needs_id)
                        e->addr.id = find_next_zero_bit(id_bitmap,
                                                        MPTCP_PM_MAX_ADDR_ID + 1,
                                                        1);
@@ -130,10 +131,21 @@ int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk,
 int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk,
                                    struct mptcp_addr_info *skc)
 {
-       struct mptcp_pm_addr_entry new_entry;
+       struct mptcp_pm_addr_entry *entry = NULL, *e, new_entry;
        __be16 msk_sport =  ((struct inet_sock *)
                             inet_sk((struct sock *)msk))->inet_sport;
 
+       spin_lock_bh(&msk->pm.lock);
+       list_for_each_entry(e, &msk->pm.userspace_pm_local_addr_list, list) {
+               if (mptcp_addresses_equal(&e->addr, skc, false)) {
+                       entry = e;
+                       break;
+               }
+       }
+       spin_unlock_bh(&msk->pm.lock);
+       if (entry)
+               return entry->addr.id;
+
        memset(&new_entry, 0, sizeof(struct mptcp_pm_addr_entry));
        new_entry.addr = *skc;
        new_entry.addr.id = 0;
@@ -142,7 +154,7 @@ int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk,
        if (new_entry.addr.port == msk_sport)
                new_entry.addr.port = 0;
 
-       return mptcp_userspace_pm_append_new_local_addr(msk, &new_entry);
+       return mptcp_userspace_pm_append_new_local_addr(msk, &new_entry, true);
 }
 
 int mptcp_pm_nl_announce_doit(struct sk_buff *skb, struct genl_info *info)
@@ -187,7 +199,7 @@ int mptcp_pm_nl_announce_doit(struct sk_buff *skb, struct genl_info *info)
                goto announce_err;
        }
 
-       err = mptcp_userspace_pm_append_new_local_addr(msk, &addr_val);
+       err = mptcp_userspace_pm_append_new_local_addr(msk, &addr_val, false);
        if (err < 0) {
                GENL_SET_ERR_MSG(info, "did not match address and id");
                goto announce_err;
@@ -222,7 +234,7 @@ static int mptcp_userspace_pm_remove_id_zero_address(struct mptcp_sock *msk,
 
        lock_sock(sk);
        mptcp_for_each_subflow(msk, subflow) {
-               if (subflow->local_id == 0) {
+               if (READ_ONCE(subflow->local_id) == 0) {
                        has_id_0 = true;
                        break;
                }
@@ -367,7 +379,7 @@ int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info)
        }
 
        local.addr = addr_l;
-       err = mptcp_userspace_pm_append_new_local_addr(msk, &local);
+       err = mptcp_userspace_pm_append_new_local_addr(msk, &local, false);
        if (err < 0) {
                GENL_SET_ERR_MSG(info, "did not match address and id");
                goto create_err;
@@ -483,6 +495,16 @@ int mptcp_pm_nl_subflow_destroy_doit(struct sk_buff *skb, struct genl_info *info
                goto destroy_err;
        }
 
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+       if (addr_l.family == AF_INET && ipv6_addr_v4mapped(&addr_r.addr6)) {
+               ipv6_addr_set_v4mapped(addr_l.addr.s_addr, &addr_l.addr6);
+               addr_l.family = AF_INET6;
+       }
+       if (addr_r.family == AF_INET && ipv6_addr_v4mapped(&addr_l.addr6)) {
+               ipv6_addr_set_v4mapped(addr_r.addr.s_addr, &addr_r.addr6);
+               addr_r.family = AF_INET6;
+       }
+#endif
        if (addr_l.family != addr_r.family) {
                GENL_SET_ERR_MSG(info, "address families do not match");
                err = -EINVAL;
index 028e8b473626f122db6e3e664414b2f0447fae69..7833a49f6214a194a282bba92671e9cdd945ad92 100644 (file)
@@ -85,7 +85,7 @@ static int __mptcp_socket_create(struct mptcp_sock *msk)
        subflow->subflow_id = msk->subflow_id++;
 
        /* This is the first subflow, always with id 0 */
-       subflow->local_id_valid = 1;
+       WRITE_ONCE(subflow->local_id, 0);
        mptcp_sock_graft(msk->first, sk->sk_socket);
        iput(SOCK_INODE(ssock));
 
@@ -1260,6 +1260,7 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
                mpext = mptcp_get_ext(skb);
                if (!mptcp_skb_can_collapse_to(data_seq, skb, mpext)) {
                        TCP_SKB_CB(skb)->eor = 1;
+                       tcp_mark_push(tcp_sk(ssk), skb);
                        goto alloc_skb;
                }
 
@@ -1505,8 +1506,11 @@ static void mptcp_update_post_push(struct mptcp_sock *msk,
 
 void mptcp_check_and_set_pending(struct sock *sk)
 {
-       if (mptcp_send_head(sk))
-               mptcp_sk(sk)->push_pending |= BIT(MPTCP_PUSH_PENDING);
+       if (mptcp_send_head(sk)) {
+               mptcp_data_lock(sk);
+               mptcp_sk(sk)->cb_flags |= BIT(MPTCP_PUSH_PENDING);
+               mptcp_data_unlock(sk);
+       }
 }
 
 static int __subflow_push_pending(struct sock *sk, struct sock *ssk,
@@ -1960,6 +1964,9 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)
        if (copied <= 0)
                return;
 
+       if (!msk->rcvspace_init)
+               mptcp_rcv_space_init(msk, msk->first);
+
        msk->rcvq_space.copied += copied;
 
        mstamp = div_u64(tcp_clock_ns(), NSEC_PER_USEC);
@@ -3142,7 +3149,6 @@ static int mptcp_disconnect(struct sock *sk, int flags)
        mptcp_destroy_common(msk, MPTCP_CF_FASTCLOSE);
        WRITE_ONCE(msk->flags, 0);
        msk->cb_flags = 0;
-       msk->push_pending = 0;
        msk->recovery = false;
        msk->can_ack = false;
        msk->fully_established = false;
@@ -3158,6 +3164,7 @@ static int mptcp_disconnect(struct sock *sk, int flags)
        msk->bytes_received = 0;
        msk->bytes_sent = 0;
        msk->bytes_retrans = 0;
+       msk->rcvspace_init = 0;
 
        WRITE_ONCE(sk->sk_shutdown, 0);
        sk_error_report(sk);
@@ -3171,8 +3178,50 @@ static struct ipv6_pinfo *mptcp_inet6_sk(const struct sock *sk)
 
        return (struct ipv6_pinfo *)(((u8 *)sk) + offset);
 }
+
+static void mptcp_copy_ip6_options(struct sock *newsk, const struct sock *sk)
+{
+       const struct ipv6_pinfo *np = inet6_sk(sk);
+       struct ipv6_txoptions *opt;
+       struct ipv6_pinfo *newnp;
+
+       newnp = inet6_sk(newsk);
+
+       rcu_read_lock();
+       opt = rcu_dereference(np->opt);
+       if (opt) {
+               opt = ipv6_dup_options(newsk, opt);
+               if (!opt)
+                       net_warn_ratelimited("%s: Failed to copy ip6 options\n", __func__);
+       }
+       RCU_INIT_POINTER(newnp->opt, opt);
+       rcu_read_unlock();
+}
 #endif
 
+static void mptcp_copy_ip_options(struct sock *newsk, const struct sock *sk)
+{
+       struct ip_options_rcu *inet_opt, *newopt = NULL;
+       const struct inet_sock *inet = inet_sk(sk);
+       struct inet_sock *newinet;
+
+       newinet = inet_sk(newsk);
+
+       rcu_read_lock();
+       inet_opt = rcu_dereference(inet->inet_opt);
+       if (inet_opt) {
+               newopt = sock_kmalloc(newsk, sizeof(*inet_opt) +
+                                     inet_opt->opt.optlen, GFP_ATOMIC);
+               if (newopt)
+                       memcpy(newopt, inet_opt, sizeof(*inet_opt) +
+                              inet_opt->opt.optlen);
+               else
+                       net_warn_ratelimited("%s: Failed to copy ip options\n", __func__);
+       }
+       RCU_INIT_POINTER(newinet->inet_opt, newopt);
+       rcu_read_unlock();
+}
+
 struct sock *mptcp_sk_clone_init(const struct sock *sk,
                                 const struct mptcp_options_received *mp_opt,
                                 struct sock *ssk,
@@ -3180,6 +3229,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
 {
        struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
        struct sock *nsk = sk_clone_lock(sk, GFP_ATOMIC);
+       struct mptcp_subflow_context *subflow;
        struct mptcp_sock *msk;
 
        if (!nsk)
@@ -3192,6 +3242,13 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
 
        __mptcp_init_sock(nsk);
 
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+       if (nsk->sk_family == AF_INET6)
+               mptcp_copy_ip6_options(nsk, sk);
+       else
+#endif
+               mptcp_copy_ip_options(nsk, sk);
+
        msk = mptcp_sk(nsk);
        msk->local_key = subflow_req->local_key;
        msk->token = subflow_req->token;
@@ -3203,7 +3260,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
        msk->write_seq = subflow_req->idsn + 1;
        msk->snd_nxt = msk->write_seq;
        msk->snd_una = msk->write_seq;
-       msk->wnd_end = msk->snd_nxt + req->rsk_rcv_wnd;
+       msk->wnd_end = msk->snd_nxt + tcp_sk(ssk)->snd_wnd;
        msk->setsockopt_seq = mptcp_sk(sk)->setsockopt_seq;
        mptcp_init_sched(msk, mptcp_sk(sk)->sched);
 
@@ -3220,7 +3277,8 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
 
        /* The msk maintain a ref to each subflow in the connections list */
        WRITE_ONCE(msk->first, ssk);
-       list_add(&mptcp_subflow_ctx(ssk)->node, &msk->conn_list);
+       subflow = mptcp_subflow_ctx(ssk);
+       list_add(&subflow->node, &msk->conn_list);
        sock_hold(ssk);
 
        /* new mpc subflow takes ownership of the newly
@@ -3235,6 +3293,9 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
        __mptcp_propagate_sndbuf(nsk, ssk);
 
        mptcp_rcv_space_init(msk, ssk);
+
+       if (mp_opt->suboptions & OPTION_MPTCP_MPC_ACK)
+               __mptcp_subflow_fully_established(msk, subflow, mp_opt);
        bh_unlock_sock(nsk);
 
        /* note: the newly allocated socket refcount is 2 now */
@@ -3245,6 +3306,7 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk)
 {
        const struct tcp_sock *tp = tcp_sk(ssk);
 
+       msk->rcvspace_init = 1;
        msk->rcvq_space.copied = 0;
        msk->rcvq_space.rtt_us = 0;
 
@@ -3255,8 +3317,6 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk)
                                      TCP_INIT_CWND * tp->advmss);
        if (msk->rcvq_space.space == 0)
                msk->rcvq_space.space = TCP_INIT_CWND * TCP_MSS_DEFAULT;
-
-       WRITE_ONCE(msk->wnd_end, msk->snd_nxt + tcp_sk(ssk)->snd_wnd);
 }
 
 void mptcp_destroy_common(struct mptcp_sock *msk, unsigned int flags)
@@ -3330,8 +3390,7 @@ static void mptcp_release_cb(struct sock *sk)
        struct mptcp_sock *msk = mptcp_sk(sk);
 
        for (;;) {
-               unsigned long flags = (msk->cb_flags & MPTCP_FLAGS_PROCESS_CTX_NEED) |
-                                     msk->push_pending;
+               unsigned long flags = (msk->cb_flags & MPTCP_FLAGS_PROCESS_CTX_NEED);
                struct list_head join_list;
 
                if (!flags)
@@ -3347,7 +3406,6 @@ static void mptcp_release_cb(struct sock *sk)
                 *    datapath acquires the msk socket spinlock while helding
                 *    the subflow socket lock
                 */
-               msk->push_pending = 0;
                msk->cb_flags &= ~flags;
                spin_unlock_bh(&sk->sk_lock.slock);
 
@@ -3475,13 +3533,8 @@ void mptcp_finish_connect(struct sock *ssk)
         * accessing the field below
         */
        WRITE_ONCE(msk->local_key, subflow->local_key);
-       WRITE_ONCE(msk->write_seq, subflow->idsn + 1);
-       WRITE_ONCE(msk->snd_nxt, msk->write_seq);
-       WRITE_ONCE(msk->snd_una, msk->write_seq);
 
        mptcp_pm_new_connection(msk, ssk, 0);
-
-       mptcp_rcv_space_init(msk, ssk);
 }
 
 void mptcp_sock_graft(struct sock *sk, struct socket *parent)
index 3517f2d24a226ff0be1adec800044810f1aa31c6..07f6242afc1ae09d3c17aadfe7bb104eb3cf177c 100644 (file)
@@ -286,7 +286,6 @@ struct mptcp_sock {
        int             rmem_released;
        unsigned long   flags;
        unsigned long   cb_flags;
-       unsigned long   push_pending;
        bool            recovery;               /* closing subflow write queue reinjected */
        bool            can_ack;
        bool            fully_established;
@@ -305,7 +304,8 @@ struct mptcp_sock {
                        nodelay:1,
                        fastopening:1,
                        in_accept_queue:1,
-                       free_first:1;
+                       free_first:1,
+                       rcvspace_init:1;
        struct work_struct work;
        struct sk_buff  *ooo_last_skb;
        struct rb_root  out_of_order_queue;
@@ -491,10 +491,9 @@ struct mptcp_subflow_context {
                remote_key_valid : 1,        /* received the peer key from */
                disposable : 1,     /* ctx can be free at ulp release time */
                stale : 1,          /* unable to snd/rcv data, do not use for xmit */
-               local_id_valid : 1, /* local_id is correctly initialized */
                valid_csum_seen : 1,        /* at least one csum validated */
                is_mptfo : 1,       /* subflow is doing TFO */
-               __unused : 9;
+               __unused : 10;
        bool    data_avail;
        bool    scheduled;
        u32     remote_nonce;
@@ -505,7 +504,7 @@ struct mptcp_subflow_context {
                u8      hmac[MPTCPOPT_HMAC_LEN]; /* MPJ subflow only */
                u64     iasn;       /* initial ack sequence number, MPC subflows only */
        };
-       u8      local_id;
+       s16     local_id;           /* if negative not initialized yet */
        u8      remote_id;
        u8      reset_seen:1;
        u8      reset_transient:1;
@@ -556,6 +555,7 @@ mptcp_subflow_ctx_reset(struct mptcp_subflow_context *subflow)
 {
        memset(&subflow->reset, 0, sizeof(subflow->reset));
        subflow->request_mptcp = 1;
+       WRITE_ONCE(subflow->local_id, -1);
 }
 
 static inline u64
@@ -622,8 +622,9 @@ unsigned int mptcp_stale_loss_cnt(const struct net *net);
 unsigned int mptcp_close_timeout(const struct sock *sk);
 int mptcp_get_pm_type(const struct net *net);
 const char *mptcp_get_scheduler(const struct net *net);
-void mptcp_subflow_fully_established(struct mptcp_subflow_context *subflow,
-                                    const struct mptcp_options_received *mp_opt);
+void __mptcp_subflow_fully_established(struct mptcp_sock *msk,
+                                      struct mptcp_subflow_context *subflow,
+                                      const struct mptcp_options_received *mp_opt);
 bool __mptcp_retransmit_pending_data(struct sock *sk);
 void mptcp_check_and_set_pending(struct sock *sk);
 void __mptcp_push_pending(struct sock *sk, unsigned int flags);
@@ -789,6 +790,16 @@ static inline bool mptcp_data_fin_enabled(const struct mptcp_sock *msk)
               READ_ONCE(msk->write_seq) == READ_ONCE(msk->snd_nxt);
 }
 
+static inline void mptcp_write_space(struct sock *sk)
+{
+       if (sk_stream_is_writeable(sk)) {
+               /* pairs with memory barrier in mptcp_poll */
+               smp_mb();
+               if (test_and_clear_bit(MPTCP_NOSPACE, &mptcp_sk(sk)->flags))
+                       sk_stream_write_space(sk);
+       }
+}
+
 static inline void __mptcp_sync_sndbuf(struct sock *sk)
 {
        struct mptcp_subflow_context *subflow;
@@ -807,6 +818,7 @@ static inline void __mptcp_sync_sndbuf(struct sock *sk)
 
        /* the msk max wmem limit is <nr_subflows> * tcp wmem[2] */
        WRITE_ONCE(sk->sk_sndbuf, new_sndbuf);
+       mptcp_write_space(sk);
 }
 
 /* The called held both the msk socket and the subflow socket locks,
@@ -837,16 +849,6 @@ static inline void mptcp_propagate_sndbuf(struct sock *sk, struct sock *ssk)
        local_bh_enable();
 }
 
-static inline void mptcp_write_space(struct sock *sk)
-{
-       if (sk_stream_is_writeable(sk)) {
-               /* pairs with memory barrier in mptcp_poll */
-               smp_mb();
-               if (test_and_clear_bit(MPTCP_NOSPACE, &mptcp_sk(sk)->flags))
-                       sk_stream_write_space(sk);
-       }
-}
-
 void mptcp_destroy_common(struct mptcp_sock *msk, unsigned int flags);
 
 #define MPTCP_TOKEN_MAX_RETRIES        4
@@ -952,8 +954,8 @@ void mptcp_event_pm_listener(const struct sock *ssk,
                             enum mptcp_event_type event);
 bool mptcp_userspace_pm_active(const struct mptcp_sock *msk);
 
-void mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow,
-                                  const struct mptcp_options_received *mp_opt);
+void __mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow,
+                                    const struct mptcp_options_received *mp_opt);
 void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subflow,
                                              struct request_sock *req);
 
@@ -1021,6 +1023,15 @@ int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc);
 int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc);
 int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc);
 
+static inline u8 subflow_get_local_id(const struct mptcp_subflow_context *subflow)
+{
+       int local_id = READ_ONCE(subflow->local_id);
+
+       if (local_id < 0)
+               return 0;
+       return local_id;
+}
+
 void __init mptcp_pm_nl_init(void);
 void mptcp_pm_nl_work(struct mptcp_sock *msk);
 void mptcp_pm_nl_rm_subflow_received(struct mptcp_sock *msk,
@@ -1128,7 +1139,8 @@ static inline bool subflow_simultaneous_connect(struct sock *sk)
 {
        struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
 
-       return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_FIN_WAIT1) &&
+       return (1 << sk->sk_state) &
+              (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2 | TCPF_CLOSING) &&
               is_active_ssk(subflow) &&
               !subflow->conn_finished;
 }
index 0dcb721c89d193e8943aa414610fcf4284d51f38..71ba86246ff893c5bf65f77802510b52c3d68fd4 100644 (file)
@@ -421,29 +421,26 @@ static bool subflow_use_different_dport(struct mptcp_sock *msk, const struct soc
 
 void __mptcp_sync_state(struct sock *sk, int state)
 {
+       struct mptcp_subflow_context *subflow;
        struct mptcp_sock *msk = mptcp_sk(sk);
+       struct sock *ssk = msk->first;
+
+       subflow = mptcp_subflow_ctx(ssk);
+       __mptcp_propagate_sndbuf(sk, ssk);
+       if (!msk->rcvspace_init)
+               mptcp_rcv_space_init(msk, ssk);
 
-       __mptcp_propagate_sndbuf(sk, msk->first);
        if (sk->sk_state == TCP_SYN_SENT) {
+               /* subflow->idsn is always available is TCP_SYN_SENT state,
+                * even for the FASTOPEN scenarios
+                */
+               WRITE_ONCE(msk->write_seq, subflow->idsn + 1);
+               WRITE_ONCE(msk->snd_nxt, msk->write_seq);
                mptcp_set_state(sk, state);
                sk->sk_state_change(sk);
        }
 }
 
-static void mptcp_propagate_state(struct sock *sk, struct sock *ssk)
-{
-       struct mptcp_sock *msk = mptcp_sk(sk);
-
-       mptcp_data_lock(sk);
-       if (!sock_owned_by_user(sk)) {
-               __mptcp_sync_state(sk, ssk->sk_state);
-       } else {
-               msk->pending_state = ssk->sk_state;
-               __set_bit(MPTCP_SYNC_STATE, &msk->cb_flags);
-       }
-       mptcp_data_unlock(sk);
-}
-
 static void subflow_set_remote_key(struct mptcp_sock *msk,
                                   struct mptcp_subflow_context *subflow,
                                   const struct mptcp_options_received *mp_opt)
@@ -465,6 +462,31 @@ static void subflow_set_remote_key(struct mptcp_sock *msk,
        atomic64_set(&msk->rcv_wnd_sent, subflow->iasn);
 }
 
+static void mptcp_propagate_state(struct sock *sk, struct sock *ssk,
+                                 struct mptcp_subflow_context *subflow,
+                                 const struct mptcp_options_received *mp_opt)
+{
+       struct mptcp_sock *msk = mptcp_sk(sk);
+
+       mptcp_data_lock(sk);
+       if (mp_opt) {
+               /* Options are available only in the non fallback cases
+                * avoid updating rx path fields otherwise
+                */
+               WRITE_ONCE(msk->snd_una, subflow->idsn + 1);
+               WRITE_ONCE(msk->wnd_end, subflow->idsn + 1 + tcp_sk(ssk)->snd_wnd);
+               subflow_set_remote_key(msk, subflow, mp_opt);
+       }
+
+       if (!sock_owned_by_user(sk)) {
+               __mptcp_sync_state(sk, ssk->sk_state);
+       } else {
+               msk->pending_state = ssk->sk_state;
+               __set_bit(MPTCP_SYNC_STATE, &msk->cb_flags);
+       }
+       mptcp_data_unlock(sk);
+}
+
 static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
 {
        struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
@@ -499,10 +521,9 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
                if (mp_opt.deny_join_id0)
                        WRITE_ONCE(msk->pm.remote_deny_join_id0, true);
                subflow->mp_capable = 1;
-               subflow_set_remote_key(msk, subflow, &mp_opt);
                MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEACK);
                mptcp_finish_connect(sk);
-               mptcp_propagate_state(parent, sk);
+               mptcp_propagate_state(parent, sk, subflow, &mp_opt);
        } else if (subflow->request_join) {
                u8 hmac[SHA256_DIGEST_SIZE];
 
@@ -514,7 +535,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
                subflow->backup = mp_opt.backup;
                subflow->thmac = mp_opt.thmac;
                subflow->remote_nonce = mp_opt.nonce;
-               subflow->remote_id = mp_opt.join_id;
+               WRITE_ONCE(subflow->remote_id, mp_opt.join_id);
                pr_debug("subflow=%p, thmac=%llu, remote_nonce=%u backup=%d",
                         subflow, subflow->thmac, subflow->remote_nonce,
                         subflow->backup);
@@ -545,8 +566,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
                }
        } else if (mptcp_check_fallback(sk)) {
 fallback:
-               mptcp_rcv_space_init(msk, sk);
-               mptcp_propagate_state(parent, sk);
+               mptcp_propagate_state(parent, sk, subflow, NULL);
        }
        return;
 
@@ -557,8 +577,8 @@ do_reset:
 
 static void subflow_set_local_id(struct mptcp_subflow_context *subflow, int local_id)
 {
-       subflow->local_id = local_id;
-       subflow->local_id_valid = 1;
+       WARN_ON_ONCE(local_id < 0 || local_id > 255);
+       WRITE_ONCE(subflow->local_id, local_id);
 }
 
 static int subflow_chk_local_id(struct sock *sk)
@@ -567,7 +587,7 @@ static int subflow_chk_local_id(struct sock *sk)
        struct mptcp_sock *msk = mptcp_sk(subflow->conn);
        int err;
 
-       if (likely(subflow->local_id_valid))
+       if (likely(subflow->local_id >= 0))
                return 0;
 
        err = mptcp_pm_get_local_id(msk, (struct sock_common *)sk);
@@ -731,17 +751,16 @@ void mptcp_subflow_drop_ctx(struct sock *ssk)
        kfree_rcu(ctx, rcu);
 }
 
-void mptcp_subflow_fully_established(struct mptcp_subflow_context *subflow,
-                                    const struct mptcp_options_received *mp_opt)
+void __mptcp_subflow_fully_established(struct mptcp_sock *msk,
+                                      struct mptcp_subflow_context *subflow,
+                                      const struct mptcp_options_received *mp_opt)
 {
-       struct mptcp_sock *msk = mptcp_sk(subflow->conn);
-
        subflow_set_remote_key(msk, subflow, mp_opt);
        subflow->fully_established = 1;
        WRITE_ONCE(msk->fully_established, true);
 
        if (subflow->is_mptfo)
-               mptcp_fastopen_gen_msk_ackseq(msk, subflow, mp_opt);
+               __mptcp_fastopen_gen_msk_ackseq(msk, subflow, mp_opt);
 }
 
 static struct sock *subflow_syn_recv_sock(const struct sock *sk,
@@ -834,7 +853,6 @@ create_child:
                         * mpc option
                         */
                        if (mp_opt.suboptions & OPTION_MPTCP_MPC_ACK) {
-                               mptcp_subflow_fully_established(ctx, &mp_opt);
                                mptcp_pm_fully_established(owner, child);
                                ctx->pm_notified = 1;
                        }
@@ -1549,7 +1567,7 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
        pr_debug("msk=%p remote_token=%u local_id=%d remote_id=%d", msk,
                 remote_token, local_id, remote_id);
        subflow->remote_token = remote_token;
-       subflow->remote_id = remote_id;
+       WRITE_ONCE(subflow->remote_id, remote_id);
        subflow->request_join = 1;
        subflow->request_bkup = !!(flags & MPTCP_PM_ADDR_FLAG_BACKUP);
        subflow->subflow_id = msk->subflow_id++;
@@ -1713,6 +1731,7 @@ static struct mptcp_subflow_context *subflow_create_ctx(struct sock *sk,
        pr_debug("subflow=%p", ctx);
 
        ctx->tcp_sock = sk;
+       WRITE_ONCE(ctx->local_id, -1);
 
        return ctx;
 }
@@ -1744,10 +1763,9 @@ static void subflow_state_change(struct sock *sk)
        msk = mptcp_sk(parent);
        if (subflow_simultaneous_connect(sk)) {
                mptcp_do_fallback(sk);
-               mptcp_rcv_space_init(msk, sk);
                pr_fallback(msk);
                subflow->conn_finished = 1;
-               mptcp_propagate_state(parent, sk);
+               mptcp_propagate_state(parent, sk, subflow, NULL);
        }
 
        /* as recvmsg() does not acquire the subflow socket for ssk selection
@@ -1949,14 +1967,14 @@ static void subflow_ulp_clone(const struct request_sock *req,
                new_ctx->idsn = subflow_req->idsn;
 
                /* this is the first subflow, id is always 0 */
-               new_ctx->local_id_valid = 1;
+               subflow_set_local_id(new_ctx, 0);
        } else if (subflow_req->mp_join) {
                new_ctx->ssn_offset = subflow_req->ssn_offset;
                new_ctx->mp_join = 1;
                new_ctx->fully_established = 1;
                new_ctx->remote_key_valid = 1;
                new_ctx->backup = subflow_req->backup;
-               new_ctx->remote_id = subflow_req->remote_id;
+               WRITE_ONCE(new_ctx->remote_id, subflow_req->remote_id);
                new_ctx->token = subflow_req->token;
                new_ctx->thmac = subflow_req->thmac;
 
index d4958e7e763101e0c27a32d21e456d092bcc9b61..614815a3ed73878212d3860e1d89d582f28c5d2b 100644 (file)
@@ -101,7 +101,7 @@ endif
 endif
 
 ifdef CONFIG_NFT_CT
-ifdef CONFIG_RETPOLINE
+ifdef CONFIG_MITIGATION_RETPOLINE
 nf_tables-objs += nft_ct_fast.o
 endif
 endif
index 2e5f3864d353a39cfde138b725e790d7290b82c9..5b876fa7f9af9e5dfe950929b29f0fc92daf9bab 100644 (file)
@@ -2756,6 +2756,7 @@ static const struct nf_ct_hook nf_conntrack_hook = {
        .get_tuple_skb  = nf_conntrack_get_tuple_skb,
        .attach         = nf_conntrack_attach,
        .set_closing    = nf_conntrack_set_closing,
+       .confirm        = __nf_conntrack_confirm,
 };
 
 void nf_conntrack_init_end(void)
index e697a824b0018e1f1e26e3d547c1e80c6ca49e39..540d97715bd23d6f53f29fc7df39f09cd6b2f5c0 100644 (file)
@@ -533,6 +533,8 @@ static int decode_seq(struct bitstr *bs, const struct field_t *f,
        /* Get fields bitmap */
        if (nf_h323_error_boundary(bs, 0, f->sz))
                return H323_ERROR_BOUND;
+       if (f->sz > 32)
+               return H323_ERROR_RANGE;
        bmp = get_bitmap(bs, f->sz);
        if (base)
                *(unsigned int *)base = bmp;
@@ -589,6 +591,8 @@ static int decode_seq(struct bitstr *bs, const struct field_t *f,
        bmp2_len = get_bits(bs, 7) + 1;
        if (nf_h323_error_boundary(bs, 0, bmp2_len))
                return H323_ERROR_BOUND;
+       if (bmp2_len > 32)
+               return H323_ERROR_RANGE;
        bmp2 = get_bitmap(bs, bmp2_len);
        bmp |= bmp2 >> f->sz;
        if (base)
index 920a5a29ae1dceba6849aaad6d62701567d3ec99..a0571339239c40ded96c4a9466d53d5de2887ed5 100644 (file)
@@ -87,12 +87,22 @@ static u32 flow_offload_dst_cookie(struct flow_offload_tuple *flow_tuple)
        return 0;
 }
 
+static struct dst_entry *nft_route_dst_fetch(struct nf_flow_route *route,
+                                            enum flow_offload_tuple_dir dir)
+{
+       struct dst_entry *dst = route->tuple[dir].dst;
+
+       route->tuple[dir].dst = NULL;
+
+       return dst;
+}
+
 static int flow_offload_fill_route(struct flow_offload *flow,
-                                  const struct nf_flow_route *route,
+                                  struct nf_flow_route *route,
                                   enum flow_offload_tuple_dir dir)
 {
        struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
-       struct dst_entry *dst = route->tuple[dir].dst;
+       struct dst_entry *dst = nft_route_dst_fetch(route, dir);
        int i, j = 0;
 
        switch (flow_tuple->l3proto) {
@@ -122,6 +132,7 @@ static int flow_offload_fill_route(struct flow_offload *flow,
                       ETH_ALEN);
                flow_tuple->out.ifidx = route->tuple[dir].out.ifindex;
                flow_tuple->out.hw_ifidx = route->tuple[dir].out.hw_ifindex;
+               dst_release(dst);
                break;
        case FLOW_OFFLOAD_XMIT_XFRM:
        case FLOW_OFFLOAD_XMIT_NEIGH:
@@ -146,7 +157,7 @@ static void nft_flow_dst_release(struct flow_offload *flow,
 }
 
 void flow_offload_route_init(struct flow_offload *flow,
-                           const struct nf_flow_route *route)
+                            struct nf_flow_route *route)
 {
        flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_ORIGINAL);
        flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_REPLY);
index c3d7ecbc777ce08525bedee77d637c18682d816c..016c816d91cbc49bfbd5417c295e26667b7be179 100644 (file)
@@ -551,8 +551,11 @@ static void nf_nat_l4proto_unique_tuple(struct nf_conntrack_tuple *tuple,
 find_free_id:
        if (range->flags & NF_NAT_RANGE_PROTO_OFFSET)
                off = (ntohs(*keyptr) - ntohs(range->base_proto.all));
-       else
+       else if ((range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL) ||
+                maniptype != NF_NAT_MANIP_DST)
                off = get_random_u16();
+       else
+               off = 0;
 
        attempts = range_size;
        if (attempts > NF_NAT_MAX_ATTEMPTS)
index f8e3f70c35bd558aec8a2b2149a7ff7db0eb3d1f..1683dc196b5921da91c8dd81b99ac9106c7493fe 100644 (file)
@@ -684,15 +684,16 @@ static int nft_delobj(struct nft_ctx *ctx, struct nft_object *obj)
        return err;
 }
 
-static int nft_trans_flowtable_add(struct nft_ctx *ctx, int msg_type,
-                                  struct nft_flowtable *flowtable)
+static struct nft_trans *
+nft_trans_flowtable_add(struct nft_ctx *ctx, int msg_type,
+                       struct nft_flowtable *flowtable)
 {
        struct nft_trans *trans;
 
        trans = nft_trans_alloc(ctx, msg_type,
                                sizeof(struct nft_trans_flowtable));
        if (trans == NULL)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        if (msg_type == NFT_MSG_NEWFLOWTABLE)
                nft_activate_next(ctx->net, flowtable);
@@ -701,22 +702,22 @@ static int nft_trans_flowtable_add(struct nft_ctx *ctx, int msg_type,
        nft_trans_flowtable(trans) = flowtable;
        nft_trans_commit_list_add_tail(ctx->net, trans);
 
-       return 0;
+       return trans;
 }
 
 static int nft_delflowtable(struct nft_ctx *ctx,
                            struct nft_flowtable *flowtable)
 {
-       int err;
+       struct nft_trans *trans;
 
-       err = nft_trans_flowtable_add(ctx, NFT_MSG_DELFLOWTABLE, flowtable);
-       if (err < 0)
-               return err;
+       trans = nft_trans_flowtable_add(ctx, NFT_MSG_DELFLOWTABLE, flowtable);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
 
        nft_deactivate_next(ctx->net, flowtable);
        nft_use_dec(&ctx->table->use);
 
-       return err;
+       return 0;
 }
 
 static void __nft_reg_track_clobber(struct nft_regs_track *track, u8 dreg)
@@ -1251,6 +1252,7 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
        return 0;
 
 err_register_hooks:
+       ctx->table->flags |= NFT_TABLE_F_DORMANT;
        nft_trans_destroy(trans);
        return ret;
 }
@@ -2080,7 +2082,7 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
        struct nft_hook *hook;
        int err;
 
-       hook = kmalloc(sizeof(struct nft_hook), GFP_KERNEL_ACCOUNT);
+       hook = kzalloc(sizeof(struct nft_hook), GFP_KERNEL_ACCOUNT);
        if (!hook) {
                err = -ENOMEM;
                goto err_hook_alloc;
@@ -2503,19 +2505,15 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
        RCU_INIT_POINTER(chain->blob_gen_0, blob);
        RCU_INIT_POINTER(chain->blob_gen_1, blob);
 
-       err = nf_tables_register_hook(net, table, chain);
-       if (err < 0)
-               goto err_destroy_chain;
-
        if (!nft_use_inc(&table->use)) {
                err = -EMFILE;
-               goto err_use;
+               goto err_destroy_chain;
        }
 
        trans = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN);
        if (IS_ERR(trans)) {
                err = PTR_ERR(trans);
-               goto err_unregister_hook;
+               goto err_trans;
        }
 
        nft_trans_chain_policy(trans) = NFT_CHAIN_POLICY_UNSET;
@@ -2523,17 +2521,22 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
                nft_trans_chain_policy(trans) = policy;
 
        err = nft_chain_add(table, chain);
-       if (err < 0) {
-               nft_trans_destroy(trans);
-               goto err_unregister_hook;
-       }
+       if (err < 0)
+               goto err_chain_add;
+
+       /* This must be LAST to ensure no packets are walking over this chain. */
+       err = nf_tables_register_hook(net, table, chain);
+       if (err < 0)
+               goto err_register_hook;
 
        return 0;
 
-err_unregister_hook:
+err_register_hook:
+       nft_chain_del(chain);
+err_chain_add:
+       nft_trans_destroy(trans);
+err_trans:
        nft_use_dec_restore(&table->use);
-err_use:
-       nf_tables_unregister_hook(net, table, chain);
 err_destroy_chain:
        nf_tables_chain_destroy(ctx);
 
@@ -4998,6 +5001,12 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
                if ((flags & (NFT_SET_EVAL | NFT_SET_OBJECT)) ==
                             (NFT_SET_EVAL | NFT_SET_OBJECT))
                        return -EOPNOTSUPP;
+               if ((flags & (NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT | NFT_SET_EVAL)) ==
+                            (NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT))
+                       return -EOPNOTSUPP;
+               if ((flags & (NFT_SET_CONSTANT | NFT_SET_TIMEOUT)) ==
+                            (NFT_SET_CONSTANT | NFT_SET_TIMEOUT))
+                       return -EOPNOTSUPP;
        }
 
        desc.dtype = 0;
@@ -5421,6 +5430,7 @@ static void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
 
        if (list_empty(&set->bindings) && nft_set_is_anonymous(set)) {
                list_del_rcu(&set->list);
+               set->dead = 1;
                if (event)
                        nf_tables_set_notify(ctx, set, NFT_MSG_DELSET,
                                             GFP_KERNEL);
@@ -8455,9 +8465,9 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
        u8 family = info->nfmsg->nfgen_family;
        const struct nf_flowtable_type *type;
        struct nft_flowtable *flowtable;
-       struct nft_hook *hook, *next;
        struct net *net = info->net;
        struct nft_table *table;
+       struct nft_trans *trans;
        struct nft_ctx ctx;
        int err;
 
@@ -8537,34 +8547,34 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
        err = nft_flowtable_parse_hook(&ctx, nla, &flowtable_hook, flowtable,
                                       extack, true);
        if (err < 0)
-               goto err4;
+               goto err_flowtable_parse_hooks;
 
        list_splice(&flowtable_hook.list, &flowtable->hook_list);
        flowtable->data.priority = flowtable_hook.priority;
        flowtable->hooknum = flowtable_hook.num;
 
+       trans = nft_trans_flowtable_add(&ctx, NFT_MSG_NEWFLOWTABLE, flowtable);
+       if (IS_ERR(trans)) {
+               err = PTR_ERR(trans);
+               goto err_flowtable_trans;
+       }
+
+       /* This must be LAST to ensure no packets are walking over this flowtable. */
        err = nft_register_flowtable_net_hooks(ctx.net, table,
                                               &flowtable->hook_list,
                                               flowtable);
-       if (err < 0) {
-               nft_hooks_destroy(&flowtable->hook_list);
-               goto err4;
-       }
-
-       err = nft_trans_flowtable_add(&ctx, NFT_MSG_NEWFLOWTABLE, flowtable);
        if (err < 0)
-               goto err5;
+               goto err_flowtable_hooks;
 
        list_add_tail_rcu(&flowtable->list, &table->flowtables);
 
        return 0;
-err5:
-       list_for_each_entry_safe(hook, next, &flowtable->hook_list, list) {
-               nft_unregister_flowtable_hook(net, flowtable, hook);
-               list_del_rcu(&hook->list);
-               kfree_rcu(hook, rcu);
-       }
-err4:
+
+err_flowtable_hooks:
+       nft_trans_destroy(trans);
+err_flowtable_trans:
+       nft_hooks_destroy(&flowtable->hook_list);
+err_flowtable_parse_hooks:
        flowtable->data.type->free(&flowtable->data);
 err3:
        module_put(type->owner);
index c3e635364701cf1cc544c6910c2eaddb1281bf29..a48d5f0e2f3e127564107ba87b3982ff865bff8d 100644 (file)
@@ -21,7 +21,7 @@
 #include <net/netfilter/nf_log.h>
 #include <net/netfilter/nft_meta.h>
 
-#if defined(CONFIG_RETPOLINE) && defined(CONFIG_X86)
+#if defined(CONFIG_MITIGATION_RETPOLINE) && defined(CONFIG_X86)
 
 static struct static_key_false nf_tables_skip_direct_calls;
 
@@ -207,7 +207,7 @@ static void expr_call_ops_eval(const struct nft_expr *expr,
                               struct nft_regs *regs,
                               struct nft_pktinfo *pkt)
 {
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
        unsigned long e;
 
        if (nf_skip_indirect_calls())
@@ -236,7 +236,7 @@ static void expr_call_ops_eval(const struct nft_expr *expr,
        X(e, nft_objref_map_eval);
 #undef  X
 indirect_call:
-#endif /* CONFIG_RETPOLINE */
+#endif /* CONFIG_MITIGATION_RETPOLINE */
        expr->ops->eval(expr, regs, pkt);
 }
 
index 1f9474fefe84923e7769efd8ea5c703f5783e37d..d3d11dede54507262022725a5e54a12f0def7f89 100644 (file)
@@ -359,10 +359,20 @@ static int nft_target_validate(const struct nft_ctx *ctx,
 
        if (ctx->family != NFPROTO_IPV4 &&
            ctx->family != NFPROTO_IPV6 &&
+           ctx->family != NFPROTO_INET &&
            ctx->family != NFPROTO_BRIDGE &&
            ctx->family != NFPROTO_ARP)
                return -EOPNOTSUPP;
 
+       ret = nft_chain_validate_hooks(ctx->chain,
+                                      (1 << NF_INET_PRE_ROUTING) |
+                                      (1 << NF_INET_LOCAL_IN) |
+                                      (1 << NF_INET_FORWARD) |
+                                      (1 << NF_INET_LOCAL_OUT) |
+                                      (1 << NF_INET_POST_ROUTING));
+       if (ret)
+               return ret;
+
        if (nft_is_base_chain(ctx->chain)) {
                const struct nft_base_chain *basechain =
                                                nft_base_chain(ctx->chain);
@@ -610,10 +620,20 @@ static int nft_match_validate(const struct nft_ctx *ctx,
 
        if (ctx->family != NFPROTO_IPV4 &&
            ctx->family != NFPROTO_IPV6 &&
+           ctx->family != NFPROTO_INET &&
            ctx->family != NFPROTO_BRIDGE &&
            ctx->family != NFPROTO_ARP)
                return -EOPNOTSUPP;
 
+       ret = nft_chain_validate_hooks(ctx->chain,
+                                      (1 << NF_INET_PRE_ROUTING) |
+                                      (1 << NF_INET_LOCAL_IN) |
+                                      (1 << NF_INET_FORWARD) |
+                                      (1 << NF_INET_LOCAL_OUT) |
+                                      (1 << NF_INET_POST_ROUTING));
+       if (ret)
+               return ret;
+
        if (nft_is_base_chain(ctx->chain)) {
                const struct nft_base_chain *basechain =
                                                nft_base_chain(ctx->chain);
index bfd3e5a14dab68484469bdba71af37a460822549..452ed94c3a4d85455bd888f48d85c1459da99c31 100644 (file)
@@ -754,7 +754,7 @@ static bool nft_ct_set_reduce(struct nft_regs_track *track,
        return false;
 }
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
 static const struct nft_expr_ops nft_ct_get_fast_ops = {
        .type           = &nft_ct_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
@@ -799,7 +799,7 @@ nft_ct_select_ops(const struct nft_ctx *ctx,
                return ERR_PTR(-EINVAL);
 
        if (tb[NFTA_CT_DREG]) {
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
                u32 k = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
 
                switch (k) {
@@ -1256,14 +1256,13 @@ static int nft_ct_expect_obj_init(const struct nft_ctx *ctx,
        switch (priv->l3num) {
        case NFPROTO_IPV4:
        case NFPROTO_IPV6:
-               if (priv->l3num != ctx->family)
-                       return -EINVAL;
+               if (priv->l3num == ctx->family || ctx->family == NFPROTO_INET)
+                       break;
 
-               fallthrough;
-       case NFPROTO_INET:
-               break;
+               return -EINVAL;
+       case NFPROTO_INET: /* tuple.src.l3num supports NFPROTO_IPV4/6 only */
        default:
-               return -EOPNOTSUPP;
+               return -EAFNOSUPPORT;
        }
 
        priv->l4proto = nla_get_u8(tb[NFTA_CT_EXPECT_L4PROTO]);
index 397351fa4d5f82d8bcec25e1d69f327dc60e0199..ab95760987010b649483bf052fbdba9fde4c9624 100644 (file)
@@ -361,6 +361,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
                ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
        }
 
+       __set_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags);
        ret = flow_offload_add(flowtable, flow);
        if (ret < 0)
                goto err_flow_add;
index 870e5b113d13ec903b00a6f7921d7c162e57418f..a0055f510e31e9b77526a11c66c565b973897706 100644 (file)
@@ -24,7 +24,7 @@ struct nft_lookup {
        struct nft_set_binding          binding;
 };
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
 bool nft_set_do_lookup(const struct net *net, const struct nft_set *set,
                       const u32 *key, const struct nft_set_ext **ext)
 {
index f59a0cd811051add128f9feaee4501fcc153ed79..3842c7341a9f40a088d78532c4b610f3a99d7d23 100644 (file)
@@ -144,10 +144,10 @@ struct nft_pipapo_scratch {
 
 /**
  * struct nft_pipapo_match - Data used for lookup and matching
- * @field_count                Amount of fields in set
+ * @field_count:       Amount of fields in set
  * @scratch:           Preallocated per-CPU maps for partial matching results
  * @bsize_max:         Maximum lookup table bucket size of all fields, in longs
- * @rcu                        Matching data is swapped on commits
+ * @rcu:               Matching data is swapped on commits
  * @f:                 Fields, with lookup and mapping tables
  */
 struct nft_pipapo_match {
index 9c962347cf859f16fc76e4d8a2fd22cdb3d142d6..ff315351269fe643073bb2984485b3a76566b1c8 100644 (file)
@@ -167,7 +167,7 @@ static inline u32 netlink_group_mask(u32 group)
 static struct sk_buff *netlink_to_full_skb(const struct sk_buff *skb,
                                           gfp_t gfp_mask)
 {
-       unsigned int len = skb_end_offset(skb);
+       unsigned int len = skb->len;
        struct sk_buff *new;
 
        new = alloc_skb(len, gfp_mask);
index 0eed00184adf454d2e06bb44330c079a402a959e..104a80b75477f60199c69811ff48e65af293297c 100644 (file)
@@ -453,16 +453,16 @@ static int nr_create(struct net *net, struct socket *sock, int protocol,
        nr_init_timers(sk);
 
        nr->t1     =
-               msecs_to_jiffies(sysctl_netrom_transport_timeout);
+               msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_timeout));
        nr->t2     =
-               msecs_to_jiffies(sysctl_netrom_transport_acknowledge_delay);
+               msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_acknowledge_delay));
        nr->n2     =
-               msecs_to_jiffies(sysctl_netrom_transport_maximum_tries);
+               msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_maximum_tries));
        nr->t4     =
-               msecs_to_jiffies(sysctl_netrom_transport_busy_delay);
+               msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_busy_delay));
        nr->idle   =
-               msecs_to_jiffies(sysctl_netrom_transport_no_activity_timeout);
-       nr->window = sysctl_netrom_transport_requested_window_size;
+               msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_no_activity_timeout));
+       nr->window = READ_ONCE(sysctl_netrom_transport_requested_window_size);
 
        nr->bpqext = 1;
        nr->state  = NR_STATE_0;
@@ -954,7 +954,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
                 * G8PZT's Xrouter which is sending packets with command type 7
                 * as an extension of the protocol.
                 */
-               if (sysctl_netrom_reset_circuit &&
+               if (READ_ONCE(sysctl_netrom_reset_circuit) &&
                    (frametype != NR_RESET || flags != 0))
                        nr_transmit_reset(skb, 1);
 
index 3aaac4a22b38763cd855e494b2c19fdf3bcbd54e..2c34389c3ce6f16acf669fa14c7b38a7d63dda4b 100644 (file)
@@ -81,7 +81,7 @@ static int nr_header(struct sk_buff *skb, struct net_device *dev,
        buff[6] |= AX25_SSSID_SPARE;
        buff    += AX25_ADDR_LEN;
 
-       *buff++ = sysctl_netrom_network_ttl_initialiser;
+       *buff++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser);
 
        *buff++ = NR_PROTO_IP;
        *buff++ = NR_PROTO_IP;
index 2f084b6f69d7e05b51d1673157e8e72f3b9e2635..97944db6b5ac64387d8c8d53dc551bb11f1789f1 100644 (file)
@@ -97,7 +97,7 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
                break;
 
        case NR_RESET:
-               if (sysctl_netrom_reset_circuit)
+               if (READ_ONCE(sysctl_netrom_reset_circuit))
                        nr_disconnect(sk, ECONNRESET);
                break;
 
@@ -128,7 +128,7 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
                break;
 
        case NR_RESET:
-               if (sysctl_netrom_reset_circuit)
+               if (READ_ONCE(sysctl_netrom_reset_circuit))
                        nr_disconnect(sk, ECONNRESET);
                break;
 
@@ -262,7 +262,7 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
                break;
 
        case NR_RESET:
-               if (sysctl_netrom_reset_circuit)
+               if (READ_ONCE(sysctl_netrom_reset_circuit))
                        nr_disconnect(sk, ECONNRESET);
                break;
 
index 44929657f5b717de639c13334f17f42f652a78cc..5e531394a724b7f919f22ae2be42c8feaafdc22e 100644 (file)
@@ -204,7 +204,7 @@ void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb)
        dptr[6] |= AX25_SSSID_SPARE;
        dptr += AX25_ADDR_LEN;
 
-       *dptr++ = sysctl_netrom_network_ttl_initialiser;
+       *dptr++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser);
 
        if (!nr_route_frame(skb, NULL)) {
                kfree_skb(skb);
index baea3cbd76ca5bb5803974a75c3f10f87cc80140..70480869ad1c566a8ab8a28c0d39bdae056ec596 100644 (file)
@@ -153,7 +153,7 @@ static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
                nr_neigh->digipeat = NULL;
                nr_neigh->ax25     = NULL;
                nr_neigh->dev      = dev;
-               nr_neigh->quality  = sysctl_netrom_default_path_quality;
+               nr_neigh->quality  = READ_ONCE(sysctl_netrom_default_path_quality);
                nr_neigh->locked   = 0;
                nr_neigh->count    = 0;
                nr_neigh->number   = nr_neigh_no++;
@@ -728,7 +728,7 @@ void nr_link_failed(ax25_cb *ax25, int reason)
        nr_neigh->ax25 = NULL;
        ax25_cb_put(ax25);
 
-       if (++nr_neigh->failed < sysctl_netrom_link_fails_count) {
+       if (++nr_neigh->failed < READ_ONCE(sysctl_netrom_link_fails_count)) {
                nr_neigh_put(nr_neigh);
                return;
        }
@@ -766,7 +766,7 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        if (ax25 != NULL) {
                ret = nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
                                  ax25->ax25_dev->dev, 0,
-                                 sysctl_netrom_obsolescence_count_initialiser);
+                                 READ_ONCE(sysctl_netrom_obsolescence_count_initialiser));
                if (ret)
                        return ret;
        }
@@ -780,7 +780,7 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                return ret;
        }
 
-       if (!sysctl_netrom_routing_control && ax25 != NULL)
+       if (!READ_ONCE(sysctl_netrom_routing_control) && ax25 != NULL)
                return 0;
 
        /* Its Time-To-Live has expired */
index e2d2af924cff4a4103e59e04a6efe69c6fcca23e..c3bbd5880850bb047c7375e2c1b8acf6e80e0231 100644 (file)
@@ -182,7 +182,8 @@ void nr_write_internal(struct sock *sk, int frametype)
                *dptr++ = nr->my_id;
                *dptr++ = frametype;
                *dptr++ = nr->window;
-               if (nr->bpqext) *dptr++ = sysctl_netrom_network_ttl_initialiser;
+               if (nr->bpqext)
+                       *dptr++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser);
                break;
 
        case NR_DISCREQ:
@@ -236,7 +237,7 @@ void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags)
        dptr[6] |= AX25_SSSID_SPARE;
        dptr += AX25_ADDR_LEN;
 
-       *dptr++ = sysctl_netrom_network_ttl_initialiser;
+       *dptr++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser);
 
        if (mine) {
                *dptr++ = 0;
index 88965e2068ac655317169256486613aadf471580..ebc5728aab4eaf0bc165cbdb03e26fc852af9a3e 100644 (file)
@@ -48,6 +48,7 @@ struct ovs_len_tbl {
 
 #define OVS_ATTR_NESTED -1
 #define OVS_ATTR_VARIABLE -2
+#define OVS_COPY_ACTIONS_MAX_DEPTH 16
 
 static bool actions_may_change_flow(const struct nlattr *actions)
 {
@@ -2545,13 +2546,15 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
                                  const struct sw_flow_key *key,
                                  struct sw_flow_actions **sfa,
                                  __be16 eth_type, __be16 vlan_tci,
-                                 u32 mpls_label_count, bool log);
+                                 u32 mpls_label_count, bool log,
+                                 u32 depth);
 
 static int validate_and_copy_sample(struct net *net, const struct nlattr *attr,
                                    const struct sw_flow_key *key,
                                    struct sw_flow_actions **sfa,
                                    __be16 eth_type, __be16 vlan_tci,
-                                   u32 mpls_label_count, bool log, bool last)
+                                   u32 mpls_label_count, bool log, bool last,
+                                   u32 depth)
 {
        const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1];
        const struct nlattr *probability, *actions;
@@ -2602,7 +2605,8 @@ static int validate_and_copy_sample(struct net *net, const struct nlattr *attr,
                return err;
 
        err = __ovs_nla_copy_actions(net, actions, key, sfa,
-                                    eth_type, vlan_tci, mpls_label_count, log);
+                                    eth_type, vlan_tci, mpls_label_count, log,
+                                    depth + 1);
 
        if (err)
                return err;
@@ -2617,7 +2621,8 @@ static int validate_and_copy_dec_ttl(struct net *net,
                                     const struct sw_flow_key *key,
                                     struct sw_flow_actions **sfa,
                                     __be16 eth_type, __be16 vlan_tci,
-                                    u32 mpls_label_count, bool log)
+                                    u32 mpls_label_count, bool log,
+                                    u32 depth)
 {
        const struct nlattr *attrs[OVS_DEC_TTL_ATTR_MAX + 1];
        int start, action_start, err, rem;
@@ -2660,7 +2665,8 @@ static int validate_and_copy_dec_ttl(struct net *net,
                return action_start;
 
        err = __ovs_nla_copy_actions(net, actions, key, sfa, eth_type,
-                                    vlan_tci, mpls_label_count, log);
+                                    vlan_tci, mpls_label_count, log,
+                                    depth + 1);
        if (err)
                return err;
 
@@ -2674,7 +2680,8 @@ static int validate_and_copy_clone(struct net *net,
                                   const struct sw_flow_key *key,
                                   struct sw_flow_actions **sfa,
                                   __be16 eth_type, __be16 vlan_tci,
-                                  u32 mpls_label_count, bool log, bool last)
+                                  u32 mpls_label_count, bool log, bool last,
+                                  u32 depth)
 {
        int start, err;
        u32 exec;
@@ -2694,7 +2701,8 @@ static int validate_and_copy_clone(struct net *net,
                return err;
 
        err = __ovs_nla_copy_actions(net, attr, key, sfa,
-                                    eth_type, vlan_tci, mpls_label_count, log);
+                                    eth_type, vlan_tci, mpls_label_count, log,
+                                    depth + 1);
        if (err)
                return err;
 
@@ -3063,7 +3071,7 @@ static int validate_and_copy_check_pkt_len(struct net *net,
                                           struct sw_flow_actions **sfa,
                                           __be16 eth_type, __be16 vlan_tci,
                                           u32 mpls_label_count,
-                                          bool log, bool last)
+                                          bool log, bool last, u32 depth)
 {
        const struct nlattr *acts_if_greater, *acts_if_lesser_eq;
        struct nlattr *a[OVS_CHECK_PKT_LEN_ATTR_MAX + 1];
@@ -3111,7 +3119,8 @@ static int validate_and_copy_check_pkt_len(struct net *net,
                return nested_acts_start;
 
        err = __ovs_nla_copy_actions(net, acts_if_lesser_eq, key, sfa,
-                                    eth_type, vlan_tci, mpls_label_count, log);
+                                    eth_type, vlan_tci, mpls_label_count, log,
+                                    depth + 1);
 
        if (err)
                return err;
@@ -3124,7 +3133,8 @@ static int validate_and_copy_check_pkt_len(struct net *net,
                return nested_acts_start;
 
        err = __ovs_nla_copy_actions(net, acts_if_greater, key, sfa,
-                                    eth_type, vlan_tci, mpls_label_count, log);
+                                    eth_type, vlan_tci, mpls_label_count, log,
+                                    depth + 1);
 
        if (err)
                return err;
@@ -3152,12 +3162,16 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
                                  const struct sw_flow_key *key,
                                  struct sw_flow_actions **sfa,
                                  __be16 eth_type, __be16 vlan_tci,
-                                 u32 mpls_label_count, bool log)
+                                 u32 mpls_label_count, bool log,
+                                 u32 depth)
 {
        u8 mac_proto = ovs_key_mac_proto(key);
        const struct nlattr *a;
        int rem, err;
 
+       if (depth > OVS_COPY_ACTIONS_MAX_DEPTH)
+               return -EOVERFLOW;
+
        nla_for_each_nested(a, attr, rem) {
                /* Expected argument lengths, (u32)-1 for variable length. */
                static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {
@@ -3355,7 +3369,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
                        err = validate_and_copy_sample(net, a, key, sfa,
                                                       eth_type, vlan_tci,
                                                       mpls_label_count,
-                                                      log, last);
+                                                      log, last, depth);
                        if (err)
                                return err;
                        skip_copy = true;
@@ -3426,7 +3440,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
                        err = validate_and_copy_clone(net, a, key, sfa,
                                                      eth_type, vlan_tci,
                                                      mpls_label_count,
-                                                     log, last);
+                                                     log, last, depth);
                        if (err)
                                return err;
                        skip_copy = true;
@@ -3440,7 +3454,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
                                                              eth_type,
                                                              vlan_tci,
                                                              mpls_label_count,
-                                                             log, last);
+                                                             log, last,
+                                                             depth);
                        if (err)
                                return err;
                        skip_copy = true;
@@ -3450,7 +3465,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
                case OVS_ACTION_ATTR_DEC_TTL:
                        err = validate_and_copy_dec_ttl(net, a, key, sfa,
                                                        eth_type, vlan_tci,
-                                                       mpls_label_count, log);
+                                                       mpls_label_count, log,
+                                                       depth);
                        if (err)
                                return err;
                        skip_copy = true;
@@ -3495,7 +3511,8 @@ int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
 
        (*sfa)->orig_len = nla_len(attr);
        err = __ovs_nla_copy_actions(net, attr, key, sfa, key->eth.type,
-                                    key->eth.vlan.tci, mpls_label_count, log);
+                                    key->eth.vlan.tci, mpls_label_count, log,
+                                    0);
        if (err)
                ovs_nla_free_flow_actions(*sfa);
 
index 3aa50dc7535b7761c77652d2f38826419b57c26a..976fe250b50955ec51b0c5d73f2dfa132990b60b 100644 (file)
@@ -34,10 +34,10 @@ static int pn_ioctl(struct sock *sk, int cmd, int *karg)
 
        switch (cmd) {
        case SIOCINQ:
-               lock_sock(sk);
+               spin_lock_bh(&sk->sk_receive_queue.lock);
                skb = skb_peek(&sk->sk_receive_queue);
                *karg = skb ? skb->len : 0;
-               release_sock(sk);
+               spin_unlock_bh(&sk->sk_receive_queue.lock);
                return 0;
 
        case SIOCPNADDRESOURCE:
index faba31f2eff2903bee7082b295f137ff848a1e10..3dd5f52bc1b58e3f1ee4e235126438c723f1f73c 100644 (file)
@@ -917,6 +917,37 @@ static int pep_sock_enable(struct sock *sk, struct sockaddr *addr, int len)
        return 0;
 }
 
+static unsigned int pep_first_packet_length(struct sock *sk)
+{
+       struct pep_sock *pn = pep_sk(sk);
+       struct sk_buff_head *q;
+       struct sk_buff *skb;
+       unsigned int len = 0;
+       bool found = false;
+
+       if (sock_flag(sk, SOCK_URGINLINE)) {
+               q = &pn->ctrlreq_queue;
+               spin_lock_bh(&q->lock);
+               skb = skb_peek(q);
+               if (skb) {
+                       len = skb->len;
+                       found = true;
+               }
+               spin_unlock_bh(&q->lock);
+       }
+
+       if (likely(!found)) {
+               q = &sk->sk_receive_queue;
+               spin_lock_bh(&q->lock);
+               skb = skb_peek(q);
+               if (skb)
+                       len = skb->len;
+               spin_unlock_bh(&q->lock);
+       }
+
+       return len;
+}
+
 static int pep_ioctl(struct sock *sk, int cmd, int *karg)
 {
        struct pep_sock *pn = pep_sk(sk);
@@ -929,15 +960,7 @@ static int pep_ioctl(struct sock *sk, int cmd, int *karg)
                        break;
                }
 
-               lock_sock(sk);
-               if (sock_flag(sk, SOCK_URGINLINE) &&
-                   !skb_queue_empty(&pn->ctrlreq_queue))
-                       *karg = skb_peek(&pn->ctrlreq_queue)->len;
-               else if (!skb_queue_empty(&sk->sk_receive_queue))
-                       *karg = skb_peek(&sk->sk_receive_queue)->len;
-               else
-                       *karg = 0;
-               release_sock(sk);
+               *karg = pep_first_packet_length(sk);
                ret = 0;
                break;
 
index fba82d36593add3317e89104aabbd69a0281cb33..a4e3c5de998be4c756cb0dc423ee9a7e7fa3e1a9 100644 (file)
@@ -301,6 +301,9 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
                        kfree(sg);
                }
                ret = PTR_ERR(trans_private);
+               /* Trigger connection so that its ready for the next retry */
+               if (ret == -ENODEV)
+                       rds_conn_connect_if_down(cp->cp_conn);
                goto out;
        }
 
index c71b923764fd7cd7268953b968c5f5749a0b98a6..5627f80013f8b17d3de6284784fe3cbb02bba754 100644 (file)
@@ -425,6 +425,7 @@ static int rds_still_queued(struct rds_sock *rs, struct rds_incoming *inc,
        struct sock *sk = rds_rs_to_sk(rs);
        int ret = 0;
        unsigned long flags;
+       struct rds_incoming *to_drop = NULL;
 
        write_lock_irqsave(&rs->rs_recv_lock, flags);
        if (!list_empty(&inc->i_item)) {
@@ -435,11 +436,14 @@ static int rds_still_queued(struct rds_sock *rs, struct rds_incoming *inc,
                                              -be32_to_cpu(inc->i_hdr.h_len),
                                              inc->i_hdr.h_dport);
                        list_del_init(&inc->i_item);
-                       rds_inc_put(inc);
+                       to_drop = inc;
                }
        }
        write_unlock_irqrestore(&rs->rs_recv_lock, flags);
 
+       if (to_drop)
+               rds_inc_put(to_drop);
+
        rdsdebug("inc %p rs %p still %d dropped %d\n", inc, rs, ret, drop);
        return ret;
 }
@@ -758,16 +762,21 @@ void rds_clear_recv_queue(struct rds_sock *rs)
        struct sock *sk = rds_rs_to_sk(rs);
        struct rds_incoming *inc, *tmp;
        unsigned long flags;
+       LIST_HEAD(to_drop);
 
        write_lock_irqsave(&rs->rs_recv_lock, flags);
        list_for_each_entry_safe(inc, tmp, &rs->rs_recv_queue, i_item) {
                rds_recv_rcvbuf_delta(rs, sk, inc->i_conn->c_lcong,
                                      -be32_to_cpu(inc->i_hdr.h_len),
                                      inc->i_hdr.h_dport);
+               list_move(&inc->i_item, &to_drop);
+       }
+       write_unlock_irqrestore(&rs->rs_recv_lock, flags);
+
+       list_for_each_entry_safe(inc, tmp, &to_drop, i_item) {
                list_del_init(&inc->i_item);
                rds_inc_put(inc);
        }
-       write_unlock_irqrestore(&rs->rs_recv_lock, flags);
 }
 
 /*
index 5e57a1581dc60571406e2faeeeba63af1e8aa29c..2899def23865fa47ce55faa7c7eb72fb52bc432b 100644 (file)
@@ -1313,12 +1313,8 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
 
        /* Parse any control messages the user may have included. */
        ret = rds_cmsg_send(rs, rm, msg, &allocated_mr, &vct);
-       if (ret) {
-               /* Trigger connection so that its ready for the next retry */
-               if (ret ==  -EAGAIN)
-                       rds_conn_connect_if_down(conn);
+       if (ret)
                goto out;
-       }
 
        if (rm->rdma.op_active && !conn->c_trans->xmit_rdma) {
                printk_ratelimited(KERN_NOTICE "rdma_op %p conn xmit_rdma %p\n",
index 12386f590b0f61f45e4ff40c9ec3605326671a2d..6faa7d00da09771ae130581604c3b14c50472966 100644 (file)
@@ -232,18 +232,14 @@ release_idr:
        return err;
 }
 
-static bool is_mirred_nested(void)
-{
-       return unlikely(__this_cpu_read(mirred_nest_level) > 1);
-}
-
-static int tcf_mirred_forward(bool want_ingress, struct sk_buff *skb)
+static int
+tcf_mirred_forward(bool at_ingress, bool want_ingress, struct sk_buff *skb)
 {
        int err;
 
        if (!want_ingress)
                err = tcf_dev_queue_xmit(skb, dev_queue_xmit);
-       else if (is_mirred_nested())
+       else if (!at_ingress)
                err = netif_rx(skb);
        else
                err = netif_receive_skb(skb);
@@ -270,8 +266,7 @@ static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m,
        if (unlikely(!(dev->flags & IFF_UP)) || !netif_carrier_ok(dev)) {
                net_notice_ratelimited("tc mirred to Houston: device %s is down\n",
                                       dev->name);
-               err = -ENODEV;
-               goto out;
+               goto err_cant_do;
        }
 
        /* we could easily avoid the clone only if called by ingress and clsact;
@@ -283,10 +278,8 @@ static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m,
                tcf_mirred_can_reinsert(retval);
        if (!dont_clone) {
                skb_to_send = skb_clone(skb, GFP_ATOMIC);
-               if (!skb_to_send) {
-                       err =  -ENOMEM;
-                       goto out;
-               }
+               if (!skb_to_send)
+                       goto err_cant_do;
        }
 
        want_ingress = tcf_mirred_act_wants_ingress(m_eaction);
@@ -319,19 +312,20 @@ static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m,
 
                skb_set_redirected(skb_to_send, skb_to_send->tc_at_ingress);
 
-               err = tcf_mirred_forward(want_ingress, skb_to_send);
+               err = tcf_mirred_forward(at_ingress, want_ingress, skb_to_send);
        } else {
-               err = tcf_mirred_forward(want_ingress, skb_to_send);
+               err = tcf_mirred_forward(at_ingress, want_ingress, skb_to_send);
        }
-
-       if (err) {
-out:
+       if (err)
                tcf_action_inc_overlimit_qstats(&m->common);
-               if (is_redirect)
-                       retval = TC_ACT_SHOT;
-       }
 
        return retval;
+
+err_cant_do:
+       if (is_redirect)
+               retval = TC_ACT_SHOT;
+       tcf_action_inc_overlimit_qstats(&m->common);
+       return retval;
 }
 
 static int tcf_blockcast_redir(struct sk_buff *skb, struct tcf_mirred *m,
@@ -533,8 +527,6 @@ static int mirred_device_event(struct notifier_block *unused,
                                 * net_device are already rcu protected.
                                 */
                                RCU_INIT_POINTER(m->tcfm_dev, NULL);
-                       } else if (m->tcfm_blockid) {
-                               m->tcfm_blockid = 0;
                        }
                        spin_unlock_bh(&m->tcf_lock);
                }
index efb9d2811b73d18862f824b0b7a8b4e6b905271d..6ee7064c82fcc3bdb7596e2ad8fe33bc6456102d 100644 (file)
@@ -2460,8 +2460,11 @@ unbind_filter:
        }
 
 errout_idr:
-       if (!fold)
+       if (!fold) {
+               spin_lock(&tp->lock);
                idr_remove(&head->handle_idr, fnew->handle);
+               spin_unlock(&tp->lock);
+       }
        __fl_put(fnew);
 errout_tb:
        kfree(tb);
index 5ea84decec19a6b6593e1f9caa31e0e914a52e9d..5337bc46275519a062e54d093df84f3ea8f58583 100644 (file)
@@ -222,6 +222,7 @@ static void __exit exit_em_canid(void)
        tcf_em_unregister(&em_canid_ops);
 }
 
+MODULE_DESCRIPTION("ematch classifier to match CAN IDs embedded in skb CAN frames");
 MODULE_LICENSE("GPL");
 
 module_init(init_em_canid);
index f17b049ea53090d750133422f90b3ad673fd6c41..c90ad7ea26b4697cbedf25a51fc1b92771040c4e 100644 (file)
@@ -87,6 +87,7 @@ static void __exit exit_em_cmp(void)
        tcf_em_unregister(&em_cmp_ops);
 }
 
+MODULE_DESCRIPTION("ematch classifier for basic data types(8/16/32 bit) against skb data");
 MODULE_LICENSE("GPL");
 
 module_init(init_em_cmp);
index 09d8afd04a2a78ac55b0ddd1b424ddcb28b9ba83..8996c73c9779b5fa804e6f913834cf1fe4d071e6 100644 (file)
@@ -1006,6 +1006,7 @@ static void __exit exit_em_meta(void)
        tcf_em_unregister(&em_meta_ops);
 }
 
+MODULE_DESCRIPTION("ematch classifier for various internal kernel metadata, skb metadata and sk metadata");
 MODULE_LICENSE("GPL");
 
 module_init(init_em_meta);
index a83b237cbeb06553c805dfeac3632fd69d6dc3c6..4f9f21a05d5e40aadfdc4c339b8178ad43dc2c8b 100644 (file)
@@ -68,6 +68,7 @@ static void __exit exit_em_nbyte(void)
        tcf_em_unregister(&em_nbyte_ops);
 }
 
+MODULE_DESCRIPTION("ematch classifier for arbitrary skb multi-bytes");
 MODULE_LICENSE("GPL");
 
 module_init(init_em_nbyte);
index f176afb70559eb0a594a2f724765ccb0a1d3b746..420c66203b1777632500ee3d5e2d89a46b50bc4c 100644 (file)
@@ -147,6 +147,7 @@ static void __exit exit_em_text(void)
        tcf_em_unregister(&em_text_ops);
 }
 
+MODULE_DESCRIPTION("ematch classifier for embedded text in skbs");
 MODULE_LICENSE("GPL");
 
 module_init(init_em_text);
index 71b070da043796d1872ae7aecc2348ab6a4b37f1..fdec4db5ec89d047427d62fb6ce95b3649a80f9f 100644 (file)
@@ -52,6 +52,7 @@ static void __exit exit_em_u32(void)
        tcf_em_unregister(&em_u32_ops);
 }
 
+MODULE_DESCRIPTION("ematch skb classifier using 32 bit chunks of data");
 MODULE_LICENSE("GPL");
 
 module_init(init_em_u32);
index 36b025cc4fd263be35cdf6c6637c7d79e53c5f8f..87f6e3c6daa86dd870fe0ac5aefb50e76cd8bdd8 100644 (file)
@@ -2410,7 +2410,7 @@ static struct pernet_operations psched_net_ops = {
        .exit = psched_net_exit,
 };
 
-#if IS_ENABLED(CONFIG_RETPOLINE)
+#if IS_ENABLED(CONFIG_MITIGATION_RETPOLINE)
 DEFINE_STATIC_KEY_FALSE(tc_skip_wrapper);
 #endif
 
index 7182c5a450fb5b804d19fdb1b04b75a2c34eb2d0..5c1652181805880ff9f5eaae45e0bab6b00170df 100644 (file)
@@ -38,6 +38,14 @@ void sctp_inq_init(struct sctp_inq *queue)
        INIT_WORK(&queue->immediate, NULL);
 }
 
+/* Properly release the chunk which is being worked on. */
+static inline void sctp_inq_chunk_free(struct sctp_chunk *chunk)
+{
+       if (chunk->head_skb)
+               chunk->skb = chunk->head_skb;
+       sctp_chunk_free(chunk);
+}
+
 /* Release the memory associated with an SCTP inqueue.  */
 void sctp_inq_free(struct sctp_inq *queue)
 {
@@ -53,7 +61,7 @@ void sctp_inq_free(struct sctp_inq *queue)
         * free it as well.
         */
        if (queue->in_progress) {
-               sctp_chunk_free(queue->in_progress);
+               sctp_inq_chunk_free(queue->in_progress);
                queue->in_progress = NULL;
        }
 }
@@ -130,9 +138,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
                                goto new_skb;
                        }
 
-                       if (chunk->head_skb)
-                               chunk->skb = chunk->head_skb;
-                       sctp_chunk_free(chunk);
+                       sctp_inq_chunk_free(chunk);
                        chunk = queue->in_progress = NULL;
                } else {
                        /* Nothing to do. Next chunk in the packet, please. */
index a2cb30af46cb158fcd3a1c12349a0375a1020203..0f53a5c6fd9d9c88c78f51640b179bf214e78bda 100644 (file)
@@ -924,6 +924,7 @@ static int smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
                smc->clcsock->file->private_data = smc->clcsock;
                smc->clcsock->wq.fasync_list =
                        smc->sk.sk_socket->wq.fasync_list;
+               smc->sk.sk_socket->wq.fasync_list = NULL;
 
                /* There might be some wait entries remaining
                 * in smc sk->sk_wq and they should be woken up
index 5b045284849e03151b172cf55248492aed2b3472..c9189a970eec317745a06c27064f504a6ff2e3d2 100644 (file)
 #include <linux/rtnetlink.h>
 #include <net/switchdev.h>
 
+static bool switchdev_obj_eq(const struct switchdev_obj *a,
+                            const struct switchdev_obj *b)
+{
+       const struct switchdev_obj_port_vlan *va, *vb;
+       const struct switchdev_obj_port_mdb *ma, *mb;
+
+       if (a->id != b->id || a->orig_dev != b->orig_dev)
+               return false;
+
+       switch (a->id) {
+       case SWITCHDEV_OBJ_ID_PORT_VLAN:
+               va = SWITCHDEV_OBJ_PORT_VLAN(a);
+               vb = SWITCHDEV_OBJ_PORT_VLAN(b);
+               return va->flags == vb->flags &&
+                       va->vid == vb->vid &&
+                       va->changed == vb->changed;
+       case SWITCHDEV_OBJ_ID_PORT_MDB:
+       case SWITCHDEV_OBJ_ID_HOST_MDB:
+               ma = SWITCHDEV_OBJ_PORT_MDB(a);
+               mb = SWITCHDEV_OBJ_PORT_MDB(b);
+               return ma->vid == mb->vid &&
+                       ether_addr_equal(ma->addr, mb->addr);
+       default:
+               break;
+       }
+
+       BUG();
+}
+
 static LIST_HEAD(deferred);
 static DEFINE_SPINLOCK(deferred_lock);
 
@@ -307,6 +336,50 @@ int switchdev_port_obj_del(struct net_device *dev,
 }
 EXPORT_SYMBOL_GPL(switchdev_port_obj_del);
 
+/**
+ *     switchdev_port_obj_act_is_deferred - Is object action pending?
+ *
+ *     @dev: port device
+ *     @nt: type of action; add or delete
+ *     @obj: object to test
+ *
+ *     Returns true if a deferred item is pending, which is
+ *     equivalent to the action @nt on an object @obj.
+ *
+ *     rtnl_lock must be held.
+ */
+bool switchdev_port_obj_act_is_deferred(struct net_device *dev,
+                                       enum switchdev_notifier_type nt,
+                                       const struct switchdev_obj *obj)
+{
+       struct switchdev_deferred_item *dfitem;
+       bool found = false;
+
+       ASSERT_RTNL();
+
+       spin_lock_bh(&deferred_lock);
+
+       list_for_each_entry(dfitem, &deferred, list) {
+               if (dfitem->dev != dev)
+                       continue;
+
+               if ((dfitem->func == switchdev_port_obj_add_deferred &&
+                    nt == SWITCHDEV_PORT_OBJ_ADD) ||
+                   (dfitem->func == switchdev_port_obj_del_deferred &&
+                    nt == SWITCHDEV_PORT_OBJ_DEL)) {
+                       if (switchdev_obj_eq((const void *)dfitem->data, obj)) {
+                               found = true;
+                               break;
+                       }
+               }
+       }
+
+       spin_unlock_bh(&deferred_lock);
+
+       return found;
+}
+EXPORT_SYMBOL_GPL(switchdev_port_obj_act_is_deferred);
+
 static ATOMIC_NOTIFIER_HEAD(switchdev_notif_chain);
 static BLOCKING_NOTIFIER_HEAD(switchdev_blocking_notif_chain);
 
index 1c2c6800949dd4c2800f76326b7500f9743c4720..b4674f03d71a9fb9a5526555d7aca9b9cc5e665c 100644 (file)
@@ -1003,7 +1003,7 @@ static u16 tls_user_config(struct tls_context *ctx, bool tx)
        return 0;
 }
 
-static int tls_get_info(const struct sock *sk, struct sk_buff *skb)
+static int tls_get_info(struct sock *sk, struct sk_buff *skb)
 {
        u16 version, cipher_type;
        struct tls_context *ctx;
index 31e8a94dfc111b7705fe19b9b4ddee3e6a317a23..211f57164cb611fd2665f682906be96aa35463ed 100644 (file)
@@ -52,6 +52,7 @@ struct tls_decrypt_arg {
        struct_group(inargs,
        bool zc;
        bool async;
+       bool async_done;
        u8 tail;
        );
 
@@ -63,6 +64,7 @@ struct tls_decrypt_ctx {
        u8 iv[TLS_MAX_IV_SIZE];
        u8 aad[TLS_MAX_AAD_SIZE];
        u8 tail;
+       bool free_sgout;
        struct scatterlist sg[];
 };
 
@@ -187,7 +189,6 @@ static void tls_decrypt_done(void *data, int err)
        struct aead_request *aead_req = data;
        struct crypto_aead *aead = crypto_aead_reqtfm(aead_req);
        struct scatterlist *sgout = aead_req->dst;
-       struct scatterlist *sgin = aead_req->src;
        struct tls_sw_context_rx *ctx;
        struct tls_decrypt_ctx *dctx;
        struct tls_context *tls_ctx;
@@ -196,6 +197,17 @@ static void tls_decrypt_done(void *data, int err)
        struct sock *sk;
        int aead_size;
 
+       /* If requests get too backlogged crypto API returns -EBUSY and calls
+        * ->complete(-EINPROGRESS) immediately followed by ->complete(0)
+        * to make waiting for backlog to flush with crypto_wait_req() easier.
+        * First wait converts -EBUSY -> -EINPROGRESS, and the second one
+        * -EINPROGRESS -> 0.
+        * We have a single struct crypto_async_request per direction, this
+        * scheme doesn't help us, so just ignore the first ->complete().
+        */
+       if (err == -EINPROGRESS)
+               return;
+
        aead_size = sizeof(*aead_req) + crypto_aead_reqsize(aead);
        aead_size = ALIGN(aead_size, __alignof__(*dctx));
        dctx = (void *)((u8 *)aead_req + aead_size);
@@ -213,7 +225,7 @@ static void tls_decrypt_done(void *data, int err)
        }
 
        /* Free the destination pages if skb was not decrypted inplace */
-       if (sgout != sgin) {
+       if (dctx->free_sgout) {
                /* Skip the first S/G entry as it points to AAD */
                for_each_sg(sg_next(sgout), sg, UINT_MAX, pages) {
                        if (!sg)
@@ -224,10 +236,17 @@ static void tls_decrypt_done(void *data, int err)
 
        kfree(aead_req);
 
-       spin_lock_bh(&ctx->decrypt_compl_lock);
-       if (!atomic_dec_return(&ctx->decrypt_pending))
+       if (atomic_dec_and_test(&ctx->decrypt_pending))
                complete(&ctx->async_wait.completion);
-       spin_unlock_bh(&ctx->decrypt_compl_lock);
+}
+
+static int tls_decrypt_async_wait(struct tls_sw_context_rx *ctx)
+{
+       if (!atomic_dec_and_test(&ctx->decrypt_pending))
+               crypto_wait_req(-EINPROGRESS, &ctx->async_wait);
+       atomic_inc(&ctx->decrypt_pending);
+
+       return ctx->async_wait.err;
 }
 
 static int tls_do_decryption(struct sock *sk,
@@ -253,20 +272,33 @@ static int tls_do_decryption(struct sock *sk,
                aead_request_set_callback(aead_req,
                                          CRYPTO_TFM_REQ_MAY_BACKLOG,
                                          tls_decrypt_done, aead_req);
+               DEBUG_NET_WARN_ON_ONCE(atomic_read(&ctx->decrypt_pending) < 1);
                atomic_inc(&ctx->decrypt_pending);
        } else {
+               DECLARE_CRYPTO_WAIT(wait);
+
                aead_request_set_callback(aead_req,
                                          CRYPTO_TFM_REQ_MAY_BACKLOG,
-                                         crypto_req_done, &ctx->async_wait);
+                                         crypto_req_done, &wait);
+               ret = crypto_aead_decrypt(aead_req);
+               if (ret == -EINPROGRESS || ret == -EBUSY)
+                       ret = crypto_wait_req(ret, &wait);
+               return ret;
        }
 
        ret = crypto_aead_decrypt(aead_req);
-       if (ret == -EINPROGRESS) {
-               if (darg->async)
-                       return 0;
+       if (ret == -EINPROGRESS)
+               return 0;
 
-               ret = crypto_wait_req(ret, &ctx->async_wait);
+       if (ret == -EBUSY) {
+               ret = tls_decrypt_async_wait(ctx);
+               darg->async_done = true;
+               /* all completions have run, we're not doing async anymore */
+               darg->async = false;
+               return ret;
        }
+
+       atomic_dec(&ctx->decrypt_pending);
        darg->async = false;
 
        return ret;
@@ -439,9 +471,10 @@ static void tls_encrypt_done(void *data, int err)
        struct tls_rec *rec = data;
        struct scatterlist *sge;
        struct sk_msg *msg_en;
-       bool ready = false;
        struct sock *sk;
-       int pending;
+
+       if (err == -EINPROGRESS) /* see the comment in tls_decrypt_done() */
+               return;
 
        msg_en = &rec->msg_encrypted;
 
@@ -476,23 +509,25 @@ static void tls_encrypt_done(void *data, int err)
                /* If received record is at head of tx_list, schedule tx */
                first_rec = list_first_entry(&ctx->tx_list,
                                             struct tls_rec, list);
-               if (rec == first_rec)
-                       ready = true;
+               if (rec == first_rec) {
+                       /* Schedule the transmission */
+                       if (!test_and_set_bit(BIT_TX_SCHEDULED,
+                                             &ctx->tx_bitmask))
+                               schedule_delayed_work(&ctx->tx_work.work, 1);
+               }
        }
 
-       spin_lock_bh(&ctx->encrypt_compl_lock);
-       pending = atomic_dec_return(&ctx->encrypt_pending);
-
-       if (!pending && ctx->async_notify)
+       if (atomic_dec_and_test(&ctx->encrypt_pending))
                complete(&ctx->async_wait.completion);
-       spin_unlock_bh(&ctx->encrypt_compl_lock);
+}
 
-       if (!ready)
-               return;
+static int tls_encrypt_async_wait(struct tls_sw_context_tx *ctx)
+{
+       if (!atomic_dec_and_test(&ctx->encrypt_pending))
+               crypto_wait_req(-EINPROGRESS, &ctx->async_wait);
+       atomic_inc(&ctx->encrypt_pending);
 
-       /* Schedule the transmission */
-       if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask))
-               schedule_delayed_work(&ctx->tx_work.work, 1);
+       return ctx->async_wait.err;
 }
 
 static int tls_do_encryption(struct sock *sk,
@@ -541,9 +576,14 @@ static int tls_do_encryption(struct sock *sk,
 
        /* Add the record in tx_list */
        list_add_tail((struct list_head *)&rec->list, &ctx->tx_list);
+       DEBUG_NET_WARN_ON_ONCE(atomic_read(&ctx->encrypt_pending) < 1);
        atomic_inc(&ctx->encrypt_pending);
 
        rc = crypto_aead_encrypt(aead_req);
+       if (rc == -EBUSY) {
+               rc = tls_encrypt_async_wait(ctx);
+               rc = rc ?: -EINPROGRESS;
+       }
        if (!rc || rc != -EINPROGRESS) {
                atomic_dec(&ctx->encrypt_pending);
                sge->offset -= prot->prepend_size;
@@ -984,7 +1024,6 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg,
        int num_zc = 0;
        int orig_size;
        int ret = 0;
-       int pending;
 
        if (!eor && (msg->msg_flags & MSG_EOR))
                return -EINVAL;
@@ -1163,24 +1202,12 @@ trim_sgl:
        if (!num_async) {
                goto send_end;
        } else if (num_zc) {
-               /* Wait for pending encryptions to get completed */
-               spin_lock_bh(&ctx->encrypt_compl_lock);
-               ctx->async_notify = true;
-
-               pending = atomic_read(&ctx->encrypt_pending);
-               spin_unlock_bh(&ctx->encrypt_compl_lock);
-               if (pending)
-                       crypto_wait_req(-EINPROGRESS, &ctx->async_wait);
-               else
-                       reinit_completion(&ctx->async_wait.completion);
-
-               /* There can be no concurrent accesses, since we have no
-                * pending encrypt operations
-                */
-               WRITE_ONCE(ctx->async_notify, false);
+               int err;
 
-               if (ctx->async_wait.err) {
-                       ret = ctx->async_wait.err;
+               /* Wait for pending encryptions to get completed */
+               err = tls_encrypt_async_wait(ctx);
+               if (err) {
+                       ret = err;
                        copied = 0;
                }
        }
@@ -1229,7 +1256,6 @@ void tls_sw_splice_eof(struct socket *sock)
        ssize_t copied = 0;
        bool retrying = false;
        int ret = 0;
-       int pending;
 
        if (!ctx->open_rec)
                return;
@@ -1264,22 +1290,7 @@ retry:
        }
 
        /* Wait for pending encryptions to get completed */
-       spin_lock_bh(&ctx->encrypt_compl_lock);
-       ctx->async_notify = true;
-
-       pending = atomic_read(&ctx->encrypt_pending);
-       spin_unlock_bh(&ctx->encrypt_compl_lock);
-       if (pending)
-               crypto_wait_req(-EINPROGRESS, &ctx->async_wait);
-       else
-               reinit_completion(&ctx->async_wait.completion);
-
-       /* There can be no concurrent accesses, since we have no pending
-        * encrypt operations
-        */
-       WRITE_ONCE(ctx->async_notify, false);
-
-       if (ctx->async_wait.err)
+       if (tls_encrypt_async_wait(ctx))
                goto unlock;
 
        /* Transmit if any encryptions have completed */
@@ -1581,12 +1592,16 @@ static int tls_decrypt_sg(struct sock *sk, struct iov_iter *out_iov,
        } else if (out_sg) {
                memcpy(sgout, out_sg, n_sgout * sizeof(*sgout));
        }
+       dctx->free_sgout = !!pages;
 
        /* Prepare and submit AEAD request */
        err = tls_do_decryption(sk, sgin, sgout, dctx->iv,
                                data_len + prot->tail_size, aead_req, darg);
-       if (err)
+       if (err) {
+               if (darg->async_done)
+                       goto exit_free_skb;
                goto exit_free_pages;
+       }
 
        darg->skb = clear_skb ?: tls_strp_msg(ctx);
        clear_skb = NULL;
@@ -1598,6 +1613,9 @@ static int tls_decrypt_sg(struct sock *sk, struct iov_iter *out_iov,
                return err;
        }
 
+       if (unlikely(darg->async_done))
+               return 0;
+
        if (prot->tail_size)
                darg->tail = dctx->tail;
 
@@ -1769,7 +1787,8 @@ static int process_rx_list(struct tls_sw_context_rx *ctx,
                           u8 *control,
                           size_t skip,
                           size_t len,
-                          bool is_peek)
+                          bool is_peek,
+                          bool *more)
 {
        struct sk_buff *skb = skb_peek(&ctx->rx_list);
        struct tls_msg *tlm;
@@ -1782,7 +1801,7 @@ static int process_rx_list(struct tls_sw_context_rx *ctx,
 
                err = tls_record_content_type(msg, tlm, control);
                if (err <= 0)
-                       goto out;
+                       goto more;
 
                if (skip < rxm->full_len)
                        break;
@@ -1800,12 +1819,12 @@ static int process_rx_list(struct tls_sw_context_rx *ctx,
 
                err = tls_record_content_type(msg, tlm, control);
                if (err <= 0)
-                       goto out;
+                       goto more;
 
                err = skb_copy_datagram_msg(skb, rxm->offset + skip,
                                            msg, chunk);
                if (err < 0)
-                       goto out;
+                       goto more;
 
                len = len - chunk;
                copied = copied + chunk;
@@ -1841,6 +1860,10 @@ static int process_rx_list(struct tls_sw_context_rx *ctx,
 
 out:
        return copied ? : err;
+more:
+       if (more)
+               *more = true;
+       goto out;
 }
 
 static bool
@@ -1940,10 +1963,12 @@ int tls_sw_recvmsg(struct sock *sk,
        struct strp_msg *rxm;
        struct tls_msg *tlm;
        ssize_t copied = 0;
+       ssize_t peeked = 0;
        bool async = false;
        int target, err;
        bool is_kvec = iov_iter_is_kvec(&msg->msg_iter);
        bool is_peek = flags & MSG_PEEK;
+       bool rx_more = false;
        bool released = true;
        bool bpf_strp_enabled;
        bool zc_capable;
@@ -1963,12 +1988,12 @@ int tls_sw_recvmsg(struct sock *sk,
                goto end;
 
        /* Process pending decrypted records. It must be non-zero-copy */
-       err = process_rx_list(ctx, msg, &control, 0, len, is_peek);
+       err = process_rx_list(ctx, msg, &control, 0, len, is_peek, &rx_more);
        if (err < 0)
                goto end;
 
        copied = err;
-       if (len <= copied)
+       if (len <= copied || (copied && control != TLS_RECORD_TYPE_DATA) || rx_more)
                goto end;
 
        target = sock_rcvlowat(sk, flags & MSG_WAITALL, len);
@@ -2061,6 +2086,8 @@ put_on_rx_list:
                                decrypted += chunk;
                                len -= chunk;
                                __skb_queue_tail(&ctx->rx_list, skb);
+                               if (unlikely(control != TLS_RECORD_TYPE_DATA))
+                                       break;
                                continue;
                        }
 
@@ -2084,8 +2111,10 @@ put_on_rx_list:
                        if (err < 0)
                                goto put_on_rx_list_err;
 
-                       if (is_peek)
+                       if (is_peek) {
+                               peeked += chunk;
                                goto put_on_rx_list;
+                       }
 
                        if (partially_consumed) {
                                rxm->offset += chunk;
@@ -2109,16 +2138,10 @@ put_on_rx_list:
 
 recv_end:
        if (async) {
-               int ret, pending;
+               int ret;
 
                /* Wait for all previously submitted records to be decrypted */
-               spin_lock_bh(&ctx->decrypt_compl_lock);
-               reinit_completion(&ctx->async_wait.completion);
-               pending = atomic_read(&ctx->decrypt_pending);
-               spin_unlock_bh(&ctx->decrypt_compl_lock);
-               ret = 0;
-               if (pending)
-                       ret = crypto_wait_req(-EINPROGRESS, &ctx->async_wait);
+               ret = tls_decrypt_async_wait(ctx);
                __skb_queue_purge(&ctx->async_hold);
 
                if (ret) {
@@ -2130,12 +2153,11 @@ recv_end:
 
                /* Drain records from the rx_list & copy if required */
                if (is_peek || is_kvec)
-                       err = process_rx_list(ctx, msg, &control, copied,
-                                             decrypted, is_peek);
+                       err = process_rx_list(ctx, msg, &control, copied + peeked,
+                                             decrypted - peeked, is_peek, NULL);
                else
                        err = process_rx_list(ctx, msg, &control, 0,
-                                             async_copy_bytes, is_peek);
-               decrypted += max(err, 0);
+                                             async_copy_bytes, is_peek, NULL);
        }
 
        copied += decrypted;
@@ -2435,16 +2457,9 @@ void tls_sw_release_resources_tx(struct sock *sk)
        struct tls_context *tls_ctx = tls_get_ctx(sk);
        struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx);
        struct tls_rec *rec, *tmp;
-       int pending;
 
        /* Wait for any pending async encryptions to complete */
-       spin_lock_bh(&ctx->encrypt_compl_lock);
-       ctx->async_notify = true;
-       pending = atomic_read(&ctx->encrypt_pending);
-       spin_unlock_bh(&ctx->encrypt_compl_lock);
-
-       if (pending)
-               crypto_wait_req(-EINPROGRESS, &ctx->async_wait);
+       tls_encrypt_async_wait(ctx);
 
        tls_tx_records(sk, -1);
 
@@ -2607,7 +2622,7 @@ static struct tls_sw_context_tx *init_ctx_tx(struct tls_context *ctx, struct soc
        }
 
        crypto_init_wait(&sw_ctx_tx->async_wait);
-       spin_lock_init(&sw_ctx_tx->encrypt_compl_lock);
+       atomic_set(&sw_ctx_tx->encrypt_pending, 1);
        INIT_LIST_HEAD(&sw_ctx_tx->tx_list);
        INIT_DELAYED_WORK(&sw_ctx_tx->tx_work.work, tx_work_handler);
        sw_ctx_tx->tx_work.sk = sk;
@@ -2628,7 +2643,7 @@ static struct tls_sw_context_rx *init_ctx_rx(struct tls_context *ctx)
        }
 
        crypto_init_wait(&sw_ctx_rx->async_wait);
-       spin_lock_init(&sw_ctx_rx->decrypt_compl_lock);
+       atomic_set(&sw_ctx_rx->decrypt_pending, 1);
        init_waitqueue_head(&sw_ctx_rx->wq);
        skb_queue_head_init(&sw_ctx_rx->rx_list);
        skb_queue_head_init(&sw_ctx_rx->async_hold);
index 30b178ebba60aa810e8442a326a14edcee071061..0748e7ea5210e7d597acf87fc6caf1ea2156562e 100644 (file)
@@ -782,19 +782,6 @@ static int unix_seqpacket_sendmsg(struct socket *, struct msghdr *, size_t);
 static int unix_seqpacket_recvmsg(struct socket *, struct msghdr *, size_t,
                                  int);
 
-static int unix_set_peek_off(struct sock *sk, int val)
-{
-       struct unix_sock *u = unix_sk(sk);
-
-       if (mutex_lock_interruptible(&u->iolock))
-               return -EINTR;
-
-       WRITE_ONCE(sk->sk_peek_off, val);
-       mutex_unlock(&u->iolock);
-
-       return 0;
-}
-
 #ifdef CONFIG_PROC_FS
 static int unix_count_nr_fds(struct sock *sk)
 {
@@ -862,7 +849,7 @@ static const struct proto_ops unix_stream_ops = {
        .read_skb =     unix_stream_read_skb,
        .mmap =         sock_no_mmap,
        .splice_read =  unix_stream_splice_read,
-       .set_peek_off = unix_set_peek_off,
+       .set_peek_off = sk_set_peek_off,
        .show_fdinfo =  unix_show_fdinfo,
 };
 
@@ -886,7 +873,7 @@ static const struct proto_ops unix_dgram_ops = {
        .read_skb =     unix_read_skb,
        .recvmsg =      unix_dgram_recvmsg,
        .mmap =         sock_no_mmap,
-       .set_peek_off = unix_set_peek_off,
+       .set_peek_off = sk_set_peek_off,
        .show_fdinfo =  unix_show_fdinfo,
 };
 
@@ -909,7 +896,7 @@ static const struct proto_ops unix_seqpacket_ops = {
        .sendmsg =      unix_seqpacket_sendmsg,
        .recvmsg =      unix_seqpacket_recvmsg,
        .mmap =         sock_no_mmap,
-       .set_peek_off = unix_set_peek_off,
+       .set_peek_off = sk_set_peek_off,
        .show_fdinfo =  unix_show_fdinfo,
 };
 
index 8f63f0b4bf0129c4704919f8742a052566943b1e..2a81880dac7b7b464b5ae9443fa3b2863cd76471 100644 (file)
@@ -284,9 +284,17 @@ void unix_gc(void)
         * which are creating the cycle(s).
         */
        skb_queue_head_init(&hitlist);
-       list_for_each_entry(u, &gc_candidates, link)
+       list_for_each_entry(u, &gc_candidates, link) {
                scan_children(&u->sk, inc_inflight, &hitlist);
 
+#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
+               if (u->oob_skb) {
+                       kfree_skb(u->oob_skb);
+                       u->oob_skb = NULL;
+               }
+#endif
+       }
+
        /* not_cycle_list contains those sockets which do not make up a
         * cycle.  Restore these to the inflight list.
         */
@@ -314,17 +322,6 @@ void unix_gc(void)
        /* Here we are. Hitlist is filled. Die. */
        __skb_queue_purge(&hitlist);
 
-#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
-       list_for_each_entry_safe(u, next, &gc_candidates, link) {
-               struct sk_buff *skb = u->oob_skb;
-
-               if (skb) {
-                       u->oob_skb = NULL;
-                       kfree_skb(skb);
-               }
-       }
-#endif
-
        spin_lock(&unix_gc_lock);
 
        /* There could be io_uring registered files, just push them back to
index b09700400d09744ee1b0c990e46806264df25e3b..bd54a928bab4120134711f54e677cb1f60c4ba7b 100644 (file)
@@ -4197,6 +4197,8 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 
                if (ntype != NL80211_IFTYPE_MESH_POINT)
                        return -EINVAL;
+               if (otype != NL80211_IFTYPE_MESH_POINT)
+                       return -EINVAL;
                if (netif_running(dev))
                        return -EBUSY;
 
index 1eadfac03cc41d35709c001a77759a23f7dbdc39..b78c0e095e221fd775b9e1eafa4dd15485915079 100644 (file)
@@ -722,7 +722,8 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
                        memcpy(vaddr, buffer, len);
                        kunmap_local(vaddr);
 
-                       skb_add_rx_frag(skb, nr_frags, page, 0, len, 0);
+                       skb_add_rx_frag(skb, nr_frags, page, 0, len, PAGE_SIZE);
+                       refcount_add(PAGE_SIZE, &xs->sk.sk_wmem_alloc);
                }
 
                if (first_frag && desc->options & XDP_TX_METADATA) {
index 41533c631431493882a7fa427d393c4b6a753e74..e6da7e8495c9cfdc3e81eb408e444a39442a2c9b 100644 (file)
@@ -858,4 +858,5 @@ int xfrm_count_pfkey_enc_supported(void)
 }
 EXPORT_SYMBOL_GPL(xfrm_count_pfkey_enc_supported);
 
+MODULE_DESCRIPTION("XFRM Algorithm interface");
 MODULE_LICENSE("GPL");
index 3784534c918552dc2db6d84b4ba00e1337d63b74..653e51ae39648da177b84c82881932e9987eaa99 100644 (file)
@@ -407,7 +407,7 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
        struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
        struct net_device *dev = x->xso.dev;
 
-       if (!x->type_offload || x->encap)
+       if (!x->type_offload)
                return false;
 
        if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET ||
index 662c83beb345ed2037d146c976180b1b62c26794..e5722c95b8bb38c528cc518cdc3a05e08a338264 100644 (file)
@@ -704,9 +704,13 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
 {
        struct net *net = dev_net(skb_dst(skb)->dev);
        struct xfrm_state *x = skb_dst(skb)->xfrm;
+       int family;
        int err;
 
-       switch (x->outer_mode.family) {
+       family = (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) ? x->outer_mode.family
+               : skb_dst(skb)->ops->family;
+
+       switch (family) {
        case AF_INET:
                memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
                IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
index 1b7e75159727791ef5ed03299729711ed775a16e..da6ecc6b3e153db74765a500afe3b4a255fdba44 100644 (file)
@@ -2694,7 +2694,9 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
                        if (xfrm[i]->props.smark.v || xfrm[i]->props.smark.m)
                                mark = xfrm_smark_get(fl->flowi_mark, xfrm[i]);
 
-                       family = xfrm[i]->props.family;
+                       if (xfrm[i]->xso.type != XFRM_DEV_OFFLOAD_PACKET)
+                               family = xfrm[i]->props.family;
+
                        oif = fl->flowi_oif ? : fl->flowi_l3mdev;
                        dst = xfrm_dst_lookup(xfrm[i], tos, oif,
                                              &saddr, &daddr, family, mark);
@@ -3416,7 +3418,7 @@ decode_session4(const struct xfrm_flow_keys *flkeys, struct flowi *fl, bool reve
        }
 
        fl4->flowi4_proto = flkeys->basic.ip_proto;
-       fl4->flowi4_tos = flkeys->ip.tos;
+       fl4->flowi4_tos = flkeys->ip.tos & ~INET_ECN_MASK;
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
index ad01997c3aa9dd851a3fa4ad6dd6c877eaaddd36..912c1189ba41c1cdca51f0212f7ea1ae293f9370 100644 (file)
@@ -2017,6 +2017,9 @@ static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb)
        if (xp->xfrm_nr == 0)
                return 0;
 
+       if (xp->xfrm_nr > XFRM_MAX_DEPTH)
+               return -ENOBUFS;
+
        for (i = 0; i < xp->xfrm_nr; i++) {
                struct xfrm_user_tmpl *up = &vec[i];
                struct xfrm_tmpl *kp = &xp->xfrm_vec[i];
@@ -3888,5 +3891,6 @@ static void __exit xfrm_user_exit(void)
 
 module_init(xfrm_user_init);
 module_exit(xfrm_user_exit);
+MODULE_DESCRIPTION("XFRM User interface");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);
index 9d2a16cc91cb44f8f8836b3e45f4ad30c13b9c22..a78fcf4004b02ab752af3e2012afb47b306a4b67 100644 (file)
@@ -40,7 +40,7 @@ obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o
 ifdef CONFIG_RUST
 
 # `$(rust_flags)` is passed in case the user added `--sysroot`.
-rustc_sysroot := $(shell $(RUSTC) $(rust_flags) --print sysroot)
+rustc_sysroot := $(shell MAKEFLAGS= $(RUSTC) $(rust_flags) --print sysroot)
 rustc_host_target := $(shell $(RUSTC) --version --verbose | grep -F 'host: ' | cut -d' ' -f2)
 RUST_LIB_SRC ?= $(rustc_sysroot)/lib/rustlib/src/rust/library
 
@@ -108,14 +108,14 @@ rustdoc-macros: private rustdoc_host = yes
 rustdoc-macros: private rustc_target_flags = --crate-type proc-macro \
     --extern proc_macro
 rustdoc-macros: $(src)/macros/lib.rs FORCE
-       $(call if_changed,rustdoc)
+       +$(call if_changed,rustdoc)
 
 rustdoc-core: private rustc_target_flags = $(core-cfgs)
 rustdoc-core: $(RUST_LIB_SRC)/core/src/lib.rs FORCE
-       $(call if_changed,rustdoc)
+       +$(call if_changed,rustdoc)
 
 rustdoc-compiler_builtins: $(src)/compiler_builtins.rs rustdoc-core FORCE
-       $(call if_changed,rustdoc)
+       +$(call if_changed,rustdoc)
 
 # We need to allow `rustdoc::broken_intra_doc_links` because some
 # `no_global_oom_handling` functions refer to non-`no_global_oom_handling`
@@ -124,7 +124,7 @@ rustdoc-compiler_builtins: $(src)/compiler_builtins.rs rustdoc-core FORCE
 rustdoc-alloc: private rustc_target_flags = $(alloc-cfgs) \
     -Arustdoc::broken_intra_doc_links
 rustdoc-alloc: $(src)/alloc/lib.rs rustdoc-core rustdoc-compiler_builtins FORCE
-       $(call if_changed,rustdoc)
+       +$(call if_changed,rustdoc)
 
 rustdoc-kernel: private rustc_target_flags = --extern alloc \
     --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \
@@ -132,7 +132,7 @@ rustdoc-kernel: private rustc_target_flags = --extern alloc \
 rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \
     rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \
     $(obj)/bindings.o FORCE
-       $(call if_changed,rustdoc)
+       +$(call if_changed,rustdoc)
 
 quiet_cmd_rustc_test_library = RUSTC TL $<
       cmd_rustc_test_library = \
@@ -146,18 +146,18 @@ quiet_cmd_rustc_test_library = RUSTC TL $<
                --crate-name $(subst rusttest-,,$(subst rusttestlib-,,$@)) $<
 
 rusttestlib-build_error: $(src)/build_error.rs rusttest-prepare FORCE
-       $(call if_changed,rustc_test_library)
+       +$(call if_changed,rustc_test_library)
 
 rusttestlib-macros: private rustc_target_flags = --extern proc_macro
 rusttestlib-macros: private rustc_test_library_proc = yes
 rusttestlib-macros: $(src)/macros/lib.rs rusttest-prepare FORCE
-       $(call if_changed,rustc_test_library)
+       +$(call if_changed,rustc_test_library)
 
 rusttestlib-bindings: $(src)/bindings/lib.rs rusttest-prepare FORCE
-       $(call if_changed,rustc_test_library)
+       +$(call if_changed,rustc_test_library)
 
 rusttestlib-uapi: $(src)/uapi/lib.rs rusttest-prepare FORCE
-       $(call if_changed,rustc_test_library)
+       +$(call if_changed,rustc_test_library)
 
 quiet_cmd_rustdoc_test = RUSTDOC T $<
       cmd_rustdoc_test = \
@@ -189,7 +189,7 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
     $(src)/kernel/lib.rs $(obj)/kernel.o \
     $(objtree)/scripts/rustdoc_test_builder \
     $(objtree)/scripts/rustdoc_test_gen FORCE
-       $(call if_changed,rustdoc_test_kernel)
+       +$(call if_changed,rustdoc_test_kernel)
 
 # We cannot use `-Zpanic-abort-tests` because some tests are dynamic,
 # so for the moment we skip `-Cpanic=abort`.
@@ -254,21 +254,21 @@ quiet_cmd_rustsysroot = RUSTSYSROOT
                $(objtree)/$(obj)/test/sysroot/lib/rustlib/$(rustc_host_target)/lib
 
 rusttest-prepare: FORCE
-       $(call if_changed,rustsysroot)
+       +$(call if_changed,rustsysroot)
 
 rusttest-macros: private rustc_target_flags = --extern proc_macro
 rusttest-macros: private rustdoc_test_target_flags = --crate-type proc-macro
 rusttest-macros: $(src)/macros/lib.rs rusttest-prepare FORCE
-       $(call if_changed,rustc_test)
-       $(call if_changed,rustdoc_test)
+       +$(call if_changed,rustc_test)
+       +$(call if_changed,rustdoc_test)
 
 rusttest-kernel: private rustc_target_flags = --extern alloc \
     --extern build_error --extern macros --extern bindings --extern uapi
 rusttest-kernel: $(src)/kernel/lib.rs rusttest-prepare \
     rusttestlib-build_error rusttestlib-macros rusttestlib-bindings \
     rusttestlib-uapi FORCE
-       $(call if_changed,rustc_test)
-       $(call if_changed,rustc_test_library)
+       +$(call if_changed,rustc_test)
+       +$(call if_changed,rustc_test_library)
 
 ifdef CONFIG_CC_IS_CLANG
 bindgen_c_flags = $(c_flags)
@@ -396,7 +396,7 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
 # Therefore, to get `libmacros.so` automatically recompiled when the compiler
 # version changes, we add `core.o` as a dependency (even if it is not needed).
 $(obj)/libmacros.so: $(src)/macros/lib.rs $(obj)/core.o FORCE
-       $(call if_changed_dep,rustc_procmacro)
+       +$(call if_changed_dep,rustc_procmacro)
 
 quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@
       cmd_rustc_library = \
@@ -435,36 +435,36 @@ $(obj)/core.o: private skip_flags = -Dunreachable_pub
 $(obj)/core.o: private rustc_objcopy = $(foreach sym,$(redirect-intrinsics),--redefine-sym $(sym)=__rust$(sym))
 $(obj)/core.o: private rustc_target_flags = $(core-cfgs)
 $(obj)/core.o: $(RUST_LIB_SRC)/core/src/lib.rs scripts/target.json FORCE
-       $(call if_changed_dep,rustc_library)
+       +$(call if_changed_dep,rustc_library)
 
 $(obj)/compiler_builtins.o: private rustc_objcopy = -w -W '__*'
 $(obj)/compiler_builtins.o: $(src)/compiler_builtins.rs $(obj)/core.o FORCE
-       $(call if_changed_dep,rustc_library)
+       +$(call if_changed_dep,rustc_library)
 
 $(obj)/alloc.o: private skip_clippy = 1
 $(obj)/alloc.o: private skip_flags = -Dunreachable_pub
 $(obj)/alloc.o: private rustc_target_flags = $(alloc-cfgs)
 $(obj)/alloc.o: $(src)/alloc/lib.rs $(obj)/compiler_builtins.o FORCE
-       $(call if_changed_dep,rustc_library)
+       +$(call if_changed_dep,rustc_library)
 
 $(obj)/build_error.o: $(src)/build_error.rs $(obj)/compiler_builtins.o FORCE
-       $(call if_changed_dep,rustc_library)
+       +$(call if_changed_dep,rustc_library)
 
 $(obj)/bindings.o: $(src)/bindings/lib.rs \
     $(obj)/compiler_builtins.o \
     $(obj)/bindings/bindings_generated.rs \
     $(obj)/bindings/bindings_helpers_generated.rs FORCE
-       $(call if_changed_dep,rustc_library)
+       +$(call if_changed_dep,rustc_library)
 
 $(obj)/uapi.o: $(src)/uapi/lib.rs \
     $(obj)/compiler_builtins.o \
     $(obj)/uapi/uapi_generated.rs FORCE
-       $(call if_changed_dep,rustc_library)
+       +$(call if_changed_dep,rustc_library)
 
 $(obj)/kernel.o: private rustc_target_flags = --extern alloc \
     --extern build_error --extern macros --extern bindings --extern uapi
 $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \
     $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE
-       $(call if_changed_dep,rustc_library)
+       +$(call if_changed_dep,rustc_library)
 
 endif # CONFIG_RUST
index 150e13750ff70eab5fa75e8f5e0a843d665d64d7..abb791cc23715a8b9678ea93ac6f6f937ef9c3d9 100644 (file)
@@ -379,13 +379,20 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
         panic!("allocation failed");
     }
 
+    #[inline]
     fn rt_error(layout: Layout) -> ! {
         unsafe {
             __rust_alloc_error_handler(layout.size(), layout.align());
         }
     }
 
-    unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) }
+    #[cfg(not(feature = "panic_immediate_abort"))]
+    unsafe {
+        core::intrinsics::const_eval_select((layout,), ct_error, rt_error)
+    }
+
+    #[cfg(feature = "panic_immediate_abort")]
+    ct_error(layout)
 }
 
 // For alloc test `std::alloc::handle_alloc_error` can be used directly.
@@ -418,12 +425,14 @@ pub mod __alloc_error_handler {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 /// Specialize clones into pre-allocated, uninitialized memory.
 /// Used by `Box::clone` and `Rc`/`Arc::make_mut`.
 pub(crate) trait WriteCloneIntoRaw: Sized {
     unsafe fn write_clone_into_raw(&self, target: *mut Self);
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T: Clone> WriteCloneIntoRaw for T {
     #[inline]
     default unsafe fn write_clone_into_raw(&self, target: *mut Self) {
@@ -433,6 +442,7 @@ impl<T: Clone> WriteCloneIntoRaw for T {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T: Copy> WriteCloneIntoRaw for T {
     #[inline]
     unsafe fn write_clone_into_raw(&self, target: *mut Self) {
index 9620eba17268724d08e0b374397336d3476f6fcf..c93a22a5c97f14fc2d37d277533ec497807f7c79 100644 (file)
@@ -161,7 +161,7 @@ use core::marker::Tuple;
 use core::marker::Unsize;
 use core::mem::{self, SizedTypeProperties};
 use core::ops::{
-    CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Generator, GeneratorState, Receiver,
+    CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, DispatchFromDyn, Receiver,
 };
 use core::pin::Pin;
 use core::ptr::{self, NonNull, Unique};
@@ -211,7 +211,7 @@ impl<T> Box<T> {
     /// ```
     /// let five = Box::new(5);
     /// ```
-    #[cfg(all(not(no_global_oom_handling)))]
+    #[cfg(not(no_global_oom_handling))]
     #[inline(always)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
@@ -1042,10 +1042,18 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// use std::ptr;
     ///
     /// let x = Box::new(String::from("Hello"));
-    /// let p = Box::into_raw(x);
+    /// let ptr = Box::into_raw(x);
     /// unsafe {
-    ///     ptr::drop_in_place(p);
-    ///     dealloc(p as *mut u8, Layout::new::<String>());
+    ///     ptr::drop_in_place(ptr);
+    ///     dealloc(ptr as *mut u8, Layout::new::<String>());
+    /// }
+    /// ```
+    /// Note: This is equivalent to the following:
+    /// ```
+    /// let x = Box::new(String::from("Hello"));
+    /// let ptr = Box::into_raw(x);
+    /// unsafe {
+    ///     drop(Box::from_raw(ptr));
     /// }
     /// ```
     ///
@@ -2110,28 +2118,28 @@ impl<T: ?Sized, A: Allocator> AsMut<T> for Box<T, A> {
 #[stable(feature = "pin", since = "1.33.0")]
 impl<T: ?Sized, A: Allocator> Unpin for Box<T, A> where A: 'static {}
 
-#[unstable(feature = "generator_trait", issue = "43122")]
-impl<G: ?Sized + Generator<R> + Unpin, R, A: Allocator> Generator<R> for Box<G, A>
+#[unstable(feature = "coroutine_trait", issue = "43122")]
+impl<G: ?Sized + Coroutine<R> + Unpin, R, A: Allocator> Coroutine<R> for Box<G, A>
 where
     A: 'static,
 {
     type Yield = G::Yield;
     type Return = G::Return;
 
-    fn resume(mut self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return> {
+    fn resume(mut self: Pin<&mut Self>, arg: R) -> CoroutineState<Self::Yield, Self::Return> {
         G::resume(Pin::new(&mut *self), arg)
     }
 }
 
-#[unstable(feature = "generator_trait", issue = "43122")]
-impl<G: ?Sized + Generator<R>, R, A: Allocator> Generator<R> for Pin<Box<G, A>>
+#[unstable(feature = "coroutine_trait", issue = "43122")]
+impl<G: ?Sized + Coroutine<R>, R, A: Allocator> Coroutine<R> for Pin<Box<G, A>>
 where
     A: 'static,
 {
     type Yield = G::Yield;
     type Return = G::Return;
 
-    fn resume(mut self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return> {
+    fn resume(mut self: Pin<&mut Self>, arg: R) -> CoroutineState<Self::Yield, Self::Return> {
         G::resume((*self).as_mut(), arg)
     }
 }
@@ -2448,4 +2456,8 @@ impl<T: core::error::Error> core::error::Error for Box<T> {
     fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
         core::error::Error::source(&**self)
     }
+
+    fn provide<'b>(&'b self, request: &mut core::error::Request<'b>) {
+        core::error::Error::provide(&**self, request);
+    }
 }
index 2506065d158a95cd10041b571b9d15b99315bed6..00ffb3b973658cf904d77495ffb0f3b28881b42b 100644 (file)
@@ -150,6 +150,7 @@ impl Display for TryReserveError {
 
 /// An intermediate trait for specialization of `Extend`.
 #[doc(hidden)]
+#[cfg(not(no_global_oom_handling))]
 trait SpecExtend<I: IntoIterator> {
     /// Extends `self` with the contents of the given iterator.
     fn spec_extend(&mut self, iter: I);
index 9c7ea73da108008ef47cafcaa2dfa2af79150a5e..36f79c0755933865cfddf9538918e5df84598d12 100644 (file)
@@ -80,6 +80,8 @@
     not(no_sync),
     target_has_atomic = "ptr"
 ))]
+#![doc(rust_logo)]
+#![feature(rustdoc_internals)]
 #![no_std]
 #![needs_allocator]
 // Lints:
 #![feature(const_eval_select)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_maybe_uninit_write)]
-#![feature(const_maybe_uninit_zeroed)]
 #![feature(const_pin)]
 #![feature(const_refs_to_cell)]
 #![feature(const_size_of_val)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_uninit_array_transpose)]
 #![feature(pattern)]
-#![feature(pointer_byte_offsets)]
 #![feature(ptr_internals)]
 #![feature(ptr_metadata)]
 #![feature(ptr_sub_ptr)]
 #![feature(std_internals)]
 #![feature(str_internals)]
 #![feature(strict_provenance)]
+#![feature(trusted_fused)]
 #![feature(trusted_len)]
 #![feature(trusted_random_access)]
 #![feature(try_trait_v2)]
 //
 // Language features:
 // tidy-alphabetical-start
-#![cfg_attr(not(test), feature(generator_trait))]
+#![cfg_attr(not(test), feature(coroutine_trait))]
 #![cfg_attr(test, feature(panic_update_hook))]
 #![cfg_attr(test, feature(test))]
 #![feature(allocator_internals)]
@@ -276,7 +277,7 @@ pub(crate) mod test_helpers {
     /// seed not being the same for every RNG invocation too.
     pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
         use std::hash::{BuildHasher, Hash, Hasher};
-        let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
+        let mut hasher = std::hash::RandomState::new().build_hasher();
         std::panic::Location::caller().hash(&mut hasher);
         let hc64 = hasher.finish();
         let seed_vec =
index a7425582a323f1c75aceb90572d16afd51b50d4a..98b6abf30af6e40338826a51d0d21c956440fd2b 100644 (file)
@@ -27,6 +27,16 @@ enum AllocInit {
     Zeroed,
 }
 
+#[repr(transparent)]
+#[cfg_attr(target_pointer_width = "16", rustc_layout_scalar_valid_range_end(0x7fff))]
+#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0x7fff_ffff))]
+#[cfg_attr(target_pointer_width = "64", rustc_layout_scalar_valid_range_end(0x7fff_ffff_ffff_ffff))]
+struct Cap(usize);
+
+impl Cap {
+    const ZERO: Cap = unsafe { Cap(0) };
+}
+
 /// A low-level utility for more ergonomically allocating, reallocating, and deallocating
 /// a buffer of memory on the heap without having to worry about all the corner cases
 /// involved. This type is excellent for building your own data structures like Vec and VecDeque.
@@ -52,7 +62,12 @@ enum AllocInit {
 #[allow(missing_debug_implementations)]
 pub(crate) struct RawVec<T, A: Allocator = Global> {
     ptr: Unique<T>,
-    cap: usize,
+    /// Never used for ZSTs; it's `capacity()`'s responsibility to return usize::MAX in that case.
+    ///
+    /// # Safety
+    ///
+    /// `cap` must be in the `0..=isize::MAX` range.
+    cap: Cap,
     alloc: A,
 }
 
@@ -121,7 +136,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// the returned `RawVec`.
     pub const fn new_in(alloc: A) -> Self {
         // `cap: 0` means "unallocated". zero-sized types are ignored.
-        Self { ptr: Unique::dangling(), cap: 0, alloc }
+        Self { ptr: Unique::dangling(), cap: Cap::ZERO, alloc }
     }
 
     /// Like `with_capacity`, but parameterized over the choice of
@@ -203,7 +218,7 @@ impl<T, A: Allocator> RawVec<T, A> {
             // here should change to `ptr.len() / mem::size_of::<T>()`.
             Self {
                 ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) },
-                cap: capacity,
+                cap: unsafe { Cap(capacity) },
                 alloc,
             }
         }
@@ -228,7 +243,7 @@ impl<T, A: Allocator> RawVec<T, A> {
         // here should change to `ptr.len() / mem::size_of::<T>()`.
         Ok(Self {
             ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) },
-            cap: capacity,
+            cap: unsafe { Cap(capacity) },
             alloc,
         })
     }
@@ -240,12 +255,13 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given
     /// `capacity`.
     /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit
-    /// systems). ZST vectors may have a capacity up to `usize::MAX`.
+    /// systems). For ZSTs capacity is ignored.
     /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is
     /// guaranteed.
     #[inline]
     pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self {
-        Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc }
+        let cap = if T::IS_ZST { Cap::ZERO } else { unsafe { Cap(capacity) } };
+        Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap, alloc }
     }
 
     /// Gets a raw pointer to the start of the allocation. Note that this is
@@ -261,7 +277,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// This will always be `usize::MAX` if `T` is zero-sized.
     #[inline(always)]
     pub fn capacity(&self) -> usize {
-        if T::IS_ZST { usize::MAX } else { self.cap }
+        if T::IS_ZST { usize::MAX } else { self.cap.0 }
     }
 
     /// Returns a shared reference to the allocator backing this `RawVec`.
@@ -270,7 +286,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     }
 
     fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
-        if T::IS_ZST || self.cap == 0 {
+        if T::IS_ZST || self.cap.0 == 0 {
             None
         } else {
             // We could use Layout::array here which ensures the absence of isize and usize overflows
@@ -280,7 +296,7 @@ impl<T, A: Allocator> RawVec<T, A> {
             let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
             unsafe {
                 let align = mem::align_of::<T>();
-                let size = mem::size_of::<T>().unchecked_mul(self.cap);
+                let size = mem::size_of::<T>().unchecked_mul(self.cap.0);
                 let layout = Layout::from_size_align_unchecked(size, align);
                 Some((self.ptr.cast().into(), layout))
             }
@@ -338,10 +354,13 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// The same as `reserve`, but returns on errors instead of panicking or aborting.
     pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
         if self.needs_to_grow(len, additional) {
-            self.grow_amortized(len, additional)
-        } else {
-            Ok(())
+            self.grow_amortized(len, additional)?;
         }
+        unsafe {
+            // Inform the optimizer that the reservation has succeeded or wasn't needed
+            core::intrinsics::assume(!self.needs_to_grow(len, additional));
+        }
+        Ok(())
     }
 
     /// The same as `reserve_for_push`, but returns on errors instead of panicking or aborting.
@@ -378,7 +397,14 @@ impl<T, A: Allocator> RawVec<T, A> {
         len: usize,
         additional: usize,
     ) -> Result<(), TryReserveError> {
-        if self.needs_to_grow(len, additional) { self.grow_exact(len, additional) } else { Ok(()) }
+        if self.needs_to_grow(len, additional) {
+            self.grow_exact(len, additional)?;
+        }
+        unsafe {
+            // Inform the optimizer that the reservation has succeeded or wasn't needed
+            core::intrinsics::assume(!self.needs_to_grow(len, additional));
+        }
+        Ok(())
     }
 
     /// Shrinks the buffer down to the specified capacity. If the given amount
@@ -404,12 +430,15 @@ impl<T, A: Allocator> RawVec<T, A> {
         additional > self.capacity().wrapping_sub(len)
     }
 
-    fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) {
+    /// # Safety:
+    ///
+    /// `cap` must not exceed `isize::MAX`.
+    unsafe fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) {
         // Allocators currently return a `NonNull<[u8]>` whose length matches
         // the size requested. If that ever changes, the capacity here should
         // change to `ptr.len() / mem::size_of::<T>()`.
         self.ptr = unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) };
-        self.cap = cap;
+        self.cap = unsafe { Cap(cap) };
     }
 
     // This method is usually instantiated many times. So we want it to be as
@@ -434,14 +463,15 @@ impl<T, A: Allocator> RawVec<T, A> {
 
         // This guarantees exponential growth. The doubling cannot overflow
         // because `cap <= isize::MAX` and the type of `cap` is `usize`.
-        let cap = cmp::max(self.cap * 2, required_cap);
+        let cap = cmp::max(self.cap.0 * 2, required_cap);
         let cap = cmp::max(Self::MIN_NON_ZERO_CAP, cap);
 
         let new_layout = Layout::array::<T>(cap);
 
         // `finish_grow` is non-generic over `T`.
         let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
-        self.set_ptr_and_cap(ptr, cap);
+        // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than isize::MAX items
+        unsafe { self.set_ptr_and_cap(ptr, cap) };
         Ok(())
     }
 
@@ -460,7 +490,10 @@ impl<T, A: Allocator> RawVec<T, A> {
 
         // `finish_grow` is non-generic over `T`.
         let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
-        self.set_ptr_and_cap(ptr, cap);
+        // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than isize::MAX items
+        unsafe {
+            self.set_ptr_and_cap(ptr, cap);
+        }
         Ok(())
     }
 
@@ -478,7 +511,7 @@ impl<T, A: Allocator> RawVec<T, A> {
         if cap == 0 {
             unsafe { self.alloc.deallocate(ptr, layout) };
             self.ptr = Unique::dangling();
-            self.cap = 0;
+            self.cap = Cap::ZERO;
         } else {
             let ptr = unsafe {
                 // `Layout::array` cannot overflow here because it would have
@@ -489,7 +522,10 @@ impl<T, A: Allocator> RawVec<T, A> {
                     .shrink(ptr, layout, new_layout)
                     .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
             };
-            self.set_ptr_and_cap(ptr, cap);
+            // SAFETY: if the allocation is valid, then the capacity is too
+            unsafe {
+                self.set_ptr_and_cap(ptr, cap);
+            }
         }
         Ok(())
     }
@@ -569,6 +605,7 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
 // ensure that the code generation related to these panics is minimal as there's
 // only one location which panics rather than a bunch throughout the module.
 #[cfg(not(no_global_oom_handling))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 fn capacity_overflow() -> ! {
     panic!("capacity overflow");
 }
index aac0ec16aef15d14f98cf9905f57355f1645ae5d..136bfe94af6c837add1a62e70306f23ee1644d82 100644 (file)
@@ -9,7 +9,8 @@ use crate::raw_vec::RawVec;
 use core::array;
 use core::fmt;
 use core::iter::{
-    FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
+    FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen,
+    TrustedRandomAccessNoCoerce,
 };
 use core::marker::PhantomData;
 use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
@@ -287,9 +288,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
         // Also note the implementation of `Self: TrustedRandomAccess` requires
         // that `T: Copy` so reading elements from the buffer doesn't invalidate
         // them for `Drop`.
-        unsafe {
-            if T::IS_ZST { mem::zeroed() } else { ptr::read(self.ptr.add(i)) }
-        }
+        unsafe { if T::IS_ZST { mem::zeroed() } else { ptr::read(self.ptr.add(i)) } }
     }
 }
 
@@ -341,6 +340,10 @@ impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {
 #[stable(feature = "fused", since = "1.26.0")]
 impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
 
+#[doc(hidden)]
+#[unstable(issue = "none", feature = "trusted_fused")]
+unsafe impl<T, A: Allocator> TrustedFused for IntoIter<T, A> {}
+
 #[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {}
 
@@ -425,7 +428,10 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> {
 // also refer to the vec::in_place_collect module documentation to get an overview
 #[unstable(issue = "none", feature = "inplace_iteration")]
 #[doc(hidden)]
-unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {}
+unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {
+    const EXPAND_BY: Option<NonZeroUsize> = NonZeroUsize::new(1);
+    const MERGE_BY: Option<NonZeroUsize> = NonZeroUsize::new(1);
+}
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 #[doc(hidden)]
index 41ca71805ef09e92f0c629d21c384887cd975b78..220fb9d6f45b3f2d12fdce0a55e878c80a6dd94a 100644 (file)
@@ -105,6 +105,7 @@ mod into_iter;
 #[cfg(not(no_global_oom_handling))]
 use self::is_zero::IsZero;
 
+#[cfg(not(no_global_oom_handling))]
 mod is_zero;
 
 #[cfg(not(no_global_oom_handling))]
@@ -123,7 +124,7 @@ use self::set_len_on_drop::SetLenOnDrop;
 mod set_len_on_drop;
 
 #[cfg(not(no_global_oom_handling))]
-use self::in_place_drop::{InPlaceDrop, InPlaceDstBufDrop};
+use self::in_place_drop::{InPlaceDrop, InPlaceDstDataSrcBufDrop};
 
 #[cfg(not(no_global_oom_handling))]
 mod in_place_drop;
@@ -1376,7 +1377,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// [`as_mut_ptr`]: Vec::as_mut_ptr
     /// [`as_ptr`]: Vec::as_ptr
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
-    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
+    #[rustc_never_returns_null_ptr]
     #[inline]
     pub fn as_ptr(&self) -> *const T {
         // We shadow the slice method of the same name to avoid going through
@@ -1436,7 +1437,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// [`as_mut_ptr`]: Vec::as_mut_ptr
     /// [`as_ptr`]: Vec::as_ptr
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
-    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
+    #[rustc_never_returns_null_ptr]
     #[inline]
     pub fn as_mut_ptr(&mut self) -> *mut T {
         // We shadow the slice method of the same name to avoid going through
@@ -1565,7 +1566,8 @@ impl<T, A: Allocator> Vec<T, A> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn swap_remove(&mut self, index: usize) -> T {
         #[cold]
-        #[inline(never)]
+        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+        #[track_caller]
         fn assert_failed(index: usize, len: usize) -> ! {
             panic!("swap_remove index (is {index}) should be < len (is {len})");
         }
@@ -1606,7 +1608,8 @@ impl<T, A: Allocator> Vec<T, A> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, index: usize, element: T) {
         #[cold]
-        #[inline(never)]
+        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+        #[track_caller]
         fn assert_failed(index: usize, len: usize) -> ! {
             panic!("insertion index (is {index}) should be <= len (is {len})");
         }
@@ -1667,7 +1670,7 @@ impl<T, A: Allocator> Vec<T, A> {
     #[track_caller]
     pub fn remove(&mut self, index: usize) -> T {
         #[cold]
-        #[inline(never)]
+        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
         #[track_caller]
         fn assert_failed(index: usize, len: usize) -> ! {
             panic!("removal index (is {index}) should be < len (is {len})");
@@ -1891,7 +1894,32 @@ impl<T, A: Allocator> Vec<T, A> {
             return;
         }
 
-        /* INVARIANT: vec.len() > read >= write > write-1 >= 0 */
+        // Check if we ever want to remove anything.
+        // This allows to use copy_non_overlapping in next cycle.
+        // And avoids any memory writes if we don't need to remove anything.
+        let mut first_duplicate_idx: usize = 1;
+        let start = self.as_mut_ptr();
+        while first_duplicate_idx != len {
+            let found_duplicate = unsafe {
+                // SAFETY: first_duplicate always in range [1..len)
+                // Note that we start iteration from 1 so we never overflow.
+                let prev = start.add(first_duplicate_idx.wrapping_sub(1));
+                let current = start.add(first_duplicate_idx);
+                // We explicitly say in docs that references are reversed.
+                same_bucket(&mut *current, &mut *prev)
+            };
+            if found_duplicate {
+                break;
+            }
+            first_duplicate_idx += 1;
+        }
+        // Don't need to remove anything.
+        // We cannot get bigger than len.
+        if first_duplicate_idx == len {
+            return;
+        }
+
+        /* INVARIANT: vec.len() > read > write > write-1 >= 0 */
         struct FillGapOnDrop<'a, T, A: core::alloc::Allocator> {
             /* Offset of the element we want to check if it is duplicate */
             read: usize,
@@ -1937,31 +1965,39 @@ impl<T, A: Allocator> Vec<T, A> {
             }
         }
 
-        let mut gap = FillGapOnDrop { read: 1, write: 1, vec: self };
-        let ptr = gap.vec.as_mut_ptr();
-
         /* Drop items while going through Vec, it should be more efficient than
          * doing slice partition_dedup + truncate */
 
+        // Construct gap first and then drop item to avoid memory corruption if `T::drop` panics.
+        let mut gap =
+            FillGapOnDrop { read: first_duplicate_idx + 1, write: first_duplicate_idx, vec: self };
+        unsafe {
+            // SAFETY: we checked that first_duplicate_idx in bounds before.
+            // If drop panics, `gap` would remove this item without drop.
+            ptr::drop_in_place(start.add(first_duplicate_idx));
+        }
+
         /* SAFETY: Because of the invariant, read_ptr, prev_ptr and write_ptr
          * are always in-bounds and read_ptr never aliases prev_ptr */
         unsafe {
             while gap.read < len {
-                let read_ptr = ptr.add(gap.read);
-                let prev_ptr = ptr.add(gap.write.wrapping_sub(1));
+                let read_ptr = start.add(gap.read);
+                let prev_ptr = start.add(gap.write.wrapping_sub(1));
 
-                if same_bucket(&mut *read_ptr, &mut *prev_ptr) {
+                // We explicitly say in docs that references are reversed.
+                let found_duplicate = same_bucket(&mut *read_ptr, &mut *prev_ptr);
+                if found_duplicate {
                     // Increase `gap.read` now since the drop may panic.
                     gap.read += 1;
                     /* We have found duplicate, drop it in-place */
                     ptr::drop_in_place(read_ptr);
                 } else {
-                    let write_ptr = ptr.add(gap.write);
+                    let write_ptr = start.add(gap.write);
 
-                    /* Because `read_ptr` can be equal to `write_ptr`, we either
-                     * have to use `copy` or conditional `copy_nonoverlapping`.
-                     * Looks like the first option is faster. */
-                    ptr::copy(read_ptr, write_ptr, 1);
+                    /* read_ptr cannot be equal to write_ptr because at this point
+                     * we guaranteed to skip at least one element (before loop starts).
+                     */
+                    ptr::copy_nonoverlapping(read_ptr, write_ptr, 1);
 
                     /* We have filled that place, so go further */
                     gap.write += 1;
@@ -2097,6 +2133,7 @@ impl<T, A: Allocator> Vec<T, A> {
         } else {
             unsafe {
                 self.len -= 1;
+                core::intrinsics::assume(self.len < self.capacity());
                 Some(ptr::read(self.as_ptr().add(self.len())))
             }
         }
@@ -2299,7 +2336,8 @@ impl<T, A: Allocator> Vec<T, A> {
         A: Clone,
     {
         #[cold]
-        #[inline(never)]
+        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+        #[track_caller]
         fn assert_failed(at: usize, len: usize) -> ! {
             panic!("`at` split index (is {at}) should be <= len (is {len})");
         }
@@ -2840,6 +2878,7 @@ pub fn from_elem_in<T: Clone, A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<
     <T as SpecFromElem>::from_elem(elem, n, alloc)
 }
 
+#[cfg(not(no_global_oom_handling))]
 trait ExtendFromWithinSpec {
     /// # Safety
     ///
@@ -2848,6 +2887,7 @@ trait ExtendFromWithinSpec {
     unsafe fn spec_extend_from_within(&mut self, src: Range<usize>);
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T: Clone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
     default unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
         // SAFETY:
@@ -2867,6 +2907,7 @@ impl<T: Clone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
     unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
         let count = src.len();
@@ -2947,7 +2988,7 @@ impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
 /// ```
 /// use std::hash::BuildHasher;
 ///
-/// let b = std::collections::hash_map::RandomState::new();
+/// let b = std::hash::RandomState::new();
 /// let v: Vec<u8> = vec![0xa8, 0x3c, 0x09];
 /// let s: &[u8] = &[0xa8, 0x3c, 0x09];
 /// assert_eq!(b.hash_one(v), b.hash_one(s));
index c0cb4b05b9185be0671138cf7cc5c510c02d90f3..65b98831b975602bf32a6947f175b0d4c0a0e50f 100644 (file)
@@ -9,12 +9,13 @@
 #include <kunit/test.h>
 #include <linux/errname.h>
 #include <linux/ethtool.h>
+#include <linux/jiffies.h>
 #include <linux/mdio.h>
 #include <linux/phy.h>
-#include <linux/slab.h>
 #include <linux/refcount.h>
-#include <linux/wait.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
 #include <linux/workqueue.h>
 
 /* `bindgen` gets confused at certain things. */
index 4b057e837358c0d040211aea530f2c6fe240f71d..01ad139e19bc096466dd984462dd7959316ef0bf 100644 (file)
@@ -35,7 +35,7 @@ unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: bindings::gf
     // - `ptr` is either null or a pointer returned from a previous `k{re}alloc()` by the
     //   function safety requirement.
     // - `size` is greater than 0 since it's either a `layout.size()` (which cannot be zero
-    //    according to the function safety requirement) or a result from `next_power_of_two()`.
+    //   according to the function safety requirement) or a result from `next_power_of_two()`.
     unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags) as *mut u8 }
 }
 
index 4f0c1edd63b7a8661151fd0dd742b9e6754d1aa5..4786d3ee1e92917c4f69f009770063e10dbaca02 100644 (file)
@@ -264,13 +264,9 @@ pub fn to_result(err: core::ffi::c_int) -> Result {
 ///     pdev: &mut PlatformDevice,
 ///     index: u32,
 /// ) -> Result<*mut core::ffi::c_void> {
-///     // SAFETY: FFI call.
-///     unsafe {
-///         from_err_ptr(bindings::devm_platform_ioremap_resource(
-///             pdev.to_ptr(),
-///             index,
-///         ))
-///     }
+///     // SAFETY: `pdev` points to a valid platform device. There are no safety requirements
+///     // on `index`.
+///     from_err_ptr(unsafe { bindings::devm_platform_ioremap_resource(pdev.to_ptr(), index) })
 /// }
 /// ```
 // TODO: Remove `dead_code` marker once an in-kernel client is available.
index 65be9ae57b80b53b4860774e2b2a2487e7611e5d..424257284d167b5caa23ed880353abbd7ef2de34 100644 (file)
@@ -36,7 +36,7 @@
 //!
 //! ```rust
 //! # #![allow(clippy::disallowed_names)]
-//! use kernel::{prelude::*, sync::Mutex, new_mutex};
+//! use kernel::sync::{new_mutex, Mutex};
 //! # use core::pin::Pin;
 //! #[pin_data]
 //! struct Foo {
@@ -56,7 +56,7 @@
 //!
 //! ```rust
 //! # #![allow(clippy::disallowed_names)]
-//! # use kernel::{prelude::*, sync::Mutex, new_mutex};
+//! # use kernel::sync::{new_mutex, Mutex};
 //! # use core::pin::Pin;
 //! # #[pin_data]
 //! # struct Foo {
@@ -79,7 +79,7 @@
 //! above method only works for types where you can access the fields.
 //!
 //! ```rust
-//! # use kernel::{new_mutex, sync::{Arc, Mutex}};
+//! # use kernel::sync::{new_mutex, Arc, Mutex};
 //! let mtx: Result<Arc<Mutex<usize>>> = Arc::pin_init(new_mutex!(42, "example::mtx"));
 //! ```
 //!
@@ -751,10 +751,10 @@ macro_rules! try_init {
 ///
 /// # Safety
 ///
-/// When implementing this type you will need to take great care. Also there are probably very few
+/// When implementing this trait you will need to take great care. Also there are probably very few
 /// cases where a manual implementation is necessary. Use [`pin_init_from_closure`] where possible.
 ///
-/// The [`PinInit::__pinned_init`] function
+/// The [`PinInit::__pinned_init`] function:
 /// - returns `Ok(())` if it initialized every field of `slot`,
 /// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means:
 ///     - `slot` can be deallocated without UB occurring,
@@ -861,10 +861,10 @@ where
 ///
 /// # Safety
 ///
-/// When implementing this type you will need to take great care. Also there are probably very few
+/// When implementing this trait you will need to take great care. Also there are probably very few
 /// cases where a manual implementation is necessary. Use [`init_from_closure`] where possible.
 ///
-/// The [`Init::__init`] function
+/// The [`Init::__init`] function:
 /// - returns `Ok(())` if it initialized every field of `slot`,
 /// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means:
 ///     - `slot` can be deallocated without UB occurring,
@@ -1013,7 +1013,7 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> {
 ///
 /// ```rust
 /// use kernel::{error::Error, init::init_array_from_fn};
-/// let array: Box<[usize; 1_000]>= Box::init::<Error>(init_array_from_fn(|i| i)).unwrap();
+/// let array: Box<[usize; 1_000]> = Box::init::<Error>(init_array_from_fn(|i| i)).unwrap();
 /// assert_eq!(array.len(), 1_000);
 /// ```
 pub fn init_array_from_fn<I, const N: usize, T, E>(
@@ -1027,7 +1027,7 @@ where
         // Counts the number of initialized elements and when dropped drops that many elements from
         // `slot`.
         let mut init_count = ScopeGuard::new_with_data(0, |i| {
-            // We now free every element that has been initialized before:
+            // We now free every element that has been initialized before.
             // SAFETY: The loop initialized exactly the values from 0..i and since we
             // return `Err` below, the caller will consider the memory at `slot` as
             // uninitialized.
@@ -1056,7 +1056,7 @@ where
 ///
 /// ```rust
 /// use kernel::{sync::{Arc, Mutex}, init::pin_init_array_from_fn, new_mutex};
-/// let array: Arc<[Mutex<usize>; 1_000]>=
+/// let array: Arc<[Mutex<usize>; 1_000]> =
 ///     Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i))).unwrap();
 /// assert_eq!(array.len(), 1_000);
 /// ```
@@ -1071,7 +1071,7 @@ where
         // Counts the number of initialized elements and when dropped drops that many elements from
         // `slot`.
         let mut init_count = ScopeGuard::new_with_data(0, |i| {
-            // We now free every element that has been initialized before:
+            // We now free every element that has been initialized before.
             // SAFETY: The loop initialized exactly the values from 0..i and since we
             // return `Err` below, the caller will consider the memory at `slot` as
             // uninitialized.
index f1d42ab699727818a01082e390c118578694b953..cfa7d080b53193338fc8adfb4813603fe21c61b6 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 
-//! ioctl() number definitions
+//! `ioctl()` number definitions.
 //!
 //! C header: [`include/asm-generic/ioctl.h`](srctree/include/asm-generic/ioctl.h)
 
@@ -28,13 +28,13 @@ pub const fn _IO(ty: u32, nr: u32) -> u32 {
     _IOC(uapi::_IOC_NONE, ty, nr, 0)
 }
 
-/// Build an ioctl number for an read-only ioctl.
+/// Build an ioctl number for a read-only ioctl.
 #[inline(always)]
 pub const fn _IOR<T>(ty: u32, nr: u32) -> u32 {
     _IOC(uapi::_IOC_READ, ty, nr, core::mem::size_of::<T>())
 }
 
-/// Build an ioctl number for an write-only ioctl.
+/// Build an ioctl number for a write-only ioctl.
 #[inline(always)]
 pub const fn _IOW<T>(ty: u32, nr: u32) -> u32 {
     _IOC(uapi::_IOC_WRITE, ty, nr, core::mem::size_of::<T>())
index 7ac39874aeac366a0fa990f8f576b914f321cdc3..be68d5e567b1a1f7a181e08586ed05f2ca008cd6 100644 (file)
 #![no_std]
 #![feature(allocator_api)]
 #![feature(coerce_unsized)]
-#![feature(const_maybe_uninit_zeroed)]
 #![feature(dispatch_from_dyn)]
 #![feature(new_uninit)]
 #![feature(offset_of)]
-#![feature(ptr_metadata)]
 #![feature(receiver_trait)]
 #![feature(unsize)]
 
@@ -49,6 +47,7 @@ pub mod std_vendor;
 pub mod str;
 pub mod sync;
 pub mod task;
+pub mod time;
 pub mod types;
 pub mod workqueue;
 
@@ -78,7 +77,7 @@ pub trait Module: Sized + Sync {
 
 /// Equivalent to `THIS_MODULE` in the C API.
 ///
-/// C header: `include/linux/export.h`
+/// C header: [`include/linux/export.h`](srctree/include/linux/export.h)
 pub struct ThisModule(*mut bindings::module);
 
 // SAFETY: `THIS_MODULE` may be used from all threads within a module.
@@ -102,3 +101,35 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
     // SAFETY: FFI call.
     unsafe { bindings::BUG() };
 }
+
+/// Produces a pointer to an object from a pointer to one of its fields.
+///
+/// # Safety
+///
+/// The pointer passed to this macro, and the pointer returned by this macro, must both be in
+/// bounds of the same allocation.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::container_of;
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// let test = Test { a: 10, b: 20 };
+/// let b_ptr = &test.b;
+/// // SAFETY: The pointer points at the `b` field of a `Test`, so the resulting pointer will be
+/// // in-bounds of the same allocation as `b_ptr`.
+/// let test_alias = unsafe { container_of!(b_ptr, Test, b) };
+/// assert!(core::ptr::eq(&test, test_alias));
+/// ```
+#[macro_export]
+macro_rules! container_of {
+    ($ptr:expr, $type:ty, $($f:tt)*) => {{
+        let ptr = $ptr as *const _ as *const u8;
+        let offset: usize = ::core::mem::offset_of!($type, $($f)*);
+        ptr.sub(offset) as *const $type
+    }}
+}
index 7d848b83add482efcb2b2cdcb3172580d00aab6b..925ced8fdc6148fdffa6730d91b1eebc15011052 100644 (file)
@@ -13,9 +13,102 @@ use crate::{
 };
 
 /// Byte string without UTF-8 validity guarantee.
-///
-/// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
-pub type BStr = [u8];
+#[repr(transparent)]
+pub struct BStr([u8]);
+
+impl BStr {
+    /// Returns the length of this string.
+    #[inline]
+    pub const fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    /// Returns `true` if the string is empty.
+    #[inline]
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Creates a [`BStr`] from a `[u8]`.
+    #[inline]
+    pub const fn from_bytes(bytes: &[u8]) -> &Self {
+        // SAFETY: `BStr` is transparent to `[u8]`.
+        unsafe { &*(bytes as *const [u8] as *const BStr) }
+    }
+}
+
+impl fmt::Display for BStr {
+    /// Formats printable ASCII characters, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::{fmt, b_str, str::{BStr, CString}};
+    /// let ascii = b_str!("Hello, BStr!");
+    /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap();
+    /// assert_eq!(s.as_bytes(), "Hello, BStr!".as_bytes());
+    ///
+    /// let non_ascii = b_str!("🦀");
+    /// let s = CString::try_from_fmt(fmt!("{}", non_ascii)).unwrap();
+    /// assert_eq!(s.as_bytes(), "\\xf0\\x9f\\xa6\\x80".as_bytes());
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        for &b in &self.0 {
+            match b {
+                // Common escape codes.
+                b'\t' => f.write_str("\\t")?,
+                b'\n' => f.write_str("\\n")?,
+                b'\r' => f.write_str("\\r")?,
+                // Printable characters.
+                0x20..=0x7e => f.write_char(b as char)?,
+                _ => write!(f, "\\x{:02x}", b)?,
+            }
+        }
+        Ok(())
+    }
+}
+
+impl fmt::Debug for BStr {
+    /// Formats printable ASCII characters with a double quote on either end,
+    /// escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::{fmt, b_str, str::{BStr, CString}};
+    /// // Embedded double quotes are escaped.
+    /// let ascii = b_str!("Hello, \"BStr\"!");
+    /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap();
+    /// assert_eq!(s.as_bytes(), "\"Hello, \\\"BStr\\\"!\"".as_bytes());
+    ///
+    /// let non_ascii = b_str!("😺");
+    /// let s = CString::try_from_fmt(fmt!("{:?}", non_ascii)).unwrap();
+    /// assert_eq!(s.as_bytes(), "\"\\xf0\\x9f\\x98\\xba\"".as_bytes());
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_char('"')?;
+        for &b in &self.0 {
+            match b {
+                // Common escape codes.
+                b'\t' => f.write_str("\\t")?,
+                b'\n' => f.write_str("\\n")?,
+                b'\r' => f.write_str("\\r")?,
+                // String escape characters.
+                b'\"' => f.write_str("\\\"")?,
+                b'\\' => f.write_str("\\\\")?,
+                // Printable characters.
+                0x20..=0x7e => f.write_char(b as char)?,
+                _ => write!(f, "\\x{:02x}", b)?,
+            }
+        }
+        f.write_char('"')
+    }
+}
+
+impl Deref for BStr {
+    type Target = [u8];
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
 
 /// Creates a new [`BStr`] from a string literal.
 ///
@@ -33,7 +126,7 @@ pub type BStr = [u8];
 macro_rules! b_str {
     ($str:literal) => {{
         const S: &'static str = $str;
-        const C: &'static $crate::str::BStr = S.as_bytes();
+        const C: &'static $crate::str::BStr = $crate::str::BStr::from_bytes(S.as_bytes());
         C
     }};
 }
@@ -149,13 +242,13 @@ impl CStr {
         self.0.as_ptr() as _
     }
 
-    /// Convert the string to a byte slice without the trailing 0 byte.
+    /// Convert the string to a byte slice without the trailing `NUL` byte.
     #[inline]
     pub fn as_bytes(&self) -> &[u8] {
         &self.0[..self.len()]
     }
 
-    /// Convert the string to a byte slice containing the trailing 0 byte.
+    /// Convert the string to a byte slice containing the trailing `NUL` byte.
     #[inline]
     pub const fn as_bytes_with_nul(&self) -> &[u8] {
         &self.0
@@ -191,9 +284,9 @@ impl CStr {
     /// ```
     /// # use kernel::c_str;
     /// # use kernel::str::CStr;
+    /// let bar = c_str!("ツ");
     /// // SAFETY: String literals are guaranteed to be valid UTF-8
     /// // by the Rust compiler.
-    /// let bar = c_str!("ツ");
     /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
     /// ```
     #[inline]
@@ -271,7 +364,7 @@ impl fmt::Debug for CStr {
 impl AsRef<BStr> for CStr {
     #[inline]
     fn as_ref(&self) -> &BStr {
-        self.as_bytes()
+        BStr::from_bytes(self.as_bytes())
     }
 }
 
@@ -280,7 +373,7 @@ impl Deref for CStr {
 
     #[inline]
     fn deref(&self) -> &Self::Target {
-        self.as_bytes()
+        self.as_ref()
     }
 }
 
@@ -327,7 +420,7 @@ where
 
     #[inline]
     fn index(&self, index: Idx) -> &Self::Output {
-        &self.as_bytes()[index]
+        &self.as_ref()[index]
     }
 }
 
@@ -357,6 +450,21 @@ macro_rules! c_str {
 #[cfg(test)]
 mod tests {
     use super::*;
+    use alloc::format;
+
+    const ALL_ASCII_CHARS: &'static str =
+        "\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\
+        \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f \
+        !\"#$%&'()*+,-./0123456789:;<=>?@\
+        ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\
+        \\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\
+        \\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\
+        \\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\
+        \\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\
+        \\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\
+        \\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\
+        \\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\
+        \\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff";
 
     #[test]
     fn test_cstr_to_str() {
@@ -381,6 +489,69 @@ mod tests {
         let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
         assert_eq!(unchecked_str, "🐧");
     }
+
+    #[test]
+    fn test_cstr_display() {
+        let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0").unwrap();
+        assert_eq!(format!("{}", hello_world), "hello, world!");
+        let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0").unwrap();
+        assert_eq!(format!("{}", non_printables), "\\x01\\x09\\x0a");
+        let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0").unwrap();
+        assert_eq!(format!("{}", non_ascii), "d\\xe9j\\xe0 vu");
+        let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0").unwrap();
+        assert_eq!(format!("{}", good_bytes), "\\xf0\\x9f\\xa6\\x80");
+    }
+
+    #[test]
+    fn test_cstr_display_all_bytes() {
+        let mut bytes: [u8; 256] = [0; 256];
+        // fill `bytes` with [1..=255] + [0]
+        for i in u8::MIN..=u8::MAX {
+            bytes[i as usize] = i.wrapping_add(1);
+        }
+        let cstr = CStr::from_bytes_with_nul(&bytes).unwrap();
+        assert_eq!(format!("{}", cstr), ALL_ASCII_CHARS);
+    }
+
+    #[test]
+    fn test_cstr_debug() {
+        let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0").unwrap();
+        assert_eq!(format!("{:?}", hello_world), "\"hello, world!\"");
+        let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0").unwrap();
+        assert_eq!(format!("{:?}", non_printables), "\"\\x01\\x09\\x0a\"");
+        let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0").unwrap();
+        assert_eq!(format!("{:?}", non_ascii), "\"d\\xe9j\\xe0 vu\"");
+        let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0").unwrap();
+        assert_eq!(format!("{:?}", good_bytes), "\"\\xf0\\x9f\\xa6\\x80\"");
+    }
+
+    #[test]
+    fn test_bstr_display() {
+        let hello_world = BStr::from_bytes(b"hello, world!");
+        assert_eq!(format!("{}", hello_world), "hello, world!");
+        let escapes = BStr::from_bytes(b"_\t_\n_\r_\\_\'_\"_");
+        assert_eq!(format!("{}", escapes), "_\\t_\\n_\\r_\\_'_\"_");
+        let others = BStr::from_bytes(b"\x01");
+        assert_eq!(format!("{}", others), "\\x01");
+        let non_ascii = BStr::from_bytes(b"d\xe9j\xe0 vu");
+        assert_eq!(format!("{}", non_ascii), "d\\xe9j\\xe0 vu");
+        let good_bytes = BStr::from_bytes(b"\xf0\x9f\xa6\x80");
+        assert_eq!(format!("{}", good_bytes), "\\xf0\\x9f\\xa6\\x80");
+    }
+
+    #[test]
+    fn test_bstr_debug() {
+        let hello_world = BStr::from_bytes(b"hello, world!");
+        assert_eq!(format!("{:?}", hello_world), "\"hello, world!\"");
+        let escapes = BStr::from_bytes(b"_\t_\n_\r_\\_\'_\"_");
+        assert_eq!(format!("{:?}", escapes), "\"_\\t_\\n_\\r_\\\\_'_\\\"_\"");
+        let others = BStr::from_bytes(b"\x01");
+        assert_eq!(format!("{:?}", others), "\"\\x01\"");
+        let non_ascii = BStr::from_bytes(b"d\xe9j\xe0 vu");
+        assert_eq!(format!("{:?}", non_ascii), "\"d\\xe9j\\xe0 vu\"");
+        let good_bytes = BStr::from_bytes(b"\xf0\x9f\xa6\x80");
+        assert_eq!(format!("{:?}", good_bytes), "\"\\xf0\\x9f\\xa6\\x80\"");
+    }
 }
 
 /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
@@ -449,7 +620,7 @@ impl RawFormatter {
         self.pos as _
     }
 
-    /// Return the number of bytes written to the formatter.
+    /// Returns the number of bytes written to the formatter.
     pub(crate) fn bytes_written(&self) -> usize {
         self.pos - self.beg
     }
index d219ee518eff155066cf4c7422ccb9614925dedb..c983f63fd56e8cd00feca5d50c0bfb5b4c9bc369 100644 (file)
@@ -13,8 +13,9 @@ pub mod lock;
 mod locked_by;
 
 pub use arc::{Arc, ArcBorrow, UniqueArc};
-pub use condvar::CondVar;
-pub use lock::{mutex::Mutex, spinlock::SpinLock};
+pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult};
+pub use lock::mutex::{new_mutex, Mutex};
+pub use lock::spinlock::{new_spinlock, SpinLock};
 pub use locked_by::LockedBy;
 
 /// Represents a lockdep class. It's a wrapper around C's `lock_class_key`.
index 77cdbcf7bd2eba082477b06cae0dc4b5705508eb..7d4c4bf5838844c853b76b85dc6004ab636a043f 100644 (file)
@@ -30,7 +30,7 @@ use core::{
     mem::{ManuallyDrop, MaybeUninit},
     ops::{Deref, DerefMut},
     pin::Pin,
-    ptr::{NonNull, Pointee},
+    ptr::NonNull,
 };
 use macros::pin_data;
 
@@ -56,7 +56,7 @@ mod std_vendor;
 ///     b: u32,
 /// }
 ///
-/// // Create a ref-counted instance of `Example`.
+/// // Create a refcounted instance of `Example`.
 /// let obj = Arc::try_new(Example { a: 10, b: 20 })?;
 ///
 /// // Get a new pointer to `obj` and increment the refcount.
@@ -239,22 +239,20 @@ impl<T: ?Sized> Arc<T> {
         // binary, so its layout is not so large that it can trigger arithmetic overflow.
         let val_offset = unsafe { refcount_layout.extend(val_layout).unwrap_unchecked().1 };
 
-        let metadata: <T as Pointee>::Metadata = core::ptr::metadata(ptr);
-        // SAFETY: The metadata of `T` and `ArcInner<T>` is the same because `ArcInner` is a struct
-        // with `T` as its last field.
+        // Pointer casts leave the metadata unchanged. This is okay because the metadata of `T` and
+        // `ArcInner<T>` is the same since `ArcInner` is a struct with `T` as its last field.
         //
         // This is documented at:
         // <https://doc.rust-lang.org/std/ptr/trait.Pointee.html>.
-        let metadata: <ArcInner<T> as Pointee>::Metadata =
-            unsafe { core::mem::transmute_copy(&metadata) };
+        let ptr = ptr as *const ArcInner<T>;
+
         // SAFETY: The pointer is in-bounds of an allocation both before and after offsetting the
         // pointer, since it originates from a previous call to `Arc::into_raw` and is still valid.
-        let ptr = unsafe { (ptr as *mut u8).sub(val_offset) as *mut () };
-        let ptr = core::ptr::from_raw_parts_mut(ptr, metadata);
+        let ptr = unsafe { ptr.byte_sub(val_offset) };
 
         // SAFETY: By the safety requirements we know that `ptr` came from `Arc::into_raw`, so the
         // reference count held then will be owned by the new `Arc` object.
-        unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) }
+        unsafe { Self::from_inner(NonNull::new_unchecked(ptr.cast_mut())) }
     }
 
     /// Returns an [`ArcBorrow`] from the given [`Arc`].
@@ -365,12 +363,12 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
 /// A borrowed reference to an [`Arc`] instance.
 ///
 /// For cases when one doesn't ever need to increment the refcount on the allocation, it is simpler
-/// to use just `&T`, which we can trivially get from an `Arc<T>` instance.
+/// to use just `&T`, which we can trivially get from an [`Arc<T>`] instance.
 ///
 /// However, when one may need to increment the refcount, it is preferable to use an `ArcBorrow<T>`
 /// over `&Arc<T>` because the latter results in a double-indirection: a pointer (shared reference)
-/// to a pointer (`Arc<T>`) to the object (`T`). An [`ArcBorrow`] eliminates this double
-/// indirection while still allowing one to increment the refcount and getting an `Arc<T>` when/if
+/// to a pointer ([`Arc<T>`]) to the object (`T`). An [`ArcBorrow`] eliminates this double
+/// indirection while still allowing one to increment the refcount and getting an [`Arc<T>`] when/if
 /// needed.
 ///
 /// # Invariants
@@ -510,7 +508,7 @@ impl<T: ?Sized> Deref for ArcBorrow<'_, T> {
 /// # test().unwrap();
 /// ```
 ///
-/// In the following example we first allocate memory for a ref-counted `Example` but we don't
+/// In the following example we first allocate memory for a refcounted `Example` but we don't
 /// initialise it on allocation. We do initialise it later with a call to [`UniqueArc::write`],
 /// followed by a conversion to `Arc<Example>`. This is particularly useful when allocation happens
 /// in one context (e.g., sleepable) and initialisation in another (e.g., atomic):
@@ -560,7 +558,7 @@ impl<T> UniqueArc<T> {
     /// Tries to allocate a new [`UniqueArc`] instance.
     pub fn try_new(value: T) -> Result<Self, AllocError> {
         Ok(Self {
-            // INVARIANT: The newly-created object has a ref-count of 1.
+            // INVARIANT: The newly-created object has a refcount of 1.
             inner: Arc::try_new(value)?,
         })
     }
@@ -574,7 +572,7 @@ impl<T> UniqueArc<T> {
             data <- init::uninit::<T, AllocError>(),
         }? AllocError))?;
         Ok(UniqueArc {
-            // INVARIANT: The newly-created object has a ref-count of 1.
+            // INVARIANT: The newly-created object has a refcount of 1.
             // SAFETY: The pointer from the `Box` is valid.
             inner: unsafe { Arc::from_inner(Box::leak(inner).into()) },
         })
index f65e19d5a37c1588d3b1b0d2015cb5d966ff4f1d..0c3671caffeb2fffe04c28d7868dcdf7aabb91a9 100644 (file)
@@ -6,8 +6,18 @@
 //! variable.
 
 use super::{lock::Backend, lock::Guard, LockClassKey};
-use crate::{bindings, init::PinInit, pin_init, str::CStr, types::Opaque};
+use crate::{
+    bindings,
+    init::PinInit,
+    pin_init,
+    str::CStr,
+    task::{MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE},
+    time::Jiffies,
+    types::Opaque,
+};
+use core::ffi::{c_int, c_long};
 use core::marker::PhantomPinned;
+use core::ptr;
 use macros::pin_data;
 
 /// Creates a [`CondVar`] initialiser with the given name and a newly-created lock class.
@@ -17,6 +27,7 @@ macro_rules! new_condvar {
         $crate::sync::CondVar::new($crate::optional_name!($($name)?), $crate::static_lock_class!())
     };
 }
+pub use new_condvar;
 
 /// A conditional variable.
 ///
@@ -34,8 +45,7 @@ macro_rules! new_condvar {
 /// The following is an example of using a condvar with a mutex:
 ///
 /// ```
-/// use kernel::sync::{CondVar, Mutex};
-/// use kernel::{new_condvar, new_mutex};
+/// use kernel::sync::{new_condvar, new_mutex, CondVar, Mutex};
 ///
 /// #[pin_data]
 /// pub struct Example {
@@ -73,10 +83,12 @@ macro_rules! new_condvar {
 #[pin_data]
 pub struct CondVar {
     #[pin]
-    pub(crate) wait_list: Opaque<bindings::wait_queue_head>,
+    pub(crate) wait_queue_head: Opaque<bindings::wait_queue_head>,
 
     /// A condvar needs to be pinned because it contains a [`struct list_head`] that is
     /// self-referential, so it cannot be safely moved once it is initialised.
+    ///
+    /// [`struct list_head`]: srctree/include/linux/types.h
     #[pin]
     _pin: PhantomPinned,
 }
@@ -96,28 +108,35 @@ impl CondVar {
             _pin: PhantomPinned,
             // SAFETY: `slot` is valid while the closure is called and both `name` and `key` have
             // static lifetimes so they live indefinitely.
-            wait_list <- Opaque::ffi_init(|slot| unsafe {
+            wait_queue_head <- Opaque::ffi_init(|slot| unsafe {
                 bindings::__init_waitqueue_head(slot, name.as_char_ptr(), key.as_ptr())
             }),
         })
     }
 
-    fn wait_internal<T: ?Sized, B: Backend>(&self, wait_state: u32, guard: &mut Guard<'_, T, B>) {
+    fn wait_internal<T: ?Sized, B: Backend>(
+        &self,
+        wait_state: c_int,
+        guard: &mut Guard<'_, T, B>,
+        timeout_in_jiffies: c_long,
+    ) -> c_long {
         let wait = Opaque::<bindings::wait_queue_entry>::uninit();
 
         // SAFETY: `wait` points to valid memory.
         unsafe { bindings::init_wait(wait.get()) };
 
-        // SAFETY: Both `wait` and `wait_list` point to valid memory.
+        // SAFETY: Both `wait` and `wait_queue_head` point to valid memory.
         unsafe {
-            bindings::prepare_to_wait_exclusive(self.wait_list.get(), wait.get(), wait_state as _)
+            bindings::prepare_to_wait_exclusive(self.wait_queue_head.get(), wait.get(), wait_state)
         };
 
-        // SAFETY: No arguments, switches to another thread.
-        guard.do_unlocked(|| unsafe { bindings::schedule() });
+        // SAFETY: Switches to another thread. The timeout can be any number.
+        let ret = guard.do_unlocked(|| unsafe { bindings::schedule_timeout(timeout_in_jiffies) });
+
+        // SAFETY: Both `wait` and `wait_queue_head` point to valid memory.
+        unsafe { bindings::finish_wait(self.wait_queue_head.get(), wait.get()) };
 
-        // SAFETY: Both `wait` and `wait_list` point to valid memory.
-        unsafe { bindings::finish_wait(self.wait_list.get(), wait.get()) };
+        ret
     }
 
     /// Releases the lock and waits for a notification in uninterruptible mode.
@@ -127,7 +146,7 @@ impl CondVar {
     /// [`CondVar::notify_one`] or [`CondVar::notify_all`]. Note that it may also wake up
     /// spuriously.
     pub fn wait<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) {
-        self.wait_internal(bindings::TASK_UNINTERRUPTIBLE, guard);
+        self.wait_internal(TASK_UNINTERRUPTIBLE, guard, MAX_SCHEDULE_TIMEOUT);
     }
 
     /// Releases the lock and waits for a notification in interruptible mode.
@@ -138,29 +157,60 @@ impl CondVar {
     /// Returns whether there is a signal pending.
     #[must_use = "wait_interruptible returns if a signal is pending, so the caller must check the return value"]
     pub fn wait_interruptible<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) -> bool {
-        self.wait_internal(bindings::TASK_INTERRUPTIBLE, guard);
+        self.wait_internal(TASK_INTERRUPTIBLE, guard, MAX_SCHEDULE_TIMEOUT);
         crate::current!().signal_pending()
     }
 
-    /// Calls the kernel function to notify the appropriate number of threads with the given flags.
-    fn notify(&self, count: i32, flags: u32) {
-        // SAFETY: `wait_list` points to valid memory.
+    /// Releases the lock and waits for a notification in interruptible mode.
+    ///
+    /// Atomically releases the given lock (whose ownership is proven by the guard) and puts the
+    /// thread to sleep. It wakes up when notified by [`CondVar::notify_one`] or
+    /// [`CondVar::notify_all`], or when a timeout occurs, or when the thread receives a signal.
+    #[must_use = "wait_interruptible_timeout returns if a signal is pending, so the caller must check the return value"]
+    pub fn wait_interruptible_timeout<T: ?Sized, B: Backend>(
+        &self,
+        guard: &mut Guard<'_, T, B>,
+        jiffies: Jiffies,
+    ) -> CondVarTimeoutResult {
+        let jiffies = jiffies.try_into().unwrap_or(MAX_SCHEDULE_TIMEOUT);
+        let res = self.wait_internal(TASK_INTERRUPTIBLE, guard, jiffies);
+
+        match (res as Jiffies, crate::current!().signal_pending()) {
+            (jiffies, true) => CondVarTimeoutResult::Signal { jiffies },
+            (0, false) => CondVarTimeoutResult::Timeout,
+            (jiffies, false) => CondVarTimeoutResult::Woken { jiffies },
+        }
+    }
+
+    /// Calls the kernel function to notify the appropriate number of threads.
+    fn notify(&self, count: c_int) {
+        // SAFETY: `wait_queue_head` points to valid memory.
         unsafe {
             bindings::__wake_up(
-                self.wait_list.get(),
-                bindings::TASK_NORMAL,
+                self.wait_queue_head.get(),
+                TASK_NORMAL,
                 count,
-                flags as _,
+                ptr::null_mut(),
             )
         };
     }
 
+    /// Calls the kernel function to notify one thread synchronously.
+    ///
+    /// This method behaves like `notify_one`, except that it hints to the scheduler that the
+    /// current thread is about to go to sleep, so it should schedule the target thread on the same
+    /// CPU.
+    pub fn notify_sync(&self) {
+        // SAFETY: `wait_queue_head` points to valid memory.
+        unsafe { bindings::__wake_up_sync(self.wait_queue_head.get(), TASK_NORMAL) };
+    }
+
     /// Wakes a single waiter up, if any.
     ///
     /// This is not 'sticky' in the sense that if no thread is waiting, the notification is lost
     /// completely (as opposed to automatically waking up the next waiter).
     pub fn notify_one(&self) {
-        self.notify(1, 0);
+        self.notify(1);
     }
 
     /// Wakes all waiters up, if any.
@@ -168,6 +218,22 @@ impl CondVar {
     /// This is not 'sticky' in the sense that if no thread is waiting, the notification is lost
     /// completely (as opposed to automatically waking up the next waiter).
     pub fn notify_all(&self) {
-        self.notify(0, 0);
+        self.notify(0);
     }
 }
+
+/// The return type of `wait_timeout`.
+pub enum CondVarTimeoutResult {
+    /// The timeout was reached.
+    Timeout,
+    /// Somebody woke us up.
+    Woken {
+        /// Remaining sleep duration.
+        jiffies: Jiffies,
+    },
+    /// A signal occurred.
+    Signal {
+        /// Remaining sleep duration.
+        jiffies: Jiffies,
+    },
+}
index f12a684bc9579458c0cd016c06668f03e6b7fb5f..5b5c8efe427ae2fc215a9ac312282cc133fb07e2 100644 (file)
@@ -21,14 +21,21 @@ pub mod spinlock;
 /// # Safety
 ///
 /// - Implementers must ensure that only one thread/CPU may access the protected data once the lock
-/// is owned, that is, between calls to `lock` and `unlock`.
-/// - Implementers must also ensure that `relock` uses the same locking method as the original
-/// lock operation.
+///   is owned, that is, between calls to [`lock`] and [`unlock`].
+/// - Implementers must also ensure that [`relock`] uses the same locking method as the original
+///   lock operation.
+///
+/// [`lock`]: Backend::lock
+/// [`unlock`]: Backend::unlock
+/// [`relock`]: Backend::relock
 pub unsafe trait Backend {
     /// The state required by the lock.
     type State;
 
-    /// The state required to be kept between lock and unlock.
+    /// The state required to be kept between [`lock`] and [`unlock`].
+    ///
+    /// [`lock`]: Backend::lock
+    /// [`unlock`]: Backend::unlock
     type GuardState;
 
     /// Initialises the lock.
@@ -139,7 +146,7 @@ pub struct Guard<'a, T: ?Sized, B: Backend> {
 unsafe impl<T: Sync + ?Sized, B: Backend> Sync for Guard<'_, T, B> {}
 
 impl<T: ?Sized, B: Backend> Guard<'_, T, B> {
-    pub(crate) fn do_unlocked(&mut self, cb: impl FnOnce()) {
+    pub(crate) fn do_unlocked<U>(&mut self, cb: impl FnOnce() -> U) -> U {
         // SAFETY: The caller owns the lock, so it is safe to unlock it.
         unsafe { B::unlock(self.lock.state.get(), &self.state) };
 
@@ -147,7 +154,7 @@ impl<T: ?Sized, B: Backend> Guard<'_, T, B> {
         let _relock =
             ScopeGuard::new(|| unsafe { B::relock(self.lock.state.get(), &mut self.state) });
 
-        cb();
+        cb()
     }
 }
 
index 8c524a3ec45af11e5f758a036a822bdf2613e6ff..ef4c4634d294eed3e8ac2067211d27299054c3d9 100644 (file)
@@ -17,6 +17,7 @@ macro_rules! new_mutex {
             $inner, $crate::optional_name!($($name)?), $crate::static_lock_class!())
     };
 }
+pub use new_mutex;
 
 /// A mutual exclusion primitive.
 ///
@@ -35,7 +36,7 @@ macro_rules! new_mutex {
 /// contains an inner struct (`Inner`) that is protected by a mutex.
 ///
 /// ```
-/// use kernel::{init::InPlaceInit, init::PinInit, new_mutex, pin_init, sync::Mutex};
+/// use kernel::sync::{new_mutex, Mutex};
 ///
 /// struct Inner {
 ///     a: u32,
index 068535ce1b29f9da0ee90164cac30d37d0254899..0b22c635634f55acb8e099239098ede76878fbad 100644 (file)
@@ -17,6 +17,7 @@ macro_rules! new_spinlock {
             $inner, $crate::optional_name!($($name)?), $crate::static_lock_class!())
     };
 }
+pub use new_spinlock;
 
 /// A spinlock.
 ///
@@ -33,7 +34,7 @@ macro_rules! new_spinlock {
 /// contains an inner struct (`Inner`) that is protected by a spinlock.
 ///
 /// ```
-/// use kernel::{init::InPlaceInit, init::PinInit, new_spinlock, pin_init, sync::SpinLock};
+/// use kernel::sync::{new_spinlock, SpinLock};
 ///
 /// struct Inner {
 ///     a: u32,
@@ -112,7 +113,7 @@ unsafe impl super::Backend for SpinLockBackend {
 
     unsafe fn unlock(ptr: *mut Self::State, _guard_state: &Self::GuardState) {
         // SAFETY: The safety requirements of this function ensure that `ptr` is valid and that the
-        // caller is the owner of the mutex.
+        // caller is the owner of the spinlock.
         unsafe { bindings::spin_unlock(ptr) }
     }
 }
index b17ee5cd98f3ebed803da9be1730b4c0d3837b57..babc731bd5f6261b3239b00d6ec5ad9c63ebec52 100644 (file)
@@ -9,14 +9,17 @@ use core::{cell::UnsafeCell, mem::size_of, ptr};
 /// Allows access to some data to be serialised by a lock that does not wrap it.
 ///
 /// In most cases, data protected by a lock is wrapped by the appropriate lock type, e.g.,
-/// [`super::Mutex`] or [`super::SpinLock`]. [`LockedBy`] is meant for cases when this is not
-/// possible. For example, if a container has a lock and some data in the contained elements needs
+/// [`Mutex`] or [`SpinLock`]. [`LockedBy`] is meant for cases when this is not possible.
+/// For example, if a container has a lock and some data in the contained elements needs
 /// to be protected by the same lock.
 ///
 /// [`LockedBy`] wraps the data in lieu of another locking primitive, and only allows access to it
 /// when the caller shows evidence that the 'external' lock is locked. It panics if the evidence
 /// refers to the wrong instance of the lock.
 ///
+/// [`Mutex`]: super::Mutex
+/// [`SpinLock`]: super::SpinLock
+///
 /// # Examples
 ///
 /// The following is an example for illustrative purposes: `InnerDirectory::bytes_used` is an
index 9451932d5d867419eb3bad9d01bea40a96e10ea1..ca6e7e31d71c9d003ff80c7d2f2814ce47d176c6 100644 (file)
@@ -5,7 +5,23 @@
 //! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h).
 
 use crate::{bindings, types::Opaque};
-use core::{marker::PhantomData, ops::Deref, ptr};
+use core::{
+    ffi::{c_int, c_long, c_uint},
+    marker::PhantomData,
+    ops::Deref,
+    ptr,
+};
+
+/// A sentinel value used for infinite timeouts.
+pub const MAX_SCHEDULE_TIMEOUT: c_long = c_long::MAX;
+
+/// Bitmask for tasks that are sleeping in an interruptible state.
+pub const TASK_INTERRUPTIBLE: c_int = bindings::TASK_INTERRUPTIBLE as c_int;
+/// Bitmask for tasks that are sleeping in an uninterruptible state.
+pub const TASK_UNINTERRUPTIBLE: c_int = bindings::TASK_UNINTERRUPTIBLE as c_int;
+/// Convenience constant for waking up tasks regardless of whether they are in interruptible or
+/// uninterruptible sleep.
+pub const TASK_NORMAL: c_uint = bindings::TASK_NORMAL as c_uint;
 
 /// Returns the currently running task.
 #[macro_export]
@@ -23,7 +39,7 @@ macro_rules! current {
 ///
 /// All instances are valid tasks created by the C portion of the kernel.
 ///
-/// Instances of this type are always ref-counted, that is, a call to `get_task_struct` ensures
+/// Instances of this type are always refcounted, that is, a call to `get_task_struct` ensures
 /// that the allocation remains valid at least until the matching call to `put_task_struct`.
 ///
 /// # Examples
@@ -116,7 +132,7 @@ impl Task {
     /// Returns the group leader of the given task.
     pub fn group_leader(&self) -> &Task {
         // SAFETY: By the type invariant, we know that `self.0` is a valid task. Valid tasks always
-        // have a valid group_leader.
+        // have a valid `group_leader`.
         let ptr = unsafe { *ptr::addr_of!((*self.0.get()).group_leader) };
 
         // SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`,
@@ -147,7 +163,7 @@ impl Task {
     }
 }
 
-// SAFETY: The type invariants guarantee that `Task` is always ref-counted.
+// SAFETY: The type invariants guarantee that `Task` is always refcounted.
 unsafe impl crate::types::AlwaysRefCounted for Task {
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference means that the refcount is nonzero.
diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
new file mode 100644 (file)
index 0000000..25a896e
--- /dev/null
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Time related primitives.
+//!
+//! This module contains the kernel APIs related to time and timers that
+//! have been ported or wrapped for usage by Rust code in the kernel.
+
+/// The time unit of Linux kernel. One jiffy equals (1/HZ) second.
+pub type Jiffies = core::ffi::c_ulong;
+
+/// The millisecond time unit.
+pub type Msecs = core::ffi::c_uint;
+
+/// Converts milliseconds to jiffies.
+#[inline]
+pub fn msecs_to_jiffies(msecs: Msecs) -> Jiffies {
+    // SAFETY: The `__msecs_to_jiffies` function is always safe to call no
+    // matter what the argument is.
+    unsafe { bindings::__msecs_to_jiffies(msecs) }
+}
index fdb778e65d79d3a900bdda573dc093564d060862..aa77bad9bce48655fa1b7ddb700710172cca759a 100644 (file)
@@ -46,6 +46,25 @@ pub trait ForeignOwnable: Sized {
     /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] for
     /// this object must have been dropped.
     unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self;
+
+    /// Tries to convert a foreign-owned object back to a Rust-owned one.
+    ///
+    /// A convenience wrapper over [`ForeignOwnable::from_foreign`] that returns [`None`] if `ptr`
+    /// is null.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must either be null or satisfy the safety requirements for
+    /// [`ForeignOwnable::from_foreign`].
+    unsafe fn try_from_foreign(ptr: *const core::ffi::c_void) -> Option<Self> {
+        if ptr.is_null() {
+            None
+        } else {
+            // SAFETY: Since `ptr` is not null here, then `ptr` satisfies the safety requirements
+            // of `from_foreign` given the safety requirements of this function.
+            unsafe { Some(Self::from_foreign(ptr)) }
+        }
+    }
 }
 
 impl<T: 'static> ForeignOwnable for Box<T> {
@@ -90,6 +109,7 @@ impl ForeignOwnable for () {
 ///
 /// In the example below, we have multiple exit paths and we want to log regardless of which one is
 /// taken:
+///
 /// ```
 /// # use kernel::types::ScopeGuard;
 /// fn example1(arg: bool) {
@@ -108,6 +128,7 @@ impl ForeignOwnable for () {
 ///
 /// In the example below, we want to log the same message on all early exits but a different one on
 /// the main exit path:
+///
 /// ```
 /// # use kernel::types::ScopeGuard;
 /// fn example2(arg: bool) {
@@ -129,6 +150,7 @@ impl ForeignOwnable for () {
 ///
 /// In the example below, we need a mutable object (the vector) to be accessible within the log
 /// function, so we wrap it in the [`ScopeGuard`]:
+///
 /// ```
 /// # use kernel::types::ScopeGuard;
 /// fn example3(arg: bool) -> Result {
index 49839787737671c8d940533c5a8fa10b8039ba70..480cb292e7c21d2d0e242d01844b10ffac92053a 100644 (file)
 //!
 //! # The raw API
 //!
-//! The raw API consists of the `RawWorkItem` trait, where the work item needs to provide an
+//! The raw API consists of the [`RawWorkItem`] trait, where the work item needs to provide an
 //! arbitrary function that knows how to enqueue the work item. It should usually not be used
 //! directly, but if you want to, you can use it without using the pieces from the safe API.
 //!
 //! # The safe API
 //!
-//! The safe API is used via the `Work` struct and `WorkItem` traits. Furthermore, it also includes
-//! a trait called `WorkItemPointer`, which is usually not used directly by the user.
+//! The safe API is used via the [`Work`] struct and [`WorkItem`] traits. Furthermore, it also
+//! includes a trait called [`WorkItemPointer`], which is usually not used directly by the user.
 //!
-//!  * The `Work` struct is the Rust wrapper for the C `work_struct` type.
-//!  * The `WorkItem` trait is implemented for structs that can be enqueued to a workqueue.
-//!  * The `WorkItemPointer` trait is implemented for the pointer type that points at a something
-//!    that implements `WorkItem`.
+//!  * The [`Work`] struct is the Rust wrapper for the C `work_struct` type.
+//!  * The [`WorkItem`] trait is implemented for structs that can be enqueued to a workqueue.
+//!  * The [`WorkItemPointer`] trait is implemented for the pointer type that points at a something
+//!    that implements [`WorkItem`].
 //!
 //! ## Example
 //!
@@ -35,8 +35,7 @@
 //! ```
 //! use kernel::prelude::*;
 //! use kernel::sync::Arc;
-//! use kernel::workqueue::{self, Work, WorkItem};
-//! use kernel::{impl_has_work, new_work};
+//! use kernel::workqueue::{self, impl_has_work, new_work, Work, WorkItem};
 //!
 //! #[pin_data]
 //! struct MyStruct {
@@ -78,8 +77,7 @@
 //! ```
 //! use kernel::prelude::*;
 //! use kernel::sync::Arc;
-//! use kernel::workqueue::{self, Work, WorkItem};
-//! use kernel::{impl_has_work, new_work};
+//! use kernel::workqueue::{self, impl_has_work, new_work, Work, WorkItem};
 //!
 //! #[pin_data]
 //! struct MyStruct {
@@ -147,6 +145,7 @@ macro_rules! new_work {
         $crate::workqueue::Work::new($crate::optional_name!($($name)?), $crate::static_lock_class!())
     };
 }
+pub use new_work;
 
 /// A kernel work queue.
 ///
@@ -168,7 +167,7 @@ impl Queue {
     /// # Safety
     ///
     /// The caller must ensure that the provided raw pointer is not dangling, that it points at a
-    /// valid workqueue, and that it remains valid until the end of 'a.
+    /// valid workqueue, and that it remains valid until the end of `'a`.
     pub unsafe fn from_raw<'a>(ptr: *const bindings::workqueue_struct) -> &'a Queue {
         // SAFETY: The `Queue` type is `#[repr(transparent)]`, so the pointer cast is valid. The
         // caller promises that the pointer is not dangling.
@@ -199,7 +198,11 @@ impl Queue {
         // stay valid until we call the function pointer in the `work_struct`, so the access is ok.
         unsafe {
             w.__enqueue(move |work_ptr| {
-                bindings::queue_work_on(bindings::WORK_CPU_UNBOUND as _, queue_ptr, work_ptr)
+                bindings::queue_work_on(
+                    bindings::wq_misc_consts_WORK_CPU_UNBOUND as _,
+                    queue_ptr,
+                    work_ptr,
+                )
             })
         }
     }
@@ -218,7 +221,9 @@ impl Queue {
     }
 }
 
-/// A helper type used in `try_spawn`.
+/// A helper type used in [`try_spawn`].
+///
+/// [`try_spawn`]: Queue::try_spawn
 #[pin_data]
 struct ClosureWork<T> {
     #[pin]
@@ -253,14 +258,16 @@ impl<T: FnOnce()> WorkItem for ClosureWork<T> {
 /// actual value of the id is not important as long as you use different ids for different fields
 /// of the same struct. (Fields of different structs need not use different ids.)
 ///
-/// Note that the id is used only to select the right method to call during compilation. It wont be
+/// Note that the id is used only to select the right method to call during compilation. It won't be
 /// part of the final executable.
 ///
 /// # Safety
 ///
-/// Implementers must ensure that any pointers passed to a `queue_work_on` closure by `__enqueue`
+/// Implementers must ensure that any pointers passed to a `queue_work_on` closure by [`__enqueue`]
 /// remain valid for the duration specified in the guarantees section of the documentation for
-/// `__enqueue`.
+/// [`__enqueue`].
+///
+/// [`__enqueue`]: RawWorkItem::__enqueue
 pub unsafe trait RawWorkItem<const ID: u64> {
     /// The return type of [`Queue::enqueue`].
     type EnqueueOutput;
@@ -290,10 +297,11 @@ pub unsafe trait RawWorkItem<const ID: u64> {
 
 /// Defines the method that should be called directly when a work item is executed.
 ///
-/// This trait is implemented by `Pin<Box<T>>` and `Arc<T>`, and is mainly intended to be
+/// This trait is implemented by `Pin<Box<T>>` and [`Arc<T>`], and is mainly intended to be
 /// implemented for smart pointer types. For your own structs, you would implement [`WorkItem`]
-/// instead. The `run` method on this trait will usually just perform the appropriate
-/// `container_of` translation and then call into the `run` method from the [`WorkItem`] trait.
+/// instead. The [`run`] method on this trait will usually just perform the appropriate
+/// `container_of` translation and then call into the [`run`][WorkItem::run] method from the
+/// [`WorkItem`] trait.
 ///
 /// This trait is used when the `work_struct` field is defined using the [`Work`] helper.
 ///
@@ -309,8 +317,10 @@ pub unsafe trait WorkItemPointer<const ID: u64>: RawWorkItem<ID> {
     ///
     /// # Safety
     ///
-    /// The provided `work_struct` pointer must originate from a previous call to `__enqueue` where
-    /// the `queue_work_on` closure returned true, and the pointer must still be valid.
+    /// The provided `work_struct` pointer must originate from a previous call to [`__enqueue`]
+    /// where the `queue_work_on` closure returned true, and the pointer must still be valid.
+    ///
+    /// [`__enqueue`]: RawWorkItem::__enqueue
     unsafe extern "C" fn run(ptr: *mut bindings::work_struct);
 }
 
@@ -328,12 +338,14 @@ pub trait WorkItem<const ID: u64 = 0> {
 
 /// Links for a work item.
 ///
-/// This struct contains a function pointer to the `run` function from the [`WorkItemPointer`]
+/// This struct contains a function pointer to the [`run`] function from the [`WorkItemPointer`]
 /// trait, and defines the linked list pointers necessary to enqueue a work item in a workqueue.
 ///
 /// Wraps the kernel's C `struct work_struct`.
 ///
 /// This is a helper type used to associate a `work_struct` with the [`WorkItem`] that uses it.
+///
+/// [`run`]: WorkItemPointer::run
 #[repr(transparent)]
 pub struct Work<T: ?Sized, const ID: u64 = 0> {
     work: Opaque<bindings::work_struct>,
@@ -396,9 +408,8 @@ impl<T: ?Sized, const ID: u64> Work<T, ID> {
 /// like this:
 ///
 /// ```no_run
-/// use kernel::impl_has_work;
 /// use kernel::prelude::*;
-/// use kernel::workqueue::Work;
+/// use kernel::workqueue::{impl_has_work, Work};
 ///
 /// struct MyWorkItem {
 ///     work_field: Work<MyWorkItem, 1>,
@@ -409,28 +420,25 @@ impl<T: ?Sized, const ID: u64> Work<T, ID> {
 /// }
 /// ```
 ///
-/// Note that since the `Work` type is annotated with an id, you can have several `work_struct`
+/// Note that since the [`Work`] type is annotated with an id, you can have several `work_struct`
 /// fields by using a different id for each one.
 ///
 /// # Safety
 ///
-/// The [`OFFSET`] constant must be the offset of a field in Self of type [`Work<T, ID>`]. The methods on
-/// this trait must have exactly the behavior that the definitions given below have.
+/// The [`OFFSET`] constant must be the offset of a field in `Self` of type [`Work<T, ID>`]. The
+/// methods on this trait must have exactly the behavior that the definitions given below have.
 ///
-/// [`Work<T, ID>`]: Work
 /// [`impl_has_work!`]: crate::impl_has_work
 /// [`OFFSET`]: HasWork::OFFSET
 pub unsafe trait HasWork<T, const ID: u64 = 0> {
     /// The offset of the [`Work<T, ID>`] field.
-    ///
-    /// [`Work<T, ID>`]: Work
     const OFFSET: usize;
 
     /// Returns the offset of the [`Work<T, ID>`] field.
     ///
-    /// This method exists because the [`OFFSET`] constant cannot be accessed if the type is not Sized.
+    /// This method exists because the [`OFFSET`] constant cannot be accessed if the type is not
+    /// [`Sized`].
     ///
-    /// [`Work<T, ID>`]: Work
     /// [`OFFSET`]: HasWork::OFFSET
     #[inline]
     fn get_work_offset(&self) -> usize {
@@ -442,8 +450,6 @@ pub unsafe trait HasWork<T, const ID: u64 = 0> {
     /// # Safety
     ///
     /// The provided pointer must point at a valid struct of type `Self`.
-    ///
-    /// [`Work<T, ID>`]: Work
     #[inline]
     unsafe fn raw_get_work(ptr: *mut Self) -> *mut Work<T, ID> {
         // SAFETY: The caller promises that the pointer is valid.
@@ -455,8 +461,6 @@ pub unsafe trait HasWork<T, const ID: u64 = 0> {
     /// # Safety
     ///
     /// The pointer must point at a [`Work<T, ID>`] field in a struct of type `Self`.
-    ///
-    /// [`Work<T, ID>`]: Work
     #[inline]
     unsafe fn work_container_of(ptr: *mut Work<T, ID>) -> *mut Self
     where
@@ -473,9 +477,8 @@ pub unsafe trait HasWork<T, const ID: u64 = 0> {
 /// # Examples
 ///
 /// ```
-/// use kernel::impl_has_work;
 /// use kernel::sync::Arc;
-/// use kernel::workqueue::{self, Work};
+/// use kernel::workqueue::{self, impl_has_work, Work};
 ///
 /// struct MyStruct {
 ///     work_field: Work<MyStruct, 17>,
@@ -485,8 +488,6 @@ pub unsafe trait HasWork<T, const ID: u64 = 0> {
 ///     impl HasWork<MyStruct, 17> for MyStruct { self.work_field }
 /// }
 /// ```
-///
-/// [`HasWork<T, ID>`]: HasWork
 #[macro_export]
 macro_rules! impl_has_work {
     ($(impl$(<$($implarg:ident),*>)?
@@ -509,6 +510,7 @@ macro_rules! impl_has_work {
         }
     )*};
 }
+pub use impl_has_work;
 
 impl_has_work! {
     impl<T> HasWork<Self> for ClosureWork<T> { self.work }
index d62d8710d77ab0043cb761d7b33fddfd1528a17c..27979e582e4b943b963a88ee7cecdea4f345b83f 100644 (file)
@@ -222,10 +222,15 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
             }};
 
             // Loadable modules need to export the `{{init,cleanup}}_module` identifiers.
+            /// # Safety
+            ///
+            /// This function must not be called after module initialization, because it may be
+            /// freed after that completes.
             #[cfg(MODULE)]
             #[doc(hidden)]
             #[no_mangle]
-            pub extern \"C\" fn init_module() -> core::ffi::c_int {{
+            #[link_section = \".init.text\"]
+            pub unsafe extern \"C\" fn init_module() -> core::ffi::c_int {{
                 __init()
             }}
 
index 5a84b6443875c47013348bfed85ebefe8c6da4db..3ee8ecfb8c044c3bf65461e81af5a9e95391fa44 100644 (file)
@@ -33,7 +33,7 @@ ld-option = $(success,$(LD) -v $(1))
 
 # $(as-instr,<instr>)
 # Return y if the assembler supports <instr>, n otherwise
-as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -c -x assembler-with-cpp -o /dev/null -)
+as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -Wa$(comma)--fatal-warnings -c -x assembler-with-cpp -o /dev/null -)
 
 # check if $(CC) and $(LD) exist
 $(error-if,$(failure,command -v $(CC)),C compiler '$(CC)' not found)
index dae447a1ad30c4a30d48f4741e7a5dfd81622ced..0fb7a785594c961ee2157be94e28172bdbb71666 100644 (file)
@@ -290,7 +290,7 @@ quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
       cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $<
 
 $(obj)/%.o: $(src)/%.rs FORCE
-       $(call if_changed_dep,rustc_o_rs)
+       +$(call if_changed_dep,rustc_o_rs)
 
 quiet_cmd_rustc_rsi_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
       cmd_rustc_rsi_rs = \
@@ -298,19 +298,19 @@ quiet_cmd_rustc_rsi_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
        command -v $(RUSTFMT) >/dev/null && $(RUSTFMT) $@
 
 $(obj)/%.rsi: $(src)/%.rs FORCE
-       $(call if_changed_dep,rustc_rsi_rs)
+       +$(call if_changed_dep,rustc_rsi_rs)
 
 quiet_cmd_rustc_s_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
       cmd_rustc_s_rs = $(rust_common_cmd) --emit=asm=$@ $<
 
 $(obj)/%.s: $(src)/%.rs FORCE
-       $(call if_changed_dep,rustc_s_rs)
+       +$(call if_changed_dep,rustc_s_rs)
 
 quiet_cmd_rustc_ll_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
       cmd_rustc_ll_rs = $(rust_common_cmd) --emit=llvm-ir=$@ $<
 
 $(obj)/%.ll: $(src)/%.rs FORCE
-       $(call if_changed_dep,rustc_ll_rs)
+       +$(call if_changed_dep,rustc_ll_rs)
 
 # Compile assembler sources (.S)
 # ---------------------------------------------------------------------------
index 8fcb427405a6f17f61655a6d0881c433f22e1dd6..92be0c9a13eeb51beca06abe15bfe22c6e72bfcb 100644 (file)
@@ -38,7 +38,7 @@ as-option = $(call try-run,\
 # Usage: aflags-y += $(call as-instr,instr,option1,option2)
 
 as-instr = $(call try-run,\
-       printf "%b\n" "$(1)" | $(CC) -Werror $(CLANG_FLAGS) $(KBUILD_AFLAGS) -c -x assembler-with-cpp -o "$$TMP" -,$(2),$(3))
+       printf "%b\n" "$(1)" | $(CC) -Werror $(CLANG_FLAGS) $(KBUILD_AFLAGS) -Wa$(comma)--fatal-warnings -c -x assembler-with-cpp -o "$$TMP" -,$(2),$(3))
 
 # __cc-option
 # Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586)
index 08d83d9db31a138420f075dd45630046a76d1180..3c17e6ba421ceffcf9af76989e4b70a5b9b9305e 100644 (file)
@@ -156,7 +156,7 @@ quiet_cmd_host-rust = HOSTRUSTC $@
       cmd_host-rust    = \
        $(HOSTRUSTC) $(hostrust_flags) --emit=link=$@ $<
 $(host-rust): $(obj)/%: $(src)/%.rs FORCE
-       $(call if_changed_dep,host-rust)
+       +$(call if_changed_dep,host-rust)
 
 targets += $(host-csingle) $(host-cmulti) $(host-cobjs) \
           $(host-cxxmulti) $(host-cxxobjs) $(host-rust)
index cd5b181060f151f2c28186feb5b96db37ee04da9..01a80a216f56462e53f6ef1440c4ff0514ca696b 100644 (file)
@@ -254,7 +254,7 @@ objtool := $(objtree)/tools/objtool/objtool
 
 objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK)            += --hacks=jump_label
 objtool-args-$(CONFIG_HAVE_NOINSTR_HACK)               += --hacks=noinstr
-objtool-args-$(CONFIG_CALL_DEPTH_TRACKING)             += --hacks=skylake
+objtool-args-$(CONFIG_MITIGATION_CALL_DEPTH_TRACKING)  += --hacks=skylake
 objtool-args-$(CONFIG_X86_KERNEL_IBT)                  += --ibt
 objtool-args-$(CONFIG_FINEIBT)                         += --cfi
 objtool-args-$(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL)       += --mcount
@@ -262,9 +262,9 @@ ifdef CONFIG_FTRACE_MCOUNT_USE_OBJTOOL
 objtool-args-$(CONFIG_HAVE_OBJTOOL_NOP_MCOUNT)         += --mnop
 endif
 objtool-args-$(CONFIG_UNWINDER_ORC)                    += --orc
-objtool-args-$(CONFIG_RETPOLINE)                       += --retpoline
-objtool-args-$(CONFIG_RETHUNK)                         += --rethunk
-objtool-args-$(CONFIG_SLS)                             += --sls
+objtool-args-$(CONFIG_MITIGATION_RETPOLINE)            += --retpoline
+objtool-args-$(CONFIG_MITIGATION_RETHUNK)              += --rethunk
+objtool-args-$(CONFIG_MITIGATION_SLS)                  += --sls
 objtool-args-$(CONFIG_STACK_VALIDATION)                        += --stackval
 objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE)         += --static-call
 objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION)         += --uaccess
@@ -340,7 +340,7 @@ quiet_cmd_gzip = GZIP    $@
 # DTC
 # ---------------------------------------------------------------------------
 DTC ?= $(objtree)/scripts/dtc/dtc
-DTC_FLAGS += -Wno-interrupt_provider \
+DTC_FLAGS += \
        -Wno-unique_unit_address
 
 # Disable noisy checks by default
@@ -358,7 +358,6 @@ endif
 ifneq ($(findstring 2,$(KBUILD_EXTRA_WARN)),)
 DTC_FLAGS += -Wnode_name_chars_strict \
        -Wproperty_name_chars_strict \
-       -Winterrupt_provider \
        -Wunique_unit_address
 endif
 
index 25b3b587d37c00cd77415ef8d6533e9a18c4dcc9..6de297916ce680accc8eff02aa2957cf8c915f19 100644 (file)
@@ -38,7 +38,7 @@ objtool-enabled := $(or $(delay-objtool),$(CONFIG_NOINSTR_VALIDATION))
 vmlinux-objtool-args-$(delay-objtool)                  += $(objtool-args-y)
 vmlinux-objtool-args-$(CONFIG_GCOV_KERNEL)             += --no-unreachable
 vmlinux-objtool-args-$(CONFIG_NOINSTR_VALIDATION)      += --noinstr \
-                                                          $(if $(or $(CONFIG_CPU_UNRET_ENTRY),$(CONFIG_CPU_SRSO)), --unret)
+                                                          $(if $(or $(CONFIG_MITIGATION_UNRET_ENTRY),$(CONFIG_MITIGATION_SRSO)), --unret)
 
 objtool-args = $(vmlinux-objtool-args-y) --link
 
index f828e5f6750c2771f85cc38d462ef5de1195425e..fbc2fadfbdc412d6b8050d08ffb0e51661cae671 100644 (file)
@@ -10,6 +10,7 @@ cat <<EOF
  * @u: ${int} value to compare with
  *
  * If (@v != @u), atomically updates @v to (@v + @a) with ${desc_order} ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * ${desc_noinstr}
  *
index 3bce328f50cff86ebd98b761689e08bd5fef1eab..02b24ee9d8a4fa63431d9c40627860f84bcea7bd 100644 (file)
@@ -6,6 +6,7 @@ cat <<EOF
  * @new: ${int} value to assign
  *
  * If (@v == @old), atomically updates @v to @new with ${desc_order} ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * ${desc_noinstr}
  *
index 04f1aed3cf830442eafac088d871435d9cdb87dc..9468b4a69603ed3edbd359cd72160de3b9dfbb0f 100644 (file)
@@ -4,6 +4,7 @@ cat <<EOF
  * @v: pointer to ${atomic}_t
  *
  * If (@v > 0), atomically updates @v to (@v - 1) with ${desc_order} ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * ${desc_noinstr}
  *
index ee73612f03547dd3054dcbad3a85d5612d9caf86..06a678678f717aedd5b90820fa07900ae387e2c9 100644 (file)
@@ -4,6 +4,7 @@ cat <<EOF
  * @v: pointer to ${atomic}_t
  *
  * If (@v <= 0), atomically updates @v to (@v - 1) with ${desc_order} ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * ${desc_noinstr}
  *
index 618be08e653e5580802bf2e4e294574a4c1ac7c2..c1a30fc66ee90378e7219d2c9cbc5fa24695a1bd 100644 (file)
@@ -4,6 +4,7 @@ cat <<EOF
  * @v: pointer to ${atomic}_t
  *
  * If (@v != 0), atomically updates @v to (@v + 1) with ${desc_order} ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * ${desc_noinstr}
  *
index 597f23d4dc8dc61a12ac99fe213433ad74e0b69b..ece0d2c7b38f1301d2b6002df5ef7e00c57f02b0 100644 (file)
@@ -4,6 +4,7 @@ cat <<EOF
  * @v: pointer to ${atomic}_t
  *
  * If (@v >= 0), atomically updates @v to (@v + 1) with ${desc_order} ordering.
+ * Otherwise, @v is not modified and relaxed ordering is provided.
  *
  * ${desc_noinstr}
  *
index 296553206c06e18c8a34da4efe79ecef66ecc89e..3ccff29538f5f8746551ad4a375bc8e4eced8f1b 100644 (file)
@@ -6,7 +6,8 @@ cat <<EOF
  * @new: ${int} value to assign
  *
  * If (@v == @old), atomically updates @v to @new with ${desc_order} ordering.
- * Otherwise, updates @old to the current value of @v.
+ * Otherwise, @v is not modified, @old is updated to the current value of @v,
+ * and relaxed ordering is provided.
  *
  * ${desc_noinstr}
  *
index 61b7dddedc461e2ece91a7b25bcf14987fc98886..0669bac5e900e134c45a025697bae3b6251c09b1 100755 (executable)
@@ -513,7 +513,7 @@ eBPF programs can have an associated license, passed along with the bytecode
 instructions to the kernel when the programs are loaded. The format for that
 string is identical to the one in use for kernel modules (Dual licenses, such
 as "Dual BSD/GPL", may be used). Some helper functions are only accessible to
-programs that are compatible with the GNU Privacy License (GPL).
+programs that are compatible with the GNU General Public License (GNU GPL).
 
 In order to use such helpers, the eBPF program must be loaded with the correct
 license string passed (via **attr**) to the **bpf**\\ () system call, and this
index 5dea4479240bc02226828f13f3fec2dc3acf36c6..e4fb686dfaa9f0ee49fadb43c6e4404fcd5ac8f3 100755 (executable)
@@ -170,7 +170,7 @@ def process_line(root_directory, command_prefix, file_path):
     # escape the pound sign '#', either as '\#' or '$(pound)' (depending on the
     # kernel version). The compile_commands.json file is not interepreted
     # by Make, so this code replaces the escaped version with '#'.
-    prefix = command_prefix.replace('\#', '#').replace('$(pound)', '#')
+    prefix = command_prefix.replace(r'\#', '#').replace('$(pound)', '#')
 
     # Return the canonical path, eliminating any symbolic links encountered in the path.
     abs_path = os.path.realpath(os.path.join(root_directory, file_path))
index e810e0c27ff18d3adc16fda616888e45f6e7d7da..10fadc2387194e1cb1fc19d29c92e8a8fa1f8c6d 100644 (file)
@@ -139,7 +139,7 @@ LX_CONFIG(CONFIG_ARM64_64K_PAGES)
 if IS_BUILTIN(CONFIG_ARM64):
     LX_VALUE(CONFIG_ARM64_PA_BITS)
     LX_VALUE(CONFIG_ARM64_VA_BITS)
-    LX_VALUE(CONFIG_ARM64_PAGE_SHIFT)
+    LX_VALUE(CONFIG_PAGE_SHIFT)
     LX_VALUE(CONFIG_ARCH_FORCE_MAX_ORDER)
 LX_CONFIG(CONFIG_SPARSEMEM)
 LX_CONFIG(CONFIG_SPARSEMEM_EXTREME)
index ad5641dcb068662c101eae4cbbd9999386db4dda..515730fd4c9d2949a493262043ba4bbb2af340bb 100644 (file)
@@ -41,7 +41,7 @@ class aarch64_page_ops():
             self.SECTION_SIZE_BITS = 27
         self.MAX_PHYSMEM_BITS = constants.LX_CONFIG_ARM64_VA_BITS
 
-        self.PAGE_SHIFT = constants.LX_CONFIG_ARM64_PAGE_SHIFT
+        self.PAGE_SHIFT = constants.LX_CONFIG_PAGE_SHIFT
         self.PAGE_SIZE = 1 << self.PAGE_SHIFT
         self.PAGE_MASK = (~(self.PAGE_SIZE - 1)) & ((1 << 64) - 1)
 
index c8047f4441e60ea944ae6fccedf0e4d0d7632dcd..e8316beb17a714588fa5358a8b514a9d383fecbf 100644 (file)
@@ -82,7 +82,7 @@ lx-symbols command."""
         self.module_files_updated = True
 
     def _get_module_file(self, module_name):
-        module_pattern = ".*/{0}\.ko(?:.debug)?$".format(
+        module_pattern = r".*/{0}\.ko(?:.debug)?$".format(
             module_name.replace("_", r"[_\-]"))
         for name in self.module_files:
             if re.match(module_pattern, name) and os.path.exists(name):
index 0da52b548ba50f5e1333c3c2b2a18da2533a18a1..19f72bfdbb82a987f834024b3e36f48e95b58351 100644 (file)
@@ -155,7 +155,7 @@ fn main() {
             "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
         );
         let mut features = "-3dnow,-3dnowa,-mmx,+soft-float".to_string();
-        if cfg.has("RETPOLINE") {
+        if cfg.has("MITIGATION_RETPOLINE") {
             features += ",+retpoline-external-thunk";
         }
         ts.push("features", features);
index a432b171be826a9c4ff362c518f97024ab90a811..7862a81017477daec1f702fdf46166e381bd396d 100755 (executable)
@@ -135,8 +135,13 @@ gen_btf()
        ${OBJCOPY} --only-section=.BTF --set-section-flags .BTF=alloc,readonly \
                --strip-all ${1} ${2} 2>/dev/null
        # Change e_type to ET_REL so that it can be used to link final vmlinux.
-       # Unlike GNU ld, lld does not allow an ET_EXEC input.
-       printf '\1' | dd of=${2} conv=notrunc bs=1 seek=16 status=none
+       # GNU ld 2.35+ and lld do not allow an ET_EXEC input.
+       if is_enabled CONFIG_CPU_BIG_ENDIAN; then
+               et_rel='\0\1'
+       else
+               et_rel='\1\0'
+       fi
+       printf "${et_rel}" | dd of=${2} conv=notrunc bs=1 seek=16 status=none
 }
 
 # Create ${2} .S file with all symbols from the ${1} object file
index 9faa4d3d91e3586e20bed71a50893c6c959252ad..e217683b10d6fabb06430917e4980664f752c35d 100755 (executable)
@@ -33,7 +33,7 @@ llvm)
        fi
        ;;
 rustc)
-       echo 1.74.1
+       echo 1.76.0
        ;;
 bindgen)
        echo 0.65.1
index 9ba1c9da0a40f28a4efe22856868ac745ab68b56..57ff5656d566fbc659801bdb4fd445b7b9ef2b86 100755 (executable)
@@ -48,17 +48,8 @@ ${NM} -n ${1} | sed >${2} -e "
 / __kvm_nvhe_\\$/d
 / __kvm_nvhe_\.L/d
 
-# arm64 lld
-/ __AArch64ADRPThunk_/d
-
-# arm lld
-/ __ARMV5PILongThunk_/d
-/ __ARMV7PILongThunk_/d
-/ __ThumbV7PILongThunk_/d
-
-# mips lld
-/ __LA25Thunk_/d
-/ __microLA25Thunk_/d
+# lld arm/aarch64/mips thunks
+/ __[[:alnum:]]*Thunk_/d
 
 # CFI type identifiers
 / __kcfi_typeid_/d
index 267b9a0a3abcd849fe4f0bae4cddd8a287d26184..bf7c4b4b5ff45694322af0d6b221b6735ea1a739 100644 (file)
@@ -1848,7 +1848,7 @@ static void add_header(struct buffer *b, struct module *mod)
 
        buf_printf(b,
                   "\n"
-                  "#ifdef CONFIG_RETPOLINE\n"
+                  "#ifdef CONFIG_MITIGATION_RETPOLINE\n"
                   "MODULE_INFO(retpoline, \"Y\");\n"
                   "#endif\n");
 
index 31066bfdba04e30abffa2d4f3088760a0a3bc753..dc4878502276ce94bc7d3d8a213934a21751078a 100644 (file)
@@ -326,7 +326,12 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md)
 
        /* Sum all files in the same dir or subdirs. */
        while ((line = get_line(&pos))) {
-               char* p = line;
+               char* p;
+
+               /* trim the leading spaces away */
+               while (isspace(*line))
+                       line++;
+               p = line;
 
                if (strncmp(line, "source_", sizeof("source_")-1) == 0) {
                        p = strrchr(line, ' ');
index 98e1150bee9d0cbecb79c7e81cb05159f6160b04..9a3dcaafb5b1ee20c4d2d5d355d81302ead8d427 100644 (file)
@@ -784,7 +784,7 @@ static int apparmor_getselfattr(unsigned int attr, struct lsm_ctx __user *lx,
        int error = -ENOENT;
        struct aa_task_ctx *ctx = task_ctx(current);
        struct aa_label *label = NULL;
-       char *value;
+       char *value = NULL;
 
        switch (attr) {
        case LSM_ATTR_CURRENT:
index df387de29bfa54bf4bf0f7607a6837ec589ebfd5..45c3e5dda355e23f823086816d00e78071b1c15c 100644 (file)
@@ -179,7 +179,8 @@ static int __init integrity_add_key(const unsigned int id, const void *data,
                                   KEY_ALLOC_NOT_IN_QUOTA);
        if (IS_ERR(key)) {
                rc = PTR_ERR(key);
-               pr_err("Problem loading X.509 certificate %d\n", rc);
+               if (id != INTEGRITY_KEYRING_MACHINE)
+                       pr_err("Problem loading X.509 certificate %d\n", rc);
        } else {
                pr_notice("Loaded X.509 cert '%s'\n",
                          key_ref_to_ptr(key)->description);
index fc520a06f9af107310aa81050b8ad21accc6640d..0171f7eb6ee15d384835a6cd68a2afcff1f3b653 100644 (file)
@@ -737,8 +737,8 @@ static int current_check_refer_path(struct dentry *const old_dentry,
        bool allow_parent1, allow_parent2;
        access_mask_t access_request_parent1, access_request_parent2;
        struct path mnt_dir;
-       layer_mask_t layer_masks_parent1[LANDLOCK_NUM_ACCESS_FS],
-               layer_masks_parent2[LANDLOCK_NUM_ACCESS_FS];
+       layer_mask_t layer_masks_parent1[LANDLOCK_NUM_ACCESS_FS] = {},
+                    layer_masks_parent2[LANDLOCK_NUM_ACCESS_FS] = {};
 
        if (!dom)
                return 0;
index 3aaad75c9ce8531b6f214ad8bd469d1c571908c7..7035ee35a393020303304741092e6b016e02669c 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/backing-dev.h>
 #include <linux/string.h>
 #include <linux/msg.h>
+#include <linux/overflow.h>
 #include <net/flow.h>
 
 /* How many LSMs were built into the kernel? */
@@ -4015,6 +4016,7 @@ int security_setselfattr(unsigned int attr, struct lsm_ctx __user *uctx,
        struct security_hook_list *hp;
        struct lsm_ctx *lctx;
        int rc = LSM_RET_DEFAULT(setselfattr);
+       u64 required_len;
 
        if (flags)
                return -EINVAL;
@@ -4027,8 +4029,9 @@ int security_setselfattr(unsigned int attr, struct lsm_ctx __user *uctx,
        if (IS_ERR(lctx))
                return PTR_ERR(lctx);
 
-       if (size < lctx->len || size < lctx->ctx_len + sizeof(*lctx) ||
-           lctx->len < lctx->ctx_len + sizeof(*lctx)) {
+       if (size < lctx->len ||
+           check_add_overflow(sizeof(*lctx), lctx->ctx_len, &required_len) ||
+           lctx->len < required_len) {
                rc = -EINVAL;
                goto free_out;
        }
index a6bf90ace84c74bdb11330d7bb278183dfb13275..338b023a8c3edb5918d59a2bc07e23221507ff45 100644 (file)
@@ -6559,7 +6559,7 @@ static int selinux_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
                               size_t *size, u32 flags)
 {
        int rc;
-       char *val;
+       char *val = NULL;
        int val_len;
 
        val_len = selinux_lsm_getattr(attr, current, &val);
index 57ee70ae50f24ac771a7bd74d224c17b1ff03d25..ea3140d510ecbfee06666df588a795b9f5bfc5ce 100644 (file)
@@ -2649,13 +2649,14 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
 {
        int error = buffer_len;
        size_t avail_len = buffer_len;
-       char *cp0 = head->write_buf;
+       char *cp0;
        int idx;
 
        if (!head->write)
                return -EINVAL;
        if (mutex_lock_interruptible(&head->io_sem))
                return -EINTR;
+       cp0 = head->write_buf;
        head->read_user_buf_avail = 0;
        idx = tomoyo_read_lock();
        /* Read a line and dispatch it to the policy handler. */
index a6b444ee283264ca60e8d5673c4378f6175f128c..f6526b33713756071c14d4da2c7e051d1ae17bf9 100644 (file)
@@ -32,7 +32,6 @@ snd-ump-objs      := ump.o
 snd-ump-$(CONFIG_SND_UMP_LEGACY_RAWMIDI) += ump_convert.o
 snd-timer-objs    := timer.o
 snd-hrtimer-objs  := hrtimer.o
-snd-rtctimer-objs := rtctimer.o
 snd-hwdep-objs    := hwdep.o
 snd-seq-device-objs := seq_device.o
 
index f5ff00f99788a80135e2832f0cdb64650e3122d7..21baf6bf7e25a048e64d37331b0109f2ad7ec354 100644 (file)
@@ -486,6 +486,11 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
                i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
                if (snd_interval_single(i))
                        params->msbits = snd_interval_value(i);
+               m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
+               if (snd_mask_single(m)) {
+                       snd_pcm_format_t format = (__force snd_pcm_format_t)snd_mask_min(m);
+                       params->msbits = snd_pcm_format_width(format);
+               }
        }
 
        if (params->msbits) {
index 3bef1944e955ff24940c1cba0d0a82f79db33d6e..fe7911498cc4325a866a87328087c54a0a6c791a 100644 (file)
@@ -985,7 +985,7 @@ static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream)
        struct snd_ump_endpoint *ump = substream->rmidi->private_data;
        int dir = substream->stream;
        int group = ump->legacy_mapping[substream->number];
-       int err;
+       int err = 0;
 
        mutex_lock(&ump->open_mutex);
        if (ump->legacy_substreams[dir][group]) {
@@ -1009,7 +1009,7 @@ static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream)
        spin_unlock_irq(&ump->legacy_locks[dir]);
  unlock:
        mutex_unlock(&ump->open_mutex);
-       return 0;
+       return err;
 }
 
 static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream)
index a13c0b408aadfcc6d2f1f588cdd96a733961bf2a..7be17bca257f0ddba4799875c9250f96ba4e4b8a 100644 (file)
@@ -951,7 +951,7 @@ static int generate_tx_packet_descs(struct amdtp_stream *s, struct pkt_desc *des
                                // to the reason.
                                unsigned int safe_cycle = increment_ohci_cycle_count(next_cycle,
                                                                IR_JUMBO_PAYLOAD_MAX_SKIP_CYCLES);
-                               lost = (compare_ohci_cycle_count(safe_cycle, cycle) > 0);
+                               lost = (compare_ohci_cycle_count(safe_cycle, cycle) < 0);
                        }
                        if (lost) {
                                dev_err(&s->unit->device, "Detect discontinuity of cycle: %d %d\n",
index 21a90b3c4cc7300e0abfc301e34338170dd6b911..8e0ff70fb6101ff9b94aab0d79c4b6f7cf90498d 100644 (file)
@@ -156,7 +156,7 @@ config SND_HDA_SCODEC_CS35L56_I2C
        depends on I2C
        depends on ACPI || COMPILE_TEST
        depends on SND_SOC
-       select CS_DSP
+       select FW_CS_DSP
        select SND_HDA_GENERIC
        select SND_SOC_CS35L56_SHARED
        select SND_HDA_SCODEC_CS35L56
@@ -171,7 +171,7 @@ config SND_HDA_SCODEC_CS35L56_SPI
        depends on SPI_MASTER
        depends on ACPI || COMPILE_TEST
        depends on SND_SOC
-       select CS_DSP
+       select FW_CS_DSP
        select SND_HDA_GENERIC
        select SND_SOC_CS35L56_SHARED
        select SND_HDA_SCODEC_CS35L56
index d74cf11eef1ea6fcb1bae71b9c00aad87203de40..e436d4dab317f05c20a8a806f14e07580bfcb2de 100644 (file)
@@ -83,6 +83,7 @@ static const struct cs35l41_config cs35l41_config_table[] = {
        { "104317F3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
        { "10431863", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
        { "104318D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+       { "10431A83", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
        { "10431C9F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
        { "10431CAF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
        { "10431CCF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
@@ -91,10 +92,14 @@ static const struct cs35l41_config cs35l41_config_table[] = {
        { "10431D1F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
        { "10431DA2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
        { "10431E02", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+       { "10431E12", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
        { "10431EE2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
        { "10431F12", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
        { "10431F1F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },
        { "10431F62", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+       { "17AA386F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+       { "17AA38A9", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
+       { "17AA38AB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
        { "17AA38B4", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
        { "17AA38B5", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
        { "17AA38B6", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
@@ -419,6 +424,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
        { "CSC3551", "104317F3", generic_dsd_config },
        { "CSC3551", "10431863", generic_dsd_config },
        { "CSC3551", "104318D3", generic_dsd_config },
+       { "CSC3551", "10431A83", generic_dsd_config },
        { "CSC3551", "10431C9F", generic_dsd_config },
        { "CSC3551", "10431CAF", generic_dsd_config },
        { "CSC3551", "10431CCF", generic_dsd_config },
@@ -427,10 +433,14 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
        { "CSC3551", "10431D1F", generic_dsd_config },
        { "CSC3551", "10431DA2", generic_dsd_config },
        { "CSC3551", "10431E02", generic_dsd_config },
+       { "CSC3551", "10431E12", generic_dsd_config },
        { "CSC3551", "10431EE2", generic_dsd_config },
        { "CSC3551", "10431F12", generic_dsd_config },
        { "CSC3551", "10431F1F", generic_dsd_config },
        { "CSC3551", "10431F62", generic_dsd_config },
+       { "CSC3551", "17AA386F", generic_dsd_config },
+       { "CSC3551", "17AA38A9", generic_dsd_config },
+       { "CSC3551", "17AA38AB", generic_dsd_config },
        { "CSC3551", "17AA38B4", generic_dsd_config },
        { "CSC3551", "17AA38B5", generic_dsd_config },
        { "CSC3551", "17AA38B6", generic_dsd_config },
index 3e7bfeee84fdadf136108212e286fd16eb3c819d..efe98f6f19a373b9c343861cf9bdc2039885d7e2 100644 (file)
@@ -1207,6 +1207,9 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots)
                                dev_warn(chip->card->dev,
                                         "Codec #%d probe error; disabling it...\n", c);
                                bus->codec_mask &= ~(1 << c);
+                               /* no codecs */
+                               if (bus->codec_mask == 0)
+                                       break;
                                /* More badly, accessing to a non-existing
                                 * codec often screws up the controller chip,
                                 * and disturbs the further communications.
index e8819e8a98763cb5a4760768be387a4a387c384d..e8209178d87bbcc88551e6773c90c9fec7d98af2 100644 (file)
@@ -344,6 +344,7 @@ enum {
        CXT_FIXUP_HP_ZBOOK_MUTE_LED,
        CXT_FIXUP_HEADSET_MIC,
        CXT_FIXUP_HP_MIC_NO_PRESENCE,
+       CXT_PINCFG_SWS_JS201D,
 };
 
 /* for hda_fixup_thinkpad_acpi() */
@@ -841,6 +842,17 @@ static const struct hda_pintbl cxt_pincfg_lemote[] = {
        {}
 };
 
+/* SuoWoSi/South-holding JS201D with sn6140 */
+static const struct hda_pintbl cxt_pincfg_sws_js201d[] = {
+       { 0x16, 0x03211040 }, /* hp out */
+       { 0x17, 0x91170110 }, /* SPK/Class_D */
+       { 0x18, 0x95a70130 }, /* Internal mic */
+       { 0x19, 0x03a11020 }, /* Headset Mic */
+       { 0x1a, 0x40f001f0 }, /* Not used */
+       { 0x21, 0x40f001f0 }, /* Not used */
+       {}
+};
+
 static const struct hda_fixup cxt_fixups[] = {
        [CXT_PINCFG_LENOVO_X200] = {
                .type = HDA_FIXUP_PINS,
@@ -996,6 +1008,10 @@ static const struct hda_fixup cxt_fixups[] = {
                .chained = true,
                .chain_id = CXT_FIXUP_HEADSET_MIC,
        },
+       [CXT_PINCFG_SWS_JS201D] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cxt_pincfg_sws_js201d,
+       },
 };
 
 static const struct snd_pci_quirk cxt5045_fixups[] = {
@@ -1069,6 +1085,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x8458, "HP Z2 G4 mini premium", CXT_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
+       SND_PCI_QUIRK(0x14f1, 0x0265, "SWS JS201D", CXT_PINCFG_SWS_JS201D),
        SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
@@ -1109,6 +1126,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = {
        { .id = CXT_FIXUP_HP_ZBOOK_MUTE_LED, .name = "hp-zbook-mute-led" },
        { .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" },
        { .id = CXT_PINCFG_LENOVO_NOTEBOOK, .name = "lenovo-20149" },
+       { .id = CXT_PINCFG_SWS_JS201D, .name = "sws-js201d" },
        {}
 };
 
index 6994c4c5073cbb6fd5ad932186db35970c7cbd0f..a1facdb98d9a00a4236ff06c0f64700a0facd1cc 100644 (file)
@@ -3684,6 +3684,7 @@ static void alc285_hp_init(struct hda_codec *codec)
        int i, val;
        int coef38, coef0d, coef36;
 
+       alc_write_coefex_idx(codec, 0x58, 0x00, 0x1888); /* write default value */
        alc_update_coef_idx(codec, 0x4a, 1<<15, 1<<15); /* Reset HP JD */
        coef38 = alc_read_coef_idx(codec, 0x38); /* Amp control */
        coef0d = alc_read_coef_idx(codec, 0x0d); /* Digital Misc control */
@@ -7444,6 +7445,7 @@ enum {
        ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE,
        ALC287_FIXUP_YOGA7_14ITL_SPEAKERS,
        ALC298_FIXUP_LENOVO_C940_DUET7,
+       ALC287_FIXUP_LENOVO_14IRP8_DUETITL,
        ALC287_FIXUP_13S_GEN2_SPEAKERS,
        ALC256_FIXUP_SET_COEF_DEFAULTS,
        ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
@@ -7495,6 +7497,26 @@ static void alc298_fixup_lenovo_c940_duet7(struct hda_codec *codec,
        __snd_hda_apply_fixup(codec, id, action, 0);
 }
 
+/* A special fixup for Lenovo Slim/Yoga Pro 9 14IRP8 and Yoga DuetITL 2021;
+ * 14IRP8 PCI SSID will mistakenly be matched with the DuetITL codec SSID,
+ * so we need to apply a different fixup in this case. The only DuetITL codec
+ * SSID reported so far is the 17aa:3802 while the 14IRP8 has the 17aa:38be
+ * and 17aa:38bf. If it weren't for the PCI SSID, the 14IRP8 models would
+ * have matched correctly by their codecs.
+ */
+static void alc287_fixup_lenovo_14irp8_duetitl(struct hda_codec *codec,
+                                             const struct hda_fixup *fix,
+                                             int action)
+{
+       int id;
+
+       if (codec->core.subsystem_id == 0x17aa3802)
+               id = ALC287_FIXUP_YOGA7_14ITL_SPEAKERS; /* DuetITL */
+       else
+               id = ALC287_FIXUP_TAS2781_I2C; /* 14IRP8 */
+       __snd_hda_apply_fixup(codec, id, action, 0);
+}
+
 static const struct hda_fixup alc269_fixups[] = {
        [ALC269_FIXUP_GPIO2] = {
                .type = HDA_FIXUP_FUNC,
@@ -9379,6 +9401,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc298_fixup_lenovo_c940_duet7,
        },
+       [ALC287_FIXUP_LENOVO_14IRP8_DUETITL] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_lenovo_14irp8_duetitl,
+       },
        [ALC287_FIXUP_13S_GEN2_SPEAKERS] = {
                .type = HDA_FIXUP_VERBS,
                .v.verbs = (const struct hda_verb[]) {
@@ -9585,7 +9611,7 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = tas2781_fixup_i2c,
                .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+               .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
        },
        [ALC287_FIXUP_YOGA7_14ARB7_I2C] = {
                .type = HDA_FIXUP_FUNC,
@@ -9737,13 +9763,16 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
        SND_PCI_QUIRK(0x1028, 0x0beb, "Dell XPS 15 9530 (2023)", ALC289_FIXUP_DELL_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1028, 0x0c03, "Dell Precision 5340", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0c0b, "Dell Oasis 14 RPL-P", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
        SND_PCI_QUIRK(0x1028, 0x0c0d, "Dell Oasis", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x0c0e, "Dell Oasis 16", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
        SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
        SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
        SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
        SND_PCI_QUIRK(0x1028, 0x0c1c, "Dell Precision 3540", ALC236_FIXUP_DELL_DUAL_CODECS),
        SND_PCI_QUIRK(0x1028, 0x0c1d, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
        SND_PCI_QUIRK(0x1028, 0x0c1e, "Dell Precision 3540", ALC236_FIXUP_DELL_DUAL_CODECS),
+       SND_PCI_QUIRK(0x1028, 0x0c28, "Dell Inspiron 16 Plus 7630", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
        SND_PCI_QUIRK(0x1028, 0x0c4d, "Dell", ALC287_FIXUP_CS35L41_I2C_4),
        SND_PCI_QUIRK(0x1028, 0x0cbd, "Dell Oasis 13 CS MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1028, 0x0cbe, "Dell Oasis 13 2-IN-1 MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
@@ -9900,6 +9929,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8973, "HP EliteBook 860 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8974, "HP EliteBook 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8975, "HP EliteBook x360 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x897d, "HP mt440 Mobile Thin Client U74", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8981, "HP Elite Dragonfly G3", ALC245_FIXUP_CS35L41_SPI_4),
        SND_PCI_QUIRK(0x103c, 0x898e, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x898f, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2),
@@ -9925,16 +9955,20 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8aa8, "HP EliteBook 640 G9 (MB 8AA6)", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8aab, "HP EliteBook 650 G9 (MB 8AA9)", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ab9, "HP EliteBook 840 G8 (MB 8AB8)", ALC285_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b0f, "HP Elite mt645 G7 Mobile Thin Client U81", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8b2f, "HP 255 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x8b3f, "HP mt440 Mobile Thin Client U91", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b42, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b43, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b44, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b45, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b46, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b47, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b59, "HP Elite mt645 G7 Mobile Thin Client U89", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8b63, "HP Elite Dragonfly 13.5 inch G4", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
@@ -9962,6 +9996,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8c70, "HP EliteBook 835 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c71, "HP EliteBook 845 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c8a, "HP EliteBook 630", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c8c, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c90, "HP EliteBook 640", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c91, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8c97, "HP ZBook", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8ca1, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
@@ -10003,6 +10041,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
        SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC),
        SND_PCI_QUIRK(0x1043, 0x1683, "ASUS UM3402YAR", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC245_FIXUP_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x16d3, "ASUS UX5304VA", ALC245_FIXUP_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
@@ -10046,14 +10085,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE),
        SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1f62, "ASUS UX7602ZM", ALC245_FIXUP_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
-       SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS),
        SND_PCI_QUIRK(0x1043, 0x1e5e, "ASUS ROG Strix G513", ALC294_FIXUP_ASUS_G513_PINS),
        SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
-       SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2),
@@ -10244,7 +10281,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340),
        SND_PCI_QUIRK(0x17aa, 0x334b, "Lenovo ThinkCentre M70 Gen5", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8 / DuetITL 2021", ALC287_FIXUP_LENOVO_14IRP8_DUETITL),
        SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7),
        SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS),
@@ -10260,6 +10297,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6),
        SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x386f, "Legion 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C),
        SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC", ALC287_FIXUP_TAS2781_I2C),
        SND_PCI_QUIRK(0x17aa, 0x387e, "Yoga S780-16 pro Quad YC", ALC287_FIXUP_TAS2781_I2C),
@@ -10269,6 +10307,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
        SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual", ALC287_FIXUP_TAS2781_I2C),
        SND_PCI_QUIRK(0x17aa, 0x38a8, "Y780P AMD VECO dual", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38a9, "Thinkbook 16P", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x17aa, 0x38ab, "Thinkbook 16P", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x17aa, 0x38b4, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x17aa, 0x38b5, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x17aa, 0x38b6, "Legion Slim 7 16APH8", ALC287_FIXUP_CS35L41_I2C_2),
@@ -10961,6 +11001,8 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
  *   at most one tbl is allowed to define for the same vendor and same codec
  */
 static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = {
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1025, "Acer", ALC2XX_FIXUP_HEADSET_MIC,
+               {0x19, 0x40000000}),
        SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
                {0x19, 0x40000000},
                {0x1b, 0x40000000}),
@@ -11650,8 +11692,7 @@ static void alc897_hp_automute_hook(struct hda_codec *codec,
 
        snd_hda_gen_hp_automute(codec, jack);
        vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
-       snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           vref);
+       snd_hda_set_pin_ctl(codec, 0x1b, vref);
 }
 
 static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
@@ -11660,6 +11701,10 @@ static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
        struct alc_spec *spec = codec->spec;
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
                spec->gen.hp_automute_hook = alc897_hp_automute_hook;
+               spec->no_shutup_pins = 1;
+       }
+       if (action == HDA_FIXUP_ACT_PROBE) {
+               snd_hda_set_pin_ctl_cache(codec, 0x1a, PIN_IN | AC_PINCTL_VREF_100);
        }
 }
 
index 2dd809de62e5a4ac049a49752f447b0a8b4a3be6..1bfb00102a77a4d49695efeaf7016eded961345b 100644 (file)
@@ -710,7 +710,7 @@ static int tas2781_hda_bind(struct device *dev, struct device *master,
 
        strscpy(comps->name, dev_name(dev), sizeof(comps->name));
 
-       ret = tascodec_init(tas_hda->priv, codec, tasdev_fw_ready);
+       ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready);
        if (!ret)
                comps->playback_hook = tas2781_hda_playback_hook;
 
index 23d44a50d8157212aa5bbaa49ecd1e9acbe9aa00..90360f8b3e81b9374680058256f59efd96ad822d 100644 (file)
@@ -199,6 +199,20 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "21HY"),
                }
        },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "21J2"),
+               }
+       },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "21J0"),
+               }
+       },
        {
                .driver_data = &acp6x_card,
                .matches = {
@@ -234,6 +248,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "82UG"),
                }
        },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "82UU"),
+               }
+       },
        {
                .driver_data = &acp6x_card,
                .matches = {
@@ -248,6 +269,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "82YM"),
                }
        },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "83AS"),
+               }
+       },
        {
                .driver_data = &acp6x_card,
                .matches = {
@@ -388,6 +416,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "8B2F"),
                }
        },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+                       DMI_MATCH(DMI_BOARD_NAME, "8BD6"),
+               }
+       },
        {
                .driver_data = &acp6x_card,
                .matches = {
index 7af6a349b1d41fb60d9450a312927e4774889a34..694b8e31390248b88e4bc8aba843316244f0bdb4 100644 (file)
@@ -162,6 +162,7 @@ static int snd_acp6x_probe(struct pci_dev *pci,
        /* Yellow Carp device check */
        switch (pci->revision) {
        case 0x60:
+       case 0x63:
        case 0x6f:
                break;
        default:
index 44c221745c3b255c7e69a4ab092ad09581a9b1f9..2392c6effed857c32326ee032f776dcc577ed0fb 100644 (file)
@@ -184,7 +184,7 @@ static int cs35l45_activate_ctl(struct snd_soc_component *component,
        else
                snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s", ctl_name);
 
-       kcontrol = snd_soc_card_get_kcontrol(component->card, name);
+       kcontrol = snd_soc_card_get_kcontrol_locked(component->card, name);
        if (!kcontrol) {
                dev_err(component->dev, "Can't find kcontrol %s\n", name);
                return -EINVAL;
index 02fba4bc0a14f4cc44690ffed69bd5217409b6e9..cb4e83126b085228fa196aeb7e635537c39cfc24 100644 (file)
@@ -51,7 +51,6 @@ static const struct reg_default cs35l56_reg_defaults[] = {
        { CS35L56_SWIRE_DP3_CH2_INPUT,          0x00000019 },
        { CS35L56_SWIRE_DP3_CH3_INPUT,          0x00000029 },
        { CS35L56_SWIRE_DP3_CH4_INPUT,          0x00000028 },
-       { CS35L56_IRQ1_CFG,                     0x00000000 },
        { CS35L56_IRQ1_MASK_1,                  0x83ffffff },
        { CS35L56_IRQ1_MASK_2,                  0xffff7fff },
        { CS35L56_IRQ1_MASK_4,                  0xe0ffffff },
@@ -336,6 +335,7 @@ void cs35l56_wait_min_reset_pulse(void)
 EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, SND_SOC_CS35L56_SHARED);
 
 static const struct reg_sequence cs35l56_system_reset_seq[] = {
+       REG_SEQ0(CS35L56_DSP1_HALO_STATE, 0),
        REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
 };
 
index c23e29da4cfb9f43fa52611fdeea96adad4a0b30..6dd0319bc843cf5d1740222e57c380881b4b5b05 100644 (file)
@@ -5,6 +5,7 @@
 // Copyright (C) 2023 Cirrus Logic, Inc. and
 //                    Cirrus Logic International Semiconductor Ltd.
 
+#include <linux/acpi.h>
 #include <linux/completion.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
@@ -15,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
+#include <linux/property.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
@@ -68,63 +70,7 @@ static const char * const cs35l56_asp1_mux_control_names[] = {
        "ASP1 TX1 Source", "ASP1 TX2 Source", "ASP1 TX3 Source", "ASP1 TX4 Source"
 };
 
-static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol,
-                                     struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
-       struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
-       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       int index = e->shift_l;
-       unsigned int addr, val;
-       int ret;
-
-       /* Wait for mux to be initialized */
-       cs35l56_wait_dsp_ready(cs35l56);
-       flush_work(&cs35l56->mux_init_work);
-
-       addr = cs35l56_asp1_mixer_regs[index];
-       ret = regmap_read(cs35l56->base.regmap, addr, &val);
-       if (ret)
-               return ret;
-
-       val &= CS35L56_ASP_TXn_SRC_MASK;
-       ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
-
-       return 0;
-}
-
-static int cs35l56_dspwait_asp1tx_put(struct snd_kcontrol *kcontrol,
-                                     struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
-       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
-       struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
-       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       int item = ucontrol->value.enumerated.item[0];
-       int index = e->shift_l;
-       unsigned int addr, val;
-       bool changed;
-       int ret;
-
-       /* Wait for mux to be initialized */
-       cs35l56_wait_dsp_ready(cs35l56);
-       flush_work(&cs35l56->mux_init_work);
-
-       addr = cs35l56_asp1_mixer_regs[index];
-       val = snd_soc_enum_item_to_val(e, item);
-
-       ret = regmap_update_bits_check(cs35l56->base.regmap, addr,
-                                      CS35L56_ASP_TXn_SRC_MASK, val, &changed);
-       if (!ret)
-               return ret;
-
-       if (changed)
-               snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
-
-       return changed;
-}
-
-static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l56)
+static int cs35l56_sync_asp1_mixer_widgets_with_firmware(struct cs35l56_private *cs35l56)
 {
        struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cs35l56->component);
        const char *prefix = cs35l56->component->name_prefix;
@@ -135,13 +81,19 @@ static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l5
        unsigned int val[4];
        int i, item, ret;
 
+       if (cs35l56->asp1_mixer_widgets_initialized)
+               return 0;
+
        /*
         * Resume so we can read the registers from silicon if the regmap
         * cache has not yet been populated.
         */
        ret = pm_runtime_resume_and_get(cs35l56->base.dev);
        if (ret < 0)
-               return;
+               return ret;
+
+       /* Wait for firmware download and reboot */
+       cs35l56_wait_dsp_ready(cs35l56);
 
        ret = regmap_bulk_read(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT,
                               val, ARRAY_SIZE(val));
@@ -151,12 +103,9 @@ static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l5
 
        if (ret) {
                dev_err(cs35l56->base.dev, "Failed to read ASP1 mixer regs: %d\n", ret);
-               return;
+               return ret;
        }
 
-       snd_soc_card_mutex_lock(dapm->card);
-       WARN_ON(!dapm->card->instantiated);
-
        for (i = 0; i < ARRAY_SIZE(cs35l56_asp1_mux_control_names); ++i) {
                name = cs35l56_asp1_mux_control_names[i];
 
@@ -165,7 +114,7 @@ static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l5
                        name = full_name;
                }
 
-               kcontrol = snd_soc_card_get_kcontrol(dapm->card, name);
+               kcontrol = snd_soc_card_get_kcontrol_locked(dapm->card, name);
                if (!kcontrol) {
                        dev_warn(cs35l56->base.dev, "Could not find control %s\n", name);
                        continue;
@@ -176,16 +125,65 @@ static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l5
                snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
        }
 
-       snd_soc_card_mutex_unlock(dapm->card);
+       cs35l56->asp1_mixer_widgets_initialized = true;
+
+       return 0;
 }
 
-static void cs35l56_mux_init_work(struct work_struct *work)
+static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
 {
-       struct cs35l56_private *cs35l56 = container_of(work,
-                                                      struct cs35l56_private,
-                                                      mux_init_work);
+       struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+       struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int index = e->shift_l;
+       unsigned int addr, val;
+       int ret;
+
+       ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56);
+       if (ret)
+               return ret;
+
+       addr = cs35l56_asp1_mixer_regs[index];
+       ret = regmap_read(cs35l56->base.regmap, addr, &val);
+       if (ret)
+               return ret;
+
+       val &= CS35L56_ASP_TXn_SRC_MASK;
+       ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
+
+       return 0;
+}
+
+static int cs35l56_dspwait_asp1tx_put(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int item = ucontrol->value.enumerated.item[0];
+       int index = e->shift_l;
+       unsigned int addr, val;
+       bool changed;
+       int ret;
 
-       cs35l56_mark_asp1_mixer_widgets_dirty(cs35l56);
+       ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56);
+       if (ret)
+               return ret;
+
+       addr = cs35l56_asp1_mixer_regs[index];
+       val = snd_soc_enum_item_to_val(e, item);
+
+       ret = regmap_update_bits_check(cs35l56->base.regmap, addr,
+                                      CS35L56_ASP_TXn_SRC_MASK, val, &changed);
+       if (ret)
+               return ret;
+
+       if (changed)
+               snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
+
+       return changed;
 }
 
 static DECLARE_TLV_DB_SCALE(vol_tlv, -10000, 25, 0);
@@ -936,14 +934,6 @@ static void cs35l56_dsp_work(struct work_struct *work)
        else
                cs35l56_patch(cs35l56, firmware_missing);
 
-
-       /*
-        * Set starting value of ASP1 mux widgets. Updating a mux takes
-        * the DAPM mutex. Post this to a separate job so that DAPM
-        * power-up can wait for dsp_work to complete without deadlocking
-        * on the DAPM mutex.
-        */
-       queue_work(cs35l56->dsp_wq, &cs35l56->mux_init_work);
 err:
        pm_runtime_mark_last_busy(cs35l56->base.dev);
        pm_runtime_put_autosuspend(cs35l56->base.dev);
@@ -989,6 +979,13 @@ static int cs35l56_component_probe(struct snd_soc_component *component)
        debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate);
        debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched);
 
+       /*
+        * The widgets for the ASP1TX mixer can't be initialized
+        * until the firmware has been downloaded and rebooted.
+        */
+       regcache_drop_region(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT, CS35L56_ASP1TX4_INPUT);
+       cs35l56->asp1_mixer_widgets_initialized = false;
+
        queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
 
        return 0;
@@ -999,7 +996,6 @@ static void cs35l56_component_remove(struct snd_soc_component *component)
        struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
 
        cancel_work_sync(&cs35l56->dsp_work);
-       cancel_work_sync(&cs35l56->mux_init_work);
 
        if (cs35l56->dsp.cs_dsp.booted)
                wm_adsp_power_down(&cs35l56->dsp);
@@ -1070,10 +1066,8 @@ int cs35l56_system_suspend(struct device *dev)
 
        dev_dbg(dev, "system_suspend\n");
 
-       if (cs35l56->component) {
+       if (cs35l56->component)
                flush_work(&cs35l56->dsp_work);
-               cancel_work_sync(&cs35l56->mux_init_work);
-       }
 
        /*
         * The interrupt line is normally shared, but after we start suspending
@@ -1224,7 +1218,6 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56)
                return -ENOMEM;
 
        INIT_WORK(&cs35l56->dsp_work, cs35l56_dsp_work);
-       INIT_WORK(&cs35l56->mux_init_work, cs35l56_mux_init_work);
 
        dsp = &cs35l56->dsp;
        cs35l56_init_cs_dsp(&cs35l56->base, &dsp->cs_dsp);
@@ -1269,6 +1262,94 @@ static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56)
        return 0;
 }
 
+/*
+ * Some SoundWire laptops have a spk-id-gpios property but it points to
+ * the wrong ACPI Device node so can't be used to get the GPIO. Try to
+ * find the SDCA node containing the GpioIo resource and add a GPIO
+ * mapping to it.
+ */
+static const struct acpi_gpio_params cs35l56_af01_first_gpio = { 0, 0, false };
+static const struct acpi_gpio_mapping cs35l56_af01_spkid_gpios_mapping[] = {
+       { "spk-id-gpios", &cs35l56_af01_first_gpio, 1 },
+       { }
+};
+
+static void cs35l56_acpi_dev_release_driver_gpios(void *adev)
+{
+       acpi_dev_remove_driver_gpios(adev);
+}
+
+static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l56)
+{
+       struct fwnode_handle *af01_fwnode;
+       const union acpi_object *obj;
+       struct gpio_desc *desc;
+       int ret;
+
+       /* Find the SDCA node containing the GpioIo */
+       af01_fwnode = device_get_named_child_node(cs35l56->base.dev, "AF01");
+       if (!af01_fwnode) {
+               dev_dbg(cs35l56->base.dev, "No AF01 node\n");
+               return -ENOENT;
+       }
+
+       ret = acpi_dev_get_property(ACPI_COMPANION(cs35l56->base.dev),
+                                   "spk-id-gpios", ACPI_TYPE_PACKAGE, &obj);
+       if (ret) {
+               dev_dbg(cs35l56->base.dev, "Could not get spk-id-gpios package: %d\n", ret);
+               return -ENOENT;
+       }
+
+       /* The broken properties we can handle are a 4-element package (one GPIO) */
+       if (obj->package.count != 4) {
+               dev_warn(cs35l56->base.dev, "Unexpected spk-id element count %d\n",
+                        obj->package.count);
+               return -ENOENT;
+       }
+
+       /* Add a GPIO mapping if it doesn't already have one */
+       if (!fwnode_property_present(af01_fwnode, "spk-id-gpios")) {
+               struct acpi_device *adev = to_acpi_device_node(af01_fwnode);
+
+               /*
+                * Can't use devm_acpi_dev_add_driver_gpios() because the
+                * mapping isn't being added to the node pointed to by
+                * ACPI_COMPANION().
+                */
+               ret = acpi_dev_add_driver_gpios(adev, cs35l56_af01_spkid_gpios_mapping);
+               if (ret) {
+                       return dev_err_probe(cs35l56->base.dev, ret,
+                                            "Failed to add gpio mapping to AF01\n");
+               }
+
+               ret = devm_add_action_or_reset(cs35l56->base.dev,
+                                              cs35l56_acpi_dev_release_driver_gpios,
+                                              adev);
+               if (ret)
+                       return ret;
+
+               dev_dbg(cs35l56->base.dev, "Added spk-id-gpios mapping to AF01\n");
+       }
+
+       desc = fwnode_gpiod_get_index(af01_fwnode, "spk-id", 0, GPIOD_IN, NULL);
+       if (IS_ERR(desc)) {
+               ret = PTR_ERR(desc);
+               return dev_err_probe(cs35l56->base.dev, ret, "Get GPIO from AF01 failed\n");
+       }
+
+       ret = gpiod_get_value_cansleep(desc);
+       gpiod_put(desc);
+
+       if (ret < 0) {
+               dev_err_probe(cs35l56->base.dev, ret, "Error reading spk-id GPIO\n");
+               return ret;
+               }
+
+       dev_info(cs35l56->base.dev, "Got spk-id from AF01\n");
+
+       return ret;
+}
+
 int cs35l56_common_probe(struct cs35l56_private *cs35l56)
 {
        int ret;
@@ -1313,6 +1394,9 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
        }
 
        ret = cs35l56_get_speaker_id(&cs35l56->base);
+       if (ACPI_COMPANION(cs35l56->base.dev) && cs35l56->sdw_peripheral && (ret == -ENOENT))
+               ret = cs35l56_try_get_broken_sdca_spkid_gpio(cs35l56);
+
        if ((ret < 0) && (ret != -ENOENT))
                goto err;
 
index 596b141e3f9612389cae4c6b80eab20f4f90fd69..b000e7365e4065eaffc3b3ea2aa2714b9acccdfd 100644 (file)
@@ -34,7 +34,6 @@ struct cs35l56_private {
        struct wm_adsp dsp; /* must be first member */
        struct cs35l56_base base;
        struct work_struct dsp_work;
-       struct work_struct mux_init_work;
        struct workqueue_struct *dsp_wq;
        struct snd_soc_component *component;
        struct regulator_bulk_data supplies[CS35L56_NUM_BULK_SUPPLIES];
@@ -52,6 +51,7 @@ struct cs35l56_private {
        u8 asp_slot_count;
        bool tdm_mode;
        bool sysclk_set;
+       bool asp1_mixer_widgets_initialized;
        u8 old_sdw_clock_scale;
 };
 
index 6a64681767de8122d06bee23b5a21674d930bf57..a97ccb512deba86305ff433fa5b639fdfbb8dcbe 100644 (file)
@@ -2257,7 +2257,10 @@ static int cs42l43_codec_probe(struct platform_device *pdev)
        pm_runtime_use_autosuspend(priv->dev);
        pm_runtime_set_active(priv->dev);
        pm_runtime_get_noresume(priv->dev);
-       devm_pm_runtime_enable(priv->dev);
+
+       ret = devm_pm_runtime_enable(priv->dev);
+       if (ret)
+               goto err_pm;
 
        for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++) {
                ret = cs42l43_request_irq(priv, dom, cs42l43_irqs[i].name,
@@ -2333,8 +2336,47 @@ static int cs42l43_codec_runtime_resume(struct device *dev)
        return 0;
 }
 
-static DEFINE_RUNTIME_DEV_PM_OPS(cs42l43_codec_pm_ops, NULL,
-                                cs42l43_codec_runtime_resume, NULL);
+static int cs42l43_codec_suspend(struct device *dev)
+{
+       struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
+
+       disable_irq(cs42l43->irq);
+
+       return 0;
+}
+
+static int cs42l43_codec_suspend_noirq(struct device *dev)
+{
+       struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
+
+       enable_irq(cs42l43->irq);
+
+       return 0;
+}
+
+static int cs42l43_codec_resume(struct device *dev)
+{
+       struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
+
+       enable_irq(cs42l43->irq);
+
+       return 0;
+}
+
+static int cs42l43_codec_resume_noirq(struct device *dev)
+{
+       struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
+
+       disable_irq(cs42l43->irq);
+
+       return 0;
+}
+
+static const struct dev_pm_ops cs42l43_codec_pm_ops = {
+       SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, cs42l43_codec_resume)
+       NOIRQ_SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend_noirq, cs42l43_codec_resume_noirq)
+       RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL)
+};
 
 static const struct platform_device_id cs42l43_codec_id_table[] = {
        { "cs42l43-codec", },
index b9f19fbd2911453803f07413fa33d2c947730ae2..b24d6472ad5fc91b43179a41b4935b53ca44c95f 100644 (file)
@@ -3884,7 +3884,7 @@ static inline int madera_set_fll_clks(struct madera_fll *fll, int base, bool ena
        return madera_set_fll_clks_reg(fll, ena,
                                       base + MADERA_FLL_CONTROL_6_OFFS,
                                       MADERA_FLL1_REFCLK_SRC_MASK,
-                                      MADERA_FLL1_REFCLK_DIV_SHIFT);
+                                      MADERA_FLL1_REFCLK_SRC_SHIFT);
 }
 
 static inline int madera_set_fllao_clks(struct madera_fll *fll, int base, bool ena)
index 5150d6ee374810f34a881dd33d4ea57187e13522..20191a4473c2d2c7b4ae6bddf34109a403b84e3d 100644 (file)
@@ -3317,6 +3317,7 @@ static void rt5645_jack_detect_work(struct work_struct *work)
                                    report, SND_JACK_HEADPHONE);
                snd_soc_jack_report(rt5645->mic_jack,
                                    report, SND_JACK_MICROPHONE);
+               mutex_unlock(&rt5645->jd_mutex);
                return;
        case 4:
                val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020;
@@ -3692,6 +3693,11 @@ static const struct rt5645_platform_data jd_mode3_monospk_platform_data = {
        .mono_speaker = true,
 };
 
+static const struct rt5645_platform_data jd_mode3_inv_data = {
+       .jd_mode = 3,
+       .inv_jd1_1 = true,
+};
+
 static const struct rt5645_platform_data jd_mode3_platform_data = {
        .jd_mode = 3,
 };
@@ -3837,6 +3843,16 @@ static const struct dmi_system_id dmi_platform_data[] = {
                  DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
                  DMI_EXACT_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
                  DMI_EXACT_MATCH(DMI_BOARD_VERSION, "Default string"),
+                 /*
+                  * Above strings are too generic, LattePanda BIOS versions for
+                  * all 4 hw revisions are:
+                  * DF-BI-7-S70CR100-*
+                  * DF-BI-7-S70CR110-*
+                  * DF-BI-7-S70CR200-*
+                  * LP-BS-7-S70CR700-*
+                  * Do a partial match for S70CR to avoid false positive matches.
+                  */
+                 DMI_MATCH(DMI_BIOS_VERSION, "S70CR"),
                },
                .driver_data = (void *)&lattepanda_board_platform_data,
        },
@@ -3871,6 +3887,16 @@ static const struct dmi_system_id dmi_platform_data[] = {
                },
                .driver_data = (void *)&intel_braswell_platform_data,
        },
+       {
+               .ident = "Meegopad T08",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Default string"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
+                       DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"),
+                       DMI_MATCH(DMI_BOARD_VERSION, "V1.1"),
+               },
+               .driver_data = (void *)&jd_mode3_inv_data,
+       },
        { }
 };
 
index b7e56ceb1acff9f41e6a26f09e1c4395ff537553..5d0e5348b361a568475fd1fde3a299a57926b365 100644 (file)
@@ -267,6 +267,7 @@ void tas2781_reset(struct tasdevice_priv *tas_dev)
 EXPORT_SYMBOL_GPL(tas2781_reset);
 
 int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
+       struct module *module,
        void (*cont)(const struct firmware *fw, void *context))
 {
        int ret = 0;
@@ -280,7 +281,7 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
                tas_priv->dev_name, tas_priv->ndev);
        crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL);
        tas_priv->codec = codec;
-       ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
+       ret = request_firmware_nowait(module, FW_ACTION_UEVENT,
                tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv,
                cont);
        if (ret)
index 32913bd1a623381ee6e8d3d72c3f8e49d60ff0f7..b5abff230e43701f0f00c7b19f895469305747d7 100644 (file)
@@ -566,7 +566,7 @@ static int tasdevice_codec_probe(struct snd_soc_component *codec)
 {
        struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 
-       return tascodec_init(tas_priv, codec, tasdevice_fw_ready);
+       return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready);
 }
 
 static void tasdevice_deinit(void *context)
index fb90ae6a8a344acade2ef3cdee183491b218159d..7c6ed29831285f6bd08ceba939684e8958ea21cc 100644 (file)
@@ -2229,6 +2229,9 @@ SND_SOC_DAPM_PGA_E("HPOUT", SND_SOC_NOPM, 0, 0, NULL, 0, hp_event,
 
 SND_SOC_DAPM_OUTPUT("HPOUTL"),
 SND_SOC_DAPM_OUTPUT("HPOUTR"),
+
+SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
 };
 
 static const struct snd_soc_dapm_widget wm8962_dapm_spk_mono_widgets[] = {
@@ -2236,7 +2239,6 @@ SND_SOC_DAPM_MIXER("Speaker Mixer", WM8962_MIXER_ENABLES, 1, 0,
                   spkmixl, ARRAY_SIZE(spkmixl)),
 SND_SOC_DAPM_MUX_E("Speaker PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
                   out_pga_event, SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA("Speaker Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
 SND_SOC_DAPM_OUTPUT("SPKOUT"),
 };
 
@@ -2251,9 +2253,6 @@ SND_SOC_DAPM_MUX_E("SPKOUTL PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
 SND_SOC_DAPM_MUX_E("SPKOUTR PGA", WM8962_PWR_MGMT_2, 3, 0, &spkoutr_mux,
                   out_pga_event, SND_SOC_DAPM_POST_PMU),
 
-SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
-SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0),
-
 SND_SOC_DAPM_OUTPUT("SPKOUTL"),
 SND_SOC_DAPM_OUTPUT("SPKOUTR"),
 };
@@ -2366,12 +2365,18 @@ static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = {
        { "Speaker PGA", "Mixer", "Speaker Mixer" },
        { "Speaker PGA", "DAC", "DACL" },
 
-       { "Speaker Output", NULL, "Speaker PGA" },
-       { "Speaker Output", NULL, "SYSCLK" },
-       { "Speaker Output", NULL, "TOCLK" },
-       { "Speaker Output", NULL, "TEMP_SPK" },
+       { "SPKOUTL Output", NULL, "Speaker PGA" },
+       { "SPKOUTL Output", NULL, "SYSCLK" },
+       { "SPKOUTL Output", NULL, "TOCLK" },
+       { "SPKOUTL Output", NULL, "TEMP_SPK" },
 
-       { "SPKOUT", NULL, "Speaker Output" },
+       { "SPKOUTR Output", NULL, "Speaker PGA" },
+       { "SPKOUTR Output", NULL, "SYSCLK" },
+       { "SPKOUTR Output", NULL, "TOCLK" },
+       { "SPKOUTR Output", NULL, "TEMP_SPK" },
+
+       { "SPKOUT", NULL, "SPKOUTL Output" },
+       { "SPKOUT", NULL, "SPKOUTR Output" },
 };
 
 static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
@@ -2914,8 +2919,12 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
        switch (fll_id) {
        case WM8962_FLL_MCLK:
        case WM8962_FLL_BCLK:
+               fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT;
+               break;
        case WM8962_FLL_OSC:
                fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT;
+               snd_soc_component_update_bits(component, WM8962_PLL2,
+                                             WM8962_OSC_ENA, WM8962_OSC_ENA);
                break;
        case WM8962_FLL_INT:
                snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
@@ -2924,7 +2933,7 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
                                    WM8962_FLL_FRC_NCO, WM8962_FLL_FRC_NCO);
                break;
        default:
-               dev_err(component->dev, "Unknown FLL source %d\n", ret);
+               dev_err(component->dev, "Unknown FLL source %d\n", source);
                return -EINVAL;
        }
 
index f0fb33d719c25135722014f9763c65df3289ed7e..c46f64557a7ffd268716e852dfe4411251da08cc 100644 (file)
@@ -174,7 +174,9 @@ static int fsl_xcvr_activate_ctl(struct snd_soc_dai *dai, const char *name,
        struct snd_kcontrol *kctl;
        bool enabled;
 
-       kctl = snd_soc_card_get_kcontrol(card, name);
+       lockdep_assert_held(&card->snd_card->controls_rwsem);
+
+       kctl = snd_soc_card_get_kcontrol_locked(card, name);
        if (kctl == NULL)
                return -ENOENT;
 
@@ -576,10 +578,14 @@ static int fsl_xcvr_startup(struct snd_pcm_substream *substream,
        xcvr->streams |= BIT(substream->stream);
 
        if (!xcvr->soc_data->spdif_only) {
+               struct snd_soc_card *card = dai->component->card;
+
                /* Disable XCVR controls if there is stream started */
+               down_read(&card->snd_card->controls_rwsem);
                fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, false);
                fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, false);
                fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, false);
+               up_read(&card->snd_card->controls_rwsem);
        }
 
        return 0;
@@ -598,11 +604,15 @@ static void fsl_xcvr_shutdown(struct snd_pcm_substream *substream,
        /* Enable XCVR controls if there is no stream started */
        if (!xcvr->streams) {
                if (!xcvr->soc_data->spdif_only) {
+                       struct snd_soc_card *card = dai->component->card;
+
+                       down_read(&card->snd_card->controls_rwsem);
                        fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, true);
                        fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
                                                (xcvr->mode == FSL_XCVR_MODE_ARC));
                        fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
                                                (xcvr->mode == FSL_XCVR_MODE_EARC));
+                       up_read(&card->snd_card->controls_rwsem);
                }
                ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
                                         FSL_XCVR_IRQ_EARC_ALL, 0);
index 59c3793f65df0c5573ec6e7f873ef33d31f46371..db78eb2f0108071736b6bafa5e77f874b15f3375 100644 (file)
@@ -477,6 +477,9 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
        return 0;
 
 err_i915_init:
+       pci_free_irq(pci, 0, adev);
+       pci_free_irq(pci, 0, bus);
+       pci_free_irq_vectors(pci);
        pci_clear_master(pci);
        pci_set_drvdata(pci, NULL);
 err_acquire_irq:
index 778236d3fd2806912120ab0eb953f96a6c79c90b..48b3c67c91032c97b7da54e9d822876f0e66b994 100644 (file)
@@ -857,7 +857,7 @@ assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcf
        }
 
        /* If topology sets value don't overwrite it */
-       if (cfg->copier.vindex.i2s.instance)
+       if (cfg->copier.vindex.val)
                return;
 
        mach = dev_get_platdata(comp->card->dev);
index 10a84a2c1036e9ce67751702a047795a5eabf9b7..c014d85a08b24755682f3faf97e3e60cd171dc7a 100644 (file)
@@ -241,7 +241,8 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev)
 
        /* fix index of codec dai */
        for (i = 0; i < ARRAY_SIZE(byt_cht_cx2072x_dais); i++) {
-               if (!strcmp(byt_cht_cx2072x_dais[i].codecs->name,
+               if (byt_cht_cx2072x_dais[i].codecs->name &&
+                   !strcmp(byt_cht_cx2072x_dais[i].codecs->name,
                            "i2c-14F10720:00")) {
                        dai_index = i;
                        break;
index 7e5eea690023dff7bbdea996c739428c28445cf9..f4ac3ddd148b83757881426a2522adacd3d966d3 100644 (file)
@@ -245,7 +245,8 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
 
        /* fix index of codec dai */
        for (i = 0; i < ARRAY_SIZE(dailink); i++) {
-               if (!strcmp(dailink[i].codecs->name, "i2c-DLGS7213:00")) {
+               if (dailink[i].codecs->name &&
+                   !strcmp(dailink[i].codecs->name, "i2c-DLGS7213:00")) {
                        dai_index = i;
                        break;
                }
index 1564a88a885efa1838317f453bf3d514a529d7e8..2fcec2e02bb53b403350ee76cb124ed99882087e 100644 (file)
@@ -546,7 +546,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
 
        /* fix index of codec dai */
        for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) {
-               if (!strcmp(byt_cht_es8316_dais[i].codecs->name,
+               if (byt_cht_es8316_dais[i].codecs->name &&
+                   !strcmp(byt_cht_es8316_dais[i].codecs->name,
                            "i2c-ESSX8316:00")) {
                        dai_index = i;
                        break;
index 42466b4b1ca45e159ea40c42809018929e0ed0dc..05f38d1f7d824dc0f46c5262e0f6616dce1b7411 100644 (file)
@@ -685,6 +685,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_SSP0_AIF1 |
                                        BYT_RT5640_MCLK_EN),
        },
+       {       /* Chuwi Vi8 dual-boot (CWI506) */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "i86"),
+                       /* The above are too generic, also match BIOS info */
+                       DMI_MATCH(DMI_BIOS_VERSION, "CHUWI2.D86JHBNR02"),
+               },
+               .driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+                                       BYT_RT5640_MONO_SPEAKER |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {
                /* Chuwi Vi10 (CWI505) */
                .matches = {
@@ -1652,7 +1664,8 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 
        /* fix index of codec dai */
        for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) {
-               if (!strcmp(byt_rt5640_dais[i].codecs->name,
+               if (byt_rt5640_dais[i].codecs->name &&
+                   !strcmp(byt_rt5640_dais[i].codecs->name,
                            "i2c-10EC5640:00")) {
                        dai_index = i;
                        break;
index f9fe8414f454ff481b7e1b84f5377bb4d8835161..80c841b000a311229c310fec3ba91264696e6025 100644 (file)
@@ -910,7 +910,8 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
 
        /* fix index of codec dai */
        for (i = 0; i < ARRAY_SIZE(byt_rt5651_dais); i++) {
-               if (!strcmp(byt_rt5651_dais[i].codecs->name,
+               if (byt_rt5651_dais[i].codecs->name &&
+                   !strcmp(byt_rt5651_dais[i].codecs->name,
                            "i2c-10EC5651:00")) {
                        dai_index = i;
                        break;
index 6978ebde669357fc7a25abc9961aaafc278b1789..cccb5e90c0fefc6a888ac302a63ed50a9423342d 100644 (file)
@@ -605,7 +605,8 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
 
        /* find index of codec dai */
        for (i = 0; i < ARRAY_SIZE(byt_wm5102_dais); i++) {
-               if (!strcmp(byt_wm5102_dais[i].codecs->name,
+               if (byt_wm5102_dais[i].codecs->name &&
+                   !strcmp(byt_wm5102_dais[i].codecs->name,
                            "wm5102-codec")) {
                        dai_index = i;
                        break;
index c952a96cde7ebe27ba6f61ed6d417d0f063d0e1e..eb41b7115d01dd38685d5a10cd393e46eb4106a4 100644 (file)
@@ -40,7 +40,6 @@ struct cht_acpi_card {
 struct cht_mc_private {
        struct snd_soc_jack jack;
        struct cht_acpi_card *acpi_card;
-       char codec_name[SND_ACPI_I2C_ID_LEN];
        struct clk *mclk;
 };
 
@@ -567,14 +566,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
        }
 
        card->dev = &pdev->dev;
-       sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
 
        /* set correct codec name */
        for (i = 0; i < ARRAY_SIZE(cht_dailink); i++)
-               if (!strcmp(card->dai_link[i].codecs->name,
+               if (cht_dailink[i].codecs->name &&
+                   !strcmp(cht_dailink[i].codecs->name,
                            "i2c-10EC5645:00")) {
-                       card->dai_link[i].codecs->name = drv->codec_name;
                        dai_index = i;
+                       break;
                }
 
        /* fixup codec name based on HID */
index 8cf0b33cc02eb5763acbb572ab0387efbe8da325..be2d1a8dbca807dd1f4af070382d2d2f169c9e27 100644 (file)
@@ -466,7 +466,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 
        /* find index of codec dai */
        for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) {
-               if (!strcmp(cht_dailink[i].codecs->name, RT5672_I2C_DEFAULT)) {
+               if (cht_dailink[i].codecs->name &&
+                   !strcmp(cht_dailink[i].codecs->name, RT5672_I2C_DEFAULT)) {
                        dai_index = i;
                        break;
                }
index 48b03e60e3a3d760c9d872d9ffc3527b0aed40fe..8106c586f68a4ec456ae2be11f37b1c2c8cd806c 100644 (file)
@@ -259,7 +259,7 @@ static int lpass_cdc_dma_daiops_trigger(struct snd_pcm_substream *substream,
                                    int cmd, struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
-       struct lpaif_dmactl *dmactl;
+       struct lpaif_dmactl *dmactl = NULL;
        int ret = 0, id;
 
        switch (cmd) {
index 052e40cb38feca032752784545a4a07332369054..00bbd291be5cea4b5f43ee06b85b55dfb8eb91c2 100644 (file)
@@ -123,7 +123,7 @@ static struct snd_pcm_hardware q6apm_dai_hardware_playback = {
        .fifo_size =            0,
 };
 
-static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv)
+static void event_handler(uint32_t opcode, uint32_t token, void *payload, void *priv)
 {
        struct q6apm_dai_rtd *prtd = priv;
        struct snd_pcm_substream *substream = prtd->substream;
@@ -157,7 +157,7 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo
 }
 
 static void event_handler_compr(uint32_t opcode, uint32_t token,
-                               uint32_t *payload, void *priv)
+                               void *payload, void *priv)
 {
        struct q6apm_dai_rtd *prtd = priv;
        struct snd_compr_stream *substream = prtd->cstream;
@@ -352,7 +352,7 @@ static int q6apm_dai_open(struct snd_soc_component *component,
 
        spin_lock_init(&prtd->lock);
        prtd->substream = substream;
-       prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler, prtd, graph_id);
+       prtd->graph = q6apm_graph_open(dev, event_handler, prtd, graph_id);
        if (IS_ERR(prtd->graph)) {
                dev_err(dev, "%s: Could not allocate memory\n", __func__);
                ret = PTR_ERR(prtd->graph);
@@ -496,7 +496,7 @@ static int q6apm_dai_compr_open(struct snd_soc_component *component,
                return -ENOMEM;
 
        prtd->cstream = stream;
-       prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler_compr, prtd, graph_id);
+       prtd->graph = q6apm_graph_open(dev, event_handler_compr, prtd, graph_id);
        if (IS_ERR(prtd->graph)) {
                ret = PTR_ERR(prtd->graph);
                kfree(prtd);
index 230c48648af359381223eda3a5e6a4b1793bc5f2..afd69c6eb6544cc21c9d533a03cbabc755c15764 100644 (file)
@@ -111,6 +111,13 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
                        ws = 7;
                        break;
                }
+       } else {
+               /*
+                * SSI8 is not connected to ADG.
+                * Thus SSI9 is using ws = 8
+                */
+               if (id == 9)
+                       ws = 8;
        }
 
        return (0x6 + ws) << 8;
index 285ab4c9c7168314ae34bead44a5229bc5d8b96b..8a2f163da6bc9e8e61fc1f196f3b89556815cafe 100644 (file)
@@ -5,6 +5,9 @@
 // Copyright (C) 2019 Renesas Electronics Corp.
 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 //
+
+#include <linux/lockdep.h>
+#include <linux/rwsem.h>
 #include <sound/soc.h>
 #include <sound/jack.h>
 
@@ -26,12 +29,15 @@ static inline int _soc_card_ret(struct snd_soc_card *card,
        return ret;
 }
 
-struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
-                                              const char *name)
+struct snd_kcontrol *snd_soc_card_get_kcontrol_locked(struct snd_soc_card *soc_card,
+                                                     const char *name)
 {
        struct snd_card *card = soc_card->snd_card;
        struct snd_kcontrol *kctl;
 
+       /* must be held read or write */
+       lockdep_assert_held(&card->controls_rwsem);
+
        if (unlikely(!name))
                return NULL;
 
@@ -40,6 +46,20 @@ struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
                        return kctl;
        return NULL;
 }
+EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol_locked);
+
+struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
+                                              const char *name)
+{
+       struct snd_card *card = soc_card->snd_card;
+       struct snd_kcontrol *kctl;
+
+       down_read(&card->controls_rwsem);
+       kctl = snd_soc_card_get_kcontrol_locked(soc_card, name);
+       up_read(&card->controls_rwsem);
+
+       return kctl;
+}
 EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol);
 
 static int jack_new(struct snd_soc_card *card, const char *id, int type,
index 2743f07a5e0811912722d174bd4096950e788a62..b44b1b1adb6ed9e913c857168902f00949abcb86 100644 (file)
@@ -188,11 +188,13 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
 
        dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write);
        if (dsp_ack) {
+               spin_lock_irq(&sdev->ipc_lock);
                /* handle immediate reply from DSP core */
                acp_dsp_ipc_get_reply(sdev);
                snd_sof_ipc_reply(sdev, 0);
                /* set the done bit */
                acp_dsp_ipc_dsp_done(sdev);
+               spin_unlock_irq(&sdev->ipc_lock);
                ipc_irq = true;
        }
 
index 32a741fcb84fffcc3988e4deabf4e99ef4863d49..07632ae6ccf5ec058565d50f1992475795c490d2 100644 (file)
@@ -355,21 +355,20 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
        unsigned int count = ACP_HW_SEM_RETRY_COUNT;
 
        spin_lock_irq(&sdev->ipc_lock);
-       while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) {
-               /* Wait until acquired HW Semaphore lock or timeout */
-               count--;
-               if (!count) {
-                       dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__);
-                       spin_unlock_irq(&sdev->ipc_lock);
-                       return IRQ_NONE;
-               }
+       /* Wait until acquired HW Semaphore lock or timeout */
+       while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset) && --count)
+               ;
+       spin_unlock_irq(&sdev->ipc_lock);
+
+       if (!count) {
+               dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__);
+               return IRQ_NONE;
        }
 
        sof_ops(sdev)->irq_thread(irq, sdev);
        /* Unlock or Release HW Semaphore */
        snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset, 0x0);
 
-       spin_unlock_irq(&sdev->ipc_lock);
        return IRQ_HANDLED;
 };
 
index 78a57eb9cbc377c0b525827a0539baea6850ca6f..b26ffe767fab553467897b4facc13931668b27fe 100644 (file)
@@ -36,7 +36,7 @@ static const struct sof_dev_desc lnl_desc = {
                [SOF_IPC_TYPE_4] = "intel/sof-ipc4/lnl",
        },
        .default_tplg_path = {
-               [SOF_IPC_TYPE_4] = "intel/sof-ace-tplg",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
        },
        .default_fw_filename = {
                [SOF_IPC_TYPE_4] = "sof-lnl.ri",
index 0660d4b2ac96b66da5997d1aed60ddb91341571a..a361ee9d1107f5ed7533d1f71400f95ae4ad34af 100644 (file)
@@ -33,18 +33,18 @@ static const struct sof_dev_desc tgl_desc = {
        .dspless_mode_supported = true,         /* Only supported for HDaudio */
        .default_fw_path = {
                [SOF_IPC_TYPE_3] = "intel/sof",
-               [SOF_IPC_TYPE_4] = "intel/avs/tgl",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4/tgl",
        },
        .default_lib_path = {
-               [SOF_IPC_TYPE_4] = "intel/avs-lib/tgl",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/tgl",
        },
        .default_tplg_path = {
                [SOF_IPC_TYPE_3] = "intel/sof-tplg",
-               [SOF_IPC_TYPE_4] = "intel/avs-tplg",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
        },
        .default_fw_filename = {
                [SOF_IPC_TYPE_3] = "sof-tgl.ri",
-               [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
+               [SOF_IPC_TYPE_4] = "sof-tgl.ri",
        },
        .nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
        .ops = &sof_tgl_ops,
@@ -66,18 +66,18 @@ static const struct sof_dev_desc tglh_desc = {
        .dspless_mode_supported = true,         /* Only supported for HDaudio */
        .default_fw_path = {
                [SOF_IPC_TYPE_3] = "intel/sof",
-               [SOF_IPC_TYPE_4] = "intel/avs/tgl-h",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4/tgl-h",
        },
        .default_lib_path = {
-               [SOF_IPC_TYPE_4] = "intel/avs-lib/tgl-h",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/tgl-h",
        },
        .default_tplg_path = {
                [SOF_IPC_TYPE_3] = "intel/sof-tplg",
-               [SOF_IPC_TYPE_4] = "intel/avs-tplg",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
        },
        .default_fw_filename = {
                [SOF_IPC_TYPE_3] = "sof-tgl-h.ri",
-               [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
+               [SOF_IPC_TYPE_4] = "sof-tgl-h.ri",
        },
        .nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
        .ops = &sof_tgl_ops,
@@ -98,18 +98,18 @@ static const struct sof_dev_desc ehl_desc = {
        .dspless_mode_supported = true,         /* Only supported for HDaudio */
        .default_fw_path = {
                [SOF_IPC_TYPE_3] = "intel/sof",
-               [SOF_IPC_TYPE_4] = "intel/avs/ehl",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4/ehl",
        },
        .default_lib_path = {
-               [SOF_IPC_TYPE_4] = "intel/avs-lib/ehl",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/ehl",
        },
        .default_tplg_path = {
                [SOF_IPC_TYPE_3] = "intel/sof-tplg",
-               [SOF_IPC_TYPE_4] = "intel/avs-tplg",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
        },
        .default_fw_filename = {
                [SOF_IPC_TYPE_3] = "sof-ehl.ri",
-               [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
+               [SOF_IPC_TYPE_4] = "sof-ehl.ri",
        },
        .nocodec_tplg_filename = "sof-ehl-nocodec.tplg",
        .ops = &sof_tgl_ops,
@@ -131,18 +131,18 @@ static const struct sof_dev_desc adls_desc = {
        .dspless_mode_supported = true,         /* Only supported for HDaudio */
        .default_fw_path = {
                [SOF_IPC_TYPE_3] = "intel/sof",
-               [SOF_IPC_TYPE_4] = "intel/avs/adl-s",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4/adl-s",
        },
        .default_lib_path = {
-               [SOF_IPC_TYPE_4] = "intel/avs-lib/adl-s",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/adl-s",
        },
        .default_tplg_path = {
                [SOF_IPC_TYPE_3] = "intel/sof-tplg",
-               [SOF_IPC_TYPE_4] = "intel/avs-tplg",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
        },
        .default_fw_filename = {
                [SOF_IPC_TYPE_3] = "sof-adl-s.ri",
-               [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
+               [SOF_IPC_TYPE_4] = "sof-adl-s.ri",
        },
        .nocodec_tplg_filename = "sof-adl-nocodec.tplg",
        .ops = &sof_tgl_ops,
@@ -164,18 +164,18 @@ static const struct sof_dev_desc adl_desc = {
        .dspless_mode_supported = true,         /* Only supported for HDaudio */
        .default_fw_path = {
                [SOF_IPC_TYPE_3] = "intel/sof",
-               [SOF_IPC_TYPE_4] = "intel/avs/adl",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4/adl",
        },
        .default_lib_path = {
-               [SOF_IPC_TYPE_4] = "intel/avs-lib/adl",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/adl",
        },
        .default_tplg_path = {
                [SOF_IPC_TYPE_3] = "intel/sof-tplg",
-               [SOF_IPC_TYPE_4] = "intel/avs-tplg",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
        },
        .default_fw_filename = {
                [SOF_IPC_TYPE_3] = "sof-adl.ri",
-               [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
+               [SOF_IPC_TYPE_4] = "sof-adl.ri",
        },
        .nocodec_tplg_filename = "sof-adl-nocodec.tplg",
        .ops = &sof_tgl_ops,
@@ -197,18 +197,18 @@ static const struct sof_dev_desc adl_n_desc = {
        .dspless_mode_supported = true,         /* Only supported for HDaudio */
        .default_fw_path = {
                [SOF_IPC_TYPE_3] = "intel/sof",
-               [SOF_IPC_TYPE_4] = "intel/avs/adl-n",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4/adl-n",
        },
        .default_lib_path = {
-               [SOF_IPC_TYPE_4] = "intel/avs-lib/adl-n",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/adl-n",
        },
        .default_tplg_path = {
                [SOF_IPC_TYPE_3] = "intel/sof-tplg",
-               [SOF_IPC_TYPE_4] = "intel/avs-tplg",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
        },
        .default_fw_filename = {
                [SOF_IPC_TYPE_3] = "sof-adl-n.ri",
-               [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
+               [SOF_IPC_TYPE_4] = "sof-adl-n.ri",
        },
        .nocodec_tplg_filename = "sof-adl-nocodec.tplg",
        .ops = &sof_tgl_ops,
@@ -230,18 +230,18 @@ static const struct sof_dev_desc rpls_desc = {
        .dspless_mode_supported = true,         /* Only supported for HDaudio */
        .default_fw_path = {
                [SOF_IPC_TYPE_3] = "intel/sof",
-               [SOF_IPC_TYPE_4] = "intel/avs/rpl-s",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4/rpl-s",
        },
        .default_lib_path = {
-               [SOF_IPC_TYPE_4] = "intel/avs-lib/rpl-s",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/rpl-s",
        },
        .default_tplg_path = {
                [SOF_IPC_TYPE_3] = "intel/sof-tplg",
-               [SOF_IPC_TYPE_4] = "intel/avs-tplg",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
        },
        .default_fw_filename = {
                [SOF_IPC_TYPE_3] = "sof-rpl-s.ri",
-               [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
+               [SOF_IPC_TYPE_4] = "sof-rpl-s.ri",
        },
        .nocodec_tplg_filename = "sof-rpl-nocodec.tplg",
        .ops = &sof_tgl_ops,
@@ -263,18 +263,18 @@ static const struct sof_dev_desc rpl_desc = {
        .dspless_mode_supported = true,         /* Only supported for HDaudio */
        .default_fw_path = {
                [SOF_IPC_TYPE_3] = "intel/sof",
-               [SOF_IPC_TYPE_4] = "intel/avs/rpl",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4/rpl",
        },
        .default_lib_path = {
-               [SOF_IPC_TYPE_4] = "intel/avs-lib/rpl",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/rpl",
        },
        .default_tplg_path = {
                [SOF_IPC_TYPE_3] = "intel/sof-tplg",
-               [SOF_IPC_TYPE_4] = "intel/avs-tplg",
+               [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
        },
        .default_fw_filename = {
                [SOF_IPC_TYPE_3] = "sof-rpl.ri",
-               [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
+               [SOF_IPC_TYPE_4] = "sof-rpl.ri",
        },
        .nocodec_tplg_filename = "sof-rpl-nocodec.tplg",
        .ops = &sof_tgl_ops,
index a8832a1c1a2442c8af573943787e3b6768b5e36f..d47698f4be2deb6f5bb943e2de2611923c45c387 100644 (file)
@@ -2360,27 +2360,16 @@ static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev)
        return 0;
 }
 
-/*
- * For older firmware, this function doesn't free widgets for static pipelines during suspend.
- * It only resets use_count for all widgets.
- */
-static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
+static int sof_ipc3_free_widgets_in_list(struct snd_sof_dev *sdev, bool include_scheduler,
+                                        bool *dyn_widgets, bool verify)
 {
        struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
        struct snd_sof_widget *swidget;
-       struct snd_sof_route *sroute;
-       bool dyn_widgets = false;
        int ret;
 
-       /*
-        * This function is called during suspend and for one-time topology verification during
-        * first boot. In both cases, there is no need to protect swidget->use_count and
-        * sroute->setup because during suspend all running streams are suspended and during
-        * topology loading the sound card unavailable to open PCMs.
-        */
        list_for_each_entry(swidget, &sdev->widget_list, list) {
                if (swidget->dynamic_pipeline_widget) {
-                       dyn_widgets = true;
+                       *dyn_widgets = true;
                        continue;
                }
 
@@ -2395,11 +2384,49 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
                        continue;
                }
 
+               if (include_scheduler && swidget->id != snd_soc_dapm_scheduler)
+                       continue;
+
+               if (!include_scheduler && swidget->id == snd_soc_dapm_scheduler)
+                       continue;
+
                ret = sof_widget_free(sdev, swidget);
                if (ret < 0)
                        return ret;
        }
 
+       return 0;
+}
+
+/*
+ * For older firmware, this function doesn't free widgets for static pipelines during suspend.
+ * It only resets use_count for all widgets.
+ */
+static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
+{
+       struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
+       struct snd_sof_widget *swidget;
+       struct snd_sof_route *sroute;
+       bool dyn_widgets = false;
+       int ret;
+
+       /*
+        * This function is called during suspend and for one-time topology verification during
+        * first boot. In both cases, there is no need to protect swidget->use_count and
+        * sroute->setup because during suspend all running streams are suspended and during
+        * topology loading the sound card unavailable to open PCMs. Do not free the scheduler
+        * widgets yet so that the secondary cores do not get powered down before all the widgets
+        * associated with the scheduler are freed.
+        */
+       ret = sof_ipc3_free_widgets_in_list(sdev, false, &dyn_widgets, verify);
+       if (ret < 0)
+               return ret;
+
+       /* free all the scheduler widgets now */
+       ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify);
+       if (ret < 0)
+               return ret;
+
        /*
         * Tear down all pipelines associated with PCMs that did not get suspended
         * and unset the prepare flag so that they can be set up again during resume.
index fb40378ad0840255a9b35cb74f99c9b80d5271b9..c03dd513fbff142fee51a9b0233920024d691f1d 100644 (file)
@@ -1067,7 +1067,7 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev)
                return;
        }
 
-       if (hdr.size < sizeof(hdr)) {
+       if (hdr.size < sizeof(hdr) || hdr.size > SOF_IPC_MSG_MAX_SIZE) {
                dev_err(sdev->dev, "The received message size is invalid\n");
                return;
        }
index 85d3f390e4b290774687086f37b2a73473117e54..07eb5c6d4adf3246877e4881c1927a6a4f8c39ee 100644 (file)
@@ -413,7 +413,18 @@ skip_pause_transition:
        ret = sof_ipc4_set_multi_pipeline_state(sdev, state, trigger_list);
        if (ret < 0) {
                dev_err(sdev->dev, "failed to set final state %d for all pipelines\n", state);
-               goto free;
+               /*
+                * workaround: if the firmware is crashed while setting the
+                * pipelines to reset state we must ignore the error code and
+                * reset it to 0.
+                * Since the firmware is crashed we will not send IPC messages
+                * and we are going to see errors printed, but the state of the
+                * widgets will be correct for the next boot.
+                */
+               if (sdev->fw_state != SOF_FW_CRASHED || state != SOF_IPC4_PIPE_RESET)
+                       goto free;
+
+               ret = 0;
        }
 
        /* update RUNNING/RESET state for all pipelines that were just triggered */
index 6b0993258e039b052b9196f3a2f43f720623f2ce..c1f2e5a03de969af932b3f8394332eb6f80983a3 100644 (file)
@@ -1742,50 +1742,44 @@ static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number,
        }
 }
 
-static struct usb_midi_in_jack_descriptor *find_usb_in_jack_descriptor(
-                                       struct usb_host_interface *hostif, uint8_t jack_id)
+/* return iJack for the corresponding jackID */
+static int find_usb_ijack(struct usb_host_interface *hostif, uint8_t jack_id)
 {
        unsigned char *extra = hostif->extra;
        int extralen = hostif->extralen;
+       struct usb_descriptor_header *h;
+       struct usb_midi_out_jack_descriptor *outjd;
+       struct usb_midi_in_jack_descriptor *injd;
+       size_t sz;
 
        while (extralen > 4) {
-               struct usb_midi_in_jack_descriptor *injd =
-                               (struct usb_midi_in_jack_descriptor *)extra;
+               h = (struct usb_descriptor_header *)extra;
+               if (h->bDescriptorType != USB_DT_CS_INTERFACE)
+                       goto next;
 
+               outjd = (struct usb_midi_out_jack_descriptor *)h;
+               if (h->bLength >= sizeof(*outjd) &&
+                   outjd->bDescriptorSubtype == UAC_MIDI_OUT_JACK &&
+                   outjd->bJackID == jack_id) {
+                       sz = USB_DT_MIDI_OUT_SIZE(outjd->bNrInputPins);
+                       if (outjd->bLength < sz)
+                               goto next;
+                       return *(extra + sz - 1);
+               }
+
+               injd = (struct usb_midi_in_jack_descriptor *)h;
                if (injd->bLength >= sizeof(*injd) &&
-                   injd->bDescriptorType == USB_DT_CS_INTERFACE &&
                    injd->bDescriptorSubtype == UAC_MIDI_IN_JACK &&
-                               injd->bJackID == jack_id)
-                       return injd;
-               if (!extra[0])
-                       break;
-               extralen -= extra[0];
-               extra += extra[0];
-       }
-       return NULL;
-}
-
-static struct usb_midi_out_jack_descriptor *find_usb_out_jack_descriptor(
-                                       struct usb_host_interface *hostif, uint8_t jack_id)
-{
-       unsigned char *extra = hostif->extra;
-       int extralen = hostif->extralen;
+                   injd->bJackID == jack_id)
+                       return injd->iJack;
 
-       while (extralen > 4) {
-               struct usb_midi_out_jack_descriptor *outjd =
-                               (struct usb_midi_out_jack_descriptor *)extra;
-
-               if (outjd->bLength >= sizeof(*outjd) &&
-                   outjd->bDescriptorType == USB_DT_CS_INTERFACE &&
-                   outjd->bDescriptorSubtype == UAC_MIDI_OUT_JACK &&
-                               outjd->bJackID == jack_id)
-                       return outjd;
+next:
                if (!extra[0])
                        break;
                extralen -= extra[0];
                extra += extra[0];
        }
-       return NULL;
+       return 0;
 }
 
 static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi,
@@ -1796,13 +1790,10 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi,
        const char *name_format;
        struct usb_interface *intf;
        struct usb_host_interface *hostif;
-       struct usb_midi_in_jack_descriptor *injd;
-       struct usb_midi_out_jack_descriptor *outjd;
        uint8_t jack_name_buf[32];
        uint8_t *default_jack_name = "MIDI";
        uint8_t *jack_name = default_jack_name;
        uint8_t iJack;
-       size_t sz;
        int res;
 
        struct snd_rawmidi_substream *substream =
@@ -1816,21 +1807,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi,
        intf = umidi->iface;
        if (intf && jack_id >= 0) {
                hostif = intf->cur_altsetting;
-               iJack = 0;
-               if (stream != SNDRV_RAWMIDI_STREAM_OUTPUT) {
-                       /* in jacks connect to outs */
-                       outjd = find_usb_out_jack_descriptor(hostif, jack_id);
-                       if (outjd) {
-                               sz = USB_DT_MIDI_OUT_SIZE(outjd->bNrInputPins);
-                               if (outjd->bLength >= sz)
-                                       iJack = *(((uint8_t *) outjd) + sz - sizeof(uint8_t));
-                       }
-               } else {
-                       /* and out jacks connect to ins */
-                       injd = find_usb_in_jack_descriptor(hostif, jack_id);
-                       if (injd)
-                               iJack = injd->iJack;
-               }
+               iJack = find_usb_ijack(hostif, jack_id);
                if (iJack != 0) {
                        res = usb_string(umidi->dev, iJack, jack_name_buf,
                          ARRAY_SIZE(jack_name_buf));
index 29cb275a219d7fb38fa0d16e6ba48e91c9d032b4..25160d26764b5e29c7f4e825979d6222ae15e5c4 100644 (file)
 #define X86_FEATURE_FZRM               (12*32+10) /* "" Fast zero-length REP MOVSB */
 #define X86_FEATURE_FSRS               (12*32+11) /* "" Fast short REP STOSB */
 #define X86_FEATURE_FSRC               (12*32+12) /* "" Fast short REP {CMPSB,SCASB} */
+#define X86_FEATURE_FRED               (12*32+17) /* Flexible Return and Event Delivery */
 #define X86_FEATURE_LKGS               (12*32+18) /* "" Load "kernel" (userspace) GS */
+#define X86_FEATURE_WRMSRNS            (12*32+19) /* "" Non-serializing WRMSR */
 #define X86_FEATURE_AMX_FP16           (12*32+21) /* "" AMX fp16 Support */
 #define X86_FEATURE_AVX_IFMA            (12*32+23) /* "" Support for VPMADD52[H,L]UQ */
 #define X86_FEATURE_LAM                        (12*32+26) /* Linear Address Masking */
 #define X86_FEATURE_SEV                        (19*32+ 1) /* AMD Secure Encrypted Virtualization */
 #define X86_FEATURE_VM_PAGE_FLUSH      (19*32+ 2) /* "" VM Page Flush MSR is supported */
 #define X86_FEATURE_SEV_ES             (19*32+ 3) /* AMD Secure Encrypted Virtualization - Encrypted State */
+#define X86_FEATURE_SEV_SNP            (19*32+ 4) /* AMD Secure Encrypted Virtualization - Secure Nested Paging */
 #define X86_FEATURE_V_TSC_AUX          (19*32+ 9) /* "" Virtual TSC_AUX */
 #define X86_FEATURE_SME_COHERENT       (19*32+10) /* "" AMD hardware-enforced cache coherency */
 #define X86_FEATURE_DEBUG_SWAP         (19*32+14) /* AMD SEV-ES full debug state swap support */
index 702d93fdd10e8d44015cc687cb90106ae5bd422c..1f23960d2b06e7bea48be6f7213e678962626e99 100644 (file)
 # define DISABLE_LA57  (1<<(X86_FEATURE_LA57 & 31))
 #endif
 
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
 # define DISABLE_PTI           0
 #else
 # define DISABLE_PTI           (1 << (X86_FEATURE_PTI & 31))
 #endif
 
-#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_MITIGATION_RETPOLINE
 # define DISABLE_RETPOLINE     0
 #else
 # define DISABLE_RETPOLINE     ((1 << (X86_FEATURE_RETPOLINE & 31)) | \
                                 (1 << (X86_FEATURE_RETPOLINE_LFENCE & 31)))
 #endif
 
-#ifdef CONFIG_RETHUNK
+#ifdef CONFIG_MITIGATION_RETHUNK
 # define DISABLE_RETHUNK       0
 #else
 # define DISABLE_RETHUNK       (1 << (X86_FEATURE_RETHUNK & 31))
 #endif
 
-#ifdef CONFIG_CPU_UNRET_ENTRY
+#ifdef CONFIG_MITIGATION_UNRET_ENTRY
 # define DISABLE_UNRET         0
 #else
 # define DISABLE_UNRET         (1 << (X86_FEATURE_UNRET & 31))
 #endif
 
-#ifdef CONFIG_CALL_DEPTH_TRACKING
+#ifdef CONFIG_MITIGATION_CALL_DEPTH_TRACKING
 # define DISABLE_CALL_DEPTH_TRACKING   0
 #else
 # define DISABLE_CALL_DEPTH_TRACKING   (1 << (X86_FEATURE_CALL_DEPTH & 31))
 #define DISABLE_IBT    (1 << (X86_FEATURE_IBT & 31))
 #endif
 
+#ifdef CONFIG_X86_FRED
+# define DISABLE_FRED  0
+#else
+# define DISABLE_FRED  (1 << (X86_FEATURE_FRED & 31))
+#endif
+
 /*
  * Make sure to add features to the correct mask
  */
 #define DISABLED_MASK10        0
 #define DISABLED_MASK11        (DISABLE_RETPOLINE|DISABLE_RETHUNK|DISABLE_UNRET| \
                         DISABLE_CALL_DEPTH_TRACKING|DISABLE_USER_SHSTK)
-#define DISABLED_MASK12        (DISABLE_LAM)
+#define DISABLED_MASK12        (DISABLE_FRED|DISABLE_LAM)
 #define DISABLED_MASK13        0
 #define DISABLED_MASK14        0
 #define DISABLED_MASK15        0
index f1bd7b91b3c63735738825f15cd3c82fca7579ce..1f9dc9bd13eb7e9c7bc509b1d09cec7f473157b4 100644 (file)
 #define EFER_FFXSR             (1<<_EFER_FFXSR)
 #define EFER_AUTOIBRS          (1<<_EFER_AUTOIBRS)
 
-/* Intel MSRs. Some also available on other CPUs */
+/* FRED MSRs */
+#define MSR_IA32_FRED_RSP0     0x1cc                   /* Level 0 stack pointer */
+#define MSR_IA32_FRED_RSP1     0x1cd                   /* Level 1 stack pointer */
+#define MSR_IA32_FRED_RSP2     0x1ce                   /* Level 2 stack pointer */
+#define MSR_IA32_FRED_RSP3     0x1cf                   /* Level 3 stack pointer */
+#define MSR_IA32_FRED_STKLVLS  0x1d0                   /* Exception stack levels */
+#define MSR_IA32_FRED_SSP0     MSR_IA32_PL0_SSP        /* Level 0 shadow stack pointer */
+#define MSR_IA32_FRED_SSP1     0x1d1                   /* Level 1 shadow stack pointer */
+#define MSR_IA32_FRED_SSP2     0x1d2                   /* Level 2 shadow stack pointer */
+#define MSR_IA32_FRED_SSP3     0x1d3                   /* Level 3 shadow stack pointer */
+#define MSR_IA32_FRED_CONFIG   0x1d4                   /* Entrypoint and interrupt stack level */
 
+/* Intel MSRs. Some also available on other CPUs */
 #define MSR_TEST_CTRL                          0x00000033
 #define MSR_TEST_CTRL_SPLIT_LOCK_DETECT_BIT    29
 #define MSR_TEST_CTRL_SPLIT_LOCK_DETECT                BIT(MSR_TEST_CTRL_SPLIT_LOCK_DETECT_BIT)
index 8fd63a067308a83ea9fe44085db306c555a1288d..ada4b4a79dd48d1402fc88b250846c4a21ec0379 100644 (file)
@@ -71,7 +71,7 @@ void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
        insn->kaddr = kaddr;
        insn->end_kaddr = kaddr + buf_len;
        insn->next_byte = kaddr;
-       insn->x86_64 = x86_64 ? 1 : 0;
+       insn->x86_64 = x86_64;
        insn->opnd_bytes = 4;
        if (x86_64)
                insn->addr_bytes = 8;
@@ -268,11 +268,9 @@ int insn_get_opcode(struct insn *insn)
        if (opcode->got)
                return 0;
 
-       if (!insn->prefixes.got) {
-               ret = insn_get_prefixes(insn);
-               if (ret)
-                       return ret;
-       }
+       ret = insn_get_prefixes(insn);
+       if (ret)
+               return ret;
 
        /* Get first opcode */
        op = get_next(insn_byte_t, insn);
@@ -339,11 +337,9 @@ int insn_get_modrm(struct insn *insn)
        if (modrm->got)
                return 0;
 
-       if (!insn->opcode.got) {
-               ret = insn_get_opcode(insn);
-               if (ret)
-                       return ret;
-       }
+       ret = insn_get_opcode(insn);
+       if (ret)
+               return ret;
 
        if (inat_has_modrm(insn->attr)) {
                mod = get_next(insn_byte_t, insn);
@@ -386,11 +382,9 @@ int insn_rip_relative(struct insn *insn)
        if (!insn->x86_64)
                return 0;
 
-       if (!modrm->got) {
-               ret = insn_get_modrm(insn);
-               if (ret)
-                       return 0;
-       }
+       ret = insn_get_modrm(insn);
+       if (ret)
+               return 0;
        /*
         * For rip-relative instructions, the mod field (top 2 bits)
         * is zero and the r/m field (bottom 3 bits) is 0x5.
@@ -417,11 +411,9 @@ int insn_get_sib(struct insn *insn)
        if (insn->sib.got)
                return 0;
 
-       if (!insn->modrm.got) {
-               ret = insn_get_modrm(insn);
-               if (ret)
-                       return ret;
-       }
+       ret = insn_get_modrm(insn);
+       if (ret)
+               return ret;
 
        if (insn->modrm.nbytes) {
                modrm = insn->modrm.bytes[0];
@@ -460,11 +452,9 @@ int insn_get_displacement(struct insn *insn)
        if (insn->displacement.got)
                return 0;
 
-       if (!insn->sib.got) {
-               ret = insn_get_sib(insn);
-               if (ret)
-                       return ret;
-       }
+       ret = insn_get_sib(insn);
+       if (ret)
+               return ret;
 
        if (insn->modrm.nbytes) {
                /*
@@ -628,11 +618,9 @@ int insn_get_immediate(struct insn *insn)
        if (insn->immediate.got)
                return 0;
 
-       if (!insn->displacement.got) {
-               ret = insn_get_displacement(insn);
-               if (ret)
-                       return ret;
-       }
+       ret = insn_get_displacement(insn);
+       if (ret)
+               return ret;
 
        if (inat_has_moffset(insn->attr)) {
                if (!__get_moffset(insn))
@@ -703,11 +691,9 @@ int insn_get_length(struct insn *insn)
        if (insn->length)
                return 0;
 
-       if (!insn->immediate.got) {
-               ret = insn_get_immediate(insn);
-               if (ret)
-                       return ret;
-       }
+       ret = insn_get_immediate(insn);
+       if (ret)
+               return ret;
 
        insn->length = (unsigned char)((unsigned long)insn->next_byte
                                     - (unsigned long)insn->kaddr);
index 5168ee0360b2461e90f51d3d8c6a8377e2c62cbd..12af572201a29fe8fe8cfe9c9796ddb26eabf330 100644 (file)
@@ -1051,8 +1051,8 @@ GrpTable: Grp6
 EndTable
 
 GrpTable: Grp7
-0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) | PCONFIG (101),(11B) | ENCLV (000),(11B)
-1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) | ENCLS (111),(11B)
+0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) | PCONFIG (101),(11B) | ENCLV (000),(11B) | WRMSRNS (110),(11B)
+1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) | ENCLS (111),(11B) | ERETU (F3),(010),(11B) | ERETS (F2),(010),(11B)
 2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) | ENCLU (111),(11B)
 3: LIDT Ms
 4: SMSW Mw/Rv
index c82a7f41b31c571c09c3dd454a7db3ebbb8a1e60..45e49671ae87b01fac48b2877f46403cf9ee1c36 100644 (file)
@@ -466,6 +466,8 @@ ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version)
 
 int ynl_recv_ack(struct ynl_sock *ys, int ret)
 {
+       struct ynl_parse_arg yarg = { .ys = ys, };
+
        if (!ret) {
                yerr(ys, YNL_ERROR_EXPECT_ACK,
                     "Expecting an ACK but nothing received");
@@ -478,7 +480,7 @@ int ynl_recv_ack(struct ynl_sock *ys, int ret)
                return ret;
        }
        return mnl_cb_run(ys->rx_buf, ret, ys->seq, ys->portid,
-                         ynl_cb_null, ys);
+                         ynl_cb_null, &yarg);
 }
 
 int ynl_cb_null(const struct nlmsghdr *nlh, void *data)
@@ -521,6 +523,7 @@ ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts)
                                ys->mcast_groups[i].name[GENL_NAMSIZ - 1] = 0;
                        }
                }
+               i++;
        }
 
        return 0;
@@ -586,7 +589,13 @@ static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name)
                return err;
        }
 
-       return ynl_recv_ack(ys, err);
+       err = ynl_recv_ack(ys, err);
+       if (err < 0) {
+               free(ys->mcast_groups);
+               return err;
+       }
+
+       return 0;
 }
 
 struct ynl_sock *
@@ -741,11 +750,14 @@ err_free:
 
 static int ynl_ntf_trampoline(const struct nlmsghdr *nlh, void *data)
 {
-       return ynl_ntf_parse((struct ynl_sock *)data, nlh);
+       struct ynl_parse_arg *yarg = data;
+
+       return ynl_ntf_parse(yarg->ys, nlh);
 }
 
 int ynl_ntf_check(struct ynl_sock *ys)
 {
+       struct ynl_parse_arg yarg = { .ys = ys, };
        ssize_t len;
        int err;
 
@@ -767,7 +779,7 @@ int ynl_ntf_check(struct ynl_sock *ys)
                        return len;
 
                err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,
-                                 ynl_ntf_trampoline, ys,
+                                 ynl_ntf_trampoline, &yarg,
                                  ynl_cb_array, NLMSG_MIN_TYPE);
                if (err < 0)
                        return err;
index e327cd8271352264ff2eb389d82948d502f77465..3a1d80a7878d335b490df2fd17accc6d961b9879 100644 (file)
@@ -509,11 +509,20 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 
                if (op2 == 0x01) {
 
-                       if (modrm == 0xca)
-                               insn->type = INSN_CLAC;
-                       else if (modrm == 0xcb)
-                               insn->type = INSN_STAC;
-
+                       switch (insn_last_prefix_id(&ins)) {
+                       case INAT_PFX_REPE:
+                       case INAT_PFX_REPNE:
+                               if (modrm == 0xca)
+                                       /* eretu/erets */
+                                       insn->type = INSN_CONTEXT_SWITCH;
+                               break;
+                       default:
+                               if (modrm == 0xca)
+                                       insn->type = INSN_CLAC;
+                               else if (modrm == 0xcb)
+                                       insn->type = INSN_STAC;
+                               break;
+                       }
                } else if (op2 >= 0x80 && op2 <= 0x8f) {
 
                        insn->type = INSN_JUMP_CONDITIONAL;
index 29e949579ede616d62c0476d0ccab36339bf02d7..4134d27c696bdce8b5ce4b49a1cd94394ae22495 100644 (file)
@@ -83,7 +83,7 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
  *    TODO: Once we have DWARF CFI and smarter instruction decoding logic,
  *    ensure the same register is used in the mov and jump instructions.
  *
- *    NOTE: RETPOLINE made it harder still to decode dynamic jumps.
+ *    NOTE: MITIGATION_RETPOLINE made it harder still to decode dynamic jumps.
  */
 struct reloc *arch_find_switch_table(struct objtool_file *file,
                                    struct instruction *insn)
index 548ec3cd7c00ca532a286eca1e6ae46b20ae0101..8440b7bb343cc769d6cd45f64a5ab02f893afb11 100644 (file)
@@ -3980,11 +3980,11 @@ static int validate_retpoline(struct objtool_file *file)
 
                if (insn->type == INSN_RETURN) {
                        if (opts.rethunk) {
-                               WARN_INSN(insn, "'naked' return found in RETHUNK build");
+                               WARN_INSN(insn, "'naked' return found in MITIGATION_RETHUNK build");
                        } else
                                continue;
                } else {
-                       WARN_INSN(insn, "indirect %s found in RETPOLINE build",
+                       WARN_INSN(insn, "indirect %s found in MITIGATION_RETPOLINE build",
                                  insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call");
                }
 
index caff3834671f9dfb7d261d5b6633532f71ecd9f5..030b388800f05191e5b6492b97ebf96e9d45dcf3 100644 (file)
@@ -13,6 +13,7 @@ ldflags-y += --wrap=cxl_hdm_decode_init
 ldflags-y += --wrap=cxl_dvsec_rr_decode
 ldflags-y += --wrap=devm_cxl_add_rch_dport
 ldflags-y += --wrap=cxl_rcd_component_reg_phys
+ldflags-y += --wrap=cxl_endpoint_parse_cdat
 
 DRIVERS := ../../../drivers
 CXL_SRC := $(DRIVERS)/cxl
index a3cdbb2be038c45e27326925d81ba43294b56c31..908e0d0839369c2e41f090bddc2e9a9b9121b4c9 100644 (file)
@@ -15,6 +15,8 @@
 
 static int interleave_arithmetic;
 
+#define FAKE_QTG_ID    42
+
 #define NR_CXL_HOST_BRIDGES 2
 #define NR_CXL_SINGLE_HOST 1
 #define NR_CXL_RCH 1
@@ -209,7 +211,7 @@ static struct {
                        .granularity = 4,
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
-                       .qtg_id = 0,
+                       .qtg_id = FAKE_QTG_ID,
                        .window_size = SZ_256M * 4UL,
                },
                .target = { 0 },
@@ -224,7 +226,7 @@ static struct {
                        .granularity = 4,
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
-                       .qtg_id = 1,
+                       .qtg_id = FAKE_QTG_ID,
                        .window_size = SZ_256M * 8UL,
                },
                .target = { 0, 1, },
@@ -239,7 +241,7 @@ static struct {
                        .granularity = 4,
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_PMEM,
-                       .qtg_id = 2,
+                       .qtg_id = FAKE_QTG_ID,
                        .window_size = SZ_256M * 4UL,
                },
                .target = { 0 },
@@ -254,7 +256,7 @@ static struct {
                        .granularity = 4,
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_PMEM,
-                       .qtg_id = 3,
+                       .qtg_id = FAKE_QTG_ID,
                        .window_size = SZ_256M * 8UL,
                },
                .target = { 0, 1, },
@@ -269,7 +271,7 @@ static struct {
                        .granularity = 4,
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_PMEM,
-                       .qtg_id = 4,
+                       .qtg_id = FAKE_QTG_ID,
                        .window_size = SZ_256M * 4UL,
                },
                .target = { 2 },
@@ -284,7 +286,7 @@ static struct {
                        .granularity = 4,
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
-                       .qtg_id = 5,
+                       .qtg_id = FAKE_QTG_ID,
                        .window_size = SZ_256M,
                },
                .target = { 3 },
@@ -301,7 +303,7 @@ static struct {
                        .granularity = 4,
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_PMEM,
-                       .qtg_id = 0,
+                       .qtg_id = FAKE_QTG_ID,
                        .window_size = SZ_256M * 8UL,
                },
                .target = { 0, },
@@ -317,7 +319,7 @@ static struct {
                        .granularity = 0,
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_PMEM,
-                       .qtg_id = 1,
+                       .qtg_id = FAKE_QTG_ID,
                        .window_size = SZ_256M * 8UL,
                },
                .target = { 0, 1, },
@@ -333,7 +335,7 @@ static struct {
                        .granularity = 0,
                        .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
                                        ACPI_CEDT_CFMWS_RESTRICT_PMEM,
-                       .qtg_id = 0,
+                       .qtg_id = FAKE_QTG_ID,
                        .window_size = SZ_256M * 16UL,
                },
                .target = { 0, 1, 0, 1, },
@@ -976,6 +978,48 @@ static int mock_cxl_port_enumerate_dports(struct cxl_port *port)
        return 0;
 }
 
+/*
+ * Faking the cxl_dpa_perf for the memdev when appropriate.
+ */
+static void dpa_perf_setup(struct cxl_port *endpoint, struct range *range,
+                          struct cxl_dpa_perf *dpa_perf)
+{
+       dpa_perf->qos_class = FAKE_QTG_ID;
+       dpa_perf->dpa_range = *range;
+       dpa_perf->coord.read_latency = 500;
+       dpa_perf->coord.write_latency = 500;
+       dpa_perf->coord.read_bandwidth = 1000;
+       dpa_perf->coord.write_bandwidth = 1000;
+}
+
+static void mock_cxl_endpoint_parse_cdat(struct cxl_port *port)
+{
+       struct cxl_root *cxl_root __free(put_cxl_root) =
+               find_cxl_root(port);
+       struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
+       struct cxl_dev_state *cxlds = cxlmd->cxlds;
+       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
+       struct range pmem_range = {
+               .start = cxlds->pmem_res.start,
+               .end = cxlds->pmem_res.end,
+       };
+       struct range ram_range = {
+               .start = cxlds->ram_res.start,
+               .end = cxlds->ram_res.end,
+       };
+
+       if (!cxl_root)
+               return;
+
+       if (range_len(&ram_range))
+               dpa_perf_setup(port, &ram_range, &mds->ram_perf);
+
+       if (range_len(&pmem_range))
+               dpa_perf_setup(port, &pmem_range, &mds->pmem_perf);
+
+       cxl_memdev_update_perf(cxlmd);
+}
+
 static struct cxl_mock_ops cxl_mock_ops = {
        .is_mock_adev = is_mock_adev,
        .is_mock_bridge = is_mock_bridge,
@@ -989,6 +1033,7 @@ static struct cxl_mock_ops cxl_mock_ops = {
        .devm_cxl_setup_hdm = mock_cxl_setup_hdm,
        .devm_cxl_add_passthrough_decoder = mock_cxl_add_passthrough_decoder,
        .devm_cxl_enumerate_decoders = mock_cxl_enumerate_decoders,
+       .cxl_endpoint_parse_cdat = mock_cxl_endpoint_parse_cdat,
        .list = LIST_HEAD_INIT(cxl_mock_ops.list),
 };
 
index 1a61e68e30950ba623b52c5920a7874e3d97b9cd..6f737941dc0e164b9611e9dac91cb9e55b69e715 100644 (file)
@@ -285,6 +285,20 @@ resource_size_t __wrap_cxl_rcd_component_reg_phys(struct device *dev,
 }
 EXPORT_SYMBOL_NS_GPL(__wrap_cxl_rcd_component_reg_phys, CXL);
 
+void __wrap_cxl_endpoint_parse_cdat(struct cxl_port *port)
+{
+       int index;
+       struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
+       struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
+
+       if (ops && ops->is_mock_dev(cxlmd->dev.parent))
+               ops->cxl_endpoint_parse_cdat(port);
+       else
+               cxl_endpoint_parse_cdat(port);
+       put_cxl_mock_ops(index);
+}
+EXPORT_SYMBOL_NS_GPL(__wrap_cxl_endpoint_parse_cdat, CXL);
+
 MODULE_LICENSE("GPL v2");
 MODULE_IMPORT_NS(ACPI);
 MODULE_IMPORT_NS(CXL);
index a94223750346c8d897197f3171091459982d29ac..d1b0271d282203b7bccac68aedef0646d1391d59 100644 (file)
@@ -25,6 +25,7 @@ struct cxl_mock_ops {
        int (*devm_cxl_add_passthrough_decoder)(struct cxl_port *port);
        int (*devm_cxl_enumerate_decoders)(
                struct cxl_hdm *hdm, struct cxl_endpoint_dvsec_info *info);
+       void (*cxl_endpoint_parse_cdat)(struct cxl_port *port);
 };
 
 void register_cxl_mock_ops(struct cxl_mock_ops *ops);
index 0b6488efed47ac309c977fd0d3249c150de8219e..7254c110ff23ab9a661ed1ca4d9dc789b8d8762f 100644 (file)
@@ -146,6 +146,7 @@ class LinuxSourceTreeOperationsUml(LinuxSourceTreeOperations):
                """Runs the Linux UML binary. Must be named 'linux'."""
                linux_bin = os.path.join(build_dir, 'linux')
                params.extend(['mem=1G', 'console=tty', 'kunit_shutdown=halt'])
+               print('Running tests with:\n$', linux_bin, ' '.join(shlex.quote(arg) for arg in params))
                return subprocess.Popen([linux_bin] + params,
                                           stdin=subprocess.PIPE,
                                           stdout=subprocess.PIPE,
index 15b6a111c3beaa180af9a1c81db2bed024b2da9c..cd9ae576bfde3fcce5d4ae8733483d59d5bf13f6 100644 (file)
@@ -67,6 +67,7 @@ TARGETS += nsfs
 TARGETS += perf_events
 TARGETS += pidfd
 TARGETS += pid_namespace
+TARGETS += power_supply
 TARGETS += powerpc
 TARGETS += prctl
 TARGETS += proc
@@ -78,6 +79,7 @@ TARGETS += riscv
 TARGETS += rlimits
 TARGETS += rseq
 TARGETS += rtc
+TARGETS += rust
 TARGETS += seccomp
 TARGETS += sgx
 TARGETS += sigaltstack
@@ -236,6 +238,7 @@ ifdef INSTALL_PATH
        install -m 744 kselftest/module.sh $(INSTALL_PATH)/kselftest/
        install -m 744 kselftest/runner.sh $(INSTALL_PATH)/kselftest/
        install -m 744 kselftest/prefix.pl $(INSTALL_PATH)/kselftest/
+       install -m 744 kselftest/ktap_helpers.sh $(INSTALL_PATH)/kselftest/
        install -m 744 run_kselftest.sh $(INSTALL_PATH)/
        rm -f $(TEST_LIST)
        @ret=1; \
index bf84d4a1d9ae2c68ceeac9f25373fd9df01b6935..3c440370c1f0f2b9cc67a754da8087e447efa625 100644 (file)
@@ -193,6 +193,7 @@ static void subtest_task_iters(void)
        ASSERT_EQ(skel->bss->procs_cnt, 1, "procs_cnt");
        ASSERT_EQ(skel->bss->threads_cnt, thread_num + 1, "threads_cnt");
        ASSERT_EQ(skel->bss->proc_threads_cnt, thread_num + 1, "proc_threads_cnt");
+       ASSERT_EQ(skel->bss->invalid_cnt, 0, "invalid_cnt");
        pthread_mutex_unlock(&do_nothing_mutex);
        for (int i = 0; i < thread_num; i++)
                ASSERT_OK(pthread_join(thread_ids[i], &ret), "pthread_join");
diff --git a/tools/testing/selftests/bpf/prog_tests/read_vsyscall.c b/tools/testing/selftests/bpf/prog_tests/read_vsyscall.c
new file mode 100644 (file)
index 0000000..3405923
--- /dev/null
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2024. Huawei Technologies Co., Ltd */
+#include "test_progs.h"
+#include "read_vsyscall.skel.h"
+
+#if defined(__x86_64__)
+/* For VSYSCALL_ADDR */
+#include <asm/vsyscall.h>
+#else
+/* To prevent build failure on non-x86 arch */
+#define VSYSCALL_ADDR 0UL
+#endif
+
+struct read_ret_desc {
+       const char *name;
+       int ret;
+} all_read[] = {
+       { .name = "probe_read_kernel", .ret = -ERANGE },
+       { .name = "probe_read_kernel_str", .ret = -ERANGE },
+       { .name = "probe_read", .ret = -ERANGE },
+       { .name = "probe_read_str", .ret = -ERANGE },
+       { .name = "probe_read_user", .ret = -EFAULT },
+       { .name = "probe_read_user_str", .ret = -EFAULT },
+       { .name = "copy_from_user", .ret = -EFAULT },
+       { .name = "copy_from_user_task", .ret = -EFAULT },
+};
+
+void test_read_vsyscall(void)
+{
+       struct read_vsyscall *skel;
+       unsigned int i;
+       int err;
+
+#if !defined(__x86_64__)
+       test__skip();
+       return;
+#endif
+       skel = read_vsyscall__open_and_load();
+       if (!ASSERT_OK_PTR(skel, "read_vsyscall open_load"))
+               return;
+
+       skel->bss->target_pid = getpid();
+       err = read_vsyscall__attach(skel);
+       if (!ASSERT_EQ(err, 0, "read_vsyscall attach"))
+               goto out;
+
+       /* userspace may don't have vsyscall page due to LEGACY_VSYSCALL_NONE,
+        * but it doesn't affect the returned error codes.
+        */
+       skel->bss->user_ptr = (void *)VSYSCALL_ADDR;
+       usleep(1);
+
+       for (i = 0; i < ARRAY_SIZE(all_read); i++)
+               ASSERT_EQ(skel->bss->read_ret[i], all_read[i].ret, all_read[i].name);
+out:
+       read_vsyscall__destroy(skel);
+}
index 760ad96b4be099ed74779d8895165df5d212f091..d66687f1ee6a8df52cb228010a293a3d4d102216 100644 (file)
@@ -4,10 +4,29 @@
 #include "timer.skel.h"
 #include "timer_failure.skel.h"
 
+#define NUM_THR 8
+
+static void *spin_lock_thread(void *arg)
+{
+       int i, err, prog_fd = *(int *)arg;
+       LIBBPF_OPTS(bpf_test_run_opts, topts);
+
+       for (i = 0; i < 10000; i++) {
+               err = bpf_prog_test_run_opts(prog_fd, &topts);
+               if (!ASSERT_OK(err, "test_run_opts err") ||
+                   !ASSERT_OK(topts.retval, "test_run_opts retval"))
+                       break;
+       }
+
+       pthread_exit(arg);
+}
+
 static int timer(struct timer *timer_skel)
 {
-       int err, prog_fd;
+       int i, err, prog_fd;
        LIBBPF_OPTS(bpf_test_run_opts, topts);
+       pthread_t thread_id[NUM_THR];
+       void *ret;
 
        err = timer__attach(timer_skel);
        if (!ASSERT_OK(err, "timer_attach"))
@@ -43,6 +62,20 @@ static int timer(struct timer *timer_skel)
        /* check that code paths completed */
        ASSERT_EQ(timer_skel->bss->ok, 1 | 2 | 4, "ok");
 
+       prog_fd = bpf_program__fd(timer_skel->progs.race);
+       for (i = 0; i < NUM_THR; i++) {
+               err = pthread_create(&thread_id[i], NULL,
+                                    &spin_lock_thread, &prog_fd);
+               if (!ASSERT_OK(err, "pthread_create"))
+                       break;
+       }
+
+       while (i) {
+               err = pthread_join(thread_id[--i], &ret);
+               if (ASSERT_OK(err, "pthread_join"))
+                       ASSERT_EQ(ret, (void *)&prog_fd, "pthread_join");
+       }
+
        return 0;
 }
 
index c3b45745cbccd71b089d23a4ee3f4d1a296c2de6..6d8b54124cb359697bcb85b369c9bcd7457e71b4 100644 (file)
@@ -511,7 +511,7 @@ static void test_xdp_bonding_features(struct skeletons *skeletons)
        if (!ASSERT_OK(err, "bond bpf_xdp_query"))
                goto out;
 
-       if (!ASSERT_EQ(query_opts.feature_flags, NETDEV_XDP_ACT_MASK,
+       if (!ASSERT_EQ(query_opts.feature_flags, 0,
                       "bond query_opts.feature_flags"))
                goto out;
 
@@ -601,7 +601,7 @@ static void test_xdp_bonding_features(struct skeletons *skeletons)
        if (!ASSERT_OK(err, "bond bpf_xdp_query"))
                goto out;
 
-       ASSERT_EQ(query_opts.feature_flags, NETDEV_XDP_ACT_MASK,
+       ASSERT_EQ(query_opts.feature_flags, 0,
                  "bond query_opts.feature_flags");
 out:
        bpf_link__destroy(link);
index c9b4055cd410ae6378066e28e2f41c9b23d47ab1..e4d53e40ff2086112dff757581ef37f8fdcbe272 100644 (file)
@@ -10,7 +10,7 @@
 char _license[] SEC("license") = "GPL";
 
 pid_t target_pid;
-int procs_cnt, threads_cnt, proc_threads_cnt;
+int procs_cnt, threads_cnt, proc_threads_cnt, invalid_cnt;
 
 void bpf_rcu_read_lock(void) __ksym;
 void bpf_rcu_read_unlock(void) __ksym;
@@ -26,6 +26,16 @@ int iter_task_for_each_sleep(void *ctx)
        procs_cnt = threads_cnt = proc_threads_cnt = 0;
 
        bpf_rcu_read_lock();
+       bpf_for_each(task, pos, NULL, ~0U) {
+               /* Below instructions shouldn't be executed for invalid flags */
+               invalid_cnt++;
+       }
+
+       bpf_for_each(task, pos, NULL, BPF_TASK_ITER_PROC_THREADS) {
+               /* Below instructions shouldn't be executed for invalid task__nullable */
+               invalid_cnt++;
+       }
+
        bpf_for_each(task, pos, NULL, BPF_TASK_ITER_ALL_PROCS)
                if (pos->pid == target_pid)
                        procs_cnt++;
diff --git a/tools/testing/selftests/bpf/progs/read_vsyscall.c b/tools/testing/selftests/bpf/progs/read_vsyscall.c
new file mode 100644 (file)
index 0000000..986f966
--- /dev/null
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2024. Huawei Technologies Co., Ltd */
+#include <linux/types.h>
+#include <bpf/bpf_helpers.h>
+
+#include "bpf_misc.h"
+
+int target_pid = 0;
+void *user_ptr = 0;
+int read_ret[8];
+
+char _license[] SEC("license") = "GPL";
+
+SEC("fentry/" SYS_PREFIX "sys_nanosleep")
+int do_probe_read(void *ctx)
+{
+       char buf[8];
+
+       if ((bpf_get_current_pid_tgid() >> 32) != target_pid)
+               return 0;
+
+       read_ret[0] = bpf_probe_read_kernel(buf, sizeof(buf), user_ptr);
+       read_ret[1] = bpf_probe_read_kernel_str(buf, sizeof(buf), user_ptr);
+       read_ret[2] = bpf_probe_read(buf, sizeof(buf), user_ptr);
+       read_ret[3] = bpf_probe_read_str(buf, sizeof(buf), user_ptr);
+       read_ret[4] = bpf_probe_read_user(buf, sizeof(buf), user_ptr);
+       read_ret[5] = bpf_probe_read_user_str(buf, sizeof(buf), user_ptr);
+
+       return 0;
+}
+
+SEC("fentry.s/" SYS_PREFIX "sys_nanosleep")
+int do_copy_from_user(void *ctx)
+{
+       char buf[8];
+
+       if ((bpf_get_current_pid_tgid() >> 32) != target_pid)
+               return 0;
+
+       read_ret[6] = bpf_copy_from_user(buf, sizeof(buf), user_ptr);
+       read_ret[7] = bpf_copy_from_user_task(buf, sizeof(buf), user_ptr,
+                                             bpf_get_current_task_btf(), 0);
+
+       return 0;
+}
index 8b946c8188c65d10ed86de886ea9aead585de86d..f615da97df26382f4dd758015dd0aaf2cd359614 100644 (file)
@@ -51,7 +51,8 @@ struct {
        __uint(max_entries, 1);
        __type(key, int);
        __type(value, struct elem);
-} abs_timer SEC(".maps"), soft_timer_pinned SEC(".maps"), abs_timer_pinned SEC(".maps");
+} abs_timer SEC(".maps"), soft_timer_pinned SEC(".maps"), abs_timer_pinned SEC(".maps"),
+       race_array SEC(".maps");
 
 __u64 bss_data;
 __u64 abs_data;
@@ -390,3 +391,34 @@ int BPF_PROG2(test5, int, a)
 
        return 0;
 }
+
+static int race_timer_callback(void *race_array, int *race_key, struct bpf_timer *timer)
+{
+       bpf_timer_start(timer, 1000000, 0);
+       return 0;
+}
+
+SEC("syscall")
+int race(void *ctx)
+{
+       struct bpf_timer *timer;
+       int err, race_key = 0;
+       struct elem init;
+
+       __builtin_memset(&init, 0, sizeof(struct elem));
+       bpf_map_update_elem(&race_array, &race_key, &init, BPF_ANY);
+
+       timer = bpf_map_lookup_elem(&race_array, &race_key);
+       if (!timer)
+               return 1;
+
+       err = bpf_timer_init(timer, &race_array, CLOCK_MONOTONIC);
+       if (err && err != -EBUSY)
+               return 1;
+
+       bpf_timer_set_callback(timer, race_timer_callback);
+       bpf_timer_start(timer, 0, 0);
+       bpf_timer_cancel(timer);
+
+       return 0;
+}
index 5905e036e0eaca6aa7c38e06412aabf0e2b1b4b9..a955a6358206eac8a4b5065b531e0171d4cc2a62 100644 (file)
@@ -239,4 +239,74 @@ int bpf_loop_iter_limit_nested(void *unused)
        return 1000 * a + b + c;
 }
 
+struct iter_limit_bug_ctx {
+       __u64 a;
+       __u64 b;
+       __u64 c;
+};
+
+static __naked void iter_limit_bug_cb(void)
+{
+       /* This is the same as C code below, but written
+        * in assembly to control which branches are fall-through.
+        *
+        *   switch (bpf_get_prandom_u32()) {
+        *   case 1:  ctx->a = 42; break;
+        *   case 2:  ctx->b = 42; break;
+        *   default: ctx->c = 42; break;
+        *   }
+        */
+       asm volatile (
+       "r9 = r2;"
+       "call %[bpf_get_prandom_u32];"
+       "r1 = r0;"
+       "r2 = 42;"
+       "r0 = 0;"
+       "if r1 == 0x1 goto 1f;"
+       "if r1 == 0x2 goto 2f;"
+       "*(u64 *)(r9 + 16) = r2;"
+       "exit;"
+       "1: *(u64 *)(r9 + 0) = r2;"
+       "exit;"
+       "2: *(u64 *)(r9 + 8) = r2;"
+       "exit;"
+       :
+       : __imm(bpf_get_prandom_u32)
+       : __clobber_all
+       );
+}
+
+SEC("tc")
+__failure
+__flag(BPF_F_TEST_STATE_FREQ)
+int iter_limit_bug(struct __sk_buff *skb)
+{
+       struct iter_limit_bug_ctx ctx = { 7, 7, 7 };
+
+       bpf_loop(2, iter_limit_bug_cb, &ctx, 0);
+
+       /* This is the same as C code below,
+        * written in assembly to guarantee checks order.
+        *
+        *   if (ctx.a == 42 && ctx.b == 42 && ctx.c == 7)
+        *     asm volatile("r1 /= 0;":::"r1");
+        */
+       asm volatile (
+       "r1 = *(u64 *)%[ctx_a];"
+       "if r1 != 42 goto 1f;"
+       "r1 = *(u64 *)%[ctx_b];"
+       "if r1 != 42 goto 1f;"
+       "r1 = *(u64 *)%[ctx_c];"
+       "if r1 != 7 goto 1f;"
+       "r1 /= 0;"
+       "1:"
+       :
+       : [ctx_a]"m"(ctx.a),
+         [ctx_b]"m"(ctx.b),
+         [ctx_c]"m"(ctx.c)
+       : "r1"
+       );
+       return 0;
+}
+
 char _license[] SEC("license") = "GPL";
index d508486cc0bdc2c917f9386aa2aea796f12d2c1d..9a3d3c389dadda07d1e8d499fea65e307c656056 100755 (executable)
@@ -62,6 +62,8 @@ prio_test()
 
        # create bond
        bond_reset "${param}"
+       # set active_slave to primary eth1 specifically
+       ip -n ${s_ns} link set bond0 type bond active_slave eth1
 
        # check bonding member prio value
        ip -n ${s_ns} link set eth0 type bond_slave prio 0
index 62dc00ee4978a46b1001bad62597d7589d261a75..2d33ee9e9b71ac2e0436abf8e35fe29af92a3cca 100644 (file)
@@ -4,7 +4,7 @@ ifneq ($(PY3),)
 
 TEST_PROGS := test_unprobed_devices.sh
 TEST_GEN_FILES := compatible_list
-TEST_FILES := compatible_ignore_list ktap_helpers.sh
+TEST_FILES := compatible_ignore_list
 
 include ../lib.mk
 
index b07af2a4c4de0b680f37d510337d38b23691a478..2d7e70c5ad2d36d0849a4c923fff64156e3841ca 100755 (executable)
 
 DIR="$(dirname $(readlink -f "$0"))"
 
-source "${DIR}"/ktap_helpers.sh
+source "${DIR}"/../kselftest/ktap_helpers.sh
 
 PDT=/proc/device-tree/
 COMPAT_LIST="${DIR}"/compatible_list
 IGNORE_LIST="${DIR}"/compatible_ignore_list
 
-KSFT_PASS=0
-KSFT_FAIL=1
-KSFT_SKIP=4
-
 ktap_print_header
 
 if [[ ! -d "${PDT}" ]]; then
@@ -33,8 +29,8 @@ if [[ ! -d "${PDT}" ]]; then
 fi
 
 nodes_compatible=$(
-       for node_compat in $(find ${PDT} -name compatible); do
-               node=$(dirname "${node_compat}")
+       for node in $(find ${PDT} -type d); do
+               [ ! -f "${node}"/compatible ] && continue
                # Check if node is available
                if [[ -e "${node}"/status ]]; then
                        status=$(tr -d '\000' < "${node}"/status)
@@ -46,10 +42,11 @@ nodes_compatible=$(
 
 nodes_dev_bound=$(
        IFS=$'\n'
-       for uevent in $(find /sys/devices -name uevent); do
-               if [[ -d "$(dirname "${uevent}")"/driver ]]; then
-                       grep '^OF_FULLNAME=' "${uevent}" | sed -e 's|OF_FULLNAME=||'
-               fi
+       for dev_dir in $(find /sys/devices -type d); do
+               [ ! -f "${dev_dir}"/uevent ] && continue
+               [ ! -d "${dev_dir}"/driver ] && continue
+
+               grep '^OF_FULLNAME=' "${dev_dir}"/uevent | sed -e 's|OF_FULLNAME=||'
        done
        )
 
index e19ab0e857091381948f1bdeb75f08c0f829b38a..759f86e7d263e43bcd7438b5979cc9815c2d4c2f 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/mount.h>
 #include <sys/syscall.h>
 #include <sys/stat.h>
-#include <sys/mount.h>
 #include <sys/mman.h>
 #include <sched.h>
 #include <fcntl.h>
@@ -32,7 +31,11 @@ static int sys_fsmount(int fd, unsigned int flags, unsigned int attr_flags)
 {
        return syscall(__NR_fsmount, fd, flags, attr_flags);
 }
-
+static int sys_mount(const char *src, const char *tgt, const char *fst,
+               unsigned long flags, const void *data)
+{
+       return syscall(__NR_mount, src, tgt, fst, flags, data);
+}
 static int sys_move_mount(int from_dfd, const char *from_pathname,
                          int to_dfd, const char *to_pathname,
                          unsigned int flags)
@@ -166,8 +169,7 @@ int main(int argc, char **argv)
                ksft_test_result_skip("unable to create a new mount namespace\n");
                return 1;
        }
-
-       if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) == -1) {
+       if (sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) == -1) {
                pr_perror("mount");
                return 1;
        }
index c778d4dcc17e58523193ffad46a79212b3e721cd..25d4e0fca385ca3733d17cadb63c235403a0161f 100755 (executable)
@@ -504,7 +504,7 @@ prlog "# of undefined(test bug): " `echo $UNDEFINED_CASES | wc -w`
 if [ "$KTAP" = "1" ]; then
   echo -n "# Totals:"
   echo -n " pass:"`echo $PASSED_CASES | wc -w`
-  echo -n " faii:"`echo $FAILED_CASES | wc -w`
+  echo -n " fail:"`echo $FAILED_CASES | wc -w`
   echo -n " xfail:"`echo $XFAILED_CASES | wc -w`
   echo -n " xpass:0"
   echo -n " skip:"`echo $UNTESTED_CASES $UNSUPPORTED_CASES | wc -w`
index add7d5bf585de51a86450997debc174ef9cbf85a..c45094d1e1d2db2e812f7a7480256f581b63b3b8 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0
-# description: Test file and directory owership changes for eventfs
+# description: Test file and directory ownership changes for eventfs
 
 original_group=`stat -c "%g" .`
 original_owner=`stat -c "%u" .`
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_hotplug.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_hotplug.tc
new file mode 100644 (file)
index 0000000..ccfbfde
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-or-later
+# description: ftrace - function trace across cpu hotplug
+# requires: function:tracer
+
+if ! which nproc ; then
+  nproc() {
+    ls -d /sys/devices/system/cpu/cpu[0-9]* | wc -l
+  }
+fi
+
+NP=`nproc`
+
+if [ $NP -eq 1 ] ;then
+  echo "We cannot test cpu hotplug in UP environment"
+  exit_unresolved
+fi
+
+# Find online cpu
+for i in /sys/devices/system/cpu/cpu[1-9]*; do
+       if [ -f $i/online ] && [ "$(cat $i/online)" = "1" ]; then
+               cpu=$i
+               break
+       fi
+done
+
+if [ -z "$cpu" ]; then
+       echo "We cannot test cpu hotplug with a single cpu online"
+       exit_unresolved
+fi
+
+echo 0 > tracing_on
+echo > trace
+
+: "Set $(basename $cpu) offline/online with function tracer enabled"
+echo function > current_tracer
+echo 1 > tracing_on
+(echo 0 > $cpu/online)
+(echo "forked"; sleep 1)
+(echo 1 > $cpu/online)
+echo 0 > tracing_on
+echo nop > current_tracer
index 4562e13cb26bcde4b643084375c22c1a7c3edfea..717898894ef76f81e1a7304826698e48e68d5d7a 100644 (file)
@@ -40,7 +40,7 @@ grep "id: \(unknown_\|sys_\)" events/raw_syscalls/sys_exit/hist > /dev/null || \
 
 reset_trigger
 
-echo "Test histgram with log2 modifier"
+echo "Test histogram with log2 modifier"
 
 echo 'hist:keys=bytes_req.log2' > events/kmem/kmalloc/trigger
 for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done
index 1ee5518ee6b7f9ffae5ae092c895d9decedc3c92..7f3ca5c78df12968f0aa14168f7dc78001b8fff8 100644 (file)
@@ -17,6 +17,8 @@
  *
  *****************************************************************************/
 
+#define _GNU_SOURCE
+
 #include <errno.h>
 #include <limits.h>
 #include <pthread.h>
@@ -358,6 +360,7 @@ out:
 
 int main(int argc, char *argv[])
 {
+       const char *test_name;
        int c, ret;
 
        while ((c = getopt(argc, argv, "bchlot:v:")) != -1) {
@@ -397,6 +400,14 @@ int main(int argc, char *argv[])
                "\tArguments: broadcast=%d locked=%d owner=%d timeout=%ldns\n",
                broadcast, locked, owner, timeout_ns);
 
+       ret = asprintf(&test_name,
+                      "%s broadcast=%d locked=%d owner=%d timeout=%ldns",
+                      TEST_NAME, broadcast, locked, owner, timeout_ns);
+       if (ret < 0) {
+               ksft_print_msg("Failed to generate test name\n");
+               test_name = TEST_NAME;
+       }
+
        /*
         * FIXME: unit_test is obsolete now that we parse options and the
         * various style of runs are done by run.sh - simplify the code and move
@@ -404,6 +415,6 @@ int main(int argc, char *argv[])
         */
        ret = unit_test(broadcast, locked, owner, timeout_ns);
 
-       print_result(TEST_NAME, ret);
+       print_result(test_name, ret);
        return ret;
 }
index 6c4f901d6fed3c200bbcb40a6ba7dd22c0b2e2bd..110d73917615d177d5d7a891f08d523619c404f3 100644 (file)
@@ -1,2 +1,3 @@
-CONFIG_IOMMUFD
-CONFIG_IOMMUFD_TEST
+CONFIG_IOMMUFD=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_IOMMUFD_TEST=y
index 1a881e7a21d1b26ce7ad19de1cc5ea07d3773ff9..edf1c99c9936c8549e8a2938a2ff11875197b3d4 100644 (file)
@@ -12,6 +12,7 @@
 static unsigned long HUGEPAGE_SIZE;
 
 #define MOCK_PAGE_SIZE (PAGE_SIZE / 2)
+#define MOCK_HUGE_PAGE_SIZE (512 * MOCK_PAGE_SIZE)
 
 static unsigned long get_huge_page_size(void)
 {
@@ -1716,10 +1717,12 @@ FIXTURE(iommufd_dirty_tracking)
 FIXTURE_VARIANT(iommufd_dirty_tracking)
 {
        unsigned long buffer_size;
+       bool hugepages;
 };
 
 FIXTURE_SETUP(iommufd_dirty_tracking)
 {
+       int mmap_flags;
        void *vrc;
        int rc;
 
@@ -1732,25 +1735,41 @@ FIXTURE_SETUP(iommufd_dirty_tracking)
                           variant->buffer_size, rc);
        }
 
+       mmap_flags = MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED;
+       if (variant->hugepages) {
+               /*
+                * MAP_POPULATE will cause the kernel to fail mmap if THPs are
+                * not available.
+                */
+               mmap_flags |= MAP_HUGETLB | MAP_POPULATE;
+       }
        assert((uintptr_t)self->buffer % HUGEPAGE_SIZE == 0);
        vrc = mmap(self->buffer, variant->buffer_size, PROT_READ | PROT_WRITE,
-                  MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+                  mmap_flags, -1, 0);
        assert(vrc == self->buffer);
 
        self->page_size = MOCK_PAGE_SIZE;
        self->bitmap_size =
                variant->buffer_size / self->page_size / BITS_PER_BYTE;
 
-       /* Provision with an extra (MOCK_PAGE_SIZE) for the unaligned case */
+       /* Provision with an extra (PAGE_SIZE) for the unaligned case */
        rc = posix_memalign(&self->bitmap, PAGE_SIZE,
-                           self->bitmap_size + MOCK_PAGE_SIZE);
+                           self->bitmap_size + PAGE_SIZE);
        assert(!rc);
        assert(self->bitmap);
        assert((uintptr_t)self->bitmap % PAGE_SIZE == 0);
 
        test_ioctl_ioas_alloc(&self->ioas_id);
-       test_cmd_mock_domain(self->ioas_id, &self->stdev_id, &self->hwpt_id,
-                            &self->idev_id);
+       /* Enable 1M mock IOMMU hugepages */
+       if (variant->hugepages) {
+               test_cmd_mock_domain_flags(self->ioas_id,
+                                          MOCK_FLAGS_DEVICE_HUGE_IOVA,
+                                          &self->stdev_id, &self->hwpt_id,
+                                          &self->idev_id);
+       } else {
+               test_cmd_mock_domain(self->ioas_id, &self->stdev_id,
+                                    &self->hwpt_id, &self->idev_id);
+       }
 }
 
 FIXTURE_TEARDOWN(iommufd_dirty_tracking)
@@ -1784,12 +1803,26 @@ FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty128M)
        .buffer_size = 128UL * 1024UL * 1024UL,
 };
 
+FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty128M_huge)
+{
+       /* 4K bitmap (128M IOVA range) */
+       .buffer_size = 128UL * 1024UL * 1024UL,
+       .hugepages = true,
+};
+
 FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty256M)
 {
        /* 8K bitmap (256M IOVA range) */
        .buffer_size = 256UL * 1024UL * 1024UL,
 };
 
+FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty256M_huge)
+{
+       /* 8K bitmap (256M IOVA range) */
+       .buffer_size = 256UL * 1024UL * 1024UL,
+       .hugepages = true,
+};
+
 TEST_F(iommufd_dirty_tracking, enforce_dirty)
 {
        uint32_t ioas_id, stddev_id, idev_id;
@@ -1849,65 +1882,80 @@ TEST_F(iommufd_dirty_tracking, device_dirty_capability)
 
 TEST_F(iommufd_dirty_tracking, get_dirty_bitmap)
 {
-       uint32_t stddev_id;
+       uint32_t page_size = MOCK_PAGE_SIZE;
        uint32_t hwpt_id;
        uint32_t ioas_id;
 
+       if (variant->hugepages)
+               page_size = MOCK_HUGE_PAGE_SIZE;
+
        test_ioctl_ioas_alloc(&ioas_id);
        test_ioctl_ioas_map_fixed_id(ioas_id, self->buffer,
                                     variant->buffer_size, MOCK_APERTURE_START);
 
        test_cmd_hwpt_alloc(self->idev_id, ioas_id,
                            IOMMU_HWPT_ALLOC_DIRTY_TRACKING, &hwpt_id);
-       test_cmd_mock_domain(hwpt_id, &stddev_id, NULL, NULL);
 
        test_cmd_set_dirty_tracking(hwpt_id, true);
 
        test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,
-                               MOCK_APERTURE_START, self->page_size,
+                               MOCK_APERTURE_START, self->page_size, page_size,
                                self->bitmap, self->bitmap_size, 0, _metadata);
 
        /* PAGE_SIZE unaligned bitmap */
        test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,
-                               MOCK_APERTURE_START, self->page_size,
+                               MOCK_APERTURE_START, self->page_size, page_size,
                                self->bitmap + MOCK_PAGE_SIZE,
                                self->bitmap_size, 0, _metadata);
 
-       test_ioctl_destroy(stddev_id);
+       /* u64 unaligned bitmap */
+       test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,
+                               MOCK_APERTURE_START, self->page_size, page_size,
+                               self->bitmap + 0xff1, self->bitmap_size, 0,
+                               _metadata);
+
        test_ioctl_destroy(hwpt_id);
 }
 
 TEST_F(iommufd_dirty_tracking, get_dirty_bitmap_no_clear)
 {
-       uint32_t stddev_id;
+       uint32_t page_size = MOCK_PAGE_SIZE;
        uint32_t hwpt_id;
        uint32_t ioas_id;
 
+       if (variant->hugepages)
+               page_size = MOCK_HUGE_PAGE_SIZE;
+
        test_ioctl_ioas_alloc(&ioas_id);
        test_ioctl_ioas_map_fixed_id(ioas_id, self->buffer,
                                     variant->buffer_size, MOCK_APERTURE_START);
 
        test_cmd_hwpt_alloc(self->idev_id, ioas_id,
                            IOMMU_HWPT_ALLOC_DIRTY_TRACKING, &hwpt_id);
-       test_cmd_mock_domain(hwpt_id, &stddev_id, NULL, NULL);
 
        test_cmd_set_dirty_tracking(hwpt_id, true);
 
        test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,
-                               MOCK_APERTURE_START, self->page_size,
+                               MOCK_APERTURE_START, self->page_size, page_size,
                                self->bitmap, self->bitmap_size,
                                IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR,
                                _metadata);
 
        /* Unaligned bitmap */
        test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,
-                               MOCK_APERTURE_START, self->page_size,
+                               MOCK_APERTURE_START, self->page_size, page_size,
                                self->bitmap + MOCK_PAGE_SIZE,
                                self->bitmap_size,
                                IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR,
                                _metadata);
 
-       test_ioctl_destroy(stddev_id);
+       /* u64 unaligned bitmap */
+       test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,
+                               MOCK_APERTURE_START, self->page_size, page_size,
+                               self->bitmap + 0xff1, self->bitmap_size,
+                               IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR,
+                               _metadata);
+
        test_ioctl_destroy(hwpt_id);
 }
 
index c646264aa41fdc1871c60bba6dc25841767f399b..8d2b46b2114da814f75740992c0dc4b1be14d33b 100644 (file)
@@ -344,16 +344,19 @@ static int _test_cmd_mock_domain_set_dirty(int fd, __u32 hwpt_id, size_t length,
                                                  page_size, bitmap, nr))
 
 static int _test_mock_dirty_bitmaps(int fd, __u32 hwpt_id, size_t length,
-                                   __u64 iova, size_t page_size, __u64 *bitmap,
+                                   __u64 iova, size_t page_size,
+                                   size_t pte_page_size, __u64 *bitmap,
                                    __u64 bitmap_size, __u32 flags,
                                    struct __test_metadata *_metadata)
 {
-       unsigned long i, nbits = bitmap_size * BITS_PER_BYTE;
-       unsigned long nr = nbits / 2;
+       unsigned long npte = pte_page_size / page_size, pteset = 2 * npte;
+       unsigned long nbits = bitmap_size * BITS_PER_BYTE;
+       unsigned long j, i, nr = nbits / pteset ?: 1;
        __u64 out_dirty = 0;
 
        /* Mark all even bits as dirty in the mock domain */
-       for (i = 0; i < nbits; i += 2)
+       memset(bitmap, 0, bitmap_size);
+       for (i = 0; i < nbits; i += pteset)
                set_bit(i, (unsigned long *)bitmap);
 
        test_cmd_mock_domain_set_dirty(fd, hwpt_id, length, iova, page_size,
@@ -365,8 +368,12 @@ static int _test_mock_dirty_bitmaps(int fd, __u32 hwpt_id, size_t length,
        test_cmd_get_dirty_bitmap(fd, hwpt_id, length, iova, page_size, bitmap,
                                  flags);
        /* Beware ASSERT_EQ() is two statements -- braces are not redundant! */
-       for (i = 0; i < nbits; i++) {
-               ASSERT_EQ(!(i % 2), test_bit(i, (unsigned long *)bitmap));
+       for (i = 0; i < nbits; i += pteset) {
+               for (j = 0; j < pteset; j++) {
+                       ASSERT_EQ(j < npte,
+                                 test_bit(i + j, (unsigned long *)bitmap));
+               }
+               ASSERT_EQ(!(i % pteset), test_bit(i, (unsigned long *)bitmap));
        }
 
        memset(bitmap, 0, bitmap_size);
@@ -374,19 +381,23 @@ static int _test_mock_dirty_bitmaps(int fd, __u32 hwpt_id, size_t length,
                                  flags);
 
        /* It as read already -- expect all zeroes */
-       for (i = 0; i < nbits; i++) {
-               ASSERT_EQ(!(i % 2) && (flags &
-                                      IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR),
-                         test_bit(i, (unsigned long *)bitmap));
+       for (i = 0; i < nbits; i += pteset) {
+               for (j = 0; j < pteset; j++) {
+                       ASSERT_EQ(
+                               (j < npte) &&
+                                       (flags &
+                                        IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR),
+                               test_bit(i + j, (unsigned long *)bitmap));
+               }
        }
 
        return 0;
 }
-#define test_mock_dirty_bitmaps(hwpt_id, length, iova, page_size, bitmap,      \
-                               bitmap_size, flags, _metadata)                 \
+#define test_mock_dirty_bitmaps(hwpt_id, length, iova, page_size, pte_size,\
+                               bitmap, bitmap_size, flags, _metadata)     \
        ASSERT_EQ(0, _test_mock_dirty_bitmaps(self->fd, hwpt_id, length, iova, \
-                                             page_size, bitmap, bitmap_size,  \
-                                             flags, _metadata))
+                                             page_size, pte_size, bitmap,     \
+                                             bitmap_size, flags, _metadata))
 
 static int _test_cmd_create_access(int fd, unsigned int ioas_id,
                                   __u32 *access_id, unsigned int flags)
similarity index 66%
rename from tools/testing/selftests/dt/ktap_helpers.sh
rename to tools/testing/selftests/kselftest/ktap_helpers.sh
index 8dfae51bb4e2e034b8d0e55ce120c41171bb981e..f2fbb914e058d2bae0f8e8e455cc20a1626c988e 100644 (file)
@@ -9,14 +9,27 @@ KTAP_CNT_PASS=0
 KTAP_CNT_FAIL=0
 KTAP_CNT_SKIP=0
 
+KSFT_PASS=0
+KSFT_FAIL=1
+KSFT_XFAIL=2
+KSFT_XPASS=3
+KSFT_SKIP=4
+
+KSFT_NUM_TESTS=0
+
 ktap_print_header() {
        echo "TAP version 13"
 }
 
+ktap_print_msg()
+{
+       echo "#" $@
+}
+
 ktap_set_plan() {
-       num_tests="$1"
+       KSFT_NUM_TESTS="$1"
 
-       echo "1..$num_tests"
+       echo "1..$KSFT_NUM_TESTS"
 }
 
 ktap_skip_all() {
@@ -65,6 +78,34 @@ ktap_test_fail() {
        KTAP_CNT_FAIL=$((KTAP_CNT_FAIL+1))
 }
 
+ktap_test_result() {
+       description="$1"
+       shift
+
+       if $@; then
+               ktap_test_pass "$description"
+       else
+               ktap_test_fail "$description"
+       fi
+}
+
+ktap_exit_fail_msg() {
+       echo "Bail out! " $@
+       ktap_print_totals
+
+       exit "$KSFT_FAIL"
+}
+
+ktap_finished() {
+       ktap_print_totals
+
+       if [ $(("$KTAP_CNT_PASS" + "$KTAP_CNT_SKIP")) -eq "$KSFT_NUM_TESTS" ]; then
+               exit "$KSFT_PASS"
+       else
+               exit "$KSFT_FAIL"
+       fi
+}
+
 ktap_print_totals() {
        echo "# Totals: pass:$KTAP_CNT_PASS fail:$KTAP_CNT_FAIL xfail:0 xpass:0 skip:$KTAP_CNT_SKIP error:0"
 }
index 274b8465b42a5aa1d210ced625db7ce42799e693..2cb8dd1f8275fb0a83e1a4cb605e7b63c46ef221 100644 (file)
@@ -248,7 +248,7 @@ static void *test_vcpu_run(void *arg)
                REPORT_GUEST_ASSERT(uc);
                break;
        default:
-               TEST_FAIL("Unexpected guest exit\n");
+               TEST_FAIL("Unexpected guest exit");
        }
 
        return NULL;
@@ -287,7 +287,7 @@ static int test_migrate_vcpu(unsigned int vcpu_idx)
 
        /* Allow the error where the vCPU thread is already finished */
        TEST_ASSERT(ret == 0 || ret == ESRCH,
-                   "Failed to migrate the vCPU:%u to pCPU: %u; ret: %d\n",
+                   "Failed to migrate the vCPU:%u to pCPU: %u; ret: %d",
                    vcpu_idx, new_pcpu, ret);
 
        return ret;
@@ -326,12 +326,12 @@ static void test_run(struct kvm_vm *vm)
 
        pthread_mutex_init(&vcpu_done_map_lock, NULL);
        vcpu_done_map = bitmap_zalloc(test_args.nr_vcpus);
-       TEST_ASSERT(vcpu_done_map, "Failed to allocate vcpu done bitmap\n");
+       TEST_ASSERT(vcpu_done_map, "Failed to allocate vcpu done bitmap");
 
        for (i = 0; i < (unsigned long)test_args.nr_vcpus; i++) {
                ret = pthread_create(&pt_vcpu_run[i], NULL, test_vcpu_run,
                                     (void *)(unsigned long)i);
-               TEST_ASSERT(!ret, "Failed to create vCPU-%d pthread\n", i);
+               TEST_ASSERT(!ret, "Failed to create vCPU-%d pthread", i);
        }
 
        /* Spawn a thread to control the vCPU migrations */
@@ -340,7 +340,7 @@ static void test_run(struct kvm_vm *vm)
 
                ret = pthread_create(&pt_vcpu_migration, NULL,
                                        test_vcpu_migration, NULL);
-               TEST_ASSERT(!ret, "Failed to create the migration pthread\n");
+               TEST_ASSERT(!ret, "Failed to create the migration pthread");
        }
 
 
@@ -384,7 +384,7 @@ static struct kvm_vm *test_vm_create(void)
                if (kvm_has_cap(KVM_CAP_COUNTER_OFFSET))
                        vm_ioctl(vm, KVM_ARM_SET_COUNTER_OFFSET, &test_args.offset);
                else
-                       TEST_FAIL("no support for global offset\n");
+                       TEST_FAIL("no support for global offset");
        }
 
        for (i = 0; i < nr_vcpus; i++)
index 31f66ba97228babe46bf2c46640077065ded7241..27c10e7a7e0124f01e0e636dfb25944c0d7abc95 100644 (file)
@@ -175,18 +175,18 @@ static void test_fw_regs_before_vm_start(struct kvm_vcpu *vcpu)
                /* First 'read' should be an upper limit of the features supported */
                vcpu_get_reg(vcpu, reg_info->reg, &val);
                TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit),
-                       "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n",
+                       "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx",
                        reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val);
 
                /* Test a 'write' by disabling all the features of the register map */
                ret = __vcpu_set_reg(vcpu, reg_info->reg, 0);
                TEST_ASSERT(ret == 0,
-                       "Failed to clear all the features of reg: 0x%lx; ret: %d\n",
+                       "Failed to clear all the features of reg: 0x%lx; ret: %d",
                        reg_info->reg, errno);
 
                vcpu_get_reg(vcpu, reg_info->reg, &val);
                TEST_ASSERT(val == 0,
-                       "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg);
+                       "Expected all the features to be cleared for reg: 0x%lx", reg_info->reg);
 
                /*
                 * Test enabling a feature that's not supported.
@@ -195,7 +195,7 @@ static void test_fw_regs_before_vm_start(struct kvm_vcpu *vcpu)
                if (reg_info->max_feat_bit < 63) {
                        ret = __vcpu_set_reg(vcpu, reg_info->reg, BIT(reg_info->max_feat_bit + 1));
                        TEST_ASSERT(ret != 0 && errno == EINVAL,
-                       "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n",
+                       "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx",
                        errno, reg_info->reg);
                }
        }
@@ -216,7 +216,7 @@ static void test_fw_regs_after_vm_start(struct kvm_vcpu *vcpu)
                 */
                vcpu_get_reg(vcpu, reg_info->reg, &val);
                TEST_ASSERT(val == 0,
-                       "Expected all the features to be cleared for reg: 0x%lx\n",
+                       "Expected all the features to be cleared for reg: 0x%lx",
                        reg_info->reg);
 
                /*
@@ -226,7 +226,7 @@ static void test_fw_regs_after_vm_start(struct kvm_vcpu *vcpu)
                 */
                ret = __vcpu_set_reg(vcpu, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit));
                TEST_ASSERT(ret != 0 && errno == EBUSY,
-               "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n",
+               "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx",
                errno, reg_info->reg);
        }
 }
@@ -265,7 +265,7 @@ static void test_guest_stage(struct kvm_vm **vm, struct kvm_vcpu **vcpu)
        case TEST_STAGE_HVC_IFACE_FALSE_INFO:
                break;
        default:
-               TEST_FAIL("Unknown test stage: %d\n", prev_stage);
+               TEST_FAIL("Unknown test stage: %d", prev_stage);
        }
 }
 
@@ -294,7 +294,7 @@ static void test_run(void)
                        REPORT_GUEST_ASSERT(uc);
                        break;
                default:
-                       TEST_FAIL("Unexpected guest exit\n");
+                       TEST_FAIL("Unexpected guest exit");
                }
        }
 
index 08a5ca5bed56a9f602c01c024b19771a5cc9e219..53fddad57cbbc689231fd81cd1947d27f1c84807 100644 (file)
@@ -414,10 +414,10 @@ static bool punch_hole_in_backing_store(struct kvm_vm *vm,
        if (fd != -1) {
                ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                                0, paging_size);
-               TEST_ASSERT(ret == 0, "fallocate failed\n");
+               TEST_ASSERT(ret == 0, "fallocate failed");
        } else {
                ret = madvise(hva, paging_size, MADV_DONTNEED);
-               TEST_ASSERT(ret == 0, "madvise failed\n");
+               TEST_ASSERT(ret == 0, "madvise failed");
        }
 
        return true;
@@ -501,7 +501,7 @@ static bool handle_cmd(struct kvm_vm *vm, int cmd)
 
 void fail_vcpu_run_no_handler(int ret)
 {
-       TEST_FAIL("Unexpected vcpu run failure\n");
+       TEST_FAIL("Unexpected vcpu run failure");
 }
 
 void fail_vcpu_run_mmio_no_syndrome_handler(int ret)
index f4ceae9c89257d211bab149be149510898e02290..2d189f3da228cdb74b8a8976c0736abde18ce9b5 100644 (file)
@@ -178,7 +178,7 @@ static void expect_call_denied(struct kvm_vcpu *vcpu)
        struct ucall uc;
 
        if (get_ucall(vcpu, &uc) != UCALL_SYNC)
-               TEST_FAIL("Unexpected ucall: %lu\n", uc.cmd);
+               TEST_FAIL("Unexpected ucall: %lu", uc.cmd);
 
        TEST_ASSERT(uc.args[1] == SMCCC_RET_NOT_SUPPORTED,
                    "Unexpected SMCCC return code: %lu", uc.args[1]);
index 9d51b56913496ed38f0413183b49380aba017ba3..5f9713364693b4eacd175bad2b1531e6a91f5504 100644 (file)
@@ -517,11 +517,11 @@ static void test_create_vpmu_vm_with_pmcr_n(uint64_t pmcr_n, bool expect_fail)
 
        if (expect_fail)
                TEST_ASSERT(pmcr_orig == pmcr,
-                           "PMCR.N modified by KVM to a larger value (PMCR: 0x%lx) for pmcr_n: 0x%lx\n",
+                           "PMCR.N modified by KVM to a larger value (PMCR: 0x%lx) for pmcr_n: 0x%lx",
                            pmcr, pmcr_n);
        else
                TEST_ASSERT(pmcr_n == get_pmcr_n(pmcr),
-                           "Failed to update PMCR.N to %lu (received: %lu)\n",
+                           "Failed to update PMCR.N to %lu (received: %lu)",
                            pmcr_n, get_pmcr_n(pmcr));
 }
 
@@ -594,12 +594,12 @@ static void run_pmregs_validity_test(uint64_t pmcr_n)
                 */
                vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(set_reg_id), &reg_val);
                TEST_ASSERT((reg_val & (~valid_counters_mask)) == 0,
-                           "Initial read of set_reg: 0x%llx has unimplemented counters enabled: 0x%lx\n",
+                           "Initial read of set_reg: 0x%llx has unimplemented counters enabled: 0x%lx",
                            KVM_ARM64_SYS_REG(set_reg_id), reg_val);
 
                vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(clr_reg_id), &reg_val);
                TEST_ASSERT((reg_val & (~valid_counters_mask)) == 0,
-                           "Initial read of clr_reg: 0x%llx has unimplemented counters enabled: 0x%lx\n",
+                           "Initial read of clr_reg: 0x%llx has unimplemented counters enabled: 0x%lx",
                            KVM_ARM64_SYS_REG(clr_reg_id), reg_val);
 
                /*
@@ -611,12 +611,12 @@ static void run_pmregs_validity_test(uint64_t pmcr_n)
 
                vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(set_reg_id), &reg_val);
                TEST_ASSERT((reg_val & (~valid_counters_mask)) == 0,
-                           "Read of set_reg: 0x%llx has unimplemented counters enabled: 0x%lx\n",
+                           "Read of set_reg: 0x%llx has unimplemented counters enabled: 0x%lx",
                            KVM_ARM64_SYS_REG(set_reg_id), reg_val);
 
                vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(clr_reg_id), &reg_val);
                TEST_ASSERT((reg_val & (~valid_counters_mask)) == 0,
-                           "Read of clr_reg: 0x%llx has unimplemented counters enabled: 0x%lx\n",
+                           "Read of clr_reg: 0x%llx has unimplemented counters enabled: 0x%lx",
                            KVM_ARM64_SYS_REG(clr_reg_id), reg_val);
        }
 
index 09c116a82a8499d7b14dc60bdcb088dd6c6914c7..bf3609f718544fb2b5d6c116d8eec4b28c29ab98 100644 (file)
@@ -45,10 +45,10 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args)
 
        /* Let the guest access its memory */
        ret = _vcpu_run(vcpu);
-       TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret);
+       TEST_ASSERT(ret == 0, "vcpu_run failed: %d", ret);
        if (get_ucall(vcpu, NULL) != UCALL_SYNC) {
                TEST_ASSERT(false,
-                           "Invalid guest sync status: exit_reason=%s\n",
+                           "Invalid guest sync status: exit_reason=%s",
                            exit_reason_str(run->exit_reason));
        }
 
index d374dbcf9a535dbd9efc7316e9c63c4152010e7a..504f6fe980e8fd7bf57ae105ed574fd3bf62d583 100644 (file)
@@ -88,9 +88,9 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args)
                ret = _vcpu_run(vcpu);
                ts_diff = timespec_elapsed(start);
 
-               TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret);
+               TEST_ASSERT(ret == 0, "vcpu_run failed: %d", ret);
                TEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC,
-                           "Invalid guest sync status: exit_reason=%s\n",
+                           "Invalid guest sync status: exit_reason=%s",
                            exit_reason_str(run->exit_reason));
 
                pr_debug("Got sync event from vCPU %d\n", vcpu_idx);
index 6cbecf4997676f327095a399a75dcfa514fca13c..eaad5b20854ccf095a4447245554f8ecd48e0506 100644 (file)
@@ -262,7 +262,7 @@ static void default_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err)
                    "vcpu run failed: errno=%d", err);
 
        TEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC,
-                   "Invalid guest sync status: exit_reason=%s\n",
+                   "Invalid guest sync status: exit_reason=%s",
                    exit_reason_str(run->exit_reason));
 
        vcpu_handle_sync_stop();
@@ -376,7 +376,10 @@ static void dirty_ring_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot,
 
        cleared = kvm_vm_reset_dirty_ring(vcpu->vm);
 
-       /* Cleared pages should be the same as collected */
+       /*
+        * Cleared pages should be the same as collected, as KVM is supposed to
+        * clear only the entries that have been harvested.
+        */
        TEST_ASSERT(cleared == count, "Reset dirty pages (%u) mismatch "
                    "with collected (%u)", cleared, count);
 
@@ -410,17 +413,11 @@ static void dirty_ring_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err)
                pr_info("vcpu continues now.\n");
        } else {
                TEST_ASSERT(false, "Invalid guest sync status: "
-                           "exit_reason=%s\n",
+                           "exit_reason=%s",
                            exit_reason_str(run->exit_reason));
        }
 }
 
-static void dirty_ring_before_vcpu_join(void)
-{
-       /* Kick another round of vcpu just to make sure it will quit */
-       sem_post(&sem_vcpu_cont);
-}
-
 struct log_mode {
        const char *name;
        /* Return true if this mode is supported, otherwise false */
@@ -433,7 +430,6 @@ struct log_mode {
                                     uint32_t *ring_buf_idx);
        /* Hook to call when after each vcpu run */
        void (*after_vcpu_run)(struct kvm_vcpu *vcpu, int ret, int err);
-       void (*before_vcpu_join) (void);
 } log_modes[LOG_MODE_NUM] = {
        {
                .name = "dirty-log",
@@ -452,7 +448,6 @@ struct log_mode {
                .supported = dirty_ring_supported,
                .create_vm_done = dirty_ring_create_vm_done,
                .collect_dirty_pages = dirty_ring_collect_dirty_pages,
-               .before_vcpu_join = dirty_ring_before_vcpu_join,
                .after_vcpu_run = dirty_ring_after_vcpu_run,
        },
 };
@@ -513,14 +508,6 @@ static void log_mode_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err)
                mode->after_vcpu_run(vcpu, ret, err);
 }
 
-static void log_mode_before_vcpu_join(void)
-{
-       struct log_mode *mode = &log_modes[host_log_mode];
-
-       if (mode->before_vcpu_join)
-               mode->before_vcpu_join();
-}
-
 static void generate_random_array(uint64_t *guest_array, uint64_t size)
 {
        uint64_t i;
@@ -719,6 +706,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
        struct kvm_vm *vm;
        unsigned long *bmap;
        uint32_t ring_buf_idx = 0;
+       int sem_val;
 
        if (!log_mode_supported()) {
                print_skip("Log mode '%s' not supported",
@@ -788,12 +776,22 @@ static void run_test(enum vm_guest_mode mode, void *arg)
        /* Start the iterations */
        iteration = 1;
        sync_global_to_guest(vm, iteration);
-       host_quit = false;
+       WRITE_ONCE(host_quit, false);
        host_dirty_count = 0;
        host_clear_count = 0;
        host_track_next_count = 0;
        WRITE_ONCE(dirty_ring_vcpu_ring_full, false);
 
+       /*
+        * Ensure the previous iteration didn't leave a dangling semaphore, i.e.
+        * that the main task and vCPU worker were synchronized and completed
+        * verification of all iterations.
+        */
+       sem_getvalue(&sem_vcpu_stop, &sem_val);
+       TEST_ASSERT_EQ(sem_val, 0);
+       sem_getvalue(&sem_vcpu_cont, &sem_val);
+       TEST_ASSERT_EQ(sem_val, 0);
+
        pthread_create(&vcpu_thread, NULL, vcpu_worker, vcpu);
 
        while (iteration < p->iterations) {
@@ -819,15 +817,21 @@ static void run_test(enum vm_guest_mode mode, void *arg)
                assert(host_log_mode == LOG_MODE_DIRTY_RING ||
                       atomic_read(&vcpu_sync_stop_requested) == false);
                vm_dirty_log_verify(mode, bmap);
-               sem_post(&sem_vcpu_cont);
 
-               iteration++;
+               /*
+                * Set host_quit before sem_vcpu_cont in the final iteration to
+                * ensure that the vCPU worker doesn't resume the guest.  As
+                * above, the dirty ring test may stop and wait even when not
+                * explicitly request to do so, i.e. would hang waiting for a
+                * "continue" if it's allowed to resume the guest.
+                */
+               if (++iteration == p->iterations)
+                       WRITE_ONCE(host_quit, true);
+
+               sem_post(&sem_vcpu_cont);
                sync_global_to_guest(vm, iteration);
        }
 
-       /* Tell the vcpu thread to quit */
-       host_quit = true;
-       log_mode_before_vcpu_join();
        pthread_join(vcpu_thread, NULL);
 
        pr_info("Total bits checked: dirty (%"PRIu64"), clear (%"PRIu64"), "
index 8274ef04301f6704528293206603efca9690b29c..91f05f78e8249124332e9a28fef53daf4e746fd1 100644 (file)
@@ -152,7 +152,7 @@ static void check_supported(struct vcpu_reg_list *c)
                        continue;
 
                __TEST_REQUIRE(kvm_has_cap(s->capability),
-                              "%s: %s not available, skipping tests\n",
+                              "%s: %s not available, skipping tests",
                               config_name(c), s->name);
        }
 }
index 41230b74619023d447f48fc8555936e194ce9387..3502caa3590c6488442a015ff40e5fa1027e41e6 100644 (file)
@@ -98,7 +98,7 @@ static void ucall_abort(const char *assert_msg, const char *expected_assert_msg)
        int offset = len_str - len_substr;
 
        TEST_ASSERT(len_substr <= len_str,
-                   "Expected '%s' to be a substring of '%s'\n",
+                   "Expected '%s' to be a substring of '%s'",
                    assert_msg, expected_assert_msg);
 
        TEST_ASSERT(strcmp(&assert_msg[offset], expected_assert_msg) == 0,
@@ -116,7 +116,7 @@ static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf,
                vcpu_run(vcpu);
 
                TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
-                           "Unexpected exit reason: %u (%s),\n",
+                           "Unexpected exit reason: %u (%s),",
                            run->exit_reason, exit_reason_str(run->exit_reason));
 
                switch (get_ucall(vcpu, &uc)) {
@@ -161,11 +161,11 @@ static void test_limits(void)
        vcpu_run(vcpu);
 
        TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
-                   "Unexpected exit reason: %u (%s),\n",
+                   "Unexpected exit reason: %u (%s),",
                    run->exit_reason, exit_reason_str(run->exit_reason));
 
        TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_ABORT,
-                   "Unexpected ucall command: %lu,  Expected: %u (UCALL_ABORT)\n",
+                   "Unexpected ucall command: %lu,  Expected: %u (UCALL_ABORT)",
                    uc.cmd, UCALL_ABORT);
 
        kvm_vm_free(vm);
index f5d59b9934f184163e3e1e48578508d2a5255eae..decc521fc7603b1440cbb414f94acdf042ce1c5a 100644 (file)
@@ -41,7 +41,7 @@ static void *run_vcpu(void *arg)
 
        vcpu_run(vcpu);
 
-       TEST_ASSERT(false, "%s: exited with reason %d: %s\n",
+       TEST_ASSERT(false, "%s: exited with reason %d: %s",
                    __func__, run->exit_reason,
                    exit_reason_str(run->exit_reason));
        pthread_exit(NULL);
@@ -55,7 +55,7 @@ static void *sleeping_thread(void *arg)
                fd = open("/dev/null", O_RDWR);
                close(fd);
        }
-       TEST_ASSERT(false, "%s: exited\n", __func__);
+       TEST_ASSERT(false, "%s: exited", __func__);
        pthread_exit(NULL);
 }
 
@@ -118,7 +118,7 @@ static void run_test(uint32_t run)
        for (i = 0; i < VCPU_NUM; ++i)
                check_join(threads[i], &b);
        /* Should not be reached */
-       TEST_ASSERT(false, "%s: [%d] child escaped the ninja\n", __func__, run);
+       TEST_ASSERT(false, "%s: [%d] child escaped the ninja", __func__, run);
 }
 
 void wait_for_child_setup(pid_t pid)
index 71a41fa924b7d09cb1a3aaf9bcc779d7d3311110..50a5e31ba8da1bc904d7cb04be2571bf786b847e 100644 (file)
@@ -195,4 +195,6 @@ __printf(3, 4) int guest_snprintf(char *buf, int n, const char *fmt, ...);
 
 char *strdup_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2), nonnull(1)));
 
+char *sys_get_cur_clocksource(void);
+
 #endif /* SELFTEST_KVM_TEST_UTIL_H */
index a84863503fcb46cda532840f3be4512cf35061c3..5bca8c947c8253819dd07ed6266a03194a0c1857 100644 (file)
@@ -1271,4 +1271,6 @@ void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
 #define PFERR_GUEST_PAGE_MASK  BIT_ULL(PFERR_GUEST_PAGE_BIT)
 #define PFERR_IMPLICIT_ACCESS  BIT_ULL(PFERR_IMPLICIT_ACCESS_BIT)
 
+bool sys_clocksource_is_based_on_tsc(void);
+
 #endif /* SELFTEST_KVM_PROCESSOR_H */
index 31b3cb24b9a75cdf0cc9e71f1f0cf820ec20edae..b9e23265e4b3833a4fa07acca1461fb35cd8297f 100644 (file)
@@ -65,7 +65,7 @@ int main(int argc, char *argv[])
 
                        int r = setrlimit(RLIMIT_NOFILE, &rl);
                        __TEST_REQUIRE(r >= 0,
-                                      "RLIMIT_NOFILE hard limit is too low (%d, wanted %d)\n",
+                                      "RLIMIT_NOFILE hard limit is too low (%d, wanted %d)",
                                       old_rlim_max, nr_fds_wanted);
                } else {
                        TEST_ASSERT(!setrlimit(RLIMIT_NOFILE, &rl), "setrlimit() failed!");
index e37dc9c21888f4bc4ed06bf3bacff89e28c68b5d..e0ba97ac1c5611a386981caf679b12910b600d8b 100644 (file)
@@ -204,9 +204,9 @@ static void *vcpu_worker(void *data)
                ret = _vcpu_run(vcpu);
                ts_diff = timespec_elapsed(start);
 
-               TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret);
+               TEST_ASSERT(ret == 0, "vcpu_run failed: %d", ret);
                TEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC,
-                           "Invalid guest sync status: exit_reason=%s\n",
+                           "Invalid guest sync status: exit_reason=%s",
                            exit_reason_str(vcpu->run->exit_reason));
 
                pr_debug("Got sync event from vCPU %d\n", vcpu->id);
index 41c776b642c0cd0be722e4bad1e0e9cc1f0cff80..43b9a72833602e072ad7ba5e7e69c341fb8469a6 100644 (file)
@@ -398,7 +398,7 @@ void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...)
        int i;
 
        TEST_ASSERT(num >= 1 && num <= 8, "Unsupported number of args,\n"
-                   "  num: %u\n", num);
+                   "  num: %u", num);
 
        va_start(ap, num);
 
index b5f28d21a947704456b3e8cc9a0e86825d386c2f..184378d593e9a8e45ca7d46e6116ca692d710abd 100644 (file)
@@ -38,7 +38,7 @@ int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs,
        struct list_head *iter;
        unsigned int nr_gic_pages, nr_vcpus_created = 0;
 
-       TEST_ASSERT(nr_vcpus, "Number of vCPUs cannot be empty\n");
+       TEST_ASSERT(nr_vcpus, "Number of vCPUs cannot be empty");
 
        /*
         * Make sure that the caller is infact calling this
@@ -47,7 +47,7 @@ int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs,
        list_for_each(iter, &vm->vcpus)
                nr_vcpus_created++;
        TEST_ASSERT(nr_vcpus == nr_vcpus_created,
-                       "Number of vCPUs requested (%u) doesn't match with the ones created for the VM (%u)\n",
+                       "Number of vCPUs requested (%u) doesn't match with the ones created for the VM (%u)",
                        nr_vcpus, nr_vcpus_created);
 
        /* Distributor setup */
index 266f3876e10aff98955b6301d4e0ddaa3236e26e..f34d926d9735913f5ba826a8bee07aa0b8169d43 100644 (file)
@@ -184,7 +184,7 @@ void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename)
                                "Seek to program segment offset failed,\n"
                                "  program header idx: %u errno: %i\n"
                                "  offset_rv: 0x%jx\n"
-                               "  expected: 0x%jx\n",
+                               "  expected: 0x%jx",
                                n1, errno, (intmax_t) offset_rv,
                                (intmax_t) phdr.p_offset);
                        test_read(fd, addr_gva2hva(vm, phdr.p_vaddr),
index e066d584c65611b4da45b0312734c3fab7b3dcd6..1b197426f29fcd1e6faf4abe3069044dfe64b9ca 100644 (file)
@@ -27,7 +27,8 @@ int open_path_or_exit(const char *path, int flags)
        int fd;
 
        fd = open(path, flags);
-       __TEST_REQUIRE(fd >= 0, "%s not available (errno: %d)", path, errno);
+       __TEST_REQUIRE(fd >= 0 || errno != ENOENT, "Cannot open %s: %s", path, strerror(errno));
+       TEST_ASSERT(fd >= 0, "Failed to open '%s'", path);
 
        return fd;
 }
@@ -320,7 +321,7 @@ static uint64_t vm_nr_pages_required(enum vm_guest_mode mode,
        uint64_t nr_pages;
 
        TEST_ASSERT(nr_runnable_vcpus,
-                   "Use vm_create_barebones() for VMs that _never_ have vCPUs\n");
+                   "Use vm_create_barebones() for VMs that _never_ have vCPUs");
 
        TEST_ASSERT(nr_runnable_vcpus <= kvm_check_cap(KVM_CAP_MAX_VCPUS),
                    "nr_vcpus = %d too large for host, max-vcpus = %d",
@@ -491,7 +492,7 @@ void kvm_pin_this_task_to_pcpu(uint32_t pcpu)
        CPU_ZERO(&mask);
        CPU_SET(pcpu, &mask);
        r = sched_setaffinity(0, sizeof(mask), &mask);
-       TEST_ASSERT(!r, "sched_setaffinity() failed for pCPU '%u'.\n", pcpu);
+       TEST_ASSERT(!r, "sched_setaffinity() failed for pCPU '%u'.", pcpu);
 }
 
 static uint32_t parse_pcpu(const char *cpu_str, const cpu_set_t *allowed_mask)
@@ -499,7 +500,7 @@ static uint32_t parse_pcpu(const char *cpu_str, const cpu_set_t *allowed_mask)
        uint32_t pcpu = atoi_non_negative("CPU number", cpu_str);
 
        TEST_ASSERT(CPU_ISSET(pcpu, allowed_mask),
-                   "Not allowed to run on pCPU '%d', check cgroups?\n", pcpu);
+                   "Not allowed to run on pCPU '%d', check cgroups?", pcpu);
        return pcpu;
 }
 
@@ -529,7 +530,7 @@ void kvm_parse_vcpu_pinning(const char *pcpus_string, uint32_t vcpu_to_pcpu[],
        int i, r;
 
        cpu_list = strdup(pcpus_string);
-       TEST_ASSERT(cpu_list, "strdup() allocation failed.\n");
+       TEST_ASSERT(cpu_list, "strdup() allocation failed.");
 
        r = sched_getaffinity(0, sizeof(allowed_mask), &allowed_mask);
        TEST_ASSERT(!r, "sched_getaffinity() failed");
@@ -538,7 +539,7 @@ void kvm_parse_vcpu_pinning(const char *pcpus_string, uint32_t vcpu_to_pcpu[],
 
        /* 1. Get all pcpus for vcpus. */
        for (i = 0; i < nr_vcpus; i++) {
-               TEST_ASSERT(cpu, "pCPU not provided for vCPU '%d'\n", i);
+               TEST_ASSERT(cpu, "pCPU not provided for vCPU '%d'", i);
                vcpu_to_pcpu[i] = parse_pcpu(cpu, &allowed_mask);
                cpu = strtok(NULL, delim);
        }
@@ -1057,7 +1058,7 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
        TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION2 IOCTL failed,\n"
                "  rc: %i errno: %i\n"
                "  slot: %u flags: 0x%x\n"
-               "  guest_phys_addr: 0x%lx size: 0x%lx guest_memfd: %d\n",
+               "  guest_phys_addr: 0x%lx size: 0x%lx guest_memfd: %d",
                ret, errno, slot, flags,
                guest_paddr, (uint64_t) region->region.memory_size,
                region->region.guest_memfd);
@@ -1222,7 +1223,7 @@ void vm_guest_mem_fallocate(struct kvm_vm *vm, uint64_t base, uint64_t size,
                len = min_t(uint64_t, end - gpa, region->region.memory_size - offset);
 
                ret = fallocate(region->region.guest_memfd, mode, fd_offset, len);
-               TEST_ASSERT(!ret, "fallocate() failed to %s at %lx (len = %lu), fd = %d, mode = %x, offset = %lx\n",
+               TEST_ASSERT(!ret, "fallocate() failed to %s at %lx (len = %lu), fd = %d, mode = %x, offset = %lx",
                            punch_hole ? "punch hole" : "allocate", gpa, len,
                            region->region.guest_memfd, mode, fd_offset);
        }
@@ -1265,7 +1266,7 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
        struct kvm_vcpu *vcpu;
 
        /* Confirm a vcpu with the specified id doesn't already exist. */
-       TEST_ASSERT(!vcpu_exists(vm, vcpu_id), "vCPU%d already exists\n", vcpu_id);
+       TEST_ASSERT(!vcpu_exists(vm, vcpu_id), "vCPU%d already exists", vcpu_id);
 
        /* Allocate and initialize new vcpu structure. */
        vcpu = calloc(1, sizeof(*vcpu));
index d05487e5a371df1d17c96d4fbec1b1f6b2e60c0f..cf2c739713080f3f55e1383fb5d0a9e65f5d1dc7 100644 (file)
@@ -192,7 +192,7 @@ struct kvm_vm *memstress_create_vm(enum vm_guest_mode mode, int nr_vcpus,
        TEST_ASSERT(guest_num_pages < region_end_gfn,
                    "Requested more guest memory than address space allows.\n"
                    "    guest pages: %" PRIx64 " max gfn: %" PRIx64
-                   " nr_vcpus: %d wss: %" PRIx64 "]\n",
+                   " nr_vcpus: %d wss: %" PRIx64 "]",
                    guest_num_pages, region_end_gfn - 1, nr_vcpus, vcpu_memory_bytes);
 
        args->gpa = (region_end_gfn - guest_num_pages - 1) * args->guest_page_size;
index 7ca736fb4194046072bf69b3210f0fefd8ce0834..2bb33a8ac03c25f622ec6dc21430529b8b128a9d 100644 (file)
@@ -327,7 +327,7 @@ void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...)
        int i;
 
        TEST_ASSERT(num >= 1 && num <= 8, "Unsupported number of args,\n"
-                   "  num: %u\n", num);
+                   "  num: %u", num);
 
        va_start(ap, num);
 
index 15945121daf17dc46bf38cf8f2a24d23b8f073f3..f6d227892cbcfc88cc97abcc9a0d78b2aa38f459 100644 (file)
@@ -198,7 +198,7 @@ void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...)
        int i;
 
        TEST_ASSERT(num >= 1 && num <= 5, "Unsupported number of args,\n"
-                   "  num: %u\n",
+                   "  num: %u",
                    num);
 
        va_start(ap, num);
index 5d7f28b02d73bab79891b808bb46c095c52bd505..5a8f8becb12984ff52a16f01281b5d396ce318be 100644 (file)
@@ -392,3 +392,28 @@ char *strdup_printf(const char *fmt, ...)
 
        return str;
 }
+
+#define CLOCKSOURCE_PATH "/sys/devices/system/clocksource/clocksource0/current_clocksource"
+
+char *sys_get_cur_clocksource(void)
+{
+       char *clk_name;
+       struct stat st;
+       FILE *fp;
+
+       fp = fopen(CLOCKSOURCE_PATH, "r");
+       TEST_ASSERT(fp, "failed to open clocksource file, errno: %d", errno);
+
+       TEST_ASSERT(!fstat(fileno(fp), &st), "failed to stat clocksource file, errno: %d",
+                   errno);
+
+       clk_name = malloc(st.st_size);
+       TEST_ASSERT(clk_name, "failed to allocate buffer to read file");
+
+       TEST_ASSERT(fgets(clk_name, st.st_size, fp), "failed to read clocksource file: %d",
+                   ferror(fp));
+
+       fclose(fp);
+
+       return clk_name;
+}
index 271f6389158122a973fa597d68ee147f7169374c..f4eef6eb2dc2cc2bdefc90cbe5ac845be3a18b53 100644 (file)
@@ -69,7 +69,7 @@ static void *uffd_handler_thread_fn(void *arg)
                if (pollfd[1].revents & POLLIN) {
                        r = read(pollfd[1].fd, &tmp_chr, 1);
                        TEST_ASSERT(r == 1,
-                                   "Error reading pipefd in UFFD thread\n");
+                                   "Error reading pipefd in UFFD thread");
                        break;
                }
 
index d8288374078e4b3ce888bed569c7e59192d43e7c..f639b3e062e3a328165bfb6ed32f606cf1f48e76 100644 (file)
@@ -170,10 +170,10 @@ static uint64_t *virt_create_upper_pte(struct kvm_vm *vm,
                 * this level.
                 */
                TEST_ASSERT(current_level != target_level,
-                           "Cannot create hugepage at level: %u, vaddr: 0x%lx\n",
+                           "Cannot create hugepage at level: %u, vaddr: 0x%lx",
                            current_level, vaddr);
                TEST_ASSERT(!(*pte & PTE_LARGE_MASK),
-                           "Cannot create page table at level: %u, vaddr: 0x%lx\n",
+                           "Cannot create page table at level: %u, vaddr: 0x%lx",
                            current_level, vaddr);
        }
        return pte;
@@ -220,7 +220,7 @@ void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level)
        /* Fill in page table entry. */
        pte = virt_get_pte(vm, pde, vaddr, PG_LEVEL_4K);
        TEST_ASSERT(!(*pte & PTE_PRESENT_MASK),
-                   "PTE already present for 4k page at vaddr: 0x%lx\n", vaddr);
+                   "PTE already present for 4k page at vaddr: 0x%lx", vaddr);
        *pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK | (paddr & PHYSICAL_PAGE_MASK);
 }
 
@@ -253,7 +253,7 @@ static bool vm_is_target_pte(uint64_t *pte, int *level, int current_level)
        if (*pte & PTE_LARGE_MASK) {
                TEST_ASSERT(*level == PG_LEVEL_NONE ||
                            *level == current_level,
-                           "Unexpected hugepage at level %d\n", current_level);
+                           "Unexpected hugepage at level %d", current_level);
                *level = current_level;
        }
 
@@ -825,7 +825,7 @@ void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...)
        struct kvm_regs regs;
 
        TEST_ASSERT(num >= 1 && num <= 6, "Unsupported number of args,\n"
-                   "  num: %u\n",
+                   "  num: %u",
                    num);
 
        va_start(ap, num);
@@ -1299,3 +1299,14 @@ void kvm_selftest_arch_init(void)
        host_cpu_is_intel = this_cpu_is_intel();
        host_cpu_is_amd = this_cpu_is_amd();
 }
+
+bool sys_clocksource_is_based_on_tsc(void)
+{
+       char *clk_name = sys_get_cur_clocksource();
+       bool ret = !strcmp(clk_name, "tsc\n") ||
+                  !strcmp(clk_name, "hyperv_clocksource_tsc_page\n");
+
+       free(clk_name);
+
+       return ret;
+}
index 59d97531c9b17f7b0c1893d1aa5a63575e3fdb5c..089b8925b6b22d9929bee551435ebdca0fa24764 100644 (file)
@@ -54,7 +54,7 @@ int vcpu_enable_evmcs(struct kvm_vcpu *vcpu)
        /* KVM should return supported EVMCS version range */
        TEST_ASSERT(((evmcs_ver >> 8) >= (evmcs_ver & 0xff)) &&
                    (evmcs_ver & 0xff) > 0,
-                   "Incorrect EVMCS version range: %x:%x\n",
+                   "Incorrect EVMCS version range: %x:%x",
                    evmcs_ver & 0xff, evmcs_ver >> 8);
 
        return evmcs_ver;
@@ -387,10 +387,10 @@ static void nested_create_pte(struct kvm_vm *vm,
                 * this level.
                 */
                TEST_ASSERT(current_level != target_level,
-                           "Cannot create hugepage at level: %u, nested_paddr: 0x%lx\n",
+                           "Cannot create hugepage at level: %u, nested_paddr: 0x%lx",
                            current_level, nested_paddr);
                TEST_ASSERT(!pte->page_size,
-                           "Cannot create page table at level: %u, nested_paddr: 0x%lx\n",
+                           "Cannot create page table at level: %u, nested_paddr: 0x%lx",
                            current_level, nested_paddr);
        }
 }
index 9855c41ca811fa69a77f41f212ddc6086d47467c..1563619666123fed1da83a2786d309c51cde25d3 100644 (file)
@@ -45,7 +45,7 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args)
        /* Let the guest access its memory until a stop signal is received */
        while (!READ_ONCE(memstress_args.stop_vcpus)) {
                ret = _vcpu_run(vcpu);
-               TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret);
+               TEST_ASSERT(ret == 0, "vcpu_run failed: %d", ret);
 
                if (get_ucall(vcpu, NULL) == UCALL_SYNC)
                        continue;
index 8698d1ab60d00f72399571b62b49314f3a8c401f..579a64f97333b8d0ebd4533fdfdee1a172ef731a 100644 (file)
@@ -175,11 +175,11 @@ static void wait_for_vcpu(void)
        struct timespec ts;
 
        TEST_ASSERT(!clock_gettime(CLOCK_REALTIME, &ts),
-                   "clock_gettime() failed: %d\n", errno);
+                   "clock_gettime() failed: %d", errno);
 
        ts.tv_sec += 2;
        TEST_ASSERT(!sem_timedwait(&vcpu_ready, &ts),
-                   "sem_timedwait() failed: %d\n", errno);
+                   "sem_timedwait() failed: %d", errno);
 }
 
 static void *vm_gpa2hva(struct vm_data *data, uint64_t gpa, uint64_t *rempages)
@@ -336,7 +336,7 @@ static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots,
 
                gpa = vm_phy_pages_alloc(data->vm, npages, guest_addr, slot);
                TEST_ASSERT(gpa == guest_addr,
-                           "vm_phy_pages_alloc() failed\n");
+                           "vm_phy_pages_alloc() failed");
 
                data->hva_slots[slot - 1] = addr_gpa2hva(data->vm, guest_addr);
                memset(data->hva_slots[slot - 1], 0, npages * guest_page_size);
index 4fd0f8951574475fc5a8c8ca879103d2e2434b25..6435e7a6564252fae5e1cbd2275a6fc0c3a7f12f 100644 (file)
@@ -177,7 +177,7 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
 
                /* Double check whether the desired extension was enabled */
                __TEST_REQUIRE(vcpu_has_ext(vcpu, feature),
-                              "%s not available, skipping tests\n", s->name);
+                              "%s not available, skipping tests", s->name);
        }
 }
 
index f74e76d03b7e306667221ee9c5411bda2af417d5..28f97fb520441476c374dffc0bcf24bf6553a021 100644 (file)
@@ -245,7 +245,7 @@ int main(int argc, char *argv[])
                } while (snapshot != atomic_read(&seq_cnt));
 
                TEST_ASSERT(rseq_cpu == cpu,
-                           "rseq CPU = %d, sched CPU = %d\n", rseq_cpu, cpu);
+                           "rseq CPU = %d, sched CPU = %d", rseq_cpu, cpu);
        }
 
        /*
@@ -256,7 +256,7 @@ int main(int argc, char *argv[])
         * migrations given the 1us+ delay in the migration task.
         */
        TEST_ASSERT(i > (NR_TASK_MIGRATIONS / 2),
-                   "Only performed %d KVM_RUNs, task stalled too much?\n", i);
+                   "Only performed %d KVM_RUNs, task stalled too much?", i);
 
        pthread_join(migration_thread, NULL);
 
index bb3ca9a5d7318ebe88fbe9f5a7ebfaaf0c2235b6..b6da8f71ea191e82a3cc68632bf61b6938f60c73 100644 (file)
@@ -375,6 +375,32 @@ static void test_copy(void)
        kvm_vm_free(t.kvm_vm);
 }
 
+static void test_copy_access_register(void)
+{
+       struct test_default t = test_default_init(guest_copy);
+
+       HOST_SYNC(t.vcpu, STAGE_INITED);
+
+       prepare_mem12();
+       t.run->psw_mask &= ~(3UL << (63 - 17));
+       t.run->psw_mask |= 1UL << (63 - 17);  /* Enable AR mode */
+
+       /*
+        * Primary address space gets used if an access register
+        * contains zero. The host makes use of AR[1] so is a good
+        * candidate to ensure the guest AR (of zero) is used.
+        */
+       CHECK_N_DO(MOP, t.vcpu, LOGICAL, WRITE, mem1, t.size,
+                  GADDR_V(mem1), AR(1));
+       HOST_SYNC(t.vcpu, STAGE_COPIED);
+
+       CHECK_N_DO(MOP, t.vcpu, LOGICAL, READ, mem2, t.size,
+                  GADDR_V(mem2), AR(1));
+       ASSERT_MEM_EQ(mem1, mem2, t.size);
+
+       kvm_vm_free(t.kvm_vm);
+}
+
 static void set_storage_key_range(void *addr, size_t len, uint8_t key)
 {
        uintptr_t _addr, abs, i;
@@ -1101,6 +1127,11 @@ int main(int argc, char *argv[])
                        .test = test_copy_key_fetch_prot_override,
                        .requirements_met = extension_cap > 0,
                },
+               {
+                       .name = "copy with access register mode",
+                       .test = test_copy_access_register,
+                       .requirements_met = true,
+               },
                {
                        .name = "error checks with key",
                        .test = test_errors_key,
index e41e2cb8ffa9797c470fb061a34fb106b687a47d..357943f2bea87fff66384bcf381cf9100a5a3a6b 100644 (file)
@@ -78,7 +78,7 @@ static void assert_noirq(struct kvm_vcpu *vcpu)
         * (notably, the emergency call interrupt we have injected) should
         * be cleared by the resets, so this should be 0.
         */
-       TEST_ASSERT(irqs >= 0, "Could not fetch IRQs: errno %d\n", errno);
+       TEST_ASSERT(irqs >= 0, "Could not fetch IRQs: errno %d", errno);
        TEST_ASSERT(!irqs, "IRQ pending");
 }
 
@@ -199,7 +199,7 @@ static void inject_irq(struct kvm_vcpu *vcpu)
        irq->type = KVM_S390_INT_EMERGENCY;
        irq->u.emerg.code = vcpu->id;
        irqs = __vcpu_ioctl(vcpu, KVM_S390_SET_IRQ_STATE, &irq_state);
-       TEST_ASSERT(irqs >= 0, "Error injecting EMERGENCY IRQ errno %d\n", errno);
+       TEST_ASSERT(irqs >= 0, "Error injecting EMERGENCY IRQ errno %d", errno);
 }
 
 static struct kvm_vm *create_vm(struct kvm_vcpu **vcpu)
index 636a70ddac1ea36151cb57a0dfd74ddcca33de14..43fb25ddc3eca3a83ba14c1905972243c4bda793 100644 (file)
@@ -39,13 +39,13 @@ static void guest_code(void)
 #define REG_COMPARE(reg) \
        TEST_ASSERT(left->reg == right->reg, \
                    "Register " #reg \
-                   " values did not match: 0x%llx, 0x%llx\n", \
+                   " values did not match: 0x%llx, 0x%llx", \
                    left->reg, right->reg)
 
 #define REG_COMPARE32(reg) \
        TEST_ASSERT(left->reg == right->reg, \
                    "Register " #reg \
-                   " values did not match: 0x%x, 0x%x\n", \
+                   " values did not match: 0x%x, 0x%x", \
                    left->reg, right->reg)
 
 
@@ -82,14 +82,14 @@ void test_read_invalid(struct kvm_vcpu *vcpu)
        run->kvm_valid_regs = INVALID_SYNC_FIELD;
        rv = _vcpu_run(vcpu);
        TEST_ASSERT(rv < 0 && errno == EINVAL,
-                   "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
+                   "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d",
                    rv);
        run->kvm_valid_regs = 0;
 
        run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
        rv = _vcpu_run(vcpu);
        TEST_ASSERT(rv < 0 && errno == EINVAL,
-                   "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
+                   "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d",
                    rv);
        run->kvm_valid_regs = 0;
 }
@@ -103,14 +103,14 @@ void test_set_invalid(struct kvm_vcpu *vcpu)
        run->kvm_dirty_regs = INVALID_SYNC_FIELD;
        rv = _vcpu_run(vcpu);
        TEST_ASSERT(rv < 0 && errno == EINVAL,
-                   "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
+                   "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d",
                    rv);
        run->kvm_dirty_regs = 0;
 
        run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
        rv = _vcpu_run(vcpu);
        TEST_ASSERT(rv < 0 && errno == EINVAL,
-                   "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
+                   "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d",
                    rv);
        run->kvm_dirty_regs = 0;
 }
@@ -125,12 +125,12 @@ void test_req_and_verify_all_valid_regs(struct kvm_vcpu *vcpu)
        /* Request and verify all valid register sets. */
        run->kvm_valid_regs = TEST_SYNC_FIELDS;
        rv = _vcpu_run(vcpu);
-       TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
+       TEST_ASSERT(rv == 0, "vcpu_run failed: %d", rv);
        TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
        TEST_ASSERT(run->s390_sieic.icptcode == 4 &&
                    (run->s390_sieic.ipa >> 8) == 0x83 &&
                    (run->s390_sieic.ipb >> 16) == 0x501,
-                   "Unexpected interception code: ic=%u, ipa=0x%x, ipb=0x%x\n",
+                   "Unexpected interception code: ic=%u, ipa=0x%x, ipb=0x%x",
                    run->s390_sieic.icptcode, run->s390_sieic.ipa,
                    run->s390_sieic.ipb);
 
@@ -161,7 +161,7 @@ void test_set_and_verify_various_reg_values(struct kvm_vcpu *vcpu)
        }
 
        rv = _vcpu_run(vcpu);
-       TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
+       TEST_ASSERT(rv == 0, "vcpu_run failed: %d", rv);
        TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
        TEST_ASSERT(run->s.regs.gprs[11] == 0xBAD1DEA + 1,
                    "r11 sync regs value incorrect 0x%llx.",
@@ -193,7 +193,7 @@ void test_clear_kvm_dirty_regs_bits(struct kvm_vcpu *vcpu)
        run->s.regs.gprs[11] = 0xDEADBEEF;
        run->s.regs.diag318 = 0x4B1D;
        rv = _vcpu_run(vcpu);
-       TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
+       TEST_ASSERT(rv == 0, "vcpu_run failed: %d", rv);
        TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
        TEST_ASSERT(run->s.regs.gprs[11] != 0xDEADBEEF,
                    "r11 sync regs value incorrect 0x%llx.",
index 075b80dbe2370d2ff472685f4b02b4e1243d7123..06b43ed23580b67c060aeaadea11b06641a629c3 100644 (file)
@@ -98,11 +98,11 @@ static void wait_for_vcpu(void)
        struct timespec ts;
 
        TEST_ASSERT(!clock_gettime(CLOCK_REALTIME, &ts),
-                   "clock_gettime() failed: %d\n", errno);
+                   "clock_gettime() failed: %d", errno);
 
        ts.tv_sec += 2;
        TEST_ASSERT(!sem_timedwait(&vcpu_ready, &ts),
-                   "sem_timedwait() failed: %d\n", errno);
+                   "sem_timedwait() failed: %d", errno);
 
        /* Wait for the vCPU thread to reenter the guest. */
        usleep(100000);
@@ -302,7 +302,7 @@ static void test_delete_memory_region(void)
        if (run->exit_reason == KVM_EXIT_INTERNAL_ERROR)
                TEST_ASSERT(regs.rip >= final_rip_start &&
                            regs.rip < final_rip_end,
-                           "Bad rip, expected 0x%lx - 0x%lx, got 0x%llx\n",
+                           "Bad rip, expected 0x%lx - 0x%lx, got 0x%llx",
                            final_rip_start, final_rip_end, regs.rip);
 
        kvm_vm_free(vm);
@@ -367,11 +367,21 @@ static void test_invalid_memory_region_flags(void)
        }
 
        if (supported_flags & KVM_MEM_GUEST_MEMFD) {
+               int guest_memfd = vm_create_guest_memfd(vm, MEM_REGION_SIZE, 0);
+
                r = __vm_set_user_memory_region2(vm, 0,
                                                 KVM_MEM_LOG_DIRTY_PAGES | KVM_MEM_GUEST_MEMFD,
-                                                0, MEM_REGION_SIZE, NULL, 0, 0);
+                                                0, MEM_REGION_SIZE, NULL, guest_memfd, 0);
                TEST_ASSERT(r && errno == EINVAL,
                            "KVM_SET_USER_MEMORY_REGION2 should have failed, dirty logging private memory is unsupported");
+
+               r = __vm_set_user_memory_region2(vm, 0,
+                                                KVM_MEM_READONLY | KVM_MEM_GUEST_MEMFD,
+                                                0, MEM_REGION_SIZE, NULL, guest_memfd, 0);
+               TEST_ASSERT(r && errno == EINVAL,
+                           "KVM_SET_USER_MEMORY_REGION2 should have failed, read-only GUEST_MEMFD memslots are unsupported");
+
+               close(guest_memfd);
        }
 }
 
index 7f5b330b6a1b182f7a5890d3f7b67b7d2535accc..513d421a9bff85a96e619f187310769de7e48490 100644 (file)
@@ -108,7 +108,7 @@ static void enter_guest(struct kvm_vcpu *vcpu)
                        handle_abort(&uc);
                        return;
                default:
-                       TEST_ASSERT(0, "unhandled ucall %ld\n",
+                       TEST_ASSERT(0, "unhandled ucall %ld",
                                    get_ucall(vcpu, &uc));
                }
        }
index 11329e5ff945eb1c383c7237ebc349712734dd50..eae521f050e09fd6f69e896c03cf381ac05c4d71 100644 (file)
@@ -221,7 +221,7 @@ int main(int argc, char *argv[])
        vm_vaddr_t amx_cfg, tiledata, xstate;
        struct ucall uc;
        u32 amx_offset;
-       int stage, ret;
+       int ret;
 
        /*
         * Note, all off-by-default features must be enabled before anything
@@ -263,7 +263,7 @@ int main(int argc, char *argv[])
        memset(addr_gva2hva(vm, xstate), 0, PAGE_SIZE * DIV_ROUND_UP(XSAVE_SIZE, PAGE_SIZE));
        vcpu_args_set(vcpu, 3, amx_cfg, tiledata, xstate);
 
-       for (stage = 1; ; stage++) {
+       for (;;) {
                vcpu_run(vcpu);
                TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
 
@@ -296,7 +296,7 @@ int main(int argc, char *argv[])
                                void *tiles_data = (void *)addr_gva2hva(vm, tiledata);
                                /* Only check TMM0 register, 1 tile */
                                ret = memcmp(amx_start, tiles_data, TILE_SIZE);
-                               TEST_ASSERT(ret == 0, "memcmp failed, ret=%d\n", ret);
+                               TEST_ASSERT(ret == 0, "memcmp failed, ret=%d", ret);
                                kvm_x86_state_cleanup(state);
                                break;
                        case 9:
index 3b34d8156d1c97a879d497a12eefe4f110628973..8c579ce714e9a7ce3982123b089856c3b5963d43 100644 (file)
@@ -84,7 +84,7 @@ static void compare_cpuids(const struct kvm_cpuid2 *cpuid1,
 
                TEST_ASSERT(e1->function == e2->function &&
                            e1->index == e2->index && e1->flags == e2->flags,
-                           "CPUID entries[%d] mismtach: 0x%x.%d.%x vs. 0x%x.%d.%x\n",
+                           "CPUID entries[%d] mismtach: 0x%x.%d.%x vs. 0x%x.%d.%x",
                            i, e1->function, e1->index, e1->flags,
                            e2->function, e2->index, e2->flags);
 
@@ -170,7 +170,7 @@ static void test_get_cpuid2(struct kvm_vcpu *vcpu)
 
        vcpu_ioctl(vcpu, KVM_GET_CPUID2, cpuid);
        TEST_ASSERT(cpuid->nent == vcpu->cpuid->nent,
-                   "KVM didn't update nent on success, wanted %u, got %u\n",
+                   "KVM didn't update nent on success, wanted %u, got %u",
                    vcpu->cpuid->nent, cpuid->nent);
 
        for (i = 0; i < vcpu->cpuid->nent; i++) {
index 634c6bfcd5720717e0d4cc93e9cdf92ae96fb1d0..ee3b384b991c8be2957bdcf56fa52aa6a4a00a26 100644 (file)
@@ -92,7 +92,6 @@ static void run_test(enum vm_guest_mode mode, void *unused)
        uint64_t host_num_pages;
        uint64_t pages_per_slot;
        int i;
-       uint64_t total_4k_pages;
        struct kvm_page_stats stats_populated;
        struct kvm_page_stats stats_dirty_logging_enabled;
        struct kvm_page_stats stats_dirty_pass[ITERATIONS];
@@ -107,6 +106,9 @@ static void run_test(enum vm_guest_mode mode, void *unused)
        guest_num_pages = vm_adjust_num_guest_pages(mode, guest_num_pages);
        host_num_pages = vm_num_host_pages(mode, guest_num_pages);
        pages_per_slot = host_num_pages / SLOTS;
+       TEST_ASSERT_EQ(host_num_pages, pages_per_slot * SLOTS);
+       TEST_ASSERT(!(host_num_pages % 512),
+                   "Number of pages, '%lu' not a multiple of 2MiB", host_num_pages);
 
        bitmaps = memstress_alloc_bitmaps(SLOTS, pages_per_slot);
 
@@ -165,10 +167,8 @@ static void run_test(enum vm_guest_mode mode, void *unused)
        memstress_free_bitmaps(bitmaps, SLOTS);
        memstress_destroy_vm(vm);
 
-       /* Make assertions about the page counts. */
-       total_4k_pages = stats_populated.pages_4k;
-       total_4k_pages += stats_populated.pages_2m * 512;
-       total_4k_pages += stats_populated.pages_1g * 512 * 512;
+       TEST_ASSERT_EQ((stats_populated.pages_2m * 512 +
+                       stats_populated.pages_1g * 512 * 512), host_num_pages);
 
        /*
         * Check that all huge pages were split. Since large pages can only
@@ -180,19 +180,22 @@ static void run_test(enum vm_guest_mode mode, void *unused)
         */
        if (dirty_log_manual_caps) {
                TEST_ASSERT_EQ(stats_clear_pass[0].hugepages, 0);
-               TEST_ASSERT_EQ(stats_clear_pass[0].pages_4k, total_4k_pages);
+               TEST_ASSERT(stats_clear_pass[0].pages_4k >= host_num_pages,
+                           "Expected at least '%lu' 4KiB pages, found only '%lu'",
+                           host_num_pages, stats_clear_pass[0].pages_4k);
                TEST_ASSERT_EQ(stats_dirty_logging_enabled.hugepages, stats_populated.hugepages);
        } else {
                TEST_ASSERT_EQ(stats_dirty_logging_enabled.hugepages, 0);
-               TEST_ASSERT_EQ(stats_dirty_logging_enabled.pages_4k, total_4k_pages);
+               TEST_ASSERT(stats_dirty_logging_enabled.pages_4k >= host_num_pages,
+                           "Expected at least '%lu' 4KiB pages, found only '%lu'",
+                           host_num_pages, stats_dirty_logging_enabled.pages_4k);
        }
 
        /*
         * Once dirty logging is disabled and the vCPUs have touched all their
-        * memory again, the page counts should be the same as they were
+        * memory again, the hugepage counts should be the same as they were
         * right after initial population of memory.
         */
-       TEST_ASSERT_EQ(stats_populated.pages_4k, stats_repopulated.pages_4k);
        TEST_ASSERT_EQ(stats_populated.pages_2m, stats_repopulated.pages_2m);
        TEST_ASSERT_EQ(stats_populated.pages_1g, stats_repopulated.pages_1g);
 }
index 0a1573d52882b7b127307a829b0d1dc4d1af6560..37b1a9f5286447a1bb4a8c8f7a69c807ac0d6ced 100644 (file)
@@ -41,7 +41,7 @@ static inline void handle_flds_emulation_failure_exit(struct kvm_vcpu *vcpu)
 
        insn_bytes = run->emulation_failure.insn_bytes;
        TEST_ASSERT(insn_bytes[0] == 0xd9 && insn_bytes[1] == 0,
-                   "Expected 'flds [eax]', opcode '0xd9 0x00', got opcode 0x%02x 0x%02x\n",
+                   "Expected 'flds [eax]', opcode '0xd9 0x00', got opcode 0x%02x 0x%02x",
                    insn_bytes[0], insn_bytes[1]);
 
        vcpu_regs_get(vcpu, &regs);
index f5e1e98f04f9ef0a00f3d80ba8a0bd94f90feffd..e058bc676cd6930d54593093579fff15e1930d91 100644 (file)
@@ -212,6 +212,7 @@ int main(void)
        int stage;
 
        TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_TIME));
+       TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
 
        vm = vm_create_with_one_vcpu(&vcpu, guest_main);
 
@@ -220,7 +221,7 @@ int main(void)
        tsc_page_gva = vm_vaddr_alloc_page(vm);
        memset(addr_gva2hva(vm, tsc_page_gva), 0x0, getpagesize());
        TEST_ASSERT((addr_gva2gpa(vm, tsc_page_gva) & (getpagesize() - 1)) == 0,
-               "TSC page has to be page aligned\n");
+               "TSC page has to be page aligned");
        vcpu_args_set(vcpu, 2, tsc_page_gva, addr_gva2gpa(vm, tsc_page_gva));
 
        host_check_tsc_msr_rdtsc(vcpu);
@@ -237,7 +238,7 @@ int main(void)
                        break;
                case UCALL_DONE:
                        /* Keep in sync with guest_main() */
-                       TEST_ASSERT(stage == 11, "Testing ended prematurely, stage %d\n",
+                       TEST_ASSERT(stage == 11, "Testing ended prematurely, stage %d",
                                    stage);
                        goto out;
                default:
index 4f4193fc74ffa29454c193ed741603c5fef1004b..b923a285e96f9492108ac17c21a070a4dd4ffa61 100644 (file)
@@ -454,7 +454,7 @@ static void guest_test_msrs_access(void)
                case 44:
                        /* MSR is not available when CPUID feature bit is unset */
                        if (!has_invtsc)
-                               continue;
+                               goto next_stage;
                        msr->idx = HV_X64_MSR_TSC_INVARIANT_CONTROL;
                        msr->write = false;
                        msr->fault_expected = true;
@@ -462,7 +462,7 @@ static void guest_test_msrs_access(void)
                case 45:
                        /* MSR is vailable when CPUID feature bit is set */
                        if (!has_invtsc)
-                               continue;
+                               goto next_stage;
                        vcpu_set_cpuid_feature(vcpu, HV_ACCESS_TSC_INVARIANT);
                        msr->idx = HV_X64_MSR_TSC_INVARIANT_CONTROL;
                        msr->write = false;
@@ -471,7 +471,7 @@ static void guest_test_msrs_access(void)
                case 46:
                        /* Writing bits other than 0 is forbidden */
                        if (!has_invtsc)
-                               continue;
+                               goto next_stage;
                        msr->idx = HV_X64_MSR_TSC_INVARIANT_CONTROL;
                        msr->write = true;
                        msr->write_val = 0xdeadbeef;
@@ -480,7 +480,7 @@ static void guest_test_msrs_access(void)
                case 47:
                        /* Setting bit 0 enables the feature */
                        if (!has_invtsc)
-                               continue;
+                               goto next_stage;
                        msr->idx = HV_X64_MSR_TSC_INVARIANT_CONTROL;
                        msr->write = true;
                        msr->write_val = 1;
@@ -513,6 +513,7 @@ static void guest_test_msrs_access(void)
                        return;
                }
 
+next_stage:
                stage++;
                kvm_vm_free(vm);
        }
index 65e5f4c05068a8fff78caf386f76ef107ac407f2..f1617762c22fecaff954824c3ca09cebec1eb78d 100644 (file)
@@ -289,7 +289,7 @@ int main(int argc, char *argv[])
                switch (get_ucall(vcpu[0], &uc)) {
                case UCALL_SYNC:
                        TEST_ASSERT(uc.args[1] == stage,
-                                   "Unexpected stage: %ld (%d expected)\n",
+                                   "Unexpected stage: %ld (%d expected)",
                                    uc.args[1], stage);
                        break;
                case UCALL_DONE:
index c4443f71f8dd01f6aafde337c618d414c61c1ce3..05b56095cf76f6b8857f7f83bccdf68b3787d759 100644 (file)
@@ -658,7 +658,7 @@ int main(int argc, char *argv[])
                switch (get_ucall(vcpu[0], &uc)) {
                case UCALL_SYNC:
                        TEST_ASSERT(uc.args[1] == stage,
-                                   "Unexpected stage: %ld (%d expected)\n",
+                                   "Unexpected stage: %ld (%d expected)",
                                    uc.args[1], stage);
                        break;
                case UCALL_ABORT:
index 1778704360a6634ee7df3dfacd8f63fd3d236cab..5bc12222d87af696dc2f35e8874c4eb3f58a4f7e 100644 (file)
@@ -92,7 +92,7 @@ static void setup_clock(struct kvm_vm *vm, struct test_case *test_case)
                                break;
                } while (errno == EINTR);
 
-               TEST_ASSERT(!r, "clock_gettime() failed: %d\n", r);
+               TEST_ASSERT(!r, "clock_gettime() failed: %d", r);
 
                data.realtime = ts.tv_sec * NSEC_PER_SEC;
                data.realtime += ts.tv_nsec;
@@ -127,47 +127,11 @@ static void enter_guest(struct kvm_vcpu *vcpu)
                        handle_abort(&uc);
                        return;
                default:
-                       TEST_ASSERT(0, "unhandled ucall: %ld\n", uc.cmd);
+                       TEST_ASSERT(0, "unhandled ucall: %ld", uc.cmd);
                }
        }
 }
 
-#define CLOCKSOURCE_PATH "/sys/devices/system/clocksource/clocksource0/current_clocksource"
-
-static void check_clocksource(void)
-{
-       char *clk_name;
-       struct stat st;
-       FILE *fp;
-
-       fp = fopen(CLOCKSOURCE_PATH, "r");
-       if (!fp) {
-               pr_info("failed to open clocksource file: %d; assuming TSC.\n",
-                       errno);
-               return;
-       }
-
-       if (fstat(fileno(fp), &st)) {
-               pr_info("failed to stat clocksource file: %d; assuming TSC.\n",
-                       errno);
-               goto out;
-       }
-
-       clk_name = malloc(st.st_size);
-       TEST_ASSERT(clk_name, "failed to allocate buffer to read file\n");
-
-       if (!fgets(clk_name, st.st_size, fp)) {
-               pr_info("failed to read clocksource file: %d; assuming TSC.\n",
-                       ferror(fp));
-               goto out;
-       }
-
-       TEST_ASSERT(!strncmp(clk_name, "tsc\n", st.st_size),
-                   "clocksource not supported: %s", clk_name);
-out:
-       fclose(fp);
-}
-
 int main(void)
 {
        struct kvm_vcpu *vcpu;
@@ -179,7 +143,7 @@ int main(void)
        flags = kvm_check_cap(KVM_CAP_ADJUST_CLOCK);
        TEST_REQUIRE(flags & KVM_CLOCK_REALTIME);
 
-       check_clocksource();
+       TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
 
        vm = vm_create_with_one_vcpu(&vcpu, guest_main);
 
index 83e25bccc139decff79249e99a336ef2cb8cc820..17bbb96fc4dfcbc25e2ed62e5010d2d71a9d1746 100644 (file)
@@ -257,9 +257,9 @@ int main(int argc, char **argv)
        TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_DISABLE_NX_HUGE_PAGES));
 
        __TEST_REQUIRE(token == MAGIC_TOKEN,
-                      "This test must be run with the magic token %d.\n"
-                      "This is done by nx_huge_pages_test.sh, which\n"
-                      "also handles environment setup for the test.", MAGIC_TOKEN);
+                      "This test must be run with the magic token via '-t %d'.\n"
+                      "Running via nx_huge_pages_test.sh, which also handles "
+                      "environment setup, is strongly recommended.", MAGIC_TOKEN);
 
        run_test(reclaim_period_ms, false, reboot_permissions);
        run_test(reclaim_period_ms, true, reboot_permissions);
index c9a07963d68aaedcc6b45d4e00e932e5981645b0..87011965dc41664d46bb285fa5dd408876fe20c2 100644 (file)
@@ -44,7 +44,7 @@ static void test_msr_platform_info_enabled(struct kvm_vcpu *vcpu)
 
        get_ucall(vcpu, &uc);
        TEST_ASSERT(uc.cmd == UCALL_SYNC,
-                       "Received ucall other than UCALL_SYNC: %lu\n", uc.cmd);
+                       "Received ucall other than UCALL_SYNC: %lu", uc.cmd);
        TEST_ASSERT((uc.args[1] & MSR_PLATFORM_INFO_MAX_TURBO_RATIO) ==
                MSR_PLATFORM_INFO_MAX_TURBO_RATIO,
                "Expected MSR_PLATFORM_INFO to have max turbo ratio mask: %i.",
index 283cc55597a4fe28c02197ea18c269b9294a16b2..a3bd54b925abaf10331886385f983001c47ebb06 100644 (file)
@@ -866,7 +866,7 @@ static void __test_fixed_counter_bitmap(struct kvm_vcpu *vcpu, uint8_t idx,
         * userspace doesn't set any pmu filter.
         */
        count = run_vcpu_to_sync(vcpu);
-       TEST_ASSERT(count, "Unexpected count value: %ld\n", count);
+       TEST_ASSERT(count, "Unexpected count value: %ld", count);
 
        for (i = 0; i < BIT(nr_fixed_counters); i++) {
                bitmap = BIT(i);
index c7ef97561038e8bc297324387160990f170f53a9..a49828adf2949464b668f530a977e9efd9d75888 100644 (file)
@@ -91,7 +91,7 @@ static void sev_migrate_from(struct kvm_vm *dst, struct kvm_vm *src)
        int ret;
 
        ret = __sev_migrate_from(dst, src);
-       TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d\n", ret, errno);
+       TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d", ret, errno);
 }
 
 static void test_sev_migrate_from(bool es)
@@ -113,7 +113,7 @@ static void test_sev_migrate_from(bool es)
        /* Migrate the guest back to the original VM. */
        ret = __sev_migrate_from(src_vm, dst_vms[NR_MIGRATE_TEST_VMS - 1]);
        TEST_ASSERT(ret == -1 && errno == EIO,
-                   "VM that was migrated from should be dead. ret %d, errno: %d\n", ret,
+                   "VM that was migrated from should be dead. ret %d, errno: %d", ret,
                    errno);
 
        kvm_vm_free(src_vm);
@@ -172,7 +172,7 @@ static void test_sev_migrate_parameters(void)
        vm_no_sev = aux_vm_create(true);
        ret = __sev_migrate_from(vm_no_vcpu, vm_no_sev);
        TEST_ASSERT(ret == -1 && errno == EINVAL,
-                   "Migrations require SEV enabled. ret %d, errno: %d\n", ret,
+                   "Migrations require SEV enabled. ret %d, errno: %d", ret,
                    errno);
 
        if (!have_sev_es)
@@ -187,25 +187,25 @@ static void test_sev_migrate_parameters(void)
        ret = __sev_migrate_from(sev_vm, sev_es_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
-               "Should not be able migrate to SEV enabled VM. ret: %d, errno: %d\n",
+               "Should not be able migrate to SEV enabled VM. ret: %d, errno: %d",
                ret, errno);
 
        ret = __sev_migrate_from(sev_es_vm, sev_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
-               "Should not be able migrate to SEV-ES enabled VM. ret: %d, errno: %d\n",
+               "Should not be able migrate to SEV-ES enabled VM. ret: %d, errno: %d",
                ret, errno);
 
        ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
-               "SEV-ES migrations require same number of vCPUS. ret: %d, errno: %d\n",
+               "SEV-ES migrations require same number of vCPUS. ret: %d, errno: %d",
                ret, errno);
 
        ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm_no_vmsa);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
-               "SEV-ES migrations require UPDATE_VMSA. ret %d, errno: %d\n",
+               "SEV-ES migrations require UPDATE_VMSA. ret %d, errno: %d",
                ret, errno);
 
        kvm_vm_free(sev_vm);
@@ -227,7 +227,7 @@ static void sev_mirror_create(struct kvm_vm *dst, struct kvm_vm *src)
        int ret;
 
        ret = __sev_mirror_create(dst, src);
-       TEST_ASSERT(!ret, "Copying context failed, ret: %d, errno: %d\n", ret, errno);
+       TEST_ASSERT(!ret, "Copying context failed, ret: %d, errno: %d", ret, errno);
 }
 
 static void verify_mirror_allowed_cmds(int vm_fd)
@@ -259,7 +259,7 @@ static void verify_mirror_allowed_cmds(int vm_fd)
                ret = __sev_ioctl(vm_fd, cmd_id, NULL, &fw_error);
                TEST_ASSERT(
                        ret == -1 && errno == EINVAL,
-                       "Should not be able call command: %d. ret: %d, errno: %d\n",
+                       "Should not be able call command: %d. ret: %d, errno: %d",
                        cmd_id, ret, errno);
        }
 
@@ -301,18 +301,18 @@ static void test_sev_mirror_parameters(void)
        ret = __sev_mirror_create(sev_vm, sev_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
-               "Should not be able copy context to self. ret: %d, errno: %d\n",
+               "Should not be able copy context to self. ret: %d, errno: %d",
                ret, errno);
 
        ret = __sev_mirror_create(vm_no_vcpu, vm_with_vcpu);
        TEST_ASSERT(ret == -1 && errno == EINVAL,
-                   "Copy context requires SEV enabled. ret %d, errno: %d\n", ret,
+                   "Copy context requires SEV enabled. ret %d, errno: %d", ret,
                    errno);
 
        ret = __sev_mirror_create(vm_with_vcpu, sev_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
-               "SEV copy context requires no vCPUS on the destination. ret: %d, errno: %d\n",
+               "SEV copy context requires no vCPUS on the destination. ret: %d, errno: %d",
                ret, errno);
 
        if (!have_sev_es)
@@ -322,13 +322,13 @@ static void test_sev_mirror_parameters(void)
        ret = __sev_mirror_create(sev_vm, sev_es_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
-               "Should not be able copy context to SEV enabled VM. ret: %d, errno: %d\n",
+               "Should not be able copy context to SEV enabled VM. ret: %d, errno: %d",
                ret, errno);
 
        ret = __sev_mirror_create(sev_es_vm, sev_vm);
        TEST_ASSERT(
                ret == -1 && errno == EINVAL,
-               "Should not be able copy context to SEV-ES enabled VM. ret: %d, errno: %d\n",
+               "Should not be able copy context to SEV-ES enabled VM. ret: %d, errno: %d",
                ret, errno);
 
        kvm_vm_free(sev_es_vm);
index 06edf00a97d61dc3ca265926c2043d839daddeeb..1a46dd7bb39136e51b1e021be08667b84c2fe001 100644 (file)
@@ -74,7 +74,7 @@ int main(int argc, char *argv[])
                                    MEM_REGION_SIZE / PAGE_SIZE, 0);
        gpa = vm_phy_pages_alloc(vm, MEM_REGION_SIZE / PAGE_SIZE,
                                 MEM_REGION_GPA, MEM_REGION_SLOT);
-       TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc\n");
+       TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc");
        virt_map(vm, MEM_REGION_GVA, MEM_REGION_GPA, 1);
        hva = addr_gpa2hva(vm, MEM_REGION_GPA);
        memset(hva, 0, PAGE_SIZE);
@@ -102,7 +102,7 @@ int main(int argc, char *argv[])
        case UCALL_DONE:
                break;
        default:
-               TEST_FAIL("Unrecognized ucall: %lu\n", uc.cmd);
+               TEST_FAIL("Unrecognized ucall: %lu", uc.cmd);
        }
 
        kvm_vm_free(vm);
index 00965ba33f730c2a443773dc89e41d465c39beeb..a91b5b145fa35ac81dfaa225ff350e4186a229d0 100644 (file)
@@ -46,7 +46,7 @@ static void compare_regs(struct kvm_regs *left, struct kvm_regs *right)
 #define REG_COMPARE(reg) \
        TEST_ASSERT(left->reg == right->reg, \
                    "Register " #reg \
-                   " values did not match: 0x%llx, 0x%llx\n", \
+                   " values did not match: 0x%llx, 0x%llx", \
                    left->reg, right->reg)
        REG_COMPARE(rax);
        REG_COMPARE(rbx);
@@ -230,14 +230,14 @@ int main(int argc, char *argv[])
        run->kvm_valid_regs = INVALID_SYNC_FIELD;
        rv = _vcpu_run(vcpu);
        TEST_ASSERT(rv < 0 && errno == EINVAL,
-                   "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
+                   "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d",
                    rv);
        run->kvm_valid_regs = 0;
 
        run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
        rv = _vcpu_run(vcpu);
        TEST_ASSERT(rv < 0 && errno == EINVAL,
-                   "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
+                   "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d",
                    rv);
        run->kvm_valid_regs = 0;
 
@@ -245,14 +245,14 @@ int main(int argc, char *argv[])
        run->kvm_dirty_regs = INVALID_SYNC_FIELD;
        rv = _vcpu_run(vcpu);
        TEST_ASSERT(rv < 0 && errno == EINVAL,
-                   "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
+                   "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d",
                    rv);
        run->kvm_dirty_regs = 0;
 
        run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
        rv = _vcpu_run(vcpu);
        TEST_ASSERT(rv < 0 && errno == EINVAL,
-                   "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
+                   "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d",
                    rv);
        run->kvm_dirty_regs = 0;
 
index 0ed32ec903d03548ce11fa5bcc42eba329808506..dcbb3c29fb8e9f82b9dce0b222111f8a8eb4776a 100644 (file)
@@ -143,7 +143,7 @@ static void run_vcpu_expect_gp(struct kvm_vcpu *vcpu)
 
        TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
        TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_SYNC,
-                   "Expect UCALL_SYNC\n");
+                   "Expect UCALL_SYNC");
        TEST_ASSERT(uc.args[1] == SYNC_GP, "#GP is expected.");
        printf("vCPU received GP in guest.\n");
 }
@@ -188,7 +188,7 @@ static void *run_ucna_injection(void *arg)
 
        TEST_ASSERT_KVM_EXIT_REASON(params->vcpu, KVM_EXIT_IO);
        TEST_ASSERT(get_ucall(params->vcpu, &uc) == UCALL_SYNC,
-                   "Expect UCALL_SYNC\n");
+                   "Expect UCALL_SYNC");
        TEST_ASSERT(uc.args[1] == SYNC_FIRST_UCNA, "Injecting first UCNA.");
 
        printf("Injecting first UCNA at %#x.\n", FIRST_UCNA_ADDR);
@@ -198,7 +198,7 @@ static void *run_ucna_injection(void *arg)
 
        TEST_ASSERT_KVM_EXIT_REASON(params->vcpu, KVM_EXIT_IO);
        TEST_ASSERT(get_ucall(params->vcpu, &uc) == UCALL_SYNC,
-                   "Expect UCALL_SYNC\n");
+                   "Expect UCALL_SYNC");
        TEST_ASSERT(uc.args[1] == SYNC_SECOND_UCNA, "Injecting second UCNA.");
 
        printf("Injecting second UCNA at %#x.\n", SECOND_UCNA_ADDR);
@@ -208,7 +208,7 @@ static void *run_ucna_injection(void *arg)
 
        TEST_ASSERT_KVM_EXIT_REASON(params->vcpu, KVM_EXIT_IO);
        if (get_ucall(params->vcpu, &uc) == UCALL_ABORT) {
-               TEST_ASSERT(false, "vCPU assertion failure: %s.\n",
+               TEST_ASSERT(false, "vCPU assertion failure: %s.",
                            (const char *)uc.args[0]);
        }
 
index 255c50b0dc32675dfef64e65e1a0c6b164d0ca39..9481cbcf284f69b662a2f9f1a5fb3ff304ab0605 100644 (file)
@@ -71,7 +71,7 @@ int main(int argc, char *argv[])
                        break;
 
                TEST_ASSERT(run->io.port == 0x80,
-                           "Expected I/O at port 0x80, got port 0x%x\n", run->io.port);
+                           "Expected I/O at port 0x80, got port 0x%x", run->io.port);
 
                /*
                 * Modify the rep string count in RCX: 2 => 1 and 3 => 8192.
index 2bed5fb3a0d6e51aa63f9732d77dac330378d2c8..a81a24761aac072a0359305826712a917ed06bba 100644 (file)
@@ -99,7 +99,7 @@ int main(int argc, char *argv[])
                        TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_INTERNAL_ERROR);
                        TEST_ASSERT(run->internal.suberror ==
                                    KVM_INTERNAL_ERROR_EMULATION,
-                                   "Got internal suberror other than KVM_INTERNAL_ERROR_EMULATION: %u\n",
+                                   "Got internal suberror other than KVM_INTERNAL_ERROR_EMULATION: %u",
                                    run->internal.suberror);
                        break;
                }
index e4ad5fef52ffc5b08ec8d3f445b518b52229e672..7f6f5f23fb9b67fcb186a0e9c9ad00aaced6d2d3 100644 (file)
@@ -128,17 +128,17 @@ int main(int argc, char *argv[])
                         */
                        kvm_vm_get_dirty_log(vm, TEST_MEM_SLOT_INDEX, bmap);
                        if (uc.args[1]) {
-                               TEST_ASSERT(test_bit(0, bmap), "Page 0 incorrectly reported clean\n");
-                               TEST_ASSERT(host_test_mem[0] == 1, "Page 0 not written by guest\n");
+                               TEST_ASSERT(test_bit(0, bmap), "Page 0 incorrectly reported clean");
+                               TEST_ASSERT(host_test_mem[0] == 1, "Page 0 not written by guest");
                        } else {
-                               TEST_ASSERT(!test_bit(0, bmap), "Page 0 incorrectly reported dirty\n");
-                               TEST_ASSERT(host_test_mem[0] == 0xaaaaaaaaaaaaaaaaULL, "Page 0 written by guest\n");
+                               TEST_ASSERT(!test_bit(0, bmap), "Page 0 incorrectly reported dirty");
+                               TEST_ASSERT(host_test_mem[0] == 0xaaaaaaaaaaaaaaaaULL, "Page 0 written by guest");
                        }
 
-                       TEST_ASSERT(!test_bit(1, bmap), "Page 1 incorrectly reported dirty\n");
-                       TEST_ASSERT(host_test_mem[4096 / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 1 written by guest\n");
-                       TEST_ASSERT(!test_bit(2, bmap), "Page 2 incorrectly reported dirty\n");
-                       TEST_ASSERT(host_test_mem[8192 / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 2 written by guest\n");
+                       TEST_ASSERT(!test_bit(1, bmap), "Page 1 incorrectly reported dirty");
+                       TEST_ASSERT(host_test_mem[4096 / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 1 written by guest");
+                       TEST_ASSERT(!test_bit(2, bmap), "Page 2 incorrectly reported dirty");
+                       TEST_ASSERT(host_test_mem[8192 / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 2 written by guest");
                        break;
                case UCALL_DONE:
                        done = true;
index a9b827c69f32c5f96548d040c72d979166041f19..fad3634fd9eb62e34ded1c3f59b1d38a0b61d03a 100644 (file)
@@ -28,7 +28,7 @@ static void __run_vcpu_with_invalid_state(struct kvm_vcpu *vcpu)
 
        TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_INTERNAL_ERROR);
        TEST_ASSERT(run->emulation_failure.suberror == KVM_INTERNAL_ERROR_EMULATION,
-                   "Expected emulation failure, got %d\n",
+                   "Expected emulation failure, got %d",
                    run->emulation_failure.suberror);
 }
 
index e710b6e7fb384aac124ad0c7f646a872b347ad51..1759fa5cb3f29c337a09a5d15569ff028067e2db 100644 (file)
@@ -116,23 +116,6 @@ static void l1_guest_code(struct vmx_pages *vmx_pages)
        GUEST_DONE();
 }
 
-static bool system_has_stable_tsc(void)
-{
-       bool tsc_is_stable;
-       FILE *fp;
-       char buf[4];
-
-       fp = fopen("/sys/devices/system/clocksource/clocksource0/current_clocksource", "r");
-       if (fp == NULL)
-               return false;
-
-       tsc_is_stable = fgets(buf, sizeof(buf), fp) &&
-                       !strncmp(buf, "tsc", sizeof(buf));
-
-       fclose(fp);
-       return tsc_is_stable;
-}
-
 int main(int argc, char *argv[])
 {
        struct kvm_vcpu *vcpu;
@@ -148,7 +131,7 @@ int main(int argc, char *argv[])
 
        TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
        TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL));
-       TEST_REQUIRE(system_has_stable_tsc());
+       TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
 
        /*
         * We set L1's scale factor to be a random number from 2 to 10.
index 67ac2a3292efd4e5a4ff24073af25849ce375dd9..725c206ba0b92bc9d073dcbc7d8403cb7d2f0bd1 100644 (file)
@@ -216,7 +216,7 @@ static void *vcpu_thread(void *arg)
                            "Halting vCPU halted %lu times, woke %lu times, received %lu IPIs.\n"
                            "Halter TPR=%#x PPR=%#x LVR=%#x\n"
                            "Migrations attempted: %lu\n"
-                           "Migrations completed: %lu\n",
+                           "Migrations completed: %lu",
                            vcpu->id, (const char *)uc.args[0],
                            params->data->ipis_sent, params->data->hlt_count,
                            params->data->wake_count,
@@ -288,7 +288,7 @@ void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs,
        }
 
        TEST_ASSERT(nodes > 1,
-                   "Did not find at least 2 numa nodes. Can't do migration\n");
+                   "Did not find at least 2 numa nodes. Can't do migration");
 
        fprintf(stderr, "Migrating amongst %d nodes found\n", nodes);
 
@@ -347,7 +347,7 @@ void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs,
                                    wake_count != data->wake_count,
                                    "IPI, HLT and wake count have not increased "
                                    "in the last %lu seconds. "
-                                   "HLTer is likely hung.\n", interval_secs);
+                                   "HLTer is likely hung.", interval_secs);
 
                        ipis_sent = data->ipis_sent;
                        hlt_count = data->hlt_count;
@@ -381,7 +381,7 @@ void get_cmdline_args(int argc, char *argv[], int *run_secs,
                                    "-m adds calls to migrate_pages while vCPUs are running."
                                    " Default is no migrations.\n"
                                    "-d <delay microseconds> - delay between migrate_pages() calls."
-                                   " Default is %d microseconds.\n",
+                                   " Default is %d microseconds.",
                                    DEFAULT_RUN_SECS, DEFAULT_DELAY_USECS);
                }
        }
index dc6217440db3ae193fd9bfbcfbaadea223e57c03..25a0b0db5c3c9dfac6819de37e8c7d0a541935fb 100644 (file)
@@ -116,7 +116,7 @@ int main(int argc, char *argv[])
                vcpu_run(vcpu);
 
                TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
-                           "Unexpected exit reason: %u (%s),\n",
+                           "Unexpected exit reason: %u (%s),",
                            run->exit_reason,
                            exit_reason_str(run->exit_reason));
 
index e0ddf47362e773fbba85169b6c517ac505a3077b..167c97abff1b816dd9792b19f71c58847f433f78 100644 (file)
@@ -29,7 +29,7 @@ int main(int argc, char *argv[])
 
        xss_val = vcpu_get_msr(vcpu, MSR_IA32_XSS);
        TEST_ASSERT(xss_val == 0,
-                   "MSR_IA32_XSS should be initialized to zero\n");
+                   "MSR_IA32_XSS should be initialized to zero");
 
        vcpu_set_msr(vcpu, MSR_IA32_XSS, xss_val);
 
index 5b79758cae627593c68b9fd465451efcf7b75f9f..e64bbdf0e86eac8bf1751ee287508aca1a7ed27c 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <errno.h>
 #include <linux/landlock.h>
+#include <linux/securebits.h>
 #include <sys/capability.h>
 #include <sys/socket.h>
 #include <sys/syscall.h>
@@ -115,11 +116,16 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
                /* clang-format off */
                CAP_DAC_OVERRIDE,
                CAP_MKNOD,
+               CAP_NET_ADMIN,
+               CAP_NET_BIND_SERVICE,
                CAP_SYS_ADMIN,
                CAP_SYS_CHROOT,
-               CAP_NET_BIND_SERVICE,
                /* clang-format on */
        };
+       const unsigned int noroot = SECBIT_NOROOT | SECBIT_NOROOT_LOCKED;
+
+       if ((cap_get_secbits() & noroot) != noroot)
+               EXPECT_EQ(0, cap_set_secbits(noroot));
 
        cap_p = cap_get_proc();
        EXPECT_NE(NULL, cap_p)
@@ -137,6 +143,8 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
                        TH_LOG("Failed to cap_set_flag: %s", strerror(errno));
                }
        }
+
+       /* Automatically resets ambient capabilities. */
        EXPECT_NE(-1, cap_set_proc(cap_p))
        {
                TH_LOG("Failed to cap_set_proc: %s", strerror(errno));
@@ -145,6 +153,9 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
        {
                TH_LOG("Failed to cap_free: %s", strerror(errno));
        }
+
+       /* Quickly checks that ambient capabilities are cleared. */
+       EXPECT_NE(-1, cap_get_ambient(caps[0]));
 }
 
 /* We cannot put such helpers in a library because of kselftest_harness.h . */
@@ -158,8 +169,9 @@ static void __maybe_unused drop_caps(struct __test_metadata *const _metadata)
        _init_caps(_metadata, true);
 }
 
-static void _effective_cap(struct __test_metadata *const _metadata,
-                          const cap_value_t caps, const cap_flag_value_t value)
+static void _change_cap(struct __test_metadata *const _metadata,
+                       const cap_flag_t flag, const cap_value_t cap,
+                       const cap_flag_value_t value)
 {
        cap_t cap_p;
 
@@ -168,7 +180,7 @@ static void _effective_cap(struct __test_metadata *const _metadata,
        {
                TH_LOG("Failed to cap_get_proc: %s", strerror(errno));
        }
-       EXPECT_NE(-1, cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &caps, value))
+       EXPECT_NE(-1, cap_set_flag(cap_p, flag, 1, &cap, value))
        {
                TH_LOG("Failed to cap_set_flag: %s", strerror(errno));
        }
@@ -183,15 +195,35 @@ static void _effective_cap(struct __test_metadata *const _metadata,
 }
 
 static void __maybe_unused set_cap(struct __test_metadata *const _metadata,
-                                  const cap_value_t caps)
+                                  const cap_value_t cap)
 {
-       _effective_cap(_metadata, caps, CAP_SET);
+       _change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_SET);
 }
 
 static void __maybe_unused clear_cap(struct __test_metadata *const _metadata,
-                                    const cap_value_t caps)
+                                    const cap_value_t cap)
+{
+       _change_cap(_metadata, CAP_EFFECTIVE, cap, CAP_CLEAR);
+}
+
+static void __maybe_unused
+set_ambient_cap(struct __test_metadata *const _metadata, const cap_value_t cap)
+{
+       _change_cap(_metadata, CAP_INHERITABLE, cap, CAP_SET);
+
+       EXPECT_NE(-1, cap_set_ambient(cap, CAP_SET))
+       {
+               TH_LOG("Failed to set ambient capability %d: %s", cap,
+                      strerror(errno));
+       }
+}
+
+static void __maybe_unused clear_ambient_cap(
+       struct __test_metadata *const _metadata, const cap_value_t cap)
 {
-       _effective_cap(_metadata, caps, CAP_CLEAR);
+       EXPECT_EQ(1, cap_get_ambient(cap));
+       _change_cap(_metadata, CAP_INHERITABLE, cap, CAP_CLEAR);
+       EXPECT_EQ(0, cap_get_ambient(cap));
 }
 
 /* Receives an FD from a UNIX socket. Returns the received FD, or -errno. */
index 50818904397c577e6953b7fd66bbfe894827b120..2d6d9b43d958cfb7c247e2cfa1fdbdf7a48c4c08 100644 (file)
@@ -241,9 +241,11 @@ struct mnt_opt {
        const char *const data;
 };
 
-const struct mnt_opt mnt_tmp = {
+#define MNT_TMP_DATA "size=4m,mode=700"
+
+static const struct mnt_opt mnt_tmp = {
        .type = "tmpfs",
-       .data = "size=4m,mode=700",
+       .data = MNT_TMP_DATA,
 };
 
 static int mount_opt(const struct mnt_opt *const mnt, const char *const target)
@@ -4632,7 +4634,10 @@ FIXTURE_VARIANT(layout3_fs)
 /* clang-format off */
 FIXTURE_VARIANT_ADD(layout3_fs, tmpfs) {
        /* clang-format on */
-       .mnt = mnt_tmp,
+       .mnt = {
+               .type = "tmpfs",
+               .data = MNT_TMP_DATA,
+       },
        .file_path = file1_s1d1,
 };
 
index ea5f727dd25778df7def21365eae073981ee08fe..936cfc879f1d2c419195338a8af04c095fe770f8 100644 (file)
@@ -17,6 +17,7 @@
 #include <string.h>
 #include <sys/prctl.h>
 #include <sys/socket.h>
+#include <sys/syscall.h>
 #include <sys/un.h>
 
 #include "common.h"
@@ -54,6 +55,11 @@ struct service_fixture {
        };
 };
 
+static pid_t sys_gettid(void)
+{
+       return syscall(__NR_gettid);
+}
+
 static int set_service(struct service_fixture *const srv,
                       const struct protocol_variant prot,
                       const unsigned short index)
@@ -88,7 +94,7 @@ static int set_service(struct service_fixture *const srv,
        case AF_UNIX:
                srv->unix_addr.sun_family = prot.domain;
                sprintf(srv->unix_addr.sun_path,
-                       "_selftests-landlock-net-tid%d-index%d", gettid(),
+                       "_selftests-landlock-net-tid%d-index%d", sys_gettid(),
                        index);
                srv->unix_addr_len = SUN_LEN(&srv->unix_addr);
                srv->unix_addr.sun_path[0] = '\0';
@@ -101,8 +107,11 @@ static void setup_loopback(struct __test_metadata *const _metadata)
 {
        set_cap(_metadata, CAP_SYS_ADMIN);
        ASSERT_EQ(0, unshare(CLONE_NEWNET));
-       ASSERT_EQ(0, system("ip link set dev lo up"));
        clear_cap(_metadata, CAP_SYS_ADMIN);
+
+       set_ambient_cap(_metadata, CAP_NET_ADMIN);
+       ASSERT_EQ(0, system("ip link set dev lo up"));
+       clear_ambient_cap(_metadata, CAP_NET_ADMIN);
 }
 
 static bool is_restricted(const struct protocol_variant *const prot,
index aa646e0661f36cac428395667f47ed11013ef083..286ce0ee102b539a0db797a4327efaee1af924a9 100644 (file)
@@ -58,7 +58,8 @@ TEST_GEN_PROGS := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS))
 TEST_GEN_PROGS_EXTENDED := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS_EXTENDED))
 TEST_GEN_FILES := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_FILES))
 
-all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES)
+all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) \
+       $(if $(TEST_GEN_MODS_DIR),gen_mods_dir)
 
 define RUN_TESTS
        BASE_DIR="$(selfdir)";                  \
@@ -71,8 +72,8 @@ endef
 
 run_tests: all
 ifdef building_out_of_srctree
-       @if [ "X$(TEST_PROGS)$(TEST_PROGS_EXTENDED)$(TEST_FILES)" != "X" ]; then \
-               rsync -aq --copy-unsafe-links $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(OUTPUT); \
+       @if [ "X$(TEST_PROGS)$(TEST_PROGS_EXTENDED)$(TEST_FILES)$(TEST_GEN_MODS_DIR)" != "X" ]; then \
+               rsync -aq --copy-unsafe-links $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(TEST_GEN_MODS_DIR) $(OUTPUT); \
        fi
        @if [ "X$(TEST_PROGS)" != "X" ]; then \
                $(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) \
@@ -84,11 +85,22 @@ else
        @$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_PROGS))
 endif
 
+gen_mods_dir:
+       $(Q)$(MAKE) -C $(TEST_GEN_MODS_DIR)
+
+clean_mods_dir:
+       $(Q)$(MAKE) -C $(TEST_GEN_MODS_DIR) clean
+
 define INSTALL_SINGLE_RULE
        $(if $(INSTALL_LIST),@mkdir -p $(INSTALL_PATH))
        $(if $(INSTALL_LIST),rsync -a --copy-unsafe-links $(INSTALL_LIST) $(INSTALL_PATH)/)
 endef
 
+define INSTALL_MODS_RULE
+       $(if $(INSTALL_LIST),@mkdir -p $(INSTALL_PATH)/$(INSTALL_LIST))
+       $(if $(INSTALL_LIST),rsync -a --copy-unsafe-links $(INSTALL_LIST)/*.ko $(INSTALL_PATH)/$(INSTALL_LIST))
+endef
+
 define INSTALL_RULE
        $(eval INSTALL_LIST = $(TEST_PROGS)) $(INSTALL_SINGLE_RULE)
        $(eval INSTALL_LIST = $(TEST_PROGS_EXTENDED)) $(INSTALL_SINGLE_RULE)
@@ -97,6 +109,7 @@ define INSTALL_RULE
        $(eval INSTALL_LIST = $(TEST_CUSTOM_PROGS)) $(INSTALL_SINGLE_RULE)
        $(eval INSTALL_LIST = $(TEST_GEN_PROGS_EXTENDED)) $(INSTALL_SINGLE_RULE)
        $(eval INSTALL_LIST = $(TEST_GEN_FILES)) $(INSTALL_SINGLE_RULE)
+       $(eval INSTALL_LIST = $(notdir $(TEST_GEN_MODS_DIR))) $(INSTALL_MODS_RULE)
        $(eval INSTALL_LIST = $(wildcard config settings)) $(INSTALL_SINGLE_RULE)
 endef
 
@@ -122,7 +135,7 @@ define CLEAN
        $(RM) -r $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(EXTRA_CLEAN)
 endef
 
-clean:
+clean: $(if $(TEST_GEN_MODS_DIR),clean_mods_dir)
        $(CLEAN)
 
 # Enables to extend CFLAGS and LDFLAGS from command line, e.g.
@@ -153,4 +166,4 @@ $(OUTPUT)/%:%.S
        $(LINK.S) $^ $(LDLIBS) -o $@
 endif
 
-.PHONY: run_tests all clean install emit_tests
+.PHONY: run_tests all clean install emit_tests gen_mods_dir clean_mods_dir
diff --git a/tools/testing/selftests/livepatch/.gitignore b/tools/testing/selftests/livepatch/.gitignore
new file mode 100644 (file)
index 0000000..f1e9c2a
--- /dev/null
@@ -0,0 +1 @@
+test_klp-call_getpid
index 02fadc9d55e0f576b22b0053189739d51ed6fba5..35418a4790be4be0461044d2a9430adea6366791 100644 (file)
@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
+TEST_GEN_FILES := test_klp-call_getpid
+TEST_GEN_MODS_DIR := test_modules
 TEST_PROGS_EXTENDED := functions.sh
 TEST_PROGS := \
        test-livepatch.sh \
@@ -7,7 +9,8 @@ TEST_PROGS := \
        test-shadow-vars.sh \
        test-state.sh \
        test-ftrace.sh \
-       test-sysfs.sh
+       test-sysfs.sh \
+       test-syscall.sh
 
 TEST_FILES := settings
 
index 0942dd5826f87d546b804d78a0b82f14329f6240..d2035dd64a2bea04cc55e1413ef76671ef6f7b0f 100644 (file)
@@ -13,23 +13,36 @@ the message buffer for only the duration of each individual test.)
 Config
 ------
 
-Set these config options and their prerequisites:
+Set CONFIG_LIVEPATCH=y option and it's prerequisites.
 
-CONFIG_LIVEPATCH=y
-CONFIG_TEST_LIVEPATCH=m
 
+Building the tests
+------------------
+
+To only build the tests without running them, run:
+
+  % make -C tools/testing/selftests/livepatch
+
+The command above will compile all test modules and test programs, making them
+ready to be packaged if so desired.
 
 Running the tests
 -----------------
 
-Test kernel modules are built as part of lib/ (make modules) and need to
-be installed (make modules_install) as the test scripts will modprobe
-them.
+Test kernel modules are built before running the livepatch selftests.  The
+modules are located under test_modules directory, and are built as out-of-tree
+modules.  This is specially useful since the same sources can be built and
+tested on systems with different kABI, ensuring they the tests are backwards
+compatible.  The modules will be loaded by the test scripts using insmod.
 
 To run the livepatch selftests, from the top of the kernel source tree:
 
   % make -C tools/testing/selftests TARGETS=livepatch run_tests
 
+or
+
+  % make kselftest TARGETS=livepatch
+
 
 Adding tests
 ------------
index ad23100cb27c84da75727efb714244487008c046..e88bf518a23ab3ccff9dfa1da9656e61e4f2a316 100644 (file)
@@ -1,3 +1,2 @@
 CONFIG_LIVEPATCH=y
 CONFIG_DYNAMIC_DEBUG=y
-CONFIG_TEST_LIVEPATCH=m
index b1fd7362c2feec339228036dace5d28fe1b1719b..fc4c6a016d3853a6b6903387ecc146a3dba86420 100644 (file)
@@ -34,6 +34,18 @@ function is_root() {
        fi
 }
 
+# Check if we can compile the modules before loading them
+function has_kdir() {
+       if [ -z "$KDIR" ]; then
+               KDIR="/lib/modules/$(uname -r)/build"
+       fi
+
+       if [ ! -d "$KDIR" ]; then
+               echo "skip all tests: KDIR ($KDIR) not available to compile modules."
+               exit $ksft_skip
+       fi
+}
+
 # die(msg) - game over, man
 #      msg - dying words
 function die() {
@@ -96,6 +108,7 @@ function cleanup() {
 #               the ftrace_enabled sysctl.
 function setup_config() {
        is_root
+       has_kdir
        push_config
        set_dynamic_debug
        set_ftrace_enabled 1
@@ -115,16 +128,14 @@ function loop_until() {
        done
 }
 
-function assert_mod() {
-       local mod="$1"
-
-       modprobe --dry-run "$mod" &>/dev/null
-}
-
 function is_livepatch_mod() {
        local mod="$1"
 
-       if [[ $(modinfo "$mod" | awk '/^livepatch:/{print $NF}') == "Y" ]]; then
+       if [[ ! -f "test_modules/$mod.ko" ]]; then
+               die "Can't find \"test_modules/$mod.ko\", try \"make\""
+       fi
+
+       if [[ $(modinfo "test_modules/$mod.ko" | awk '/^livepatch:/{print $NF}') == "Y" ]]; then
                return 0
        fi
 
@@ -134,9 +145,9 @@ function is_livepatch_mod() {
 function __load_mod() {
        local mod="$1"; shift
 
-       local msg="% modprobe $mod $*"
+       local msg="% insmod test_modules/$mod.ko $*"
        log "${msg%% }"
-       ret=$(modprobe "$mod" "$@" 2>&1)
+       ret=$(insmod "test_modules/$mod.ko" "$@" 2>&1)
        if [[ "$ret" != "" ]]; then
                die "$ret"
        fi
@@ -149,13 +160,10 @@ function __load_mod() {
 
 # load_mod(modname, params) - load a kernel module
 #      modname - module name to load
-#      params  - module parameters to pass to modprobe
+#      params  - module parameters to pass to insmod
 function load_mod() {
        local mod="$1"; shift
 
-       assert_mod "$mod" ||
-               skip "unable to load module ${mod}, verify CONFIG_TEST_LIVEPATCH=m and run self-tests as root"
-
        is_livepatch_mod "$mod" &&
                die "use load_lp() to load the livepatch module $mod"
 
@@ -165,13 +173,10 @@ function load_mod() {
 # load_lp_nowait(modname, params) - load a kernel module with a livepatch
 #                      but do not wait on until the transition finishes
 #      modname - module name to load
-#      params  - module parameters to pass to modprobe
+#      params  - module parameters to pass to insmod
 function load_lp_nowait() {
        local mod="$1"; shift
 
-       assert_mod "$mod" ||
-               skip "unable to load module ${mod}, verify CONFIG_TEST_LIVEPATCH=m and run self-tests as root"
-
        is_livepatch_mod "$mod" ||
                die "module $mod is not a livepatch"
 
@@ -184,7 +189,7 @@ function load_lp_nowait() {
 
 # load_lp(modname, params) - load a kernel module with a livepatch
 #      modname - module name to load
-#      params  - module parameters to pass to modprobe
+#      params  - module parameters to pass to insmod
 function load_lp() {
        local mod="$1"; shift
 
@@ -197,13 +202,13 @@ function load_lp() {
 
 # load_failing_mod(modname, params) - load a kernel module, expect to fail
 #      modname - module name to load
-#      params  - module parameters to pass to modprobe
+#      params  - module parameters to pass to insmod
 function load_failing_mod() {
        local mod="$1"; shift
 
-       local msg="% modprobe $mod $*"
+       local msg="% insmod test_modules/$mod.ko $*"
        log "${msg%% }"
-       ret=$(modprobe "$mod" "$@" 2>&1)
+       ret=$(insmod "test_modules/$mod.ko" "$@" 2>&1)
        if [[ "$ret" == "" ]]; then
                die "$mod unexpectedly loaded"
        fi
index 90b26dbb26262c6f21ac02741cec6c316636fff2..32b150e25b10b8ab8e3cbc8a20005b2e883f8b50 100755 (executable)
@@ -34,9 +34,9 @@ disable_lp $MOD_LIVEPATCH
 unload_lp $MOD_LIVEPATCH
 unload_mod $MOD_TARGET
 
-check_result "% modprobe $MOD_TARGET
+check_result "% insmod test_modules/$MOD_TARGET.ko
 $MOD_TARGET: ${MOD_TARGET}_init
-% modprobe $MOD_LIVEPATCH
+% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 $MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -81,7 +81,7 @@ disable_lp $MOD_LIVEPATCH
 unload_lp $MOD_LIVEPATCH
 unload_mod $MOD_TARGET
 
-check_result "% modprobe $MOD_LIVEPATCH
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 $MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -89,7 +89,7 @@ livepatch: '$MOD_LIVEPATCH': starting patching transition
 livepatch: '$MOD_LIVEPATCH': completing patching transition
 $MOD_LIVEPATCH: post_patch_callback: vmlinux
 livepatch: '$MOD_LIVEPATCH': patching complete
-% modprobe $MOD_TARGET
+% insmod test_modules/$MOD_TARGET.ko
 livepatch: applying patch '$MOD_LIVEPATCH' to loading module '$MOD_TARGET'
 $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init
 $MOD_LIVEPATCH: post_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init
@@ -129,9 +129,9 @@ unload_mod $MOD_TARGET
 disable_lp $MOD_LIVEPATCH
 unload_lp $MOD_LIVEPATCH
 
-check_result "% modprobe $MOD_TARGET
+check_result "% insmod test_modules/$MOD_TARGET.ko
 $MOD_TARGET: ${MOD_TARGET}_init
-% modprobe $MOD_LIVEPATCH
+% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 $MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -177,7 +177,7 @@ unload_mod $MOD_TARGET
 disable_lp $MOD_LIVEPATCH
 unload_lp $MOD_LIVEPATCH
 
-check_result "% modprobe $MOD_LIVEPATCH
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 $MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -185,7 +185,7 @@ livepatch: '$MOD_LIVEPATCH': starting patching transition
 livepatch: '$MOD_LIVEPATCH': completing patching transition
 $MOD_LIVEPATCH: post_patch_callback: vmlinux
 livepatch: '$MOD_LIVEPATCH': patching complete
-% modprobe $MOD_TARGET
+% insmod test_modules/$MOD_TARGET.ko
 livepatch: applying patch '$MOD_LIVEPATCH' to loading module '$MOD_TARGET'
 $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init
 $MOD_LIVEPATCH: post_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init
@@ -219,7 +219,7 @@ load_lp $MOD_LIVEPATCH
 disable_lp $MOD_LIVEPATCH
 unload_lp $MOD_LIVEPATCH
 
-check_result "% modprobe $MOD_LIVEPATCH
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 $MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -254,9 +254,9 @@ load_mod $MOD_TARGET
 load_failing_mod $MOD_LIVEPATCH pre_patch_ret=-19
 unload_mod $MOD_TARGET
 
-check_result "% modprobe $MOD_TARGET
+check_result "% insmod test_modules/$MOD_TARGET.ko
 $MOD_TARGET: ${MOD_TARGET}_init
-% modprobe $MOD_LIVEPATCH pre_patch_ret=-19
+% insmod test_modules/$MOD_LIVEPATCH.ko pre_patch_ret=-19
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 test_klp_callbacks_demo: pre_patch_callback: vmlinux
@@ -265,7 +265,7 @@ livepatch: failed to enable patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': canceling patching transition, going to unpatch
 livepatch: '$MOD_LIVEPATCH': completing unpatching transition
 livepatch: '$MOD_LIVEPATCH': unpatching complete
-modprobe: ERROR: could not insert '$MOD_LIVEPATCH': No such device
+insmod: ERROR: could not insert module test_modules/$MOD_LIVEPATCH.ko: No such device
 % rmmod $MOD_TARGET
 $MOD_TARGET: ${MOD_TARGET}_exit"
 
@@ -295,7 +295,7 @@ load_failing_mod $MOD_TARGET
 disable_lp $MOD_LIVEPATCH
 unload_lp $MOD_LIVEPATCH
 
-check_result "% modprobe $MOD_LIVEPATCH
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 $MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -304,12 +304,12 @@ livepatch: '$MOD_LIVEPATCH': completing patching transition
 $MOD_LIVEPATCH: post_patch_callback: vmlinux
 livepatch: '$MOD_LIVEPATCH': patching complete
 % echo -19 > /sys/module/$MOD_LIVEPATCH/parameters/pre_patch_ret
-% modprobe $MOD_TARGET
+% insmod test_modules/$MOD_TARGET.ko
 livepatch: applying patch '$MOD_LIVEPATCH' to loading module '$MOD_TARGET'
 $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init
 livepatch: pre-patch callback failed for object '$MOD_TARGET'
 livepatch: patch '$MOD_LIVEPATCH' failed for module '$MOD_TARGET', refusing to load module '$MOD_TARGET'
-modprobe: ERROR: could not insert '$MOD_TARGET': No such device
+insmod: ERROR: could not insert module test_modules/$MOD_TARGET.ko: No such device
 % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH/enabled
 livepatch: '$MOD_LIVEPATCH': initializing unpatching transition
 $MOD_LIVEPATCH: pre_unpatch_callback: vmlinux
@@ -340,11 +340,11 @@ disable_lp $MOD_LIVEPATCH
 unload_lp $MOD_LIVEPATCH
 unload_mod $MOD_TARGET_BUSY
 
-check_result "% modprobe $MOD_TARGET_BUSY block_transition=N
+check_result "% insmod test_modules/$MOD_TARGET_BUSY.ko block_transition=N
 $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_init
 $MOD_TARGET_BUSY: busymod_work_func enter
 $MOD_TARGET_BUSY: busymod_work_func exit
-% modprobe $MOD_LIVEPATCH
+% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 $MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -354,7 +354,7 @@ livepatch: '$MOD_LIVEPATCH': completing patching transition
 $MOD_LIVEPATCH: post_patch_callback: vmlinux
 $MOD_LIVEPATCH: post_patch_callback: $MOD_TARGET_BUSY -> [MODULE_STATE_LIVE] Normal state
 livepatch: '$MOD_LIVEPATCH': patching complete
-% modprobe $MOD_TARGET
+% insmod test_modules/$MOD_TARGET.ko
 livepatch: applying patch '$MOD_LIVEPATCH' to loading module '$MOD_TARGET'
 $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init
 $MOD_LIVEPATCH: post_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init
@@ -421,16 +421,16 @@ disable_lp $MOD_LIVEPATCH
 unload_lp $MOD_LIVEPATCH
 unload_mod $MOD_TARGET_BUSY
 
-check_result "% modprobe $MOD_TARGET_BUSY block_transition=Y
+check_result "% insmod test_modules/$MOD_TARGET_BUSY.ko block_transition=Y
 $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_init
 $MOD_TARGET_BUSY: busymod_work_func enter
-% modprobe $MOD_LIVEPATCH
+% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 $MOD_LIVEPATCH: pre_patch_callback: vmlinux
 $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET_BUSY -> [MODULE_STATE_LIVE] Normal state
 livepatch: '$MOD_LIVEPATCH': starting patching transition
-% modprobe $MOD_TARGET
+% insmod test_modules/$MOD_TARGET.ko
 livepatch: applying patch '$MOD_LIVEPATCH' to loading module '$MOD_TARGET'
 $MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init
 $MOD_TARGET: ${MOD_TARGET}_init
@@ -467,7 +467,7 @@ disable_lp $MOD_LIVEPATCH
 unload_lp $MOD_LIVEPATCH2
 unload_lp $MOD_LIVEPATCH
 
-check_result "% modprobe $MOD_LIVEPATCH
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 $MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -475,7 +475,7 @@ livepatch: '$MOD_LIVEPATCH': starting patching transition
 livepatch: '$MOD_LIVEPATCH': completing patching transition
 $MOD_LIVEPATCH: post_patch_callback: vmlinux
 livepatch: '$MOD_LIVEPATCH': patching complete
-% modprobe $MOD_LIVEPATCH2
+% insmod test_modules/$MOD_LIVEPATCH2.ko
 livepatch: enabling patch '$MOD_LIVEPATCH2'
 livepatch: '$MOD_LIVEPATCH2': initializing patching transition
 $MOD_LIVEPATCH2: pre_patch_callback: vmlinux
@@ -523,7 +523,7 @@ disable_lp $MOD_LIVEPATCH2
 unload_lp $MOD_LIVEPATCH2
 unload_lp $MOD_LIVEPATCH
 
-check_result "% modprobe $MOD_LIVEPATCH
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 $MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -531,7 +531,7 @@ livepatch: '$MOD_LIVEPATCH': starting patching transition
 livepatch: '$MOD_LIVEPATCH': completing patching transition
 $MOD_LIVEPATCH: post_patch_callback: vmlinux
 livepatch: '$MOD_LIVEPATCH': patching complete
-% modprobe $MOD_LIVEPATCH2 replace=1
+% insmod test_modules/$MOD_LIVEPATCH2.ko replace=1
 livepatch: enabling patch '$MOD_LIVEPATCH2'
 livepatch: '$MOD_LIVEPATCH2': initializing patching transition
 $MOD_LIVEPATCH2: pre_patch_callback: vmlinux
index 825540a5194d472a122963fdf1b1327aac4e6217..730218bce99c5006336c1c08e4a1d5a74054bda8 100755 (executable)
@@ -35,7 +35,7 @@ disable_lp $MOD_LIVEPATCH
 unload_lp $MOD_LIVEPATCH
 
 check_result "livepatch: kernel.ftrace_enabled = 0
-% modprobe $MOD_LIVEPATCH
+% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 livepatch: failed to register ftrace handler for function 'cmdline_proc_show' (-16)
@@ -44,9 +44,9 @@ livepatch: failed to enable patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': canceling patching transition, going to unpatch
 livepatch: '$MOD_LIVEPATCH': completing unpatching transition
 livepatch: '$MOD_LIVEPATCH': unpatching complete
-modprobe: ERROR: could not insert '$MOD_LIVEPATCH': Device or resource busy
+insmod: ERROR: could not insert module test_modules/$MOD_LIVEPATCH.ko: Device or resource busy
 livepatch: kernel.ftrace_enabled = 1
-% modprobe $MOD_LIVEPATCH
+% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 livepatch: '$MOD_LIVEPATCH': starting patching transition
index 5fe79ac34be12de172ca12ef4295f18223331f7c..e3455a6b11589eed3df64e818b5d5bae1fd97b54 100755 (executable)
@@ -31,7 +31,7 @@ if [[ "$(cat /proc/cmdline)" == "$MOD_LIVEPATCH: this has been live patched" ]]
        die "livepatch kselftest(s) failed"
 fi
 
-check_result "% modprobe $MOD_LIVEPATCH
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 livepatch: '$MOD_LIVEPATCH': starting patching transition
@@ -75,14 +75,14 @@ unload_lp $MOD_LIVEPATCH
 grep 'live patched' /proc/cmdline > /dev/kmsg
 grep 'live patched' /proc/meminfo > /dev/kmsg
 
-check_result "% modprobe $MOD_LIVEPATCH
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 livepatch: '$MOD_LIVEPATCH': starting patching transition
 livepatch: '$MOD_LIVEPATCH': completing patching transition
 livepatch: '$MOD_LIVEPATCH': patching complete
 $MOD_LIVEPATCH: this has been live patched
-% modprobe $MOD_REPLACE replace=0
+% insmod test_modules/$MOD_REPLACE.ko replace=0
 livepatch: enabling patch '$MOD_REPLACE'
 livepatch: '$MOD_REPLACE': initializing patching transition
 livepatch: '$MOD_REPLACE': starting patching transition
@@ -135,14 +135,14 @@ unload_lp $MOD_REPLACE
 grep 'live patched' /proc/cmdline > /dev/kmsg
 grep 'live patched' /proc/meminfo > /dev/kmsg
 
-check_result "% modprobe $MOD_LIVEPATCH
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 livepatch: '$MOD_LIVEPATCH': starting patching transition
 livepatch: '$MOD_LIVEPATCH': completing patching transition
 livepatch: '$MOD_LIVEPATCH': patching complete
 $MOD_LIVEPATCH: this has been live patched
-% modprobe $MOD_REPLACE replace=1
+% insmod test_modules/$MOD_REPLACE.ko replace=1
 livepatch: enabling patch '$MOD_REPLACE'
 livepatch: '$MOD_REPLACE': initializing patching transition
 livepatch: '$MOD_REPLACE': starting patching transition
index e04cb354f56b2059359f0aa3fa941a5cb6d8b220..1218c155bffeaba5735b0b127348bbe569a9017a 100755 (executable)
@@ -16,7 +16,7 @@ start_test "basic shadow variable API"
 load_mod $MOD_TEST
 unload_mod $MOD_TEST
 
-check_result "% modprobe $MOD_TEST
+check_result "% insmod test_modules/$MOD_TEST.ko
 $MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1234) = PTR0
 $MOD_TEST:   got expected NULL result
 $MOD_TEST: shadow_ctor: PTR3 -> PTR2
index 38656721c958b48814f58f0f9b7741a1482db3db..10a52ac061850561f7d2fb9201755c55fdd9c7c7 100755 (executable)
@@ -19,7 +19,7 @@ load_lp $MOD_LIVEPATCH
 disable_lp $MOD_LIVEPATCH
 unload_lp $MOD_LIVEPATCH
 
-check_result "% modprobe $MOD_LIVEPATCH
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 $MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -51,7 +51,7 @@ unload_lp $MOD_LIVEPATCH
 disable_lp $MOD_LIVEPATCH2
 unload_lp $MOD_LIVEPATCH2
 
-check_result "% modprobe $MOD_LIVEPATCH
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 $MOD_LIVEPATCH: pre_patch_callback: vmlinux
@@ -61,7 +61,7 @@ livepatch: '$MOD_LIVEPATCH': completing patching transition
 $MOD_LIVEPATCH: post_patch_callback: vmlinux
 $MOD_LIVEPATCH: fix_console_loglevel: fixing console_loglevel
 livepatch: '$MOD_LIVEPATCH': patching complete
-% modprobe $MOD_LIVEPATCH2
+% insmod test_modules/$MOD_LIVEPATCH2.ko
 livepatch: enabling patch '$MOD_LIVEPATCH2'
 livepatch: '$MOD_LIVEPATCH2': initializing patching transition
 $MOD_LIVEPATCH2: pre_patch_callback: vmlinux
@@ -96,7 +96,7 @@ disable_lp $MOD_LIVEPATCH2
 unload_lp $MOD_LIVEPATCH2
 unload_lp $MOD_LIVEPATCH3
 
-check_result "% modprobe $MOD_LIVEPATCH2
+check_result "% insmod test_modules/$MOD_LIVEPATCH2.ko
 livepatch: enabling patch '$MOD_LIVEPATCH2'
 livepatch: '$MOD_LIVEPATCH2': initializing patching transition
 $MOD_LIVEPATCH2: pre_patch_callback: vmlinux
@@ -106,7 +106,7 @@ livepatch: '$MOD_LIVEPATCH2': completing patching transition
 $MOD_LIVEPATCH2: post_patch_callback: vmlinux
 $MOD_LIVEPATCH2: fix_console_loglevel: fixing console_loglevel
 livepatch: '$MOD_LIVEPATCH2': patching complete
-% modprobe $MOD_LIVEPATCH3
+% insmod test_modules/$MOD_LIVEPATCH3.ko
 livepatch: enabling patch '$MOD_LIVEPATCH3'
 livepatch: '$MOD_LIVEPATCH3': initializing patching transition
 $MOD_LIVEPATCH3: pre_patch_callback: vmlinux
@@ -117,7 +117,7 @@ $MOD_LIVEPATCH3: post_patch_callback: vmlinux
 $MOD_LIVEPATCH3: fix_console_loglevel: taking over the console_loglevel change
 livepatch: '$MOD_LIVEPATCH3': patching complete
 % rmmod $MOD_LIVEPATCH2
-% modprobe $MOD_LIVEPATCH2
+% insmod test_modules/$MOD_LIVEPATCH2.ko
 livepatch: enabling patch '$MOD_LIVEPATCH2'
 livepatch: '$MOD_LIVEPATCH2': initializing patching transition
 $MOD_LIVEPATCH2: pre_patch_callback: vmlinux
@@ -149,7 +149,7 @@ load_failing_mod $MOD_LIVEPATCH
 disable_lp $MOD_LIVEPATCH2
 unload_lp $MOD_LIVEPATCH2
 
-check_result "% modprobe $MOD_LIVEPATCH2
+check_result "% insmod test_modules/$MOD_LIVEPATCH2.ko
 livepatch: enabling patch '$MOD_LIVEPATCH2'
 livepatch: '$MOD_LIVEPATCH2': initializing patching transition
 $MOD_LIVEPATCH2: pre_patch_callback: vmlinux
@@ -159,9 +159,9 @@ livepatch: '$MOD_LIVEPATCH2': completing patching transition
 $MOD_LIVEPATCH2: post_patch_callback: vmlinux
 $MOD_LIVEPATCH2: fix_console_loglevel: fixing console_loglevel
 livepatch: '$MOD_LIVEPATCH2': patching complete
-% modprobe $MOD_LIVEPATCH
+% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: Livepatch patch ($MOD_LIVEPATCH) is not compatible with the already installed livepatches.
-modprobe: ERROR: could not insert '$MOD_LIVEPATCH': Invalid argument
+insmod: ERROR: could not insert module test_modules/$MOD_LIVEPATCH.ko: Invalid parameters
 % echo 0 > /sys/kernel/livepatch/$MOD_LIVEPATCH2/enabled
 livepatch: '$MOD_LIVEPATCH2': initializing unpatching transition
 $MOD_LIVEPATCH2: pre_unpatch_callback: vmlinux
diff --git a/tools/testing/selftests/livepatch/test-syscall.sh b/tools/testing/selftests/livepatch/test-syscall.sh
new file mode 100755 (executable)
index 0000000..b76a881
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2023 SUSE
+# Author: Marcos Paulo de Souza <mpdesouza@suse.com>
+
+. $(dirname $0)/functions.sh
+
+MOD_SYSCALL=test_klp_syscall
+
+setup_config
+
+# - Start _NRPROC processes calling getpid and load a livepatch to patch the
+#   getpid syscall. Check if all the processes transitioned to the livepatched
+#   state.
+
+start_test "patch getpid syscall while being heavily hammered"
+
+for i in $(seq 1 $(getconf _NPROCESSORS_ONLN)); do
+       ./test_klp-call_getpid &
+       pids[$i]="$!"
+done
+
+pid_list=$(echo ${pids[@]} | tr ' ' ',')
+load_lp $MOD_SYSCALL klp_pids=$pid_list
+
+# wait for all tasks to transition to patched state
+loop_until 'grep -q '^0$' /sys/kernel/test_klp_syscall/npids'
+
+pending_pids=$(cat /sys/kernel/test_klp_syscall/npids)
+log "$MOD_SYSCALL: Remaining not livepatched processes: $pending_pids"
+
+for pid in ${pids[@]}; do
+       kill $pid || true
+done
+
+disable_lp $MOD_SYSCALL
+unload_lp $MOD_SYSCALL
+
+check_result "% insmod test_modules/$MOD_SYSCALL.ko klp_pids=$pid_list
+livepatch: enabling patch '$MOD_SYSCALL'
+livepatch: '$MOD_SYSCALL': initializing patching transition
+livepatch: '$MOD_SYSCALL': starting patching transition
+livepatch: '$MOD_SYSCALL': completing patching transition
+livepatch: '$MOD_SYSCALL': patching complete
+$MOD_SYSCALL: Remaining not livepatched processes: 0
+% echo 0 > /sys/kernel/livepatch/$MOD_SYSCALL/enabled
+livepatch: '$MOD_SYSCALL': initializing unpatching transition
+livepatch: '$MOD_SYSCALL': starting unpatching transition
+livepatch: '$MOD_SYSCALL': completing unpatching transition
+livepatch: '$MOD_SYSCALL': unpatching complete
+% rmmod $MOD_SYSCALL"
+
+exit 0
index 7f76f280189a0c341517e641612387ae1ec63143..6c646afa7395e5324c24c0aeaa6ac606745ea4f4 100755 (executable)
@@ -27,7 +27,7 @@ disable_lp $MOD_LIVEPATCH
 
 unload_lp $MOD_LIVEPATCH
 
-check_result "% modprobe $MOD_LIVEPATCH
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko
 livepatch: enabling patch '$MOD_LIVEPATCH'
 livepatch: '$MOD_LIVEPATCH': initializing patching transition
 livepatch: '$MOD_LIVEPATCH': starting patching transition
@@ -56,7 +56,7 @@ check_sysfs_value  "$MOD_LIVEPATCH" "$MOD_TARGET/patched" "0"
 disable_lp $MOD_LIVEPATCH
 unload_lp $MOD_LIVEPATCH
 
-check_result "% modprobe test_klp_callbacks_demo
+check_result "% insmod test_modules/test_klp_callbacks_demo.ko
 livepatch: enabling patch 'test_klp_callbacks_demo'
 livepatch: 'test_klp_callbacks_demo': initializing patching transition
 test_klp_callbacks_demo: pre_patch_callback: vmlinux
@@ -64,7 +64,7 @@ livepatch: 'test_klp_callbacks_demo': starting patching transition
 livepatch: 'test_klp_callbacks_demo': completing patching transition
 test_klp_callbacks_demo: post_patch_callback: vmlinux
 livepatch: 'test_klp_callbacks_demo': patching complete
-% modprobe test_klp_callbacks_mod
+% insmod test_modules/test_klp_callbacks_mod.ko
 livepatch: applying patch 'test_klp_callbacks_demo' to loading module 'test_klp_callbacks_mod'
 test_klp_callbacks_demo: pre_patch_callback: test_klp_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init
 test_klp_callbacks_demo: post_patch_callback: test_klp_callbacks_mod -> [MODULE_STATE_COMING] Full formed, running module_init
diff --git a/tools/testing/selftests/livepatch/test_klp-call_getpid.c b/tools/testing/selftests/livepatch/test_klp-call_getpid.c
new file mode 100644 (file)
index 0000000..ce321a2
--- /dev/null
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 SUSE
+ * Authors: Libor Pechacek <lpechacek@suse.cz>
+ *          Marcos Paulo de Souza <mpdesouza@suse.com>
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <signal.h>
+
+static int stop;
+static int sig_int;
+
+void hup_handler(int signum)
+{
+       stop = 1;
+}
+
+void int_handler(int signum)
+{
+       stop = 1;
+       sig_int = 1;
+}
+
+int main(int argc, char *argv[])
+{
+       long count = 0;
+
+       signal(SIGHUP, &hup_handler);
+       signal(SIGINT, &int_handler);
+
+       while (!stop) {
+               (void)syscall(SYS_getpid);
+               count++;
+       }
+
+       if (sig_int)
+               printf("%ld iterations done\n", count);
+
+       return 0;
+}
diff --git a/tools/testing/selftests/livepatch/test_modules/Makefile b/tools/testing/selftests/livepatch/test_modules/Makefile
new file mode 100644 (file)
index 0000000..e6e638c
--- /dev/null
@@ -0,0 +1,26 @@
+TESTMODS_DIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
+KDIR ?= /lib/modules/$(shell uname -r)/build
+
+obj-m += test_klp_atomic_replace.o \
+       test_klp_callbacks_busy.o \
+       test_klp_callbacks_demo.o \
+       test_klp_callbacks_demo2.o \
+       test_klp_callbacks_mod.o \
+       test_klp_livepatch.o \
+       test_klp_state.o \
+       test_klp_state2.o \
+       test_klp_state3.o \
+       test_klp_shadow_vars.o \
+       test_klp_syscall.o
+
+# Ensure that KDIR exists, otherwise skip the compilation
+modules:
+ifneq ("$(wildcard $(KDIR))", "")
+       $(Q)$(MAKE) -C $(KDIR) modules KBUILD_EXTMOD=$(TESTMODS_DIR)
+endif
+
+# Ensure that KDIR exists, otherwise skip the clean target
+clean:
+ifneq ("$(wildcard $(KDIR))", "")
+       $(Q)$(MAKE) -C $(KDIR) clean KBUILD_EXTMOD=$(TESTMODS_DIR)
+endif
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c b/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c
new file mode 100644 (file)
index 0000000..dd80278
--- /dev/null
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017-2023 SUSE
+ * Authors: Libor Pechacek <lpechacek@suse.cz>
+ *          Nicolai Stange <nstange@suse.de>
+ *          Marcos Paulo de Souza <mpdesouza@suse.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/livepatch.h>
+
+#if defined(__x86_64__)
+#define FN_PREFIX __x64_
+#elif defined(__s390x__)
+#define FN_PREFIX __s390x_
+#elif defined(__aarch64__)
+#define FN_PREFIX __arm64_
+#else
+/* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER */
+#define FN_PREFIX
+#endif
+
+/* Protects klp_pids */
+static DEFINE_MUTEX(kpid_mutex);
+
+static unsigned int npids, npids_pending;
+static int klp_pids[NR_CPUS];
+module_param_array(klp_pids, int, &npids_pending, 0);
+MODULE_PARM_DESC(klp_pids, "Array of pids to be transitioned to livepatched state.");
+
+static ssize_t npids_show(struct kobject *kobj, struct kobj_attribute *attr,
+                         char *buf)
+{
+       return sprintf(buf, "%u\n", npids_pending);
+}
+
+static struct kobj_attribute klp_attr = __ATTR_RO(npids);
+static struct kobject *klp_kobj;
+
+static asmlinkage long lp_sys_getpid(void)
+{
+       int i;
+
+       mutex_lock(&kpid_mutex);
+       if (npids_pending > 0) {
+               for (i = 0; i < npids; i++) {
+                       if (current->pid == klp_pids[i]) {
+                               klp_pids[i] = 0;
+                               npids_pending--;
+                               break;
+                       }
+               }
+       }
+       mutex_unlock(&kpid_mutex);
+
+       return task_tgid_vnr(current);
+}
+
+static struct klp_func vmlinux_funcs[] = {
+       {
+               .old_name = __stringify(FN_PREFIX) "sys_getpid",
+               .new_func = lp_sys_getpid,
+       }, {}
+};
+
+static struct klp_object objs[] = {
+       {
+               /* name being NULL means vmlinux */
+               .funcs = vmlinux_funcs,
+       }, {}
+};
+
+static struct klp_patch patch = {
+       .mod = THIS_MODULE,
+       .objs = objs,
+};
+
+static int livepatch_init(void)
+{
+       int ret;
+
+       klp_kobj = kobject_create_and_add("test_klp_syscall", kernel_kobj);
+       if (!klp_kobj)
+               return -ENOMEM;
+
+       ret = sysfs_create_file(klp_kobj, &klp_attr.attr);
+       if (ret) {
+               kobject_put(klp_kobj);
+               return ret;
+       }
+
+       /*
+        * Save the number pids to transition to livepatched state before the
+        * number of pending pids is decremented.
+        */
+       npids = npids_pending;
+
+       return klp_enable_patch(&patch);
+}
+
+static void livepatch_exit(void)
+{
+       kobject_put(klp_kobj);
+}
+
+module_init(livepatch_init);
+module_exit(livepatch_exit);
+MODULE_LICENSE("GPL");
+MODULE_INFO(livepatch, "Y");
+MODULE_AUTHOR("Libor Pechacek <lpechacek@suse.cz>");
+MODULE_AUTHOR("Nicolai Stange <nstange@suse.de>");
+MODULE_AUTHOR("Marcos Paulo de Souza <mpdesouza@suse.com>");
+MODULE_DESCRIPTION("Livepatch test: syscall transition");
index cce90a10515ad2fe78fe68147d26732d717c3bb6..2b9f8cc52639d1942238b41a1ad55edc6bd406ed 100644 (file)
@@ -1517,6 +1517,12 @@ int main(int argc, char *argv[])
                                continue;
 
                        uffd_test_start("%s on %s", test->name, mem_type->name);
+                       if ((mem_type->mem_flag == MEM_HUGETLB ||
+                           mem_type->mem_flag == MEM_HUGETLB_PRIVATE) &&
+                           (default_huge_page_size() == 0)) {
+                               uffd_test_skip("huge page size is 0, feature missing?");
+                               continue;
+                       }
                        if (!uffd_feature_supported(test)) {
                                uffd_test_skip("feature missing");
                                continue;
index 50ed5d475dd1317ede706a90d68ec3db06c82e32..bcf51d785a3712934e9e6d2833f6bac00cbe68a2 100644 (file)
@@ -218,7 +218,7 @@ static bool move_mount_set_group_supported(void)
        if (mount(NULL, SET_GROUP_FROM, NULL, MS_SHARED, 0))
                return -1;
 
-       ret = syscall(SYS_move_mount, AT_FDCWD, SET_GROUP_FROM,
+       ret = syscall(__NR_move_mount, AT_FDCWD, SET_GROUP_FROM,
                      AT_FDCWD, SET_GROUP_TO, MOVE_MOUNT_SET_GROUP);
        umount2("/tmp", MNT_DETACH);
 
@@ -363,7 +363,7 @@ TEST_F(move_mount_set_group, complex_sharing_copying)
                       CLONE_VM | CLONE_FILES); ASSERT_GT(pid, 0);
        ASSERT_EQ(wait_for_pid(pid), 0);
 
-       ASSERT_EQ(syscall(SYS_move_mount, ca_from.mntfd, "",
+       ASSERT_EQ(syscall(__NR_move_mount, ca_from.mntfd, "",
                          ca_to.mntfd, "", MOVE_MOUNT_SET_GROUP
                          | MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH),
                  0);
diff --git a/tools/testing/selftests/mqueue/setting b/tools/testing/selftests/mqueue/setting
new file mode 100644 (file)
index 0000000..a953c96
--- /dev/null
@@ -0,0 +1 @@
+timeout=180
index 3b749addd364040491010ab9d4b50a19c4e3b643..5e4390cac17eda2c96d35c5cdcdf6899610e4367 100644 (file)
@@ -24,10 +24,14 @@ CONFIG_IFB=y
 CONFIG_INET_DIAG=y
 CONFIG_INET_ESP=y
 CONFIG_INET_ESP_OFFLOAD=y
+CONFIG_NET_FOU=y
+CONFIG_NET_FOU_IP_TUNNELS=y
 CONFIG_IP_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_ADVANCED=y
 CONFIG_NF_CONNTRACK=m
+CONFIG_IPV6_SIT=y
+CONFIG_IP_DCCP=m
 CONFIG_NF_NAT=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP_NF_IPTABLES=m
@@ -62,6 +66,7 @@ CONFIG_NET_CLS_MATCHALL=m
 CONFIG_NET_CLS_U32=m
 CONFIG_NET_IPGRE_DEMUX=m
 CONFIG_NET_IPGRE=m
+CONFIG_NET_IPIP=y
 CONFIG_NET_SCH_FQ_CODEL=m
 CONFIG_NET_SCH_HTB=m
 CONFIG_NET_SCH_FQ=m
@@ -78,7 +83,6 @@ CONFIG_TLS=m
 CONFIG_TRACEPOINTS=y
 CONFIG_NET_DROP_MONITOR=m
 CONFIG_NETDEVSIM=m
-CONFIG_NET_FOU=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
 CONFIG_NET_SCH_INGRESS=m
index 9af9f6964808baee53e69c51ad1adb4128fc700a..c62331b2e006069e8812dedf797968c24726493d 100755 (executable)
@@ -327,10 +327,10 @@ locked_port_mab_redirect()
        RET=0
        check_port_mab_support || return 0
 
-       bridge link set dev $swp1 learning on locked on mab on
        tc qdisc add dev $swp1 clsact
        tc filter add dev $swp1 ingress protocol all pref 1 handle 101 flower \
                action mirred egress redirect dev $swp2
+       bridge link set dev $swp1 learning on locked on mab on
 
        ping_do $h1 192.0.2.2
        check_err $? "Ping did not work with redirection"
@@ -349,8 +349,8 @@ locked_port_mab_redirect()
        check_err $? "Locked entry not created after deleting filter"
 
        bridge fdb del `mac_get $h1` vlan 1 dev $swp1 master
-       tc qdisc del dev $swp1 clsact
        bridge link set dev $swp1 learning off locked off mab off
+       tc qdisc del dev $swp1 clsact
 
        log_test "Locked port MAB redirect"
 }
index 61348f71728cd54537f49e17b192e08514323b4c..d9d587454d207931a539f59be15cbc63d471888f 100755 (executable)
@@ -329,7 +329,7 @@ __cfg_test_port_ip_star_g()
 
        bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q " 0.00"
        check_err $? "(*, G) \"permanent\" entry has a pending group timer"
-       bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "\/0.00"
+       bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "/0.00"
        check_err $? "\"permanent\" source entry has a pending source timer"
 
        bridge mdb del dev br0 port $swp1 grp $grp vid 10
@@ -346,7 +346,7 @@ __cfg_test_port_ip_star_g()
 
        bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q " 0.00"
        check_fail $? "(*, G) EXCLUDE entry does not have a pending group timer"
-       bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "\/0.00"
+       bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "/0.00"
        check_err $? "\"blocked\" source entry has a pending source timer"
 
        bridge mdb del dev br0 port $swp1 grp $grp vid 10
@@ -363,7 +363,7 @@ __cfg_test_port_ip_star_g()
 
        bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q " 0.00"
        check_err $? "(*, G) INCLUDE entry has a pending group timer"
-       bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "\/0.00"
+       bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "/0.00"
        check_fail $? "Source entry does not have a pending source timer"
 
        bridge mdb del dev br0 port $swp1 grp $grp vid 10
@@ -1252,14 +1252,17 @@ fwd_test()
        echo
        log_info "# Forwarding tests"
 
+       # Set the Max Response Delay to 100 centiseconds (1 second) so that the
+       # bridge will start forwarding according to its MDB soon after a
+       # multicast querier is enabled.
+       ip link set dev br0 type bridge mcast_query_response_interval 100
+
        # Forwarding according to MDB entries only takes place when the bridge
        # detects that there is a valid querier in the network. Set the bridge
        # as the querier and assign it a valid IPv6 link-local address to be
        # used as the source address for MLD queries.
        ip -6 address add fe80::1/64 nodad dev br0
        ip link set dev br0 type bridge mcast_querier 1
-       # Wait the default Query Response Interval (10 seconds) for the bridge
-       # to determine that there are no other queriers in the network.
        sleep 10
 
        fwd_test_host
@@ -1267,6 +1270,7 @@ fwd_test()
 
        ip link set dev br0 type bridge mcast_querier 0
        ip -6 address del fe80::1/64 dev br0
+       ip link set dev br0 type bridge mcast_query_response_interval 1000
 }
 
 ctrl_igmpv3_is_in_test()
index b0f5e55d2d0b2584aefacc135ffe6b2d2cab34fc..58962963650227bcc942354a052d8bf2bd95aa13 100755 (executable)
@@ -235,9 +235,6 @@ mirred_egress_to_ingress_tcp_test()
        check_err $? "didn't mirred redirect ICMP"
        tc_check_packets "dev $h1 ingress" 102 10
        check_err $? "didn't drop mirred ICMP"
-       local overlimits=$(tc_rule_stats_get ${h1} 101 egress .overlimits)
-       test ${overlimits} = 10
-       check_err $? "wrong overlimits, expected 10 got ${overlimits}"
 
        tc filter del dev $h1 egress protocol ip pref 100 handle 100 flower
        tc filter del dev $h1 egress protocol ip pref 101 handle 101 flower
index 20a7cb7222b8baa4062a769f2f0d27daf2b00cfd..c2420bb72c128119f005de590e36952dc5960f36 100755 (executable)
@@ -209,14 +209,17 @@ test_l2_miss_multicast()
        # both registered and unregistered multicast traffic.
        bridge link set dev $swp2 mcast_router 2
 
+       # Set the Max Response Delay to 100 centiseconds (1 second) so that the
+       # bridge will start forwarding according to its MDB soon after a
+       # multicast querier is enabled.
+       ip link set dev br1 type bridge mcast_query_response_interval 100
+
        # Forwarding according to MDB entries only takes place when the bridge
        # detects that there is a valid querier in the network. Set the bridge
        # as the querier and assign it a valid IPv6 link-local address to be
        # used as the source address for MLD queries.
        ip link set dev br1 type bridge mcast_querier 1
        ip -6 address add fe80::1/64 nodad dev br1
-       # Wait the default Query Response Interval (10 seconds) for the bridge
-       # to determine that there are no other queriers in the network.
        sleep 10
 
        test_l2_miss_multicast_ipv4
@@ -224,6 +227,7 @@ test_l2_miss_multicast()
 
        ip -6 address del fe80::1/64 dev br1
        ip link set dev br1 type bridge mcast_querier 0
+       ip link set dev br1 type bridge mcast_query_response_interval 1000
        bridge link set dev $swp2 mcast_router 1
 }
 
index 19352f106c1dff1b316ef9991e32c9d78142ac45..02c21ff4ca81fddc89ca697fe3d3f04a5dc792c8 100755 (executable)
@@ -31,6 +31,11 @@ run_test() {
       1>>log.txt
     wait "${server_pid}"
     exit_code=$?
+    if [[ ${test} == "large" && -n "${KSFT_MACHINE_SLOW}" && \
+          ${exit_code} -ne 0 ]]; then
+        echo "Ignoring errors due to slow environment" 1>&2
+        exit_code=0
+    fi
     if [[ "${exit_code}" -eq 0 ]]; then
         break;
     fi
index fe59ca3e5596bfe3abfbb477dad2d8bcbb608a56..12491850ae985a779b069662ccba312a3dc1964e 100755 (executable)
@@ -367,14 +367,12 @@ run_test()
   local desc=$2
   local node_src=$3
   local node_dst=$4
-  local ip6_src=$5
-  local ip6_dst=$6
-  local if_dst=$7
-  local trace_type=$8
-  local ioam_ns=$9
-
-  ip netns exec $node_dst ./ioam6_parser $if_dst $name $ip6_src $ip6_dst \
-         $trace_type $ioam_ns &
+  local ip6_dst=$5
+  local trace_type=$6
+  local ioam_ns=$7
+  local type=$8
+
+  ip netns exec $node_dst ./ioam6_parser $name $trace_type $ioam_ns $type &
   local spid=$!
   sleep 0.1
 
@@ -489,7 +487,7 @@ out_undef_ns()
          trace prealloc type 0x800000 ns 0 size 4 dev veth0
 
   run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
-         db01::2 db01::1 veth0 0x800000 0
+         db01::1 0x800000 0 $1
 
   [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
 }
@@ -509,7 +507,7 @@ out_no_room()
          trace prealloc type 0xc00000 ns 123 size 4 dev veth0
 
   run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
-         db01::2 db01::1 veth0 0xc00000 123
+         db01::1 0xc00000 123 $1
 
   [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
 }
@@ -543,14 +541,14 @@ out_bits()
       if [ $cmd_res != 0 ]
       then
         npassed=$((npassed+1))
-        log_test_passed "$descr"
+        log_test_passed "$descr ($1 mode)"
       else
         nfailed=$((nfailed+1))
-        log_test_failed "$descr"
+        log_test_failed "$descr ($1 mode)"
       fi
     else
        run_test "out_bit$i" "$descr ($1 mode)" $ioam_node_alpha \
-           $ioam_node_beta db01::2 db01::1 veth0 ${bit2type[$i]} 123
+           $ioam_node_beta db01::1 ${bit2type[$i]} 123 $1
     fi
   done
 
@@ -574,7 +572,7 @@ out_full_supp_trace()
          trace prealloc type 0xfff002 ns 123 size 100 dev veth0
 
   run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
-         db01::2 db01::1 veth0 0xfff002 123
+         db01::1 0xfff002 123 $1
 
   [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
 }
@@ -604,7 +602,7 @@ in_undef_ns()
          trace prealloc type 0x800000 ns 0 size 4 dev veth0
 
   run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
-         db01::2 db01::1 veth0 0x800000 0
+         db01::1 0x800000 0 $1
 
   [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
 }
@@ -624,7 +622,7 @@ in_no_room()
          trace prealloc type 0xc00000 ns 123 size 4 dev veth0
 
   run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
-         db01::2 db01::1 veth0 0xc00000 123
+         db01::1 0xc00000 123 $1
 
   [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
 }
@@ -651,7 +649,7 @@ in_bits()
            dev veth0
 
     run_test "in_bit$i" "${desc/<n>/$i} ($1 mode)" $ioam_node_alpha \
-           $ioam_node_beta db01::2 db01::1 veth0 ${bit2type[$i]} 123
+           $ioam_node_beta db01::1 ${bit2type[$i]} 123 $1
   done
 
   [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
@@ -679,7 +677,7 @@ in_oflag()
          trace prealloc type 0xc00000 ns 123 size 4 dev veth0
 
   run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
-         db01::2 db01::1 veth0 0xc00000 123
+         db01::1 0xc00000 123 $1
 
   [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
 
@@ -703,7 +701,7 @@ in_full_supp_trace()
          trace prealloc type 0xfff002 ns 123 size 80 dev veth0
 
   run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
-         db01::2 db01::1 veth0 0xfff002 123
+         db01::1 0xfff002 123 $1
 
   [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
 }
@@ -731,7 +729,7 @@ fwd_full_supp_trace()
          trace prealloc type 0xfff002 ns 123 size 244 via db01::1 dev veth0
 
   run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_gamma \
-         db01::2 db02::2 veth0 0xfff002 123
+         db02::2 0xfff002 123 $1
 
   [ "$1" = "encap" ] && ip -netns $ioam_node_gamma link set ip6tnl0 down
 }
index d9d1d41901267439aac832166e46410c85f44111..895e5bb5044bb126dc9894cf35a68d7cf1c79ec7 100644 (file)
@@ -8,7 +8,6 @@
 #include <errno.h>
 #include <limits.h>
 #include <linux/const.h>
-#include <linux/if_ether.h>
 #include <linux/ioam6.h>
 #include <linux/ipv6.h>
 #include <stdlib.h>
@@ -512,14 +511,6 @@ static int str2id(const char *tname)
        return -1;
 }
 
-static int ipv6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2)
-{
-       return ((a1->s6_addr32[0] ^ a2->s6_addr32[0]) |
-               (a1->s6_addr32[1] ^ a2->s6_addr32[1]) |
-               (a1->s6_addr32[2] ^ a2->s6_addr32[2]) |
-               (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0;
-}
-
 static int get_u32(__u32 *val, const char *arg, int base)
 {
        unsigned long res;
@@ -603,70 +594,80 @@ static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = {
 
 int main(int argc, char **argv)
 {
-       int fd, size, hoplen, tid, ret = 1;
-       struct in6_addr src, dst;
+       int fd, size, hoplen, tid, ret = 1, on = 1;
        struct ioam6_hdr *opt;
-       struct ipv6hdr *ip6h;
-       __u8 buffer[400], *p;
-       __u16 ioam_ns;
+       struct cmsghdr *cmsg;
+       struct msghdr msg;
+       struct iovec iov;
+       __u8 buffer[512];
        __u32 tr_type;
+       __u16 ioam_ns;
+       __u8 *ptr;
 
-       if (argc != 7)
+       if (argc != 5)
                goto out;
 
-       tid = str2id(argv[2]);
+       tid = str2id(argv[1]);
        if (tid < 0 || !func[tid])
                goto out;
 
-       if (inet_pton(AF_INET6, argv[3], &src) != 1 ||
-           inet_pton(AF_INET6, argv[4], &dst) != 1)
+       if (get_u32(&tr_type, argv[2], 16) ||
+           get_u16(&ioam_ns, argv[3], 0))
                goto out;
 
-       if (get_u32(&tr_type, argv[5], 16) ||
-           get_u16(&ioam_ns, argv[6], 0))
+       fd = socket(PF_INET6, SOCK_RAW,
+                   !strcmp(argv[4], "encap") ? IPPROTO_IPV6 : IPPROTO_ICMPV6);
+       if (fd < 0)
                goto out;
 
-       fd = socket(AF_PACKET, SOCK_DGRAM, __cpu_to_be16(ETH_P_IPV6));
-       if (!fd)
-               goto out;
+       setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPOPTS,  &on, sizeof(on));
 
-       if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
-                      argv[1], strlen(argv[1])))
+       iov.iov_len = 1;
+       iov.iov_base = malloc(CMSG_SPACE(sizeof(buffer)));
+       if (!iov.iov_base)
                goto close;
-
 recv:
-       size = recv(fd, buffer, sizeof(buffer), 0);
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_control = buffer;
+       msg.msg_controllen = CMSG_SPACE(sizeof(buffer));
+
+       size = recvmsg(fd, &msg, 0);
        if (size <= 0)
                goto close;
 
-       ip6h = (struct ipv6hdr *)buffer;
+       for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+               if (cmsg->cmsg_level != IPPROTO_IPV6 ||
+                   cmsg->cmsg_type != IPV6_HOPOPTS ||
+                   cmsg->cmsg_len < sizeof(struct ipv6_hopopt_hdr))
+                       continue;
 
-       if (!ipv6_addr_equal(&ip6h->saddr, &src) ||
-           !ipv6_addr_equal(&ip6h->daddr, &dst))
-               goto recv;
+               ptr = (__u8 *)CMSG_DATA(cmsg);
 
-       if (ip6h->nexthdr != IPPROTO_HOPOPTS)
-               goto close;
+               hoplen = (ptr[1] + 1) << 3;
+               ptr += sizeof(struct ipv6_hopopt_hdr);
 
-       p = buffer + sizeof(*ip6h);
-       hoplen = (p[1] + 1) << 3;
-       p += sizeof(struct ipv6_hopopt_hdr);
+               while (hoplen > 0) {
+                       opt = (struct ioam6_hdr *)ptr;
 
-       while (hoplen > 0) {
-               opt = (struct ioam6_hdr *)p;
+                       if (opt->opt_type == IPV6_TLV_IOAM &&
+                           opt->type == IOAM6_TYPE_PREALLOC) {
+                               ptr += sizeof(*opt);
+                               ret = func[tid](tid,
+                                               (struct ioam6_trace_hdr *)ptr,
+                                               tr_type, ioam_ns);
+                               goto close;
+                       }
 
-               if (opt->opt_type == IPV6_TLV_IOAM &&
-                   opt->type == IOAM6_TYPE_PREALLOC) {
-                       p += sizeof(*opt);
-                       ret = func[tid](tid, (struct ioam6_trace_hdr *)p,
-                                          tr_type, ioam_ns);
-                       break;
+                       ptr += opt->opt_len + 2;
+                       hoplen -= opt->opt_len + 2;
                }
-
-               p += opt->opt_len + 2;
-               hoplen -= opt->opt_len + 2;
        }
+
+       goto recv;
 close:
+       free(iov.iov_base);
        close(fd);
 out:
        return ret;
index 0f217a1cc837de22de278d15f7cfb6bbdb372c50..6ebd58869a637227319524c0bdc69fe2495a37c9 100644 (file)
 #define IP_LOCAL_PORT_RANGE 51
 #endif
 
+#ifndef IPPROTO_MPTCP
+#define IPPROTO_MPTCP 262
+#endif
+
 static __u32 pack_port_range(__u16 lo, __u16 hi)
 {
        return (hi << 16) | (lo << 0);
index 04fcb8a077c995c768d222171c045caf2ab3c3b3..75fc95675e2dcaa7a4593d0b9bd2ccaccdb12921 100755 (executable)
@@ -20,7 +20,7 @@ flush_pids()
 
        ip netns pids "${ns}" | xargs --no-run-if-empty kill -SIGUSR1 &>/dev/null
 
-       for _ in $(seq 10); do
+       for _ in $(seq $((timeout_poll * 10))); do
                [ -z "$(ip netns pids "${ns}")" ] && break
                sleep 0.1
        done
@@ -62,14 +62,14 @@ __chk_nr()
        nr=$(eval $command)
 
        printf "%-50s" "$msg"
-       if [ $nr != $expected ]; then
-               if [ $nr = "$skip" ] && ! mptcp_lib_expect_all_features; then
+       if [ "$nr" != "$expected" ]; then
+               if [ "$nr" = "$skip" ] && ! mptcp_lib_expect_all_features; then
                        echo "[ skip ] Feature probably not supported"
                        mptcp_lib_result_skip "${msg}"
                else
                        echo "[ fail ] expected $expected found $nr"
                        mptcp_lib_result_fail "${msg}"
-                       ret=$test_cnt
+                       ret=${KSFT_FAIL}
                fi
        else
                echo "[  ok  ]"
@@ -91,6 +91,15 @@ chk_msk_nr()
        __chk_msk_nr "grep -c token:" "$@"
 }
 
+chk_listener_nr()
+{
+       local expected=$1
+       local msg="$2"
+
+       __chk_nr "ss -nlHMON $ns | wc -l" "$expected" "$msg - mptcp" 0
+       __chk_nr "ss -nlHtON $ns | wc -l" "$expected" "$msg - subflows"
+}
+
 wait_msk_nr()
 {
        local condition="grep -c token:"
@@ -115,11 +124,11 @@ wait_msk_nr()
        if [ $i -ge $timeout ]; then
                echo "[ fail ] timeout while expecting $expected max $max last $nr"
                mptcp_lib_result_fail "${msg} # timeout"
-               ret=$test_cnt
+               ret=${KSFT_FAIL}
        elif [ $nr != $expected ]; then
                echo "[ fail ] expected $expected found $nr"
                mptcp_lib_result_fail "${msg} # unexpected result"
-               ret=$test_cnt
+               ret=${KSFT_FAIL}
        else
                echo "[  ok  ]"
                mptcp_lib_result_pass "${msg}"
@@ -166,9 +175,13 @@ chk_msk_listen()
 chk_msk_inuse()
 {
        local expected=$1
-       local msg="$2"
+       local msg="....chk ${2:-${expected}} msk in use"
        local listen_nr
 
+       if [ "${expected}" -eq 0 ]; then
+               msg+=" after flush"
+       fi
+
        listen_nr=$(ss -N "${ns}" -Ml | grep -c LISTEN)
        expected=$((expected + listen_nr))
 
@@ -179,16 +192,21 @@ chk_msk_inuse()
                sleep 0.1
        done
 
-       __chk_nr get_msk_inuse $expected "$msg" 0
+       __chk_nr get_msk_inuse $expected "${msg}" 0
 }
 
 # $1: cestab nr
 chk_msk_cestab()
 {
-       local cestab=$1
+       local expected=$1
+       local msg="....chk ${2:-${expected}} cestab"
+
+       if [ "${expected}" -eq 0 ]; then
+               msg+=" after flush"
+       fi
 
        __chk_nr "mptcp_lib_get_counter ${ns} MPTcpExtMPCurrEstab" \
-                "${cestab}" "....chk ${cestab} cestab" ""
+                "${expected}" "${msg}" ""
 }
 
 wait_connected()
@@ -227,12 +245,12 @@ wait_connected $ns 10000
 chk_msk_nr 2 "after MPC handshake "
 chk_msk_remote_key_nr 2 "....chk remote_key"
 chk_msk_fallback_nr 0 "....chk no fallback"
-chk_msk_inuse 2 "....chk 2 msk in use"
+chk_msk_inuse 2
 chk_msk_cestab 2
 flush_pids
 
-chk_msk_inuse 0 "....chk 0 msk in use after flush"
-chk_msk_cestab 0
+chk_msk_inuse 0 "2->0"
+chk_msk_cestab 0 "2->0"
 
 echo "a" | \
        timeout ${timeout_test} \
@@ -247,12 +265,12 @@ echo "b" | \
                                127.0.0.1 >/dev/null &
 wait_connected $ns 10001
 chk_msk_fallback_nr 1 "check fallback"
-chk_msk_inuse 1 "....chk 1 msk in use"
+chk_msk_inuse 1
 chk_msk_cestab 1
 flush_pids
 
-chk_msk_inuse 0 "....chk 0 msk in use after flush"
-chk_msk_cestab 0
+chk_msk_inuse 0 "1->0"
+chk_msk_cestab 0 "1->0"
 
 NR_CLIENTS=100
 for I in `seq 1 $NR_CLIENTS`; do
@@ -273,12 +291,28 @@ for I in `seq 1 $NR_CLIENTS`; do
 done
 
 wait_msk_nr $((NR_CLIENTS*2)) "many msk socket present"
-chk_msk_inuse $((NR_CLIENTS*2)) "....chk many msk in use"
-chk_msk_cestab $((NR_CLIENTS*2))
+chk_msk_inuse $((NR_CLIENTS*2)) "many"
+chk_msk_cestab $((NR_CLIENTS*2)) "many"
 flush_pids
 
-chk_msk_inuse 0 "....chk 0 msk in use after flush"
-chk_msk_cestab 0
+chk_msk_inuse 0 "many->0"
+chk_msk_cestab 0 "many->0"
+
+chk_listener_nr 0 "no listener sockets"
+NR_SERVERS=100
+for I in $(seq 1 $NR_SERVERS); do
+       ip netns exec $ns ./mptcp_connect -p $((I + 20001)) \
+               -t ${timeout_poll} -l 0.0.0.0 >/dev/null 2>&1 &
+done
+mptcp_lib_wait_local_port_listen $ns $((NR_SERVERS + 20001))
+
+chk_listener_nr $NR_SERVERS "many listener sockets"
+
+# graceful termination
+for I in $(seq 1 $NR_SERVERS); do
+       echo a | ip netns exec $ns ./mptcp_connect -p $((I + 20001)) 127.0.0.1 >/dev/null 2>&1 &
+done
+flush_pids
 
 mptcp_lib_result_print_all_tap
 exit $ret
index c07386e21e0a4aa10b004cb820488f15ff18dd7a..e4581b0dfb967723e36b1847c512f02f4bc87a45 100755 (executable)
@@ -161,6 +161,11 @@ check_tools()
                exit $ksft_skip
        fi
 
+       if ! ss -h | grep -q MPTCP; then
+               echo "SKIP: ss tool does not support MPTCP"
+               exit $ksft_skip
+       fi
+
        # Use the legacy version if available to support old kernel versions
        if iptables-legacy -V &> /dev/null; then
                iptables="iptables-legacy"
@@ -3333,16 +3338,17 @@ userspace_pm_rm_sf()
 {
        local evts=$evts_ns1
        local t=${3:-1}
-       local ip=4
+       local ip
        local tk da dp sp
        local cnt
 
        [ "$1" == "$ns2" ] && evts=$evts_ns2
-       if mptcp_lib_is_v6 $2; then ip=6; fi
+       [ -n "$(mptcp_lib_evts_get_info "saddr4" "$evts" $t)" ] && ip=4
+       [ -n "$(mptcp_lib_evts_get_info "saddr6" "$evts" $t)" ] && ip=6
        tk=$(mptcp_lib_evts_get_info token "$evts")
-       da=$(mptcp_lib_evts_get_info "daddr$ip" "$evts" $t)
-       dp=$(mptcp_lib_evts_get_info dport "$evts" $t)
-       sp=$(mptcp_lib_evts_get_info sport "$evts" $t)
+       da=$(mptcp_lib_evts_get_info "daddr$ip" "$evts" $t $2)
+       dp=$(mptcp_lib_evts_get_info dport "$evts" $t $2)
+       sp=$(mptcp_lib_evts_get_info sport "$evts" $t $2)
 
        cnt=$(rm_sf_count ${1})
        ip netns exec $1 ./pm_nl_ctl dsf lip $2 lport $sp \
@@ -3429,20 +3435,23 @@ userspace_tests()
        if reset_with_events "userspace pm add & remove address" &&
           continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
                set_userspace_pm $ns1
-               pm_nl_set_limits $ns2 1 1
+               pm_nl_set_limits $ns2 2 2
                speed=5 \
                        run_tests $ns1 $ns2 10.0.1.1 &
                local tests_pid=$!
                wait_mpj $ns1
                userspace_pm_add_addr $ns1 10.0.2.1 10
-               chk_join_nr 1 1 1
-               chk_add_nr 1 1
-               chk_mptcp_info subflows 1 subflows 1
-               chk_subflows_total 2 2
-               chk_mptcp_info add_addr_signal 1 add_addr_accepted 1
+               userspace_pm_add_addr $ns1 10.0.3.1 20
+               chk_join_nr 2 2 2
+               chk_add_nr 2 2
+               chk_mptcp_info subflows 2 subflows 2
+               chk_subflows_total 3 3
+               chk_mptcp_info add_addr_signal 2 add_addr_accepted 2
                userspace_pm_rm_addr $ns1 10
                userspace_pm_rm_sf $ns1 "::ffff:10.0.2.1" $SUB_ESTABLISHED
-               chk_rm_nr 1 1 invert
+               userspace_pm_rm_addr $ns1 20
+               userspace_pm_rm_sf $ns1 10.0.3.1 $SUB_ESTABLISHED
+               chk_rm_nr 2 2 invert
                chk_mptcp_info subflows 0 subflows 0
                chk_subflows_total 1 1
                kill_events_pids
index 3a2abae5993e2b4b32ae810d080dc3d336e41e11..3777d66fc56d36a4770b164fd781af298cd4eb70 100644 (file)
@@ -213,9 +213,9 @@ mptcp_lib_get_info_value() {
        grep "${2}" | sed -n 's/.*\('"${1}"':\)\([0-9a-f:.]*\).*$/\2/p;q'
 }
 
-# $1: info name ; $2: evts_ns ; $3: event type
+# $1: info name ; $2: evts_ns ; [$3: event type; [$4: addr]]
 mptcp_lib_evts_get_info() {
-       mptcp_lib_get_info_value "${1}" "^type:${3:-1}," < "${2}"
+       grep "${4:-}" "${2}" | mptcp_lib_get_info_value "${1}" "^type:${3:-1},"
 }
 
 # $1: PID
index 8f4ff123a7eb92646845a5dea4caf28483057085..71899a3ffa7a9d7831c61f08b7f3b9c20aaed58e 100755 (executable)
@@ -183,7 +183,7 @@ check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
 subflow 10.0.1.1" "          (nobackup)"
 
 # fullmesh support has been added later
-ip netns exec $ns1 ./pm_nl_ctl set id 1 flags fullmesh
+ip netns exec $ns1 ./pm_nl_ctl set id 1 flags fullmesh 2>/dev/null
 if ip netns exec $ns1 ./pm_nl_ctl dump | grep -q "fullmesh" ||
    mptcp_lib_expect_all_features; then
        check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
@@ -194,6 +194,12 @@ subflow 10.0.1.1" "          (nofullmesh)"
        ip netns exec $ns1 ./pm_nl_ctl set id 1 flags backup,fullmesh
        check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
 subflow,backup,fullmesh 10.0.1.1" "          (backup,fullmesh)"
+else
+       for st in fullmesh nofullmesh backup,fullmesh; do
+               st="          (${st})"
+               printf "%-50s%s\n" "${st}" "[SKIP]"
+               mptcp_lib_result_skip "${st}"
+       done
 fi
 
 mptcp_lib_result_print_all_tap
index 0cc964e6f2c1768dad6a474cffd1c521580b7741..8f9ddb3ad4fe83501f54a1ac5e62047108eea910 100755 (executable)
@@ -250,7 +250,8 @@ run_test()
                [ $bail -eq 0 ] || exit $ret
        fi
 
-       printf "%-60s" "$msg - reverse direction"
+       msg+=" - reverse direction"
+       printf "%-60s" "${msg}"
        do_transfer $large $small $time
        lret=$?
        mptcp_lib_result_code "${lret}" "${msg}"
index 6167837f48e17ef8ba0d41ba541f73da765f945e..1b94a75604fee98788ba5792b384ca4870bdafbb 100755 (executable)
@@ -75,7 +75,7 @@ print_test()
 {
        test_name="${1}"
 
-       _printf "%-63s" "${test_name}"
+       _printf "%-68s" "${test_name}"
 }
 
 print_results()
@@ -542,7 +542,7 @@ verify_subflow_events()
        local remid
        local info
 
-       info="${e_saddr} (${e_from}) => ${e_daddr} (${e_to})"
+       info="${e_saddr} (${e_from}) => ${e_daddr}:${e_dport} (${e_to})"
 
        if [ "$e_type" = "$SUB_ESTABLISHED" ]
        then
index 4fe0befa13fbc6aa52fed84080615362ff92724f..6596fe03c77f43742e5676e5ccd1e46ba96e5c12 100644 (file)
@@ -8,13 +8,16 @@ wait_local_port_listen()
        local listener_ns="${1}"
        local port="${2}"
        local protocol="${3}"
-       local port_hex
+       local pattern
        local i
 
-       port_hex="$(printf "%04X" "${port}")"
+       pattern=":$(printf "%04X" "${port}") "
+
+       # for tcp protocol additionally check the socket state
+       [ ${protocol} = "tcp" ] && pattern="${pattern}0A"
        for i in $(seq 10); do
-               if ip netns exec "${listener_ns}" cat /proc/net/"${protocol}"* | \
-                  grep -q "${port_hex}"; then
+               if ip netns exec "${listener_ns}" awk '{print $2" "$4}' \
+                  /proc/net/"${protocol}"* | grep -q "${pattern}"; then
                        break
                fi
                sleep 0.1
index f8499d4c87f3f763e774619666e00ce6a17d333b..36e40256ab92a696de62339dd7c7342df3468372 100755 (executable)
@@ -502,7 +502,20 @@ test_netlink_checks () {
            wc -l) == 2 ] || \
              return 1
 
+       info "Checking clone depth"
        ERR_MSG="Flow actions may not be safe on all matching packets"
+       PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
+       ovs_add_flow "test_netlink_checks" nv0 \
+               'in_port(1),eth(),eth_type(0x800),ipv4()' \
+               'clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(drop)))))))))))))))))' \
+               >/dev/null 2>&1 && return 1
+       POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
+
+       if [ "$PRE_TEST" == "$POST_TEST" ]; then
+               info "failed - clone depth too large"
+               return 1
+       fi
+
        PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
        ovs_add_flow "test_netlink_checks" nv0 \
                'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(0),2' \
index b97e621face958838f1ad5cf2d12dfc5875db4f4..5e0e539a323d55a44802495ca356661ef8de783a 100644 (file)
@@ -299,7 +299,7 @@ class ovsactions(nla):
         ("OVS_ACTION_ATTR_PUSH_NSH", "none"),
         ("OVS_ACTION_ATTR_POP_NSH", "flag"),
         ("OVS_ACTION_ATTR_METER", "none"),
-        ("OVS_ACTION_ATTR_CLONE", "none"),
+        ("OVS_ACTION_ATTR_CLONE", "recursive"),
         ("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"),
         ("OVS_ACTION_ATTR_ADD_MPLS", "none"),
         ("OVS_ACTION_ATTR_DEC_TTL", "none"),
@@ -465,29 +465,42 @@ class ovsactions(nla):
                     print_str += "pop_mpls"
             else:
                 datum = self.get_attr(field[0])
-                print_str += datum.dpstr(more)
+                if field[0] == "OVS_ACTION_ATTR_CLONE":
+                    print_str += "clone("
+                    print_str += datum.dpstr(more)
+                    print_str += ")"
+                else:
+                    print_str += datum.dpstr(more)
 
         return print_str
 
     def parse(self, actstr):
+        totallen = len(actstr)
         while len(actstr) != 0:
             parsed = False
+            parencount = 0
             if actstr.startswith("drop"):
                 # If no reason is provided, the implicit drop is used (i.e no
                 # action). If some reason is given, an explicit action is used.
-                actstr, reason = parse_extract_field(
-                    actstr,
-                    "drop(",
-                    "([0-9]+)",
-                    lambda x: int(x, 0),
-                    False,
-                    None,
-                )
+                reason = None
+                if actstr.startswith("drop("):
+                    parencount += 1
+
+                    actstr, reason = parse_extract_field(
+                        actstr,
+                        "drop(",
+                        "([0-9]+)",
+                        lambda x: int(x, 0),
+                        False,
+                        None,
+                    )
+
                 if reason is not None:
                     self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason])
                     parsed = True
                 else:
-                    return
+                    actstr = actstr[len("drop"): ]
+                    return (totallen - len(actstr))
 
             elif parse_starts_block(actstr, "^(\d+)", False, True):
                 actstr, output = parse_extract_field(
@@ -504,6 +517,7 @@ class ovsactions(nla):
                     False,
                     0,
                 )
+                parencount += 1
                 self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid])
                 parsed = True
 
@@ -516,12 +530,22 @@ class ovsactions(nla):
 
             for flat_act in parse_flat_map:
                 if parse_starts_block(actstr, flat_act[0], False):
-                    actstr += len(flat_act[0])
+                    actstr = actstr[len(flat_act[0]):]
                     self["attrs"].append([flat_act[1]])
                     actstr = actstr[strspn(actstr, ", ") :]
                     parsed = True
 
-            if parse_starts_block(actstr, "ct(", False):
+            if parse_starts_block(actstr, "clone(", False):
+                parencount += 1
+                subacts = ovsactions()
+                actstr = actstr[len("clone("):]
+                parsedLen = subacts.parse(actstr)
+                lst = []
+                self["attrs"].append(("OVS_ACTION_ATTR_CLONE", subacts))
+                actstr = actstr[parsedLen:]
+                parsed = True
+            elif parse_starts_block(actstr, "ct(", False):
+                parencount += 1
                 actstr = actstr[len("ct(") :]
                 ctact = ovsactions.ctact()
 
@@ -553,6 +577,7 @@ class ovsactions(nla):
                         natact = ovsactions.ctact.natattr()
 
                         if actstr.startswith("("):
+                            parencount += 1
                             t = None
                             actstr = actstr[1:]
                             if actstr.startswith("src"):
@@ -607,15 +632,29 @@ class ovsactions(nla):
                                     actstr = actstr[strspn(actstr, ", ") :]
 
                         ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact])
-                        actstr = actstr[strspn(actstr, ",) ") :]
+                        actstr = actstr[strspn(actstr, ", ") :]
 
                 self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact])
                 parsed = True
 
-            actstr = actstr[strspn(actstr, "), ") :]
+            actstr = actstr[strspn(actstr, ", ") :]
+            while parencount > 0:
+                parencount -= 1
+                actstr = actstr[strspn(actstr, " "):]
+                if len(actstr) and actstr[0] != ")":
+                    raise ValueError("Action str: '%s' unbalanced" % actstr)
+                actstr = actstr[1:]
+
+            if len(actstr) and actstr[0] == ")":
+                return (totallen - len(actstr))
+
+            actstr = actstr[strspn(actstr, ", ") :]
+
             if not parsed:
                 raise ValueError("Action str: '%s' not supported" % actstr)
 
+        return (totallen - len(actstr))
+
 
 class ovskey(nla):
     nla_flags = NLA_F_NESTED
@@ -2111,6 +2150,8 @@ def main(argv):
     ovsflow = OvsFlow()
     ndb = NDB()
 
+    sys.setrecursionlimit(100000)
+
     if hasattr(args, "showdp"):
         found = False
         for iface in ndb.interfaces:
index d65fdd407d73f99bc0cbcdf17cfcca9ad6efea87..cfc84958025a61e7ee24a3675a0969e0e3c7cd52 100755 (executable)
@@ -1336,16 +1336,16 @@ test_pmtu_ipvX_over_bridged_vxlanY_or_geneveY_exception() {
                else
                        TCPDST="TCP:[${dst}]:50000"
                fi
-               ${ns_b} socat -T 3 -u -6 TCP-LISTEN:50000 STDOUT > $tmpoutfile &
+               ${ns_b} socat -T 3 -u -6 TCP-LISTEN:50000,reuseaddr STDOUT > $tmpoutfile &
                local socat_pid=$!
 
                wait_local_port_listen ${NS_B} 50000 tcp
 
                dd if=/dev/zero status=none bs=1M count=1 | ${target} socat -T 3 -u STDIN $TCPDST,connect-timeout=3
 
+               wait ${socat_pid}
                size=$(du -sb $tmpoutfile)
                size=${size%%/tmp/*}
-               wait ${socat_pid}
 
                [ $size -ne 1048576 ] && err "File size $size mismatches exepcted value in locally bridged vxlan test" && return 1
        done
index 3f06f4d286a988f15ccbc006f8015b24a07be3f0..5e861ad32a42e11b680236b4a016ed952caf5914 100755 (executable)
@@ -5,6 +5,7 @@
 
 set -e
 
+readonly ksft_skip=4
 readonly DEV="veth0"
 readonly BIN="./so_txtime"
 
@@ -46,7 +47,7 @@ ip -netns "${NS2}" addr add 192.168.1.2/24 dev "${DEV}"
 ip -netns "${NS1}" addr add       fd::1/64 dev "${DEV}" nodad
 ip -netns "${NS2}" addr add       fd::2/64 dev "${DEV}" nodad
 
-do_test() {
+run_test() {
        local readonly IP="$1"
        local readonly CLOCK="$2"
        local readonly TXARGS="$3"
@@ -64,12 +65,25 @@ do_test() {
        fi
 
        local readonly START="$(date +%s%N --date="+ 0.1 seconds")"
+
        ip netns exec "${NS2}" "${BIN}" -"${IP}" -c "${CLOCK}" -t "${START}" -S "${SADDR}" -D "${DADDR}" "${RXARGS}" -r &
        ip netns exec "${NS1}" "${BIN}" -"${IP}" -c "${CLOCK}" -t "${START}" -S "${SADDR}" -D "${DADDR}" "${TXARGS}"
        wait "$!"
 }
 
+do_test() {
+       run_test $@
+       [ $? -ne 0 ] && ret=1
+}
+
+do_fail_test() {
+       run_test $@
+       [ $? -eq 0 ] && ret=1
+}
+
 ip netns exec "${NS1}" tc qdisc add dev "${DEV}" root fq
+set +e
+ret=0
 do_test 4 mono a,-1 a,-1
 do_test 6 mono a,0 a,0
 do_test 6 mono a,10 a,10
@@ -77,13 +91,20 @@ do_test 4 mono a,10,b,20 a,10,b,20
 do_test 6 mono a,20,b,10 b,20,a,20
 
 if ip netns exec "${NS1}" tc qdisc replace dev "${DEV}" root etf clockid CLOCK_TAI delta 400000; then
-       ! do_test 4 tai a,-1 a,-1
-       ! do_test 6 tai a,0 a,0
+       do_fail_test 4 tai a,-1 a,-1
+       do_fail_test 6 tai a,0 a,0
        do_test 6 tai a,10 a,10
        do_test 4 tai a,10,b,20 a,10,b,20
        do_test 6 tai a,20,b,10 b,10,a,20
 else
        echo "tc ($(tc -V)) does not support qdisc etf. skipping"
+       [ $ret -eq 0 ] && ret=$ksft_skip
 fi
 
-echo OK. All tests passed
+if [ $ret -eq 0 ]; then
+       echo OK. All tests passed
+elif [[ $ret -ne $ksft_skip && -n "$KSFT_MACHINE_SLOW" ]]; then
+       echo "Ignoring errors due to slow environment" 1>&2
+       ret=0
+fi
+exit $ret
index 70a7d87ba2d21cecf6d76f7d184e0902e7b6d3e9..1b3f89e2b86e6aac2f9d631bb9bb22265c3f1734 100755 (executable)
@@ -124,6 +124,16 @@ tc_check_packets()
        [[ $pkts == $count ]]
 }
 
+bridge_link_check()
+{
+       local ns=$1; shift
+       local dev=$1; shift
+       local state=$1; shift
+
+       bridge -n $ns -d -j link show dev $dev | \
+               jq -e ".[][\"state\"] == \"$state\"" &> /dev/null
+}
+
 ################################################################################
 # Setup
 
@@ -259,6 +269,7 @@ backup_port()
        log_test $? 0 "No forwarding out of vx0"
 
        run_cmd "ip -n $sw1 link set dev swp1 carrier off"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled
        log_test $? 0 "swp1 carrier off"
 
        run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
@@ -268,6 +279,7 @@ backup_port()
        log_test $? 0 "No forwarding out of vx0"
 
        run_cmd "ip -n $sw1 link set dev swp1 carrier on"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding
        log_test $? 0 "swp1 carrier on"
 
        # Configure vx0 as the backup port of swp1 and check that packets are
@@ -284,6 +296,7 @@ backup_port()
        log_test $? 0 "No forwarding out of vx0"
 
        run_cmd "ip -n $sw1 link set dev swp1 carrier off"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled
        log_test $? 0 "swp1 carrier off"
 
        run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
@@ -293,6 +306,7 @@ backup_port()
        log_test $? 0 "Forwarding out of vx0"
 
        run_cmd "ip -n $sw1 link set dev swp1 carrier on"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding
        log_test $? 0 "swp1 carrier on"
 
        run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
@@ -314,6 +328,7 @@ backup_port()
        log_test $? 0 "No forwarding out of vx0"
 
        run_cmd "ip -n $sw1 link set dev swp1 carrier off"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled
        log_test $? 0 "swp1 carrier off"
 
        run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
@@ -369,6 +384,7 @@ backup_nhid()
        log_test $? 0 "No forwarding out of vx0"
 
        run_cmd "ip -n $sw1 link set dev swp1 carrier off"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled
        log_test $? 0 "swp1 carrier off"
 
        run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
@@ -382,6 +398,7 @@ backup_nhid()
        log_test $? 0 "Forwarding using VXLAN FDB entry"
 
        run_cmd "ip -n $sw1 link set dev swp1 carrier on"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding
        log_test $? 0 "swp1 carrier on"
 
        # Configure nexthop ID 10 as the backup nexthop ID of swp1 and check
@@ -398,6 +415,7 @@ backup_nhid()
        log_test $? 0 "No forwarding out of vx0"
 
        run_cmd "ip -n $sw1 link set dev swp1 carrier off"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled
        log_test $? 0 "swp1 carrier off"
 
        run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
@@ -411,6 +429,7 @@ backup_nhid()
        log_test $? 0 "No forwarding using VXLAN FDB entry"
 
        run_cmd "ip -n $sw1 link set dev swp1 carrier on"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding
        log_test $? 0 "swp1 carrier on"
 
        run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
@@ -441,6 +460,7 @@ backup_nhid()
        log_test $? 0 "No forwarding using VXLAN FDB entry"
 
        run_cmd "ip -n $sw1 link set dev swp1 carrier off"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled
        log_test $? 0 "swp1 carrier off"
 
        run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
@@ -497,6 +517,7 @@ backup_nhid_invalid()
        log_test $? 0 "Valid nexthop as backup nexthop"
 
        run_cmd "ip -n $sw1 link set dev swp1 carrier off"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled
        log_test $? 0 "swp1 carrier off"
 
        run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
@@ -604,7 +625,9 @@ backup_nhid_ping()
        run_cmd "bridge -n $sw2 link set dev swp1 backup_nhid 10"
 
        run_cmd "ip -n $sw1 link set dev swp1 carrier off"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled
        run_cmd "ip -n $sw2 link set dev swp1 carrier off"
+       busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw2 swp1 disabled
 
        run_cmd "ip netns exec $sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66"
        log_test $? 0 "Ping with backup nexthop ID"
index 7799e042a9719cda33ea7d004d2ae4a2ec608a4f..b95c249f81c254dae9160b42ec595b3d2daf6679 100644 (file)
@@ -1002,12 +1002,12 @@ TEST_F(tls, recv_partial)
 
        memset(recv_mem, 0, sizeof(recv_mem));
        EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
-       EXPECT_NE(recv(self->cfd, recv_mem, strlen(test_str_first),
-                      MSG_WAITALL), -1);
+       EXPECT_EQ(recv(self->cfd, recv_mem, strlen(test_str_first),
+                      MSG_WAITALL), strlen(test_str_first));
        EXPECT_EQ(memcmp(test_str_first, recv_mem, strlen(test_str_first)), 0);
        memset(recv_mem, 0, sizeof(recv_mem));
-       EXPECT_NE(recv(self->cfd, recv_mem, strlen(test_str_second),
-                      MSG_WAITALL), -1);
+       EXPECT_EQ(recv(self->cfd, recv_mem, strlen(test_str_second),
+                      MSG_WAITALL), strlen(test_str_second));
        EXPECT_EQ(memcmp(test_str_second, recv_mem, strlen(test_str_second)),
                  0);
 }
@@ -1485,6 +1485,51 @@ TEST_F(tls, control_msg)
        EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
 }
 
+TEST_F(tls, control_msg_nomerge)
+{
+       char *rec1 = "1111";
+       char *rec2 = "2222";
+       int send_len = 5;
+       char buf[15];
+
+       if (self->notls)
+               SKIP(return, "no TLS support");
+
+       EXPECT_EQ(tls_send_cmsg(self->fd, 100, rec1, send_len, 0), send_len);
+       EXPECT_EQ(tls_send_cmsg(self->fd, 100, rec2, send_len, 0), send_len);
+
+       EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, 100, buf, sizeof(buf), MSG_PEEK), send_len);
+       EXPECT_EQ(memcmp(buf, rec1, send_len), 0);
+
+       EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, 100, buf, sizeof(buf), MSG_PEEK), send_len);
+       EXPECT_EQ(memcmp(buf, rec1, send_len), 0);
+
+       EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, 100, buf, sizeof(buf), 0), send_len);
+       EXPECT_EQ(memcmp(buf, rec1, send_len), 0);
+
+       EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, 100, buf, sizeof(buf), 0), send_len);
+       EXPECT_EQ(memcmp(buf, rec2, send_len), 0);
+}
+
+TEST_F(tls, data_control_data)
+{
+       char *rec1 = "1111";
+       char *rec2 = "2222";
+       char *rec3 = "3333";
+       int send_len = 5;
+       char buf[15];
+
+       if (self->notls)
+               SKIP(return, "no TLS support");
+
+       EXPECT_EQ(send(self->fd, rec1, send_len, 0), send_len);
+       EXPECT_EQ(tls_send_cmsg(self->fd, 100, rec2, send_len, 0), send_len);
+       EXPECT_EQ(send(self->fd, rec3, send_len, 0), send_len);
+
+       EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_PEEK), send_len);
+       EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_PEEK), send_len);
+}
+
 TEST_F(tls, shutdown)
 {
        char const *test_str = "test_read";
@@ -1874,13 +1919,13 @@ TEST_F(tls_err, poll_partial_rec_async)
                /* Child should sleep in poll(), never get a wake */
                pfd.fd = self->cfd2;
                pfd.events = POLLIN;
-               EXPECT_EQ(poll(&pfd, 1, 5), 0);
+               EXPECT_EQ(poll(&pfd, 1, 20), 0);
 
                EXPECT_EQ(write(p[1], &token, 1), 1); /* Barrier #1 */
 
                pfd.fd = self->cfd2;
                pfd.events = POLLIN;
-               EXPECT_EQ(poll(&pfd, 1, 5), 1);
+               EXPECT_EQ(poll(&pfd, 1, 20), 1);
 
                exit(!_metadata->passed);
        }
index 27574bbf2d6386f770673b82684edf07b586c79a..5ae85def07395b50c07600f4a31b7ff69578bb9f 100755 (executable)
@@ -246,6 +246,20 @@ ip netns exec $NS_DST ethtool -K veth$DST rx-udp-gro-forwarding on
 chk_gro "        - aggregation with TSO off" 1
 cleanup
 
+create_ns
+ip -n $NS_DST link set dev veth$DST up
+ip -n $NS_DST link set dev veth$DST xdp object ${BPF_FILE} section xdp
+chk_gro_flag "gro vs xdp while down - gro flag on" $DST on
+ip -n $NS_DST link set dev veth$DST down
+chk_gro_flag "                      - after down" $DST on
+ip -n $NS_DST link set dev veth$DST xdp off
+chk_gro_flag "                      - after xdp off" $DST off
+ip -n $NS_DST link set dev veth$DST up
+chk_gro_flag "                      - after up" $DST off
+ip -n $NS_SRC link set dev veth$SRC xdp object ${BPF_FILE} section xdp
+chk_gro_flag "                      - after peer xdp" $DST off
+cleanup
+
 create_ns
 chk_channels "default channels" $DST 1 1
 
index db27153eb4a02c1db3f0f9dc55445558fbb5d5ea..936c3085bb8373ea74036a6870cb67f5b103f0ae 100644 (file)
@@ -7,7 +7,8 @@ TEST_PROGS := nft_trans_stress.sh nft_fib.sh nft_nat.sh bridge_brouter.sh \
        nft_queue.sh nft_meta.sh nf_nat_edemux.sh \
        ipip-conntrack-mtu.sh conntrack_tcp_unreplied.sh \
        conntrack_vrf.sh nft_synproxy.sh rpath.sh nft_audit.sh \
-       conntrack_sctp_collision.sh xt_string.sh
+       conntrack_sctp_collision.sh xt_string.sh \
+       bridge_netfilter.sh
 
 HOSTPKG_CONFIG := pkg-config
 
diff --git a/tools/testing/selftests/netfilter/bridge_netfilter.sh b/tools/testing/selftests/netfilter/bridge_netfilter.sh
new file mode 100644 (file)
index 0000000..659b3ab
--- /dev/null
@@ -0,0 +1,188 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Test bridge netfilter + conntrack, a combination that doesn't really work,
+# with multicast/broadcast packets racing for hash table insertion.
+
+#           eth0    br0     eth0
+# setup is: ns1 <->,ns0 <-> ns3
+#           ns2 <-'    `'-> ns4
+
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+ret=0
+
+sfx=$(mktemp -u "XXXXXXXX")
+ns0="ns0-$sfx"
+ns1="ns1-$sfx"
+ns2="ns2-$sfx"
+ns3="ns3-$sfx"
+ns4="ns4-$sfx"
+
+ebtables -V > /dev/null 2>&1
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not run test without ebtables"
+       exit $ksft_skip
+fi
+
+ip -Version > /dev/null 2>&1
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not run test without ip tool"
+       exit $ksft_skip
+fi
+
+for i in $(seq 0 4); do
+  eval ip netns add \$ns$i
+done
+
+cleanup() {
+  for i in $(seq 0 4); do eval ip netns del \$ns$i;done
+}
+
+trap cleanup EXIT
+
+do_ping()
+{
+       fromns="$1"
+       dstip="$2"
+
+       ip netns exec $fromns ping -c 1 -q $dstip > /dev/null
+       if [ $? -ne 0 ]; then
+               echo "ERROR: ping from $fromns to $dstip"
+               ip netns exec ${ns0} nft list ruleset
+               ret=1
+       fi
+}
+
+bcast_ping()
+{
+       fromns="$1"
+       dstip="$2"
+
+       for i in $(seq 1 1000); do
+               ip netns exec $fromns ping -q -f -b -c 1 -q $dstip > /dev/null 2>&1
+               if [ $? -ne 0 ]; then
+                       echo "ERROR: ping -b from $fromns to $dstip"
+                       ip netns exec ${ns0} nft list ruleset
+                       fi
+       done
+}
+
+ip link add veth1 netns ${ns0} type veth peer name eth0 netns ${ns1}
+if [ $? -ne 0 ]; then
+       echo "SKIP: Can't create veth device"
+       exit $ksft_skip
+fi
+
+ip link add veth2 netns ${ns0} type veth peer name eth0 netns $ns2
+ip link add veth3 netns ${ns0} type veth peer name eth0 netns $ns3
+ip link add veth4 netns ${ns0} type veth peer name eth0 netns $ns4
+
+ip -net ${ns0} link set lo up
+
+for i in $(seq 1 4); do
+  ip -net ${ns0} link set veth$i up
+done
+
+ip -net ${ns0} link add br0 type bridge stp_state 0 forward_delay 0 nf_call_iptables 1 nf_call_ip6tables 1 nf_call_arptables 1
+if [ $? -ne 0 ]; then
+       echo "SKIP: Can't create bridge br0"
+       exit $ksft_skip
+fi
+
+# make veth0,1,2 part of bridge.
+for i in $(seq 1 3); do
+  ip -net ${ns0} link set veth$i master br0
+done
+
+# add a macvlan on top of the bridge.
+MACVLAN_ADDR=ba:f3:13:37:42:23
+ip -net ${ns0} link add link br0 name macvlan0 type macvlan mode private
+ip -net ${ns0} link set macvlan0 address ${MACVLAN_ADDR}
+ip -net ${ns0} link set macvlan0 up
+ip -net ${ns0} addr add 10.23.0.1/24 dev macvlan0
+
+# add a macvlan on top of veth4.
+MACVLAN_ADDR=ba:f3:13:37:42:24
+ip -net ${ns0} link add link veth4 name macvlan4 type macvlan mode vepa
+ip -net ${ns0} link set macvlan4 address ${MACVLAN_ADDR}
+ip -net ${ns0} link set macvlan4 up
+
+# make the macvlan part of the bridge.
+# veth4 is not a bridge port, only the macvlan on top of it.
+ip -net ${ns0} link set macvlan4 master br0
+
+ip -net ${ns0} link set br0 up
+ip -net ${ns0} addr add 10.0.0.1/24 dev br0
+ip netns exec ${ns0} sysctl -q net.bridge.bridge-nf-call-iptables=1
+ret=$?
+if [ $ret -ne 0 ] ; then
+       echo "SKIP: bridge netfilter not available"
+       ret=$ksft_skip
+fi
+
+# for testing, so namespaces will reply to ping -b probes.
+ip netns exec ${ns0} sysctl -q net.ipv4.icmp_echo_ignore_broadcasts=0
+
+# enable conntrack in ns0 and drop broadcast packets in forward to
+# avoid them from getting confirmed in the postrouting hook before
+# the cloned skb is passed up the stack.
+ip netns exec ${ns0} nft -f - <<EOF
+table ip filter {
+       chain input {
+               type filter hook input priority 1; policy accept
+               iifname br0 counter
+               ct state new accept
+       }
+}
+
+table bridge filter {
+       chain forward {
+               type filter hook forward priority 0; policy accept
+               meta pkttype broadcast ip protocol icmp counter drop
+       }
+}
+EOF
+
+# place 1, 2 & 3 in same subnet, connected via ns0:br0.
+# ns4 is placed in same subnet as well, but its not
+# part of the bridge: the corresponding veth4 is not
+# part of the bridge, only its macvlan interface.
+for i in $(seq 1 4); do
+  eval ip -net \$ns$i link set lo up
+  eval ip -net \$ns$i link set eth0 up
+done
+for i in $(seq 1 2); do
+  eval ip -net \$ns$i addr add 10.0.0.1$i/24 dev eth0
+done
+
+ip -net ${ns3} addr add 10.23.0.13/24 dev eth0
+ip -net ${ns4} addr add 10.23.0.14/24 dev eth0
+
+# test basic connectivity
+do_ping ${ns1} 10.0.0.12
+do_ping ${ns3} 10.23.0.1
+do_ping ${ns4} 10.23.0.1
+
+if [ $ret -eq 0 ];then
+       echo "PASS: netns connectivity: ns1 can reach ns2, ns3 and ns4 can reach ns0"
+fi
+
+bcast_ping ${ns1} 10.0.0.255
+
+# This should deliver broadcast to macvlan0, which is on top of ns0:br0.
+bcast_ping ${ns3} 10.23.0.255
+
+# same, this time via veth4:macvlan4.
+bcast_ping ${ns4} 10.23.0.255
+
+read t < /proc/sys/kernel/tainted
+
+if [ $t -eq 0 ];then
+       echo PASS: kernel not tainted
+else
+       echo ERROR: kernel is tainted
+       ret=1
+fi
+
+exit $ret
index 0930e2411dfb9a1337988e4cb815e14bfa4464b5..cd51d547b751db39547d4e25b8db44f25dd23780 100644 (file)
@@ -5,6 +5,7 @@
 #include <fcntl.h>
 #include <limits.h>
 #include <linux/types.h>
+#include <poll.h>
 #include <sched.h>
 #include <signal.h>
 #include <stdio.h>
@@ -129,6 +130,7 @@ FIXTURE(child)
         * When it is closed, the child will exit.
         */
        int sk;
+       bool ignore_child_result;
 };
 
 FIXTURE_SETUP(child)
@@ -165,10 +167,14 @@ FIXTURE_SETUP(child)
 
 FIXTURE_TEARDOWN(child)
 {
+       int ret;
+
        EXPECT_EQ(0, close(self->pidfd));
        EXPECT_EQ(0, close(self->sk));
 
-       EXPECT_EQ(0, wait_for_pid(self->pid));
+       ret = wait_for_pid(self->pid);
+       if (!self->ignore_child_result)
+               EXPECT_EQ(0, ret);
 }
 
 TEST_F(child, disable_ptrace)
@@ -235,6 +241,29 @@ TEST(flags_set)
        EXPECT_EQ(errno, EINVAL);
 }
 
+TEST_F(child, no_strange_EBADF)
+{
+       struct pollfd fds;
+
+       self->ignore_child_result = true;
+
+       fds.fd = self->pidfd;
+       fds.events = POLLIN;
+
+       ASSERT_EQ(kill(self->pid, SIGKILL), 0);
+       ASSERT_EQ(poll(&fds, 1, 5000), 1);
+
+       /*
+        * It used to be that pidfd_getfd() could race with the exiting thread
+        * between exit_files() and release_task(), and get a non-null task
+        * with a NULL files struct, and you'd get EBADF, which was slightly
+        * confusing.
+        */
+       errno = 0;
+       EXPECT_EQ(sys_pidfd_getfd(self->pidfd, self->remote_fd, 0), -1);
+       EXPECT_EQ(errno, ESRCH);
+}
+
 #if __NR_pidfd_getfd == -1
 int main(void)
 {
diff --git a/tools/testing/selftests/power_supply/Makefile b/tools/testing/selftests/power_supply/Makefile
new file mode 100644 (file)
index 0000000..44f0658
--- /dev/null
@@ -0,0 +1,4 @@
+TEST_PROGS := test_power_supply_properties.sh
+TEST_FILES := helpers.sh
+
+include ../lib.mk
diff --git a/tools/testing/selftests/power_supply/helpers.sh b/tools/testing/selftests/power_supply/helpers.sh
new file mode 100644 (file)
index 0000000..1ec90d7
--- /dev/null
@@ -0,0 +1,178 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2022, 2024 Collabora Ltd
+SYSFS_SUPPLIES=/sys/class/power_supply
+
+calc() {
+       awk "BEGIN { print $* }";
+}
+
+test_sysfs_prop() {
+       PROP="$1"
+       VALUE="$2" # optional
+
+       PROP_PATH="$SYSFS_SUPPLIES"/"$DEVNAME"/"$PROP"
+       TEST_NAME="$DEVNAME".sysfs."$PROP"
+
+       if [ -z "$VALUE" ]; then
+               ktap_test_result "$TEST_NAME" [ -f "$PROP_PATH" ]
+       else
+               ktap_test_result "$TEST_NAME" grep -q "$VALUE" "$PROP_PATH"
+       fi
+}
+
+to_human_readable_unit() {
+       VALUE="$1"
+       UNIT="$2"
+
+       case "$VALUE" in
+               *[!0-9]* ) return ;; # Not a number
+       esac
+
+       if [ "$UNIT" = "uA" ]; then
+               new_unit="mA"
+               div=1000
+       elif [ "$UNIT" = "uV" ]; then
+               new_unit="V"
+               div=1000000
+       elif [ "$UNIT" = "uAh" ]; then
+               new_unit="Ah"
+               div=1000000
+       elif [ "$UNIT" = "uW" ]; then
+               new_unit="mW"
+               div=1000
+       elif [ "$UNIT" = "uWh" ]; then
+               new_unit="Wh"
+               div=1000000
+       else
+               return
+       fi
+
+       value_converted=$(calc "$VALUE"/"$div")
+       echo "$value_converted" "$new_unit"
+}
+
+_check_sysfs_prop_available() {
+       PROP=$1
+
+       PROP_PATH="$SYSFS_SUPPLIES"/"$DEVNAME"/"$PROP"
+       TEST_NAME="$DEVNAME".sysfs."$PROP"
+
+       if [ ! -e "$PROP_PATH" ] ; then
+               ktap_test_skip "$TEST_NAME"
+               return 1
+       fi
+
+       if ! cat "$PROP_PATH" >/dev/null; then
+               ktap_print_msg "Failed to read"
+               ktap_test_fail "$TEST_NAME"
+               return 1
+       fi
+
+       return 0
+}
+
+test_sysfs_prop_optional() {
+       PROP=$1
+       UNIT=$2 # optional
+
+       TEST_NAME="$DEVNAME".sysfs."$PROP"
+
+       _check_sysfs_prop_available "$PROP" || return
+       DATA=$(cat "$SYSFS_SUPPLIES"/"$DEVNAME"/"$PROP")
+
+       ktap_print_msg "Reported: '$DATA' $UNIT ($(to_human_readable_unit "$DATA" "$UNIT"))"
+       ktap_test_pass "$TEST_NAME"
+}
+
+test_sysfs_prop_optional_range() {
+       PROP=$1
+       MIN=$2
+       MAX=$3
+       UNIT=$4 # optional
+
+       TEST_NAME="$DEVNAME".sysfs."$PROP"
+
+       _check_sysfs_prop_available "$PROP" || return
+       DATA=$(cat "$SYSFS_SUPPLIES"/"$DEVNAME"/"$PROP")
+
+       if [ "$DATA" -lt "$MIN" ] || [ "$DATA" -gt "$MAX" ]; then
+               ktap_print_msg "'$DATA' is out of range (min=$MIN, max=$MAX)"
+               ktap_test_fail "$TEST_NAME"
+       else
+               ktap_print_msg "Reported: '$DATA' $UNIT ($(to_human_readable_unit "$DATA" "$UNIT"))"
+               ktap_test_pass "$TEST_NAME"
+       fi
+}
+
+test_sysfs_prop_optional_list() {
+       PROP=$1
+       LIST=$2
+
+       TEST_NAME="$DEVNAME".sysfs."$PROP"
+
+       _check_sysfs_prop_available "$PROP" || return
+       DATA=$(cat "$SYSFS_SUPPLIES"/"$DEVNAME"/"$PROP")
+
+       valid=0
+
+       OLDIFS=$IFS
+       IFS=","
+       for item in $LIST; do
+               if [ "$DATA" = "$item" ]; then
+                       valid=1
+                       break
+               fi
+       done
+       if [ "$valid" -eq 1 ]; then
+               ktap_print_msg "Reported: '$DATA'"
+               ktap_test_pass "$TEST_NAME"
+       else
+               ktap_print_msg "'$DATA' is not a valid value for this property"
+               ktap_test_fail "$TEST_NAME"
+       fi
+       IFS=$OLDIFS
+}
+
+dump_file() {
+       FILE="$1"
+       while read -r line; do
+               ktap_print_msg "$line"
+       done < "$FILE"
+}
+
+__test_uevent_prop() {
+       PROP="$1"
+       OPTIONAL="$2"
+       VALUE="$3" # optional
+
+       UEVENT_PATH="$SYSFS_SUPPLIES"/"$DEVNAME"/uevent
+       TEST_NAME="$DEVNAME".uevent."$PROP"
+
+       if ! grep -q "POWER_SUPPLY_$PROP=" "$UEVENT_PATH"; then
+               if [ "$OPTIONAL" -eq 1 ]; then
+                       ktap_test_skip "$TEST_NAME"
+               else
+                       ktap_print_msg "Missing property"
+                       ktap_test_fail "$TEST_NAME"
+               fi
+               return
+       fi
+
+       if ! grep -q "POWER_SUPPLY_$PROP=$VALUE" "$UEVENT_PATH"; then
+               ktap_print_msg "Invalid value for uevent property, dumping..."
+               dump_file "$UEVENT_PATH"
+               ktap_test_fail "$TEST_NAME"
+       else
+               ktap_test_pass "$TEST_NAME"
+       fi
+}
+
+test_uevent_prop() {
+       __test_uevent_prop "$1" 0 "$2"
+}
+
+test_uevent_prop_optional() {
+       __test_uevent_prop "$1" 1 "$2"
+}
diff --git a/tools/testing/selftests/power_supply/test_power_supply_properties.sh b/tools/testing/selftests/power_supply/test_power_supply_properties.sh
new file mode 100755 (executable)
index 0000000..df272df
--- /dev/null
@@ -0,0 +1,114 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2022, 2024 Collabora Ltd
+#
+# This test validates the power supply uAPI: namely, the files in sysfs and
+# lines in uevent that expose the power supply properties.
+#
+# By default all power supplies available are tested. Optionally the name of a
+# power supply can be passed as a parameter to test only that one instead.
+DIR="$(dirname "$(readlink -f "$0")")"
+
+. "${DIR}"/../kselftest/ktap_helpers.sh
+
+. "${DIR}"/helpers.sh
+
+count_tests() {
+       SUPPLIES=$1
+
+       # This needs to be updated every time a new test is added.
+       NUM_TESTS=33
+
+       total_tests=0
+
+       for i in $SUPPLIES; do
+               total_tests=$(("$total_tests" + "$NUM_TESTS"))
+       done
+
+       echo "$total_tests"
+}
+
+ktap_print_header
+
+SYSFS_SUPPLIES=/sys/class/power_supply/
+
+if [ $# -eq 0 ]; then
+       supplies=$(ls "$SYSFS_SUPPLIES")
+else
+       supplies=$1
+fi
+
+ktap_set_plan "$(count_tests "$supplies")"
+
+for DEVNAME in $supplies; do
+       ktap_print_msg Testing device "$DEVNAME"
+
+       if [ ! -d "$SYSFS_SUPPLIES"/"$DEVNAME" ]; then
+               ktap_test_fail "$DEVNAME".exists
+               ktap_exit_fail_msg Device does not exist
+       fi
+
+       ktap_test_pass "$DEVNAME".exists
+
+       test_uevent_prop NAME "$DEVNAME"
+
+       test_sysfs_prop type
+       SUPPLY_TYPE=$(cat "$SYSFS_SUPPLIES"/"$DEVNAME"/type)
+       # This fails on kernels < 5.8 (needs 2ad3d74e3c69f)
+       test_uevent_prop TYPE "$SUPPLY_TYPE"
+
+       test_sysfs_prop_optional usb_type
+
+       test_sysfs_prop_optional_range online 0 2
+       test_sysfs_prop_optional_range present 0 1
+
+       test_sysfs_prop_optional_list status "Unknown","Charging","Discharging","Not charging","Full"
+
+       # Capacity is reported as percentage, thus any value less than 0 and
+       # greater than 100 are not allowed.
+       test_sysfs_prop_optional_range capacity 0 100 "%"
+
+       test_sysfs_prop_optional_list capacity_level "Unknown","Critical","Low","Normal","High","Full"
+
+       test_sysfs_prop_optional model_name
+       test_sysfs_prop_optional manufacturer
+       test_sysfs_prop_optional serial_number
+       test_sysfs_prop_optional_list technology "Unknown","NiMH","Li-ion","Li-poly","LiFe","NiCd","LiMn"
+
+       test_sysfs_prop_optional cycle_count
+
+       test_sysfs_prop_optional_list scope "Unknown","System","Device"
+
+       test_sysfs_prop_optional input_current_limit "uA"
+       test_sysfs_prop_optional input_voltage_limit "uV"
+
+       # Technically the power-supply class does not limit reported values.
+       # E.g. one could expose an RTC backup-battery, which goes below 1.5V or
+       # an electric vehicle battery with over 300V. But most devices do not
+       # have a step-up capable regulator behind the battery and operate with
+       # voltages considered safe to touch, so we limit the allowed range to
+       # 1.8V-60V to catch drivers reporting incorrectly scaled values. E.g. a
+       # common mistake is reporting data in mV instead of µV.
+       test_sysfs_prop_optional_range voltage_now 1800000 60000000 "uV"
+       test_sysfs_prop_optional_range voltage_min 1800000 60000000 "uV"
+       test_sysfs_prop_optional_range voltage_max 1800000 60000000 "uV"
+       test_sysfs_prop_optional_range voltage_min_design 1800000 60000000 "uV"
+       test_sysfs_prop_optional_range voltage_max_design 1800000 60000000 "uV"
+
+       # current based systems
+       test_sysfs_prop_optional current_now "uA"
+       test_sysfs_prop_optional current_max "uA"
+       test_sysfs_prop_optional charge_now "uAh"
+       test_sysfs_prop_optional charge_full "uAh"
+       test_sysfs_prop_optional charge_full_design "uAh"
+
+       # power based systems
+       test_sysfs_prop_optional power_now "uW"
+       test_sysfs_prop_optional energy_now "uWh"
+       test_sysfs_prop_optional energy_full "uWh"
+       test_sysfs_prop_optional energy_full_design "uWh"
+       test_sysfs_prop_optional energy_full_design "uWh"
+done
+
+ktap_finished
index 7b1addd504209fadb59f908a843b23a9d0218f3f..8a64f63e37ce215e4aeff2675b7114704075ae48 100644 (file)
@@ -18,6 +18,7 @@
 #include <pthread.h>
 
 #include "utils.h"
+#include "fpu.h"
 
 /* Number of times each thread should receive the signal */
 #define ITERATIONS 10
@@ -27,9 +28,7 @@
  */
 #define THREAD_FACTOR 8
 
-__thread double darray[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
-                    1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0,
-                    2.1};
+__thread double darray[32];
 
 bool bad_context;
 int threads_starting;
@@ -43,9 +42,9 @@ void signal_fpu_sig(int sig, siginfo_t *info, void *context)
        ucontext_t *uc = context;
        mcontext_t *mc = &uc->uc_mcontext;
 
-       /* Only the non volatiles were loaded up */
-       for (i = 14; i < 32; i++) {
-               if (mc->fp_regs[i] != darray[i - 14]) {
+       // Don't check f30/f31, they're used as scratches in check_all_fprs()
+       for (i = 0; i < 30; i++) {
+               if (mc->fp_regs[i] != darray[i]) {
                        bad_context = true;
                        break;
                }
@@ -54,7 +53,6 @@ void signal_fpu_sig(int sig, siginfo_t *info, void *context)
 
 void *signal_fpu_c(void *p)
 {
-       int i;
        long rc;
        struct sigaction act;
        act.sa_sigaction = signal_fpu_sig;
@@ -64,9 +62,7 @@ void *signal_fpu_c(void *p)
                return p;
 
        srand(pthread_self());
-       for (i = 0; i < 21; i++)
-               darray[i] = rand();
-
+       randomise_darray(darray, ARRAY_SIZE(darray));
        rc = preempt_fpu(darray, &threads_starting, &running);
 
        return (void *) rc;
index 98cbb9109ee6e8e1e6047c1640c8cb0f4a2b5625..505294da1b9fb5e7bd07aac4a119164900c8f2e6 100644 (file)
@@ -263,10 +263,10 @@ static int papr_vpd_system_loc_code(void)
        off_t size;
        int fd;
 
-       SKIP_IF_MSG(get_system_loc_code(&lc),
-                   "Cannot determine system location code");
        SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
                    DEVPATH " not present");
+       SKIP_IF_MSG(get_system_loc_code(&lc),
+                   "Cannot determine system location code");
 
        FAIL_IF(devfd < 0);
 
index d5a0d8a33c27bae242e8eb3f4e23ef67a576f24d..bbac5f4b03d04bfbda25da59a175cb09ca2f6fd2 100755 (executable)
@@ -567,7 +567,7 @@ then
        torture_bootargs="rcupdate.rcu_cpu_stall_suppress_at_boot=1 torture.disable_onoff_at_boot rcupdate.rcu_task_stall_timeout=30000 tsc=watchdog"
        torture_set "clocksourcewd-1" tools/testing/selftests/rcutorture/bin/kvm.sh --allcpus --duration 45s --configs TREE03 --kconfig "CONFIG_TEST_CLOCKSOURCE_WATCHDOG=y" --trust-make
 
-       torture_bootargs="rcupdate.rcu_cpu_stall_suppress_at_boot=1 torture.disable_onoff_at_boot rcupdate.rcu_task_stall_timeout=30000 clocksource.max_cswd_read_retries=1 tsc=watchdog"
+       torture_bootargs="rcupdate.rcu_cpu_stall_suppress_at_boot=1 torture.disable_onoff_at_boot rcupdate.rcu_task_stall_timeout=30000 tsc=watchdog"
        torture_set "clocksourcewd-2" tools/testing/selftests/rcutorture/bin/kvm.sh --allcpus --duration 45s --configs TREE03 --kconfig "CONFIG_TEST_CLOCKSOURCE_WATCHDOG=y" --trust-make
 
        # In case our work is already done...
index bcbca356d56a8d7ddd449af2bc0b01a69e960624..1b339d6bbff1c945fdcfac6acafd908ae1bd96c8 100644 (file)
 #include <stdint.h>
 #include "resctrl.h"
 
-struct read_format {
-       __u64 nr;                       /* The number of events */
-       struct {
-               __u64 value;            /* The value of the event */
-       } values[2];
-};
-
-static struct perf_event_attr pea_llc_miss;
-static struct read_format rf_cqm;
-static int fd_lm;
 char llc_occup_path[1024];
 
-static void initialize_perf_event_attr(void)
+void perf_event_attr_initialize(struct perf_event_attr *pea, __u64 config)
 {
-       pea_llc_miss.type = PERF_TYPE_HARDWARE;
-       pea_llc_miss.size = sizeof(struct perf_event_attr);
-       pea_llc_miss.read_format = PERF_FORMAT_GROUP;
-       pea_llc_miss.exclude_kernel = 1;
-       pea_llc_miss.exclude_hv = 1;
-       pea_llc_miss.exclude_idle = 1;
-       pea_llc_miss.exclude_callchain_kernel = 1;
-       pea_llc_miss.inherit = 1;
-       pea_llc_miss.exclude_guest = 1;
-       pea_llc_miss.disabled = 1;
-}
-
-static void ioctl_perf_event_ioc_reset_enable(void)
-{
-       ioctl(fd_lm, PERF_EVENT_IOC_RESET, 0);
-       ioctl(fd_lm, PERF_EVENT_IOC_ENABLE, 0);
-}
-
-static int perf_event_open_llc_miss(pid_t pid, int cpu_no)
-{
-       fd_lm = perf_event_open(&pea_llc_miss, pid, cpu_no, -1,
-                               PERF_FLAG_FD_CLOEXEC);
-       if (fd_lm == -1) {
-               perror("Error opening leader");
-               ctrlc_handler(0, NULL, NULL);
-               return -1;
-       }
-
-       return 0;
-}
-
-static void initialize_llc_perf(void)
-{
-       memset(&pea_llc_miss, 0, sizeof(struct perf_event_attr));
-       memset(&rf_cqm, 0, sizeof(struct read_format));
-
-       /* Initialize perf_event_attr structures for HW_CACHE_MISSES */
-       initialize_perf_event_attr();
-
-       pea_llc_miss.config = PERF_COUNT_HW_CACHE_MISSES;
-
-       rf_cqm.nr = 1;
+       memset(pea, 0, sizeof(*pea));
+       pea->type = PERF_TYPE_HARDWARE;
+       pea->size = sizeof(*pea);
+       pea->read_format = PERF_FORMAT_GROUP;
+       pea->exclude_kernel = 1;
+       pea->exclude_hv = 1;
+       pea->exclude_idle = 1;
+       pea->exclude_callchain_kernel = 1;
+       pea->inherit = 1;
+       pea->exclude_guest = 1;
+       pea->disabled = 1;
+       pea->config = config;
 }
 
-static int reset_enable_llc_perf(pid_t pid, int cpu_no)
+/* Start counters to log values */
+int perf_event_reset_enable(int pe_fd)
 {
-       int ret = 0;
+       int ret;
 
-       ret = perf_event_open_llc_miss(pid, cpu_no);
+       ret = ioctl(pe_fd, PERF_EVENT_IOC_RESET, 0);
        if (ret < 0)
                return ret;
 
-       /* Start counters to log values */
-       ioctl_perf_event_ioc_reset_enable();
+       ret = ioctl(pe_fd, PERF_EVENT_IOC_ENABLE, 0);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
 
-/*
- * get_llc_perf:       llc cache miss through perf events
- * @llc_perf_miss:     LLC miss counter that is filled on success
- *
- * Perf events like HW_CACHE_MISSES could be used to validate number of
- * cache lines allocated.
- *
- * Return: =0 on success.  <0 on failure.
- */
-static int get_llc_perf(unsigned long *llc_perf_miss)
+void perf_event_initialize_read_format(struct perf_event_read *pe_read)
 {
-       __u64 total_misses;
-       int ret;
-
-       /* Stop counters after one span to get miss rate */
+       memset(pe_read, 0, sizeof(*pe_read));
+       pe_read->nr = 1;
+}
 
-       ioctl(fd_lm, PERF_EVENT_IOC_DISABLE, 0);
+int perf_open(struct perf_event_attr *pea, pid_t pid, int cpu_no)
+{
+       int pe_fd;
 
-       ret = read(fd_lm, &rf_cqm, sizeof(struct read_format));
-       if (ret == -1) {
-               perror("Could not get llc misses through perf");
+       pe_fd = perf_event_open(pea, pid, cpu_no, -1, PERF_FLAG_FD_CLOEXEC);
+       if (pe_fd == -1) {
+               ksft_perror("Error opening leader");
                return -1;
        }
 
-       total_misses = rf_cqm.values[0].value;
-       *llc_perf_miss = total_misses;
+       perf_event_reset_enable(pe_fd);
 
-       return 0;
+       return pe_fd;
 }
 
 /*
@@ -124,12 +77,12 @@ static int get_llc_occu_resctrl(unsigned long *llc_occupancy)
 
        fp = fopen(llc_occup_path, "r");
        if (!fp) {
-               perror("Failed to open results file");
+               ksft_perror("Failed to open results file");
 
-               return errno;
+               return -1;
        }
        if (fscanf(fp, "%lu", llc_occupancy) <= 0) {
-               perror("Could not get llc occupancy");
+               ksft_perror("Could not get llc occupancy");
                fclose(fp);
 
                return -1;
@@ -146,163 +99,91 @@ static int get_llc_occu_resctrl(unsigned long *llc_occupancy)
  * @llc_value:         perf miss value /
  *                     llc occupancy value reported by resctrl FS
  *
- * Return:             0 on success. non-zero on failure.
+ * Return:             0 on success, < 0 on error.
  */
-static int print_results_cache(char *filename, int bm_pid,
-                              unsigned long llc_value)
+static int print_results_cache(const char *filename, int bm_pid, __u64 llc_value)
 {
        FILE *fp;
 
        if (strcmp(filename, "stdio") == 0 || strcmp(filename, "stderr") == 0) {
-               printf("Pid: %d \t LLC_value: %lu\n", bm_pid,
-                      llc_value);
+               printf("Pid: %d \t LLC_value: %llu\n", bm_pid, llc_value);
        } else {
                fp = fopen(filename, "a");
                if (!fp) {
-                       perror("Cannot open results file");
+                       ksft_perror("Cannot open results file");
 
-                       return errno;
+                       return -1;
                }
-               fprintf(fp, "Pid: %d \t llc_value: %lu\n", bm_pid, llc_value);
+               fprintf(fp, "Pid: %d \t llc_value: %llu\n", bm_pid, llc_value);
                fclose(fp);
        }
 
        return 0;
 }
 
-int measure_cache_vals(struct resctrl_val_param *param, int bm_pid)
+/*
+ * perf_event_measure - Measure perf events
+ * @filename:  Filename for writing the results
+ * @bm_pid:    PID that runs the benchmark
+ *
+ * Measures perf events (e.g., cache misses) and writes the results into
+ * @filename. @bm_pid is written to the results file along with the measured
+ * value.
+ *
+ * Return: =0 on success. <0 on failure.
+ */
+int perf_event_measure(int pe_fd, struct perf_event_read *pe_read,
+                      const char *filename, int bm_pid)
 {
-       unsigned long llc_perf_miss = 0, llc_occu_resc = 0, llc_value = 0;
        int ret;
 
-       /*
-        * Measure cache miss from perf.
-        */
-       if (!strncmp(param->resctrl_val, CAT_STR, sizeof(CAT_STR))) {
-               ret = get_llc_perf(&llc_perf_miss);
-               if (ret < 0)
-                       return ret;
-               llc_value = llc_perf_miss;
-       }
+       /* Stop counters after one span to get miss rate */
+       ret = ioctl(pe_fd, PERF_EVENT_IOC_DISABLE, 0);
+       if (ret < 0)
+               return ret;
 
-       /*
-        * Measure llc occupancy from resctrl.
-        */
-       if (!strncmp(param->resctrl_val, CMT_STR, sizeof(CMT_STR))) {
-               ret = get_llc_occu_resctrl(&llc_occu_resc);
-               if (ret < 0)
-                       return ret;
-               llc_value = llc_occu_resc;
+       ret = read(pe_fd, pe_read, sizeof(*pe_read));
+       if (ret == -1) {
+               ksft_perror("Could not get perf value");
+               return -1;
        }
-       ret = print_results_cache(param->filename, bm_pid, llc_value);
-       if (ret)
-               return ret;
 
-       return 0;
+       return print_results_cache(filename, bm_pid, pe_read->values[0].value);
 }
 
 /*
- * cache_val:          execute benchmark and measure LLC occupancy resctrl
- * and perf cache miss for the benchmark
- * @param:             parameters passed to cache_val()
- * @span:              buffer size for the benchmark
+ * measure_llc_resctrl - Measure resctrl LLC value from resctrl
+ * @filename:  Filename for writing the results
+ * @bm_pid:    PID that runs the benchmark
  *
- * Return:             0 on success. non-zero on failure.
+ * Measures LLC occupancy from resctrl and writes the results into @filename.
+ * @bm_pid is written to the results file along with the measured value.
+ *
+ * Return: =0 on success. <0 on failure.
  */
-int cat_val(struct resctrl_val_param *param, size_t span)
+int measure_llc_resctrl(const char *filename, int bm_pid)
 {
-       int memflush = 1, operation = 0, ret = 0;
-       char *resctrl_val = param->resctrl_val;
-       pid_t bm_pid;
-
-       if (strcmp(param->filename, "") == 0)
-               sprintf(param->filename, "stdio");
-
-       bm_pid = getpid();
-
-       /* Taskset benchmark to specified cpu */
-       ret = taskset_benchmark(bm_pid, param->cpu_no);
-       if (ret)
-               return ret;
+       unsigned long llc_occu_resc = 0;
+       int ret;
 
-       /* Write benchmark to specified con_mon grp, mon_grp in resctrl FS*/
-       ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp,
-                                     resctrl_val);
-       if (ret)
+       ret = get_llc_occu_resctrl(&llc_occu_resc);
+       if (ret < 0)
                return ret;
 
-       initialize_llc_perf();
-
-       /* Test runs until the callback setup() tells the test to stop. */
-       while (1) {
-               ret = param->setup(param);
-               if (ret == END_OF_TESTS) {
-                       ret = 0;
-                       break;
-               }
-               if (ret < 0)
-                       break;
-               ret = reset_enable_llc_perf(bm_pid, param->cpu_no);
-               if (ret)
-                       break;
-
-               if (run_fill_buf(span, memflush, operation, true)) {
-                       fprintf(stderr, "Error-running fill buffer\n");
-                       ret = -1;
-                       goto pe_close;
-               }
-
-               sleep(1);
-               ret = measure_cache_vals(param, bm_pid);
-               if (ret)
-                       goto pe_close;
-       }
-
-       return ret;
-
-pe_close:
-       close(fd_lm);
-       return ret;
+       return print_results_cache(filename, bm_pid, llc_occu_resc);
 }
 
 /*
- * show_cache_info:    show cache test result information
- * @sum_llc_val:       sum of LLC cache result data
- * @no_of_bits:                number of bits
- * @cache_span:                cache span in bytes for CMT or in lines for CAT
- * @max_diff:          max difference
- * @max_diff_percent:  max difference percentage
- * @num_of_runs:       number of runs
- * @platform:          show test information on this platform
- * @cmt:               CMT test or CAT test
- *
- * Return:             0 on success. non-zero on failure.
+ * show_cache_info - Show generic cache test information
+ * @no_of_bits:                Number of bits
+ * @avg_llc_val:       Average of LLC cache result data
+ * @cache_span:                Cache span
+ * @lines:             @cache_span in lines or bytes
  */
-int show_cache_info(unsigned long sum_llc_val, int no_of_bits,
-                   size_t cache_span, unsigned long max_diff,
-                   unsigned long max_diff_percent, unsigned long num_of_runs,
-                   bool platform, bool cmt)
+void show_cache_info(int no_of_bits, __u64 avg_llc_val, size_t cache_span, bool lines)
 {
-       unsigned long avg_llc_val = 0;
-       float diff_percent;
-       long avg_diff = 0;
-       int ret;
-
-       avg_llc_val = sum_llc_val / num_of_runs;
-       avg_diff = (long)abs(cache_span - avg_llc_val);
-       diff_percent = ((float)cache_span - avg_llc_val) / cache_span * 100;
-
-       ret = platform && abs((int)diff_percent) > max_diff_percent &&
-             (cmt ? (abs(avg_diff) > max_diff) : true);
-
-       ksft_print_msg("%s Check cache miss rate within %lu%%\n",
-                      ret ? "Fail:" : "Pass:", max_diff_percent);
-
-       ksft_print_msg("Percent diff=%d\n", abs((int)diff_percent));
        ksft_print_msg("Number of bits: %d\n", no_of_bits);
-       ksft_print_msg("Average LLC val: %lu\n", avg_llc_val);
-       ksft_print_msg("Cache span (%s): %zu\n", cmt ? "bytes" : "lines",
+       ksft_print_msg("Average LLC val: %llu\n", avg_llc_val);
+       ksft_print_msg("Cache span (%s): %zu\n", lines ? "lines" : "bytes",
                       cache_span);
-
-       return ret;
 }
index 224ba8544d8afc88910b01e77e77a35c8e2cfdc2..4cb991be8e31be37032d9811a070fc68dce27f66 100644 (file)
 #include "resctrl.h"
 #include <unistd.h>
 
-#define RESULT_FILE_NAME1      "result_cat1"
-#define RESULT_FILE_NAME2      "result_cat2"
+#define RESULT_FILE_NAME       "result_cat"
 #define NUM_OF_RUNS            5
-#define MAX_DIFF_PERCENT       4
-#define MAX_DIFF               1000000
 
 /*
- * Change schemata. Write schemata to specified
- * con_mon grp, mon_grp in resctrl FS.
- * Run 5 times in order to get average values.
+ * Minimum difference in LLC misses between a test with n+1 bits CBM to the
+ * test with n bits is MIN_DIFF_PERCENT_PER_BIT * (n - 1). With e.g. 5 vs 4
+ * bits in the CBM mask, the minimum difference must be at least
+ * MIN_DIFF_PERCENT_PER_BIT * (4 - 1) = 3 percent.
+ *
+ * The relationship between number of used CBM bits and difference in LLC
+ * misses is not expected to be linear. With a small number of bits, the
+ * margin is smaller than with larger number of bits. For selftest purposes,
+ * however, linear approach is enough because ultimately only pass/fail
+ * decision has to be made and distinction between strong and stronger
+ * signal is irrelevant.
  */
-static int cat_setup(struct resctrl_val_param *p)
+#define MIN_DIFF_PERCENT_PER_BIT       1UL
+
+static int show_results_info(__u64 sum_llc_val, int no_of_bits,
+                            unsigned long cache_span,
+                            unsigned long min_diff_percent,
+                            unsigned long num_of_runs, bool platform,
+                            __s64 *prev_avg_llc_val)
 {
-       char schemata[64];
+       __u64 avg_llc_val = 0;
+       float avg_diff;
        int ret = 0;
 
-       /* Run NUM_OF_RUNS times */
-       if (p->num_of_runs >= NUM_OF_RUNS)
-               return END_OF_TESTS;
+       avg_llc_val = sum_llc_val / num_of_runs;
+       if (*prev_avg_llc_val) {
+               float delta = (__s64)(avg_llc_val - *prev_avg_llc_val);
+
+               avg_diff = delta / *prev_avg_llc_val;
+               ret = platform && (avg_diff * 100) < (float)min_diff_percent;
+
+               ksft_print_msg("%s Check cache miss rate changed more than %.1f%%\n",
+                              ret ? "Fail:" : "Pass:", (float)min_diff_percent);
 
-       if (p->num_of_runs == 0) {
-               sprintf(schemata, "%lx", p->mask);
-               ret = write_schemata(p->ctrlgrp, schemata, p->cpu_no,
-                                    p->resctrl_val);
+               ksft_print_msg("Percent diff=%.1f\n", avg_diff * 100);
        }
-       p->num_of_runs++;
+       *prev_avg_llc_val = avg_llc_val;
+
+       show_cache_info(no_of_bits, avg_llc_val, cache_span, true);
 
        return ret;
 }
 
-static int check_results(struct resctrl_val_param *param, size_t span)
+/* Remove the highest bit from CBM */
+static unsigned long next_mask(unsigned long current_mask)
+{
+       return current_mask & (current_mask >> 1);
+}
+
+static int check_results(struct resctrl_val_param *param, const char *cache_type,
+                        unsigned long cache_total_size, unsigned long full_cache_mask,
+                        unsigned long current_mask)
 {
        char *token_array[8], temp[512];
-       unsigned long sum_llc_perf_miss = 0;
-       int runs = 0, no_of_bits = 0;
+       __u64 sum_llc_perf_miss = 0;
+       __s64 prev_avg_llc_val = 0;
+       unsigned long alloc_size;
+       int runs = 0;
+       int fail = 0;
+       int ret;
        FILE *fp;
 
        ksft_print_msg("Checking for pass/fail\n");
        fp = fopen(param->filename, "r");
        if (!fp) {
-               perror("# Cannot open file");
+               ksft_perror("Cannot open file");
 
-               return errno;
+               return -1;
        }
 
        while (fgets(temp, sizeof(temp), fp)) {
                char *token = strtok(temp, ":\t");
                int fields = 0;
+               int bits;
 
                while (token) {
                        token_array[fields++] = token;
                        token = strtok(NULL, ":\t");
                }
-               /*
-                * Discard the first value which is inaccurate due to monitoring
-                * setup transition phase.
-                */
-               if (runs > 0)
-                       sum_llc_perf_miss += strtoul(token_array[3], NULL, 0);
+
+               sum_llc_perf_miss += strtoull(token_array[3], NULL, 0);
                runs++;
+
+               if (runs < NUM_OF_RUNS)
+                       continue;
+
+               if (!current_mask) {
+                       ksft_print_msg("Unexpected empty cache mask\n");
+                       break;
+               }
+
+               alloc_size = cache_portion_size(cache_total_size, current_mask, full_cache_mask);
+
+               bits = count_bits(current_mask);
+
+               ret = show_results_info(sum_llc_perf_miss, bits,
+                                       alloc_size / 64,
+                                       MIN_DIFF_PERCENT_PER_BIT * (bits - 1),
+                                       runs, get_vendor() == ARCH_INTEL,
+                                       &prev_avg_llc_val);
+               if (ret)
+                       fail = 1;
+
+               runs = 0;
+               sum_llc_perf_miss = 0;
+               current_mask = next_mask(current_mask);
        }
 
        fclose(fp);
-       no_of_bits = count_bits(param->mask);
 
-       return show_cache_info(sum_llc_perf_miss, no_of_bits, span / 64,
-                              MAX_DIFF, MAX_DIFF_PERCENT, runs - 1,
-                              get_vendor() == ARCH_INTEL, false);
+       return fail;
 }
 
 void cat_test_cleanup(void)
 {
-       remove(RESULT_FILE_NAME1);
-       remove(RESULT_FILE_NAME2);
+       remove(RESULT_FILE_NAME);
 }
 
-int cat_perf_miss_val(int cpu_no, int n, char *cache_type)
+/*
+ * cat_test - Execute CAT benchmark and measure cache misses
+ * @test:              Test information structure
+ * @uparams:           User supplied parameters
+ * @param:             Parameters passed to cat_test()
+ * @span:              Buffer size for the benchmark
+ * @current_mask       Start mask for the first iteration
+ *
+ * Run CAT selftest by varying the allocated cache portion and comparing the
+ * impact on cache misses (the result analysis is done in check_results()
+ * and show_results_info(), not in this function).
+ *
+ * One bit is removed from the CAT allocation bit mask (in current_mask) for
+ * each subsequent test which keeps reducing the size of the allocated cache
+ * portion. A single test flushes the buffer, reads it to warm up the cache,
+ * and reads the buffer again. The cache misses are measured during the last
+ * read pass.
+ *
+ * Return:             0 when the test was run, < 0 on error.
+ */
+static int cat_test(const struct resctrl_test *test,
+                   const struct user_params *uparams,
+                   struct resctrl_val_param *param,
+                   size_t span, unsigned long current_mask)
 {
-       unsigned long l_mask, l_mask_1;
-       int ret, pipefd[2], sibling_cpu_no;
-       unsigned long cache_size = 0;
-       unsigned long long_mask;
-       char cbm_mask[256];
+       char *resctrl_val = param->resctrl_val;
+       struct perf_event_read pe_read;
+       struct perf_event_attr pea;
+       cpu_set_t old_affinity;
+       unsigned char *buf;
+       char schemata[64];
+       int ret, i, pe_fd;
+       pid_t bm_pid;
+
+       if (strcmp(param->filename, "") == 0)
+               sprintf(param->filename, "stdio");
+
+       bm_pid = getpid();
+
+       /* Taskset benchmark to specified cpu */
+       ret = taskset_benchmark(bm_pid, uparams->cpu, &old_affinity);
+       if (ret)
+               return ret;
+
+       /* Write benchmark to specified con_mon grp, mon_grp in resctrl FS*/
+       ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp,
+                                     resctrl_val);
+       if (ret)
+               goto reset_affinity;
+
+       perf_event_attr_initialize(&pea, PERF_COUNT_HW_CACHE_MISSES);
+       perf_event_initialize_read_format(&pe_read);
+       pe_fd = perf_open(&pea, bm_pid, uparams->cpu);
+       if (pe_fd < 0) {
+               ret = -1;
+               goto reset_affinity;
+       }
+
+       buf = alloc_buffer(span, 1);
+       if (!buf) {
+               ret = -1;
+               goto pe_close;
+       }
+
+       while (current_mask) {
+               snprintf(schemata, sizeof(schemata), "%lx", param->mask & ~current_mask);
+               ret = write_schemata("", schemata, uparams->cpu, test->resource);
+               if (ret)
+                       goto free_buf;
+               snprintf(schemata, sizeof(schemata), "%lx", current_mask);
+               ret = write_schemata(param->ctrlgrp, schemata, uparams->cpu, test->resource);
+               if (ret)
+                       goto free_buf;
+
+               for (i = 0; i < NUM_OF_RUNS; i++) {
+                       mem_flush(buf, span);
+                       fill_cache_read(buf, span, true);
+
+                       ret = perf_event_reset_enable(pe_fd);
+                       if (ret)
+                               goto free_buf;
+
+                       fill_cache_read(buf, span, true);
+
+                       ret = perf_event_measure(pe_fd, &pe_read, param->filename, bm_pid);
+                       if (ret)
+                               goto free_buf;
+               }
+               current_mask = next_mask(current_mask);
+       }
+
+free_buf:
+       free(buf);
+pe_close:
+       close(pe_fd);
+reset_affinity:
+       taskset_restore(bm_pid, &old_affinity);
+
+       return ret;
+}
+
+static int cat_run_test(const struct resctrl_test *test, const struct user_params *uparams)
+{
+       unsigned long long_mask, start_mask, full_cache_mask;
+       unsigned long cache_total_size = 0;
+       int n = uparams->bits;
+       unsigned int start;
        int count_of_bits;
-       char pipe_message;
        size_t span;
+       int ret;
 
-       /* Get default cbm mask for L3/L2 cache */
-       ret = get_cbm_mask(cache_type, cbm_mask);
+       ret = get_full_cbm(test->resource, &full_cache_mask);
+       if (ret)
+               return ret;
+       /* Get the largest contiguous exclusive portion of the cache */
+       ret = get_mask_no_shareable(test->resource, &long_mask);
        if (ret)
                return ret;
-
-       long_mask = strtoul(cbm_mask, NULL, 16);
 
        /* Get L3/L2 cache size */
-       ret = get_cache_size(cpu_no, cache_type, &cache_size);
+       ret = get_cache_size(uparams->cpu, test->resource, &cache_total_size);
        if (ret)
                return ret;
-       ksft_print_msg("Cache size :%lu\n", cache_size);
+       ksft_print_msg("Cache size :%lu\n", cache_total_size);
 
-       /* Get max number of bits from default-cabm mask */
-       count_of_bits = count_bits(long_mask);
+       count_of_bits = count_contiguous_bits(long_mask, &start);
 
        if (!n)
                n = count_of_bits / 2;
@@ -123,89 +269,124 @@ int cat_perf_miss_val(int cpu_no, int n, char *cache_type)
                               count_of_bits - 1);
                return -1;
        }
-
-       /* Get core id from same socket for running another thread */
-       sibling_cpu_no = get_core_sibling(cpu_no);
-       if (sibling_cpu_no < 0)
-               return -1;
+       start_mask = create_bit_mask(start, n);
 
        struct resctrl_val_param param = {
                .resctrl_val    = CAT_STR,
-               .cpu_no         = cpu_no,
-               .setup          = cat_setup,
+               .ctrlgrp        = "c1",
+               .filename       = RESULT_FILE_NAME,
+               .num_of_runs    = 0,
        };
+       param.mask = long_mask;
+       span = cache_portion_size(cache_total_size, start_mask, full_cache_mask);
 
-       l_mask = long_mask >> n;
-       l_mask_1 = ~l_mask & long_mask;
+       remove(param.filename);
 
-       /* Set param values for parent thread which will be allocated bitmask
-        * with (max_bits - n) bits
-        */
-       span = cache_size * (count_of_bits - n) / count_of_bits;
-       strcpy(param.ctrlgrp, "c2");
-       strcpy(param.mongrp, "m2");
-       strcpy(param.filename, RESULT_FILE_NAME2);
-       param.mask = l_mask;
-       param.num_of_runs = 0;
-
-       if (pipe(pipefd)) {
-               perror("# Unable to create pipe");
-               return errno;
-       }
+       ret = cat_test(test, uparams, &param, span, start_mask);
+       if (ret)
+               goto out;
 
-       fflush(stdout);
-       bm_pid = fork();
+       ret = check_results(&param, test->resource,
+                           cache_total_size, full_cache_mask, start_mask);
+out:
+       cat_test_cleanup();
 
-       /* Set param values for child thread which will be allocated bitmask
-        * with n bits
-        */
-       if (bm_pid == 0) {
-               param.mask = l_mask_1;
-               strcpy(param.ctrlgrp, "c1");
-               strcpy(param.mongrp, "m1");
-               span = cache_size * n / count_of_bits;
-               strcpy(param.filename, RESULT_FILE_NAME1);
-               param.num_of_runs = 0;
-               param.cpu_no = sibling_cpu_no;
+       return ret;
+}
+
+static int noncont_cat_run_test(const struct resctrl_test *test,
+                               const struct user_params *uparams)
+{
+       unsigned long full_cache_mask, cont_mask, noncont_mask;
+       unsigned int eax, ebx, ecx, edx, sparse_masks;
+       int bit_center, ret;
+       char schemata[64];
+
+       /* Check to compare sparse_masks content to CPUID output. */
+       ret = resource_info_unsigned_get(test->resource, "sparse_masks", &sparse_masks);
+       if (ret)
+               return ret;
+
+       if (!strcmp(test->resource, "L3"))
+               __cpuid_count(0x10, 1, eax, ebx, ecx, edx);
+       else if (!strcmp(test->resource, "L2"))
+               __cpuid_count(0x10, 2, eax, ebx, ecx, edx);
+       else
+               return -EINVAL;
+
+       if (sparse_masks != ((ecx >> 3) & 1)) {
+               ksft_print_msg("CPUID output doesn't match 'sparse_masks' file content!\n");
+               return 1;
        }
 
-       remove(param.filename);
+       /* Write checks initialization. */
+       ret = get_full_cbm(test->resource, &full_cache_mask);
+       if (ret < 0)
+               return ret;
+       bit_center = count_bits(full_cache_mask) / 2;
 
-       ret = cat_val(&param, span);
-       if (ret == 0)
-               ret = check_results(&param, span);
-
-       if (bm_pid == 0) {
-               /* Tell parent that child is ready */
-               close(pipefd[0]);
-               pipe_message = 1;
-               if (write(pipefd[1], &pipe_message, sizeof(pipe_message)) <
-                   sizeof(pipe_message))
-                       /*
-                        * Just print the error message.
-                        * Let while(1) run and wait for itself to be killed.
-                        */
-                       perror("# failed signaling parent process");
-
-               close(pipefd[1]);
-               while (1)
-                       ;
-       } else {
-               /* Parent waits for child to be ready. */
-               close(pipefd[1]);
-               pipe_message = 0;
-               while (pipe_message != 1) {
-                       if (read(pipefd[0], &pipe_message,
-                                sizeof(pipe_message)) < sizeof(pipe_message)) {
-                               perror("# failed reading from child process");
-                               break;
-                       }
-               }
-               close(pipefd[0]);
-               kill(bm_pid, SIGKILL);
+       /*
+        * The bit_center needs to be at least 3 to properly calculate the CBM
+        * hole in the noncont_mask. If it's smaller return an error since the
+        * cache mask is too short and that shouldn't happen.
+        */
+       if (bit_center < 3)
+               return -EINVAL;
+       cont_mask = full_cache_mask >> bit_center;
+
+       /* Contiguous mask write check. */
+       snprintf(schemata, sizeof(schemata), "%lx", cont_mask);
+       ret = write_schemata("", schemata, uparams->cpu, test->resource);
+       if (ret) {
+               ksft_print_msg("Write of contiguous CBM failed\n");
+               return 1;
        }
 
-       cat_test_cleanup();
+       /*
+        * Non-contiguous mask write check. CBM has a 0xf hole approximately in the middle.
+        * Output is compared with support information to catch any edge case errors.
+        */
+       noncont_mask = ~(0xfUL << (bit_center - 2)) & full_cache_mask;
+       snprintf(schemata, sizeof(schemata), "%lx", noncont_mask);
+       ret = write_schemata("", schemata, uparams->cpu, test->resource);
+       if (ret && sparse_masks)
+               ksft_print_msg("Non-contiguous CBMs supported but write of non-contiguous CBM failed\n");
+       else if (ret && !sparse_masks)
+               ksft_print_msg("Non-contiguous CBMs not supported and write of non-contiguous CBM failed as expected\n");
+       else if (!ret && !sparse_masks)
+               ksft_print_msg("Non-contiguous CBMs not supported but write of non-contiguous CBM succeeded\n");
+
+       return !ret == !sparse_masks;
+}
 
-       return ret;
+static bool noncont_cat_feature_check(const struct resctrl_test *test)
+{
+       if (!resctrl_resource_exists(test->resource))
+               return false;
+
+       return resource_info_file_exists(test->resource, "sparse_masks");
 }
+
+struct resctrl_test l3_cat_test = {
+       .name = "L3_CAT",
+       .group = "CAT",
+       .resource = "L3",
+       .feature_check = test_resource_feature_check,
+       .run_test = cat_run_test,
+};
+
+struct resctrl_test l3_noncont_cat_test = {
+       .name = "L3_NONCONT_CAT",
+       .group = "CAT",
+       .resource = "L3",
+       .feature_check = noncont_cat_feature_check,
+       .run_test = noncont_cat_run_test,
+};
+
+struct resctrl_test l2_noncont_cat_test = {
+       .name = "L2_NONCONT_CAT",
+       .group = "CAT",
+       .resource = "L2",
+       .feature_check = noncont_cat_feature_check,
+       .run_test = noncont_cat_run_test,
+};
index 50bdbce9fba95f9b16c0526b98f64229450d0058..a81f91222a89a820b14117e133fc6b5d596d7b72 100644 (file)
@@ -16,7 +16,9 @@
 #define MAX_DIFF               2000000
 #define MAX_DIFF_PERCENT       15
 
-static int cmt_setup(struct resctrl_val_param *p)
+static int cmt_setup(const struct resctrl_test *test,
+                    const struct user_params *uparams,
+                    struct resctrl_val_param *p)
 {
        /* Run NUM_OF_RUNS times */
        if (p->num_of_runs >= NUM_OF_RUNS)
@@ -27,6 +29,33 @@ static int cmt_setup(struct resctrl_val_param *p)
        return 0;
 }
 
+static int show_results_info(unsigned long sum_llc_val, int no_of_bits,
+                            unsigned long cache_span, unsigned long max_diff,
+                            unsigned long max_diff_percent, unsigned long num_of_runs,
+                            bool platform)
+{
+       unsigned long avg_llc_val = 0;
+       float diff_percent;
+       long avg_diff = 0;
+       int ret;
+
+       avg_llc_val = sum_llc_val / num_of_runs;
+       avg_diff = (long)abs(cache_span - avg_llc_val);
+       diff_percent = ((float)cache_span - avg_llc_val) / cache_span * 100;
+
+       ret = platform && abs((int)diff_percent) > max_diff_percent &&
+             abs(avg_diff) > max_diff;
+
+       ksft_print_msg("%s Check cache miss rate within %lu%%\n",
+                      ret ? "Fail:" : "Pass:", max_diff_percent);
+
+       ksft_print_msg("Percent diff=%d\n", abs((int)diff_percent));
+
+       show_cache_info(no_of_bits, avg_llc_val, cache_span, false);
+
+       return ret;
+}
+
 static int check_results(struct resctrl_val_param *param, size_t span, int no_of_bits)
 {
        char *token_array[8], temp[512];
@@ -37,9 +66,9 @@ static int check_results(struct resctrl_val_param *param, size_t span, int no_of
        ksft_print_msg("Checking for pass/fail\n");
        fp = fopen(param->filename, "r");
        if (!fp) {
-               perror("# Error in opening file\n");
+               ksft_perror("Error in opening file");
 
-               return errno;
+               return -1;
        }
 
        while (fgets(temp, sizeof(temp), fp)) {
@@ -58,9 +87,8 @@ static int check_results(struct resctrl_val_param *param, size_t span, int no_of
        }
        fclose(fp);
 
-       return show_cache_info(sum_llc_occu_resc, no_of_bits, span,
-                              MAX_DIFF, MAX_DIFF_PERCENT, runs - 1,
-                              true, true);
+       return show_results_info(sum_llc_occu_resc, no_of_bits, span,
+                                MAX_DIFF, MAX_DIFF_PERCENT, runs - 1, true);
 }
 
 void cmt_test_cleanup(void)
@@ -68,28 +96,26 @@ void cmt_test_cleanup(void)
        remove(RESULT_FILE_NAME);
 }
 
-int cmt_resctrl_val(int cpu_no, int n, const char * const *benchmark_cmd)
+static int cmt_run_test(const struct resctrl_test *test, const struct user_params *uparams)
 {
-       const char * const *cmd = benchmark_cmd;
+       const char * const *cmd = uparams->benchmark_cmd;
        const char *new_cmd[BENCHMARK_ARGS];
-       unsigned long cache_size = 0;
+       unsigned long cache_total_size = 0;
+       int n = uparams->bits ? : 5;
        unsigned long long_mask;
        char *span_str = NULL;
-       char cbm_mask[256];
        int count_of_bits;
        size_t span;
        int ret, i;
 
-       ret = get_cbm_mask("L3", cbm_mask);
+       ret = get_full_cbm("L3", &long_mask);
        if (ret)
                return ret;
 
-       long_mask = strtoul(cbm_mask, NULL, 16);
-
-       ret = get_cache_size(cpu_no, "L3", &cache_size);
+       ret = get_cache_size(uparams->cpu, "L3", &cache_total_size);
        if (ret)
                return ret;
-       ksft_print_msg("Cache size :%lu\n", cache_size);
+       ksft_print_msg("Cache size :%lu\n", cache_total_size);
 
        count_of_bits = count_bits(long_mask);
 
@@ -103,19 +129,18 @@ int cmt_resctrl_val(int cpu_no, int n, const char * const *benchmark_cmd)
                .resctrl_val    = CMT_STR,
                .ctrlgrp        = "c1",
                .mongrp         = "m1",
-               .cpu_no         = cpu_no,
                .filename       = RESULT_FILE_NAME,
                .mask           = ~(long_mask << n) & long_mask,
                .num_of_runs    = 0,
                .setup          = cmt_setup,
        };
 
-       span = cache_size * n / count_of_bits;
+       span = cache_portion_size(cache_total_size, param.mask, long_mask);
 
        if (strcmp(cmd[0], "fill_buf") == 0) {
                /* Duplicate the command to be able to replace span in it */
-               for (i = 0; benchmark_cmd[i]; i++)
-                       new_cmd[i] = benchmark_cmd[i];
+               for (i = 0; uparams->benchmark_cmd[i]; i++)
+                       new_cmd[i] = uparams->benchmark_cmd[i];
                new_cmd[i] = NULL;
 
                ret = asprintf(&span_str, "%zu", span);
@@ -127,11 +152,13 @@ int cmt_resctrl_val(int cpu_no, int n, const char * const *benchmark_cmd)
 
        remove(RESULT_FILE_NAME);
 
-       ret = resctrl_val(cmd, &param);
+       ret = resctrl_val(test, uparams, cmd, &param);
        if (ret)
                goto out;
 
        ret = check_results(&param, span, n);
+       if (ret && (get_vendor() == ARCH_INTEL))
+               ksft_print_msg("Intel CMT may be inaccurate when Sub-NUMA Clustering is enabled. Check BIOS configuration.\n");
 
 out:
        cmt_test_cleanup();
@@ -139,3 +166,16 @@ out:
 
        return ret;
 }
+
+static bool cmt_feature_check(const struct resctrl_test *test)
+{
+       return test_resource_feature_check(test) &&
+              resctrl_mon_feature_exists("L3_MON", "llc_occupancy");
+}
+
+struct resctrl_test cmt_test = {
+       .name = "CMT",
+       .resource = "L3",
+       .feature_check = cmt_feature_check,
+       .run_test = cmt_run_test,
+};
index 0d425f26583a9596479ae8a017c70d3523fa25a8..ae120f1735c0bc0d9e12bd8c38fabf9d75711b08 100644 (file)
@@ -38,7 +38,7 @@ static void cl_flush(void *p)
 #endif
 }
 
-static void mem_flush(unsigned char *buf, size_t buf_size)
+void mem_flush(unsigned char *buf, size_t buf_size)
 {
        unsigned char *cp = buf;
        size_t i = 0;
@@ -51,39 +51,38 @@ static void mem_flush(unsigned char *buf, size_t buf_size)
        sb();
 }
 
-static void *malloc_and_init_memory(size_t buf_size)
-{
-       void *p = NULL;
-       uint64_t *p64;
-       size_t s64;
-       int ret;
-
-       ret = posix_memalign(&p, PAGE_SIZE, buf_size);
-       if (ret < 0)
-               return NULL;
-
-       p64 = (uint64_t *)p;
-       s64 = buf_size / sizeof(uint64_t);
-
-       while (s64 > 0) {
-               *p64 = (uint64_t)rand();
-               p64 += (CL_SIZE / sizeof(uint64_t));
-               s64 -= (CL_SIZE / sizeof(uint64_t));
-       }
-
-       return p;
-}
+/*
+ * Buffer index step advance to workaround HW prefetching interfering with
+ * the measurements.
+ *
+ * Must be a prime to step through all indexes of the buffer.
+ *
+ * Some primes work better than others on some architectures (from MBA/MBM
+ * result stability point of view).
+ */
+#define FILL_IDX_MULT  23
 
 static int fill_one_span_read(unsigned char *buf, size_t buf_size)
 {
-       unsigned char *end_ptr = buf + buf_size;
-       unsigned char sum, *p;
-
-       sum = 0;
-       p = buf;
-       while (p < end_ptr) {
-               sum += *p;
-               p += (CL_SIZE / 2);
+       unsigned int size = buf_size / (CL_SIZE / 2);
+       unsigned int i, idx = 0;
+       unsigned char sum = 0;
+
+       /*
+        * Read the buffer in an order that is unexpected by HW prefetching
+        * optimizations to prevent them interfering with the caching pattern.
+        *
+        * The read order is (in terms of halves of cachelines):
+        *      i * FILL_IDX_MULT % size
+        * The formula is open-coded below to avoiding modulo inside the loop
+        * as it improves MBA/MBM result stability on some architectures.
+        */
+       for (i = 0; i < size; i++) {
+               sum += buf[idx * (CL_SIZE / 2)];
+
+               idx += FILL_IDX_MULT;
+               while (idx >= size)
+                       idx -= size;
        }
 
        return sum;
@@ -101,10 +100,9 @@ static void fill_one_span_write(unsigned char *buf, size_t buf_size)
        }
 }
 
-static int fill_cache_read(unsigned char *buf, size_t buf_size, bool once)
+void fill_cache_read(unsigned char *buf, size_t buf_size, bool once)
 {
        int ret = 0;
-       FILE *fp;
 
        while (1) {
                ret = fill_one_span_read(buf, buf_size);
@@ -113,67 +111,59 @@ static int fill_cache_read(unsigned char *buf, size_t buf_size, bool once)
        }
 
        /* Consume read result so that reading memory is not optimized out. */
-       fp = fopen("/dev/null", "w");
-       if (!fp) {
-               perror("Unable to write to /dev/null");
-               return -1;
-       }
-       fprintf(fp, "Sum: %d ", ret);
-       fclose(fp);
-
-       return 0;
+       *value_sink = ret;
 }
 
-static int fill_cache_write(unsigned char *buf, size_t buf_size, bool once)
+static void fill_cache_write(unsigned char *buf, size_t buf_size, bool once)
 {
        while (1) {
                fill_one_span_write(buf, buf_size);
                if (once)
                        break;
        }
-
-       return 0;
 }
 
-static int fill_cache(size_t buf_size, int memflush, int op, bool once)
+unsigned char *alloc_buffer(size_t buf_size, int memflush)
 {
-       unsigned char *buf;
+       void *buf = NULL;
+       uint64_t *p64;
+       size_t s64;
        int ret;
 
-       buf = malloc_and_init_memory(buf_size);
-       if (!buf)
-               return -1;
-
-       /* Flush the memory before using to avoid "cache hot pages" effect */
-       if (memflush)
-               mem_flush(buf, buf_size);
-
-       if (op == 0)
-               ret = fill_cache_read(buf, buf_size, once);
-       else
-               ret = fill_cache_write(buf, buf_size, once);
+       ret = posix_memalign(&buf, PAGE_SIZE, buf_size);
+       if (ret < 0)
+               return NULL;
 
-       free(buf);
+       /* Initialize the buffer */
+       p64 = buf;
+       s64 = buf_size / sizeof(uint64_t);
 
-       if (ret) {
-               printf("\n Error in fill cache read/write...\n");
-               return -1;
+       while (s64 > 0) {
+               *p64 = (uint64_t)rand();
+               p64 += (CL_SIZE / sizeof(uint64_t));
+               s64 -= (CL_SIZE / sizeof(uint64_t));
        }
 
+       /* Flush the memory before using to avoid "cache hot pages" effect */
+       if (memflush)
+               mem_flush(buf, buf_size);
 
-       return 0;
+       return buf;
 }
 
-int run_fill_buf(size_t span, int memflush, int op, bool once)
+int run_fill_buf(size_t buf_size, int memflush, int op, bool once)
 {
-       size_t cache_size = span;
-       int ret;
+       unsigned char *buf;
 
-       ret = fill_cache(cache_size, memflush, op, once);
-       if (ret) {
-               printf("\n Error in fill cache\n");
+       buf = alloc_buffer(buf_size, memflush);
+       if (!buf)
                return -1;
-       }
+
+       if (op == 0)
+               fill_cache_read(buf, buf_size, once);
+       else
+               fill_cache_write(buf, buf_size, once);
+       free(buf);
 
        return 0;
 }
index d3bf4368341ece023dff1a96a4c795122baf8464..7946e32e85c83fb9422caf1ab3168f4994f21048 100644 (file)
@@ -22,7 +22,9 @@
  * con_mon grp, mon_grp in resctrl FS.
  * For each allocation, run 5 times in order to get average values.
  */
-static int mba_setup(struct resctrl_val_param *p)
+static int mba_setup(const struct resctrl_test *test,
+                    const struct user_params *uparams,
+                    struct resctrl_val_param *p)
 {
        static int runs_per_allocation, allocation = 100;
        char allocation_str[64];
@@ -40,8 +42,7 @@ static int mba_setup(struct resctrl_val_param *p)
 
        sprintf(allocation_str, "%d", allocation);
 
-       ret = write_schemata(p->ctrlgrp, allocation_str, p->cpu_no,
-                            p->resctrl_val);
+       ret = write_schemata(p->ctrlgrp, allocation_str, uparams->cpu, test->resource);
        if (ret < 0)
                return ret;
 
@@ -109,9 +110,9 @@ static int check_results(void)
 
        fp = fopen(output, "r");
        if (!fp) {
-               perror(output);
+               ksft_perror(output);
 
-               return errno;
+               return -1;
        }
 
        runs = 0;
@@ -141,13 +142,12 @@ void mba_test_cleanup(void)
        remove(RESULT_FILE_NAME);
 }
 
-int mba_schemata_change(int cpu_no, const char * const *benchmark_cmd)
+static int mba_run_test(const struct resctrl_test *test, const struct user_params *uparams)
 {
        struct resctrl_val_param param = {
                .resctrl_val    = MBA_STR,
                .ctrlgrp        = "c1",
                .mongrp         = "m1",
-               .cpu_no         = cpu_no,
                .filename       = RESULT_FILE_NAME,
                .bw_report      = "reads",
                .setup          = mba_setup
@@ -156,7 +156,7 @@ int mba_schemata_change(int cpu_no, const char * const *benchmark_cmd)
 
        remove(RESULT_FILE_NAME);
 
-       ret = resctrl_val(benchmark_cmd, &param);
+       ret = resctrl_val(test, uparams, uparams->benchmark_cmd, &param);
        if (ret)
                goto out;
 
@@ -167,3 +167,17 @@ out:
 
        return ret;
 }
+
+static bool mba_feature_check(const struct resctrl_test *test)
+{
+       return test_resource_feature_check(test) &&
+              resctrl_mon_feature_exists("L3_MON", "mbm_local_bytes");
+}
+
+struct resctrl_test mba_test = {
+       .name = "MBA",
+       .resource = "MB",
+       .vendor_specific = ARCH_INTEL,
+       .feature_check = mba_feature_check,
+       .run_test = mba_run_test,
+};
index 741533f2b075884d8983e8635cc454f05d29ea6c..d67ffa3ec63a321416855d2405f06c3e2c16af05 100644 (file)
@@ -59,9 +59,9 @@ static int check_results(size_t span)
 
        fp = fopen(output, "r");
        if (!fp) {
-               perror(output);
+               ksft_perror(output);
 
-               return errno;
+               return -1;
        }
 
        runs = 0;
@@ -86,7 +86,9 @@ static int check_results(size_t span)
        return ret;
 }
 
-static int mbm_setup(struct resctrl_val_param *p)
+static int mbm_setup(const struct resctrl_test *test,
+                    const struct user_params *uparams,
+                    struct resctrl_val_param *p)
 {
        int ret = 0;
 
@@ -95,9 +97,8 @@ static int mbm_setup(struct resctrl_val_param *p)
                return END_OF_TESTS;
 
        /* Set up shemata with 100% allocation on the first run. */
-       if (p->num_of_runs == 0 && validate_resctrl_feature_request("MB", NULL))
-               ret = write_schemata(p->ctrlgrp, "100", p->cpu_no,
-                                    p->resctrl_val);
+       if (p->num_of_runs == 0 && resctrl_resource_exists("MB"))
+               ret = write_schemata(p->ctrlgrp, "100", uparams->cpu, test->resource);
 
        p->num_of_runs++;
 
@@ -109,13 +110,12 @@ void mbm_test_cleanup(void)
        remove(RESULT_FILE_NAME);
 }
 
-int mbm_bw_change(int cpu_no, const char * const *benchmark_cmd)
+static int mbm_run_test(const struct resctrl_test *test, const struct user_params *uparams)
 {
        struct resctrl_val_param param = {
                .resctrl_val    = MBM_STR,
                .ctrlgrp        = "c1",
                .mongrp         = "m1",
-               .cpu_no         = cpu_no,
                .filename       = RESULT_FILE_NAME,
                .bw_report      = "reads",
                .setup          = mbm_setup
@@ -124,14 +124,30 @@ int mbm_bw_change(int cpu_no, const char * const *benchmark_cmd)
 
        remove(RESULT_FILE_NAME);
 
-       ret = resctrl_val(benchmark_cmd, &param);
+       ret = resctrl_val(test, uparams, uparams->benchmark_cmd, &param);
        if (ret)
                goto out;
 
        ret = check_results(DEFAULT_SPAN);
+       if (ret && (get_vendor() == ARCH_INTEL))
+               ksft_print_msg("Intel MBM may be inaccurate when Sub-NUMA Clustering is enabled. Check BIOS configuration.\n");
 
 out:
        mbm_test_cleanup();
 
        return ret;
 }
+
+static bool mbm_feature_check(const struct resctrl_test *test)
+{
+       return resctrl_mon_feature_exists("L3_MON", "mbm_total_bytes") &&
+              resctrl_mon_feature_exists("L3_MON", "mbm_local_bytes");
+}
+
+struct resctrl_test mbm_test = {
+       .name = "MBM",
+       .resource = "MB",
+       .vendor_specific = ARCH_INTEL,
+       .feature_check = mbm_feature_check,
+       .run_test = mbm_run_test,
+};
index a33f414f60199ac543412589780b1e554d148ac8..2051bd135e0d04d0d403e28b3c9b393a7d043926 100644 (file)
 #define PHYS_ID_PATH           "/sys/devices/system/cpu/cpu"
 #define INFO_PATH              "/sys/fs/resctrl/info"
 
+/*
+ * CPU vendor IDs
+ *
+ * Define as bits because they're used for vendor_specific bitmask in
+ * the struct resctrl_test.
+ */
 #define ARCH_INTEL     1
 #define ARCH_AMD       2
 
 
 #define DEFAULT_SPAN           (250 * MB)
 
-#define PARENT_EXIT(err_msg)                   \
+#define PARENT_EXIT()                          \
        do {                                    \
-               perror(err_msg);                \
                kill(ppid, SIGKILL);            \
                umount_resctrlfs();             \
                exit(EXIT_FAILURE);             \
        } while (0)
 
+/*
+ * user_params:                User supplied parameters
+ * @cpu:               CPU number to which the benchmark will be bound to
+ * @bits:              Number of bits used for cache allocation size
+ * @benchmark_cmd:     Benchmark command to run during (some of the) tests
+ */
+struct user_params {
+       int cpu;
+       int bits;
+       const char *benchmark_cmd[BENCHMARK_ARGS];
+};
+
+/*
+ * resctrl_test:       resctrl test definition
+ * @name:              Test name
+ * @group:             Test group - a common name for tests that share some characteristic
+ *                     (e.g., L3 CAT test belongs to the CAT group). Can be NULL
+ * @resource:          Resource to test (e.g., MB, L3, L2, etc.)
+ * @vendor_specific:   Bitmask for vendor-specific tests (can be 0 for universal tests)
+ * @disabled:          Test is disabled
+ * @feature_check:     Callback to check required resctrl features
+ * @run_test:          Callback to run the test
+ */
+struct resctrl_test {
+       const char      *name;
+       const char      *group;
+       const char      *resource;
+       unsigned int    vendor_specific;
+       bool            disabled;
+       bool            (*feature_check)(const struct resctrl_test *test);
+       int             (*run_test)(const struct resctrl_test *test,
+                                   const struct user_params *uparams);
+};
+
 /*
  * resctrl_val_param:  resctrl test parameters
  * @resctrl_val:       Resctrl feature (Eg: mbm, mba.. etc)
  * @ctrlgrp:           Name of the control monitor group (con_mon grp)
  * @mongrp:            Name of the monitor group (mon grp)
- * @cpu_no:            CPU number to which the benchmark would be binded
  * @filename:          Name of file to which the o/p should be written
  * @bw_report:         Bandwidth report type (reads vs writes)
  * @setup:             Call back function to setup test environment
@@ -59,12 +97,20 @@ struct resctrl_val_param {
        char            *resctrl_val;
        char            ctrlgrp[64];
        char            mongrp[64];
-       int             cpu_no;
        char            filename[64];
        char            *bw_report;
        unsigned long   mask;
        int             num_of_runs;
-       int             (*setup)(struct resctrl_val_param *param);
+       int             (*setup)(const struct resctrl_test *test,
+                                const struct user_params *uparams,
+                                struct resctrl_val_param *param);
+};
+
+struct perf_event_read {
+       __u64 nr;                       /* The number of events */
+       struct {
+               __u64 value;            /* The value of the event */
+       } values[2];
 };
 
 #define MBM_STR                        "mbm"
@@ -72,6 +118,13 @@ struct resctrl_val_param {
 #define CMT_STR                        "cmt"
 #define CAT_STR                        "cat"
 
+/*
+ * Memory location that consumes values compiler must not optimize away.
+ * Volatile ensures writes to this location cannot be optimized away by
+ * compiler.
+ */
+extern volatile int *value_sink;
+
 extern pid_t bm_pid, ppid;
 
 extern char llc_occup_path[1024];
@@ -79,42 +132,84 @@ extern char llc_occup_path[1024];
 int get_vendor(void);
 bool check_resctrlfs_support(void);
 int filter_dmesg(void);
-int get_resource_id(int cpu_no, int *resource_id);
+int get_domain_id(const char *resource, int cpu_no, int *domain_id);
 int mount_resctrlfs(void);
 int umount_resctrlfs(void);
 int validate_bw_report_request(char *bw_report);
-bool validate_resctrl_feature_request(const char *resource, const char *feature);
+bool resctrl_resource_exists(const char *resource);
+bool resctrl_mon_feature_exists(const char *resource, const char *feature);
+bool resource_info_file_exists(const char *resource, const char *file);
+bool test_resource_feature_check(const struct resctrl_test *test);
 char *fgrep(FILE *inf, const char *str);
-int taskset_benchmark(pid_t bm_pid, int cpu_no);
-int write_schemata(char *ctrlgrp, char *schemata, int cpu_no,
-                  char *resctrl_val);
+int taskset_benchmark(pid_t bm_pid, int cpu_no, cpu_set_t *old_affinity);
+int taskset_restore(pid_t bm_pid, cpu_set_t *old_affinity);
+int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, const char *resource);
 int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
                            char *resctrl_val);
 int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
                    int group_fd, unsigned long flags);
-int run_fill_buf(size_t span, int memflush, int op, bool once);
-int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *param);
-int mbm_bw_change(int cpu_no, const char * const *benchmark_cmd);
+unsigned char *alloc_buffer(size_t buf_size, int memflush);
+void mem_flush(unsigned char *buf, size_t buf_size);
+void fill_cache_read(unsigned char *buf, size_t buf_size, bool once);
+int run_fill_buf(size_t buf_size, int memflush, int op, bool once);
+int resctrl_val(const struct resctrl_test *test,
+               const struct user_params *uparams,
+               const char * const *benchmark_cmd,
+               struct resctrl_val_param *param);
 void tests_cleanup(void);
 void mbm_test_cleanup(void);
-int mba_schemata_change(int cpu_no, const char * const *benchmark_cmd);
 void mba_test_cleanup(void);
-int get_cbm_mask(char *cache_type, char *cbm_mask);
-int get_cache_size(int cpu_no, char *cache_type, unsigned long *cache_size);
+unsigned long create_bit_mask(unsigned int start, unsigned int len);
+unsigned int count_contiguous_bits(unsigned long val, unsigned int *start);
+int get_full_cbm(const char *cache_type, unsigned long *mask);
+int get_mask_no_shareable(const char *cache_type, unsigned long *mask);
+int get_cache_size(int cpu_no, const char *cache_type, unsigned long *cache_size);
+int resource_info_unsigned_get(const char *resource, const char *filename, unsigned int *val);
 void ctrlc_handler(int signum, siginfo_t *info, void *ptr);
 int signal_handler_register(void);
 void signal_handler_unregister(void);
-int cat_val(struct resctrl_val_param *param, size_t span);
 void cat_test_cleanup(void);
-int cat_perf_miss_val(int cpu_no, int no_of_bits, char *cache_type);
-int cmt_resctrl_val(int cpu_no, int n, const char * const *benchmark_cmd);
 unsigned int count_bits(unsigned long n);
 void cmt_test_cleanup(void);
-int get_core_sibling(int cpu_no);
-int measure_cache_vals(struct resctrl_val_param *param, int bm_pid);
-int show_cache_info(unsigned long sum_llc_val, int no_of_bits,
-                   size_t cache_span, unsigned long max_diff,
-                   unsigned long max_diff_percent, unsigned long num_of_runs,
-                   bool platform, bool cmt);
+
+void perf_event_attr_initialize(struct perf_event_attr *pea, __u64 config);
+void perf_event_initialize_read_format(struct perf_event_read *pe_read);
+int perf_open(struct perf_event_attr *pea, pid_t pid, int cpu_no);
+int perf_event_reset_enable(int pe_fd);
+int perf_event_measure(int pe_fd, struct perf_event_read *pe_read,
+                      const char *filename, int bm_pid);
+int measure_llc_resctrl(const char *filename, int bm_pid);
+void show_cache_info(int no_of_bits, __u64 avg_llc_val, size_t cache_span, bool lines);
+
+/*
+ * cache_portion_size - Calculate the size of a cache portion
+ * @cache_size:                Total cache size in bytes
+ * @portion_mask:      Cache portion mask
+ * @full_cache_mask:   Full Cache Bit Mask (CBM) for the cache
+ *
+ * Return: The size of the cache portion in bytes.
+ */
+static inline unsigned long cache_portion_size(unsigned long cache_size,
+                                              unsigned long portion_mask,
+                                              unsigned long full_cache_mask)
+{
+       unsigned int bits = count_bits(full_cache_mask);
+
+       /*
+        * With no bits the full CBM, assume cache cannot be split into
+        * smaller portions. To avoid divide by zero, return cache_size.
+        */
+       if (!bits)
+               return cache_size;
+
+       return cache_size * count_bits(portion_mask) / bits;
+}
+
+extern struct resctrl_test mbm_test;
+extern struct resctrl_test mba_test;
+extern struct resctrl_test cmt_test;
+extern struct resctrl_test l3_cat_test;
+extern struct resctrl_test l3_noncont_cat_test;
+extern struct resctrl_test l2_noncont_cat_test;
 
 #endif /* RESCTRL_H */
index 2bbe3045a018e2c09edb5785ca9e79d589c7d0f8..f3dc1b9696e71a47e91495c4d046cfadbee46c24 100644 (file)
  */
 #include "resctrl.h"
 
+/* Volatile memory sink to prevent compiler optimizations */
+static volatile int sink_target;
+volatile int *value_sink = &sink_target;
+
+static struct resctrl_test *resctrl_tests[] = {
+       &mbm_test,
+       &mba_test,
+       &cmt_test,
+       &l3_cat_test,
+       &l3_noncont_cat_test,
+       &l2_noncont_cat_test,
+};
+
 static int detect_vendor(void)
 {
        FILE *inf = fopen("/proc/cpuinfo", "r");
@@ -49,11 +62,20 @@ int get_vendor(void)
 
 static void cmd_help(void)
 {
+       int i;
+
        printf("usage: resctrl_tests [-h] [-t test list] [-n no_of_bits] [-b benchmark_cmd [option]...]\n");
        printf("\t-b benchmark_cmd [option]...: run specified benchmark for MBM, MBA and CMT\n");
        printf("\t   default benchmark is builtin fill_buf\n");
-       printf("\t-t test list: run tests specified in the test list, ");
+       printf("\t-t test list: run tests/groups specified by the list, ");
        printf("e.g. -t mbm,mba,cmt,cat\n");
+       printf("\t\tSupported tests (group):\n");
+       for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++) {
+               if (resctrl_tests[i]->group)
+                       printf("\t\t\t%s (%s)\n", resctrl_tests[i]->name, resctrl_tests[i]->group);
+               else
+                       printf("\t\t\t%s\n", resctrl_tests[i]->name);
+       }
        printf("\t-n no_of_bits: run cache tests using specified no of bits in cache bit mask\n");
        printf("\t-p cpu_no: specify CPU number to run the test. 1 is default\n");
        printf("\t-h: help\n");
@@ -92,116 +114,63 @@ static void test_cleanup(void)
        signal_handler_unregister();
 }
 
-static void run_mbm_test(const char * const *benchmark_cmd, int cpu_no)
+static bool test_vendor_specific_check(const struct resctrl_test *test)
 {
-       int res;
-
-       ksft_print_msg("Starting MBM BW change ...\n");
-
-       if (test_prepare()) {
-               ksft_exit_fail_msg("Abnormal failure when preparing for the test\n");
-               return;
-       }
-
-       if (!validate_resctrl_feature_request("L3_MON", "mbm_total_bytes") ||
-           !validate_resctrl_feature_request("L3_MON", "mbm_local_bytes") ||
-           (get_vendor() != ARCH_INTEL)) {
-               ksft_test_result_skip("Hardware does not support MBM or MBM is disabled\n");
-               goto cleanup;
-       }
-
-       res = mbm_bw_change(cpu_no, benchmark_cmd);
-       ksft_test_result(!res, "MBM: bw change\n");
-       if ((get_vendor() == ARCH_INTEL) && res)
-               ksft_print_msg("Intel MBM may be inaccurate when Sub-NUMA Clustering is enabled. Check BIOS configuration.\n");
+       if (!test->vendor_specific)
+               return true;
 
-cleanup:
-       test_cleanup();
+       return get_vendor() & test->vendor_specific;
 }
 
-static void run_mba_test(const char * const *benchmark_cmd, int cpu_no)
+static void run_single_test(const struct resctrl_test *test, const struct user_params *uparams)
 {
-       int res;
-
-       ksft_print_msg("Starting MBA Schemata change ...\n");
+       int ret;
 
-       if (test_prepare()) {
-               ksft_exit_fail_msg("Abnormal failure when preparing for the test\n");
+       if (test->disabled)
                return;
-       }
 
-       if (!validate_resctrl_feature_request("MB", NULL) ||
-           !validate_resctrl_feature_request("L3_MON", "mbm_local_bytes") ||
-           (get_vendor() != ARCH_INTEL)) {
-               ksft_test_result_skip("Hardware does not support MBA or MBA is disabled\n");
-               goto cleanup;
+       if (!test_vendor_specific_check(test)) {
+               ksft_test_result_skip("Hardware does not support %s\n", test->name);
+               return;
        }
 
-       res = mba_schemata_change(cpu_no, benchmark_cmd);
-       ksft_test_result(!res, "MBA: schemata change\n");
-
-cleanup:
-       test_cleanup();
-}
-
-static void run_cmt_test(const char * const *benchmark_cmd, int cpu_no)
-{
-       int res;
-
-       ksft_print_msg("Starting CMT test ...\n");
+       ksft_print_msg("Starting %s test ...\n", test->name);
 
        if (test_prepare()) {
                ksft_exit_fail_msg("Abnormal failure when preparing for the test\n");
                return;
        }
 
-       if (!validate_resctrl_feature_request("L3_MON", "llc_occupancy") ||
-           !validate_resctrl_feature_request("L3", NULL)) {
-               ksft_test_result_skip("Hardware does not support CMT or CMT is disabled\n");
+       if (!test->feature_check(test)) {
+               ksft_test_result_skip("Hardware does not support %s or %s is disabled\n",
+                                     test->name, test->name);
                goto cleanup;
        }
 
-       res = cmt_resctrl_val(cpu_no, 5, benchmark_cmd);
-       ksft_test_result(!res, "CMT: test\n");
-       if ((get_vendor() == ARCH_INTEL) && res)
-               ksft_print_msg("Intel CMT may be inaccurate when Sub-NUMA Clustering is enabled. Check BIOS configuration.\n");
+       ret = test->run_test(test, uparams);
+       ksft_test_result(!ret, "%s: test\n", test->name);
 
 cleanup:
        test_cleanup();
 }
 
-static void run_cat_test(int cpu_no, int no_of_bits)
+static void init_user_params(struct user_params *uparams)
 {
-       int res;
-
-       ksft_print_msg("Starting CAT test ...\n");
-
-       if (test_prepare()) {
-               ksft_exit_fail_msg("Abnormal failure when preparing for the test\n");
-               return;
-       }
-
-       if (!validate_resctrl_feature_request("L3", NULL)) {
-               ksft_test_result_skip("Hardware does not support CAT or CAT is disabled\n");
-               goto cleanup;
-       }
+       memset(uparams, 0, sizeof(*uparams));
 
-       res = cat_perf_miss_val(cpu_no, no_of_bits, "L3");
-       ksft_test_result(!res, "CAT: test\n");
-
-cleanup:
-       test_cleanup();
+       uparams->cpu = 1;
+       uparams->bits = 0;
 }
 
 int main(int argc, char **argv)
 {
-       bool mbm_test = true, mba_test = true, cmt_test = true;
-       const char *benchmark_cmd[BENCHMARK_ARGS] = {};
-       int c, cpu_no = 1, i, no_of_bits = 0;
+       int tests = ARRAY_SIZE(resctrl_tests);
+       bool test_param_seen = false;
+       struct user_params uparams;
        char *span_str = NULL;
-       bool cat_test = true;
-       int tests = 0;
-       int ret;
+       int ret, c, i;
+
+       init_user_params(&uparams);
 
        while ((c = getopt(argc, argv, "ht:b:n:p:")) != -1) {
                char *token;
@@ -219,32 +188,35 @@ int main(int argc, char **argv)
 
                        /* Extract benchmark command from command line. */
                        for (i = 0; i < argc - optind; i++)
-                               benchmark_cmd[i] = argv[i + optind];
-                       benchmark_cmd[i] = NULL;
+                               uparams.benchmark_cmd[i] = argv[i + optind];
+                       uparams.benchmark_cmd[i] = NULL;
 
                        goto last_arg;
                case 't':
                        token = strtok(optarg, ",");
 
-                       mbm_test = false;
-                       mba_test = false;
-                       cmt_test = false;
-                       cat_test = false;
+                       if (!test_param_seen) {
+                               for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++)
+                                       resctrl_tests[i]->disabled = true;
+                               tests = 0;
+                               test_param_seen = true;
+                       }
                        while (token) {
-                               if (!strncmp(token, MBM_STR, sizeof(MBM_STR))) {
-                                       mbm_test = true;
-                                       tests++;
-                               } else if (!strncmp(token, MBA_STR, sizeof(MBA_STR))) {
-                                       mba_test = true;
-                                       tests++;
-                               } else if (!strncmp(token, CMT_STR, sizeof(CMT_STR))) {
-                                       cmt_test = true;
-                                       tests++;
-                               } else if (!strncmp(token, CAT_STR, sizeof(CAT_STR))) {
-                                       cat_test = true;
-                                       tests++;
-                               } else {
-                                       printf("invalid argument\n");
+                               bool found = false;
+
+                               for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++) {
+                                       if (!strcasecmp(token, resctrl_tests[i]->name) ||
+                                           (resctrl_tests[i]->group &&
+                                            !strcasecmp(token, resctrl_tests[i]->group))) {
+                                               if (resctrl_tests[i]->disabled)
+                                                       tests++;
+                                               resctrl_tests[i]->disabled = false;
+                                               found = true;
+                                       }
+                               }
+
+                               if (!found) {
+                                       printf("invalid test: %s\n", token);
 
                                        return -1;
                                }
@@ -252,11 +224,11 @@ int main(int argc, char **argv)
                        }
                        break;
                case 'p':
-                       cpu_no = atoi(optarg);
+                       uparams.cpu = atoi(optarg);
                        break;
                case 'n':
-                       no_of_bits = atoi(optarg);
-                       if (no_of_bits <= 0) {
+                       uparams.bits = atoi(optarg);
+                       if (uparams.bits <= 0) {
                                printf("Bail out! invalid argument for no_of_bits\n");
                                return -1;
                        }
@@ -291,32 +263,23 @@ last_arg:
 
        filter_dmesg();
 
-       if (!benchmark_cmd[0]) {
+       if (!uparams.benchmark_cmd[0]) {
                /* If no benchmark is given by "-b" argument, use fill_buf. */
-               benchmark_cmd[0] = "fill_buf";
+               uparams.benchmark_cmd[0] = "fill_buf";
                ret = asprintf(&span_str, "%u", DEFAULT_SPAN);
                if (ret < 0)
                        ksft_exit_fail_msg("Out of memory!\n");
-               benchmark_cmd[1] = span_str;
-               benchmark_cmd[2] = "1";
-               benchmark_cmd[3] = "0";
-               benchmark_cmd[4] = "false";
-               benchmark_cmd[5] = NULL;
+               uparams.benchmark_cmd[1] = span_str;
+               uparams.benchmark_cmd[2] = "1";
+               uparams.benchmark_cmd[3] = "0";
+               uparams.benchmark_cmd[4] = "false";
+               uparams.benchmark_cmd[5] = NULL;
        }
 
-       ksft_set_plan(tests ? : 4);
-
-       if (mbm_test)
-               run_mbm_test(benchmark_cmd, cpu_no);
-
-       if (mba_test)
-               run_mba_test(benchmark_cmd, cpu_no);
-
-       if (cmt_test)
-               run_cmt_test(benchmark_cmd, cpu_no);
+       ksft_set_plan(tests);
 
-       if (cat_test)
-               run_cat_test(cpu_no, no_of_bits);
+       for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++)
+               run_single_test(resctrl_tests[i], &uparams);
 
        free(span_str);
        ksft_finished();
index 88789678917b6b9d799bd7ee54f4e9c9ecf7d311..5a49f07a6c857daee0d8639880bafb77af3acf6e 100644 (file)
@@ -156,12 +156,12 @@ static int read_from_imc_dir(char *imc_dir, int count)
        sprintf(imc_counter_type, "%s%s", imc_dir, "type");
        fp = fopen(imc_counter_type, "r");
        if (!fp) {
-               perror("Failed to open imc counter type file");
+               ksft_perror("Failed to open iMC counter type file");
 
                return -1;
        }
        if (fscanf(fp, "%u", &imc_counters_config[count][READ].type) <= 0) {
-               perror("Could not get imc type");
+               ksft_perror("Could not get iMC type");
                fclose(fp);
 
                return -1;
@@ -175,12 +175,12 @@ static int read_from_imc_dir(char *imc_dir, int count)
        sprintf(imc_counter_cfg, "%s%s", imc_dir, READ_FILE_NAME);
        fp = fopen(imc_counter_cfg, "r");
        if (!fp) {
-               perror("Failed to open imc config file");
+               ksft_perror("Failed to open iMC config file");
 
                return -1;
        }
        if (fscanf(fp, "%s", cas_count_cfg) <= 0) {
-               perror("Could not get imc cas count read");
+               ksft_perror("Could not get iMC cas count read");
                fclose(fp);
 
                return -1;
@@ -193,12 +193,12 @@ static int read_from_imc_dir(char *imc_dir, int count)
        sprintf(imc_counter_cfg, "%s%s", imc_dir, WRITE_FILE_NAME);
        fp = fopen(imc_counter_cfg, "r");
        if (!fp) {
-               perror("Failed to open imc config file");
+               ksft_perror("Failed to open iMC config file");
 
                return -1;
        }
        if  (fscanf(fp, "%s", cas_count_cfg) <= 0) {
-               perror("Could not get imc cas count write");
+               ksft_perror("Could not get iMC cas count write");
                fclose(fp);
 
                return -1;
@@ -262,12 +262,12 @@ static int num_of_imcs(void)
                }
                closedir(dp);
                if (count == 0) {
-                       perror("Unable find iMC counters!\n");
+                       ksft_print_msg("Unable to find iMC counters\n");
 
                        return -1;
                }
        } else {
-               perror("Unable to open PMU directory!\n");
+               ksft_perror("Unable to open PMU directory");
 
                return -1;
        }
@@ -339,14 +339,14 @@ static int get_mem_bw_imc(int cpu_no, char *bw_report, float *bw_imc)
 
                if (read(r->fd, &r->return_value,
                         sizeof(struct membw_read_format)) == -1) {
-                       perror("Couldn't get read b/w through iMC");
+                       ksft_perror("Couldn't get read b/w through iMC");
 
                        return -1;
                }
 
                if (read(w->fd, &w->return_value,
                         sizeof(struct membw_read_format)) == -1) {
-                       perror("Couldn't get write bw through iMC");
+                       ksft_perror("Couldn't get write bw through iMC");
 
                        return -1;
                }
@@ -387,20 +387,20 @@ static int get_mem_bw_imc(int cpu_no, char *bw_report, float *bw_imc)
        return 0;
 }
 
-void set_mbm_path(const char *ctrlgrp, const char *mongrp, int resource_id)
+void set_mbm_path(const char *ctrlgrp, const char *mongrp, int domain_id)
 {
        if (ctrlgrp && mongrp)
                sprintf(mbm_total_path, CON_MON_MBM_LOCAL_BYTES_PATH,
-                       RESCTRL_PATH, ctrlgrp, mongrp, resource_id);
+                       RESCTRL_PATH, ctrlgrp, mongrp, domain_id);
        else if (!ctrlgrp && mongrp)
                sprintf(mbm_total_path, MON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
-                       mongrp, resource_id);
+                       mongrp, domain_id);
        else if (ctrlgrp && !mongrp)
                sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
-                       ctrlgrp, resource_id);
+                       ctrlgrp, domain_id);
        else if (!ctrlgrp && !mongrp)
                sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
-                       resource_id);
+                       domain_id);
 }
 
 /*
@@ -413,23 +413,23 @@ void set_mbm_path(const char *ctrlgrp, const char *mongrp, int resource_id)
 static void initialize_mem_bw_resctrl(const char *ctrlgrp, const char *mongrp,
                                      int cpu_no, char *resctrl_val)
 {
-       int resource_id;
+       int domain_id;
 
-       if (get_resource_id(cpu_no, &resource_id) < 0) {
-               perror("Could not get resource_id");
+       if (get_domain_id("MB", cpu_no, &domain_id) < 0) {
+               ksft_print_msg("Could not get domain ID\n");
                return;
        }
 
        if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)))
-               set_mbm_path(ctrlgrp, mongrp, resource_id);
+               set_mbm_path(ctrlgrp, mongrp, domain_id);
 
        if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
                if (ctrlgrp)
                        sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH,
-                               RESCTRL_PATH, ctrlgrp, resource_id);
+                               RESCTRL_PATH, ctrlgrp, domain_id);
                else
                        sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH,
-                               RESCTRL_PATH, resource_id);
+                               RESCTRL_PATH, domain_id);
        }
 }
 
@@ -449,12 +449,12 @@ static int get_mem_bw_resctrl(unsigned long *mbm_total)
 
        fp = fopen(mbm_total_path, "r");
        if (!fp) {
-               perror("Failed to open total bw file");
+               ksft_perror("Failed to open total bw file");
 
                return -1;
        }
        if (fscanf(fp, "%lu", mbm_total) <= 0) {
-               perror("Could not get mbm local bytes");
+               ksft_perror("Could not get mbm local bytes");
                fclose(fp);
 
                return -1;
@@ -495,7 +495,7 @@ int signal_handler_register(void)
        if (sigaction(SIGINT, &sigact, NULL) ||
            sigaction(SIGTERM, &sigact, NULL) ||
            sigaction(SIGHUP, &sigact, NULL)) {
-               perror("# sigaction");
+               ksft_perror("sigaction");
                ret = -1;
        }
        return ret;
@@ -515,7 +515,7 @@ void signal_handler_unregister(void)
        if (sigaction(SIGINT, &sigact, NULL) ||
            sigaction(SIGTERM, &sigact, NULL) ||
            sigaction(SIGHUP, &sigact, NULL)) {
-               perror("# sigaction");
+               ksft_perror("sigaction");
        }
 }
 
@@ -526,7 +526,7 @@ void signal_handler_unregister(void)
  * @bw_imc:            perf imc counter value
  * @bw_resc:           memory bandwidth value
  *
- * Return:             0 on success. non-zero on failure.
+ * Return:             0 on success, < 0 on error.
  */
 static int print_results_bw(char *filename,  int bm_pid, float bw_imc,
                            unsigned long bw_resc)
@@ -540,16 +540,16 @@ static int print_results_bw(char *filename,  int bm_pid, float bw_imc,
        } else {
                fp = fopen(filename, "a");
                if (!fp) {
-                       perror("Cannot open results file");
+                       ksft_perror("Cannot open results file");
 
-                       return errno;
+                       return -1;
                }
                if (fprintf(fp, "Pid: %d \t Mem_BW_iMC: %f \t Mem_BW_resc: %lu \t Difference: %lu\n",
                            bm_pid, bw_imc, bw_resc, diff) <= 0) {
+                       ksft_print_msg("Could not log results\n");
                        fclose(fp);
-                       perror("Could not log results.");
 
-                       return errno;
+                       return -1;
                }
                fclose(fp);
        }
@@ -582,19 +582,20 @@ static void set_cmt_path(const char *ctrlgrp, const char *mongrp, char sock_num)
 static void initialize_llc_occu_resctrl(const char *ctrlgrp, const char *mongrp,
                                        int cpu_no, char *resctrl_val)
 {
-       int resource_id;
+       int domain_id;
 
-       if (get_resource_id(cpu_no, &resource_id) < 0) {
-               perror("# Unable to resource_id");
+       if (get_domain_id("L3", cpu_no, &domain_id) < 0) {
+               ksft_print_msg("Could not get domain ID\n");
                return;
        }
 
        if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
-               set_cmt_path(ctrlgrp, mongrp, resource_id);
+               set_cmt_path(ctrlgrp, mongrp, domain_id);
 }
 
-static int
-measure_vals(struct resctrl_val_param *param, unsigned long *bw_resc_start)
+static int measure_vals(const struct user_params *uparams,
+                       struct resctrl_val_param *param,
+                       unsigned long *bw_resc_start)
 {
        unsigned long bw_resc, bw_resc_end;
        float bw_imc;
@@ -607,7 +608,7 @@ measure_vals(struct resctrl_val_param *param, unsigned long *bw_resc_start)
         * Compare the two values to validate resctrl value.
         * It takes 1sec to measure the data.
         */
-       ret = get_mem_bw_imc(param->cpu_no, param->bw_report, &bw_imc);
+       ret = get_mem_bw_imc(uparams->cpu, param->bw_report, &bw_imc);
        if (ret < 0)
                return ret;
 
@@ -647,20 +648,24 @@ static void run_benchmark(int signum, siginfo_t *info, void *ucontext)
         * stdio (console)
         */
        fp = freopen("/dev/null", "w", stdout);
-       if (!fp)
-               PARENT_EXIT("Unable to direct benchmark status to /dev/null");
+       if (!fp) {
+               ksft_perror("Unable to direct benchmark status to /dev/null");
+               PARENT_EXIT();
+       }
 
        if (strcmp(benchmark_cmd[0], "fill_buf") == 0) {
                /* Execute default fill_buf benchmark */
                span = strtoul(benchmark_cmd[1], NULL, 10);
                memflush =  atoi(benchmark_cmd[2]);
                operation = atoi(benchmark_cmd[3]);
-               if (!strcmp(benchmark_cmd[4], "true"))
+               if (!strcmp(benchmark_cmd[4], "true")) {
                        once = true;
-               else if (!strcmp(benchmark_cmd[4], "false"))
+               } else if (!strcmp(benchmark_cmd[4], "false")) {
                        once = false;
-               else
-                       PARENT_EXIT("Invalid once parameter");
+               } else {
+                       ksft_print_msg("Invalid once parameter\n");
+                       PARENT_EXIT();
+               }
 
                if (run_fill_buf(span, memflush, operation, once))
                        fprintf(stderr, "Error in running fill buffer\n");
@@ -668,22 +673,28 @@ static void run_benchmark(int signum, siginfo_t *info, void *ucontext)
                /* Execute specified benchmark */
                ret = execvp(benchmark_cmd[0], benchmark_cmd);
                if (ret)
-                       perror("wrong\n");
+                       ksft_perror("execvp");
        }
 
        fclose(stdout);
-       PARENT_EXIT("Unable to run specified benchmark");
+       ksft_print_msg("Unable to run specified benchmark\n");
+       PARENT_EXIT();
 }
 
 /*
  * resctrl_val:        execute benchmark and measure memory bandwidth on
  *                     the benchmark
+ * @test:              test information structure
+ * @uparams:           user supplied parameters
  * @benchmark_cmd:     benchmark command and its arguments
  * @param:             parameters passed to resctrl_val()
  *
- * Return:             0 on success. non-zero on failure.
+ * Return:             0 when the test was run, < 0 on error.
  */
-int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *param)
+int resctrl_val(const struct resctrl_test *test,
+               const struct user_params *uparams,
+               const char * const *benchmark_cmd,
+               struct resctrl_val_param *param)
 {
        char *resctrl_val = param->resctrl_val;
        unsigned long bw_resc_start = 0;
@@ -709,7 +720,7 @@ int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *par
        ppid = getpid();
 
        if (pipe(pipefd)) {
-               perror("# Unable to create pipe");
+               ksft_perror("Unable to create pipe");
 
                return -1;
        }
@@ -721,7 +732,7 @@ int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *par
        fflush(stdout);
        bm_pid = fork();
        if (bm_pid == -1) {
-               perror("# Unable to fork");
+               ksft_perror("Unable to fork");
 
                return -1;
        }
@@ -738,15 +749,17 @@ int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *par
                sigact.sa_flags = SA_SIGINFO;
 
                /* Register for "SIGUSR1" signal from parent */
-               if (sigaction(SIGUSR1, &sigact, NULL))
-                       PARENT_EXIT("Can't register child for signal");
+               if (sigaction(SIGUSR1, &sigact, NULL)) {
+                       ksft_perror("Can't register child for signal");
+                       PARENT_EXIT();
+               }
 
                /* Tell parent that child is ready */
                close(pipefd[0]);
                pipe_message = 1;
                if (write(pipefd[1], &pipe_message, sizeof(pipe_message)) <
                    sizeof(pipe_message)) {
-                       perror("# failed signaling parent process");
+                       ksft_perror("Failed signaling parent process");
                        close(pipefd[1]);
                        return -1;
                }
@@ -755,7 +768,8 @@ int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *par
                /* Suspend child until delivery of "SIGUSR1" from parent */
                sigsuspend(&sigact.sa_mask);
 
-               PARENT_EXIT("Child is done");
+               ksft_perror("Child is done");
+               PARENT_EXIT();
        }
 
        ksft_print_msg("Benchmark PID: %d\n", bm_pid);
@@ -769,7 +783,7 @@ int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *par
        value.sival_ptr = (void *)benchmark_cmd;
 
        /* Taskset benchmark to specified cpu */
-       ret = taskset_benchmark(bm_pid, param->cpu_no);
+       ret = taskset_benchmark(bm_pid, uparams->cpu, NULL);
        if (ret)
                goto out;
 
@@ -786,17 +800,17 @@ int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *par
                        goto out;
 
                initialize_mem_bw_resctrl(param->ctrlgrp, param->mongrp,
-                                         param->cpu_no, resctrl_val);
+                                         uparams->cpu, resctrl_val);
        } else if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
                initialize_llc_occu_resctrl(param->ctrlgrp, param->mongrp,
-                                           param->cpu_no, resctrl_val);
+                                           uparams->cpu, resctrl_val);
 
        /* Parent waits for child to be ready. */
        close(pipefd[1]);
        while (pipe_message != 1) {
                if (read(pipefd[0], &pipe_message, sizeof(pipe_message)) <
                    sizeof(pipe_message)) {
-                       perror("# failed reading message from child process");
+                       ksft_perror("Failed reading message from child process");
                        close(pipefd[0]);
                        goto out;
                }
@@ -805,8 +819,8 @@ int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *par
 
        /* Signal child to start benchmark */
        if (sigqueue(bm_pid, SIGUSR1, value) == -1) {
-               perror("# sigqueue SIGUSR1 to child");
-               ret = errno;
+               ksft_perror("sigqueue SIGUSR1 to child");
+               ret = -1;
                goto out;
        }
 
@@ -815,7 +829,7 @@ int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *par
 
        /* Test runs until the callback setup() tells the test to stop. */
        while (1) {
-               ret = param->setup(param);
+               ret = param->setup(test, uparams, param);
                if (ret == END_OF_TESTS) {
                        ret = 0;
                        break;
@@ -825,12 +839,12 @@ int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *par
 
                if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) ||
                    !strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
-                       ret = measure_vals(param, &bw_resc_start);
+                       ret = measure_vals(uparams, param, &bw_resc_start);
                        if (ret)
                                break;
                } else if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) {
                        sleep(1);
-                       ret = measure_cache_vals(param, bm_pid);
+                       ret = measure_llc_resctrl(param->filename, bm_pid);
                        if (ret)
                                break;
                }
index 5ebd436838769561bfd426a8b9c398347dc210e5..1cade75176eb1d01bf43113414e24a5d7b3190fa 100644 (file)
@@ -20,7 +20,7 @@ static int find_resctrl_mount(char *buffer)
 
        mounts = fopen("/proc/mounts", "r");
        if (!mounts) {
-               perror("/proc/mounts");
+               ksft_perror("/proc/mounts");
                return -ENXIO;
        }
        while (!feof(mounts)) {
@@ -56,7 +56,7 @@ static int find_resctrl_mount(char *buffer)
  * Mounts resctrl FS. Fails if resctrl FS is already mounted to avoid
  * pre-existing settings interfering with the test results.
  *
- * Return: 0 on success, non-zero on failure
+ * Return: 0 on success, < 0 on error.
  */
 int mount_resctrlfs(void)
 {
@@ -69,7 +69,7 @@ int mount_resctrlfs(void)
        ksft_print_msg("Mounting resctrl to \"%s\"\n", RESCTRL_PATH);
        ret = mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL);
        if (ret)
-               perror("# mount");
+               ksft_perror("mount");
 
        return ret;
 }
@@ -86,41 +86,67 @@ int umount_resctrlfs(void)
                return ret;
 
        if (umount(mountpoint)) {
-               perror("# Unable to umount resctrl");
+               ksft_perror("Unable to umount resctrl");
 
-               return errno;
+               return -1;
        }
 
        return 0;
 }
 
 /*
- * get_resource_id - Get socket number/l3 id for a specified CPU
+ * get_cache_level - Convert cache level from string to integer
+ * @cache_type:                Cache level as string
+ *
+ * Return: cache level as integer or -1 if @cache_type is invalid.
+ */
+static int get_cache_level(const char *cache_type)
+{
+       if (!strcmp(cache_type, "L3"))
+               return 3;
+       if (!strcmp(cache_type, "L2"))
+               return 2;
+
+       ksft_print_msg("Invalid cache level\n");
+       return -1;
+}
+
+static int get_resource_cache_level(const char *resource)
+{
+       /* "MB" use L3 (LLC) as resource */
+       if (!strcmp(resource, "MB"))
+               return 3;
+       return get_cache_level(resource);
+}
+
+/*
+ * get_domain_id - Get resctrl domain ID for a specified CPU
+ * @resource:  resource name
  * @cpu_no:    CPU number
- * @resource_id: Socket number or l3_id
+ * @domain_id: domain ID (cache ID; for MB, L3 cache ID)
  *
  * Return: >= 0 on success, < 0 on failure.
  */
-int get_resource_id(int cpu_no, int *resource_id)
+int get_domain_id(const char *resource, int cpu_no, int *domain_id)
 {
        char phys_pkg_path[1024];
+       int cache_num;
        FILE *fp;
 
-       if (get_vendor() == ARCH_AMD)
-               sprintf(phys_pkg_path, "%s%d/cache/index3/id",
-                       PHYS_ID_PATH, cpu_no);
-       else
-               sprintf(phys_pkg_path, "%s%d/topology/physical_package_id",
-                       PHYS_ID_PATH, cpu_no);
+       cache_num = get_resource_cache_level(resource);
+       if (cache_num < 0)
+               return cache_num;
+
+       sprintf(phys_pkg_path, "%s%d/cache/index%d/id", PHYS_ID_PATH, cpu_no, cache_num);
 
        fp = fopen(phys_pkg_path, "r");
        if (!fp) {
-               perror("Failed to open physical_package_id");
+               ksft_perror("Failed to open cache id file");
 
                return -1;
        }
-       if (fscanf(fp, "%d", resource_id) <= 0) {
-               perror("Could not get socket number or l3 id");
+       if (fscanf(fp, "%d", domain_id) <= 0) {
+               ksft_perror("Could not get domain ID");
                fclose(fp);
 
                return -1;
@@ -138,31 +164,26 @@ int get_resource_id(int cpu_no, int *resource_id)
  *
  * Return: = 0 on success, < 0 on failure.
  */
-int get_cache_size(int cpu_no, char *cache_type, unsigned long *cache_size)
+int get_cache_size(int cpu_no, const char *cache_type, unsigned long *cache_size)
 {
        char cache_path[1024], cache_str[64];
        int length, i, cache_num;
        FILE *fp;
 
-       if (!strcmp(cache_type, "L3")) {
-               cache_num = 3;
-       } else if (!strcmp(cache_type, "L2")) {
-               cache_num = 2;
-       } else {
-               perror("Invalid cache level");
-               return -1;
-       }
+       cache_num = get_cache_level(cache_type);
+       if (cache_num < 0)
+               return cache_num;
 
        sprintf(cache_path, "/sys/bus/cpu/devices/cpu%d/cache/index%d/size",
                cpu_no, cache_num);
        fp = fopen(cache_path, "r");
        if (!fp) {
-               perror("Failed to open cache size");
+               ksft_perror("Failed to open cache size");
 
                return -1;
        }
        if (fscanf(fp, "%s", cache_str) <= 0) {
-               perror("Could not get cache_size");
+               ksft_perror("Could not get cache_size");
                fclose(fp);
 
                return -1;
@@ -196,30 +217,29 @@ int get_cache_size(int cpu_no, char *cache_type, unsigned long *cache_size)
 #define CORE_SIBLINGS_PATH     "/sys/bus/cpu/devices/cpu"
 
 /*
- * get_cbm_mask - Get cbm mask for given cache
- * @cache_type:        Cache level L2/L3
- * @cbm_mask:  cbm_mask returned as a string
+ * get_bit_mask - Get bit mask from given file
+ * @filename:  File containing the mask
+ * @mask:      The bit mask returned as unsigned long
  *
  * Return: = 0 on success, < 0 on failure.
  */
-int get_cbm_mask(char *cache_type, char *cbm_mask)
+static int get_bit_mask(const char *filename, unsigned long *mask)
 {
-       char cbm_mask_path[1024];
        FILE *fp;
 
-       if (!cbm_mask)
+       if (!filename || !mask)
                return -1;
 
-       sprintf(cbm_mask_path, "%s/%s/cbm_mask", INFO_PATH, cache_type);
-
-       fp = fopen(cbm_mask_path, "r");
+       fp = fopen(filename, "r");
        if (!fp) {
-               perror("Failed to open cache level");
-
+               ksft_print_msg("Failed to open bit mask file '%s': %s\n",
+                              filename, strerror(errno));
                return -1;
        }
-       if (fscanf(fp, "%s", cbm_mask) <= 0) {
-               perror("Could not get max cbm_mask");
+
+       if (fscanf(fp, "%lx", mask) <= 0) {
+               ksft_print_msg("Could not read bit mask file '%s': %s\n",
+                              filename, strerror(errno));
                fclose(fp);
 
                return -1;
@@ -230,64 +250,200 @@ int get_cbm_mask(char *cache_type, char *cbm_mask)
 }
 
 /*
- * get_core_sibling - Get sibling core id from the same socket for given CPU
- * @cpu_no:    CPU number
+ * resource_info_unsigned_get - Read an unsigned value from
+ * /sys/fs/resctrl/info/@resource/@filename
+ * @resource:  Resource name that matches directory name in
+ *             /sys/fs/resctrl/info
+ * @filename:  File in /sys/fs/resctrl/info/@resource
+ * @val:       Contains read value on success.
  *
- * Return:     > 0 on success, < 0 on failure.
+ * Return: = 0 on success, < 0 on failure. On success the read
+ * value is saved into @val.
  */
-int get_core_sibling(int cpu_no)
+int resource_info_unsigned_get(const char *resource, const char *filename,
+                              unsigned int *val)
 {
-       char core_siblings_path[1024], cpu_list_str[64];
-       int sibling_cpu_no = -1;
+       char file_path[PATH_MAX];
        FILE *fp;
 
-       sprintf(core_siblings_path, "%s%d/topology/core_siblings_list",
-               CORE_SIBLINGS_PATH, cpu_no);
+       snprintf(file_path, sizeof(file_path), "%s/%s/%s", INFO_PATH, resource,
+                filename);
 
-       fp = fopen(core_siblings_path, "r");
+       fp = fopen(file_path, "r");
        if (!fp) {
-               perror("Failed to open core siblings path");
-
+               ksft_print_msg("Error opening %s: %m\n", file_path);
                return -1;
        }
-       if (fscanf(fp, "%s", cpu_list_str) <= 0) {
-               perror("Could not get core_siblings list");
-               fclose(fp);
 
+       if (fscanf(fp, "%u", val) <= 0) {
+               ksft_print_msg("Could not get contents of %s: %m\n", file_path);
+               fclose(fp);
                return -1;
        }
+
        fclose(fp);
+       return 0;
+}
 
-       char *token = strtok(cpu_list_str, "-,");
+/*
+ * create_bit_mask- Create bit mask from start, len pair
+ * @start:     LSB of the mask
+ * @len                Number of bits in the mask
+ */
+unsigned long create_bit_mask(unsigned int start, unsigned int len)
+{
+       return ((1UL << len) - 1UL) << start;
+}
 
-       while (token) {
-               sibling_cpu_no = atoi(token);
-               /* Skipping core 0 as we don't want to run test on core 0 */
-               if (sibling_cpu_no != 0 && sibling_cpu_no != cpu_no)
-                       break;
-               token = strtok(NULL, "-,");
+/*
+ * count_contiguous_bits - Returns the longest train of bits in a bit mask
+ * @val                A bit mask
+ * @start      The location of the least-significant bit of the longest train
+ *
+ * Return:     The length of the contiguous bits in the longest train of bits
+ */
+unsigned int count_contiguous_bits(unsigned long val, unsigned int *start)
+{
+       unsigned long last_val;
+       unsigned int count = 0;
+
+       while (val) {
+               last_val = val;
+               val &= (val >> 1);
+               count++;
+       }
+
+       if (start) {
+               if (count)
+                       *start = ffsl(last_val) - 1;
+               else
+                       *start = 0;
        }
 
-       return sibling_cpu_no;
+       return count;
+}
+
+/*
+ * get_full_cbm - Get full Cache Bit Mask (CBM)
+ * @cache_type:        Cache type as "L2" or "L3"
+ * @mask:      Full cache bit mask representing the maximal portion of cache
+ *             available for allocation, returned as unsigned long.
+ *
+ * Return: = 0 on success, < 0 on failure.
+ */
+int get_full_cbm(const char *cache_type, unsigned long *mask)
+{
+       char cbm_path[PATH_MAX];
+       int ret;
+
+       if (!cache_type)
+               return -1;
+
+       snprintf(cbm_path, sizeof(cbm_path), "%s/%s/cbm_mask",
+                INFO_PATH, cache_type);
+
+       ret = get_bit_mask(cbm_path, mask);
+       if (ret || !*mask)
+               return -1;
+
+       return 0;
+}
+
+/*
+ * get_shareable_mask - Get shareable mask from shareable_bits
+ * @cache_type:                Cache type as "L2" or "L3"
+ * @shareable_mask:    Shareable mask returned as unsigned long
+ *
+ * Return: = 0 on success, < 0 on failure.
+ */
+static int get_shareable_mask(const char *cache_type, unsigned long *shareable_mask)
+{
+       char mask_path[PATH_MAX];
+
+       if (!cache_type)
+               return -1;
+
+       snprintf(mask_path, sizeof(mask_path), "%s/%s/shareable_bits",
+                INFO_PATH, cache_type);
+
+       return get_bit_mask(mask_path, shareable_mask);
+}
+
+/*
+ * get_mask_no_shareable - Get Cache Bit Mask (CBM) without shareable bits
+ * @cache_type:                Cache type as "L2" or "L3"
+ * @mask:              The largest exclusive portion of the cache out of the
+ *                     full CBM, returned as unsigned long
+ *
+ * Parts of a cache may be shared with other devices such as GPU. This function
+ * calculates the largest exclusive portion of the cache where no other devices
+ * besides CPU have access to the cache portion.
+ *
+ * Return: = 0 on success, < 0 on failure.
+ */
+int get_mask_no_shareable(const char *cache_type, unsigned long *mask)
+{
+       unsigned long full_mask, shareable_mask;
+       unsigned int start, len;
+
+       if (get_full_cbm(cache_type, &full_mask) < 0)
+               return -1;
+       if (get_shareable_mask(cache_type, &shareable_mask) < 0)
+               return -1;
+
+       len = count_contiguous_bits(full_mask & ~shareable_mask, &start);
+       if (!len)
+               return -1;
+
+       *mask = create_bit_mask(start, len);
+
+       return 0;
 }
 
 /*
  * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu
- * @bm_pid:    PID that should be binded
- * @cpu_no:    CPU number at which the PID would be binded
+ * @bm_pid:            PID that should be binded
+ * @cpu_no:            CPU number at which the PID would be binded
+ * @old_affinity:      When not NULL, set to old CPU affinity
  *
- * Return: 0 on success, non-zero on failure
+ * Return: 0 on success, < 0 on error.
  */
-int taskset_benchmark(pid_t bm_pid, int cpu_no)
+int taskset_benchmark(pid_t bm_pid, int cpu_no, cpu_set_t *old_affinity)
 {
        cpu_set_t my_set;
 
+       if (old_affinity) {
+               CPU_ZERO(old_affinity);
+               if (sched_getaffinity(bm_pid, sizeof(*old_affinity),
+                                     old_affinity)) {
+                       ksft_perror("Unable to read CPU affinity");
+                       return -1;
+               }
+       }
+
        CPU_ZERO(&my_set);
        CPU_SET(cpu_no, &my_set);
 
        if (sched_setaffinity(bm_pid, sizeof(cpu_set_t), &my_set)) {
-               perror("Unable to taskset benchmark");
+               ksft_perror("Unable to taskset benchmark");
+
+               return -1;
+       }
+
+       return 0;
+}
 
+/*
+ * taskset_restore - Taskset PID to the earlier CPU affinity
+ * @bm_pid:            PID that should be reset
+ * @old_affinity:      The old CPU affinity to restore
+ *
+ * Return: 0 on success, < 0 on error.
+ */
+int taskset_restore(pid_t bm_pid, cpu_set_t *old_affinity)
+{
+       if (sched_setaffinity(bm_pid, sizeof(*old_affinity), old_affinity)) {
+               ksft_perror("Unable to restore CPU affinity");
                return -1;
        }
 
@@ -300,7 +456,7 @@ int taskset_benchmark(pid_t bm_pid, int cpu_no)
  * @grp:       Full path and name of the group
  * @parent_grp:        Full path and name of the parent group
  *
- * Return: 0 on success, non-zero on failure
+ * Return: 0 on success, < 0 on error.
  */
 static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
 {
@@ -325,7 +481,7 @@ static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
                }
                closedir(dp);
        } else {
-               perror("Unable to open resctrl for group");
+               ksft_perror("Unable to open resctrl for group");
 
                return -1;
        }
@@ -333,7 +489,7 @@ static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
        /* Requested grp doesn't exist, hence create it */
        if (found_grp == 0) {
                if (mkdir(grp, 0) == -1) {
-                       perror("Unable to create group");
+                       ksft_perror("Unable to create group");
 
                        return -1;
                }
@@ -348,12 +504,12 @@ static int write_pid_to_tasks(char *tasks, pid_t pid)
 
        fp = fopen(tasks, "w");
        if (!fp) {
-               perror("Failed to open tasks file");
+               ksft_perror("Failed to open tasks file");
 
                return -1;
        }
        if (fprintf(fp, "%d\n", pid) < 0) {
-               perror("Failed to wr pid to tasks file");
+               ksft_print_msg("Failed to write pid to tasks file\n");
                fclose(fp);
 
                return -1;
@@ -376,7 +532,7 @@ static int write_pid_to_tasks(char *tasks, pid_t pid)
  * pid is not written, this means that pid is in con_mon grp and hence
  * should consult con_mon grp's mon_data directory for results.
  *
- * Return: 0 on success, non-zero on failure
+ * Return: 0 on success, < 0 on error.
  */
 int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
                            char *resctrl_val)
@@ -420,7 +576,7 @@ int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
 out:
        ksft_print_msg("Writing benchmark parameters to resctrl FS\n");
        if (ret)
-               perror("# writing to resctrlfs");
+               ksft_print_msg("Failed writing to resctrlfs\n");
 
        return ret;
 }
@@ -430,23 +586,17 @@ out:
  * @ctrlgrp:           Name of the con_mon grp
  * @schemata:          Schemata that should be updated to
  * @cpu_no:            CPU number that the benchmark PID is binded to
- * @resctrl_val:       Resctrl feature (Eg: mbm, mba.. etc)
+ * @resource:          Resctrl resource (Eg: MB, L3, L2, etc.)
  *
- * Update schemata of a con_mon grp *only* if requested resctrl feature is
+ * Update schemata of a con_mon grp *only* if requested resctrl resource is
  * allocation type
  *
- * Return: 0 on success, non-zero on failure
+ * Return: 0 on success, < 0 on error.
  */
-int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
+int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, const char *resource)
 {
        char controlgroup[1024], reason[128], schema[1024] = {};
-       int resource_id, fd, schema_len = -1, ret = 0;
-
-       if (strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)) &&
-           strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) &&
-           strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)) &&
-           strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
-               return -ENOENT;
+       int domain_id, fd, schema_len, ret = 0;
 
        if (!schemata) {
                ksft_print_msg("Skipping empty schemata update\n");
@@ -454,8 +604,8 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
                return -1;
        }
 
-       if (get_resource_id(cpu_no, &resource_id) < 0) {
-               sprintf(reason, "Failed to get resource id");
+       if (get_domain_id(resource, cpu_no, &domain_id) < 0) {
+               sprintf(reason, "Failed to get domain ID");
                ret = -1;
 
                goto out;
@@ -466,14 +616,8 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
        else
                sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
 
-       if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)) ||
-           !strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
-               schema_len = snprintf(schema, sizeof(schema), "%s%d%c%s\n",
-                                     "L3:", resource_id, '=', schemata);
-       if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)) ||
-           !strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)))
-               schema_len = snprintf(schema, sizeof(schema), "%s%d%c%s\n",
-                                     "MB:", resource_id, '=', schemata);
+       schema_len = snprintf(schema, sizeof(schema), "%s:%d=%s\n",
+                             resource, domain_id, schemata);
        if (schema_len < 0 || schema_len >= sizeof(schema)) {
                snprintf(reason, sizeof(reason),
                         "snprintf() failed with return value : %d", schema_len);
@@ -564,20 +708,16 @@ char *fgrep(FILE *inf, const char *str)
 }
 
 /*
- * validate_resctrl_feature_request - Check if requested feature is valid.
- * @resource:  Required resource (e.g., MB, L3, L2, L3_MON, etc.)
- * @feature:   Required monitor feature (in mon_features file). Can only be
- *             set for L3_MON. Must be NULL for all other resources.
+ * resctrl_resource_exists - Check if a resource is supported.
+ * @resource:  Resctrl resource (e.g., MB, L3, L2, L3_MON, etc.)
  *
- * Return: True if the resource/feature is supported, else false. False is
+ * Return: True if the resource is supported, else false. False is
  *         also returned if resctrl FS is not mounted.
  */
-bool validate_resctrl_feature_request(const char *resource, const char *feature)
+bool resctrl_resource_exists(const char *resource)
 {
        char res_path[PATH_MAX];
        struct stat statbuf;
-       char *res;
-       FILE *inf;
        int ret;
 
        if (!resource)
@@ -592,8 +732,25 @@ bool validate_resctrl_feature_request(const char *resource, const char *feature)
        if (stat(res_path, &statbuf))
                return false;
 
-       if (!feature)
-               return true;
+       return true;
+}
+
+/*
+ * resctrl_mon_feature_exists - Check if requested monitoring feature is valid.
+ * @resource:  Resource that uses the mon_features file. Currently only L3_MON
+ *             is valid.
+ * @feature:   Required monitor feature (in mon_features file).
+ *
+ * Return: True if the feature is supported, else false.
+ */
+bool resctrl_mon_feature_exists(const char *resource, const char *feature)
+{
+       char res_path[PATH_MAX];
+       char *res;
+       FILE *inf;
+
+       if (!feature || !resource)
+               return false;
 
        snprintf(res_path, sizeof(res_path), "%s/%s/mon_features", INFO_PATH, resource);
        inf = fopen(res_path, "r");
@@ -607,6 +764,36 @@ bool validate_resctrl_feature_request(const char *resource, const char *feature)
        return !!res;
 }
 
+/*
+ * resource_info_file_exists - Check if a file is present inside
+ * /sys/fs/resctrl/info/@resource.
+ * @resource:  Required resource (Eg: MB, L3, L2, etc.)
+ * @file:      Required file.
+ *
+ * Return: True if the /sys/fs/resctrl/info/@resource/@file exists, else false.
+ */
+bool resource_info_file_exists(const char *resource, const char *file)
+{
+       char res_path[PATH_MAX];
+       struct stat statbuf;
+
+       if (!file || !resource)
+               return false;
+
+       snprintf(res_path, sizeof(res_path), "%s/%s/%s", INFO_PATH, resource,
+                file);
+
+       if (stat(res_path, &statbuf))
+               return false;
+
+       return true;
+}
+
+bool test_resource_feature_check(const struct resctrl_test *test)
+{
+       return resctrl_resource_exists(test->resource);
+}
+
 int filter_dmesg(void)
 {
        char line[1024];
@@ -617,7 +804,7 @@ int filter_dmesg(void)
 
        ret = pipe(pipefds);
        if (ret) {
-               perror("pipe");
+               ksft_perror("pipe");
                return ret;
        }
        fflush(stdout);
@@ -626,13 +813,13 @@ int filter_dmesg(void)
                close(pipefds[0]);
                dup2(pipefds[1], STDOUT_FILENO);
                execlp("dmesg", "dmesg", NULL);
-               perror("executing dmesg");
+               ksft_perror("Executing dmesg");
                exit(1);
        }
        close(pipefds[1]);
        fp = fdopen(pipefds[0], "r");
        if (!fp) {
-               perror("fdopen(pipe)");
+               ksft_perror("fdopen(pipe)");
                kill(pid, SIGTERM);
 
                return -1;
diff --git a/tools/testing/selftests/rust/Makefile b/tools/testing/selftests/rust/Makefile
new file mode 100644 (file)
index 0000000..fce1584
--- /dev/null
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+TEST_PROGS += test_probe_samples.sh
+
+include ../lib.mk
diff --git a/tools/testing/selftests/rust/config b/tools/testing/selftests/rust/config
new file mode 100644 (file)
index 0000000..b4002ac
--- /dev/null
@@ -0,0 +1,5 @@
+CONFIG_RUST=y
+CONFIG_SAMPLES=y
+CONFIG_SAMPLES_RUST=y
+CONFIG_SAMPLE_RUST_MINIMAL=m
+CONFIG_SAMPLE_RUST_PRINT=m
\ No newline at end of file
diff --git a/tools/testing/selftests/rust/test_probe_samples.sh b/tools/testing/selftests/rust/test_probe_samples.sh
new file mode 100755 (executable)
index 0000000..ad0397e
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2023 Collabora Ltd
+#
+# This script tests whether the rust sample modules can
+# be added and removed correctly.
+#
+DIR="$(dirname "$(readlink -f "$0")")"
+
+KTAP_HELPERS="${DIR}/../kselftest/ktap_helpers.sh"
+if [ -e "$KTAP_HELPERS" ]; then
+    source "$KTAP_HELPERS"
+else
+    echo "$KTAP_HELPERS file not found [SKIP]"
+    exit 4
+fi
+
+rust_sample_modules=("rust_minimal" "rust_print")
+
+ktap_print_header
+
+for sample in "${rust_sample_modules[@]}"; do
+    if ! /sbin/modprobe -n -q "$sample"; then
+        ktap_skip_all "module $sample is not found in /lib/modules/$(uname -r)"
+        exit "$KSFT_SKIP"
+    fi
+done
+
+ktap_set_plan "${#rust_sample_modules[@]}"
+
+for sample in "${rust_sample_modules[@]}"; do
+    if /sbin/modprobe -q "$sample"; then
+        /sbin/modprobe -q -r "$sample"
+        ktap_test_pass "$sample"
+    else
+        ktap_test_fail "$sample"
+    fi
+done
+
+ktap_finished
index 7ba057154343fbdbcef82ca95c3cedfd561866b7..62fba7356af2ef0e8e824209f668ba6e8dce6a62 100644 (file)
@@ -276,7 +276,7 @@ int main(int argc, char *argv[])
        if (setpgid(0, 0) != 0)
                handle_error("process group");
 
-       printf("\n## Create a thread/process/process group hiearchy\n");
+       printf("\n## Create a thread/process/process group hierarchy\n");
        create_processes(num_processes, num_threads, procs);
        need_cleanup = 1;
        disp_processes(num_processes, procs);
diff --git a/tools/testing/selftests/thermal/intel/power_floor/.gitignore b/tools/testing/selftests/thermal/intel/power_floor/.gitignore
new file mode 100644 (file)
index 0000000..1b9a764
--- /dev/null
@@ -0,0 +1 @@
+power_floor_test
diff --git a/tools/testing/selftests/thermal/intel/workload_hint/.gitignore b/tools/testing/selftests/thermal/intel/workload_hint/.gitignore
new file mode 100644 (file)
index 0000000..d697b03
--- /dev/null
@@ -0,0 +1 @@
+workload_hint_test
diff --git a/tools/testing/selftests/uevent/.gitignore b/tools/testing/selftests/uevent/.gitignore
new file mode 100644 (file)
index 0000000..382afb7
--- /dev/null
@@ -0,0 +1 @@
+uevent_filtering
index 2456a399eb9ae1ce2a3c90c10ce1403dd23f62d1..afd18c678ff5a584a92e13ae8ee30bcba90f21ca 100644 (file)
@@ -28,10 +28,15 @@ FOPTS       :=      -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \
                -fasynchronous-unwind-tables -fstack-clash-protection
 WOPTS  :=      -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized
 
+ifeq ($(CC),clang)
+  FOPTS := $(filter-out -ffat-lto-objects, $(FOPTS))
+  WOPTS := $(filter-out -Wno-maybe-uninitialized, $(WOPTS))
+endif
+
 TRACEFS_HEADERS        := $$($(PKG_CONFIG) --cflags libtracefs)
 
 CFLAGS :=      -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS) $(EXTRA_CFLAGS)
-LDFLAGS        :=      -ggdb $(EXTRA_LDFLAGS)
+LDFLAGS        :=      -flto=auto -ggdb $(EXTRA_LDFLAGS)
 LIBS   :=      $$($(PKG_CONFIG) --libs libtracefs)
 
 SRC    :=      $(wildcard src/*.c)
index 8f81fa007364890dd4303b047c484786a56390f2..01870d50942a19a242f6444c7b11f019b460ec4e 100644 (file)
@@ -135,8 +135,7 @@ static void osnoise_hist_update_multiple(struct osnoise_tool *tool, int cpu,
        if (params->output_divisor)
                duration = duration / params->output_divisor;
 
-       if (data->bucket_size)
-               bucket = duration / data->bucket_size;
+       bucket = duration / data->bucket_size;
 
        total_duration = duration * count;
 
@@ -480,7 +479,11 @@ static void osnoise_hist_usage(char *usage)
 
        for (i = 0; msg[i]; i++)
                fprintf(stderr, "%s\n", msg[i]);
-       exit(1);
+
+       if (usage)
+               exit(EXIT_FAILURE);
+
+       exit(EXIT_SUCCESS);
 }
 
 /*
index f7c959be8677799788eda3e577246cd3d2ec444a..457360db07673191fbc034c9fdb3193b91c4499c 100644 (file)
@@ -331,7 +331,11 @@ static void osnoise_top_usage(struct osnoise_top_params *params, char *usage)
 
        for (i = 0; msg[i]; i++)
                fprintf(stderr, "%s\n", msg[i]);
-       exit(1);
+
+       if (usage)
+               exit(EXIT_FAILURE);
+
+       exit(EXIT_SUCCESS);
 }
 
 /*
index 47d3d8b53cb2177fe7db4c39a21e630aca22fa23..dbf154082f958c146bed6537dc527f83e57993d4 100644 (file)
@@ -178,8 +178,7 @@ timerlat_hist_update(struct osnoise_tool *tool, int cpu,
        if (params->output_divisor)
                latency = latency / params->output_divisor;
 
-       if (data->bucket_size)
-               bucket = latency / data->bucket_size;
+       bucket = latency / data->bucket_size;
 
        if (!context) {
                hist = data->hist[cpu].irq;
@@ -546,7 +545,11 @@ static void timerlat_hist_usage(char *usage)
 
        for (i = 0; msg[i]; i++)
                fprintf(stderr, "%s\n", msg[i]);
-       exit(1);
+
+       if (usage)
+               exit(EXIT_FAILURE);
+
+       exit(EXIT_SUCCESS);
 }
 
 /*
index 1640f121baca50d99b94621309522d3fb824bc33..3e9af2c3868880197dc3075b74d94a15bea07d38 100644 (file)
@@ -375,7 +375,11 @@ static void timerlat_top_usage(char *usage)
 
        for (i = 0; msg[i]; i++)
                fprintf(stderr, "%s\n", msg[i]);
-       exit(1);
+
+       if (usage)
+               exit(EXIT_FAILURE);
+
+       exit(EXIT_SUCCESS);
 }
 
 /*
index c769d7b3842c0967e85f7dc1d8c6c705edd1f2dd..9ac71a66840c1bec2e944f3a9db0f427f3c7edfb 100644 (file)
@@ -238,12 +238,6 @@ static inline int sched_setattr(pid_t pid, const struct sched_attr *attr,
        return syscall(__NR_sched_setattr, pid, attr, flags);
 }
 
-static inline int sched_getattr(pid_t pid, struct sched_attr *attr,
-                               unsigned int size, unsigned int flags)
-{
-       return syscall(__NR_sched_getattr, pid, attr, size, flags);
-}
-
 int __set_sched_attr(int pid, struct sched_attr *attr)
 {
        int flags = 0;
@@ -479,13 +473,13 @@ int parse_prio(char *arg, struct sched_attr *sched_param)
                if (prio == INVALID_VAL)
                        return -1;
 
-               if (prio < sched_get_priority_min(SCHED_OTHER))
+               if (prio < MIN_NICE)
                        return -1;
-               if (prio > sched_get_priority_max(SCHED_OTHER))
+               if (prio > MAX_NICE)
                        return -1;
 
                sched_param->sched_policy   = SCHED_OTHER;
-               sched_param->sched_priority = prio;
+               sched_param->sched_nice = prio;
                break;
        default:
                return -1;
@@ -536,7 +530,7 @@ int set_cpu_dma_latency(int32_t latency)
  */
 static const int find_mount(const char *fs, char *mp, int sizeof_mp)
 {
-       char mount_point[MAX_PATH];
+       char mount_point[MAX_PATH+1];
        char type[100];
        int found = 0;
        FILE *fp;
index 04ed1e650495a357daabfe40653c1eab5e89b005..d44513e6c66a01a5fc75f472dcfb9ebbfbd57bfb 100644 (file)
@@ -9,6 +9,8 @@
  */
 #define BUFF_U64_STR_SIZE      24
 #define MAX_PATH               1024
+#define MAX_NICE               20
+#define MIN_NICE               -19
 
 #define container_of(ptr, type, member)({                      \
        const typeof(((type *)0)->member) *__mptr = (ptr);      \
index 3d0f3888a58c66816fca24b5a9d7ab2106f0e992..485f8aeddbe033f227faf32139630d2a616cbd66 100644 (file)
@@ -28,10 +28,15 @@ FOPTS       :=      -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \
                -fasynchronous-unwind-tables -fstack-clash-protection
 WOPTS  :=      -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized
 
+ifeq ($(CC),clang)
+  FOPTS := $(filter-out -ffat-lto-objects, $(FOPTS))
+  WOPTS := $(filter-out -Wno-maybe-uninitialized, $(WOPTS))
+endif
+
 TRACEFS_HEADERS        := $$($(PKG_CONFIG) --cflags libtracefs)
 
 CFLAGS :=      -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS) $(EXTRA_CFLAGS) -I include
-LDFLAGS        :=      -ggdb $(EXTRA_LDFLAGS)
+LDFLAGS        :=      -flto=auto -ggdb $(EXTRA_LDFLAGS)
 LIBS   :=      $$($(PKG_CONFIG) --libs libtracefs)
 
 SRC    :=      $(wildcard src/*.c)
index ad28582bcf2b1ca6b6c9ba9e5d09b0bb5fbe63c0..f04479ecc96c0b75af1afb2e7855cf1cf2491970 100644 (file)
@@ -210,9 +210,9 @@ static char *ikm_read_reactor(char *monitor_name)
 static char *ikm_get_current_reactor(char *monitor_name)
 {
        char *reactors = ikm_read_reactor(monitor_name);
+       char *curr_reactor = NULL;
        char *start;
        char *end;
-       char *curr_reactor;
 
        if (!reactors)
                return NULL;
index d0df5833f2c1851a816b40ce9e308d5ac2cc9a0d..d29b918306b48dd82eba5aab33d7049cede9ff47 100644 (file)
@@ -50,6 +50,7 @@ import drgn
 from drgn.helpers.linux.list import list_for_each_entry,list_empty
 from drgn.helpers.linux.percpu import per_cpu_ptr
 from drgn.helpers.linux.cpumask import for_each_cpu,for_each_possible_cpu
+from drgn.helpers.linux.nodemask import for_each_node
 from drgn.helpers.linux.idr import idr_for_each
 
 import argparse
@@ -75,6 +76,22 @@ def cpumask_str(cpumask):
         output += f'{v:08x}'
     return output.strip()
 
+wq_type_len = 9
+
+def wq_type_str(wq):
+    if wq.flags & WQ_BH:
+        return f'{"bh":{wq_type_len}}'
+    elif wq.flags & WQ_UNBOUND:
+        if wq.flags & WQ_ORDERED:
+            return f'{"ordered":{wq_type_len}}'
+        else:
+            if wq.unbound_attrs.affn_strict:
+                return f'{"unbound,S":{wq_type_len}}'
+            else:
+                return f'{"unbound":{wq_type_len}}'
+    else:
+        return f'{"percpu":{wq_type_len}}'
+
 worker_pool_idr         = prog['worker_pool_idr']
 workqueues              = prog['workqueues']
 wq_unbound_cpumask      = prog['wq_unbound_cpumask']
@@ -82,6 +99,7 @@ wq_pod_types            = prog['wq_pod_types']
 wq_affn_dfl             = prog['wq_affn_dfl']
 wq_affn_names           = prog['wq_affn_names']
 
+WQ_BH                   = prog['WQ_BH']
 WQ_UNBOUND              = prog['WQ_UNBOUND']
 WQ_ORDERED              = prog['__WQ_ORDERED']
 WQ_MEM_RECLAIM          = prog['WQ_MEM_RECLAIM']
@@ -92,6 +110,11 @@ WQ_AFFN_CACHE           = prog['WQ_AFFN_CACHE']
 WQ_AFFN_NUMA            = prog['WQ_AFFN_NUMA']
 WQ_AFFN_SYSTEM          = prog['WQ_AFFN_SYSTEM']
 
+POOL_BH                 = prog['POOL_BH']
+
+WQ_NAME_LEN             = prog['WQ_NAME_LEN'].value_()
+cpumask_str_len         = len(cpumask_str(wq_unbound_cpumask))
+
 print('Affinity Scopes')
 print('===============')
 
@@ -133,10 +156,12 @@ for pi, pool in idr_for_each(worker_pool_idr):
 
 for pi, pool in idr_for_each(worker_pool_idr):
     pool = drgn.Object(prog, 'struct worker_pool', address=pool)
-    print(f'pool[{pi:0{max_pool_id_len}}] ref={pool.refcnt.value_():{max_ref_len}} nice={pool.attrs.nice.value_():3} ', end='')
+    print(f'pool[{pi:0{max_pool_id_len}}] flags=0x{pool.flags.value_():02x} ref={pool.refcnt.value_():{max_ref_len}} nice={pool.attrs.nice.value_():3} ', end='')
     print(f'idle/workers={pool.nr_idle.value_():3}/{pool.nr_workers.value_():3} ', end='')
     if pool.cpu >= 0:
         print(f'cpu={pool.cpu.value_():3}', end='')
+        if pool.flags & POOL_BH:
+            print(' bh', end='')
     else:
         print(f'cpus={cpumask_str(pool.attrs.cpumask)}', end='')
         print(f' pod_cpus={cpumask_str(pool.attrs.__pod_cpumask)}', end='')
@@ -148,24 +173,13 @@ print('')
 print('Workqueue CPU -> pool')
 print('=====================')
 
-print('[    workqueue     \     type   CPU', end='')
+print(f'[{"workqueue":^{WQ_NAME_LEN-2}}\\ {"type   CPU":{wq_type_len}}', end='')
 for cpu in for_each_possible_cpu(prog):
     print(f' {cpu:{max_pool_id_len}}', end='')
 print(' dfl]')
 
 for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'):
-    print(f'{wq.name.string_().decode()[-24:]:24}', end='')
-    if wq.flags & WQ_UNBOUND:
-        if wq.flags & WQ_ORDERED:
-            print(' ordered   ', end='')
-        else:
-            print(' unbound', end='')
-            if wq.unbound_attrs.affn_strict:
-                print(',S ', end='')
-            else:
-                print('   ', end='')
-    else:
-        print(' percpu    ', end='')
+    print(f'{wq.name.string_().decode():{WQ_NAME_LEN}} {wq_type_str(wq):10}', end='')
 
     for cpu in for_each_possible_cpu(prog):
         pool_id = per_cpu_ptr(wq.cpu_pwq, cpu)[0].pool.id.value_()
@@ -175,3 +189,65 @@ for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(
     if wq.flags & WQ_UNBOUND:
         print(f' {wq.dfl_pwq.pool.id.value_():{max_pool_id_len}}', end='')
     print('')
+
+print('')
+print('Workqueue -> rescuer')
+print('====================')
+
+ucpus_len = max(cpumask_str_len, len("unbound_cpus"))
+rcpus_len = max(cpumask_str_len, len("rescuer_cpus"))
+
+print(f'[{"workqueue":^{WQ_NAME_LEN-2}}\\ {"unbound_cpus":{ucpus_len}}    pid {"rescuer_cpus":{rcpus_len}} ]')
+
+for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'):
+    if not (wq.flags & WQ_MEM_RECLAIM):
+        continue
+
+    print(f'{wq.name.string_().decode():{WQ_NAME_LEN}}', end='')
+    if wq.unbound_attrs.value_() != 0:
+        print(f' {cpumask_str(wq.unbound_attrs.cpumask):{ucpus_len}}', end='')
+    else:
+        print(f' {"":{ucpus_len}}', end='')
+
+    print(f' {wq.rescuer.task.pid.value_():6}', end='')
+    print(f' {cpumask_str(wq.rescuer.task.cpus_ptr):{rcpus_len}}', end='')
+    print('')
+
+print('')
+print('Unbound workqueue -> node_nr/max_active')
+print('=======================================')
+
+if 'node_to_cpumask_map' in prog:
+    __cpu_online_mask = prog['__cpu_online_mask']
+    node_to_cpumask_map = prog['node_to_cpumask_map']
+    nr_node_ids = prog['nr_node_ids'].value_()
+
+    print(f'online_cpus={cpumask_str(__cpu_online_mask.address_of_())}')
+    for node in for_each_node():
+        print(f'NODE[{node:02}]={cpumask_str(node_to_cpumask_map[node])}')
+    print('')
+
+    print(f'[{"workqueue":^{WQ_NAME_LEN-2}}\\ min max', end='')
+    first = True
+    for node in for_each_node():
+        if first:
+            print(f'  NODE {node}', end='')
+            first = False
+        else:
+            print(f' {node:7}', end='')
+    print(f' {"dfl":>7} ]')
+    print('')
+
+    for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'):
+        if not (wq.flags & WQ_UNBOUND):
+            continue
+
+        print(f'{wq.name.string_().decode():{WQ_NAME_LEN}} ', end='')
+        print(f'{wq.min_active.value_():3} {wq.max_active.value_():3}', end='')
+        for node in for_each_node():
+            nna = wq.node_nr_active[node]
+            print(f' {nna.nr.counter.value_():3}/{nna.max.value_():3}', end='')
+        nna = wq.node_nr_active[nr_node_ids]
+        print(f' {nna.nr.counter.value_():3}/{nna.max.value_():3}')
+else:
+    printf(f'node_to_cpumask_map not present, is NUMA enabled?')
index 10bfc88a69f72b6a0e310cca043fb04882e24eb1..0f50960b0e3a89215757163ad3b458c92670f4de 100644 (file)
@@ -1615,7 +1615,13 @@ static int check_memory_region_flags(struct kvm *kvm,
                valid_flags &= ~KVM_MEM_LOG_DIRTY_PAGES;
 
 #ifdef __KVM_HAVE_READONLY_MEM
-       valid_flags |= KVM_MEM_READONLY;
+       /*
+        * GUEST_MEMFD is incompatible with read-only memslots, as writes to
+        * read-only memslots have emulated MMIO, not page fault, semantics,
+        * and KVM doesn't allow emulated MMIO for private memory.
+        */
+       if (!(mem->flags & KVM_MEM_GUEST_MEMFD))
+               valid_flags |= KVM_MEM_READONLY;
 #endif
 
        if (mem->flags & ~valid_flags)